Loading [MathJax]/jax/output/HTML-CSS/jax.js
library(ramp.dts)
#devtools::load_all()

In this vignette, we present a model for the dynamics of malaria infection in adult mosquito populations. We call it a Ross-Macdonald model because it makes the same basic assumptions as the model that Macdonald analyzed in 1952. While that model was developed using differential equations, the equations we describe herein are difference equations.

We begin by discrete-time model in a simple population, with one patch, and then we present the equations for the multi-patch model.

In a Single Patch

We define several variables describing adult female mosquitoes. Let Mt denote the total density of uninfected mosquitoes at time t. We assume that mosquitoes emerge from aquatic habitats at the rate Λt and that a proportion of mosquitoes, p, survives each day. The total density of mosquitoes is described by an equation:

Mt+1=Λt+pMt

We let f denote the proportion of mosquitoes that blood feeds each day, and let Pt denote the density of parous mosquitoes:

Pt+1=f(MtPt)+pPt

To model the infection process we need two additional parameters:

  • q - the proportion of blood meals that are taken on humans

  • κt - fraction of human blood meals that infect the mosquito

Let U denote the density of uninfected mosquitoes:

Ut+1=Λt+pefqκtUt Let Yi,t denote a the density of cohorts of infected mosquitoes infected i days ago:

Y1,t+1=p(1efqκt)Ut We let τ denote the oldest cohort of infected mosquitoes that we would wish to track. For mosquitoes infected more than 1 day ago, we let Gi be the fraction that becomes infectious the next day. If we modeled the EIP with a fixed delay, then Gi=1 for i<τ, and Gτ=1. Mosquitoes would become infectious on day τ+1.

Yi+1,t+1=p(1Gi)Yi,t

and

Yτ,t+1=p(1Gτ1)Yτ1,t+p(1Gτ)Yτ,t

Zt denote the density of infectious mosquitoes at time t

Zt+1=ipGiYi+pZt

As we have defined our variables, one of them is not necessary, since

U=MiYiZ

The Multi-Patch Model

In a model with n patches, the model is defined as before, but now we let Mt, Pt, Ut, and Zt be vectors of length p, and we let G be a vector of length τ, (where G1=0). We let Yt denote a p×τ matrix, where each row is a cohort of mosquitoes, and where column represents the mosquitoes in a location. We let Yi,t denote the ith cohort:

Now, we also need to define mosquito movement. We let σ denote a vector describing the proportion of mosquitoes that emigrates from each patch, and let K denote a matrix describing the fraction of emigrating mosquitoes that end up in every other patch, where diagK=0. and where the columns sum up to a number that is less than or equal to one, where the gap represents mortality occurring during dispersal.

We let Ω denote the demographic matrix where:

Ω=diag(p(1σ))+diag(pσ)K Now the dynamics are very similar:

Mt+1=Λt+ΩMtPt+1=f(MtPt)+ΩPtUt+1=Λt+Ω(efqκtUt)Y1,t+1=Ω((1efqκt)Ut)Yi+1,t+1=ΩYi,t(1Gi)Yτ,t+1=Ω(Yτ1,t(1Gτ1))+Ω(Yτ,t(1Gτ))Zt+1=Ω(Ytdiag(G))+ΩZt

Implementation Notes:

In the implementation, we could choose models where the EIP is distributed over some period but where the fraction maturing after time τ is continuous. We have chosen a rotating index to track age of infection cohorts in the matrix Y; using modulo arithmetic, each columns tracks a single cohort for τ days. On the τ+1 day, the column is added to the one before, and then we compute Y1,t. The computation thus does this:

Mt+1=Λt+ΩMtPt+1=f(MtPt)+ΩPtUt+1=Λt+Ω(efqκtUt)Yt+1=Ω(Yi,tdiag(1G))Zt+1=Ω(YtdiagG)+ΩZt

Noting that in the modulo arithmetic, τ+1=1, we get:

Yτ,t+1=Yτ,t+1+Yτ+1,tY1,t+1=Ω((1efqκt)Ut)

Verification

We can verify our model by solving for steady states.

ˉM=Λ(1Ω)1

ˉP=fˉM(1Ω+diagf)1

ˉU=Λ(1Ωdiagefqκ)1

ˉY1=Ω(1efqκ)ˉU For 1<i<τ, we get a recursive relationship:

ˉYi+1=ΩˉYi(1Gi) and for Yτ, we get:

ˉYτ=Ω(diag(1G))ˉYτ1(1Ω(1Gτ))1 and

ˉZ=ΩGY(1Ω)1

Demo

devtools::load_all()
rm1 <- dts_setup(Xname = "trace")
dts_solve(rm1, Tmax=200) -> rm1
dts_steady(rm1) -> rm1
with(rm1$outputs$orbits$MYZ[[1]], {
  plot(time, M, type = "l") 
  lines(time, U, col = "darkblue") 
  lines(time, Y, col = "purple") 
  lines(time, Z, col = "darkred") 
})

compute_MYZ_equil = function(pars, Lambda, kappa, i=1){
  Omega = make_Omega(0, pars$MYZpar[[i]])
  with(pars$MYZpar[[i]],{

    Mbar <-  Lambda/(1-p) 
    Pbar <- f*Mbar/(1 - p + f)
    Ubar <- Lambda/(1-p*exp(-f*q*kappa))
    
    Y1 <- Omega*(1-exp(-f*q*kappa))*Ubar 
    Yi = Y1
    Y = Yi
    for(i in 2:(max_eip-1)){
      Yi <- Omega*Yi*(1-G[i])
      Y = Y+Yi
    }
    Yn <- Omega*Yi
    Y = Y + Yn
    Zbar <- Omega*Yn/(1-p) 
    return(c(M = Mbar, P=Pbar, U=Ubar, Y=Y, Z= Zbar)) 
})}
compute_MYZ_equil(rm1, 1000, .1) 
#>          M          P          U          Y          Z 
#> 12000.0000  9391.3043  9166.7797  1835.9391   997.2812
c(
M = tail(rm1$outputs$orbits$MYZ[[1]]$M, 1), 
P = tail(rm1$outputs$orbits$MYZ[[1]]$P, 1), 
U = tail(rm1$outputs$orbits$MYZ[[1]]$U, 1),
Y = tail(rm1$outputs$orbits$MYZ[[1]]$Y, 1),
Z = tail(rm1$outputs$orbits$MYZ[[1]]$Z, 1)
)
#>          M          P          U          Y          Z 
#> 11999.9997  9391.3040  9166.7797  1835.9391   997.2808
rm10 <- dts_setup(Xname = "trace", nPatches = 10, membership = 1:10)
rm10$Lpar[[1]]$scale = 1.5^c(1:10) 
dts_solve(rm10, Tmax=200) -> rm10
with(rm10$outputs$orbits$MYZ[[1]], {
  plot(time, M[,10], type = "l")
  for(i in 2:10)
    lines(time, M[,i]) 
#  lines(time, U, col = "darkblue") 
#  lines(time, Y, col = "purple") 
#  lines(time, Z, col = "darkred") 
})