Friday, June 1, 2012

Spatial malaria epidemiology infection model - simulation


* Spatial Malaria epidemiology infection model - simulation

* This code creates a simulation similar to that of:
* International Journal for Parasitology's article

* "Spatial simulation of malaria transmission and its control by malaria transmission blocking vaccination"

* by Richard Carter

* I am not sure exactly how well the simulation follow's Carter's simulation because I do not understand how the disease vector works exactly.

* I think his simulation does not have individual mosquitos as mine does but rather relies on "disease vectors".

* Something I do not fully understand.

* Much of the techniques used in this simulation are employed in the previous simulation:
http://www.econometricsbysimulation.com/2012/05/value-added-modelling-stata-simulation.html

************************************************************
* Part 1: Set the simulation parameters
************************************************************

* The following locals set the parameters of the simulation.
* Number of people to be generated
local num_people = 1000

* The gross number of mosquitos to be generated (this could be thought of as a group of mosquitos)
local num_mos = 10000

* The actual amount of mosquitos generated is a fraction of this number relative to how many mosquitos end up in the mosquito ecology.
* If the radius isbbbbb no greater than .5 the then expected number of mosquitos generated will be (pi*r^2)*num_mos = 78.5%*num_mos|r=.5
* The radius of the ecology
local r=.5

* How fast do the mosquitos move change_x = x+mos_speed*rnormal()
local mos_speed=.01

* Specify a breeding rate for mosquitos outside of the ecological zone.
* Close to zero 0 means that almost no mosquitos can breed outside of the ecological zone.
* Warning
* A 1 means there is no difference between the ecological zone and the non-ecological.
local mos_breed=0.1

* Specify the life expectancy for mosquitos in terms of rounds.
* At round `mos_life' all of the mosquitos die and round `mos_life'+1 new mosquitos are born which are now all free of infections.
local mos_life=25

* Initial infection rate within the human population
local infect_rate=.05

* How detailed is the grid (0,1) in which the humans and mosquitos inhabit.
* A highly detailed grid will make encounters between humans and mosquitos less likely.
local grid=.01

* How many rounds of the simulation are going to be modelled
local num_rounds=500

* This tells the simulation to keep information for the last keep_round number of rounds.
* This number must be larger than the recover_rate and the immune_rate
local keep_round=21

* Display initial
local graphs = 1
************************************************************
* Part 2: Generate the population of people
************************************************************

* First lets clear the memory
clear

* Next lets set the number of observations
set obs `num_people'

* We will first generate our people
gen pid = _n
  label var pid "Person ID"

* Generate the locations of the people.
* We can think of this as the locations that the people sleep in.
gen x = round(runiform()-.5,`grid')
  label var x "Human x position"
gen y = round(runiform()-.5,`grid')
  label var y "Human y position"

* For simplicity two people cannot occupy the same location
duplicates drop x y , force

* Imagine a mesquito ecology which is a circle of r radius with a center at zero  x^2 + y^2 <.3:
*1.  x<(r-y^2)^.5
*2.  x>-(r-y^2)^.5
*3.  y<(r-x^2)^.5
*4.  y>-(r-x^2)^.5

* This indicates if the person lives within the mosquito ecology or not.
tempvar inC
gen `inC'=0
replace `inC' = 1 if x<(`r'^2-y^2)^.5 & x>-(`r'^2-y^2)^.5 & y<(`r'^2-x^2)^.5 & y>-(`r'^2-x^2)^.5
if `graphs'==1 two (scatter y x if !`inC', color(red)) ///
 (scatter y x if `inC', color(blue)) , title(Malaria Ecology)

gen infected = rbinomial(1,`infect_rate')
  label var infected "Person infected with Malaria"

if `graphs'==1 two (scatter y x)  ///
  (scatter y x if infected, color(green)), ///
  title(Infected Population)

save "people.dta", replace
* End People part of simulation

* Let's trim down the data set to be only those relevant for the merge
  keep x y infected
  save "people_infected.dta", replace

************************************************************
* Part 3: Generate the population of mosquitos
************************************************************

* Now let us imagine a population of `num_mos' mosquitos that could have been hypathetically born anywhere but if they are not born in the mosquito econology they do not exist.

clear
set obs `num_mos'

gen x = round(runiform()-.5,`grid')
  label var x "Mosquito Position x"
gen y = round(runiform()-.5,`grid')
  label var y "Mosquito Position y"

* Generate an indicator if a mosquito can be bred outside of the ecological zone
  tempvar mos_exist
  gen `mos_exist' = rbinomial(1,`mos_breed')

* Lets first remove the mosquitos which are not born in the ecology and got a bad draw of mos_breed:
  drop if !(x<(`r'^2-y^2)^.5 & x>-(`r'^2-y^2)^.5 & y<(`r'^2-x^2)^.5 & y>-(`r'^2-x^2)^.5)  & `mos_exist'==0

  gen infect=0

save "mos.dta", replace

************************************************************
* Part 4: Do round 1 of infecting the mosquitos with malaria.
************************************************************

* When thinking about Malaria we should be thinking not so much about Mosquitos being the problem but Mosquitos infected with Malaria being the problem.

* The assumption of this simulation will be that any mosquito that lands in the same area (defined by the grid) as a person with Malaria will become infected.

* Likewise, after that, any person bitten by an infected Mosquito will become infected.

* Still using the mosquito data.

* Let us first merge in the people data:

merge m:1 x y using "people_infected.dta"
  replace infected = 0 if infected == .

* We only want to keep data from master (mosquitos) or that matches with mosquitos but not person data:
  drop if _merge==2
  drop _merge

* Now we can see first how many mosquitos are infected.
if `graphs'==1 twoway (scatter y x if !infected)   ///
  (scatter y x if infected, color(red))    ///
  , legend(label(1 "Infected") ///
  label (2 "Not Infected"))    ///
  title(Mosquitos Initially Infected with Malaria)

gl round=1
* Generate an indicator of what round we are in.

* Initially there is not a lot of mosquitos infected because they have just been born and they only become infected by encountering infected humans.

gen x_mos_r$round = x
  label var x_mos_r$round "Mosquito round $round x position"
gen y_mos_r$round = y
  label var y_mos_r$round "Mosquito round $round y position"

* Next mosquitos move randomly from there current position
  replace x = round(x + rnormal()*`mos_speed',`grid')
  replace y = round(y + rnormal()*`mos_speed',`grid')

rename infected mos_infected_r$round
  label var mos_infected_r$round "Mosquito infected round $round"

* Now lets first see if any more mosquitos are infected by encountering people
merge m:1 x y using "people_infected.dta"
  drop if _merge==2
  drop _merge

replace infected = 1 if mos_infected_r$round == 1
  replace infected = 0 if infected == .

* Create a temporary variable to indicate if the mosquitos are within the specified graphing area.
tempvar graph_area
gen `graph_area' = 1 if x>=-.5 & x<=.5 & y>=-.5 & y<=.5

if `graphs'==1  twoway (scatter y x if !infected & `graph_area' == 1 )   ///
  (scatter y x if infected & `graph_area' == 1 , color(red))    ///
  (scatter y x if mos_infected_r1 & `graph_area' == 1 , mcolor(cranberry))    ///
  , legend(label(1 "Not Infected") ///
  label (2 "Infected round 1")          ///
  label (3 "Infected round 2"))    ///
  title(Mosquitos Infected with Malaria)

sum *infected*

* Save the infection rates of the population
  qui sum mos_infected_r1
  gen mos_infection_rate = r(mean) if _n==1

save "mos.dta", replace

* Let's trim down the data set to be only those relevant for later merges
  keep x y infected
  save "mos_infected.dta", replace

************************************************************
* Part 5: Let's infect the first group of people with malaria from mosquitos.
************************************************************

* Now we see if any more people are infected by encountering mosquitos
use "people.dta", clear

* Save data on the infected humans from the current round
rename infected human_infected_r$round
  label var human_infected_r$round "Human infected with Malaria Round $round"

* Merge in the mosquito data
merge 1:m x y using "mos_infected.dta"
  drop if _merge==2
  drop _merge

* This should eliminate any duplicate humans created by the 1:m merge
* We can think of this as some humans get bit by 2 mosquitos, if one of them is infected then the human is now infected, thus max.
collapse (max) x y infected human_infected_*, by(pid)

replace infected = 1 if human_infected_r$round == 1
  replace infected = 0 if infected == .

if `graphs'==1 twoway (scatter y x if !infected)   ///
  (scatter y x if infected, color(pink))    ///
  (scatter y x if human_infected_r1, mcolor(cranberry))    ///
  , legend(label(1 "Not Infected") ///
  label (2 "Infected round 2")          ///
  label (3 "Infected round 1"))    ///
  title(Humans)
* Not too many additional people get infected with Malaria as a result of the first round

* Save the infection rates of the population
  qui sum human_infected_r1
  gen obs_infection_rate = r(mean) if _n==1

save "people.dta", replace

* Trim down the data set to be only those relevant for the next merge
  keep x y infected
  save "people_infected.dta", replace

* This is just the setup to the full simulatiom.
* If you are interested in getting the full simulation contact me with a description of the project you are currently working on and I will check with my team.

2 comments: