From 940179f3531bf7c7c283eac2364b03e7e73e240a Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Tue, 14 Feb 2023 17:16:11 +0000 Subject: [PATCH 001/164] Adding descriptions, changing plots --- vignettes/VectorControl.Rmd | 141 +++++++++++++++++++++++++----------- 1 file changed, 100 insertions(+), 41 deletions(-) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index 67e07881..0560c0d7 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -23,7 +23,7 @@ library(reshape2) # Parameterisation -We are going to set the default parameters to run the simulation from an equilibrium. +We will set the default parameters to run the simulation from an equilibrium. ```{r} year <- 365 @@ -35,97 +35,156 @@ starting_EIR <- 50 simparams <- get_parameters( list( human_population = human_population, + # carrying capacity parameters model_seasonality = TRUE, # Let's try a bi-modal model g0 = 0.28605, g = c(0.20636, -0.0740318, -0.0009293), h = c(0.173743, -0.0730962, -0.116019), - severe_incidence_rendering_min_ages = 2*year, - severe_incidence_rendering_max_ages = 10*year + # Here, we are asking for the output to contain information on severe incidence in children 2-10 years old. + clinical_incidence_rendering_min_ages = 2*year, + clinical_incidence_rendering_max_ages = 10*year ) ) simparams <- set_equilibrium(simparams, starting_EIR) +``` +We can create a few plotting functions to visualise the output. +```{r} # Plotting functions plot_prevalence <- function(output) { - ggplot(output) + geom_line( - aes(x = timestep, y = (n_inc_severe_730_3650 / n_730_3650))) + - labs(x = "timestep", y = "Severe incidence") + plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, type = 'l', + xlab = 'Timestep (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), + xaxs = "i", yaxs = "i", bty = "l") } add_intervention_lines <- function(plot, events) { - plot + geom_vline( - data = events, - mapping = aes(xintercept=timestep), - color="blue" - ) + geom_text( - data = events, - mapping = aes(x = timestep, y = 0, label = name), - size = 4, - angle = 90, - vjust = -0.4, - hjust = 0 - ) + plot + abline(v = events$timestep, col = 'blue') + text(x = events$timestep-20, y = 0.018, events$name, + cex = 1, col = 'black', srt = 90) } ``` Then we can run the simulation for a variety of vector control strategies: -## Bed nets - -We can distribute bed nets once a year for two years, changing the -characteristics of the bed nets on each distribution... +## Bednets +We can distribute bednets once a year for two years, changing the characteristics of the bed nets on each distribution. + ```{r} bednetparams <- simparams bednet_events = data.frame( - timestep = c(1, 2) * year, - name=c("Bednets 1", "Bednets 2") + timestep = c(1, 2) * year, # The bednets will be distributed at the end of the first and the second year. + name=c("Bednets 1", "Bednets 2") # These are labels for the two distributions. ) bednetparams <- set_bednets( bednetparams, - timesteps = bednet_events$timestep, - coverages = c(.8, .8), - retention = 5 * year, - dn0 = matrix(c(.533, .45), nrow=2, ncol=1), - rn = matrix(c(.56, .5), nrow=2, ncol=1), - rnm = matrix(c(.24, .24), nrow=2, ncol=1), - gamman = rep(2.64 * 365, 2) + timesteps = bednet_events$timestep, + coverages = c(.8, .8), # Each round is distributed to 80% of the population + retention = 5 * year, # Nets are kept on average 5 years + dn0 = matrix(c(.533, .45), nrow=2, ncol=1), # Matrix of death probabilities for each mosquito species over time + rn = matrix(c(.56, .5), nrow=2, ncol=1), # Matrix of repelling probabilities for each mosquito species over time + rnm = matrix(c(.24, .24), nrow=2, ncol=1), # Matrix of minimum repelling probabilities for each mosquito species over time + gamman = rep(2.64 * 365, 2) # Vector of bednet half-lives for each distribution timestep ) output <- run_simulation(sim_length, bednetparams) add_intervention_lines(plot_prevalence(output), bednet_events) ``` + + +It is important to understand the difference between the input `coverages` argument of `malariasimulation::set_bednets()` and the resulting population bednet usage over time in the model. In the above example, bednets are distributed to 80% of the population at each distribution round. + +The average population bednet usage will be influenced by: +* The size and frequency of distributions specified in `set_bednets()` +* The assumed net retention half life +* Correlations in the recipients of nets between rounds + +### Visualising usage over time +```{r} +output$prop_use_net <- output$n_use_net / output$n_0_100 +plot(x = output$timestep, y = output$prop_use_net, type = 'l', + xlab = 'Timestep (days)', ylab = 'Proportion of popoulation i', + xaxs = "i", yaxs = "i", bty = "l") +``` + + + ## Indoor spraying -We can do the same for IRS... +We can do the same for IRS. ```{r} sprayingparams <- simparams peak <- peak_season_offset(sprayingparams) spraying_events = data.frame( - timestep = c(1, 2) * year + peak - 3 * month, - name=c("Spraying 1", "Spraying 2") + timestep = c(1, 2) * year + peak - 3 * month, # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. + name=c("Spraying 1", "Spraying 2") # These are labels for the two rounds of IRS ) sprayingparams <- set_spraying( sprayingparams, timesteps = spraying_events$timestep, - coverages = rep(.8, 2), - ls_theta = matrix(c(2.025, 2.025), nrow=2, ncol=1), - ls_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1), - ks_theta = matrix(c(-2.222, -2.222), nrow=2, ncol=1), - ks_gamma = matrix(c(0.008, 0.008), nrow=2, ncol=1), - ms_theta = matrix(c(-1.232, -1.232), nrow=2, ncol=1), - ms_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1) + coverages = rep(.8, 2), # # Each round covers 80% of the population + ls_theta = matrix(c(2.025, 2.025), nrow=2, ncol=1), # Matrix of mortality parameters + ls_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1), # Matrix of mortality parameters per timestep + ks_theta = matrix(c(-2.222, -2.222), nrow=2, ncol=1), # Matrix of feeding success parameters + ks_gamma = matrix(c(0.008, 0.008), nrow=2, ncol=1), # Matrix of feeding success parameters per timestep + ms_theta = matrix(c(-1.232, -1.232), nrow=2, ncol=1), # Matrix of deterrence parameters + ms_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1) # Matrix of deterrence parameters per timestep ) output <- run_simulation(sim_length, sprayingparams) add_intervention_lines(plot_prevalence(output), spraying_events) ``` + +## Additional species +It is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. If you have specified more than 1 species, then the arguments for set_spraying() and set_bednets() must be populated with values for each species at each time point. +```{r} +# Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae +simparams <- set_species( + simparams, + species = list(arab_params, fun_params, gamb_params), + proportions = c(0.25, 0.25, 0.5) +) + +#Here we will run the same model with IRS as before, but this time with 3 species of mosquitoes. Note that now there are 3 columns for the ls_theta, ls_gamma, ks_theta, ks_gamma, ms_theta, and ms_gamma arguments. Each column corresponds to a species and each row corresponds to a timestep when a round of IRS occurred. Here, we are assuming the same values for each species for simplicity. +sprayingparams <- simparams + +peak <- peak_season_offset(sprayingparams) +spraying_events = data.frame( + timestep = c(1, 2) * year + peak - 3 * month, # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. + name=c("Spraying 1", "Spraying 2") # These are labels for the two rounds of IRS +) + +sprayingparams <- set_spraying( + sprayingparams, + timesteps = spraying_events$timestep, + coverages = rep(.8, 2), # # Each round covers 80% of the population + ls_theta = matrix(c(2.025, 2.025), nrow=2, ncol=3), # Matrix of mortality parameters + ls_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=3), # Matrix of mortality parameters per timestep + ks_theta = matrix(c(-2.222, -2.222), nrow=2, ncol=3), # Matrix of feeding success parameters + ks_gamma = matrix(c(0.008, 0.008), nrow=2, ncol=3), # Matrix of feeding success parameters per timestep + ms_theta = matrix(c(-1.232, -1.232), nrow=2, ncol=3), # Matrix of deterrence parameters + ms_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=3) # Matrix of deterrence parameters per timestep +) + +output <- run_simulation(sim_length, sprayingparams) + +add_intervention_lines(plot_prevalence(output), spraying_events) +``` + + +## Using the `netz` package +The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool to help set up bednets in `malariasimulation`. `malariasimulation` takes as input the proportion of the population who were distributed a bednet at specific time points, but the available data do not always have this information. `netz` allows for simple conversions between bednet metrics. +```{r} + +``` + From 031fd57303ef35e9fbbede190a68c44e5abcf734 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Tue, 14 Feb 2023 18:06:11 +0000 Subject: [PATCH 002/164] Create IRS vignette and visualize usage --- vignettes/VectorControl.Rmd | 103 ++++++-------------------- vignettes/VectorControl_IRS.Rmd | 125 ++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 82 deletions(-) create mode 100644 vignettes/VectorControl_IRS.Rmd diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index 0560c0d7..08c0b69e 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -1,8 +1,8 @@ --- -title: "Vector Control" +title: "Vector Control: Bednets" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Vector Control} + %\VignetteIndexEntry{Vector Control: Bednets} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -51,6 +51,9 @@ simparams <- set_equilibrium(simparams, starting_EIR) We can create a few plotting functions to visualise the output. ```{r} +cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", + "#F0E442", "#0072B2", "#D55E00", "#CC79A7") + # Plotting functions plot_prevalence <- function(output) { plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, type = 'l', @@ -60,17 +63,15 @@ plot_prevalence <- function(output) { add_intervention_lines <- function(plot, events) { plot - abline(v = events$timestep, col = 'blue') - text(x = events$timestep-20, y = 0.018, events$name, + abline(v = events$timestep, col = cols[6]) + text(x = events$timestep - 20, y = 0.4, events$name, cex = 1, col = 'black', srt = 90) } ``` -Then we can run the simulation for a variety of vector control strategies: - -## Bednets +## Adding bednets -We can distribute bednets once a year for two years, changing the characteristics of the bed nets on each distribution. +Then we can run the simulation for a variety of bednet strategies. In the example below, we distribute bednets once a year for two years, changing the characteristics of the bed nets for each distribution. ```{r} bednetparams <- simparams @@ -104,86 +105,24 @@ The average population bednet usage will be influenced by: * The assumed net retention half life * Correlations in the recipients of nets between rounds -### Visualising usage over time -```{r} -output$prop_use_net <- output$n_use_net / output$n_0_100 - -plot(x = output$timestep, y = output$prop_use_net, type = 'l', - xlab = 'Timestep (days)', ylab = 'Proportion of popoulation i', - xaxs = "i", yaxs = "i", bty = "l") -``` +### Visualising bednet usage +The output from `malariasimulation::run_simulation()` has a variable that shows the number of people using bednets at any given timestep. We can visualise this to understand how bednet usage changes over time. - -## Indoor spraying - -We can do the same for IRS. ```{r} -sprayingparams <- simparams - -peak <- peak_season_offset(sprayingparams) -spraying_events = data.frame( - timestep = c(1, 2) * year + peak - 3 * month, # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. - name=c("Spraying 1", "Spraying 2") # These are labels for the two rounds of IRS -) - -sprayingparams <- set_spraying( - sprayingparams, - timesteps = spraying_events$timestep, - coverages = rep(.8, 2), # # Each round covers 80% of the population - ls_theta = matrix(c(2.025, 2.025), nrow=2, ncol=1), # Matrix of mortality parameters - ls_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1), # Matrix of mortality parameters per timestep - ks_theta = matrix(c(-2.222, -2.222), nrow=2, ncol=1), # Matrix of feeding success parameters - ks_gamma = matrix(c(0.008, 0.008), nrow=2, ncol=1), # Matrix of feeding success parameters per timestep - ms_theta = matrix(c(-1.232, -1.232), nrow=2, ncol=1), # Matrix of deterrence parameters - ms_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1) # Matrix of deterrence parameters per timestep -) - -output <- run_simulation(sim_length, sprayingparams) - -add_intervention_lines(plot_prevalence(output), spraying_events) -``` - -## Additional species -It is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. If you have specified more than 1 species, then the arguments for set_spraying() and set_bednets() must be populated with values for each species at each time point. -```{r} -# Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae -simparams <- set_species( - simparams, - species = list(arab_params, fun_params, gamb_params), - proportions = c(0.25, 0.25, 0.5) -) - -#Here we will run the same model with IRS as before, but this time with 3 species of mosquitoes. Note that now there are 3 columns for the ls_theta, ls_gamma, ks_theta, ks_gamma, ms_theta, and ms_gamma arguments. Each column corresponds to a species and each row corresponds to a timestep when a round of IRS occurred. Here, we are assuming the same values for each species for simplicity. -sprayingparams <- simparams - -peak <- peak_season_offset(sprayingparams) -spraying_events = data.frame( - timestep = c(1, 2) * year + peak - 3 * month, # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. - name=c("Spraying 1", "Spraying 2") # These are labels for the two rounds of IRS -) - -sprayingparams <- set_spraying( - sprayingparams, - timesteps = spraying_events$timestep, - coverages = rep(.8, 2), # # Each round covers 80% of the population - ls_theta = matrix(c(2.025, 2.025), nrow=2, ncol=3), # Matrix of mortality parameters - ls_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=3), # Matrix of mortality parameters per timestep - ks_theta = matrix(c(-2.222, -2.222), nrow=2, ncol=3), # Matrix of feeding success parameters - ks_gamma = matrix(c(0.008, 0.008), nrow=2, ncol=3), # Matrix of feeding success parameters per timestep - ms_theta = matrix(c(-1.232, -1.232), nrow=2, ncol=3), # Matrix of deterrence parameters - ms_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=3) # Matrix of deterrence parameters per timestep -) - -output <- run_simulation(sim_length, sprayingparams) - -add_intervention_lines(plot_prevalence(output), spraying_events) +plot(x = output$timestep, y = output$n_use_net, type = 'l', col = '', + xlab = 'Timestep (days)', ylab = 'N using bednets', + xaxs = "i", yaxs = "i", bty = "l") ``` + +## Using the `netz` package to estimate coverage inputs needed to achieve target population usage - -## Using the `netz` package -The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool to help set up bednets in `malariasimulation`. `malariasimulation` takes as input the proportion of the population who were distributed a bednet at specific time points, but the available data do not always have this information. `netz` allows for simple conversions between bednet metrics. +The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool to help set up bednets in `malariasimulation`. `malariasimulation` takes as input the proportion of the population who were distributed a bednet at specific time points, but the available data do not always have this information. `netz` allows for simple conversions between bednet metrics like crop, access, distribution, and usage. + +See the vignettes from the `netz` package: +* [here](https://mrc-ide.github.io/netz/articles/overview.html) that explains how to estimate the distribution coverage from a specified usage. +* [here](https://mrc-ide.github.io/netz/articles/population_usage.html) that explains how to estimate population usage from input distribution. ```{r} ``` diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd new file mode 100644 index 00000000..17290c80 --- /dev/null +++ b/vignettes/VectorControl_IRS.Rmd @@ -0,0 +1,125 @@ +--- +title: "Vector Control: Indoor Residual Spraying" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Vector Control: IRS} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +# Parameterisation + +We will set the default parameters to run the simulation from an equilibrium. + +```{r} +year <- 365 +month <- 30 +sim_length <- 3 * year +human_population <- 1000 +starting_EIR <- 50 + +simparams <- get_parameters( + list( + human_population = human_population, + # carrying capacity parameters + model_seasonality = TRUE, # Let's try a bi-modal model + g0 = 0.28605, + g = c(0.20636, -0.0740318, -0.0009293), + h = c(0.173743, -0.0730962, -0.116019), + # Here, we are asking for the output to contain information on severe incidence in children 2-10 years old. + clinical_incidence_rendering_min_ages = 2*year, + clinical_incidence_rendering_max_ages = 10*year + ) +) + +simparams <- set_equilibrium(simparams, starting_EIR) +``` + +We can create a few plotting functions to visualise the output. +```{r} +# Plotting functions +plot_prevalence <- function(output) { + plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, type = 'l', + xlab = 'Timestep (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), + xaxs = "i", yaxs = "i", bty = "l") +} + +add_intervention_lines <- function(plot, events) { + plot + abline(v = events$timestep, col = 'blue') + text(x = events$timestep-20, y = 0.018, events$name, + cex = 1, col = 'black', srt = 90) +} +``` + +## Adding indoor residual spraying (IRS) + +Then we can run the simulation for a variety of IRS strategies. In the example below, there are two rounds of IRS, each 3 months prior to peak transmission for that year. +```{r} +sprayingparams <- simparams + +peak <- peak_season_offset(sprayingparams) +spraying_events = data.frame( + timestep = c(1, 2) * year + peak - 3 * month, # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. + name=c("Spraying 1", "Spraying 2") # These are labels for the two rounds of IRS +) + +sprayingparams <- set_spraying( + sprayingparams, + timesteps = spraying_events$timestep, + coverages = rep(.8, 2), # # Each round covers 80% of the population + ls_theta = matrix(c(2.025, 2.025), nrow=2, ncol=1), # Matrix of mortality parameters + ls_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1), # Matrix of mortality parameters per timestep + ks_theta = matrix(c(-2.222, -2.222), nrow=2, ncol=1), # Matrix of feeding success parameters + ks_gamma = matrix(c(0.008, 0.008), nrow=2, ncol=1), # Matrix of feeding success parameters per timestep + ms_theta = matrix(c(-1.232, -1.232), nrow=2, ncol=1), # Matrix of deterrence parameters + ms_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1) # Matrix of deterrence parameters per timestep +) + +output <- run_simulation(sim_length, sprayingparams) + +add_intervention_lines(plot_prevalence(output), spraying_events) +``` + +## Additional species +It is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. If you have specified more than 1 species, then the arguments for set_spraying() and set_bednets() must be populated with values for each species at each time point. +```{r} +# Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae +simparams <- set_species( + simparams, + species = list(arab_params, fun_params, gamb_params), + proportions = c(0.25, 0.25, 0.5) +) + +#Here we will run the same model with IRS as before, but this time with 3 species of mosquitoes. Note that now there are 3 columns for the ls_theta, ls_gamma, ks_theta, ks_gamma, ms_theta, and ms_gamma arguments. Each column corresponds to a species and each row corresponds to a timestep when a round of IRS occurred. Here, we are assuming the same values for each species for simplicity. +sprayingparams <- simparams + +peak <- peak_season_offset(sprayingparams) +spraying_events = data.frame( + timestep = c(1, 2) * year + peak - 3 * month, # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. + name=c("Spraying 1", "Spraying 2") # These are labels for the two rounds of IRS +) + +sprayingparams <- set_spraying( + sprayingparams, + timesteps = spraying_events$timestep, + coverages = rep(.8, 2), # # Each round covers 80% of the population + ls_theta = matrix(c(2.025, 2.025), nrow=2, ncol=3), # Matrix of mortality parameters + ls_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=3), # Matrix of mortality parameters per timestep + ks_theta = matrix(c(-2.222, -2.222), nrow=2, ncol=3), # Matrix of feeding success parameters + ks_gamma = matrix(c(0.008, 0.008), nrow=2, ncol=3), # Matrix of feeding success parameters per timestep + ms_theta = matrix(c(-1.232, -1.232), nrow=2, ncol=3), # Matrix of deterrence parameters + ms_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=3) # Matrix of deterrence parameters per timestep +) + +output <- run_simulation(sim_length, sprayingparams) + +add_intervention_lines(plot_prevalence(output), spraying_events) +``` From b36150f0d1049154f770255210178a1cfb17f900 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Wed, 15 Feb 2023 11:01:57 +0000 Subject: [PATCH 003/164] Bednets: improving plots, expanding netz paragraph IRS: improving plots, adding species --- vignettes/VectorControl.Rmd | 22 +++++++++------------- vignettes/VectorControl_IRS.Rmd | 26 +++++++++++++++----------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index 08c0b69e..154bb6df 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -63,9 +63,9 @@ plot_prevalence <- function(output) { add_intervention_lines <- function(plot, events) { plot - abline(v = events$timestep, col = cols[6]) + abline(v = events$timestep, col = cols[6], lwd = 2.5) text(x = events$timestep - 20, y = 0.4, events$name, - cex = 1, col = 'black', srt = 90) + cex = 1, col = cols[1], srt = 90) } ``` @@ -109,21 +109,17 @@ The average population bednet usage will be influenced by: The output from `malariasimulation::run_simulation()` has a variable that shows the number of people using bednets at any given timestep. We can visualise this to understand how bednet usage changes over time. - ```{r} -plot(x = output$timestep, y = output$n_use_net, type = 'l', col = '', - xlab = 'Timestep (days)', ylab = 'N using bednets', - xaxs = "i", yaxs = "i", bty = "l") +plot(x = output$timestep, y = output$n_use_net, type = 'l', col = cols[1], + xlab = 'Timestep (days)', ylab = 'N using bednets', + xaxs = "i", yaxs = "i", bty = "l") ``` ## Using the `netz` package to estimate coverage inputs needed to achieve target population usage -The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool to help set up bednets in `malariasimulation`. `malariasimulation` takes as input the proportion of the population who were distributed a bednet at specific time points, but the available data do not always have this information. `netz` allows for simple conversions between bednet metrics like crop, access, distribution, and usage. +The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool to help set up bednets in `malariasimulation`. `malariasimulation` takes as input the proportion of the population who were distributed a bednet at specific time points, but available data for a specific region or country do not always have this information. `netz` allows for simple conversions between bednet metrics like crop, access, distribution, and usage. -See the vignettes from the `netz` package: -* [here](https://mrc-ide.github.io/netz/articles/overview.html) that explains how to estimate the distribution coverage from a specified usage. -* [here](https://mrc-ide.github.io/netz/articles/population_usage.html) that explains how to estimate population usage from input distribution. -```{r} - -``` +See the vignettes from the `netz` package that explain these concepts more comprehensively: +* [This vignette](https://mrc-ide.github.io/netz/articles/overview.html) explains how to estimate the distribution coverage from a specified bednet usage. +* [This vignette](https://mrc-ide.github.io/netz/articles/population_usage.html) demonstrates how to estimate population bednet usage from input distribution. diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index 17290c80..d7b04b55 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -44,6 +44,9 @@ simparams <- set_equilibrium(simparams, starting_EIR) We can create a few plotting functions to visualise the output. ```{r} +cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", + "#F0E442", "#0072B2", "#D55E00", "#CC79A7") + # Plotting functions plot_prevalence <- function(output) { plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, type = 'l', @@ -53,9 +56,9 @@ plot_prevalence <- function(output) { add_intervention_lines <- function(plot, events) { plot - abline(v = events$timestep, col = 'blue') - text(x = events$timestep-20, y = 0.018, events$name, - cex = 1, col = 'black', srt = 90) + abline(v = events$timestep, col = cols[6], lwd = 2.5) + text(x = events$timestep - 20, y = 0.4, events$name, + cex = 1, col = cols[1], srt = 90) } ``` @@ -89,7 +92,9 @@ add_intervention_lines(plot_prevalence(output), spraying_events) ``` ## Additional species -It is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. If you have specified more than 1 species, then the arguments for set_spraying() and set_bednets() must be populated with values for each species at each time point. +It is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. If you have specified more than 1 species, then the arguments for `set_spraying()` and `set_bednets()` must be populated with values for each species at each time point. + +We will run the same model with IRS as above, but this time with 3 species of mosquitoes. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. Each column corresponds to a species of mosquito, and each row corresponds to the timestep when a round of IRS occurred. Here, we are assuming the same values for each species at each timepoint for simplicity, but the matrix could be edited to have different values by species or over time. ```{r} # Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae simparams <- set_species( @@ -98,7 +103,6 @@ simparams <- set_species( proportions = c(0.25, 0.25, 0.5) ) -#Here we will run the same model with IRS as before, but this time with 3 species of mosquitoes. Note that now there are 3 columns for the ls_theta, ls_gamma, ks_theta, ks_gamma, ms_theta, and ms_gamma arguments. Each column corresponds to a species and each row corresponds to a timestep when a round of IRS occurred. Here, we are assuming the same values for each species for simplicity. sprayingparams <- simparams peak <- peak_season_offset(sprayingparams) @@ -111,12 +115,12 @@ sprayingparams <- set_spraying( sprayingparams, timesteps = spraying_events$timestep, coverages = rep(.8, 2), # # Each round covers 80% of the population - ls_theta = matrix(c(2.025, 2.025), nrow=2, ncol=3), # Matrix of mortality parameters - ls_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=3), # Matrix of mortality parameters per timestep - ks_theta = matrix(c(-2.222, -2.222), nrow=2, ncol=3), # Matrix of feeding success parameters - ks_gamma = matrix(c(0.008, 0.008), nrow=2, ncol=3), # Matrix of feeding success parameters per timestep - ms_theta = matrix(c(-1.232, -1.232), nrow=2, ncol=3), # Matrix of deterrence parameters - ms_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=3) # Matrix of deterrence parameters per timestep + ls_theta = matrix(2.025, nrow=2, ncol=3), # Matrix of mortality parameters + ls_gamma = matrix(-0.009, nrow=2, ncol=3), # Matrix of mortality parameters per timestep + ks_theta = matrix(-2.222, nrow=2, ncol=3), # Matrix of feeding success parameters + ks_gamma = matrix(0.008, nrow=2, ncol=3), # Matrix of feeding success parameters per timestep + ms_theta = matrix(-1.232, nrow=2, ncol=3), # Matrix of deterrence parameters + ms_gamma = matrix(-0.009, nrow=2, ncol=3) # Matrix of deterrence parameters per timestep ) output <- run_simulation(sim_length, sprayingparams) From a4bdd232fb768f99454c3202253568a8c4aa3803 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Wed, 15 Feb 2023 11:11:56 +0000 Subject: [PATCH 004/164] Updated plots to match Tom's --- vignettes/VectorControl.Rmd | 7 ++++--- vignettes/VectorControl_IRS.Rmd | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index 154bb6df..07d8ae3a 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -56,14 +56,15 @@ cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", # Plotting functions plot_prevalence <- function(output) { - plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, type = 'l', - xlab = 'Timestep (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), + plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, + type = 'l', col = cols[4], + xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), xaxs = "i", yaxs = "i", bty = "l") } add_intervention_lines <- function(plot, events) { plot - abline(v = events$timestep, col = cols[6], lwd = 2.5) + abline(v = events$timestep, lty = 2, lwd = 2.5) text(x = events$timestep - 20, y = 0.4, events$name, cex = 1, col = cols[1], srt = 90) } diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index d7b04b55..691d989a 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -49,14 +49,15 @@ cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", # Plotting functions plot_prevalence <- function(output) { - plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, type = 'l', - xlab = 'Timestep (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), + plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, + type = 'l', col = cols[4], + xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), xaxs = "i", yaxs = "i", bty = "l") } add_intervention_lines <- function(plot, events) { plot - abline(v = events$timestep, col = cols[6], lwd = 2.5) + abline(v = events$timestep, lty = 2, lwd = 2.5) text(x = events$timestep - 20, y = 0.4, events$name, cex = 1, col = cols[1], srt = 90) } From 00e3b9bd58f7209c1ea51de9aaaf7f800fe2457c Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Wed, 15 Feb 2023 11:22:05 +0000 Subject: [PATCH 005/164] First edits to add plotting functions in base R --- vignettes/Variation.Rmd | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index e8f39746..563d4f01 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -10,29 +10,47 @@ vignette: > ```{r setup, include=FALSE} library(malariasimulation) library(cowplot) -library(ggplot2) ``` +First we will create a few plotting functions to visualise outputs. +```{r} +plot_n_detect <- function(output){ + plot(x = output$timestep, y = output$n_detect_730_3650, + type = 'l', col = cols[4], + xlab = 'Time (days)', ylab = "Cases detected in children aged 2-10 years", + xaxs = "i", yaxs = "i", bty = "l") +} + +plot_p_detect <- function(output){ + plot(x = output$timestep, y = output$p_detect_730_3650, + type = 'l', col = cols[4], + xlab = 'Time (days)', ylab = "Sum of probabilities of case detection in children aged 2-10 years", + xaxs = "i", yaxs = "i", bty = "l") +} +``` ## Variation in outputs -Malariasimulation is a stochastic model, so there will be be variation in model outputs. For example, we could look at detected malaria cases over a year... +Malariasimulation is a stochastic model, so there will be be variation in model outputs. To illustrate this, we could compare the prevalence of malaria cases over a year in simulations with a small and a larger population. ```{r} # A small population -p <- get_parameters(list( +params <- get_parameters(list( human_population = 1000, individual_mosquitoes = FALSE )) -p <- set_equilibrium(p, 2) -small_o <- run_simulation(365, p) -p <- get_parameters(list( +params <- set_equilibrium(params, 2) +small_pop <- run_simulation(365, params) + +# A larger population +params <- get_parameters(list( human_population = 10000, individual_mosquitoes = FALSE )) -p <- set_equilibrium(p, 2) -big_o <- run_simulation(365, p) +params <- set_equilibrium(params, 2) +big_pop <- run_simulation(365, params) plot_grid( + ggplot(small_o) + geom_line(aes(timestep, n_detect_730_3650)) + ggtitle('n_detect at n = 1,000'), ggplot(small_o) + geom_line(aes(timestep, p_detect_730_3650)) + ggtitle('p_detect at n = 1,000'), ggplot(big_o) + geom_line(aes(timestep, n_detect_730_3650)) + ggtitle('n_detect at n = 10,000'), From fafefbdc8d2df62e672838e8909f6b34ced3a9e2 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Wed, 15 Feb 2023 11:27:10 +0000 Subject: [PATCH 006/164] Removing ggplot2 and reshape2 dependencies --- vignettes/VectorControl.Rmd | 2 -- vignettes/VectorControl_IRS.Rmd | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index 07d8ae3a..0f98830f 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -15,10 +15,8 @@ knitr::opts_chunk$set( ``` ```{r setup} -suppressPackageStartupMessages(library(ggplot2)) library(malariasimulation) library(malariaEquilibrium) -library(reshape2) ``` # Parameterisation diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index 691d989a..74820357 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -14,6 +14,11 @@ knitr::opts_chunk$set( ) ``` +```{r setup} +library(malariasimulation) +library(malariaEquilibrium) +``` + # Parameterisation We will set the default parameters to run the simulation from an equilibrium. From 71e78f80269e6b04381989a53e684dc1bd4c27eb Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Wed, 15 Feb 2023 12:20:24 +0000 Subject: [PATCH 007/164] Updated some plots to base R --- vignettes/Variation.Rmd | 56 ++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index 563d4f01..ab44e644 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -14,6 +14,9 @@ library(cowplot) First we will create a few plotting functions to visualise outputs. ```{r} +cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", + "#F0E442", "#0072B2", "#D55E00", "#CC79A7") + plot_n_detect <- function(output){ plot(x = output$timestep, y = output$n_detect_730_3650, type = 'l', col = cols[4], @@ -49,13 +52,15 @@ params <- get_parameters(list( params <- set_equilibrium(params, 2) big_pop <- run_simulation(365, params) -plot_grid( - - ggplot(small_o) + geom_line(aes(timestep, n_detect_730_3650)) + ggtitle('n_detect at n = 1,000'), - ggplot(small_o) + geom_line(aes(timestep, p_detect_730_3650)) + ggtitle('p_detect at n = 1,000'), - ggplot(big_o) + geom_line(aes(timestep, n_detect_730_3650)) + ggtitle('n_detect at n = 10,000'), - ggplot(big_o) + geom_line(aes(timestep, p_detect_730_3650)) + ggtitle('p_detect at n = 10,000') -) +par(mfrow = c(2,2)) +plot_n_detect(small_pop) +title('n_detect at n = 1,000') +plot_p_detect(small_pop) +title('p_detect at n = 1,000') +plot_n_detect(big_pop) +title('n_detect at n = 10,000') +plot_p_detect(big_pop) +title('p_detect at n = 10,000') ``` The n_detect output shows the result of sampling individuals who would be detected by microscopy. @@ -66,19 +71,20 @@ Notice that the p_detect output is slightly smoother. That's because it forgoes ## Estimating variation -We can estimate the variation in the number of detectable cases by repeating the simulation several times... +We can estimate the variation in the number of detectable cases by repeating the simulation several times and plotting the IQR and 95% confidence intervals. ```{r} outputs <- run_simulation_with_repetitions( timesteps = 365, repetitions = 10, - overrides = p, + overrides = params, parallel=TRUE ) +# Calculate IQR and 95% confidence intervals for each of the repetitions df <- aggregate( outputs$n_detect_730_3650, - by=list(outputs$timestep), + by = list(outputs$timestep), FUN = function(x) { c( median = median(x), @@ -91,19 +97,23 @@ df <- aggregate( } ) -df <- data.frame(cbind(t = df$Group.1, df$x)) - -plot_grid( - ggplot(df) - + geom_line(aes(x = t, y = median, group = 1)) - + geom_ribbon(aes(x = t, ymin = lowq, ymax = highq), alpha = .2) - + xlab('timestep') + ylab('n_detect') + ggtitle('IQR spread'), - ggplot(df) - + geom_line(aes(x = t, y = mean, group = 1)) - + geom_ribbon(aes(x = t, ymin = lowci, ymax = highci), alpha = .2) - + xlab('timestep') + ylab('n_detect') + ggtitle('95% confidence interval') -) +df <- data.frame(cbind(timestep = df$Group.1, df$x)) + +par(mfrow = c(1,2)) +plot(x = df$timestep, y = df$median, + type = 'l', col = cols[4], + xlab = 'Time (days)', ylab = "Cases detected in children aged 2-10 years", + xaxs = "i", yaxs = "i", bty = "l") + + ggplot(df)+ + geom_line(aes(x = timestep, y = median, group = 1))+ + geom_ribbon(aes(x = timestep, ymin = lowq, ymax = highq), alpha = .2)+ + xlab('timestep') + ylab('Cases detected in children aged 2-10 years') + ggtitle('IQR spread') + ggplot(df)+ + geom_line(aes(x = timestep, y = mean, group = 1))+ + geom_ribbon(aes(x = timestep, ymin = lowci, ymax = highci), alpha = .2)+ + xlab('timestep') + ylab('Cases detected in children aged 2-10 years') + ggtitle('95% confidence interval') ``` -These are useful techniques for comparing the expected variance from model outputs to outcomes from trials with lower population sizes. \ No newline at end of file +These are useful techniques for comparing the expected variance from model outputs to outcomes from trials that had lower population sizes. \ No newline at end of file From ff529e6919161d2b79efcbf569ed23886dc325a1 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Wed, 15 Feb 2023 12:22:12 +0000 Subject: [PATCH 008/164] More plot modifications to avoid ggplot2 --- vignettes/Variation.Rmd | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index ab44e644..a566eb99 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -104,15 +104,17 @@ plot(x = df$timestep, y = df$median, type = 'l', col = cols[4], xlab = 'Time (days)', ylab = "Cases detected in children aged 2-10 years", xaxs = "i", yaxs = "i", bty = "l") +title('IQR spread') +plot(x = df$timestep, y = df$mean, + type = 'l', col = cols[4], + xlab = 'Time (days)', ylab = "Cases detected in children aged 2-10 years", + xaxs = "i", yaxs = "i", bty = "l") +title('95% Confidence interval') ggplot(df)+ - geom_line(aes(x = timestep, y = median, group = 1))+ - geom_ribbon(aes(x = timestep, ymin = lowq, ymax = highq), alpha = .2)+ - xlab('timestep') + ylab('Cases detected in children aged 2-10 years') + ggtitle('IQR spread') + geom_ribbon(aes(x = timestep, ymin = lowq, ymax = highq), alpha = .2) ggplot(df)+ - geom_line(aes(x = timestep, y = mean, group = 1))+ - geom_ribbon(aes(x = timestep, ymin = lowci, ymax = highci), alpha = .2)+ - xlab('timestep') + ylab('Cases detected in children aged 2-10 years') + ggtitle('95% confidence interval') + geom_ribbon(aes(x = timestep, ymin = lowci, ymax = highci), alpha = .2) ``` From db6a683ae4c8906beddf6f5a1add7d8772668535 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Wed, 15 Feb 2023 13:15:14 +0000 Subject: [PATCH 009/164] Removing cowplot dependency and changing last plot to base r --- vignettes/Variation.Rmd | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index a566eb99..1a68eaf5 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -9,7 +9,6 @@ vignette: > ```{r setup, include=FALSE} library(malariasimulation) -library(cowplot) ``` First we will create a few plotting functions to visualise outputs. @@ -100,22 +99,27 @@ df <- aggregate( df <- data.frame(cbind(timestep = df$Group.1, df$x)) par(mfrow = c(1,2)) +xx <- c(df$timestep, rev(df$timestep)) +yy <- c(df$lowq, rev(df$highq)) plot(x = df$timestep, y = df$median, - type = 'l', col = cols[4], + type = 'n', xlim = c(-1,365),ylim = c(510,565), xlab = 'Time (days)', ylab = "Cases detected in children aged 2-10 years", xaxs = "i", yaxs = "i", bty = "l") +polygon(xx, yy, + col = 'grey90', border= 'grey95') +lines(x = df$timestep, y = df$median, col = cols[4], lwd = 2) title('IQR spread') + +xx <- c(df$timestep, rev(df$timestep)) +yy <- c(df$lowci, rev(df$highci)) plot(x = df$timestep, y = df$mean, - type = 'l', col = cols[4], + type = 'n', xlim = c(-1,365),ylim = c(490,590), xlab = 'Time (days)', ylab = "Cases detected in children aged 2-10 years", xaxs = "i", yaxs = "i", bty = "l") +polygon(xx, yy, + col = 'grey90', border= 'grey95') +lines(x = df$timestep, y = df$mean, col = cols[4], lwd = 2) title('95% Confidence interval') - - ggplot(df)+ - geom_ribbon(aes(x = timestep, ymin = lowq, ymax = highq), alpha = .2) - ggplot(df)+ - geom_ribbon(aes(x = timestep, ymin = lowci, ymax = highci), alpha = .2) - ``` These are useful techniques for comparing the expected variance from model outputs to outcomes from trials that had lower population sizes. \ No newline at end of file From 456c6e281695901314fe4b5e2730fb8705b2b6e3 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 16 Feb 2023 13:13:15 +0000 Subject: [PATCH 010/164] Correction to set_spraying() argument description --- R/vector_control_parameters.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/vector_control_parameters.R b/R/vector_control_parameters.R index fe4b1f0c..6e88c733 100644 --- a/R/vector_control_parameters.R +++ b/R/vector_control_parameters.R @@ -84,11 +84,11 @@ set_bednets <- function( #' With nrows=length(timesteps), ncols=length(species) #' @param ls_gamma matrix of mortality parameters per timestep #' With nrows=length(timesteps), ncols=length(species) -#' @param ks_theta matrix of feeding success parameters per timestep +#' @param ks_theta matrix of feeding success parameters #' With nrows=length(timesteps), ncols=length(species) #' @param ks_gamma matrix of feeding success parameters per timestep #' With nrows=length(timesteps), ncols=length(species) -#' @param ms_theta matrix of deterrence parameters per timestep +#' @param ms_theta matrix of deterrence parameters #' With nrows=length(timesteps), ncols=length(species) #' @param ms_gamma matrix of deterrence parameters per timestep #' With nrows=length(timesteps), ncols=length(species) From d8e44c49890a6e9176a48425048ad3171a7ff41f Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 16 Feb 2023 16:34:38 +0000 Subject: [PATCH 011/164] Updating usage plot and clarifying set spraying --- vignettes/VectorControl.Rmd | 6 ++++-- vignettes/VectorControl_IRS.Rmd | 30 ++++++++++++++++++++++++------ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index 0f98830f..2f5dff91 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -109,8 +109,10 @@ The average population bednet usage will be influenced by: The output from `malariasimulation::run_simulation()` has a variable that shows the number of people using bednets at any given timestep. We can visualise this to understand how bednet usage changes over time. ```{r} -plot(x = output$timestep, y = output$n_use_net, type = 'l', col = cols[1], - xlab = 'Timestep (days)', ylab = 'N using bednets', +output$prop_use_net <- output$n_use_net / human_population + +plot(x = output$timestep, y = output$prop_use_net, type = 'l', col = cols[1], + xlab = 'Timestep (days)', ylab = 'Proportion using bednets', xaxs = "i", yaxs = "i", bty = "l") ``` diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index 74820357..ce794b0a 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -121,12 +121,30 @@ sprayingparams <- set_spraying( sprayingparams, timesteps = spraying_events$timestep, coverages = rep(.8, 2), # # Each round covers 80% of the population - ls_theta = matrix(2.025, nrow=2, ncol=3), # Matrix of mortality parameters - ls_gamma = matrix(-0.009, nrow=2, ncol=3), # Matrix of mortality parameters per timestep - ks_theta = matrix(-2.222, nrow=2, ncol=3), # Matrix of feeding success parameters - ks_gamma = matrix(0.008, nrow=2, ncol=3), # Matrix of feeding success parameters per timestep - ms_theta = matrix(-1.232, nrow=2, ncol=3), # Matrix of deterrence parameters - ms_gamma = matrix(-0.009, nrow=2, ncol=3) # Matrix of deterrence parameters per timestep + ls_theta = matrix(c(rep(2.025, sim_length/year), + rep(2.025, sim_length/year), + rep(2.025, sim_length/year), + nrow=sim_length/year, ncol=3)), # Matrix of mortality parameters + ls_gamma = matrix(c(rep(-0.009, sim_length/year), + rep(-0.009, sim_length/year), + rep(-0.009, sim_length/year)), + nrow=sim_length/year, ncol=3), # Matrix of mortality parameters per timestep + ks_theta = matrix(c(rep(-2.222, sim_length/year), + rep(-2.222, sim_length/year), + rep(-2.222, sim_length/year)), + nrow=sim_length/year, ncol=3), # Matrix of feeding success parameters + ks_gamma = matrix(c(rep(0.008, sim_length/year), + rep(0.008, sim_length/year), + rep(0.008, sim_length/year)), + nrow=sim_length/year, ncol=3), # Matrix of feeding success parameters per timestep + ms_theta = matrix(c(rep(-1.232, sim_length/year), + rep(-1.232, sim_length/year), + rep(-1.232, sim_length/year)), + nrow=sim_length/year, ncol=3), # Matrix of deterrence parameters + ms_gamma = matrix(c(rep(-0.009, sim_length/year), + rep(-0.009, sim_length/year), + rep(-0.009, sim_length/year)), + nrow=sim_length/year, ncol=3) # Matrix of deterrence parameters per timestep ) output <- run_simulation(sim_length, sprayingparams) From d560771ed85e2a37ddda2472820f8cd0bc9ffe5e Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Mon, 20 Feb 2023 10:21:40 +0000 Subject: [PATCH 012/164] Swapped ggplot plot for base r plot --- vignettes/Metapopulation.Rmd | 50 ++++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/vignettes/Metapopulation.Rmd b/vignettes/Metapopulation.Rmd index 1cbb433d..18af806b 100644 --- a/vignettes/Metapopulation.Rmd +++ b/vignettes/Metapopulation.Rmd @@ -15,7 +15,6 @@ knitr::opts_chunk$set( ``` ```{r setup} -suppressPackageStartupMessages(library(ggplot2)) library(malariasimulation) library(malariaEquilibrium) ``` @@ -112,13 +111,44 @@ output <- aggregate(prev2to10 ~ mix + EIR + year, data = output, FUN = mean) Now let's visualize the results of mixing on PfPR2-10: ```{r} -# plot -ggplot(data = output) + - geom_line(aes(x = year, y = prev2to10, color = factor(EIR))) + - facet_wrap(~ mix) + - scale_y_continuous(limits = c(0, 0.35)) + - labs(x = 'time (years)', - y = 'PfPR 2-10 (month)', - color = 'EIR') + - theme_classic() + +colorBlindBlack8 <- c("#000000", "#E69F00", "#56B4E9", "#009E73", + "#F0E442", "#0072B2", "#D55E00", "#CC79A7") + +Panel_spec <- rbind(c(0,0.37,0,1), + c(0.37,0.635,0,1), + c(0.635,0.9,0,1), + c(0.9,1,0,1)) + +Margin_spec <- rbind(c(0.8,0.8,0.3,0.1), + c(0.8,0.1,0.3,0.1), + c(0.8,0.1,0.3,0.1)) + + +Mix_vec <- unique(output$mix) +EIR_vec <- unique(output$EIR) + +Xlab_vec <- c("","Time (years)","") +Ylab_vec <- c("PfPR 2-10 (months)","","") +New_vec <- c(F,T,T) + +Plot_Mixing <- function(output){ + for(i in 1:3){ + par(fig=Panel_spec[i,], cex = 0.8, mai = Margin_spec[i,], new = New_vec[i]) + with(subset(output,output$mix == Mix_vec[i] & output$EIR == EIR_vec[1]),{ + plot(x = year, y = prev2to10, type = "l", col = colorBlindBlack8[1], ylim = c(0,0.35), yaxt = "n", xaxs = "i", yaxs = "i", ylab = Ylab_vec[i], xlab = Xlab_vec[i]) + if(i ==1){axis(side = 2, at = seq(0,0.4,by=0.1))} + title(gsub("(^[[:alpha:]])", "\\U\\1", Mix_vec[i], perl=TRUE), line = -1.5) + + }) + for(j in 2:3){ + with(subset(output,output$mix == Mix_vec[i] & output$EIR == EIR_vec[j]), points(x = year, y = prev2to10, type = "l", col = colorBlindBlack8[j])) + } + } + par(fig=c(0.9,1,0,1), cex = 0.8, new = T, xpd = T, mai = c(0,0,0,0)) + legend("left", legend = EIR_vec, col = colorBlindBlack8[1:3], bty = "n", lty = 1, title = "EIR") +} + +Plot_Mixing(output) + ``` From 21a8e811906da993295690251e73f8d5bfe25012 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Mon, 20 Feb 2023 10:26:32 +0000 Subject: [PATCH 013/164] changed y axis label on plot --- vignettes/Metapopulation.Rmd | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vignettes/Metapopulation.Rmd b/vignettes/Metapopulation.Rmd index 18af806b..31692ad1 100644 --- a/vignettes/Metapopulation.Rmd +++ b/vignettes/Metapopulation.Rmd @@ -129,16 +129,17 @@ Mix_vec <- unique(output$mix) EIR_vec <- unique(output$EIR) Xlab_vec <- c("","Time (years)","") -Ylab_vec <- c("PfPR 2-10 (months)","","") +Ylab_vec <- c(expression(paste(italic(Pf),"PR"[2-10])),"","") New_vec <- c(F,T,T) Plot_Mixing <- function(output){ for(i in 1:3){ par(fig=Panel_spec[i,], cex = 0.8, mai = Margin_spec[i,], new = New_vec[i]) with(subset(output,output$mix == Mix_vec[i] & output$EIR == EIR_vec[1]),{ - plot(x = year, y = prev2to10, type = "l", col = colorBlindBlack8[1], ylim = c(0,0.35), yaxt = "n", xaxs = "i", yaxs = "i", ylab = Ylab_vec[i], xlab = Xlab_vec[i]) + plot(x = year, y = prev2to10, type = "l", col = colorBlindBlack8[1], ylim = c(0,0.36), yaxt = "n", xaxs = "i", yaxs = "i", ylab = Ylab_vec[i], xlab = Xlab_vec[i]) if(i ==1){axis(side = 2, at = seq(0,0.4,by=0.1))} title(gsub("(^[[:alpha:]])", "\\U\\1", Mix_vec[i], perl=TRUE), line = -1.5) + abline(h = 0.325) }) for(j in 2:3){ From b08b8b29304158b5952c2d4f72ae94e3ad64a480 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Mon, 20 Feb 2023 10:41:58 +0000 Subject: [PATCH 014/164] ggplot figure changed to base r figure --- vignettes/Treatment.Rmd | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/vignettes/Treatment.Rmd b/vignettes/Treatment.Rmd index 3986c202..f64af7e5 100644 --- a/vignettes/Treatment.Rmd +++ b/vignettes/Treatment.Rmd @@ -15,7 +15,6 @@ knitr::opts_chunk$set( ``` ```{r setup} -suppressPackageStartupMessages(library(ggplot2)) library(malariasimulation) library(malariaEquilibrium) ``` @@ -58,7 +57,20 @@ df <- do.call('rbind', lapply(seq_along(outputs), function(i) { df })) -ggplot(df) + geom_line( - aes(x = timestep, y = (n_detect_730_3650/n_730_3650), colour = ft)) + - labs(x = "timestep", y = "PfPR2-10") +colorBlindBlack8 <- c("#000000", "#E69F00", "#56B4E9", "#009E73", + "#F0E442", "#0072B2", "#D55E00", "#CC79A7") + +Treatment_plot_function <- function(df){ + par(fig=c(0,0.9,0,1), cex = 0.8, mai = c(0.8,0.8,0.3,0.1)) + with(df[df$ft==unique(df$ft)[1],], expr = plot(x = timestep, y = n_detect_730_3650/n_730_3650, type = "l", + xlab = "Days", ylab = expression(paste(italic(Pf),"PR"[2-10])), + ylim = c(min(df$n_detect_730_3650/df$n_730_3650),max(df$n_detect_730_3650/df$n_730_3650)), col = colorBlindBlack8[1])) + invisible(sapply(2:length(unique(df$ft)), function(x){ + with(df[df$ft==unique(df$ft)[x],], expr = points(x = timestep, y = n_detect_730_3650/n_730_3650, type = "l", col = colorBlindBlack8[x])) +})) + par(fig=c(0.9,1,0,1), cex = 0.8, new = T, xpd = T, mai = c(0,0,0,0)) + legend("right", legend = unique(df$ft), col = colorBlindBlack8, bty = "n", lty = 1, title = "Coverage") +} + +Treatment_plot_function(df) ``` From 7053390ca7805cf409b9c8fd08642b0bb063e21b Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Mon, 20 Feb 2023 17:20:36 +0000 Subject: [PATCH 015/164] Changing to base R plotting, updating language, adding examples --- vignettes/Vaccines.Rmd | 217 ++++++++++++++++++++++++++++------------- 1 file changed, 149 insertions(+), 68 deletions(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 6e75b950..4936e81f 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -15,8 +15,71 @@ knitr::opts_chunk$set( ``` ```{r setup} -suppressPackageStartupMessages(library(ggplot2)) library(malariasimulation) +library(dplyr) + +cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", + "#F0E442", "#0072B2", "#D55E00", "#CC79A7") +``` + +# Plotting functions +```{r} +# Plotting clinical incidence +plot_inci <- function(xtext = 1 - 0.1, ytext = 4){ + output$clinical_incidence <- 1000 * output$n_inc_0_1825 / output$n_0_1825 + output$time_year <- output$timestep / year + + plot(x = output$time_year, y = output$clinical_incidence, + type = 'l', col = cols[3], + xlab = 'Time (years)', ylab = 'Clinical incidence (per 1000 children aged 0-5)', + xaxs = "i", yaxs = "i", bty = "l") + abline(v = 1, col = cols[7], lty = 2, lwd = 2.5) + curve_values <- loess(clinical_incidence ~ time_year, data = output, span = 0.3, method = 'loess') + lines(output$time_year, predict(curve_values), + col = cols[6], + lwd = 3) + text(x = xtext, y = ytext, 'Vaccination', + cex = 1, col = cols[1], srt = 90) +} + +# Plot parasite prevalence +plot_prev <- function(xtext = 1 - 0.1, ytext = 0.44){ + output$time_year <- output$timestep / year + + plot(x = output$time_year, y = output$n_detect_730_3650/output$n_730_3650, + type = 'l', col = cols[4], + xlab = 'Time (years)', ylab = expression(paste(italic(Pf),"PR"[2-10])), + xaxs = "i", yaxs = "i", bty = "l") + abline(v = 1, col = cols[7], lty = 2, lwd = 2.5) + text(x = xtext, y = ytext, 'Vaccination', + cex = 1, col = cols[1], srt = 90) +} + +plot_doses <- function(){ + if(any(names(output) == 'n_rtss_epi_dose_1')) { + doses <- output |> + select(timestep, n_rtss_epi_dose_1:n_rtss_epi_booster_1) |> + pivot_longer(n_rtss_epi_dose_1:n_rtss_epi_booster_1, names_to = "dose", values_to = "count") |> + mutate(month = ceiling(timestep / month)) |> + group_by(month, dose) |> + summarize(count = sum(count)) + } else if (any(names(output) == 'n_rtss_mass_dose_1')) { + doses <- output |> + select(timestep, n_rtss_mass_dose_1:n_rtss_mass_booster_1) |> + pivot_longer(n_rtss_mass_dose_1:n_rtss_mass_booster_1, names_to = "dose", values_to = "count") |> + mutate(month = ceiling(timestep / month)) |> + group_by(month, dose) |> + summarize(count = sum(count)) + } + + plot(x = doses$month, y = doses$count, type = 'h', + lwd = 10, lend=1, ylim = c(0,max(doses$count + 500)), + col = c(cols[6], cols[7],cols[8],cols[5]), + xlab = 'Time (months)', ylab = 'Doses (n)', + xaxs = "i", yaxs = "i", bty = "l") + text(x = max(doses$month[doses$count!=0])-1, y =500, 'Booster', + cex = 1, col = cols[1], srt = 90) +} ``` # Parameterisation @@ -39,58 +102,46 @@ simparams <- get_parameters(list( ) simparams <- set_equilibrium(simparams, starting_EIR) - ``` -Then we can run the simulation for a variety of Vaccination strategies: +Then we can run the simulation for a variety of vaccination strategies for RTS,S: ## Mass RTS,S -This is a round of RTS,S vaccine for individuals between 5 months and 10 years followed by a booster after 18 months: +This is a single round of RTS,S vaccine given in a mass vaccination strategy for individuals between 5 months and 10 years, followed by a booster after 12 months: ```{r} rtssparams <- simparams rtssparams <- set_mass_rtss( rtssparams, - timesteps = 1 * year, - coverages = 1, - min_wait = 0, - min_ages = 5 * month, - max_ages = 10 * year, - boosters = 18 * month, - booster_coverage = 0.95 + timesteps = 1 * year, # The single round of vaccination is at 1 year into the simulation. + coverages = 1, # The vaccine is given to 100% of the population between the specified ages. + min_wait = 0, # The minimum acceptable time since the last vaccination is 0. + min_ages = 5 * month, # The minimum age for the target population to be vaccinated. + max_ages = 10 * year, # The maximum age for the target population to be vaccinated. + boosters = 12 * month, # The booster is given at 12 months after the initial vaccination. + booster_coverage = 0.95 # Coverage of the booster dose is 95%. ) output <- run_simulation(sim_length, rtssparams) -output$clinical_incidence <- 1000 * output$n_inc_0_1825 / output$n_0_1825 - -ggplot(data = output, aes(x = timestep / 365, y = clinical_incidence)) + - geom_line(col = "grey80") + - stat_smooth(col = "darkblue", se = FALSE) + - geom_vline(xintercept = 1, col = "red") + - xlab("year") + - ylab("Clinical incidence \n (per 1000 children aged 0-5)") + - theme_bw() +``` +# Plot clinical incidence and prevalence +```{r, fig.show='hold', fig.align='center'} +plot_inci() +plot_prev() ``` -You can look at the distribution of doses using the n_rtss_mass_dose\_\* outputs: +You can look at the distribution of doses using the `n_rtss_mass_dose\_\*` or `n_rtss_epi_dose\_\*` outputs. It is always a good idea to check the timing of vaccine doses to ensure that it is specified as intended. ```{r} -dose_data <- data.frame(timestep = output$timestep, - dose = rep(c("mass 1", "mass 2", "mass 3", "mass booster"), each = length(output$timestep)), - n = c(output$n_rtss_mass_dose_1, output$n_rtss_mass_dose_2, output$n_rtss_mass_dose_3, - output$n_rtss_mass_booster_1)) -dose_data[dose_data$n > 0, ] - +plot_doses() ``` ## RTS,S EPI -You can opt for a more gradual dosing using the EPI strategy. -Individuals will be vaccinated once they reach 5 months. For this intervention -we see a much more gradual increase in impact following implementation +You can opt for a more gradual dosing using the EPI strategy. In the example below, individuals will be vaccinated once they reach 5 months of age. For this intervention, we see a much more gradual increase in impact following implementation. ```{r} rtssepiparams <- simparams @@ -98,30 +149,31 @@ rtssepiparams <- simparams # Add RTS,S strategy rtssepiparams <- set_rtss_epi( rtssepiparams, - timesteps = 1 * year, - coverages = 1, - min_wait = 0, - age = 5 * month, - boosters = 18 * month, - booster_coverage = 0.95 + timesteps = 1 * year, # Vaccination will begin at 1 year. + coverages = 1, # Vaccine coverage is 100%. + min_wait = 0, # There is no minimum wait since the last vaccination. + age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. + boosters = 12 * month, # The booster is administered 12 months following the initial vaccination. + booster_coverage = 0.95 # 95% of those vaccinated with the primary series will be boosted. ) output <- run_simulation(sim_length * 2, rtssepiparams) -output$clinical_incidence <- 1000 * output$n_inc_0_1825 / output$n_0_1825 +``` -ggplot(data = output, aes(x = timestep / 365, y = clinical_incidence)) + - geom_line(col = "grey80") + - stat_smooth(col = "darkblue", se = FALSE) + - geom_vline(xintercept = 1, col = "red") + - xlab("year") + - ylab("Clinical incidence \n (per 1000 children aged 0-5)") + - theme_bw() +# Plot clinical incidence and prevalence +```{r, fig.show='hold', fig.align='center'} +plot_inci() +plot_prev(ytext = 0.51) ``` +```{r} +plot_doses() +``` + + ## RTS,S seasonal boosters -In a seasonal setting, we can set booster timesteps relative to the start of the year. -This allows us to target seasonal dynamics +In a seasonal setting, we can set booster timesteps relative to the start of the year. This allows us to target seasonal dynamics. ```{r} rtssepiseasonalparams <- simparams @@ -129,44 +181,70 @@ rtssepiseasonalparams$model_seasonality = TRUE rtssepiseasonalparams$g0 = 0.28605 rtssepiseasonalparams$g = c(0.20636, -0.0740318, -0.0009293) rtssepiseasonalparams$h = c(0.173743, -0.0730962, -0.116019) -peak <- peak_season_offset(rtssepiseasonalparams) +# Calculate the peak of the transmission season based on seasonality parameters above. +peak <- peak_season_offset(rtssepiseasonalparams) # Add RTS,S seasonal strategy rtssepiseasonalparams <- set_rtss_epi( rtssepiseasonalparams, - timesteps = 1 * year, - coverages = 1, - min_wait = 6 * month, - age = 5 * month, - boosters = (peak - 3 * month) + c(0, year), - booster_coverage = rep(.7, 2), + timesteps = 1 * year, # Vaccination begins 1 year after the start of the simulation. + coverages = 1, # Vaccine coverage is 100%. + min_wait = 6 * month, # When seasonal_boosters = TRUE, this is the minimum time between an individual receiving the final dose and the first booster. + age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. + boosters = round(c(12 * month + 2 * month)), # There is one booster, a year and 2 months after the final dose of the primary series. + booster_coverage = c(.7), # 70% of the vaccinated population is boosted. seasonal_boosters = TRUE ) + +output <- run_simulation(sim_length * 2, rtssepiseasonalparams) +``` + +# Plot clinical incidence and prevalence +```{r, fig.show='hold', fig.align='center'} +plot_inci(ytext = 15) +plot_prev(ytext = 0.51) +``` + + +```{r} +plot_doses() ``` ## RTS,S dosing -You can try different dosing schedules using the rtss_doses parameter +You can try different dosing schedules using the `rtss_doses` parameter. As before, it is a good idea to visualise the timing of the vaccination strategy to ensure that you have implemented it as intended. ```{r} rtssepiparams2 <- rtssepiparams -rtssepiparams2$rtss_doses <- c(0, 30, 60) +rtssepiparams2$rtss_doses <- c(0, 30, 60) # setting the timesteps for the 3 doses in the primary series at 0, 1, 2 months + rtssepiparams2 <- set_rtss_epi( rtssepiparams2, timesteps = 1 * year, coverages = 1, age = 5 * month, min_wait = 0, - boosters = c(12 * month, 18 * month, 24 * month), - booster_coverage = c(1, 1, 1) + boosters = c(12 * month, 24 * month), # Here, we are testing a strategy with 2 boosters. + booster_coverage = c(1, 1) ) + +output <- run_simulation(sim_length * 2, rtssepiparams2) ``` +# Plot clinical incidence and prevalence +```{r, fig.show='hold', fig.align='center'} +plot_inci(ytext = 6) +plot_prev(ytext = 0.52) +``` + +```{r} +plot_doses() +``` + + ## TBV -We can also model vaccines with completely different modes of actions. For example -a transmission blocking vaccines (TBV). This example shows 5 rounds of the TBV -to everyone aged over 5 +We can also model vaccines with completely different modes of actions. For example, a transmission blocking vaccine (TBV). This example shows 5 rounds of a TBV to everyone aged 5 years or older. ```{r} tbvparams <- simparams @@ -179,14 +257,17 @@ tbvparams <- set_tbv( ) output <- run_simulation(sim_length, tbvparams) -output$clinical_incidence <- 1000 * output$n_inc_0_1825 / output$n_0_1825 +``` + +# Plot clinical incidence and prevalence +```{r, fig.show='hold', fig.align='center'} +plot_inci(ytext = 15) +plot_prev(ytext = 0.51) +``` -ggplot(data = output, aes(x = timestep / 365, y = clinical_incidence)) + - geom_line(col = "grey80") + - stat_smooth(col = "darkblue", se = FALSE) + - geom_vline(xintercept = 1, col = "red") + - xlab("year") + - ylab("Clinical incidence \n (per 1000 children aged 0-5)") + - theme_bw() +You can look at the distribution of doses using the `n_rtss_mass_dose\_\*` outputs. It is always a good idea to check the timing of vaccine doses to ensure that it is specified as intended. + +```{r} +plot_doses() ``` From 8939ec3f9a7762ec3b719f323a1616ed208bcf95 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Mon, 20 Feb 2023 17:43:43 +0000 Subject: [PATCH 016/164] Improve plot rendering --- vignettes/Vaccines.Rmd | 73 ++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 4936e81f..388cff1c 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -17,6 +17,7 @@ knitr::opts_chunk$set( ```{r setup} library(malariasimulation) library(dplyr) +library(tidyr) cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") @@ -127,15 +128,19 @@ rtssparams <- set_mass_rtss( output <- run_simulation(sim_length, rtssparams) ``` -# Plot clinical incidence and prevalence -```{r, fig.show='hold', fig.align='center'} +### Plot clinical incidence +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_inci() -plot_prev() ``` +### Plot prevalence +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +plot_prev() +``` +### Plot doses You can look at the distribution of doses using the `n_rtss_mass_dose\_\*` or `n_rtss_epi_dose\_\*` outputs. It is always a good idea to check the timing of vaccine doses to ensure that it is specified as intended. -```{r} +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_doses() ``` @@ -160,13 +165,19 @@ rtssepiparams <- set_rtss_epi( output <- run_simulation(sim_length * 2, rtssepiparams) ``` -# Plot clinical incidence and prevalence -```{r, fig.show='hold', fig.align='center'} + +### Plot clinical incidence +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_inci() -plot_prev(ytext = 0.51) ``` -```{r} +### Plot prevalence +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +plot_prev() +``` + +### Plot doses +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_doses() ``` @@ -199,14 +210,19 @@ rtssepiseasonalparams <- set_rtss_epi( output <- run_simulation(sim_length * 2, rtssepiseasonalparams) ``` -# Plot clinical incidence and prevalence -```{r, fig.show='hold', fig.align='center'} -plot_inci(ytext = 15) -plot_prev(ytext = 0.51) + +### Plot clinical incidence +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +plot_inci() ``` +### Plot prevalence +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +plot_prev() +``` -```{r} +### Plot doses +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_doses() ``` @@ -231,13 +247,19 @@ rtssepiparams2 <- set_rtss_epi( output <- run_simulation(sim_length * 2, rtssepiparams2) ``` -# Plot clinical incidence and prevalence -```{r, fig.show='hold', fig.align='center'} -plot_inci(ytext = 6) -plot_prev(ytext = 0.52) + +### Plot clinical incidence +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +plot_inci() ``` -```{r} +### Plot prevalence +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +plot_prev() +``` + +### Plot doses +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_doses() ``` @@ -259,15 +281,12 @@ tbvparams <- set_tbv( output <- run_simulation(sim_length, tbvparams) ``` -# Plot clinical incidence and prevalence -```{r, fig.show='hold', fig.align='center'} -plot_inci(ytext = 15) -plot_prev(ytext = 0.51) +### Plot clinical incidence +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +plot_inci() ``` - -You can look at the distribution of doses using the `n_rtss_mass_dose\_\*` outputs. It is always a good idea to check the timing of vaccine doses to ensure that it is specified as intended. - -```{r} -plot_doses() +### Plot prevalence +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +plot_prev() ``` From f527f1d1201574592f3de08c70626d8f402b5e7d Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Tue, 21 Feb 2023 09:47:01 +0000 Subject: [PATCH 017/164] Corrected error in matrix for set_spraying, updated plots --- vignettes/VectorControl.Rmd | 4 ++-- vignettes/VectorControl_IRS.Rmd | 40 ++++++++++++--------------------- 2 files changed, 16 insertions(+), 28 deletions(-) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index 2f5dff91..e43bf83f 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -72,7 +72,7 @@ add_intervention_lines <- function(plot, events) { Then we can run the simulation for a variety of bednet strategies. In the example below, we distribute bednets once a year for two years, changing the characteristics of the bed nets for each distribution. -```{r} +```{r, fig.align='center', fig.height=4, fig.width=6} bednetparams <- simparams bednet_events = data.frame( @@ -108,7 +108,7 @@ The average population bednet usage will be influenced by: The output from `malariasimulation::run_simulation()` has a variable that shows the number of people using bednets at any given timestep. We can visualise this to understand how bednet usage changes over time. -```{r} +```{r, fig.align='center', fig.height=4, fig.width=6} output$prop_use_net <- output$n_use_net / human_population plot(x = output$timestep, y = output$prop_use_net, type = 'l', col = cols[1], diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index ce794b0a..e6a8a740 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -71,7 +71,7 @@ add_intervention_lines <- function(plot, events) { ## Adding indoor residual spraying (IRS) Then we can run the simulation for a variety of IRS strategies. In the example below, there are two rounds of IRS, each 3 months prior to peak transmission for that year. -```{r} +```{r, fig.align='center', fig.height=4, fig.width=6} sprayingparams <- simparams peak <- peak_season_offset(sprayingparams) @@ -101,7 +101,7 @@ add_intervention_lines(plot_prevalence(output), spraying_events) It is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. If you have specified more than 1 species, then the arguments for `set_spraying()` and `set_bednets()` must be populated with values for each species at each time point. We will run the same model with IRS as above, but this time with 3 species of mosquitoes. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. Each column corresponds to a species of mosquito, and each row corresponds to the timestep when a round of IRS occurred. Here, we are assuming the same values for each species at each timepoint for simplicity, but the matrix could be edited to have different values by species or over time. -```{r} +```{r, fig.align='center', fig.height=4, fig.width=6} # Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae simparams <- set_species( simparams, @@ -121,30 +121,18 @@ sprayingparams <- set_spraying( sprayingparams, timesteps = spraying_events$timestep, coverages = rep(.8, 2), # # Each round covers 80% of the population - ls_theta = matrix(c(rep(2.025, sim_length/year), - rep(2.025, sim_length/year), - rep(2.025, sim_length/year), - nrow=sim_length/year, ncol=3)), # Matrix of mortality parameters - ls_gamma = matrix(c(rep(-0.009, sim_length/year), - rep(-0.009, sim_length/year), - rep(-0.009, sim_length/year)), - nrow=sim_length/year, ncol=3), # Matrix of mortality parameters per timestep - ks_theta = matrix(c(rep(-2.222, sim_length/year), - rep(-2.222, sim_length/year), - rep(-2.222, sim_length/year)), - nrow=sim_length/year, ncol=3), # Matrix of feeding success parameters - ks_gamma = matrix(c(rep(0.008, sim_length/year), - rep(0.008, sim_length/year), - rep(0.008, sim_length/year)), - nrow=sim_length/year, ncol=3), # Matrix of feeding success parameters per timestep - ms_theta = matrix(c(rep(-1.232, sim_length/year), - rep(-1.232, sim_length/year), - rep(-1.232, sim_length/year)), - nrow=sim_length/year, ncol=3), # Matrix of deterrence parameters - ms_gamma = matrix(c(rep(-0.009, sim_length/year), - rep(-0.009, sim_length/year), - rep(-0.009, sim_length/year)), - nrow=sim_length/year, ncol=3) # Matrix of deterrence parameters per timestep + ls_theta = matrix(c(rep(2.025, length(spraying_events$timestep))), + nrow=length(spraying_events$timestep), ncol=3), # Matrix of mortality parameters; nrows=length(timesteps), ncols=length(species) + ls_gamma = matrix(c(rep(-0.009, length(spraying_events$timestep))), + nrow=length(spraying_events$timestep), ncol=3), # Matrix of mortality parameters per timestep + ks_theta = matrix(c(rep(-2.222, length(spraying_events$timestep))), + nrow=length(spraying_events$timestep), ncol=3), # Matrix of feeding success parameters + ks_gamma = matrix(c(rep(0.008, length(spraying_events$timestep))), + nrow=length(spraying_events$timestep), ncol=3), # Matrix of feeding success parameters per timestep + ms_theta = matrix(c(rep(-1.232, length(spraying_events$timestep))), + nrow=length(spraying_events$timestep), ncol=3), # Matrix of deterrence parameters + ms_gamma = matrix(c(rep(-0.009, length(spraying_events$timestep))), + nrow=length(spraying_events$timestep), ncol=3) # Matrix of deterrence parameters per timestep ) output <- run_simulation(sim_length, sprayingparams) From 8095e0796939ecc2e8c4cdcc3265309ed93322a9 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Tue, 21 Feb 2023 10:06:47 +0000 Subject: [PATCH 018/164] Updating plot rendering --- vignettes/Variation.Rmd | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index 1a68eaf5..a6213471 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -19,14 +19,14 @@ cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", plot_n_detect <- function(output){ plot(x = output$timestep, y = output$n_detect_730_3650, type = 'l', col = cols[4], - xlab = 'Time (days)', ylab = "Cases detected in children aged 2-10 years", + xlab = 'Time (days)', ylab = "Cases detected in children \naged 2-10 years", xaxs = "i", yaxs = "i", bty = "l") } plot_p_detect <- function(output){ plot(x = output$timestep, y = output$p_detect_730_3650, type = 'l', col = cols[4], - xlab = 'Time (days)', ylab = "Sum of probabilities of case detection in children aged 2-10 years", + xlab = 'Time (days)', ylab = "Sum of probabilities of case detection\nin children aged 2-10 years", xaxs = "i", yaxs = "i", bty = "l") } ``` @@ -34,7 +34,7 @@ plot_p_detect <- function(output){ Malariasimulation is a stochastic model, so there will be be variation in model outputs. To illustrate this, we could compare the prevalence of malaria cases over a year in simulations with a small and a larger population. -```{r} +```{r, fig.align='center',fig.height=6, fig.width=9} # A small population params <- get_parameters(list( human_population = 1000, @@ -62,17 +62,15 @@ plot_p_detect(big_pop) title('p_detect at n = 10,000') ``` -The n_detect output shows the result of sampling individuals who would be detected by microscopy. +The `n_detect` output shows the result of sampling individuals who would be detected by microscopy, while the `p_detect` output shows the sum of probabilities of detection in the population. -While the p_detect output shows the sum of probabilities of detection in the population. - -Notice that the p_detect output is slightly smoother. That's because it forgoes the sampling step. At low population sizes, p_detect will be smoother than the n_detect counterpart. +Notice that the `p_detect` output is slightly smoother. This is because it forgoes the sampling step, so at low population sizes, `p_detect` will be smoother than its `n_detect` counterpart. ## Estimating variation We can estimate the variation in the number of detectable cases by repeating the simulation several times and plotting the IQR and 95% confidence intervals. -```{r} +```{r, fig.align='center',fig.height=4, fig.width=8} outputs <- run_simulation_with_repetitions( timesteps = 365, repetitions = 10, @@ -98,28 +96,33 @@ df <- aggregate( df <- data.frame(cbind(timestep = df$Group.1, df$x)) +# Plot the IQR and 95% CI par(mfrow = c(1,2)) xx <- c(df$timestep, rev(df$timestep)) yy <- c(df$lowq, rev(df$highq)) plot(x = df$timestep, y = df$median, - type = 'n', xlim = c(-1,365),ylim = c(510,565), + type = 'n', xlim = c(-1,365),ylim = c(500,565), xlab = 'Time (days)', ylab = "Cases detected in children aged 2-10 years", xaxs = "i", yaxs = "i", bty = "l") polygon(xx, yy, col = 'grey90', border= 'grey95') lines(x = df$timestep, y = df$median, col = cols[4], lwd = 2) title('IQR spread') +legend('bottom', legend = c('Median','IQR Spread'), col = c(cols[4],'grey90'), + lwd = 5, xpd = TRUE, horiz = TRUE, cex = 1, seg.len=1, bty = 'n') xx <- c(df$timestep, rev(df$timestep)) yy <- c(df$lowci, rev(df$highci)) plot(x = df$timestep, y = df$mean, - type = 'n', xlim = c(-1,365),ylim = c(490,590), + type = 'n', xlim = c(-1,365),ylim = c(460,600), xlab = 'Time (days)', ylab = "Cases detected in children aged 2-10 years", xaxs = "i", yaxs = "i", bty = "l") polygon(xx, yy, col = 'grey90', border= 'grey95') lines(x = df$timestep, y = df$mean, col = cols[4], lwd = 2) title('95% Confidence interval') +legend('bottom', inset = 0, legend = c('Mean','95% CI'), col = c(cols[4],'grey90'), + lwd = 5, xpd = TRUE, horiz = TRUE, cex = 1, seg.len=1, bty = 'n') ``` -These are useful techniques for comparing the expected variance from model outputs to outcomes from trials that had lower population sizes. \ No newline at end of file +These are useful techniques for comparing the expected variance from model outputs to outcomes from trials that might have had lower population sizes. \ No newline at end of file From b212c2858b32617df24b4527dfd658411485b6d4 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 23 Feb 2023 11:41:08 +0000 Subject: [PATCH 019/164] Improved explanations and plots --- vignettes/Variation.Rmd | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index a6213471..6e16b845 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -11,7 +11,11 @@ vignette: > library(malariasimulation) ``` -First we will create a few plotting functions to visualise outputs. +## Variation in outputs + +Malariasimulation is a stochastic model, meaning that randomness is incorporated, so there will be be variation in model outputs. To illustrate this, we could compare the prevalence of malaria over a year in simulations with a small and a larger population. + +### First we will create a few plotting functions to visualise outputs. ```{r} cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") @@ -19,21 +23,23 @@ cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", plot_n_detect <- function(output){ plot(x = output$timestep, y = output$n_detect_730_3650, type = 'l', col = cols[4], - xlab = 'Time (days)', ylab = "Cases detected in children \naged 2-10 years", + xlab = 'Time (days)', ylab = "Cases detected in children aged 2-10 years", xaxs = "i", yaxs = "i", bty = "l") } plot_p_detect <- function(output){ plot(x = output$timestep, y = output$p_detect_730_3650, type = 'l', col = cols[4], - xlab = 'Time (days)', ylab = "Sum of probabilities of case detection\nin children aged 2-10 years", + xlab = 'Time (days)', ylab = "Sum of probabilities of case detection \nin children aged 2-10 years", xaxs = "i", yaxs = "i", bty = "l") } ``` -## Variation in outputs -Malariasimulation is a stochastic model, so there will be be variation in model outputs. To illustrate this, we could compare the prevalence of malaria cases over a year in simulations with a small and a larger population. +### Simulations +The `n_detect` output below shows the result of sampling individuals who would have cases of malaria that were detected by microscopy, while the `p_detect` output shows the sum of individual probabilities of detection of malaria in the population. + +Notice that the `p_detect` output is slightly smoother. This is because it forgoes the sampling step, so at low population sizes, `p_detect` will be smoother than its `n_detect` counterpart. ```{r, fig.align='center',fig.height=6, fig.width=9} # A small population params <- get_parameters(list( @@ -62,9 +68,6 @@ plot_p_detect(big_pop) title('p_detect at n = 10,000') ``` -The `n_detect` output shows the result of sampling individuals who would be detected by microscopy, while the `p_detect` output shows the sum of probabilities of detection in the population. - -Notice that the `p_detect` output is slightly smoother. This is because it forgoes the sampling step, so at low population sizes, `p_detect` will be smoother than its `n_detect` counterpart. ## Estimating variation From 19b3a7997490e9e0be6cf2be0c9252ef1796957d Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 23 Feb 2023 12:39:43 +0000 Subject: [PATCH 020/164] add legends to inci and prev plots. half done with doses plot updates --- vignettes/Vaccines.Rmd | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 388cff1c..aac28006 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -26,7 +26,7 @@ cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", # Plotting functions ```{r} # Plotting clinical incidence -plot_inci <- function(xtext = 1 - 0.1, ytext = 4){ +plot_inci <- function(){ output$clinical_incidence <- 1000 * output$n_inc_0_1825 / output$n_0_1825 output$time_year <- output$timestep / year @@ -39,12 +39,11 @@ plot_inci <- function(xtext = 1 - 0.1, ytext = 4){ lines(output$time_year, predict(curve_values), col = cols[6], lwd = 3) - text(x = xtext, y = ytext, 'Vaccination', - cex = 1, col = cols[1], srt = 90) + legend('topright', box.lty = 0, legend = 'Vaccination',col = cols[7], lty = 2, lwd = 2.5) } # Plot parasite prevalence -plot_prev <- function(xtext = 1 - 0.1, ytext = 0.44){ +plot_prev <- function(){ output$time_year <- output$timestep / year plot(x = output$time_year, y = output$n_detect_730_3650/output$n_730_3650, @@ -52,27 +51,43 @@ plot_prev <- function(xtext = 1 - 0.1, ytext = 0.44){ xlab = 'Time (years)', ylab = expression(paste(italic(Pf),"PR"[2-10])), xaxs = "i", yaxs = "i", bty = "l") abline(v = 1, col = cols[7], lty = 2, lwd = 2.5) - text(x = xtext, y = ytext, 'Vaccination', - cex = 1, col = cols[1], srt = 90) + legend('topright', box.lty = 0, legend = 'Vaccination',col = cols[7], lty = 2, lwd = 2.5) } plot_doses <- function(){ if(any(names(output) == 'n_rtss_epi_dose_1')) { doses <- output |> - select(timestep, n_rtss_epi_dose_1:n_rtss_epi_booster_1) |> - pivot_longer(n_rtss_epi_dose_1:n_rtss_epi_booster_1, names_to = "dose", values_to = "count") |> + select(timestep, starts_with('n_rtss_epi')) |> + pivot_longer(starts_with('n_rtss_epi'), names_to = "dose", values_to = "count") |> mutate(month = ceiling(timestep / month)) |> group_by(month, dose) |> - summarize(count = sum(count)) + summarize(count = sum(count)) |> + pivot_wider(names_from = dose, values_from = count) + + barplot(doses$n_rtss_epi_dose_1, doses$month, col = cols[6], + xlab = 'Time (months)', ylab = 'Doses (n)') + barplot(doses$n_rtss_epi_dose_2, doses$month, add = TRUE, col = cols[7]) + barplot(doses$n_rtss_epi_dose_3, doses$month, add = TRUE, col = cols[8]) + barplot(doses$n_rtss_epi_booster_1, doses$month, add = TRUE, col = cols[5]) + } else if (any(names(output) == 'n_rtss_mass_dose_1')) { doses <- output |> - select(timestep, n_rtss_mass_dose_1:n_rtss_mass_booster_1) |> - pivot_longer(n_rtss_mass_dose_1:n_rtss_mass_booster_1, names_to = "dose", values_to = "count") |> + select(timestep, starts_with('n_rtss_mass')) |> + pivot_longer(starts_with('n_rtss_mass'), names_to = "dose", values_to = "count") |> mutate(month = ceiling(timestep / month)) |> group_by(month, dose) |> - summarize(count = sum(count)) + summarize(count = sum(count)) |> + pivot_wider(names_from = dose, values_from = count) + + barplot(doses$n_rtss_mass_dose_1,doses$month, col = cols[6], + xlab = 'Time (months)', ylab = 'Doses (n)') + barplot(doses$n_rtss_mass_dose_2, doses$month, add = TRUE, col = cols[7]) + barplot(doses$n_rtss_mass_dose_3, doses$month, add = TRUE, col = cols[8]) + barplot(doses$n_rtss_mass_booster_1, doses$month, add = TRUE, col = cols[5]) + } + plot(x = doses$month, y = doses$count, type = 'h', lwd = 10, lend=1, ylim = c(0,max(doses$count + 500)), col = c(cols[6], cols[7],cols[8],cols[5]), @@ -80,6 +95,7 @@ plot_doses <- function(){ xaxs = "i", yaxs = "i", bty = "l") text(x = max(doses$month[doses$count!=0])-1, y =500, 'Booster', cex = 1, col = cols[1], srt = 90) + # legend('topright', box.lty = 0, legend = 'Vaccination',col = cols[7], lty = 2, lwd = 2.5) } ``` From 33fc4d5704d0719d6411afd1a142e1e0693a7f15 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 23 Feb 2023 12:44:22 +0000 Subject: [PATCH 021/164] replacing labels with legend --- vignettes/VectorControl.Rmd | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index e43bf83f..52ff7ace 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -58,13 +58,12 @@ plot_prevalence <- function(output) { type = 'l', col = cols[4], xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), xaxs = "i", yaxs = "i", bty = "l") + legend('topright', box.lty = 0, legend = 'Bednets',col = cols[7], lty = 2, lwd = 2.5) } add_intervention_lines <- function(plot, events) { plot - abline(v = events$timestep, lty = 2, lwd = 2.5) - text(x = events$timestep - 20, y = 0.4, events$name, - cex = 1, col = cols[1], srt = 90) + abline(v = events$timestep, col = cols[7], lty = 2, lwd = 2.5) } ``` From 3b950c25763cbb76bd23b5952f2f8e708ed4f652 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 23 Feb 2023 12:53:53 +0000 Subject: [PATCH 022/164] Simplified plotting function. removed "events". --- vignettes/VectorControl.Rmd | 20 +++++++------------- vignettes/VectorControl_IRS.Rmd | 31 +++++++++++-------------------- 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index 52ff7ace..cdb4262b 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -55,16 +55,12 @@ cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", # Plotting functions plot_prevalence <- function(output) { plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, - type = 'l', col = cols[4], + type = 'l', col = cols[4], lwd = 2.5, xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), xaxs = "i", yaxs = "i", bty = "l") + abline(v = bednetstimesteps, col = cols[7], lty = 2, lwd = 2.5) legend('topright', box.lty = 0, legend = 'Bednets',col = cols[7], lty = 2, lwd = 2.5) } - -add_intervention_lines <- function(plot, events) { - plot - abline(v = events$timestep, col = cols[7], lty = 2, lwd = 2.5) -} ``` ## Adding bednets @@ -74,14 +70,11 @@ Then we can run the simulation for a variety of bednet strategies. In the exampl ```{r, fig.align='center', fig.height=4, fig.width=6} bednetparams <- simparams -bednet_events = data.frame( - timestep = c(1, 2) * year, # The bednets will be distributed at the end of the first and the second year. - name=c("Bednets 1", "Bednets 2") # These are labels for the two distributions. -) +bednetstimesteps <- c(1, 2) * year # The bednets will be distributed at the end of the first and the second year. bednetparams <- set_bednets( bednetparams, - timesteps = bednet_events$timestep, + timesteps = bednetstimesteps, coverages = c(.8, .8), # Each round is distributed to 80% of the population retention = 5 * year, # Nets are kept on average 5 years dn0 = matrix(c(.533, .45), nrow=2, ncol=1), # Matrix of death probabilities for each mosquito species over time @@ -110,8 +103,9 @@ The output from `malariasimulation::run_simulation()` has a variable that shows ```{r, fig.align='center', fig.height=4, fig.width=6} output$prop_use_net <- output$n_use_net / human_population -plot(x = output$timestep, y = output$prop_use_net, type = 'l', col = cols[1], - xlab = 'Timestep (days)', ylab = 'Proportion using bednets', +plot(x = output$timestep, y = output$prop_use_net, type = 'l', + col = cols[4], lwd = 2.5, + xlab = 'Timestep (days)', ylab = 'Proportion of population using bednets', xaxs = "i", yaxs = "i", bty = "l") ``` diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index e6a8a740..0f27e3c5 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -53,18 +53,13 @@ cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") # Plotting functions -plot_prevalence <- function(output) { +plot_prev <- function(output) { plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, - type = 'l', col = cols[4], + type = 'l', col = cols[4], lwd = 2.5, xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), xaxs = "i", yaxs = "i", bty = "l") -} - -add_intervention_lines <- function(plot, events) { - plot - abline(v = events$timestep, lty = 2, lwd = 2.5) - text(x = events$timestep - 20, y = 0.4, events$name, - cex = 1, col = cols[1], srt = 90) + abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = cols[7]) + legend('topright', box.lty = 0, legend = 'Spraying',col = cols[7], lty = 2, lwd = 2.5) } ``` @@ -75,14 +70,12 @@ Then we can run the simulation for a variety of IRS strategies. In the example b sprayingparams <- simparams peak <- peak_season_offset(sprayingparams) -spraying_events = data.frame( - timestep = c(1, 2) * year + peak - 3 * month, # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. - name=c("Spraying 1", "Spraying 2") # These are labels for the two rounds of IRS -) + +sprayingtimesteps <- c(1, 2) * year + peak - 3 * month # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. sprayingparams <- set_spraying( sprayingparams, - timesteps = spraying_events$timestep, + timesteps = sprayingtimesteps, coverages = rep(.8, 2), # # Each round covers 80% of the population ls_theta = matrix(c(2.025, 2.025), nrow=2, ncol=1), # Matrix of mortality parameters ls_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1), # Matrix of mortality parameters per timestep @@ -94,7 +87,7 @@ sprayingparams <- set_spraying( output <- run_simulation(sim_length, sprayingparams) -add_intervention_lines(plot_prevalence(output), spraying_events) +plot_prev(output) ``` ## Additional species @@ -112,14 +105,12 @@ simparams <- set_species( sprayingparams <- simparams peak <- peak_season_offset(sprayingparams) -spraying_events = data.frame( - timestep = c(1, 2) * year + peak - 3 * month, # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. - name=c("Spraying 1", "Spraying 2") # These are labels for the two rounds of IRS -) + +sprayingtimesteps <- c(1, 2) * year + peak - 3 * month # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. sprayingparams <- set_spraying( sprayingparams, - timesteps = spraying_events$timestep, + timesteps = sprayingtimesteps, coverages = rep(.8, 2), # # Each round covers 80% of the population ls_theta = matrix(c(rep(2.025, length(spraying_events$timestep))), nrow=length(spraying_events$timestep), ncol=3), # Matrix of mortality parameters; nrows=length(timesteps), ncols=length(species) From c5c320998c432c627d25aa02b68375221efc8f9a Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 23 Feb 2023 14:25:24 +0000 Subject: [PATCH 023/164] fixing legends and plots --- vignettes/Vaccines.Rmd | 65 +++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index aac28006..67abbfc8 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -61,14 +61,16 @@ plot_doses <- function(){ pivot_longer(starts_with('n_rtss_epi'), names_to = "dose", values_to = "count") |> mutate(month = ceiling(timestep / month)) |> group_by(month, dose) |> - summarize(count = sum(count)) |> - pivot_wider(names_from = dose, values_from = count) + summarize(count = sum(count)) |> ungroup() |> + pivot_wider(names_from = dose, values_from = count) %>% + select(-month) %>% t %>% as.matrix() - barplot(doses$n_rtss_epi_dose_1, doses$month, col = cols[6], - xlab = 'Time (months)', ylab = 'Doses (n)') - barplot(doses$n_rtss_epi_dose_2, doses$month, add = TRUE, col = cols[7]) - barplot(doses$n_rtss_epi_dose_3, doses$month, add = TRUE, col = cols[8]) - barplot(doses$n_rtss_epi_booster_1, doses$month, add = TRUE, col = cols[5]) + barplot(doses, xlab = "Month", + ylab = 'Number of doses', + col = cols[2:7], + beside = FALSE) + legend('topleft', box.lty = 0, legend = c('Booster 1','Dose 1','Dose 2','Dose 3'), + col = cols[2:7], lty = rep(1, 4), lwd = 2.5) } else if (any(names(output) == 'n_rtss_mass_dose_1')) { doses <- output |> @@ -76,26 +78,17 @@ plot_doses <- function(){ pivot_longer(starts_with('n_rtss_mass'), names_to = "dose", values_to = "count") |> mutate(month = ceiling(timestep / month)) |> group_by(month, dose) |> - summarize(count = sum(count)) |> - pivot_wider(names_from = dose, values_from = count) + summarize(count = sum(count)) |> ungroup() |> + pivot_wider(names_from = dose, values_from = count) %>% + select(-month) %>% t %>% as.matrix() - barplot(doses$n_rtss_mass_dose_1,doses$month, col = cols[6], - xlab = 'Time (months)', ylab = 'Doses (n)') - barplot(doses$n_rtss_mass_dose_2, doses$month, add = TRUE, col = cols[7]) - barplot(doses$n_rtss_mass_dose_3, doses$month, add = TRUE, col = cols[8]) - barplot(doses$n_rtss_mass_booster_1, doses$month, add = TRUE, col = cols[5]) - + barplot(doses, xlab = "Month", + ylab = 'Number of doses', + col = cols[2:7], + beside = FALSE) + legend('topleft', box.lty = 0, legend = c('Booster 1','Dose 1','Dose 2','Dose 3'), + col = cols[2:7], lty = rep(1, 4), lwd = 2.5) } - - - plot(x = doses$month, y = doses$count, type = 'h', - lwd = 10, lend=1, ylim = c(0,max(doses$count + 500)), - col = c(cols[6], cols[7],cols[8],cols[5]), - xlab = 'Time (months)', ylab = 'Doses (n)', - xaxs = "i", yaxs = "i", bty = "l") - text(x = max(doses$month[doses$count!=0])-1, y =500, 'Booster', - cex = 1, col = cols[1], srt = 90) - # legend('topright', box.lty = 0, legend = 'Vaccination',col = cols[7], lty = 2, lwd = 2.5) } ``` @@ -183,17 +176,17 @@ output <- run_simulation(sim_length * 2, rtssepiparams) ### Plot clinical incidence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} plot_inci() ``` ### Plot prevalence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} plot_prev() ``` ### Plot doses -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} plot_doses() ``` @@ -228,17 +221,17 @@ output <- run_simulation(sim_length * 2, rtssepiseasonalparams) ### Plot clinical incidence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} plot_inci() ``` ### Plot prevalence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} plot_prev() ``` ### Plot doses -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} plot_doses() ``` @@ -265,17 +258,17 @@ output <- run_simulation(sim_length * 2, rtssepiparams2) ### Plot clinical incidence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} plot_inci() ``` ### Plot prevalence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} plot_prev() ``` ### Plot doses -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} plot_doses() ``` @@ -298,11 +291,11 @@ output <- run_simulation(sim_length, tbvparams) ``` ### Plot clinical incidence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} plot_inci() ``` ### Plot prevalence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} plot_prev() ``` From 10dad758c6ac9d0abc7ef1ca7d6e4b0ec52a5fb2 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 23 Feb 2023 16:01:36 +0000 Subject: [PATCH 024/164] fixing legend positions --- vignettes/Vaccines.Rmd | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 67abbfc8..e3a26c89 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -70,7 +70,7 @@ plot_doses <- function(){ col = cols[2:7], beside = FALSE) legend('topleft', box.lty = 0, legend = c('Booster 1','Dose 1','Dose 2','Dose 3'), - col = cols[2:7], lty = rep(1, 4), lwd = 2.5) + col = cols[2:7], lty = rep(1, 4), lwd = 2.5,bg="transparent") } else if (any(names(output) == 'n_rtss_mass_dose_1')) { doses <- output |> @@ -86,8 +86,8 @@ plot_doses <- function(){ ylab = 'Number of doses', col = cols[2:7], beside = FALSE) - legend('topleft', box.lty = 0, legend = c('Booster 1','Dose 1','Dose 2','Dose 3'), - col = cols[2:7], lty = rep(1, 4), lwd = 2.5) + legend('topleft', box.lty = 0, legend = c('Booster 1','Dose 1','Dose 2','Dose 3'), + col = cols[2:7], lty = rep(1, 4), lwd = 2.5,bg="transparent") } } ``` @@ -176,17 +176,17 @@ output <- run_simulation(sim_length * 2, rtssepiparams) ### Plot clinical incidence -```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_inci() ``` ### Plot prevalence -```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_prev() ``` ### Plot doses -```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_doses() ``` @@ -221,17 +221,17 @@ output <- run_simulation(sim_length * 2, rtssepiseasonalparams) ### Plot clinical incidence -```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_inci() ``` ### Plot prevalence -```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_prev() ``` ### Plot doses -```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_doses() ``` @@ -258,17 +258,17 @@ output <- run_simulation(sim_length * 2, rtssepiparams2) ### Plot clinical incidence -```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_inci() ``` ### Plot prevalence -```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_prev() ``` ### Plot doses -```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_doses() ``` @@ -291,11 +291,11 @@ output <- run_simulation(sim_length, tbvparams) ``` ### Plot clinical incidence -```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_inci() ``` ### Plot prevalence -```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_prev() ``` From 32cd998c2739fd7fac6b90372962e232d4503529 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Thu, 23 Feb 2023 17:38:11 +0000 Subject: [PATCH 025/164] Improved model vignette, round 1 --- vignettes/Model.Rmd | 280 ++++++++--- vignettes/Model_human.svg | 774 ++++++++++++++++++++++++++++++ vignettes/Model_mos_figure.svg | 849 +++++++++++++++++++++++++++++++++ 3 files changed, 1830 insertions(+), 73 deletions(-) create mode 100644 vignettes/Model_human.svg create mode 100644 vignettes/Model_mos_figure.svg diff --git a/vignettes/Model.Rmd b/vignettes/Model.Rmd index f83e48ac..672f43c2 100644 --- a/vignettes/Model.Rmd +++ b/vignettes/Model.Rmd @@ -1,5 +1,7 @@ --- title: "Model Structure" +header-includes: + -\usepackage{svg} output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Model Structure} @@ -10,90 +12,222 @@ vignette: > ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, - comment = "#>" + comment = "#>", + dev="svglite" ) ``` -```{r setup} -library(DiagrammeR) -``` - This is an individual based model for P. Falciparum and malaria interventions. -# Human Biology +## Human Biology -The human variables are documented in "R/variables.R". +The human variables are documented in [R/variables.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/variables.R). The human biological processes are spread out between the following files: - 1. 'human_infection.R' (orange) - 2. 'disease_progression.R' (green) - 3. 'mortality_processes.R'(red) - -```{r echo=FALSE} -DiagrammeR::grViz("digraph { - graph [layout = dot, rankdir = LR] - - node [shape = rectangle] - S - D - A - U - Tr - - node [shape = circle] - i [label = ''] - - # edge definitions with the node IDs - S -> i [color='orange'] - i -> D [color='orange'] - i -> A [color='orange'] - i -> Tr [color='orange'] - D -> A -> U -> S [color='green'] - Tr -> s [color='green'] - A -> i [color='orange'] - U -> i [color='orange'] - U -> S [color='red'] - A -> S [color='red'] - D -> S [color='red'] - }") -``` + 1. [R/human_infection.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/human_infection.R) + 2. [R/disease_progression.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/disease_progression.R) + 3. [R/mortality_processes.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/mortality_processes.R) + + + + + +### States +Modelled human states are Susceptible (*S*), Treated (*Tr*), Clinical disease (*D*), Asymptomatic infection (*A*) and Sub-patent infection (*U*). + +### Parameters +Parameters shown on the infographic include: the force of infection ($\Lambda_i$), the probability of clinical disease ($\phi_i$), the probability of receiving treatment ($f_T$), and rates of recovery from clinical disease to asymptomatic infection ($r_D$), asymptomatic infection to sub-patent infection ($r_A$), sub-patent infection and treated disease to complete recovery ($r_T$ and $r_U$). Superinfection may occur in individuals with asymptomatic or sub-patent infections at the same rates as standard infection (dashed arrows). + +Details that determine the force of infection can be found ***elsewhere: give links to resources***. All default parameters can be found using [get_parameters()](https://mrc-ide.github.io/malariasimulation/reference/get_parameters.html) where the rate parameters shown here represent delays are input into the model by first converting to duration in days, e.g. for the input `dr`, $dr = \frac{1}{r_D}$. + +To maintain a constant population size during simulations, the birth rate of new susceptible individuals is set to be equal to the overall death rate. -# Mosquito Biology +***Could give explicit equations*** + +***Could give defaults for parameters specified*** + +***Could explain how lambda is given*** + +## Mosquito Biology The mosquito biological processes are spread out between the following files: - 1. 'src/mosquito_ode.cpp' (green) - 2. 'src/mosquito_emergence.cpp' (green) - 3. 'R/mosquito_biology.R' (orange) - 4. 'R/mosquito_biology.R' (red) - -```{r echo=FALSE} -DiagrammeR::grViz("digraph { - graph [layout = dot, rankdir = LR] - - subgraph clusterode { - style=filled; - color=lightblue; - node [shape = rectangle] - E - L - P - label='ODE' - } - - node [shape = rectangle] - Sm - Pm - Im - NonExistent - - # edge definitions with the node IDs - E -> L -> P [color='green', label='1'] - P -> Sm [color='green', label='2'] - Sm -> Pm -> Im [color='orange', label='3'] - Sm -> NonExistent [color='red', label='4'] - Pm -> NonExistent [color='red', label='4'] - Im -> NonExistent [color='red', label='4'] - }") + 1. [src/mosquito_ode.cpp]() ***Can't find a file with this name*** + 2. [src/mosquito_emergence.cpp]() ***Can't find a file with this name***'' + 3. [R/mosquito_biology.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/mosquito_biology.R) + + + +### States +Modelled mosquito states are separated into early (*E*) and late (*L*) larval stages, the pupal stage (*P*) and three adult states for susceptible (*Sm*), incubating (*Pm*) and infectious individuals (*Im*). + +### Parameters +Parameters shown on the infographic include: mosquito developmental rates from early to late larval stages ($r_{EL}$), to the pupal stage ($r_{L}$) and to adult stage ($r_P$). Susceptible adults (*Sm*) may become infected (***These rates are not clear to me and it would be good to add these to the model infographic and to this text***) with a latent period (*Pm*) before becoming infectious (*Im*). Larval and pupal stages die at a rate of $\mu_p$ while adults die at a density dependent rate of $\mu_m$, where they then enter the *NonExistent* state. ***I need to read up on this density dependence.*** + +***Density dependence of mosquito deaths*** + +***Could show how these models are connected together in a bit more detail*** + +\ + +# Basic simulation + +### Simulation code +The key package function is `run_simulation()` which, in its most basic form, simply requires a number of timesteps in days. Default parameter settings assume a population of size of 100 with no treatment interventions ***what are other default settings?***, and which can be seen in full using [get_parameters()](https://mrc-ide.github.io/malariasimulation/reference/get_parameters.html). + +```{r, output.lines=6} +library(malariasimulation) +Test_Sim <- run_simulation(timesteps = 100) +``` + + +### Output +The model then simulates a malaria epidemic and returns key outputs such as: + +- `infectivity`: human infectiousness +- `EIR_All`: the entomological inoculation rate +- `FOIM`: the force of mosquito infection +- `mu_All`: adult mosquito death rate ***Why is this important? isn't this just mu_m? I suppose it's density dependent. Look into this in more detail*** +- `n_bitten`: the number of infectious bites +- `n_infections`: the number human infections +- `natural_deaths`: deaths from old age +- `S_count`, `A_count`, `D_count`, `U_count`, `Tr_count`: the human population size in each state +- `ica_mean`: mean acquired immunity to clinical infection +- `icm_mean`: mean maternal immunity to clinical infection +- `ib_mean`: mean blood immunity to all infection +- `id_mean`: mean immunity from detected using microscopy +- `iva_mean`: mean acquired immunity to severe infection +- `ivm_mean`: mean maternal immunity to severe infection +- `n_730_3650`: population size of an age group of interest (where the default is set to 730-3650 days old, or 2-10 years, but which may be adjusted (see [Demography](https://mrc-ide.github.io/malariasimulation/articles/Demography.html) vignette for more details) +- `n_detect_730_3650`: number with possible detection through microscopy of a given age group +- `p_detect_730_3650`: the sum of probabilities of detection through microscopy of a given age group +- `E_All_count`, `L_All_count`, `P_All_count`, `Sm_All_count`, `Pm_All_count`, `Im_All_count`, `NonExistent_All_count`: mosquito population sizes in each state +- `mosquito_deaths`: mosquito deaths + + +```{r, output.lines=6} +head(Test_Sim, n = 3) ``` + +### Additional outputs +**Age stratified** results for **incidence**, **clinical incidence** and **severe case incidence** may also be included in the output if desired and must be specified in the parameter list (see [get_parameters()](https://mrc-ide.github.io/malariasimulation/reference/get_parameters.html) for more details and [Demography](https://mrc-ide.github.io/malariasimulation/articles/Demography.html) for an example). These inputs will add extra columns to the output for the number of infections (**`n_`**) and the sum of probabilities of infection (**`p_`**) for the relevant total, clinical or severe incidences for each specified age group. + +Where **treatments** are specified, `n_treated` will report the number that have received treatment. Where **bed nets** are distributed, `net_usage` specifies the number sleeping under a bednet. + +***`rate_D_A`, `rate_A_U`, `rate_U_S`*** These are found in the help page for `run_simulation()` How are these output??? + + +### Output visualisation +These outputs can then be visualised, such as the population changes in states. Another key output is the prevalence of detectable infections between the ages of 2-10 (*Pf*PR~2-10~), which can be obtained by dividing `n_detect_730_3650` by `n_730_3650`. + +```{r, out.width = "45%", echo = FALSE} +cols_to_plot <- paste0(c("S","A","D","U","Tr"),"_count") +Rich_cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") +states_plot <- function(){ + plot(x = Test_Sim$timestep, y = Test_Sim[,cols_to_plot[1]], type = "l", col = Rich_cols[1], ylim = c(0,80), ylab = "Population size", xlab = "Days") + sapply(2:5, function(x){points(x = Test_Sim$timestep, y = Test_Sim[,cols_to_plot[x]], type = "l", col = Rich_cols[x])}) + legend("topleft", legend = c("S","A","D","U","Tr"), col = Rich_cols, lty = 1, bty = "n", ncol = 5) +} + +states_plot() +plot(x = Test_Sim$timestep, y = Test_Sim$n_detect_730_3650/Test_Sim$n_730_3650, type = "l", col = Rich_cols[7], ylim = c(0,1), ylab = expression(paste(italic(Pf),"PR"[2-10])), xlab = "Days") +``` + + +\ + +# Changing parameters + +## Vignettes + +The remaining vignettes describe how to adjust sets of parameters through a number of functions as follows: + +1. [Population demography](https://mrc-ide.github.io/malariasimulation/articles/Demography.html) + + - rendering age groups + - `set_demography()`: setting demographies + - `set_equilibrium()`: establishing initial human and mosquito populations to achieve initial equilibrium conditions + - ***Possibly include `find_birthrates`.*** + +\ + +2. Mosquito related functions + + - Modelling mosquito seasonality, + - IBM or ODE modelling of mosquitoes, + - `set_species()`: for species specific parameters (with in-built parameter sets) + - ***Possibly include *** - parameterise_mosquito_equilibrium??? + - parameterise_total_M??? + +\ + +3. [Treatment](https://mrc-ide.github.io/malariasimulation/articles/Treatment.html) + + - `set_drugs()`: for drug-specific parameters (with in-built parameter sets) + - `set_clinical_treatment()`: implemention of clinical treatment interventions + +\ + +4. [MDA and chemoprevention](https://mrc-ide.github.io/malariasimulation/articles/MDA.html) + + - `set_mda()`: implemention of mass drug administration interventions + - `set_smc()`: implementation of seasonal malarial chemoprevention interventions + - `set_pmc()`: implementation of perrenial malarial chemoprevention interventions + - `peak_season_offset()`: correlating timed intervetions with seasonal malaria + +\ + +5. [Vaccines](https://mrc-ide.github.io/malariasimulation/articles/Vaccines.html) + + - `set_mass_rtss()`: implementation of a rtss vaccination intervention + - `set_tbv()`: implementation of a tbv vaccination intervention + +\ + +6. [Vector Control](https://mrc-ide.github.io/malariasimulation/articles/VectorControl.html) + + - `set_bednets()`: implementation of bednet distribution intervention + - `set_spraying()`: implementation of an indoor residual spraying intervention + +\ + +7. [Matching PfPR2-10 to EIR](https://mrc-ide.github.io/malariasimulation/articles/EIRprevmatch.html) + + - ***Need to work out what this is doing and why*** + - malariaEquilibrium::human equilibrium (Is there anything else from this package that would be useful to describe?). Also, links to package information??? + - set an equilibrium (set_equilibrium) + +\ + +8. [Metapopulation modelling](https://mrc-ide.github.io/malariasimulation/articles/Metapopulation.html) + + - `run_metapop_simulation()`: to model multiple areas simulateously + +\ + +9. [Variation](https://mrc-ide.github.io/malariasimulation/articles/Variation.html) + + - `run_simulation_with_repetitions()`: running simulations with replicates + +\ + +## Changing other parameters + +It is not recommended that parameters are adjusted without using these functions without close and detailed attention, but if this is necessary, any parameter may be changed using the `overrides` argument in the `get_parameters()` function. The `get_parameters()` function generates a complete parameter set that may be fed into `run_simulation()`. New parameters must be in the same class as the parameters they replace (e.g. if the parameter is a numeric, its replacement must also be numeric, if logical, the replacement must also be logical) and inputs must be given as a list. An example is given below. + +This simple example shows how to change the human population size. The parameter name for human population size is `human_population`. +```{r} +# Use get_parameters(overrides = list(...))) to set new parameters +new_params <- get_parameters(overrides = list(human_population = 200)) +``` + + + +### +***Which parameters don't get addressed in the vignettes? What do these parameters do?*** +Correlation_Parameters +find_birthrates() +get_correlation_parameters() +parameterise_mosquito_equilibrium() +parameterise_total_M() \ No newline at end of file diff --git a/vignettes/Model_human.svg b/vignettes/Model_human.svg new file mode 100644 index 00000000..be311bdb --- /dev/null +++ b/vignettes/Model_human.svg @@ -0,0 +1,774 @@ + + + + + + + + + + %0 + + + + S + + S + + + + i + + + + + S->i + + + Λ + + i + + + + D + + D + + + + A + + A + + + + D->A + + + r + D + + + + U + + U + + + + A->U + + + r + A + + + + A:sw->i:se + + + Λ + + i + + + + U:w->S:s + + + r + U + + + + U->i:s + + + Λ + + i + + + + Tr + + Tr + + + + Tr:w->S:n + + + r + T + + + + i->D + + + ϕ + i + (1-f + T + ) + + + + i->A + + + 1-ϕ + i + + + + i->Tr + + + ϕ + i + f + T + + + + %0 + + + + y2 + Infection + "human_infection.R" + + + + y4 + Superinfection + "human_infection.R" + + + + g2 + Disease progression + "disease_progression.R" + + + + y1 + + + + y1->y2 + + + + + + y3 + + + + y1->y3 + + + + y3->y4 + + + + + + g1 + + + + y3->g1 + + + + g1->g2 + + + + + diff --git a/vignettes/Model_mos_figure.svg b/vignettes/Model_mos_figure.svg new file mode 100644 index 00000000..3e174868 --- /dev/null +++ b/vignettes/Model_mos_figure.svg @@ -0,0 +1,849 @@ + + + + + + + + + + + + + + + %0 + + + NonExistent + + NonExistent + Adultmosquitoes + Juvenilemosquitoes + + + + P + + P + + + + NonExistent->P + + + µ + p + + + + L + + L + + + + NonExistent->L + + + µ + p + + + + E + + E + + + + NonExistent->E + + + µ + p + + + + Im + + Im + + + + NonExistent->Im + + + µ + m + + + + Pm + + Pm + + + + NonExistent->Pm + + + µ + m + + + + Sm + + Sm + + + + NonExistent->Sm + + + µ + m + + + + P->Sm + + + r + P + + + + L->P + + + r + L + + + + E->L + + + r + EL + + + + Im->E + + + + Pm->Im + + + ???? + + ???? + + + + Sm->Pm + + + ???? + + ???? + + + + %0 + + + + g2 + Development + + + + y2 + Infection + + + + r2 + Mortality + + + + y1 + + + + y1->y2 + + + + + + r1 + + + + y1->r1 + + + + r1->r2 + + + + + + g1 + + + + g1->g2 + + + + + + g1->y1 + + + From 93bbec41e13ae3a2a403c2112132421e095eff58 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Mon, 27 Feb 2023 15:21:00 +0000 Subject: [PATCH 026/164] Update labels/order on doses plot, adding explanations --- vignettes/Vaccines.Rmd | 96 ++++++++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 40 deletions(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index e3a26c89..4561fea2 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -7,14 +7,16 @@ vignette: > %\VignetteEncoding{UTF-8} --- -```{r, include = FALSE} +```{r, include = FALSE, message=FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` -```{r setup} +You may want to add a malaria vaccine to your simulation. It is possible to model the RTS,S vaccine or a theoretical transmission blocking vaccine through both a routine EPI strategy or a mass vaccination strategy using the helper functions `set_rtss_epi()`, `set_mass_rtss()` or `set_tbv()`. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the peak of malaria prevalence given by `peak_season_offset()`. + +```{r setup, message=FALSE} library(malariasimulation) library(dplyr) library(tidyr) @@ -23,7 +25,8 @@ cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") ``` -# Plotting functions +### Plotting functions +First, we will define a few functions to make plotting easier. ```{r} # Plotting clinical incidence plot_inci <- function(){ @@ -64,12 +67,12 @@ plot_doses <- function(){ summarize(count = sum(count)) |> ungroup() |> pivot_wider(names_from = dose, values_from = count) %>% select(-month) %>% t %>% as.matrix() - + doses <- doses[c(2,3,4,1),] barplot(doses, xlab = "Month", ylab = 'Number of doses', col = cols[2:7], beside = FALSE) - legend('topleft', box.lty = 0, legend = c('Booster 1','Dose 1','Dose 2','Dose 3'), + legend('topleft', box.lty = 0, legend = c('Dose 1','Dose 2','Dose 3','Booster 1'), col = cols[2:7], lty = rep(1, 4), lwd = 2.5,bg="transparent") } else if (any(names(output) == 'n_rtss_mass_dose_1')) { @@ -81,21 +84,20 @@ plot_doses <- function(){ summarize(count = sum(count)) |> ungroup() |> pivot_wider(names_from = dose, values_from = count) %>% select(-month) %>% t %>% as.matrix() - + doses <- doses[c(2,3,4,1),] barplot(doses, xlab = "Month", ylab = 'Number of doses', col = cols[2:7], beside = FALSE) - legend('topleft', box.lty = 0, legend = c('Booster 1','Dose 1','Dose 2','Dose 3'), + legend('topleft', box.lty = 0, legend = c('Dose 1','Dose 2','Dose 3','Booster 1'), col = cols[2:7], lty = rep(1, 4), lwd = 2.5,bg="transparent") } } ``` -# Parameterisation - -We are going to set the default parameters to run the simulation from an equilibrium. +## Parameterisation +We will set the default parameters to run the simulation from an equilibrium. ```{r} year <- 365 month <- 30 @@ -118,7 +120,7 @@ Then we can run the simulation for a variety of vaccination strategies for RTS,S ## Mass RTS,S -This is a single round of RTS,S vaccine given in a mass vaccination strategy for individuals between 5 months and 10 years, followed by a booster after 12 months: +First, we will model a single round of RTS,S vaccine given in a mass vaccination strategy where those within a given age range will be vaccinated to a specified coverage level and during a short window of time. In this example, individuals aged between 5 months and 10 years are vaccinated with a primary series, then a booster 12 months after the initial vaccination. The age groups to be vaccinated as well as timing of all vaccinations can be modified within the `set_mass_rtss()` function. ```{r} rtssparams <- simparams @@ -137,25 +139,25 @@ rtssparams <- set_mass_rtss( output <- run_simulation(sim_length, rtssparams) ``` -### Plot clinical incidence +#### Plot clinical incidence ```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_inci() ``` -### Plot prevalence +#### Plot prevalence ```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_prev() ``` -### Plot doses -You can look at the distribution of doses using the `n_rtss_mass_dose\_\*` or `n_rtss_epi_dose\_\*` outputs. It is always a good idea to check the timing of vaccine doses to ensure that it is specified as intended. -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +#### Plot doses +You can look at the distribution of doses using the `n_rtss_mass_dose_*` or `n_rtss_epi_dose_*` outputs. It is always a good idea to check the timing of vaccine doses to ensure that it is specified as intended. +```{r, fig.width = 6, fig.height = 4, fig.align = 'center', message=FALSE} plot_doses() ``` -## RTS,S EPI +### RTS,S EPI -You can opt for a more gradual dosing using the EPI strategy. In the example below, individuals will be vaccinated once they reach 5 months of age. For this intervention, we see a much more gradual increase in impact following implementation. +You can also opt to vaccinate using the EPI strategy, where individuals will be vaccinated once they reach a certain age. In the example below, individuals will be vaccinated once they reach 5 months of age. For this intervention, we see a much more gradual impact following implementation. ```{r} rtssepiparams <- simparams @@ -175,26 +177,25 @@ output <- run_simulation(sim_length * 2, rtssepiparams) ``` -### Plot clinical incidence +#### Plot clinical incidence ```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_inci() ``` -### Plot prevalence +#### Plot prevalence ```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_prev() ``` -### Plot doses -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +#### Plot doses +```{r, fig.width = 6, fig.height = 4, fig.align = 'center', message=FALSE} plot_doses() ``` -## RTS,S seasonal boosters - -In a seasonal setting, we can set booster timesteps relative to the start of the year. This allows us to target seasonal dynamics. +### RTS,S seasonal boosters +In a seasonal setting, we can set booster timesteps relative to the start of the year instead of relative to the last dose. This allows us to target seasonal dynamics. ```{r} rtssepiseasonalparams <- simparams rtssepiseasonalparams$model_seasonality = TRUE @@ -211,7 +212,7 @@ rtssepiseasonalparams <- set_rtss_epi( coverages = 1, # Vaccine coverage is 100%. min_wait = 6 * month, # When seasonal_boosters = TRUE, this is the minimum time between an individual receiving the final dose and the first booster. age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. - boosters = round(c(12 * month + 2 * month)), # There is one booster, a year and 2 months after the final dose of the primary series. + boosters = peak - month * 3.5 , # Because seasonal_boosters = TRUE, the timestep here is relative to the start of the year. Here, we will give a booster at 3.5 months prior to peak transmission. booster_coverage = c(.7), # 70% of the vaccinated population is boosted. seasonal_boosters = TRUE ) @@ -220,27 +221,27 @@ output <- run_simulation(sim_length * 2, rtssepiseasonalparams) ``` -### Plot clinical incidence +#### Plot clinical incidence ```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_inci() ``` -### Plot prevalence +#### Plot prevalence ```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_prev() ``` -### Plot doses -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +#### Plot doses +```{r, fig.width = 6, fig.height = 4, fig.align = 'center', message=FALSE} plot_doses() ``` -## RTS,S dosing +### RTS,S dosing You can try different dosing schedules using the `rtss_doses` parameter. As before, it is a good idea to visualise the timing of the vaccination strategy to ensure that you have implemented it as intended. ```{r} -rtssepiparams2 <- rtssepiparams +rtssepiparams2 <- simparams rtssepiparams2$rtss_doses <- c(0, 30, 60) # setting the timesteps for the 3 doses in the primary series at 0, 1, 2 months rtssepiparams2 <- set_rtss_epi( @@ -257,23 +258,38 @@ output <- run_simulation(sim_length * 2, rtssepiparams2) ``` -### Plot clinical incidence +#### Plot clinical incidence ```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_inci() ``` -### Plot prevalence +#### Plot prevalence ```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_prev() ``` -### Plot doses -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} -plot_doses() +#### Plot doses +```{r, fig.width = 6, fig.height = 4, fig.align = 'center', message=FALSE} +doses <- output |> + select(timestep, starts_with('n_rtss_epi')) |> + pivot_longer(starts_with('n_rtss_epi'), names_to = "dose", values_to = "count") |> + mutate(month = ceiling(timestep / month)) |> + group_by(month, dose) |> + summarize(count = sum(count)) |> ungroup() |> + pivot_wider(names_from = dose, values_from = count) %>% + select(-month) %>% t %>% as.matrix() +doses <- doses[c(3:5,1,2),] + +barplot(doses, xlab = "Month", + ylab = 'Number of doses', + col = cols[2:7], + beside = FALSE) +legend('topleft', box.lty = 0, legend = c('Dose 1','Dose 2','Dose 3','Booster 1','Booster 2'), + col = cols[2:7], lty = rep(1, 4), lwd = 2.5,bg="transparent") ``` -## TBV +### TBV We can also model vaccines with completely different modes of actions. For example, a transmission blocking vaccine (TBV). This example shows 5 rounds of a TBV to everyone aged 5 years or older. @@ -290,12 +306,12 @@ tbvparams <- set_tbv( output <- run_simulation(sim_length, tbvparams) ``` -### Plot clinical incidence +#### Plot clinical incidence ```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_inci() ``` -### Plot prevalence +#### Plot prevalence ```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} plot_prev() ``` From 7a674631406e8d893c3a69c21fbfe24c797e2be5 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Mon, 27 Feb 2023 15:51:53 +0000 Subject: [PATCH 027/164] Adding explanations, fixing bullet points, small editorial changes --- vignettes/VectorControl.Rmd | 24 ++++++++++++++---------- vignettes/VectorControl_IRS.Rmd | 27 ++++++++++++--------------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index cdb4262b..da7242f2 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -19,7 +19,9 @@ library(malariasimulation) library(malariaEquilibrium) ``` -# Parameterisation +Bednets can be incorporated into the simulations, with various timings and coverage and in settings with specified proportions of mosquito species. + +### Parameterisation We will set the default parameters to run the simulation from an equilibrium. @@ -47,6 +49,7 @@ simparams <- get_parameters( simparams <- set_equilibrium(simparams, starting_EIR) ``` +### Plotting functions We can create a few plotting functions to visualise the output. ```{r} cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", @@ -85,19 +88,19 @@ bednetparams <- set_bednets( output <- run_simulation(sim_length, bednetparams) -add_intervention_lines(plot_prevalence(output), bednet_events) +plot_prevalence(output) ``` +## Visualising bednet usage It is important to understand the difference between the input `coverages` argument of `malariasimulation::set_bednets()` and the resulting population bednet usage over time in the model. In the above example, bednets are distributed to 80% of the population at each distribution round. -The average population bednet usage will be influenced by: -* The size and frequency of distributions specified in `set_bednets()` -* The assumed net retention half life -* Correlations in the recipients of nets between rounds - -### Visualising bednet usage +The average population bednet usage will be influenced by: +* The size and frequency of distributions specified in `set_bednets()` +* The assumed net retention half life +* Correlations in the recipients of nets between rounds + The output from `malariasimulation::run_simulation()` has a variable that shows the number of people using bednets at any given timestep. We can visualise this to understand how bednet usage changes over time. ```{r, fig.align='center', fig.height=4, fig.width=6} @@ -113,7 +116,8 @@ plot(x = output$timestep, y = output$prop_use_net, type = 'l', The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool to help set up bednets in `malariasimulation`. `malariasimulation` takes as input the proportion of the population who were distributed a bednet at specific time points, but available data for a specific region or country do not always have this information. `netz` allows for simple conversions between bednet metrics like crop, access, distribution, and usage. -See the vignettes from the `netz` package that explain these concepts more comprehensively: -* [This vignette](https://mrc-ide.github.io/netz/articles/overview.html) explains how to estimate the distribution coverage from a specified bednet usage. +See the vignettes from the `netz` package that explain these concepts more comprehensively: + +* [This vignette](https://mrc-ide.github.io/netz/articles/overview.html) explains how to estimate the distribution coverage from a specified bednet usage. * [This vignette](https://mrc-ide.github.io/netz/articles/population_usage.html) demonstrates how to estimate population bednet usage from input distribution. diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index 0f27e3c5..aaaa2411 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -19,7 +19,9 @@ library(malariasimulation) library(malariaEquilibrium) ``` -# Parameterisation +We can add indoor residual spraying (IRS) as an intervention in the model with different timings and coverages and in settings with specified proportions of mosquito species with the help of the `set_spraying()` function. + +### Parameterisation We will set the default parameters to run the simulation from an equilibrium. @@ -47,6 +49,7 @@ simparams <- get_parameters( simparams <- set_equilibrium(simparams, starting_EIR) ``` +### Plotting functions We can create a few plotting functions to visualise the output. ```{r} cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", @@ -95,7 +98,7 @@ It is possible to account for varying proportions of mosquito species in the set We will run the same model with IRS as above, but this time with 3 species of mosquitoes. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. Each column corresponds to a species of mosquito, and each row corresponds to the timestep when a round of IRS occurred. Here, we are assuming the same values for each species at each timepoint for simplicity, but the matrix could be edited to have different values by species or over time. ```{r, fig.align='center', fig.height=4, fig.width=6} -# Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae +## Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae simparams <- set_species( simparams, species = list(arab_params, fun_params, gamb_params), @@ -112,21 +115,15 @@ sprayingparams <- set_spraying( sprayingparams, timesteps = sprayingtimesteps, coverages = rep(.8, 2), # # Each round covers 80% of the population - ls_theta = matrix(c(rep(2.025, length(spraying_events$timestep))), - nrow=length(spraying_events$timestep), ncol=3), # Matrix of mortality parameters; nrows=length(timesteps), ncols=length(species) - ls_gamma = matrix(c(rep(-0.009, length(spraying_events$timestep))), - nrow=length(spraying_events$timestep), ncol=3), # Matrix of mortality parameters per timestep - ks_theta = matrix(c(rep(-2.222, length(spraying_events$timestep))), - nrow=length(spraying_events$timestep), ncol=3), # Matrix of feeding success parameters - ks_gamma = matrix(c(rep(0.008, length(spraying_events$timestep))), - nrow=length(spraying_events$timestep), ncol=3), # Matrix of feeding success parameters per timestep - ms_theta = matrix(c(rep(-1.232, length(spraying_events$timestep))), - nrow=length(spraying_events$timestep), ncol=3), # Matrix of deterrence parameters - ms_gamma = matrix(c(rep(-0.009, length(spraying_events$timestep))), - nrow=length(spraying_events$timestep), ncol=3) # Matrix of deterrence parameters per timestep + ls_theta = matrix(2.025, nrow=length(sprayingtimesteps), ncol=3), # Matrix of mortality parameters; nrows=length(timesteps), ncols=length(species) + ls_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=3), # Matrix of mortality parameters per timestep + ks_theta = matrix(-2.222, nrow=length(sprayingtimesteps), ncol=3), # Matrix of feeding success parameters + ks_gamma = matrix(0.008, nrow=length(sprayingtimesteps), ncol=3), # Matrix of feeding success parameters per timestep + ms_theta = matrix(-1.232, nrow=length(sprayingtimesteps), ncol=3), # Matrix of deterrence parameters + ms_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=3) # Matrix of deterrence parameters per timestep ) output <- run_simulation(sim_length, sprayingparams) -add_intervention_lines(plot_prevalence(output), spraying_events) +plot_prev(output) ``` From 45b0d87e2eda7668cb30f9c9391e78034b3f0b2a Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Mon, 27 Feb 2023 15:57:21 +0000 Subject: [PATCH 028/164] Fixing formatting, edits to explanations --- vignettes/Variation.Rmd | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index 6e16b845..ee1275d8 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -11,11 +11,12 @@ vignette: > library(malariasimulation) ``` -## Variation in outputs +### Variation in outputs Malariasimulation is a stochastic model, meaning that randomness is incorporated, so there will be be variation in model outputs. To illustrate this, we could compare the prevalence of malaria over a year in simulations with a small and a larger population. -### First we will create a few plotting functions to visualise outputs. +### Plotting functions +First, we will create a few plotting functions to visualise outputs. ```{r} cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") @@ -35,7 +36,7 @@ plot_p_detect <- function(output){ } ``` -### Simulations +## Simulations The `n_detect` output below shows the result of sampling individuals who would have cases of malaria that were detected by microscopy, while the `p_detect` output shows the sum of individual probabilities of detection of malaria in the population. @@ -71,7 +72,7 @@ title('p_detect at n = 10,000') ## Estimating variation -We can estimate the variation in the number of detectable cases by repeating the simulation several times and plotting the IQR and 95% confidence intervals. +We can estimate the variation in the number of detectable cases by repeating the simulation several times and plotting the IQR and 95% confidence intervals. These are useful techniques for comparing the expected variance from model outputs to outcomes from trials that might have had lower population sizes. ```{r, fig.align='center',fig.height=4, fig.width=8} outputs <- run_simulation_with_repetitions( @@ -127,5 +128,3 @@ title('95% Confidence interval') legend('bottom', inset = 0, legend = c('Mean','95% CI'), col = c(cols[4],'grey90'), lwd = 5, xpd = TRUE, horiz = TRUE, cex = 1, seg.len=1, bty = 'n') ``` - -These are useful techniques for comparing the expected variance from model outputs to outcomes from trials that might have had lower population sizes. \ No newline at end of file From 1a4ca70a7b805ee2b57d96e8ad2fe77d3d0897ad Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Tue, 28 Feb 2023 15:16:46 +0000 Subject: [PATCH 029/164] Almost finished --- vignettes/Treatment.Rmd | 136 ++++++++++++++++++++++++++++++++-------- 1 file changed, 111 insertions(+), 25 deletions(-) diff --git a/vignettes/Treatment.Rmd b/vignettes/Treatment.Rmd index f64af7e5..f866691c 100644 --- a/vignettes/Treatment.Rmd +++ b/vignettes/Treatment.Rmd @@ -19,57 +19,143 @@ library(malariasimulation) library(malariaEquilibrium) ``` -Set up some baseline parameters: +# Introduction + +This vignette describes how to implement clinical drug treatments in malariasimulation. + +The malariasimulation package contains in-built parameters sets for three anti-malarial drugs: + +1. AL_params: artemether-lumefantrine +2. DHA_PQP_params: dihydroartemisinin and piperaquine +3. SP_AQ: sulfadoxine-pyrimethamine and amodiaquine + +which can be included using the `set_drugs()` function. Multiple drugs can be used simultaneously, input as a list as shown in the below example. + +Each drug parameter set is a vector of length four, that represent the `drug efficacy`, ***drug_rel_c***, ***drug_prophylaxis_shape***, and ***drug_prophylaxis_scale***. ***I don't fully know the impact of changing these parameters, or what they mean exactly, e.g. rel_c is relative concentration? prophylaxis_shape? Scale? What does that look like*** \ + +For example: + +```{r} +AL_params +``` + +Drug parameters can be incorporated into a complete parameter set: ```{r} +Intro_parms <- set_drugs(parameters = get_parameters(), drugs = AL_params) +``` + +A treatment regiment for each drug can then be described using the `set_clinical_treatment()` function which takes the drug index, a vector of timesteps for each change in coverage and a vector of coverages for the drug, as well as the complete parameter set. This function must be used for each drug included (e.g., if there are two drugs, `set_clinical_treatment()` must be called twice). + +```{r} +Intro_parms <- set_clinical_treatment(parameters = Intro_parms, drug = 1, + timesteps = c(10,15,20), coverages = c(0.2,0.5,1)) +``` + +\ + +# Example + +## Parameterisation + +Set up some initial parameters: + +```{r} +# Daily simulation timesteps for two years year <- 365 sim_length <- 2 * year -human_population <- 1000 +# With a population size of 1000 +human_population <- 1000 simparams <- get_parameters(list(human_population = human_population)) +``` + +Update parameter set with chosen drug-specific parameters: + +```{r} +# Incorporate drug parameters (AL and DHA/PQP) into complete parameter set simparams <- set_drugs(simparams, list(AL_params, DHA_PQP_params)) + ``` -Run the model for some starting EIRs and fts: +\ + +## Simulation + +This simulation will be run for 2 years for different drug coverage programs: ```{r} -outputs <- list() -starting_EIR <- 10 -fts <- c(0, .25, .5, .75, 1.) - -for (ft in fts) { - simparams <- set_clinical_treatment(simparams, 1, 1, ft / 2) - simparams <- set_clinical_treatment(simparams, 2, 1, ft / 2) - simparams <- set_equilibrium(simparams, starting_EIR) +outputs <- list() # Create an empty list for results +starting_EIR <- 10 # Set initial EIR to 10 + +# We will vary coverage values between 0 and 0.5 +covs <- seq(0, 0.5, by = 0.1) + +# Iterate over coverage values +for (cov in covs) { + + # Set treatment programs for each drug (1 and 2), starting on day 1: + simparams <- set_clinical_treatment(simparams, 1, 1, cov) # Set treatment program for AL + simparams <- set_clinical_treatment(simparams, 2, 1, cov) # Set treatment program for DHA/PQP + + # Use set_equilibrium to update the parameter set for a given initial EIR + simparams2 <- set_equilibrium(simparams, starting_EIR) + + # Run simulation: output <- run_simulation(sim_length, simparams) - # cut out the warmup + # remove the first year (which can be considered a warmup) output <- output[output$timestep > year,] - outputs[[length(outputs) + 1]] <- output + # Add output to outputs list + outputs[[length(outputs) + 1]] <- output } ``` -Let's plot the effect of ft on PfPR2-10: +\ + +## Visualisation + +We will plot the effect of drug treatment coverage on *Pf*PR~2-10~ through time using the n_detect_730_3650 and n_730_3650 outputs. ```{r} +Rich_cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") + +# Join listed results into a single data frame df <- do.call('rbind', lapply(seq_along(outputs), function(i) { + + # Select variables of interest df <- outputs[[i]][c('timestep', 'n_detect_730_3650', 'n_730_3650')] - df$ft <- fts[[i]] + + # Create a new variable for Pf Prevalence + df$PfPR2_10 <- df$n_detect_730_3650/df$n_730_3650 + + # Attach coverage value + df$coverage <- covs[[i]] + + # return results df })) -colorBlindBlack8 <- c("#000000", "#E69F00", "#56B4E9", "#009E73", - "#F0E442", "#0072B2", "#D55E00", "#CC79A7") - Treatment_plot_function <- function(df){ - par(fig=c(0,0.9,0,1), cex = 0.8, mai = c(0.8,0.8,0.3,0.1)) - with(df[df$ft==unique(df$ft)[1],], expr = plot(x = timestep, y = n_detect_730_3650/n_730_3650, type = "l", - xlab = "Days", ylab = expression(paste(italic(Pf),"PR"[2-10])), - ylim = c(min(df$n_detect_730_3650/df$n_730_3650),max(df$n_detect_730_3650/df$n_730_3650)), col = colorBlindBlack8[1])) - invisible(sapply(2:length(unique(df$ft)), function(x){ - with(df[df$ft==unique(df$ft)[x],], expr = points(x = timestep, y = n_detect_730_3650/n_730_3650, type = "l", col = colorBlindBlack8[x])) + + # Set figure margins and sections + par(fig=c(0,0.9,0,1), cex = 0.8, mai = c(0.8,0.8,0.3,0.1)) + + # Create initial plot with first set of results + with(df[df$coverage==unique(df$coverage)[1],], + expr = plot(x = timestep, y = PfPR2_10, type = "l", + xlab = "Days", ylab = expression(paste(italic(Pf),"PR"[2-10])), + ylim = c(min(df$PfPR2_10),max(df$PfPR2_10)), col = Rich_cols[1])) + + # Add remaining results + invisible(sapply(2:length(unique(df$coverage)), function(x){ + with(df[df$coverage==unique(df$coverage)[x],], + expr = points(x = timestep, y = PfPR2_10, type = "l",col = Rich_cols[x])) })) + + # Add figure legend par(fig=c(0.9,1,0,1), cex = 0.8, new = T, xpd = T, mai = c(0,0,0,0)) - legend("right", legend = unique(df$ft), col = colorBlindBlack8, bty = "n", lty = 1, title = "Coverage") + legend("right", legend = paste0(100*unique(df$coverage),"%"), + col = Rich_cols, bty = "n", lty = 1, title = "Coverage") } Treatment_plot_function(df) From 7601f895f05516782206f0e0746efe1d003ba043 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Tue, 28 Feb 2023 15:57:36 +0000 Subject: [PATCH 030/164] More explanation / clarification --- vignettes/VectorControl.Rmd | 14 +++++++------- vignettes/VectorControl_IRS.Rmd | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index da7242f2..f03d93ef 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -19,11 +19,11 @@ library(malariasimulation) library(malariaEquilibrium) ``` -Bednets can be incorporated into the simulations, with various timings and coverage and in settings with specified proportions of mosquito species. +Long-lasting insecticidal bednets are highly effective and relatively cheap interventions to prevent malaria. They can be incorporated into `malariasimulation` with various timings and coverage and in settings with specified proportions of mosquito species. We will illustrate this through an example of ### Parameterisation -We will set the default parameters to run the simulation from an equilibrium. +Set the default parameters to run the simulation from an equilibrium. ```{r} year <- 365 @@ -68,7 +68,7 @@ plot_prevalence <- function(output) { ## Adding bednets -Then we can run the simulation for a variety of bednet strategies. In the example below, we distribute bednets once a year for two years, changing the characteristics of the bed nets for each distribution. +Then we can run the simulation for a variety of bednet strategies. In the example below, we distribute bednets once a year for two years, the first round to 80% of teh population and the second round to 50% of the population. It is possible to change the characteristics of the bednets for each distribution timestep by modifying the values in the matrices for `dn0`, `rn`, `rnm`, and `gamman`. ```{r, fig.align='center', fig.height=4, fig.width=6} bednetparams <- simparams @@ -78,7 +78,7 @@ bednetstimesteps <- c(1, 2) * year # The bednets will be distributed at th bednetparams <- set_bednets( bednetparams, timesteps = bednetstimesteps, - coverages = c(.8, .8), # Each round is distributed to 80% of the population + coverages = c(.8, .5), # The first round is distributed to 80% of the population and the second round to 50%. retention = 5 * year, # Nets are kept on average 5 years dn0 = matrix(c(.533, .45), nrow=2, ncol=1), # Matrix of death probabilities for each mosquito species over time rn = matrix(c(.56, .5), nrow=2, ncol=1), # Matrix of repelling probabilities for each mosquito species over time @@ -93,7 +93,7 @@ plot_prevalence(output) ## Visualising bednet usage -It is important to understand the difference between the input `coverages` argument of `malariasimulation::set_bednets()` and the resulting population bednet usage over time in the model. In the above example, bednets are distributed to 80% of the population at each distribution round. +It is important to understand the difference between the input `coverages` argument of `malariasimulation::set_bednets()` and the resulting population bednet usage over time in the model. In the above example, bednets are distributed to a specified percentage of the population at each distribution round; however, the level of bednet usage may be different. The average population bednet usage will be influenced by: @@ -101,7 +101,7 @@ The average population bednet usage will be influenced by: * The assumed net retention half life * Correlations in the recipients of nets between rounds -The output from `malariasimulation::run_simulation()` has a variable that shows the number of people using bednets at any given timestep. We can visualise this to understand how bednet usage changes over time. +The output from `malariasimulation::run_simulation()` has a variable `n_use_net` that shows the number of people using bednets at any given timestep. We can visualise the proportion of the population using bednets over time to understand how bednet usage changes. ```{r, fig.align='center', fig.height=4, fig.width=6} output$prop_use_net <- output$n_use_net / human_population @@ -119,5 +119,5 @@ The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool See the vignettes from the `netz` package that explain these concepts more comprehensively: * [This vignette](https://mrc-ide.github.io/netz/articles/overview.html) explains how to estimate the distribution coverage from a specified bednet usage. -* [This vignette](https://mrc-ide.github.io/netz/articles/population_usage.html) demonstrates how to estimate population bednet usage from input distribution. +* [This vignette](https://mrc-ide.github.io/netz/articles/population_usage.html) demonstrates how to estimate population bednet usage from an input distribution. diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index aaaa2411..75254788 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -19,7 +19,7 @@ library(malariasimulation) library(malariaEquilibrium) ``` -We can add indoor residual spraying (IRS) as an intervention in the model with different timings and coverages and in settings with specified proportions of mosquito species with the help of the `set_spraying()` function. +Indoor residual spraying (IRS) is another common intervention to prevent malaria. We can add IRS in the model with different timings and coverages and in settings with specified proportions of mosquito species with the help of the `set_spraying()` function. ### Parameterisation From 557c0335d0a8ae837f3f69690191e98bac591e9e Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Tue, 28 Feb 2023 16:04:39 +0000 Subject: [PATCH 031/164] adding clarification/explanation --- vignettes/Variation.Rmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index ee1275d8..a89bd46b 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -13,7 +13,7 @@ library(malariasimulation) ### Variation in outputs -Malariasimulation is a stochastic model, meaning that randomness is incorporated, so there will be be variation in model outputs. To illustrate this, we could compare the prevalence of malaria over a year in simulations with a small and a larger population. +`malariasimulation` is a stochastic model, meaning that randomness is incorporated, creating random variation in model outputs. To illustrate this, we could compare the prevalence of malaria over a year in simulations with a small and a larger population. A smaller population would be more likely to have wide variations in the output compared to a larger one. ### Plotting functions First, we will create a few plotting functions to visualise outputs. @@ -40,7 +40,7 @@ plot_p_detect <- function(output){ The `n_detect` output below shows the result of sampling individuals who would have cases of malaria that were detected by microscopy, while the `p_detect` output shows the sum of individual probabilities of detection of malaria in the population. -Notice that the `p_detect` output is slightly smoother. This is because it forgoes the sampling step, so at low population sizes, `p_detect` will be smoother than its `n_detect` counterpart. +Notice that the `p_detect` output is slightly smoother. This is because it forgoes the sampling step, so especially at low population sizes, `p_detect` will be smoother than its `n_detect` counterpart. ```{r, fig.align='center',fig.height=6, fig.width=9} # A small population params <- get_parameters(list( From 1e7fa608bb3889012f09cc4bd5593c7f6348d955 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Tue, 28 Feb 2023 16:13:13 +0000 Subject: [PATCH 032/164] Clarification + adding text --- vignettes/Vaccines.Rmd | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 4561fea2..7db70a0a 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -14,7 +14,7 @@ knitr::opts_chunk$set( ) ``` -You may want to add a malaria vaccine to your simulation. It is possible to model the RTS,S vaccine or a theoretical transmission blocking vaccine through both a routine EPI strategy or a mass vaccination strategy using the helper functions `set_rtss_epi()`, `set_mass_rtss()` or `set_tbv()`. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the peak of malaria prevalence given by `peak_season_offset()`. +You may want to add a malaria vaccine to your simulation. It is possible to model both pre-erythrocytic vaccines with a specified profile or a theoretical transmission blocking vaccine. Parameters for the pre-erythrocytic vaccine can be set for a routine Expanded Programme on Immunization (EPI) strategy or a mass vaccination strategy using the helper functions `set_rtss_epi()` and `set_mass_rtss()`, while parameters for a TBV can be set using `set_tbv()`. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the expected peak of malaria prevalence given by `peak_season_offset()`. ```{r setup, message=FALSE} library(malariasimulation) @@ -26,7 +26,7 @@ cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", ``` ### Plotting functions -First, we will define a few functions to make plotting easier. +First, we will define a few functions to visualise the outputs. ```{r} # Plotting clinical incidence plot_inci <- function(){ @@ -57,6 +57,7 @@ plot_prev <- function(){ legend('topright', box.lty = 0, legend = 'Vaccination',col = cols[7], lty = 2, lwd = 2.5) } +# Plot dose timing plot_doses <- function(){ if(any(names(output) == 'n_rtss_epi_dose_1')) { doses <- output |> From 64b39d448f53a4142566848f944c7a50d81ab8a5 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Tue, 28 Feb 2023 16:26:01 +0000 Subject: [PATCH 033/164] Adding gridlines --- vignettes/Vaccines.Rmd | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 7db70a0a..2435b0ad 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -42,6 +42,7 @@ plot_inci <- function(){ lines(output$time_year, predict(curve_values), col = cols[6], lwd = 3) + grid(lty = 2, col = 'grey80', lwd = 1) legend('topright', box.lty = 0, legend = 'Vaccination',col = cols[7], lty = 2, lwd = 2.5) } @@ -54,6 +55,7 @@ plot_prev <- function(){ xlab = 'Time (years)', ylab = expression(paste(italic(Pf),"PR"[2-10])), xaxs = "i", yaxs = "i", bty = "l") abline(v = 1, col = cols[7], lty = 2, lwd = 2.5) + grid(lty = 2, col = 'grey80', lwd = 1) legend('topright', box.lty = 0, legend = 'Vaccination',col = cols[7], lty = 2, lwd = 2.5) } @@ -73,6 +75,7 @@ plot_doses <- function(){ ylab = 'Number of doses', col = cols[2:7], beside = FALSE) + grid(lty = 2, col = 'grey80', lwd = 1) legend('topleft', box.lty = 0, legend = c('Dose 1','Dose 2','Dose 3','Booster 1'), col = cols[2:7], lty = rep(1, 4), lwd = 2.5,bg="transparent") @@ -90,6 +93,7 @@ plot_doses <- function(){ ylab = 'Number of doses', col = cols[2:7], beside = FALSE) + grid(lty = 2, col = 'grey80', lwd = 1) legend('topleft', box.lty = 0, legend = c('Dose 1','Dose 2','Dose 3','Booster 1'), col = cols[2:7], lty = rep(1, 4), lwd = 2.5,bg="transparent") } @@ -287,6 +291,7 @@ barplot(doses, xlab = "Month", beside = FALSE) legend('topleft', box.lty = 0, legend = c('Dose 1','Dose 2','Dose 3','Booster 1','Booster 2'), col = cols[2:7], lty = rep(1, 4), lwd = 2.5,bg="transparent") +grid(lty = 2, col = 'grey80', lwd = 1) ``` From ea354a6cbd28882a80b4d0855b24ce92a8a42f24 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Tue, 28 Feb 2023 16:34:24 +0000 Subject: [PATCH 034/164] fix y axis label --- vignettes/Variation.Rmd | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index a89bd46b..ceed89ff 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -29,9 +29,10 @@ plot_n_detect <- function(output){ } plot_p_detect <- function(output){ + par(mar = c(5, 6, 4, 2) + 0.1) plot(x = output$timestep, y = output$p_detect_730_3650, type = 'l', col = cols[4], - xlab = 'Time (days)', ylab = "Sum of probabilities of case detection \nin children aged 2-10 years", + xlab = 'Time (days)', ylab = "Sum of probabilities of case detection\nin children aged 2-10 years", xaxs = "i", yaxs = "i", bty = "l") } ``` From df5a203f712f331b46ace22fd89994445e02178a Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Tue, 28 Feb 2023 17:08:14 +0000 Subject: [PATCH 035/164] Adding no intervention scenario to plots --- vignettes/Vaccines.Rmd | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 2435b0ad..9ae989cd 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -32,31 +32,40 @@ First, we will define a few functions to visualise the outputs. plot_inci <- function(){ output$clinical_incidence <- 1000 * output$n_inc_0_1825 / output$n_0_1825 output$time_year <- output$timestep / year + output_control$clinical_incidence <- 1000 * output_control$n_inc_0_1825 / output_control$n_0_1825 + output_control$time_year <- output_control$timestep / year plot(x = output$time_year, y = output$clinical_incidence, type = 'l', col = cols[3], xlab = 'Time (years)', ylab = 'Clinical incidence (per 1000 children aged 0-5)', xaxs = "i", yaxs = "i", bty = "l") - abline(v = 1, col = cols[7], lty = 2, lwd = 2.5) + abline(v = 1, col = cols[1], lty = 2, lwd = 2.5) curve_values <- loess(clinical_incidence ~ time_year, data = output, span = 0.3, method = 'loess') lines(output$time_year, predict(curve_values), col = cols[6], lwd = 3) + curve_values <- loess(clinical_incidence ~ time_year, data = output_control, span = 0.3, method = 'loess') + lines(output_control$time_year, predict(curve_values), col = cols[7], lwd = 3) grid(lty = 2, col = 'grey80', lwd = 1) - legend('topright', box.lty = 0, legend = 'Vaccination',col = cols[7], lty = 2, lwd = 2.5) + legend('topright', box.lty = 0, legend = c('Vaccination', 'Incidence for vaccine scenario', 'Smoothed incidence for \nno intervention scenario'), + col = c(cols[1], cols[6], cols[7]), lty = c(2,1,1), lwd = 2.5) } # Plot parasite prevalence plot_prev <- function(){ output$time_year <- output$timestep / year + output_control$time_year <- output_control$timestep / year plot(x = output$time_year, y = output$n_detect_730_3650/output$n_730_3650, - type = 'l', col = cols[4], + type = 'l', col = cols[4], ylim=c(0.39,0.58), xlab = 'Time (years)', ylab = expression(paste(italic(Pf),"PR"[2-10])), xaxs = "i", yaxs = "i", bty = "l") - abline(v = 1, col = cols[7], lty = 2, lwd = 2.5) + lines(x = output_control$time_year, y = output_control$n_detect_730_3650/output_control$n_730_3650, + col = cols[7]) + abline(v = 1, col = cols[1], lty = 2, lwd = 2.5) grid(lty = 2, col = 'grey80', lwd = 1) - legend('topright', box.lty = 0, legend = 'Vaccination',col = cols[7], lty = 2, lwd = 2.5) + legend('topright', box.lty = 0, legend = c('Vaccination', 'Prevalence for vaccine scenario', 'Prevalence for no intervention scenario'), + col = c(cols[1], cols[4], cols[7]), lty = c(2,1, 1), lwd = 2.5) } # Plot dose timing @@ -119,6 +128,9 @@ simparams <- get_parameters(list( ) simparams <- set_equilibrium(simparams, starting_EIR) + +# Run a model with no interventions +output_control <- run_simulation(sim_length * 2, simparams) ``` Then we can run the simulation for a variety of vaccination strategies for RTS,S: From f388e315c3da6d6db3285d10061b979971065f0d Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Tue, 28 Feb 2023 17:20:39 +0000 Subject: [PATCH 036/164] adding gridlines and no intervention scenario to plots --- vignettes/VectorControl.Rmd | 17 ++++++++++++----- vignettes/VectorControl_IRS.Rmd | 18 ++++++++++++------ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index f03d93ef..57c78126 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -47,6 +47,8 @@ simparams <- get_parameters( ) simparams <- set_equilibrium(simparams, starting_EIR) + +output_control <- run_simulation(sim_length, simparams) ``` ### Plotting functions @@ -56,13 +58,17 @@ cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") # Plotting functions -plot_prevalence <- function(output) { +plot_prev <- function() { plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, type = 'l', col = cols[4], lwd = 2.5, xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), - xaxs = "i", yaxs = "i", bty = "l") - abline(v = bednetstimesteps, col = cols[7], lty = 2, lwd = 2.5) - legend('topright', box.lty = 0, legend = 'Bednets',col = cols[7], lty = 2, lwd = 2.5) + xaxs = "i", yaxs = "i", bty = "l", ylim = c(0.15, 0.93)) + lines(x = output_control$timestep, y = output_control$n_detect_730_3650/output_control$n_730_3650, + col = cols[6], lwd = 2.5) + abline(v = bednetstimesteps, col = cols[1], lty = 2, lwd = 2.5) + grid(lty = 2, col = 'grey80', lwd = 1) + legend('topright', box.lty = 0, legend = c('Bednets','Prevalence for bednet scenario','Prevalence for control scenario'), + col = c(cols[1], cols[4], cols[6]), lty = c(2,1,1), lwd = 2.5) } ``` @@ -88,7 +94,7 @@ bednetparams <- set_bednets( output <- run_simulation(sim_length, bednetparams) -plot_prevalence(output) +plot_prev() ``` ## Visualising bednet usage @@ -110,6 +116,7 @@ plot(x = output$timestep, y = output$prop_use_net, type = 'l', col = cols[4], lwd = 2.5, xlab = 'Timestep (days)', ylab = 'Proportion of population using bednets', xaxs = "i", yaxs = "i", bty = "l") +grid(lty = 2, col = 'grey80', lwd = 1) ``` ## Using the `netz` package to estimate coverage inputs needed to achieve target population usage diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index 75254788..d251b6f6 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -47,6 +47,8 @@ simparams <- get_parameters( ) simparams <- set_equilibrium(simparams, starting_EIR) + +output_control <- run_simulation(sim_length, simparams) ``` ### Plotting functions @@ -56,13 +58,17 @@ cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") # Plotting functions -plot_prev <- function(output) { +plot_prev <- function() { plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, type = 'l', col = cols[4], lwd = 2.5, xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), - xaxs = "i", yaxs = "i", bty = "l") - abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = cols[7]) - legend('topright', box.lty = 0, legend = 'Spraying',col = cols[7], lty = 2, lwd = 2.5) + xaxs = "i", yaxs = "i", bty = "l", ylim = c(0.05, 0.9)) + lines(x = output_control$timestep, y = output_control$n_detect_730_3650/output_control$n_730_3650, + col = cols[6], lwd = 2.5) + abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = cols[1]) + grid(lty = 2, col = 'grey80', lwd = 1) + legend('topright', box.lty = 0, legend = c('Spraying', 'Prevalence for IRS scenario','Prevalence for control scenario'), + col = c(cols[1], cols[4], cols[6]), lty = c(2,1,1), lwd = 2.5) } ``` @@ -90,7 +96,7 @@ sprayingparams <- set_spraying( output <- run_simulation(sim_length, sprayingparams) -plot_prev(output) +plot_prev() ``` ## Additional species @@ -125,5 +131,5 @@ sprayingparams <- set_spraying( output <- run_simulation(sim_length, sprayingparams) -plot_prev(output) +plot_prev() ``` From 10c7f4a57b31f703287d8a8595a1121926a48f81 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Wed, 1 Mar 2023 09:33:14 +0000 Subject: [PATCH 037/164] Added mosquito seasonality, set_species --- vignettes/Model.Rmd | 258 +++++++++++++++++++++++++++----------------- 1 file changed, 162 insertions(+), 96 deletions(-) diff --git a/vignettes/Model.Rmd b/vignettes/Model.Rmd index 672f43c2..175b714b 100644 --- a/vignettes/Model.Rmd +++ b/vignettes/Model.Rmd @@ -17,7 +17,7 @@ knitr::opts_chunk$set( ) ``` -This is an individual based model for P. Falciparum and malaria interventions. +This is an individual based model for *P. falciparum* and malaria interventions. ## Human Biology @@ -25,100 +25,107 @@ The human variables are documented in [R/variables.R](https://github.com/mrc-ide The human biological processes are spread out between the following files: - 1. [R/human_infection.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/human_infection.R) - 2. [R/disease_progression.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/disease_progression.R) - 3. [R/mortality_processes.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/mortality_processes.R) - - - +1. [R/human_infection.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/human_infection.R) +2. [R/disease_progression.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/disease_progression.R) +3. [R/mortality_processes.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/mortality_processes.R) + ### States + Modelled human states are Susceptible (*S*), Treated (*Tr*), Clinical disease (*D*), Asymptomatic infection (*A*) and Sub-patent infection (*U*). ### Parameters -Parameters shown on the infographic include: the force of infection ($\Lambda_i$), the probability of clinical disease ($\phi_i$), the probability of receiving treatment ($f_T$), and rates of recovery from clinical disease to asymptomatic infection ($r_D$), asymptomatic infection to sub-patent infection ($r_A$), sub-patent infection and treated disease to complete recovery ($r_T$ and $r_U$). Superinfection may occur in individuals with asymptomatic or sub-patent infections at the same rates as standard infection (dashed arrows). - -Details that determine the force of infection can be found ***elsewhere: give links to resources***. All default parameters can be found using [get_parameters()](https://mrc-ide.github.io/malariasimulation/reference/get_parameters.html) where the rate parameters shown here represent delays are input into the model by first converting to duration in days, e.g. for the input `dr`, $dr = \frac{1}{r_D}$. -To maintain a constant population size during simulations, the birth rate of new susceptible individuals is set to be equal to the overall death rate. - -***Could give explicit equations*** +Parameters shown on the infographic include: the force of infection ($\Lambda_i$), the probability of clinical disease ($\phi_i$), the probability of receiving treatment ($f_T$, or force of treatment), and rates of recovery from clinical disease to asymptomatic infection ($r_D$), asymptomatic infection to sub-patent infection ($r_A$), sub-patent infection and treated disease to complete recovery ($r_T$ and $r_U$). Superinfection may occur in individuals with asymptomatic or sub-patent infections at the same rates as standard infection (dashed arrows). -***Could give defaults for parameters specified*** +The force of infection ($\Lambda_i$) is impacted by pre-erythrocytic immunity, mosquito biting rate and population size and level of infectivity (specific details can be found in the references below). All default parameters can be found using [get_parameters()](https://mrc-ide.github.io/malariasimulation/reference/get_parameters.html) where the rate parameters shown here represent delays are input into the model by first converting to duration in days, e.g. for the input `dr`, $dr = \frac{1}{r_D}$. -***Could explain how lambda is given*** +To maintain a constant population size during simulations, the birth rate of new susceptible individuals is set to be equal to the overall death rate. ## Mosquito Biology The mosquito biological processes are spread out between the following files: - 1. [src/mosquito_ode.cpp]() ***Can't find a file with this name*** - 2. [src/mosquito_emergence.cpp]() ***Can't find a file with this name***'' - 3. [R/mosquito_biology.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/mosquito_biology.R) +1. [src/mosquito_ode.cpp]() ***Can't find a file with this name*** +2. [src/mosquito_emergence.cpp]() ***Can't find a file with this name***'' +3. [R/mosquito_biology.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/mosquito_biology.R) - + ### States + Modelled mosquito states are separated into early (*E*) and late (*L*) larval stages, the pupal stage (*P*) and three adult states for susceptible (*Sm*), incubating (*Pm*) and infectious individuals (*Im*). ### Parameters + Parameters shown on the infographic include: mosquito developmental rates from early to late larval stages ($r_{EL}$), to the pupal stage ($r_{L}$) and to adult stage ($r_P$). Susceptible adults (*Sm*) may become infected (***These rates are not clear to me and it would be good to add these to the model infographic and to this text***) with a latent period (*Pm*) before becoming infectious (*Im*). Larval and pupal stages die at a rate of $\mu_p$ while adults die at a density dependent rate of $\mu_m$, where they then enter the *NonExistent* state. ***I need to read up on this density dependence.*** ***Density dependence of mosquito deaths*** ***Could show how these models are connected together in a bit more detail*** -\ +## Model References + +Griffin JT, Hollingsworth TD, Okell LC, Churcher TS, White M, et al. (2010) Reducing *Plasmodium falciparum* Malaria Transmission in Africa: A Model-Based Evaluation of Intervention Strategies. PLOS Medicine 7(8): e1000324. + +White, M.T., Griffin, J.T., Churcher, T.S. *et al.* Modelling the impact of vector control interventions on *Anopheles gambiae* population dynamics. *Parasites Vectors* **4**, 153 (2011). + +Griffin, J., Ferguson, N. & Ghani, A. Estimates of the changing age-burden of *Plasmodium falciparum* malaria disease in sub-Saharan Africa. *Nat Commun* **5**, 3136 (2014). + +Griffin, J. T., Déirdre Hollingsworth, T., Reyburn, H., Drakeley, C. J., Riley, E. M., & Ghani, A. C. (2015). Gradual acquisition of immunity to severe malaria with increasing exposure. Proceedings of the Royal Society B: Biological Sciences, 282(1801). + +Griffin, J. T., Bhatt, S., Sinka, M. E., Gething, P. W., Lynch, M., Patouillard, E., Shutes, E., Newman, R. D., Alonso, P., Cibulskis, R. E., & Ghani, A. C. (2016). Potential for reduction of burden and local elimination of malaria by reducing Plasmodium falciparum malaria transmission: A mathematical modelling study. The Lancet Infectious Diseases, 16(4), 465--472. [https://doi.org/10.1016/S1473-3099(15)00423-5](https://doi.org/10.1016/S1473-3099(15)00423-5) # Basic simulation ### Simulation code -The key package function is `run_simulation()` which, in its most basic form, simply requires a number of timesteps in days. Default parameter settings assume a population of size of 100 with no treatment interventions ***what are other default settings?***, and which can be seen in full using [get_parameters()](https://mrc-ide.github.io/malariasimulation/reference/get_parameters.html). + +The key package function is `run_simulation()` which, in its most basic form, simply requires a number of timesteps in days. Default parameter settings assume a human population of size of 100, an initial mosquito population size of 1000 with all species in equal proportions, with no treatment interventions and no seasonality. The full parameters list can be seen using [get_parameters()](https://mrc-ide.github.io/malariasimulation/reference/get_parameters.html). ```{r, output.lines=6} library(malariasimulation) Test_Sim <- run_simulation(timesteps = 100) ``` - ### Output -The model then simulates a malaria epidemic and returns key outputs such as: -- `infectivity`: human infectiousness -- `EIR_All`: the entomological inoculation rate -- `FOIM`: the force of mosquito infection -- `mu_All`: adult mosquito death rate ***Why is this important? isn't this just mu_m? I suppose it's density dependent. Look into this in more detail*** -- `n_bitten`: the number of infectious bites -- `n_infections`: the number human infections -- `natural_deaths`: deaths from old age -- `S_count`, `A_count`, `D_count`, `U_count`, `Tr_count`: the human population size in each state -- `ica_mean`: mean acquired immunity to clinical infection -- `icm_mean`: mean maternal immunity to clinical infection -- `ib_mean`: mean blood immunity to all infection -- `id_mean`: mean immunity from detected using microscopy -- `iva_mean`: mean acquired immunity to severe infection -- `ivm_mean`: mean maternal immunity to severe infection -- `n_730_3650`: population size of an age group of interest (where the default is set to 730-3650 days old, or 2-10 years, but which may be adjusted (see [Demography](https://mrc-ide.github.io/malariasimulation/articles/Demography.html) vignette for more details) -- `n_detect_730_3650`: number with possible detection through microscopy of a given age group -- `p_detect_730_3650`: the sum of probabilities of detection through microscopy of a given age group -- `E_All_count`, `L_All_count`, `P_All_count`, `Sm_All_count`, `Pm_All_count`, `Im_All_count`, `NonExistent_All_count`: mosquito population sizes in each state -- `mosquito_deaths`: mosquito deaths +The model then simulates a malaria epidemic and returns key outputs such as: +- `infectivity`: human infectiousness +- `EIR_All`: the entomological inoculation rate +- `FOIM`: the force of mosquito infection +- `mu_All`: adult mosquito death rate ***Why is this important? isn't this just mu_m? I suppose it's density dependent. Look into this in more detail*** +- `n_bitten`: the number of infectious bites +- `n_infections`: the number human infections +- `natural_deaths`: deaths from old age +- `S_count`, `A_count`, `D_count`, `U_count`, `Tr_count`: the human population size in each state +- `ica_mean`: mean acquired immunity to clinical infection +- `icm_mean`: mean maternal immunity to clinical infection +- `ib_mean`: mean blood immunity to all infection +- `id_mean`: mean immunity from detected using microscopy +- `iva_mean`: mean acquired immunity to severe infection +- `ivm_mean`: mean maternal immunity to severe infection +- `n_730_3650`: population size of an age group of interest (where the default is set to 730-3650 days old, or 2-10 years, but which may be adjusted (see [Demography](https://mrc-ide.github.io/malariasimulation/articles/Demography.html) vignette for more details) +- `n_detect_730_3650`: number with possible detection through microscopy of a given age group +- `p_detect_730_3650`: the sum of probabilities of detection through microscopy of a given age group +- `E_All_count`, `L_All_count`, `P_All_count`, `Sm_All_count`, `Pm_All_count`, `Im_All_count`, `NonExistent_All_count`: mosquito population sizes in each state +- `mosquito_deaths`: mosquito deaths ```{r, output.lines=6} head(Test_Sim, n = 3) ``` ### Additional outputs + **Age stratified** results for **incidence**, **clinical incidence** and **severe case incidence** may also be included in the output if desired and must be specified in the parameter list (see [get_parameters()](https://mrc-ide.github.io/malariasimulation/reference/get_parameters.html) for more details and [Demography](https://mrc-ide.github.io/malariasimulation/articles/Demography.html) for an example). These inputs will add extra columns to the output for the number of infections (**`n_`**) and the sum of probabilities of infection (**`p_`**) for the relevant total, clinical or severe incidences for each specified age group. Where **treatments** are specified, `n_treated` will report the number that have received treatment. Where **bed nets** are distributed, `net_usage` specifies the number sleeping under a bednet. ***`rate_D_A`, `rate_A_U`, `rate_U_S`*** These are found in the help page for `run_simulation()` How are these output??? - ### Output visualisation + These outputs can then be visualised, such as the population changes in states. Another key output is the prevalence of detectable infections between the ages of 2-10 (*Pf*PR~2-10~), which can be obtained by dividing `n_detect_730_3650` by `n_730_3650`. ```{r, out.width = "45%", echo = FALSE} @@ -134,100 +141,159 @@ states_plot() plot(x = Test_Sim$timestep, y = Test_Sim$n_detect_730_3650/Test_Sim$n_730_3650, type = "l", col = Rich_cols[7], ylim = c(0,1), ylab = expression(paste(italic(Pf),"PR"[2-10])), xlab = "Days") ``` - \ # Changing parameters -## Vignettes +## Mosquito modelling -The remaining vignettes describe how to adjust sets of parameters through a number of functions as follows: +### Species distribution -1. [Population demography](https://mrc-ide.github.io/malariasimulation/articles/Demography.html) +`malariasimulation` contains in built parameter sets for three mosquito species: *A. arabiensis* (`arab_params`), *A. funestus* (`fun_params`) and *A. gambiae* (`gamb_params`). Each parameter set contains feeding rates, foraging time etc. - - rendering age groups - - `set_demography()`: setting demographies - - `set_equilibrium()`: establishing initial human and mosquito populations to achieve initial equilibrium conditions - - ***Possibly include `find_birthrates`.*** +```{r} +unlist(arab_params) +``` -\ +The proportion of each species can be set using the `set_species()` function, requiring a full parameter set and arguments of a list of species parameter sets and a vector of relative species proportions. -2. Mosquito related functions +```{r} +# Create list of default parameters +params <- get_parameters() + +# Update parameter list with species distributions +params_species <- set_species(parameters = params, species = list(arab_params, fun_params, gamb_params), proportions = c(0.1,0.3,0.6)) + +# Run simulation +species_simulation <- run_simulation(timesteps = 100, parameters = params_species) + +## Plot species distributions +# Collect species column names +arab_cols <- paste0(c("E","L","P","Sm","Pm", "Im", "NonExistent"),"_arab_count") +fun_cols <- paste0(c("E","L","P","Sm","Pm", "Im", "NonExistent"),"_fun_count") +gamb_cols <- paste0(c("E","L","P","Sm","Pm", "Im", "NonExistent"),"_gamb_count") + +Mos_sp_dist_sim <- cbind(species_simulation$timestep, + rowSums(species_simulation[,arab_cols]), + rowSums(species_simulation[,fun_cols]), + rowSums(species_simulation[,gamb_cols])) + +cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") + +species_plot <- function(Mos_pops){ + plot(x = Mos_pops[,1], y = Mos_pops[,2], type = "l", col = cols[2], ylim = c(0,140000), ylab = "Mosquito population size", xlab = "Days") + sapply(3:4, function(x){points(x = Mos_pops[,1], y = Mos_pops[,x], type = "l", col = cols[x])}) + legend("topright", legend = c("A. arab","A. fun","A. gamb"), col = cols[-1], lty = 1, bty = "n", ncol = 1) +} - - Modelling mosquito seasonality, - - IBM or ODE modelling of mosquitoes, - - `set_species()`: for species specific parameters (with in-built parameter sets) - - ***Possibly include *** - parameterise_mosquito_equilibrium??? - - parameterise_total_M??? +species_plot(Mos_sp_dist_sim) +``` -\ +### Seasonality -3. [Treatment](https://mrc-ide.github.io/malariasimulation/articles/Treatment.html) +We can also include the impact of seasonality on mosquito prevalence. To do this, we must set the parameter `model_seasonality = TRUE` and assign values to parameters that determine seasonality: `g0`, `g` and `h`. These parameters must be set directly using the `overrides` argument of `get_parameters()`. `overrides` takes a list of named parameters that can be overwritten. - - `set_drugs()`: for drug-specific parameters (with in-built parameter sets) - - `set_clinical_treatment()`: implemention of clinical treatment interventions +```{r} +# Set parameters, inclusing seasonality parameters +params_seasons <- get_parameters(overrides = list( + model_seasonality = TRUE, + g0 = 0.28, + g = c(0.2, -0.07, -0.001), + h = c(0.2, -0.07, -0.1))) -\ +# Run simulation +seasonality_simulation <- run_simulation(timesteps = 600, parameters = params_seasons) -4. [MDA and chemoprevention](https://mrc-ide.github.io/malariasimulation/articles/MDA.html) +# Collect results +All_mos_cols <- paste0(c("E","L","P","Sm","Pm", "Im", "NonExistent"),"_All_count") - - `set_mda()`: implemention of mass drug administration interventions - - `set_smc()`: implementation of seasonal malarial chemoprevention interventions - - `set_pmc()`: implementation of perrenial malarial chemoprevention interventions - - `peak_season_offset()`: correlating timed intervetions with seasonal malaria +# Plot results +plot(seasonality_simulation[,1], rowSums(seasonality_simulation[,All_mos_cols]), ylim = c(0, 200000), type = "l", xlab = "Days", ylab = "Mosquito population size") -\ +### Run simulation using seasonality over previous species distribution +# Update seasonality parameter set to include species distributions +params_seasons_species <- set_species(parameters = params_seasons, species = list(arab_params, fun_params, gamb_params), proportions = c(0.1,0.3,0.6)) -5. [Vaccines](https://mrc-ide.github.io/malariasimulation/articles/Vaccines.html) +# Run simulation +seasonality_species_simulation <- run_simulation(timesteps = 600, parameters = params_seasons_species) - - `set_mass_rtss()`: implementation of a rtss vaccination intervention - - `set_tbv()`: implementation of a tbv vaccination intervention +# Collect results +Mos_season_species_sim <- cbind(seasonality_species_simulation$timestep, + rowSums(seasonality_species_simulation[,arab_cols]), + rowSums(seasonality_species_simulation[,fun_cols]), + rowSums(seasonality_species_simulation[,gamb_cols])) -\ +# Plot results +species_plot(Mos_season_species_sim) -6. [Vector Control](https://mrc-ide.github.io/malariasimulation/articles/VectorControl.html) - - `set_bednets()`: implementation of bednet distribution intervention - - `set_spraying()`: implementation of an indoor residual spraying intervention +``` -\ +### Individual or deterministic life -7. [Matching PfPR2-10 to EIR](https://mrc-ide.github.io/malariasimulation/articles/EIRprevmatch.html) +## - - ***Need to work out what this is doing and why*** - - malariaEquilibrium::human equilibrium (Is there anything else from this package that would be useful to describe?). Also, links to package information??? - - set an equilibrium (set_equilibrium) +## Vignettes -\ +The remaining vignettes describe how to adjust sets of parameters through a number of functions as follows: -8. [Metapopulation modelling](https://mrc-ide.github.io/malariasimulation/articles/Metapopulation.html) +1. [Population Demography](https://mrc-ide.github.io/malariasimulation/articles/Demography.html) - - `run_metapop_simulation()`: to model multiple areas simulateously + - Age group rendering + - `set_demography()`: setting demographies + - `set_equilibrium()`: establishing initial human and mosquito populations to achieve initial equilibrium conditions -\ +2. [Treatment](https://mrc-ide.github.io/malariasimulation/articles/Treatment.html) -9. [Variation](https://mrc-ide.github.io/malariasimulation/articles/Variation.html) + - `set_drugs()`: for drug-specific parameters (with in-built parameter sets) + - `set_clinical_treatment()`: implemention of clinical treatment interventions - - `run_simulation_with_repetitions()`: running simulations with replicates +3. [MDA and Chemoprevention](https://mrc-ide.github.io/malariasimulation/articles/MDA.html) -\ + - `set_mda()`: implementation of mass drug administration interventions + - `set_smc()`: implementation of seasonal malarial chemoprevention interventions + - `set_pmc()`: implementation of perrenial malarial chemoprevention interventions + - `peak_season_offset()`: correlating timed interventions with seasonal malaria + +4. [Vaccines](https://mrc-ide.github.io/malariasimulation/articles/Vaccines.html) + + - `set_mass_rtss()`: implementation of a RTS,S vaccination intervention + - `set_rtss_epi()`: Implementation of RTS,S vaccination intervention from a certain age + - `set_tbv()`: implementation of a tbv vaccination intervention + +5. [Vector Control: Bednets](https://mrc-ide.github.io/malariasimulation/articles/VectorControl.html) + + - `set_bednets()`: implementation of bednet distribution intervention + +6. [Vector Control: Indoor Residual Spraying](https://mrc-ide.github.io/malariasimulation/articles/VectorControl.html) + + - `set_spraying()`: implementation of an indoor residual spraying intervention + +7. [Matching PfPR2-10 to EIR](https://mrc-ide.github.io/malariasimulation/articles/EIRprevmatch.html) + + - ***Need to work out what this is doing and why*** + - malariaEquilibrium::human equilibrium (Is there anything else from this package that would be useful to describe?). Also, links to package information??? + - set an equilibrium \ (set_equilibrium) + +8. [Metapopulation Modelling](https://mrc-ide.github.io/malariasimulation/articles/Metapopulation.html) + + - `run_metapop_simulation()`: to model multiple areas simulateously + +9. [Variation](https://mrc-ide.github.io/malariasimulation/articles/Variation.html) + + - `run_simulation_with_repetitions()`: running simulations with replicates ## Changing other parameters It is not recommended that parameters are adjusted without using these functions without close and detailed attention, but if this is necessary, any parameter may be changed using the `overrides` argument in the `get_parameters()` function. The `get_parameters()` function generates a complete parameter set that may be fed into `run_simulation()`. New parameters must be in the same class as the parameters they replace (e.g. if the parameter is a numeric, its replacement must also be numeric, if logical, the replacement must also be logical) and inputs must be given as a list. An example is given below. This simple example shows how to change the human population size. The parameter name for human population size is `human_population`. + ```{r} # Use get_parameters(overrides = list(...))) to set new parameters new_params <- get_parameters(overrides = list(human_population = 200)) ``` +### - -### -***Which parameters don't get addressed in the vignettes? What do these parameters do?*** -Correlation_Parameters -find_birthrates() -get_correlation_parameters() -parameterise_mosquito_equilibrium() -parameterise_total_M() \ No newline at end of file +***Which parameters don't get addressed in the vignettes? What do these parameters do?*** Correlation_Parameters find_birthrates() get_correlation_parameters() parameterise_mosquito_equilibrium() parameterise_total_M() From 57f88a0bedfadd72203457c3bfa1c1250c83d250 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Wed, 1 Mar 2023 17:21:29 +0000 Subject: [PATCH 038/164] Made a few more changes --- vignettes/Model.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/Model.Rmd b/vignettes/Model.Rmd index 175b714b..2073f2d1 100644 --- a/vignettes/Model.Rmd +++ b/vignettes/Model.Rmd @@ -147,7 +147,7 @@ plot(x = Test_Sim$timestep, y = Test_Sim$n_detect_730_3650/Test_Sim$n_730_3650, ## Mosquito modelling -### Species distribution +### Species distribution `malariasimulation` contains in built parameter sets for three mosquito species: *A. arabiensis* (`arab_params`), *A. funestus* (`fun_params`) and *A. gambiae* (`gamb_params`). Each parameter set contains feeding rates, foraging time etc. From e12daee73ee78cab2ea3bcb936cd85a38eae141b Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Wed, 1 Mar 2023 18:04:18 +0000 Subject: [PATCH 039/164] Incorporating Richard's and TOm's comments - improving plots - fixing seasonality of comparison output - adding more explanation --- vignettes/Vaccines.Rmd | 304 +++++++++++++++++++++++------------------ 1 file changed, 174 insertions(+), 130 deletions(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 9ae989cd..113a181a 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -14,104 +14,98 @@ knitr::opts_chunk$set( ) ``` -You may want to add a malaria vaccine to your simulation. It is possible to model both pre-erythrocytic vaccines with a specified profile or a theoretical transmission blocking vaccine. Parameters for the pre-erythrocytic vaccine can be set for a routine Expanded Programme on Immunization (EPI) strategy or a mass vaccination strategy using the helper functions `set_rtss_epi()` and `set_mass_rtss()`, while parameters for a TBV can be set using `set_tbv()`. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the expected peak of malaria prevalence given by `peak_season_offset()`. +It is possible to model both pre-erythrocytic malaria vaccines and a theoretical transmission blocking vaccine (TBV). Parameters for the pre-erythrocytic vaccine can be set for a routine Expanded Programme on Immunization (EPI) strategy or a mass vaccination strategy using the helper functions `set_rtss_epi()` and `set_mass_rtss()`, while parameters for a TBV can be set using `set_tbv()`. Under an EPI strategy, everybody within a certain age range will be vaccinated within the routine immunisation system. A mass vaccination strategy is typically a one-time event where everybody, or everybody within a certain age group, is targeted for vaccination during a relatively short window of time. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the expected peak of malaria prevalence given by `peak_season_offset()`. ```{r setup, message=FALSE} library(malariasimulation) -library(dplyr) -library(tidyr) -cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", +cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") ``` ### Plotting functions -First, we will define a few functions to visualise the outputs. -```{r} + +First, we will define a few functions to visualise the outputs. + +```{r} # Plotting clinical incidence -plot_inci <- function(){ +plot_inci <- function(type = 'not seasonal'){ + if(type == 'seasonal'){ + comparison <- output_seas_control + vaccinetime <- round(year + (peak - month * 3.5), 0) / 365 + } else { + comparison <- output_control + vaccinetime <- 1 + } output$clinical_incidence <- 1000 * output$n_inc_0_1825 / output$n_0_1825 output$time_year <- output$timestep / year - output_control$clinical_incidence <- 1000 * output_control$n_inc_0_1825 / output_control$n_0_1825 - output_control$time_year <- output_control$timestep / year + comparison$clinical_incidence <- 1000 * comparison$n_inc_0_1825 / comparison$n_0_1825 + comparison$time_year <- comparison$timestep / year plot(x = output$time_year, y = output$clinical_incidence, - type = 'l', col = cols[3], + type = 'l', col = cols[2], xlab = 'Time (years)', ylab = 'Clinical incidence (per 1000 children aged 0-5)', - xaxs = "i", yaxs = "i", bty = "l") - abline(v = 1, col = cols[1], lty = 2, lwd = 2.5) + xaxs = "i", yaxs = "i", bty = "l", xaxs = "i", yaxs = "i") + grid(lty = 2, col = 'grey80', lwd = 1) + abline(v = vaccinetime, col = 'black', lty = 2, lwd = 2.5) curve_values <- loess(clinical_incidence ~ time_year, data = output, span = 0.3, method = 'loess') lines(output$time_year, predict(curve_values), - col = cols[6], - lwd = 3) - curve_values <- loess(clinical_incidence ~ time_year, data = output_control, span = 0.3, method = 'loess') - lines(output_control$time_year, predict(curve_values), col = cols[7], lwd = 3) - grid(lty = 2, col = 'grey80', lwd = 1) - legend('topright', box.lty = 0, legend = c('Vaccination', 'Incidence for vaccine scenario', 'Smoothed incidence for \nno intervention scenario'), - col = c(cols[1], cols[6], cols[7]), lty = c(2,1,1), lwd = 2.5) + col = cols[5], lwd = 3) + curve_valuescomp <- loess(clinical_incidence ~ time_year, data = comparison, span = 0.3, method = 'loess') + lines(comparison$time_year, predict(curve_valuescomp), + col = cols[6], lwd = 3) + legend('topright', box.lty = 0, legend = c('Start of vaccination', 'Incidence for vaccine scenario', 'Smoothed incidence for \nno intervention scenario'), + col = c('black', cols[5], cols[5]), lty = c(2,1,1), lwd = 2.5) } # Plot parasite prevalence -plot_prev <- function(){ +plot_prev <- function(type = 'not seasonal'){ + if(type == 'seasonal'){ + comparison <- output_seas_control + vaccinetime <- round(year + (peak - month * 3.5), 0) / 365 + } else { + comparison <- output_control + vaccinetime <- 1 + } output$time_year <- output$timestep / year - output_control$time_year <- output_control$timestep / year + comparison$time_year <- comparison$timestep / year plot(x = output$time_year, y = output$n_detect_730_3650/output$n_730_3650, - type = 'l', col = cols[4], ylim=c(0.39,0.58), + type = 'l', col = cols[3], ylim=c(0,1), xlab = 'Time (years)', ylab = expression(paste(italic(Pf),"PR"[2-10])), - xaxs = "i", yaxs = "i", bty = "l") - lines(x = output_control$time_year, y = output_control$n_detect_730_3650/output_control$n_730_3650, - col = cols[7]) - abline(v = 1, col = cols[1], lty = 2, lwd = 2.5) + xaxs = "i", yaxs = "i", bty = "l", xaxs = "i", yaxs = "i") grid(lty = 2, col = 'grey80', lwd = 1) - legend('topright', box.lty = 0, legend = c('Vaccination', 'Prevalence for vaccine scenario', 'Prevalence for no intervention scenario'), - col = c(cols[1], cols[4], cols[7]), lty = c(2,1, 1), lwd = 2.5) + lines(x = comparison$time_year, y = comparison$n_detect_730_3650/comparison$n_730_3650, + col = cols[6]) + abline(v = vaccinetime, col = 'black', lty = 2, lwd = 2.5) + legend('topright', box.lty = 0, legend = c('Start of vaccination', 'Prevalence for vaccine scenario', 'Prevalence for no intervention scenario'), + col = c('black', cols[3], cols[6]), lty = c(2,1,1), lwd = 2.5) } # Plot dose timing plot_doses <- function(){ - if(any(names(output) == 'n_rtss_epi_dose_1')) { - doses <- output |> - select(timestep, starts_with('n_rtss_epi')) |> - pivot_longer(starts_with('n_rtss_epi'), names_to = "dose", values_to = "count") |> - mutate(month = ceiling(timestep / month)) |> - group_by(month, dose) |> - summarize(count = sum(count)) |> ungroup() |> - pivot_wider(names_from = dose, values_from = count) %>% - select(-month) %>% t %>% as.matrix() - doses <- doses[c(2,3,4,1),] - barplot(doses, xlab = "Month", - ylab = 'Number of doses', - col = cols[2:7], - beside = FALSE) - grid(lty = 2, col = 'grey80', lwd = 1) - legend('topleft', box.lty = 0, legend = c('Dose 1','Dose 2','Dose 3','Booster 1'), - col = cols[2:7], lty = rep(1, 4), lwd = 2.5,bg="transparent") - - } else if (any(names(output) == 'n_rtss_mass_dose_1')) { - doses <- output |> - select(timestep, starts_with('n_rtss_mass')) |> - pivot_longer(starts_with('n_rtss_mass'), names_to = "dose", values_to = "count") |> - mutate(month = ceiling(timestep / month)) |> - group_by(month, dose) |> - summarize(count = sum(count)) |> ungroup() |> - pivot_wider(names_from = dose, values_from = count) %>% - select(-month) %>% t %>% as.matrix() - doses <- doses[c(2,3,4,1),] - barplot(doses, xlab = "Month", - ylab = 'Number of doses', - col = cols[2:7], - beside = FALSE) - grid(lty = 2, col = 'grey80', lwd = 1) - legend('topleft', box.lty = 0, legend = c('Dose 1','Dose 2','Dose 3','Booster 1'), - col = cols[2:7], lty = rep(1, 4), lwd = 2.5,bg="transparent") - } + output$month <- ceiling(output$timestep / month) + doses <- output[,c(2:5,38)] + doses <- aggregate(cbind(doses[1:4]), + by = list(doses$month), + FUN = sum) + doses <- as.matrix(t(doses[,-1])) + + barplot(doses, xlab = "Month", + ylab = 'Number of doses', + col = cols[1:6],space = 0, + beside = FALSE, xaxs = "i", yaxs = "i") + grid(lty = 2, col = 'grey80', lwd = 1) + axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") + legend('topleft', box.lty = 0, legend = c('Dose 1','Dose 2','Dose 3','Booster 1'), + col = cols[1:6], lty = rep(1, 4), lwd = 2.5, bg="transparent") } ``` ## Parameterisation -We will set the default parameters to run the simulation from an equilibrium. +We will set the default parameters to run the simulation from an equilibrium that has no seasonality using the `set_equilibrium()` function. + ```{r} year <- 365 month <- 30 @@ -129,21 +123,19 @@ simparams <- get_parameters(list( simparams <- set_equilibrium(simparams, starting_EIR) -# Run a model with no interventions +# Run a model with no interventions in a setting with no seasonality output_control <- run_simulation(sim_length * 2, simparams) ``` -Then we can run the simulation for a variety of vaccination strategies for RTS,S: +Then we can run the simulation for a variety of vaccination strategies. ## Mass RTS,S -First, we will model a single round of RTS,S vaccine given in a mass vaccination strategy where those within a given age range will be vaccinated to a specified coverage level and during a short window of time. In this example, individuals aged between 5 months and 10 years are vaccinated with a primary series, then a booster 12 months after the initial vaccination. The age groups to be vaccinated as well as timing of all vaccinations can be modified within the `set_mass_rtss()` function. +First, we will model a single round of RTS,S vaccine given in a mass vaccination strategy where those within a given age range will be vaccinated to a specified coverage level and during a short window of time. In this example, individuals aged between 5 months and 10 years are vaccinated with a primary series, then with a booster 12 months after the initial vaccination. The age groups to be vaccinated as well as timing of all vaccinations can be modified within the `set_mass_rtss()` function. ```{r} -rtssparams <- simparams - rtssparams <- set_mass_rtss( - rtssparams, + simparams, timesteps = 1 * year, # The single round of vaccination is at 1 year into the simulation. coverages = 1, # The vaccine is given to 100% of the population between the specified ages. min_wait = 0, # The minimum acceptable time since the last vaccination is 0. @@ -156,32 +148,91 @@ rtssparams <- set_mass_rtss( output <- run_simulation(sim_length, rtssparams) ``` -#### Plot clinical incidence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +#### Plot clinical incidence and prevalence + +```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} +par(mfrow = c(1,2)) plot_inci() +plot_prev() +``` + +#### Plot doses + +You can look at the distribution of doses using the `n_rtss_mass_dose_*` or `n_rtss_epi_dose_*` outputs. It is always a good idea to check the timing of vaccine doses to ensure that it is specified as intended. + +```{r, fig.width = 6, fig.height = 4, fig.align = 'center', message=FALSE} +plot_doses() +``` + +### Seasonal mass vaccination + +Mass vaccination can also be targeted seasonally. For example, we may want to have a mass vaccination campaign a few months prior to the peak transmission season. In the example below, we will create a parameter set with seasonality and first run a simulation with no vaccine, then run a simulation with a mass vaccination campaign to everyone between the ages of 5 months and 15 years. + +```{r} +# Use the get_parameters() function to establish a parameter set with a seasonal profile with malaria incidence in children aged 0-5 rendered in the model output: +seas_simparams <- get_parameters( + list( + human_population = human_population, + incidence_rendering_min_ages = 0, + incidence_rendering_max_ages = 5 * year, + individual_mosquitoes = FALSE, + model_seasonality = TRUE, # Let's try a bi-modal model + g0 = 0.285505, + g = c(-0.325352,-0.0109352,0.0779865), + h = c(-0.132815,0.104675,-0.013919) + ) +) + +seas_simparams <- set_equilibrium(seas_simparams, starting_EIR) + +# Run no vaccine scenario +output_seas_control <- run_simulation(sim_length *2, seas_simparams) +``` + +Next, we will run the scenario with a seasonal mass vaccination campaign. +```{r} +# Find the peak seasonality +peak <- peak_season_offset(seas_simparams) + +seasmass_simparams <- set_mass_rtss( + parameters = seas_simparams, + timesteps = round(year + (peak - month * 3.5), 0),# The vaccination will begin 3.5 months prior to the peak seasonality in the second year. + coverages = 1, + min_ages = 5 * month, + max_ages = 15 * year, + min_wait = 0, + boosters = round(c(12 * month + 2 * month)), + booster_coverage = 1) + +output <- run_simulation(sim_length * 2, seasmass_simparams) +``` + +#### Plot clinical incidence + +```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} +plot_inci(type = 'seasonal') ``` #### Plot prevalence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} -plot_prev() +```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} +plot_prev(type = 'seasonal') ``` #### Plot doses -You can look at the distribution of doses using the `n_rtss_mass_dose_*` or `n_rtss_epi_dose_*` outputs. It is always a good idea to check the timing of vaccine doses to ensure that it is specified as intended. + ```{r, fig.width = 6, fig.height = 4, fig.align = 'center', message=FALSE} plot_doses() ``` -### RTS,S EPI + +## RTS,S EPI You can also opt to vaccinate using the EPI strategy, where individuals will be vaccinated once they reach a certain age. In the example below, individuals will be vaccinated once they reach 5 months of age. For this intervention, we see a much more gradual impact following implementation. ```{r} -rtssepiparams <- simparams - # Add RTS,S strategy rtssepiparams <- set_rtss_epi( - rtssepiparams, + simparams, timesteps = 1 * year, # Vaccination will begin at 1 year. coverages = 1, # Vaccine coverage is 100%. min_wait = 0, # There is no minimum wait since the last vaccination. @@ -193,38 +244,34 @@ rtssepiparams <- set_rtss_epi( output <- run_simulation(sim_length * 2, rtssepiparams) ``` - #### Plot clinical incidence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} + +```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} plot_inci() ``` #### Plot prevalence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} plot_prev() ``` #### Plot doses + ```{r, fig.width = 6, fig.height = 4, fig.align = 'center', message=FALSE} plot_doses() ``` - - + ### RTS,S seasonal boosters -In a seasonal setting, we can set booster timesteps relative to the start of the year instead of relative to the last dose. This allows us to target seasonal dynamics. +In a seasonal setting, we can set booster timesteps relative to the start of the year instead of relative to the last dose. This allows us to target seasonal dynamics. + ```{r} -rtssepiseasonalparams <- simparams -rtssepiseasonalparams$model_seasonality = TRUE -rtssepiseasonalparams$g0 = 0.28605 -rtssepiseasonalparams$g = c(0.20636, -0.0740318, -0.0009293) -rtssepiseasonalparams$h = c(0.173743, -0.0730962, -0.116019) # Calculate the peak of the transmission season based on seasonality parameters above. -peak <- peak_season_offset(rtssepiseasonalparams) +peak <- peak_season_offset(seas_simparams) # Add RTS,S seasonal strategy rtssepiseasonalparams <- set_rtss_epi( - rtssepiseasonalparams, + seas_simparams, timesteps = 1 * year, # Vaccination begins 1 year after the start of the simulation. coverages = 1, # Vaccine coverage is 100%. min_wait = 6 * month, # When seasonal_boosters = TRUE, this is the minimum time between an individual receiving the final dose and the first booster. @@ -237,18 +284,19 @@ rtssepiseasonalparams <- set_rtss_epi( output <- run_simulation(sim_length * 2, rtssepiseasonalparams) ``` - #### Plot clinical incidence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} -plot_inci() + +```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} +plot_inci(type = 'seasonal') ``` #### Plot prevalence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} -plot_prev() +```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} +plot_prev(type = 'seasonal') ``` #### Plot doses + ```{r, fig.width = 6, fig.height = 4, fig.align = 'center', message=FALSE} plot_doses() ``` @@ -258,11 +306,8 @@ plot_doses() You can try different dosing schedules using the `rtss_doses` parameter. As before, it is a good idea to visualise the timing of the vaccination strategy to ensure that you have implemented it as intended. ```{r} -rtssepiparams2 <- simparams -rtssepiparams2$rtss_doses <- c(0, 30, 60) # setting the timesteps for the 3 doses in the primary series at 0, 1, 2 months - rtssepiparams2 <- set_rtss_epi( - rtssepiparams2, + simparams, timesteps = 1 * year, coverages = 1, age = 5 * month, @@ -271,65 +316,64 @@ rtssepiparams2 <- set_rtss_epi( booster_coverage = c(1, 1) ) +rtssepiparams2$rtss_doses <- c(0, 30, 60) # setting the timesteps for the 3 doses in the primary series at 0, 1, 2 months + output <- run_simulation(sim_length * 2, rtssepiparams2) ``` - #### Plot clinical incidence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} + +```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} plot_inci() ``` #### Plot prevalence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} plot_prev() ``` #### Plot doses + ```{r, fig.width = 6, fig.height = 4, fig.align = 'center', message=FALSE} -doses <- output |> - select(timestep, starts_with('n_rtss_epi')) |> - pivot_longer(starts_with('n_rtss_epi'), names_to = "dose", values_to = "count") |> - mutate(month = ceiling(timestep / month)) |> - group_by(month, dose) |> - summarize(count = sum(count)) |> ungroup() |> - pivot_wider(names_from = dose, values_from = count) %>% - select(-month) %>% t %>% as.matrix() -doses <- doses[c(3:5,1,2),] - +output$month <- ceiling(output$timestep / month) +doses <- output[,c(2:6,39)] +doses <- aggregate(cbind(doses[1:5]), + by = list(doses$month), + FUN = sum) +doses <- as.matrix(t(doses[,-1])) + barplot(doses, xlab = "Month", ylab = 'Number of doses', - col = cols[2:7], - beside = FALSE) -legend('topleft', box.lty = 0, legend = c('Dose 1','Dose 2','Dose 3','Booster 1','Booster 2'), - col = cols[2:7], lty = rep(1, 4), lwd = 2.5,bg="transparent") + col = cols[1:6],space = 0, + beside = FALSE, xaxs = "i", yaxs = "i") grid(lty = 2, col = 'grey80', lwd = 1) +axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") +legend('topleft', box.lty = 0, legend = c('Dose 1','Dose 2','Dose 3','Booster 1', 'Booster 2'), + col = cols[1:6], lty = rep(1, 4), lwd = 2.5,bg="transparent") ``` - - -### TBV + +## TBV We can also model vaccines with completely different modes of actions. For example, a transmission blocking vaccine (TBV). This example shows 5 rounds of a TBV to everyone aged 5 years or older. ```{r} -tbvparams <- simparams - tbvparams <- set_tbv( - tbvparams, - timesteps = round(c(1, 1.25, 1.5, 1.75, 2) * 365), - coverages = rep(0.99, 5), - ages = 5:60 + simparams, + timesteps = round(c(1, 1.25, 1.5, 1.75, 2) * 365), # The TBV will be given at year 1, year 2, and every 3 months in between. + coverages = rep(0.99, 5), # 99% of the population will be covered. + ages = 5:60 # The age range in years of those receiving the vaccine. ) output <- run_simulation(sim_length, tbvparams) ``` #### Plot clinical incidence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} + +```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} plot_inci() ``` #### Plot prevalence -```{r, fig.width = 6, fig.height = 4, fig.align = 'center'} +```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} plot_prev() ``` From 5283b19c0cc82b71229fca58d100ceec51c56076 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 2 Mar 2023 10:46:52 +0000 Subject: [PATCH 040/164] Updating plots, editing text, removed p_detect references --- vignettes/Variation.Rmd | 124 ++++++++++++++++++++-------------------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index ceed89ff..b1303514 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -7,84 +7,82 @@ vignette: > %\VignetteEncoding{UTF-8} --- -```{r setup, include=FALSE} +```{r setup} library(malariasimulation) ``` -### Variation in outputs - -`malariasimulation` is a stochastic model, meaning that randomness is incorporated, creating random variation in model outputs. To illustrate this, we could compare the prevalence of malaria over a year in simulations with a small and a larger population. A smaller population would be more likely to have wide variations in the output compared to a larger one. +`malariasimulation` is a stochastic, individual-based model and, as such, simulations run with identical parameterisations will generate non-identical, sometimes highly variable, outputs. To illustrate this, we could compare the prevalence of malaria over a year in simulations with a small and a larger population. A smaller population would be more likely to have wide variations in the output compared to a larger one. ### Plotting functions First, we will create a few plotting functions to visualise outputs. ```{r} -cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", +cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") -plot_n_detect <- function(output){ +plot_n_detect <- function(output, ylab=TRUE){ + if (ylab==TRUE) { + ylab = "Cases detected in children aged 2-10 years" + } else {ylab=''} plot(x = output$timestep, y = output$n_detect_730_3650, - type = 'l', col = cols[4], - xlab = 'Time (days)', ylab = "Cases detected in children aged 2-10 years", - xaxs = "i", yaxs = "i", bty = "l") -} - -plot_p_detect <- function(output){ - par(mar = c(5, 6, 4, 2) + 0.1) - plot(x = output$timestep, y = output$p_detect_730_3650, - type = 'l', col = cols[4], - xlab = 'Time (days)', ylab = "Sum of probabilities of case detection\nin children aged 2-10 years", + type = 'l', col = cols[3], + xlab = 'Time (days)', ylab = ylab, xaxs = "i", yaxs = "i", bty = "l") + grid(lty = 2, col = 'grey80', lwd = 1) } ``` -## Simulations - -The `n_detect` output below shows the result of sampling individuals who would have cases of malaria that were detected by microscopy, while the `p_detect` output shows the sum of individual probabilities of detection of malaria in the population. - -Notice that the `p_detect` output is slightly smoother. This is because it forgoes the sampling step, so especially at low population sizes, `p_detect` will be smoother than its `n_detect` counterpart. -```{r, fig.align='center',fig.height=6, fig.width=9} -# A small population -params <- get_parameters(list( - human_population = 1000, +## Parameterisation +First, we will use the `get_parameters()` function to generate a list of parameters, accepting the default values, for two different population sizes. Then we will update the parameters to match equilibrium parameters and to achieve the initial EIR using `set_equilibrium()` +```{r} +# A small population +simparams <- get_parameters(list( + human_population = 100, individual_mosquitoes = FALSE )) -params <- set_equilibrium(params, 2) -small_pop <- run_simulation(365, params) -# A larger population -params <- get_parameters(list( +simparams <- set_equilibrium(simparams, init_EIR = 20) + +# A larger population +simparams <- get_parameters(list( human_population = 10000, individual_mosquitoes = FALSE )) -params <- set_equilibrium(params, 2) -big_pop <- run_simulation(365, params) - -par(mfrow = c(2,2)) -plot_n_detect(small_pop) -title('n_detect at n = 1,000') -plot_p_detect(small_pop) -title('p_detect at n = 1,000') -plot_n_detect(big_pop) -title('n_detect at n = 10,000') -plot_p_detect(big_pop) -title('p_detect at n = 10,000') + +simparams <- set_equilibrium(simparams, init_EIR = 20) ``` +## Simulations + +The `n_detect_730_3650` output below shows the total number of individuals in the age group rendered (here, 730-3650 timesteps or 2-10 years) who have microscopy-detectable malaria. Notice that the output is smoother at a higher population. + +```{r, fig.align='center',fig.height=4, fig.width=10} +# A small population +output_small_pop <- run_simulation(365, simparams) + +# A larger population +output_big_pop <- run_simulation(365, simparams) + +# Plotting +par(mfrow = c(1,2)) +plot_n_detect(output_small_pop); title('n_detect at n = 100') +plot_n_detect(output_big_pop, ylab = FALSE); title('n_detect at n = 10,000') +``` + ## Estimating variation -We can estimate the variation in the number of detectable cases by repeating the simulation several times and plotting the IQR and 95% confidence intervals. These are useful techniques for comparing the expected variance from model outputs to outcomes from trials that might have had lower population sizes. +We can estimate the variation in the number of detectable cases by repeating the simulation several times with the function `run_simulation_with_repetitions()`, then plotting the IQR and 95% confidence intervals. These are useful techniques for comparing the expected variance from model outputs to outcomes from trials that might have had lower population sizes. -```{r, fig.align='center',fig.height=4, fig.width=8} +```{r, fig.align='center',fig.height=4, fig.width=10} outputs <- run_simulation_with_repetitions( - timesteps = 365, - repetitions = 10, - overrides = params, - parallel=TRUE + timesteps = 365, # We will run each simulation for 365 timesteps. + repetitions = 10, # The simulation will be run 10 times + overrides = simparams, # using the parameter list with the larger population that we created earlier. + parallel = TRUE # The runs will be done in parallel. ) # Calculate IQR and 95% confidence intervals for each of the repetitions -df <- aggregate( +output <- aggregate( outputs$n_detect_730_3650, by = list(outputs$timestep), FUN = function(x) { @@ -99,33 +97,35 @@ df <- aggregate( } ) -df <- data.frame(cbind(timestep = df$Group.1, df$x)) +output <- data.frame(cbind(timestep = output$Group.1, output$x)) # Plot the IQR and 95% CI par(mfrow = c(1,2)) -xx <- c(df$timestep, rev(df$timestep)) -yy <- c(df$lowq, rev(df$highq)) -plot(x = df$timestep, y = df$median, - type = 'n', xlim = c(-1,365),ylim = c(500,565), +xx <- c(output$timestep, rev(output$timestep)) +yy <- c(output$lowq, rev(output$highq)) +plot(x = output$timestep, y = output$median, + type = 'n', xlim = c(-1,365),ylim = c(1400,1700), xlab = 'Time (days)', ylab = "Cases detected in children aged 2-10 years", xaxs = "i", yaxs = "i", bty = "l") polygon(xx, yy, col = 'grey90', border= 'grey95') -lines(x = df$timestep, y = df$median, col = cols[4], lwd = 2) +lines(x = output$timestep, y = output$median, col = cols[3], lwd = 2) +grid(lty = 2, col = 'grey80', lwd = 1) title('IQR spread') -legend('bottom', legend = c('Median','IQR Spread'), col = c(cols[4],'grey90'), +legend('bottomleft', legend = c('Median','IQR Spread'), col = c(cols[3],'grey90'), lwd = 5, xpd = TRUE, horiz = TRUE, cex = 1, seg.len=1, bty = 'n') -xx <- c(df$timestep, rev(df$timestep)) -yy <- c(df$lowci, rev(df$highci)) -plot(x = df$timestep, y = df$mean, - type = 'n', xlim = c(-1,365),ylim = c(460,600), - xlab = 'Time (days)', ylab = "Cases detected in children aged 2-10 years", +xx <- c(output$timestep, rev(output$timestep)) +yy <- c(output$lowci, rev(output$highci)) +plot(x = output$timestep, y = output$mean, + type = 'n', xlim = c(-1,365),ylim = c(1400,1700), + xlab = 'Time (days)', ylab = "", xaxs = "i", yaxs = "i", bty = "l") polygon(xx, yy, col = 'grey90', border= 'grey95') -lines(x = df$timestep, y = df$mean, col = cols[4], lwd = 2) +lines(x = output$timestep, y = output$mean, col = cols[3], lwd = 2) +grid(lty = 2, col = 'grey80', lwd = 1) title('95% Confidence interval') -legend('bottom', inset = 0, legend = c('Mean','95% CI'), col = c(cols[4],'grey90'), +legend('bottomleft', inset = 0, legend = c('Mean','95% CI'), col = c(cols[3],'grey90'), lwd = 5, xpd = TRUE, horiz = TRUE, cex = 1, seg.len=1, bty = 'n') ``` From 0000e1204767726aeab0fa8bf7094aa1943355d7 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 2 Mar 2023 10:53:58 +0000 Subject: [PATCH 041/164] Last minutes updates to the text --- vignettes/Variation.Rmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index b1303514..a3228307 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -11,7 +11,7 @@ vignette: > library(malariasimulation) ``` -`malariasimulation` is a stochastic, individual-based model and, as such, simulations run with identical parameterisations will generate non-identical, sometimes highly variable, outputs. To illustrate this, we could compare the prevalence of malaria over a year in simulations with a small and a larger population. A smaller population would be more likely to have wide variations in the output compared to a larger one. +`malariasimulation` is a stochastic, individual-based model and, as such, simulations run with identical parameterisations will generate non-identical, sometimes highly variable, outputs. To illustrate this, we will compare the prevalence of malaria over a year in simulations with a small and a larger population, where a smaller population is more likely to have wide variations between simulation runs. ### Plotting functions First, we will create a few plotting functions to visualise outputs. @@ -71,7 +71,7 @@ plot_n_detect(output_big_pop, ylab = FALSE); title('n_detect at n = 10,000') ## Estimating variation -We can estimate the variation in the number of detectable cases by repeating the simulation several times with the function `run_simulation_with_repetitions()`, then plotting the IQR and 95% confidence intervals. These are useful techniques for comparing the expected variance from model outputs to outcomes from trials that might have had lower population sizes. +We can estimate the variation in the number of detectable cases by repeating the simulation several times with the function `run_simulation_with_repetitions()`, then plotting the IQR and 95% confidence intervals. Running multiple simulations is particularly important for simulations of a small population size, due to the disproportionate impact of stochasticity in small populations. ```{r, fig.align='center',fig.height=4, fig.width=10} outputs <- run_simulation_with_repetitions( From efc68b2b64729dd79dce20260dae0b0494c70325 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 2 Mar 2023 11:09:26 +0000 Subject: [PATCH 042/164] Updating text for new functions --- vignettes/Vaccines.Rmd | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 113a181a..02f287bf 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -14,7 +14,7 @@ knitr::opts_chunk$set( ) ``` -It is possible to model both pre-erythrocytic malaria vaccines and a theoretical transmission blocking vaccine (TBV). Parameters for the pre-erythrocytic vaccine can be set for a routine Expanded Programme on Immunization (EPI) strategy or a mass vaccination strategy using the helper functions `set_rtss_epi()` and `set_mass_rtss()`, while parameters for a TBV can be set using `set_tbv()`. Under an EPI strategy, everybody within a certain age range will be vaccinated within the routine immunisation system. A mass vaccination strategy is typically a one-time event where everybody, or everybody within a certain age group, is targeted for vaccination during a relatively short window of time. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the expected peak of malaria prevalence given by `peak_season_offset()`. +In this tutorial, we will explore how to model different strategies for both pre-erythrocytic malaria vaccines and a theoretical malaria transmission blocking vaccine (TBV). Parameters for the pre-erythrocytic vaccine can be set for a routine Expanded Programme on Immunization (EPI) strategy or a mass vaccination strategy using the helper functions `set_rtss_epi()` and `set_mass_rtss()`, while parameters for a TBV can be set using `set_tbv()`. Under an EPI strategy, everybody within a certain age range will be vaccinated within the routine immunisation system. A mass vaccination strategy is typically a one-time event where everybody, or everybody within a certain age group, is targeted for vaccination during a relatively short window of time. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the expected peak of malaria prevalence given by `peak_season_offset()`. ```{r setup, message=FALSE} library(malariasimulation) @@ -104,7 +104,7 @@ plot_doses <- function(){ ## Parameterisation -We will set the default parameters to run the simulation from an equilibrium that has no seasonality using the `set_equilibrium()` function. +We will set the default parameters to run the simulation from an equilibrium starting point that has no seasonality using the `set_equilibrium()` function. ```{r} year <- 365 @@ -131,7 +131,9 @@ Then we can run the simulation for a variety of vaccination strategies. ## Mass RTS,S -First, we will model a single round of RTS,S vaccine given in a mass vaccination strategy where those within a given age range will be vaccinated to a specified coverage level and during a short window of time. In this example, individuals aged between 5 months and 10 years are vaccinated with a primary series, then with a booster 12 months after the initial vaccination. The age groups to be vaccinated as well as timing of all vaccinations can be modified within the `set_mass_rtss()` function. +First, we will model a single round of RTS,S vaccine given in a mass vaccination strategy where those within a given age range will be vaccinated to a specified coverage level and during a short window of time. In this example, individuals aged between 5 months and 10 years are vaccinated with a primary series (3 doses) followed by a single booster 12 months after the initial vaccination. The age groups to be vaccinated as well as timing of all vaccinations can be modified within the `set_mass_rtss()` function. + +We specify that the intervention should use the RTS,S vaccine through the `profile` and `booster_profile` inputs. ```{r} rtssparams <- set_mass_rtss( @@ -155,7 +157,8 @@ par(mfrow = c(1,2)) plot_inci() plot_prev() ``` - +We see a much more gradual decrease in clinical incidence following EPI implementation compared to the mass vaccination strategy. + #### Plot doses You can look at the distribution of doses using the `n_rtss_mass_dose_*` or `n_rtss_epi_dose_*` outputs. It is always a good idea to check the timing of vaccine doses to ensure that it is specified as intended. @@ -166,10 +169,12 @@ plot_doses() ### Seasonal mass vaccination -Mass vaccination can also be targeted seasonally. For example, we may want to have a mass vaccination campaign a few months prior to the peak transmission season. In the example below, we will create a parameter set with seasonality and first run a simulation with no vaccine, then run a simulation with a mass vaccination campaign to everyone between the ages of 5 months and 15 years. +Mass vaccination can also be targeted seasonally. For example, we may want to have a mass vaccination campaign a few months prior to the peak transmission season. In the example below, we will create a parameter set with seasonality and first run a simulation with no vaccine, then run a simulation with a mass vaccination campaign targeting everyone between the ages of 5 months and 15 years. + +We specify that the intervention should use the RTS,S vaccine through the `profile` and `booster_profile` inputs. ```{r} -# Use the get_parameters() function to establish a parameter set with a seasonal profile with malaria incidence in children aged 0-5 rendered in the model output: +# Use the get_parameters() function to generate a new parameter set with a seasonal profile with malaria incidence in children aged 0-5 rendered in the model output: seas_simparams <- get_parameters( list( human_population = human_population, @@ -189,7 +194,7 @@ seas_simparams <- set_equilibrium(seas_simparams, starting_EIR) output_seas_control <- run_simulation(sim_length *2, seas_simparams) ``` -Next, we will run the scenario with a seasonal mass vaccination campaign. +Next, we will run the scenario with a seasonal mass vaccination campaign implemented starting 3.5 months before the peak of the transmission season. ```{r} # Find the peak seasonality peak <- peak_season_offset(seas_simparams) @@ -197,12 +202,12 @@ peak <- peak_season_offset(seas_simparams) seasmass_simparams <- set_mass_rtss( parameters = seas_simparams, timesteps = round(year + (peak - month * 3.5), 0),# The vaccination will begin 3.5 months prior to the peak seasonality in the second year. - coverages = 1, - min_ages = 5 * month, + coverages = 1, # 100% of the population between min_ages and max_ages is vaccinated. + min_ages = 5 * month, # max_ages = 15 * year, - min_wait = 0, - boosters = round(c(12 * month + 2 * month)), - booster_coverage = 1) + min_wait = 0, # There is no minimum wait between the last vaccination. + boosters = round(c(12 * month + 2 * month)), # The booster is given 14 months after the first dose. + booster_coverage = 1) # 100% of the vaccinated population is boosted. output <- run_simulation(sim_length * 2, seasmass_simparams) ``` @@ -263,7 +268,7 @@ plot_doses() ### RTS,S seasonal boosters -In a seasonal setting, we can set booster timesteps relative to the start of the year instead of relative to the last dose. This allows us to target seasonal dynamics. +In a seasonal setting, we can set booster timesteps relative to the start of the year instead of relative to the last dose. This allows us to consider seasonal dynamics and implement booster doses right before the start of the high transmission season to maximize impact. ```{r} # Calculate the peak of the transmission season based on seasonality parameters above. @@ -303,7 +308,7 @@ plot_doses() ### RTS,S dosing -You can try different dosing schedules using the `rtss_doses` parameter. As before, it is a good idea to visualise the timing of the vaccination strategy to ensure that you have implemented it as intended. +You can try different dosing schedules using the `pev_doses` parameter. Here we administer dose 1 at 5 months, dose 2 30 days after dose 1, and dose 3 60 days after dose 1. We also administer two booster doses 12 and 24 months following dose 3. As before, it is a good idea to visualise the timing of the vaccination strategy to ensure that you have implemented it as intended. ```{r} rtssepiparams2 <- set_rtss_epi( @@ -354,7 +359,7 @@ legend('topleft', box.lty = 0, legend = c('Dose 1','Dose 2','Dose 3','Booster 1' ## TBV -We can also model vaccines with completely different modes of actions. For example, a transmission blocking vaccine (TBV). This example shows 5 rounds of a TBV to everyone aged 5 years or older. +We can also model vaccines with completely different modes of actions. For example, a transmission blocking vaccine (TBV). This example shows 5 rounds of a TBV to 99% of the population aged 5 and 60. ```{r} tbvparams <- set_tbv( From 2fcf45a1a09ec2dc4f3eedc515f16248c3efc093 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 2 Mar 2023 11:14:36 +0000 Subject: [PATCH 043/164] edit text --- vignettes/Vaccines.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 02f287bf..64a90284 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -232,7 +232,7 @@ plot_doses() ## RTS,S EPI -You can also opt to vaccinate using the EPI strategy, where individuals will be vaccinated once they reach a certain age. In the example below, individuals will be vaccinated once they reach 5 months of age. For this intervention, we see a much more gradual impact following implementation. +We can also opt to vaccinate using the EPI strategy, where individuals will be vaccinated once they reach a certain age. In the example below, individuals will be vaccinated once they reach 5 months of age. For this intervention, we see a much more gradual impact following implementation. ```{r} # Add RTS,S strategy From 066c783f992bca878b13fbc2e534dcbbe3080a70 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 2 Mar 2023 11:42:58 +0000 Subject: [PATCH 044/164] improving plots and edits to text --- vignettes/VectorControl.Rmd | 84 ++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index 57c78126..9a466f89 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -19,15 +19,35 @@ library(malariasimulation) library(malariaEquilibrium) ``` -Long-lasting insecticidal bednets are highly effective and relatively cheap interventions to prevent malaria. They can be incorporated into `malariasimulation` with various timings and coverage and in settings with specified proportions of mosquito species. We will illustrate this through an example of +Long-lasting insecticidal bednets are highly effective and relatively cheap interventions to prevent malaria. The effects of insecticidal bed net distribution campsigns can be simulated using malariasimulation. The model provides the user with the flexibility to specify parameters that describe the net distribution campaign (e.g. timing, coverage, and target population), the bed nets distributed (e.g. efficacy, longevity), and the relative densities of the mosquito species present in the target population. We will illustrate this through an example with two bednet distributions, once per year. +### Plotting functions +We can create a few plotting functions to visualise the output. +```{r} +cols <- c("#E69F00", "#56B4E9", "#009E73", + "#F0E442", "#0072B2", "#D55E00", "#CC79A7") + +# Plotting functions +plot_prev <- function() { + plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, + type = 'l', col = cols[3], lwd = 2.5, + xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), + xaxs = "i", yaxs = "i", bty = "l", ylim = c(0.15, 0.93)) + lines(x = output_control$timestep, y = output_control$n_detect_730_3650/output_control$n_730_3650, + col = cols[5], lwd = 2.5) + abline(v = bednetstimesteps, col = 'black', lty = 2, lwd = 2.5) + grid(lty = 2, col = 'grey80', lwd = 1) + legend('bottomleft', box.lty = 0, legend = c('Bednets','Prevalence for bednet scenario','Prevalence for control scenario'), + col = c('black', cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) +} +``` + ### Parameterisation -Set the default parameters to run the simulation from an equilibrium. +Use the get_parameters() function to generate the list of parameters for a seasonal profile, accepting the default values to run the simulation from an equilibrium starting point. The seasonality will drive mosquito dynamics in the absence of interventions. ```{r} year <- 365 -month <- 30 sim_length <- 3 * year human_population <- 1000 starting_EIR <- 50 @@ -35,7 +55,7 @@ starting_EIR <- 50 simparams <- get_parameters( list( human_population = human_population, - # carrying capacity parameters + # seasonality parameters model_seasonality = TRUE, # Let's try a bi-modal model g0 = 0.28605, g = c(0.20636, -0.0740318, -0.0009293), @@ -46,77 +66,65 @@ simparams <- get_parameters( ) ) +# Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae +simparams <- set_species( + simparams, + species = list(arab_params, fun_params, gamb_params), + proportions = c(0.25, 0.25, 0.5) +) + simparams <- set_equilibrium(simparams, starting_EIR) output_control <- run_simulation(sim_length, simparams) ``` -### Plotting functions -We can create a few plotting functions to visualise the output. -```{r} -cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", - "#F0E442", "#0072B2", "#D55E00", "#CC79A7") +## Simulation -# Plotting functions -plot_prev <- function() { - plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, - type = 'l', col = cols[4], lwd = 2.5, - xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), - xaxs = "i", yaxs = "i", bty = "l", ylim = c(0.15, 0.93)) - lines(x = output_control$timestep, y = output_control$n_detect_730_3650/output_control$n_730_3650, - col = cols[6], lwd = 2.5) - abline(v = bednetstimesteps, col = cols[1], lty = 2, lwd = 2.5) - grid(lty = 2, col = 'grey80', lwd = 1) - legend('topright', box.lty = 0, legend = c('Bednets','Prevalence for bednet scenario','Prevalence for control scenario'), - col = c(cols[1], cols[4], cols[6]), lty = c(2,1,1), lwd = 2.5) -} -``` - -## Adding bednets - -Then we can run the simulation for a variety of bednet strategies. In the example below, we distribute bednets once a year for two years, the first round to 80% of teh population and the second round to 50% of the population. It is possible to change the characteristics of the bednets for each distribution timestep by modifying the values in the matrices for `dn0`, `rn`, `rnm`, and `gamman`. +Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bednets once a year for two years, the first round to 80% of the population and the second round to 50% of the population. It is possible to change the characteristics of the bednets for each distribution timestep by modifying the values for `dn0`, `rn`, `rnm`, and `gamman`. Because there are 3 mosquito species specified in `set_species()` above and two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 3 columns and 2 rows. ```{r, fig.align='center', fig.height=4, fig.width=6} -bednetparams <- simparams - -bednetstimesteps <- c(1, 2) * year # The bednets will be distributed at the end of the first and the second year. +bednetstimesteps <- c(1, 2) * year # The bednets will be distributed at the end of the first and the second year. bednetparams <- set_bednets( - bednetparams, + simparams, timesteps = bednetstimesteps, coverages = c(.8, .5), # The first round is distributed to 80% of the population and the second round to 50%. retention = 5 * year, # Nets are kept on average 5 years - dn0 = matrix(c(.533, .45), nrow=2, ncol=1), # Matrix of death probabilities for each mosquito species over time - rn = matrix(c(.56, .5), nrow=2, ncol=1), # Matrix of repelling probabilities for each mosquito species over time - rnm = matrix(c(.24, .24), nrow=2, ncol=1), # Matrix of minimum repelling probabilities for each mosquito species over time + dn0 = matrix(c(.533, .45), nrow=2, ncol=3), # Matrix of death probabilities for each mosquito species over time + rn = matrix(c(.56, .5), nrow=2, ncol=3), # Matrix of repelling probabilities for each mosquito species over time + rnm = matrix(c(.24, .24), nrow=2, ncol=3), # Matrix of minimum repelling probabilities for each mosquito species over time gamman = rep(2.64 * 365, 2) # Vector of bednet half-lives for each distribution timestep ) output <- run_simulation(sim_length, bednetparams) +``` +### Plot prevalence +```{r, fig.align='center', fig.height=5, fig.width=7} plot_prev() ``` -## Visualising bednet usage +## Visualisation It is important to understand the difference between the input `coverages` argument of `malariasimulation::set_bednets()` and the resulting population bednet usage over time in the model. In the above example, bednets are distributed to a specified percentage of the population at each distribution round; however, the level of bednet usage may be different. The average population bednet usage will be influenced by: * The size and frequency of distributions specified in `set_bednets()` -* The assumed net retention half life +* The assumed net retention half life (`gamman`) * Correlations in the recipients of nets between rounds The output from `malariasimulation::run_simulation()` has a variable `n_use_net` that shows the number of people using bednets at any given timestep. We can visualise the proportion of the population using bednets over time to understand how bednet usage changes. -```{r, fig.align='center', fig.height=4, fig.width=6} +```{r, fig.align='center', fig.height=5, fig.width=7} output$prop_use_net <- output$n_use_net / human_population plot(x = output$timestep, y = output$prop_use_net, type = 'l', - col = cols[4], lwd = 2.5, + col = cols[3], lwd = 2.5, ylim = c(0,1), xlab = 'Timestep (days)', ylab = 'Proportion of population using bednets', xaxs = "i", yaxs = "i", bty = "l") grid(lty = 2, col = 'grey80', lwd = 1) +axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") ``` ## Using the `netz` package to estimate coverage inputs needed to achieve target population usage From edb933643f5c466dbbf9b5cf686a859b0e2d3094 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 2 Mar 2023 11:44:00 +0000 Subject: [PATCH 045/164] updating to rmarkdown::html_vignette to match other vignettes --- vignettes/Variation.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index a3228307..e965ee31 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -1,6 +1,6 @@ --- title: "Variation" -output: html_document +output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Variation} %\VignetteEngine{knitr::rmarkdown} From 70e830502663eae06877608b8104cc559346c834 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 2 Mar 2023 14:53:00 +0000 Subject: [PATCH 046/164] updating text for IRS, reorganisation, add plot for mosquito species over time --- vignettes/VectorControl.Rmd | 2 +- vignettes/VectorControl_IRS.Rmd | 91 ++++++++++++++++++++------------- 2 files changed, 57 insertions(+), 36 deletions(-) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index 9a466f89..7c44da1b 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -44,7 +44,7 @@ plot_prev <- function() { ### Parameterisation -Use the get_parameters() function to generate the list of parameters for a seasonal profile, accepting the default values to run the simulation from an equilibrium starting point. The seasonality will drive mosquito dynamics in the absence of interventions. +Use the `get_parameters()` function to generate the list of parameters for a seasonal profile, accepting the default values to run the simulation from an equilibrium starting point. The seasonality will drive mosquito dynamics in the absence of interventions. ```{r} year <- 365 diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index d251b6f6..aa282300 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -19,11 +19,32 @@ library(malariasimulation) library(malariaEquilibrium) ``` -Indoor residual spraying (IRS) is another common intervention to prevent malaria. We can add IRS in the model with different timings and coverages and in settings with specified proportions of mosquito species with the help of the `set_spraying()` function. +Indoor Residual Spraying (IRS) involves periodically treating indoor walls with insecticides to eliminate adult female mosquitoes that rest indoors. `malariasimulation` can be used to investigate the effect of malaria control strategies that deploy IRS. The model has the functionality to allow users to specify a range of IRS campaigns, including different timings and coverages and in settings with specified proportions of mosquito species with the help of the `set_spraying()` function. -### Parameterisation +### Plotting functions +We will create a few plotting functions to visualise the output. +```{r} +cols <- c("#E69F00", "#56B4E9", "#009E73", + "#F0E442", "#0072B2", "#D55E00", "#CC79A7") + +# Plotting functions +plot_prev <- function() { + plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, + type = 'l', col = cols[3], lwd = 2.5, + xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), + xaxs = "i", yaxs = "i", bty = "l", ylim = c(0,1)) + lines(x = output_control$timestep, y = output_control$n_detect_730_3650/output_control$n_730_3650, + col = cols[5], lwd = 2.5) + abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = 'black') + grid(lty = 2, col = 'grey80', lwd = 1) + legend('bottomleft', box.lty = 0, legend = c('Spraying', 'Prevalence for IRS scenario','Prevalence for control scenario'), + col = c('black', cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) +} +``` -We will set the default parameters to run the simulation from an equilibrium. +### Parameterisation + +Use the `get_parameters()` function to generate the list of parameters for a seasonal profile, accepting the default values to run the simulation from an equilibrium starting point. The seasonality will drive mosquito dynamics in the absence of interventions. ```{r} year <- 365 @@ -35,7 +56,7 @@ starting_EIR <- 50 simparams <- get_parameters( list( human_population = human_population, - # carrying capacity parameters + # seasonality parameters model_seasonality = TRUE, # Let's try a bi-modal model g0 = 0.28605, g = c(0.20636, -0.0740318, -0.0009293), @@ -48,42 +69,21 @@ simparams <- get_parameters( simparams <- set_equilibrium(simparams, starting_EIR) +# Running simulation with no IRS output_control <- run_simulation(sim_length, simparams) ``` + +## Simulation -### Plotting functions -We can create a few plotting functions to visualise the output. -```{r} -cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", - "#F0E442", "#0072B2", "#D55E00", "#CC79A7") +Then we can run the simulation for a variety of IRS strategies. In the example below, there are two rounds of IRS at 80% coverage, each 3 months prior to peak transmission for that year. Notice that the matrices specified for the parameters for `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` have two rows, one for each timestep where IRS occurs, and 1 column for all mosquitoes, not divided by species. -# Plotting functions -plot_prev <- function() { - plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, - type = 'l', col = cols[4], lwd = 2.5, - xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), - xaxs = "i", yaxs = "i", bty = "l", ylim = c(0.05, 0.9)) - lines(x = output_control$timestep, y = output_control$n_detect_730_3650/output_control$n_730_3650, - col = cols[6], lwd = 2.5) - abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = cols[1]) - grid(lty = 2, col = 'grey80', lwd = 1) - legend('topright', box.lty = 0, legend = c('Spraying', 'Prevalence for IRS scenario','Prevalence for control scenario'), - col = c(cols[1], cols[4], cols[6]), lty = c(2,1,1), lwd = 2.5) -} -``` - -## Adding indoor residual spraying (IRS) - -Then we can run the simulation for a variety of IRS strategies. In the example below, there are two rounds of IRS, each 3 months prior to peak transmission for that year. ```{r, fig.align='center', fig.height=4, fig.width=6} -sprayingparams <- simparams - -peak <- peak_season_offset(sprayingparams) +peak <- peak_season_offset(simparams) sprayingtimesteps <- c(1, 2) * year + peak - 3 * month # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. sprayingparams <- set_spraying( - sprayingparams, + simparams, timesteps = sprayingtimesteps, coverages = rep(.8, 2), # # Each round covers 80% of the population ls_theta = matrix(c(2.025, 2.025), nrow=2, ncol=1), # Matrix of mortality parameters @@ -95,7 +95,11 @@ sprayingparams <- set_spraying( ) output <- run_simulation(sim_length, sprayingparams) +``` + +### Plot prevalence +```{r,fig.align='center', fig.height=5, fig.width=7} plot_prev() ``` @@ -103,6 +107,7 @@ plot_prev() It is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. If you have specified more than 1 species, then the arguments for `set_spraying()` and `set_bednets()` must be populated with values for each species at each time point. We will run the same model with IRS as above, but this time with 3 species of mosquitoes. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. Each column corresponds to a species of mosquito, and each row corresponds to the timestep when a round of IRS occurred. Here, we are assuming the same values for each species at each timepoint for simplicity, but the matrix could be edited to have different values by species or over time. + ```{r, fig.align='center', fig.height=4, fig.width=6} ## Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae simparams <- set_species( @@ -111,14 +116,12 @@ simparams <- set_species( proportions = c(0.25, 0.25, 0.5) ) -sprayingparams <- simparams - -peak <- peak_season_offset(sprayingparams) +peak <- peak_season_offset(simparams) sprayingtimesteps <- c(1, 2) * year + peak - 3 * month # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. sprayingparams <- set_spraying( - sprayingparams, + simparams, timesteps = sprayingtimesteps, coverages = rep(.8, 2), # # Each round covers 80% of the population ls_theta = matrix(2.025, nrow=length(sprayingtimesteps), ncol=3), # Matrix of mortality parameters; nrows=length(timesteps), ncols=length(species) @@ -130,6 +133,24 @@ sprayingparams <- set_spraying( ) output <- run_simulation(sim_length, sprayingparams) +``` +### Plot prevalence +```{r,fig.align='center', fig.height=5, fig.width=7} plot_prev() ``` + +### Plot adult female infectious mosquitoes by species over time +```{r,fig.align='center', fig.height=5, fig.width=7} +plot(x = output$timestep, y = output$Im_gamb_count, + type = 'l', col = cols[5], lwd = 2.5, + xlab = 'Time (days)', ylab = 'N mosquitoes', + xaxs = "i", yaxs = "i", bty = "l") +lines(x = output$timestep, y = output$Im_fun_count, + col = cols[6], lwd = 2.5) +lines(x = output$timestep, y = output$Im_arab_count, + col = cols[3], lwd = 2.5) +grid(lty = 2, col = 'grey80', lwd = 1) +legend('topright', box.lty = 0, legend = c(expression(paste('N ', italic('An. gambiae'))), expression(paste('N ', italic('An. funestus'))),expression(paste('N ', italic('An. arabiensis')))), col = c(cols[5], cols[6], cols[3]), lty = c(1,1,1), lwd = 2.5) +``` + From 174179c3e79a30cc6459f6a5fe47386590a7cf92 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 2 Mar 2023 15:06:15 +0000 Subject: [PATCH 047/164] Adding further explanation for different species --- vignettes/VectorControl_IRS.Rmd | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index aa282300..af4116e4 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -75,7 +75,7 @@ output_control <- run_simulation(sim_length, simparams) ## Simulation -Then we can run the simulation for a variety of IRS strategies. In the example below, there are two rounds of IRS at 80% coverage, each 3 months prior to peak transmission for that year. Notice that the matrices specified for the parameters for `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` have two rows, one for each timestep where IRS occurs, and 1 column for all mosquitoes, not divided by species. +Then we can run the simulation for a variety of IRS strategies. In the example below, there are two rounds of IRS at 80% coverage, each 3 months prior to peak rainfall for that year. The function `peak_season_offset()` outputs a timestep when peak rainfall will be observed. Notice that the matrices specified for the parameters for `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` have two rows, one for each timestep where IRS occurs, and 1 column for all mosquitoes, not divided by species. ```{r, fig.align='center', fig.height=4, fig.width=6} peak <- peak_season_offset(simparams) @@ -104,7 +104,9 @@ plot_prev() ``` ## Additional species -It is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. If you have specified more than 1 species, then the arguments for `set_spraying()` and `set_bednets()` must be populated with values for each species at each time point. +It is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. There are preset parameters for *An. gambiae*, *An. arabiensis*, and *An. funestus* that can be set by the helper functions `gamb_params()`, `arab_params()`, and `fun_params()`, respectively. IRS could be expected to have different impacts depending on the proportion of each mosquito species because of variations in indoor resting, insecticide resistance, and proportion of bites on humans versus animals by species. + +If you have specified more than 1 species, then the arguments for `set_spraying()` and `set_bednets()` must be populated with values for each species at each time point. We will run the same model with IRS as above, but this time with 3 species of mosquitoes. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. Each column corresponds to a species of mosquito, and each row corresponds to the timestep when a round of IRS occurred. Here, we are assuming the same values for each species at each timepoint for simplicity, but the matrix could be edited to have different values by species or over time. @@ -124,11 +126,11 @@ sprayingparams <- set_spraying( simparams, timesteps = sprayingtimesteps, coverages = rep(.8, 2), # # Each round covers 80% of the population - ls_theta = matrix(2.025, nrow=length(sprayingtimesteps), ncol=3), # Matrix of mortality parameters; nrows=length(timesteps), ncols=length(species) + ls_theta = matrix(2.025, nrow=length(sprayingtimesteps), ncol=3), # Matrix of mortality parameters per timestep; nrows=length(timesteps), ncols=length(species) ls_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=3), # Matrix of mortality parameters per timestep - ks_theta = matrix(-2.222, nrow=length(sprayingtimesteps), ncol=3), # Matrix of feeding success parameters - ks_gamma = matrix(0.008, nrow=length(sprayingtimesteps), ncol=3), # Matrix of feeding success parameters per timestep - ms_theta = matrix(-1.232, nrow=length(sprayingtimesteps), ncol=3), # Matrix of deterrence parameters + ks_theta = matrix(-2.222, nrow=length(sprayingtimesteps), ncol=3), # Matrix of feeding success parameters per timestep + ks_gamma = matrix(0.008, nrow=length(sprayingtimesteps), ncol=3), # Matrix of feeding success parametersper timestep + ms_theta = matrix(-1.232, nrow=length(sprayingtimesteps), ncol=3), # Matrix of deterrence parameters per timestep ms_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=3) # Matrix of deterrence parameters per timestep ) From df6795e165efab4e3e106aa48735b73d2014b2bd Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 2 Mar 2023 15:12:51 +0000 Subject: [PATCH 048/164] Updating labels for arugments in set_spraying --- vignettes/VectorControl_IRS.Rmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index af4116e4..c4e3d67a 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -126,11 +126,11 @@ sprayingparams <- set_spraying( simparams, timesteps = sprayingtimesteps, coverages = rep(.8, 2), # # Each round covers 80% of the population - ls_theta = matrix(2.025, nrow=length(sprayingtimesteps), ncol=3), # Matrix of mortality parameters per timestep; nrows=length(timesteps), ncols=length(species) + ls_theta = matrix(2.025, nrow=length(sprayingtimesteps), ncol=3), # Matrix of mortality parameters; nrows=length(timesteps), ncols=length(species) ls_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=3), # Matrix of mortality parameters per timestep - ks_theta = matrix(-2.222, nrow=length(sprayingtimesteps), ncol=3), # Matrix of feeding success parameters per timestep + ks_theta = matrix(-2.222, nrow=length(sprayingtimesteps), ncol=3), # Matrix of feeding success parameters ks_gamma = matrix(0.008, nrow=length(sprayingtimesteps), ncol=3), # Matrix of feeding success parametersper timestep - ms_theta = matrix(-1.232, nrow=length(sprayingtimesteps), ncol=3), # Matrix of deterrence parameters per timestep + ms_theta = matrix(-1.232, nrow=length(sprayingtimesteps), ncol=3), # Matrix of deterrence parameters ms_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=3) # Matrix of deterrence parameters per timestep ) From 025a4a3e3c89e04fa56e6d6126c68805a0550362 Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Thu, 2 Mar 2023 16:20:42 +0000 Subject: [PATCH 049/164] Updated the demography vignette to remove ggplot2 dependency and added added more detail to the explanations --- vignettes/Demography.Rmd | 211 +++++++++++++++++++++++++++------------ 1 file changed, 147 insertions(+), 64 deletions(-) diff --git a/vignettes/Demography.Rmd b/vignettes/Demography.Rmd index cfa68a00..cf76b0a5 100644 --- a/vignettes/Demography.Rmd +++ b/vignettes/Demography.Rmd @@ -15,24 +15,38 @@ knitr::opts_chunk$set( ``` ```{r setup} -suppressPackageStartupMessages(library(ggplot2)) +# Load in the requisite package(s): library(malariasimulation) ``` -# Parameterisation +# Introduction -We are going to create a scenario where we track severe prevalence for 5 years. +The dynamics of malaria transmission, and the efficacy of interventions designed to interrupt it, are highly context specific and an important consideration is the demography of the population(s) under investigation. To suit the research needs of the user, `malariasimulation` allows for the specification of custom human population demographics by allowing them to specify age-group specific death rates parameters. It also enables users to instruct the model to render output(s) with variables of interest (e.g. human population, number of cases detectable by microscopy, number of severe cases, etc.) presented by user-defined age groups. In this vignette we'll use simple, illustrative cases to demonstrate how to customise the output rendered by the `run_simulation()` function, specify a custom death rates, and, specify time-varying death rates. + +# Specifying human death rates by age group + +The `malariasimulation` package allows users to capture different human population demographies by specifying age-specific death rates. In the first section, we'll demonstrate how to instruct the model to output population and disease metrics by user-defined age groups and how to establish and run simulations with age-specific death rates. We'll illustrate the effect this has by comparing the demographic make-up of this custom parameterisation with that produced using the default parameters. + +## Default Parameterisation + +First, we'll establish a base set of parameters using the `get_parameters()` function and accepting the default values. The `run_simulation()` function's default behaviour is to output only the number of individuals aged 2-10 years old (`output$n_730_3650`). However, the user can instruct the model to output the number of individuals in age groups of their choosing using the `age_group_rendering_min_ages` and `age_group_rendering_max_ages` parameters. These arguments take vectors containing the minimum and maximum ages (in daily time steps) of the groups to be captured. To allow us to see the effect of changing demographic parameters, we'll use this functionality to output the number of individuals in ages groups ranging from 0 to 85 at 5 year intervals. Note that the same is possible for other model outputs, including the number (`n_detect` , `p_detect`, `n_severe`, `n_inc`, `p_inc`, `n_inc_clinical`, `p_inc_clinical`, `n_inc_severe`, and `p_inc_severe` ) using their equivalent min/max age-class rendering arguments (run `?run_simulation()` for more detail). + +We next use the `set_equilibrium()` function to tune the initial parameter set to that required to observe the specified initial entomological inoculation rate (`starting_EIR`). We now have a set of default parameters ready to use to run simulations. ```{r} -year <- 365 -month <- 30 -sim_length <- 5 * year + +# Set the timespan over which to simulate +year <- 365; years <- 5; sim_length <- year * years + +# Set an initial human population and initial entomological inoculation rate (EIR) human_population <- 1000 starting_EIR <- 5 +# Set the age ranges (in days) age_min <- seq(0, 80, 5) * 365 age_max <- seq(5, 85, 5) * 365 +# Use the get_parameters() function to establish the default simulation parameters, specifying age categories from 0-85 in 5 year intervals. simparams <- get_parameters( list( human_population = human_population, @@ -41,55 +55,74 @@ simparams <- get_parameters( ) ) +# Use set_equilibrium to tune the human and mosquito populations to those required for the defined EIR simparams <- set_equilibrium(simparams, starting_EIR) + ``` -## Custom demography +## **Custom Demographic Parameterisation** -We can set a custom demography: +Next, we'll use the the in-built `set_demography()` function to specify human death rates by age group. This function takes as inputs a parameter list to update, a vector of the age groups (in days) for which we specify death rates, a vector of time steps in which we want the death rates to be updated, and a matrix containing the death rates for each age group in each timestep. The `set_demography()` function appends these to the parameter list and updates the `custom_demography` parameter to `TRUE`. ```{r} -demography_params <- simparams -# Set a flat demography -ages <- round(c( - .083333, 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, - 85, 90, 95, 200) * year) +# Copy the simulation parameters as demography parameters: +dem_params <- simparams + +# We can set our own custom demography: +ages <- round(c(0.083333, 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 200) * year) +# Set deathrates for each age group (looks like by taking annual values and dividing by 365: deathrates <- c( .4014834, .0583379, .0380348, .0395061, .0347255, .0240849, .0300902, .0357914, .0443123, .0604932, .0466799, .0426199, .0268332, .049361, .0234852, .0988317, .046755, .1638875, .1148753, .3409079, .2239224, .8338688) / 365 -demography_params <- set_demography( - demography_params, +# Pass these custom ages and death rates through the in-built set_demography function +dem_params <- set_demography( + dem_params, agegroups = ages, timesteps = 0, deathrates = matrix(deathrates, nrow = 1) ) + +# Confirm that the custom demography has been set: +dem_params$custom_demography + ``` -Let's run the simulations +## Simulations + +Having established parameter sets with both default and custom demographic parameterisations, we can now run a simulation for each using the `run_simulation()` function. We'll also add a column to each identify the runs. ```{r} -# run and combine the outputs + +# Run the simulation with the default (?) demogaphic set-up exp_output <- run_simulation(sim_length, simparams) exp_output$run <- 'exponential' -custom_output <- run_simulation(sim_length, demography_params) + +# Run the simulation for the custom demographic set-up +custom_output <- run_simulation(sim_length, dem_params) custom_output$run <- 'custom' + + ``` -and now we can compare the age distributions in the populations -in year 5: +## Visualisation -```{r} -# wrangle outputs -output <- rbind(exp_output, custom_output) -output <- output[output$timestep == 5 * 365,] +Using barplots, we can visualise the effect of altering the demographic parameters by comparing the distribution of people among the age-classes we instructed the model to output. The default parameterisation. + +```{r, fig.width = 7.2, fig.height = 4, fig.fullwidth = TRUE} + +# Combine the two dataframes: +dem_output <- rbind(exp_output, custom_output) -# A function to extract the age variables and convert to long format -convert_to_long <- function(age_min, age_max, output){ +# Select the final day of the simulation for each of the two demography runs: +dem_output <- dem_output[dem_output$timestep == 5 * 365,] + +# Extract the age variables and convert the dataframe to long format: +convert_to_long <- function(age_min, age_max, output) { output <- lapply( seq_along(age_min), function(i) { @@ -97,60 +130,110 @@ convert_to_long <- function(age_min, age_max, output){ age_lower = age_min[[i]], age_upper = age_max[[i]], n = output[,paste0('n_age_', age_min[[i]], '_',age_max[[i]])], - age_mid = (age_min[[i]] + (age_min[[i]] - age_max[[i]]) / 2) / 365, - run = output$run, + age_plot = age_min[[i]]/365, + run = output$run, timestep = output$timestep) } ) output <- do.call("rbind", output) } -output <- convert_to_long(age_min, age_max, output) -# Plot the age distributions -ggplot(output, aes(x = age_mid, y = n)) + - geom_bar(stat = "identity") + - theme_bw() + - facet_wrap(~ run) +# Convert the output for plotting: +dem_output <- convert_to_long(age_min, age_max, dem_output) + +# Define a colour palette for plotting: +dem_cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") + +# Define the plotting window +par(mfrow = c(1, 2), mar = c(4, 4, 1, 1)) + +# a) Default/Exponentially-distributed demography +plot.new(); grid(lty = 1, col = "darkgrey", nx = 17, ny = 10, lwd = 0.5); par(new = TRUE) +barplot(height = dem_output[dem_output$run == "exponential", c("n", "age_plot")]$n, + names = dem_output[dem_output$run == "exponential", c("n", "age_plot")]$age_plot, + axes = TRUE, space = 0, ylim = c(0, 250), xaxs = "i", yaxs = "i", + main = "Default", xlab = "Age Group", ylab = "Individuals", + cex.axis = 0.8, cex.lab = 1, cex.main = 1, + col = dem_cols[2]); box() + +# b) Custom demography +plot.new() +grid(lty = 1, col = "darkgrey", nx = 17, ny = 10, lwd = 0.5) +par(new = TRUE) +barplot(height = dem_output[dem_output$run == "custom", c("n", "age_plot")]$n, + names = dem_output[dem_output$run == "custom", c("n", "age_plot")]$age_plot, + axes = TRUE, space = 0, ylim = c(0, 250), xaxs = "i", yaxs = "i", + main = "Custom", xlab = "Age Group", + cex.axis = 0.8, cex.lab = 1, cex.main = 1, + col = dem_cols[1]); box() + ``` -We can also specify time-varying death rates to capture a dynamic demography +# Dynamic demography: time-varying death rates -```{r, fig.width=7} -dynamic_demography_params <- simparams +Using the `timesteps` and `deathrates` arguments, we can also use the `set_demography()` function to update the death rates of specific age groups through time. In the following example, we'll use this functionality to first set our own initial death rates by age group, then instruct the model to increase the death rates in the age groups 5-10, 10-15, and 15-20 years old by a factor of 10. We'll finish by plotting the number of individuals in each age class at the end of each year to visualise the effect of time-varying death rates on the human population age-structure. -# Set a flat demography -ages <- round(c( - .083333, 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, - 85, 90, 95, 200) * year) +## Parameterisation -deathrates <- c( - .4014834, .0583379, .0380348, .0395061, .0347255, .0240849, .0300902, - .0357914, .0443123, .0604932, .0466799, .0426199, .0268332, .049361, - .0234852, .0988317, .046755, .1638875, .1148753, .3409079, .2239224, - .8338688) / 365 -# Let's increase the death rates in some age groups -deathrates_changed <- deathrates -deathrates_changed[3:6] <- deathrates_changed[3:6] * 10 +We'll start by making a copy of the base parameters which have been instructed to output the population size through time (`simparams`). Next, we create a version of the `deathrates` vector created earlier updated to increase the death rates of the 5-10, 10-15, and 15-20 age groups by 1000%. Finally, we use `set_demography()` to update our parameter list and specify our custom demography. This is achieved providing the `timesteps` argument with a vector of days to update the death rates (0 and 730 days), and providing `deathrates` with a matrix of death rates where each row corresponds to a set of death rates for a given update. + +```{r} + +# Store the simulation parameters in a new object for modification +dyn_dem_params <- simparams + +# Increase the death rates in some age groups (5-15 year olds): +deathrates_increased <- deathrates +deathrates_increased[3:6] <- deathrates_increased[3:6] * 10 -dynamic_demography_params <- set_demography( - dynamic_demography_params, +# Set the population demography using these updated deathrates +dyn_dem_params <- set_demography( + dyn_dem_params, agegroups = ages, - timesteps = c(0, 2 * 365), - deathrates = matrix(c(deathrates, deathrates_changed), nrow = 2, byrow = TRUE) + timesteps = c(0, 2*365), + deathrates = matrix(c(deathrates, deathrates_increased), nrow = 2, byrow = TRUE) ) -dynamic_demography_output <- run_simulation(sim_length, dynamic_demography_params) +``` + +## Simulations -# wrangle outputs -dynamic_demography_output <- dynamic_demography_output[dynamic_demography_output$timestep %in% (1:5 * 365),] -dynamic_demography_output$run <- "dynamic" +```{r} +# Run the simulation for the dynamic death rate demography +dyn_dem_output <- run_simulation(sim_length, dyn_dem_params) -dynamic_demography_output <- convert_to_long(age_min, age_max, dynamic_demography_output) +``` -# Plot the age distributions each year -ggplot(dynamic_demography_output, aes(x = age_mid, y = n)) + - geom_bar(stat = "identity") + - theme_bw() + - facet_wrap(~ timestep / 365, ncol = 5) -``` \ No newline at end of file +## Visualisation + +Boxplots of the age structure of the human population at the end of each year show the marked effect that increasing the death rate within a small subset of age classes can have on the demography of the human population over time. + +```{r, fig.width = 7.2, fig.height = 3, fig.fullwidth = TRUE} + +# Filter out the end-of-year population sizes, add a column naming the run, and convert dataframe to long-form: +dyn_dem_output <- dyn_dem_output[dyn_dem_output$timestep %in% (1:5 * 365),] +dyn_dem_output$run <- 'dynamic' +dyn_dem_output <- convert_to_long(age_min, age_max, dyn_dem_output) + +# Set a 1x5 plotting window: +par(mfrow = c(1,5), mar = c(4, 4, 1, 1)) + +# Loop through the years to plot: +for(i in 1:5) { + plot.new() + grid(lty = 1, col = "darkgrey", nx = 11, ny = 10, lwd = 0.5) + par(new = TRUE) + barplot(height = dyn_dem_output[dyn_dem_output$timestep/365 == i,c("n", "age_plot")]$n, + names = dyn_dem_output[dyn_dem_output$timestep/365 == i,c("n", "age_plot")]$age_plot, + axes = TRUE, space = 0, + ylim = c(0, 500), + main = paste0("Year ", i), cex.main = 1.4, + xlab = ifelse(i == 3, "Age Group", ""), + ylab = ifelse(i == 1, "Individuals", ""), + xaxs = "i", yaxs = "i", + cex.axis = 0.8, cex.lab = 1, cex.main = 1, col = dem_cols[3]) + box() +} + +``` From 84fe4884532478588a237c8b8d8dab227df40a9b Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Thu, 2 Mar 2023 16:35:05 +0000 Subject: [PATCH 050/164] Updated MDA vignette to remove ggplot2 dependency add additional explanations and illustrations --- vignettes/MDA.Rmd | 345 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 254 insertions(+), 91 deletions(-) diff --git a/vignettes/MDA.Rmd b/vignettes/MDA.Rmd index 7ac3f20c..c3299116 100644 --- a/vignettes/MDA.Rmd +++ b/vignettes/MDA.Rmd @@ -1,8 +1,8 @@ --- -title: "Mass Drug Administration" +title: "Mass Drug Administriation and Chemoprevention" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Mass Drug Administration} + %\VignetteIndexEntry{Mass Drug Administriation and Chemoprevention} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -15,22 +15,39 @@ knitr::opts_chunk$set( ``` ```{r setup} -suppressPackageStartupMessages(library(ggplot2)) -library(malariasimulation) -library(malariaEquilibrium) -library(reshape2) +# Load the requisite packages: +library(malariasimulation); library(malariaEquilibrium) + +# Define a colour palette for plotting: +plot_cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") + ``` -# Parameterisation +## Introduction + +Malaria chemoprevention encompasses a suite of strategies for reducing malaria morbidity, mortality, and transmission through the treatment of at-risk populations with antimalarial drugs. Three such strategies are mass drug administration (MDA), seasonal malaria chemoprevention (SMC), and perennial malaria chemoprevention (PMC). MDA attempts to simultaneously treat an entire population, irrespective of their infection risk or status. SMC targets children aged 3-59 months with a course of an antimalarial through the peak malaria transmission season. PMC is designed for settings with perennially high transmission and seeks to administer a full antimalarial course at defined intervals irrespective of age or disease status. + +`malariasimulation` enables users to simulate the effects of chemoprevention strategies on malaria transmission, and provides the flexibility to design and simulate a range of MDA/SMC/PMC campaigns for a suite of antimalarial drugs. Specifically, users are able to specify parameters describing both the characteristics of the antimalarial(s) (e.g. drug efficacy, prophylactic profile) and their distribution (e.g. coverage, distribution timing, and the section of the population to treat). This vignette provides simple, illustrative demonstrations of how MDA and SMC campaigns can be set-up and simulated using `malariasimulation`. **The functionality to simulate PMC campaigns is also built into `malariasimulation`, but we do not demonstrate that here (*can add*).** + +## Mass Drug Administration + +To illustrate how MDA can be simulated using `malariasimulation` , we will implement a campaign that distributes a single dose of sulphadoxine-pyrimethamine amodiaquine (SP-AQ) to 80% of the entire population once a year over a two year period, initiated at the end of the first year. -We are going to set the default parameters to run the simulation from an equilibrium. +### Parameterisation + +The first step is to generate the list of requisite parameters using the `get_parameters()` function. Here, we'll use the default `malariasimulation` parameter set (run `?get_parameters()` to view), but specify the seasonality parameters to simulate a bimodal rainfall pattern (see plot of adult female mosquitoes below). To do this, we set `model_seasonality` to TRUE within `get_parameters()`, and then tune the rainfall pattern using the `g0`, `g`, and `h` parameters (which represent fourier coefficients) to generate the seasonal rainfall profile. Rainfall governs the time-varying mosquito population carrying capacity through density-dependent regulation and, therefore, annual patterns of malaria transmission. Next, we use the `set_equilibrium()` function to tune the initial human and mosquito populations to those required to observe the specified initial EIR. ```{r} -year <- 365 -sim_length <- 3 * year +# Establish the length of time over which to simulate: +# Set the simulation duration +year <- 365; years <- 3 +sim_length <- years * year + +# Set the size of the human population and an initial entomological inoculation rate (EIR) human_population <- 1000 starting_EIR <- 50 +# Use the simparams() function to build the list of simulation parameters simparams <- get_parameters( list( human_population = human_population, @@ -40,119 +57,265 @@ simparams <- get_parameters( h = c(0.173743, -0.0730962, -0.116019) ) ) -simparams <- set_equilibrium(simparams, starting_EIR) -simparams <- set_drugs(simparams, list(SP_AQ_params)) - -# Plotting functions -plot_prevalence <- function(output) { - ggplot(output) + geom_line( - aes(x = timestep, y = (n_detect_730_3650/n_730_3650))) + - labs(x = "timestep", y = "PfPR2-10") -} -plot_state_counts <- function(output) { - ggplot( - melt( - output[c( - 'timestep', - 'S_count', - 'D_count', - 'A_count', - 'U_count', - 'Tr_count' - )], - id.vars='timestep' - ) - ) + geom_line( - aes( - x = timestep, - y = value, - group = variable, - color = variable - ) - ) -} +# Use the set_equilibrium() function to update the individual-based model parameters to those +# required to match the specified initial EIR (starting_EIR): +simparams <- set_equilibrium(simparams, starting_EIR) -add_mda_lines <- function(plot, events) { - plot + geom_vline( - data = events, - mapping = aes(xintercept=timestep), - color="blue" - ) + geom_text( - data = events, - mapping = aes(x = timestep, y = 0, label = name), - size = 4, - angle = 90, - vjust = -0.4, - hjust = 0 - ) -} ``` -Then we can run the simulation for a variety of MDA strategies: +### Interventions + +Having established a base set of parameters (`simparams`), the next step is to add the parameters specifying the MDA campaign. We first use the `get_drugs()` function to update `simparams` with the parameter values for the drug(s) we wish to simulate, in this case using the in-built parameter set for SP-AQ. Note that the `malariasimulation` package also contains in-built parameter sets for dihydroartemisinin-piperaquine (DHA_PQP_params) and artemether lumefantrine (AL_params), and users can also define their own drug parameters. -## MDA +**Re-Add explanatnion of drug parameters** -This is a dose of SP-AQ to 80% of the population once a year. +We then define the dates on which we want the MDA (stored here in the vector `mda_events` for legibility), and use the `set_mda()` function to update the parameter list with our MDA campaign parameters. `set_mda()` takes as its first two arguments the base parameter list and the time steps on which to schedule MDA events. This function also requires the user to specify the proportion of the population we want to treat using `coverages`, as well as the age-range of the population we want to treat using `min_ages` and `max_ages`, *for each day of scheduled MDA*. Note that this enables users to specify individual events to have different properties. The `drug` argument refers to the index of the drug we want to distribute in the MDA in the list of parameters (in this demonstration we have only added a single drug, SP-AQ, using `set_drugs()`, but we could have specified additional drugs). ```{r} + +# Make a copy of the base simulation parameters to which we can add the MDA campaign parameters: mdaparams <- simparams -# Add MDA strategy -mda_events = data.frame( - timestep = c(1, 2) * 365, - name=c("MDA 1", "MDA 2") -) +# Update the parameter list with the default parameters for sulphadoxine-pyrimethamine amodiaquine (SP-AQ) +mdaparams <- set_drugs(mdaparams, list(SP_AQ_params)) -mdaparams <- set_mda( - mdaparams, - drug = 1, - timesteps = mda_events$timestep, - coverages = rep(.8, 2), - min_ages = rep(0, length(mda_events$timestep)), - max_ages = rep(200 * 365, length(mda_events$timestep)) -) +# Specify the days on which to administer the SP-AQ +mda_events <- (c(1, 2) * 365) + +# Use set_mda() function to set the proportion of the population that the MDA reaches and the age +# ranges which can receive treatment. +mdaparams <- set_mda(mdaparams, + drug = 1, + timesteps = mda_events, + coverages = rep(.8, 2), + min_ages = rep(0, length(mda_events)), + max_ages = rep(200 * 365, length(mda_events))) -output <- run_simulation(sim_length, mdaparams) ``` +Having generated a base, no-intervention parameter set (`simparams`) and a version updated to define an MDA campaign (`mdaparams`), we can now use the `run_simulation()` function to run simulations for scenarios without interventions and with our MDA campaign. + +### Simulation + ```{r} -add_mda_lines(plot_state_counts(output), mda_events) +# Run the simulation in the absence of any interventions: +noint_output <- run_simulation(sim_length, simparams) + +# Run the simulation with the prescribed MDA campaign +mda_output <- run_simulation(sim_length, mdaparams) ``` -```{r} -add_mda_lines(plot_prevalence(output), mda_events) +### Visualisation + +The `run_simulation()` function returns a dataframe containing time series for a range of variables, including the number of human individuals in each infectious state, and the number of people and detected cases in children aged 2-10. The plots below illustrate how the effect of an MDA campaign on the malaria transmission dynamics can be visualised. The first presents the distribution of people in the amongt the infectious states. The second compares the prevalence of malaria in children aged 2-10 years old (*Pf*PR~2-10~) between the no-intervention and MDA scenarios simulated. + +```{r, fig.width=7.2, fig.height=4, fig.fullwidth=TRUE} + +# Store the state names, and labels and colours with which to plot them: +states <- c("S_Count", "D_count", "Tr_count", "A_count", "U_count") +state_labels <- c("S", "D", "Tr", "A", "U") + +# Open a new plotting window: +plot.new(); par(mar = c(4, 4, 1, 1), new = TRUE) + +# Plot the time series +plot(x = mda_output$timestep, y = mda_output$S_count, + type = "l", col = plot_cols[1], lwd = 2, + ylim = c(0, 850), ylab = "Individuals", xlab = "Time (days)", + xaxs = "i", yaxs = "i", cex = 0.8) + +# Overlay the time-series for other states +for(i in 1:(length(states)-1)) { + lines(mda_output[,states[i+1]], col = plot_cols[i+1], lwd = 2) +} + +# Add vlines to show when SP-AQ was administered: +abline(v = mda_events, lty = "dashed", lwd = 1) + +# Add gridlines: +grid(lty = 1, col = "darkgrey", nx = NULL, ny = NULL, lwd = 0.5); box() + +# Add a legend: +legend(x = 930, y = 840, + legend = c(state_labels, "MDA"), + col = c(plot_cols[1:5], "black"), lty = c(rep(1, 5), 2), + lwd = 1, cex = 0.8, box.col = "white") + ``` -## SMC +```{r, fig.width = 7.2, fig.height = 4, fig.fullwidth = TRUE} -This is a dose of SP-AQ to 90% of 2 - 11 year olds once a year a month before the peak season for mosquitoes. +# Open a new plotting window and add a grid: +plot.new(); par(mar = c(4, 4, 1, 1), new = TRUE) -```{r} +# Plot malaria prevalence in 2-10 years through time: +plot(x = mda_output$timestep, + y = mda_output$n_detect_730_3650/mda_output$n_730_3650, + xlab = "Time (days)", + ylab = expression(paste(italic(Pf),"PR"[2-10])), cex = 0.8, + ylim = c(0, 1), type = "l", lwd = 2, xaxs = "i", yaxs = "i", + col = plot_cols[3]) + +# Add the dynamics for no-intervention simulation +lines(x = noint_output$timestep, + y = noint_output$n_detect_730_3650/noint_output$n_730_3650, + col = plot_cols[4]) + +# Add vlines to indicate when SP-AQ were administered: +abline(v = mda_events, lty = "dashed", lwd = 1) + +# Add gridlines: +grid(lty = 1, col = "darkgrey", nx = NULL, ny = NULL, lwd = 0.5); box() + +# Add a legend: +legend(x = 870, y = 0.99, + legend = c("MDA", "No-Int", "MDA Day"), + col= c(plot_cols[3:4], "black"), box.col = "white", + lwd = 1, lty = c(1, 1, 2), cex = 0.8) + +``` + +## Seasonal Malaria Chemoprevention + +To demonstrate how to simulate SMC in `malariasimulation` , in the following section we'll set-up and simulate a campaign that treats 80% of children aged 3-59 months old with four doses of SP-AQ per year. We will set the SMC campaign to begin in the second year, run for two years, and target the four SMC events to at monthly intervals, starting a month prior to the peak malaria season. + +### Interventions + +While the first step would typically be to establish the base set of parameters, we can use those stored earlier in `simparams`. We first store a copy of these base parameters and then use `set_drugs()` to store the preset parameters for SP-AQ in the parameter list. + +As SMC is conducted during the peak malaria season, we need to use the `peak_season_offset()` function to determine when the peak malaria season occurs given our specified seasonal profile. This function reads in the parameter list, uses `g0`, `g`, `h`, and `rainfall_floor` to generate the rainfall profile for a single year, and returns the day on which the maximum value occurs. We can then take this calculated seasonal peak and time SMC events around it. Here, we've specified four monthly drug administration days per year starting one month before the seasonal peak. + +To illustrate this, we can plot the total adult mosquito population size through time, which in the absence of interventions targeting mosquitoes will closely matches the rainfall pattern, and overlay both the annual seasonal peak and planned SMC events. Once we're happy with our SMC campaign, we use the `set_smc()` function to update the parameter list with our `drug`, `timesteps`, `coverages` and target age group (`min_ages` and `max_ages`). + +```{r, fig.width=7.2, fig.height=4, fig.fullwidth=TRUE} + +# Copy the original simulation parameters smcparams <- simparams -# Add SMC strategy +# Append the parameters for SP-AQ using set_drugs +smcparams <- set_drugs(smcparams, list(SP_AQ_params)) + +# Use the peak_season_offset() to calculate the yearly offset (in daily timesteps) for the peak mosq. +# season peak <- peak_season_offset(smcparams) -smc_events = data.frame( - timestep = c(1, 2) * 365 + peak - 30, - name=c("SMC 1", "SMC 2") -) + +# Create a variable for total mosquito population through time: +noint_output$mosq_total = noint_output$Sm_All_count + noint_output$Im_All_count + noint_output$Pm_All_count + +# Set-up the times (in days) around the peak to schedule drug administration days: +admin_days <- c(-30, 0, 30, 60) + +# Use the peak-offset, number of simulation years and number of drug admin. days to calculate the days +# on which to administer drugs in each year +smc_days <- rep((365 * seq(1, years-1, by = 1)), each = length(admin_days)) + peak + rep(admin_days, 2) + +# Plot the total adult mosquito population through time: +# Open a new plotting window,set the margins and plot the mosquito population +plot.new(); par(new = TRUE, mar = c(4, 4, 1, 1)) +plot(x = noint_output$timestep, y = noint_output$mosq_total, + xlab = "Time (days)", ylab = "Adult Female Mosquitos", + ylim = c(0, max(noint_output$mosq_total)*1.1), + type = "l", lwd = 2, cex = 0.8, + xaxs = "i", yaxs = "i", + col = plot_cols[3]) + +# Add grinlines +grid(lty = 1, col = "darkgrey", nx = 11, ny = NULL, lwd = 0.5); box() + +# Overlay the SMC days and the calculated seasonal peak +abline(v = smc_days, lty = "dashed", lwd = 2) +abline(v = c(0, 1, 2) * 365 + peak, lty = 2, lwd = 2, col = plot_cols[4]) + +# Add a legend: +legend(x = (sim_length * 0.83), y = 61000, + legend = c(expression("M"["Tot"]), "MDA", "Peak"), + col= c(plot_cols[3], "black", plot_cols[4]), box.col = "white", + lty = c(1, 2, 2), lwd = 2, cex = 0.9) + +# Update the SMC parameters list: smcparams <- set_smc( smcparams, drug = 1, - timesteps = smc_events$timestep, - coverages = rep(.9, 2), - min_ages = rep(2 * 365 - 1, length(smc_events$timestep)), - max_ages = rep(11 * 365, length(smc_events$timestep)) + timesteps = smc_days, + coverages = rep(0.9, length(smc_days)), + min_ages = rep(3 * 30, length(smc_days)), + max_ages = rep(59 * 30, length(smc_days)) ) -output <- run_simulation(sim_length, smcparams) ``` +### Simulations + +Having generated our SMC parameter list, we can run the simulation using the `run_simulation()` function. + ```{r} -add_mda_lines(plot_state_counts(output), smc_events) +# Run the SMC simulation +smc_output <- run_simulation(sim_length, smcparams) + ``` -```{r} -add_mda_lines(plot_prevalence(output), smc_events) +### Visualisation + +We can now plot the model output to get an idea of the effect of our SMC campaign on malaria transmission dynamics, again focusing on the distribution of people in each of the infectious states and on malaria prevalence in children aged 2-10 (*Pf*PR~2-10~). + +```{r, fig.width=7.2, fig.height=4, fig.fullwidth=TRUE} + +# Open a new plotting window and add a grid: +plot.new(); par(new = TRUE, mar = c(4, 4, 1, 1)) + +# Plot the time series of human infectious states through time under the SMC campaign +plot(x = smc_output$timestep, y = smc_output$S_count, + type = "l", col = plot_cols[1], lwd = 2, + ylim = c(0, 850), ylab = "Individuals", xlab = "Time (days)", + xaxs = "i", yaxs = "i", cex = 0.8) + +# Overlay the time-series for other human infection states +for(i in 1:(length(states)-1)) { + lines(smc_output[,states[i+1]], col = plot_cols[i+1], lwd = 2) +} + +# Add vlines to indicate when SMC drugs were administered: +abline(v = smc_days, lty = "dashed", lwd = 1) + +# Add gridlines: +grid(lty = 1, col = "darkgrey", nx = NULL, ny = NULL, lwd = 0.5) + +# Add a legend: +legend(x = 920, y = 840, + legend = c(state_labels, "SMC"), + col = c(plot_cols[1:5], "black"), lty = c(rep(1, 5), 2), + box.col = "white", lwd = 2, cex = 0.9) + +``` + +```{r, fig.width=7.2, fig.height=4, fig.fullwidth=TRUE} + +# Open a new plotting window and add a grid: +plot.new(); par(new = TRUE, mar = c(4, 4, 1, 1)) + +# Recreate figure 2: +plot(x = smc_output$timestep, y = smc_output$n_detect_730_3650/smc_output$n_730_3650, + xlab = "Time (days)", + ylab = expression(paste(italic(Pf),"PR"[2-10])), cex = 0.8, + ylim = c(0, 1), type = "l", lwd = 2, xaxs = "i", yaxs = "i", + col = plot_cols[3]) + +# Add the dynamics for no-intervention simulation +lines(x = noint_output$timestep, + y = noint_output$n_detect_730_3650/noint_output$n_730_3650, + col = plot_cols[4]) + +# Add lines to indicate SMC events: +abline(v = smc_days, lty = "dashed", lwd = 1) + +# Add gridlines: +grid(lty = 1, col = "darkgrey", nx = 11, ny = 10, lwd = 0.5) + +# Add a legend: +legend(x = 870, y = 0.99, + legend = c("SMC", "No-Int", "SMC Day"), + col= c(plot_cols[3:4], "black"), box.col = "white", + lwd = 1, lty = c(1, 1, 2), cex = 0.8) + ``` From a6da47d54df7477c57830192a4de00beab2886df Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 3 Mar 2023 12:17:24 +0000 Subject: [PATCH 051/164] reverting changes to vector_control_parameters.R --- R/vector_control_parameters.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/vector_control_parameters.R b/R/vector_control_parameters.R index 6e88c733..5a6bfe0a 100644 --- a/R/vector_control_parameters.R +++ b/R/vector_control_parameters.R @@ -84,11 +84,11 @@ set_bednets <- function( #' With nrows=length(timesteps), ncols=length(species) #' @param ls_gamma matrix of mortality parameters per timestep #' With nrows=length(timesteps), ncols=length(species) -#' @param ks_theta matrix of feeding success parameters +#' @param ks_theta matrix of feeding success parameters per timestep #' With nrows=length(timesteps), ncols=length(species) #' @param ks_gamma matrix of feeding success parameters per timestep #' With nrows=length(timesteps), ncols=length(species) -#' @param ms_theta matrix of deterrence parameters +#' @param ms_theta matrix of deterrence parameters per timestep #' With nrows=length(timesteps), ncols=length(species) #' @param ms_gamma matrix of deterrence parameters per timestep #' With nrows=length(timesteps), ncols=length(species) From 7a633813e356777fe0c08dcd12aa240bc48cbf5b Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 3 Mar 2023 12:19:14 +0000 Subject: [PATCH 052/164] reverting changes --- R/vector_control_parameters.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/vector_control_parameters.R b/R/vector_control_parameters.R index 5a6bfe0a..fe4b1f0c 100644 --- a/R/vector_control_parameters.R +++ b/R/vector_control_parameters.R @@ -84,11 +84,11 @@ set_bednets <- function( #' With nrows=length(timesteps), ncols=length(species) #' @param ls_gamma matrix of mortality parameters per timestep #' With nrows=length(timesteps), ncols=length(species) -#' @param ks_theta matrix of feeding success parameters per timestep +#' @param ks_theta matrix of feeding success parameters per timestep #' With nrows=length(timesteps), ncols=length(species) #' @param ks_gamma matrix of feeding success parameters per timestep #' With nrows=length(timesteps), ncols=length(species) -#' @param ms_theta matrix of deterrence parameters per timestep +#' @param ms_theta matrix of deterrence parameters per timestep #' With nrows=length(timesteps), ncols=length(species) #' @param ms_gamma matrix of deterrence parameters per timestep #' With nrows=length(timesteps), ncols=length(species) From 00b942fbc066e3a8e7c0c4da8cc41e5ac9d7b6cd Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 3 Mar 2023 12:28:03 +0000 Subject: [PATCH 053/164] Deleting IRS vignette and reverting bednet vignette --- vignettes/VectorControl.Rmd | 125 ++++++++++++-------------- vignettes/VectorControl_IRS.Rmd | 153 -------------------------------- 2 files changed, 59 insertions(+), 219 deletions(-) delete mode 100644 vignettes/VectorControl_IRS.Rmd diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index 2f5dff91..733ddb27 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -1,8 +1,8 @@ --- -title: "Vector Control: Bednets" +title: "Vector Control" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Vector Control: Bednets} + %\VignetteIndexEntry{Vector Control} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -15,13 +15,15 @@ knitr::opts_chunk$set( ``` ```{r setup} +suppressPackageStartupMessages(library(ggplot2)) library(malariasimulation) library(malariaEquilibrium) +library(reshape2) ``` # Parameterisation -We will set the default parameters to run the simulation from an equilibrium. +We are going to set the default parameters to run the simulation from an equilibrium. ```{r} year <- 365 @@ -29,98 +31,89 @@ month <- 30 sim_length <- 3 * year human_population <- 1000 starting_EIR <- 50 - simparams <- get_parameters( list( human_population = human_population, - # carrying capacity parameters model_seasonality = TRUE, # Let's try a bi-modal model g0 = 0.28605, g = c(0.20636, -0.0740318, -0.0009293), h = c(0.173743, -0.0730962, -0.116019), - # Here, we are asking for the output to contain information on severe incidence in children 2-10 years old. - clinical_incidence_rendering_min_ages = 2*year, - clinical_incidence_rendering_max_ages = 10*year + severe_incidence_rendering_min_ages = 2*year, + severe_incidence_rendering_max_ages = 10*year ) ) - simparams <- set_equilibrium(simparams, starting_EIR) -``` - -We can create a few plotting functions to visualise the output. -```{r} -cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", - "#F0E442", "#0072B2", "#D55E00", "#CC79A7") - # Plotting functions plot_prevalence <- function(output) { - plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, - type = 'l', col = cols[4], - xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), - xaxs = "i", yaxs = "i", bty = "l") + ggplot(output) + geom_line( + aes(x = timestep, y = (n_inc_severe_730_3650 / n_730_3650))) + + labs(x = "timestep", y = "Severe incidence") } - add_intervention_lines <- function(plot, events) { - plot - abline(v = events$timestep, lty = 2, lwd = 2.5) - text(x = events$timestep - 20, y = 0.4, events$name, - cex = 1, col = cols[1], srt = 90) + plot + geom_vline( + data = events, + mapping = aes(xintercept=timestep), + color="blue" + ) + geom_text( + data = events, + mapping = aes(x = timestep, y = 0, label = name), + size = 4, + angle = 90, + vjust = -0.4, + hjust = 0 + ) } ``` -## Adding bednets +Then we can run the simulation for a variety of vector control strategies: + +## Bed nets + +We can distribute bed nets once a year for two years, changing the +characteristics of the bed nets on each distribution... -Then we can run the simulation for a variety of bednet strategies. In the example below, we distribute bednets once a year for two years, changing the characteristics of the bed nets for each distribution. - ```{r} bednetparams <- simparams - bednet_events = data.frame( - timestep = c(1, 2) * year, # The bednets will be distributed at the end of the first and the second year. - name=c("Bednets 1", "Bednets 2") # These are labels for the two distributions. + timestep = c(1, 2) * year, + name=c("Bednets 1", "Bednets 2") ) - bednetparams <- set_bednets( bednetparams, - timesteps = bednet_events$timestep, - coverages = c(.8, .8), # Each round is distributed to 80% of the population - retention = 5 * year, # Nets are kept on average 5 years - dn0 = matrix(c(.533, .45), nrow=2, ncol=1), # Matrix of death probabilities for each mosquito species over time - rn = matrix(c(.56, .5), nrow=2, ncol=1), # Matrix of repelling probabilities for each mosquito species over time - rnm = matrix(c(.24, .24), nrow=2, ncol=1), # Matrix of minimum repelling probabilities for each mosquito species over time - gamman = rep(2.64 * 365, 2) # Vector of bednet half-lives for each distribution timestep + timesteps = bednet_events$timestep, + coverages = c(.8, .8), + retention = 5 * year, + dn0 = matrix(c(.533, .45), nrow=2, ncol=1), + rn = matrix(c(.56, .5), nrow=2, ncol=1), + rnm = matrix(c(.24, .24), nrow=2, ncol=1), + gamman = rep(2.64 * 365, 2) ) - output <- run_simulation(sim_length, bednetparams) - add_intervention_lines(plot_prevalence(output), bednet_events) ``` - -It is important to understand the difference between the input `coverages` argument of `malariasimulation::set_bednets()` and the resulting population bednet usage over time in the model. In the above example, bednets are distributed to 80% of the population at each distribution round. - -The average population bednet usage will be influenced by: -* The size and frequency of distributions specified in `set_bednets()` -* The assumed net retention half life -* Correlations in the recipients of nets between rounds - -### Visualising bednet usage +## Indoor spraying -The output from `malariasimulation::run_simulation()` has a variable that shows the number of people using bednets at any given timestep. We can visualise this to understand how bednet usage changes over time. +We can do the same for IRS... ```{r} -output$prop_use_net <- output$n_use_net / human_population - -plot(x = output$timestep, y = output$prop_use_net, type = 'l', col = cols[1], - xlab = 'Timestep (days)', ylab = 'Proportion using bednets', - xaxs = "i", yaxs = "i", bty = "l") -``` - -## Using the `netz` package to estimate coverage inputs needed to achieve target population usage - -The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool to help set up bednets in `malariasimulation`. `malariasimulation` takes as input the proportion of the population who were distributed a bednet at specific time points, but available data for a specific region or country do not always have this information. `netz` allows for simple conversions between bednet metrics like crop, access, distribution, and usage. - -See the vignettes from the `netz` package that explain these concepts more comprehensively: -* [This vignette](https://mrc-ide.github.io/netz/articles/overview.html) explains how to estimate the distribution coverage from a specified bednet usage. -* [This vignette](https://mrc-ide.github.io/netz/articles/population_usage.html) demonstrates how to estimate population bednet usage from input distribution. - +sprayingparams <- simparams +peak <- peak_season_offset(sprayingparams) +spraying_events = data.frame( + timestep = c(1, 2) * year + peak - 3 * month, + name=c("Spraying 1", "Spraying 2") +) +sprayingparams <- set_spraying( + sprayingparams, + timesteps = spraying_events$timestep, + coverages = rep(.8, 2), + ls_theta = matrix(c(2.025, 2.025), nrow=2, ncol=1), + ls_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1), + ks_theta = matrix(c(-2.222, -2.222), nrow=2, ncol=1), + ks_gamma = matrix(c(0.008, 0.008), nrow=2, ncol=1), + ms_theta = matrix(c(-1.232, -1.232), nrow=2, ncol=1), + ms_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1) +) +output <- run_simulation(sim_length, sprayingparams) +add_intervention_lines(plot_prevalence(output), spraying_events) +``` \ No newline at end of file diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd deleted file mode 100644 index ce794b0a..00000000 --- a/vignettes/VectorControl_IRS.Rmd +++ /dev/null @@ -1,153 +0,0 @@ ---- -title: "Vector Control: Indoor Residual Spraying" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{Vector Control: IRS} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r, include = FALSE} -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>" -) -``` - -```{r setup} -library(malariasimulation) -library(malariaEquilibrium) -``` - -# Parameterisation - -We will set the default parameters to run the simulation from an equilibrium. - -```{r} -year <- 365 -month <- 30 -sim_length <- 3 * year -human_population <- 1000 -starting_EIR <- 50 - -simparams <- get_parameters( - list( - human_population = human_population, - # carrying capacity parameters - model_seasonality = TRUE, # Let's try a bi-modal model - g0 = 0.28605, - g = c(0.20636, -0.0740318, -0.0009293), - h = c(0.173743, -0.0730962, -0.116019), - # Here, we are asking for the output to contain information on severe incidence in children 2-10 years old. - clinical_incidence_rendering_min_ages = 2*year, - clinical_incidence_rendering_max_ages = 10*year - ) -) - -simparams <- set_equilibrium(simparams, starting_EIR) -``` - -We can create a few plotting functions to visualise the output. -```{r} -cols <- c("#000000", "#E69F00", "#56B4E9", "#009E73", - "#F0E442", "#0072B2", "#D55E00", "#CC79A7") - -# Plotting functions -plot_prevalence <- function(output) { - plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, - type = 'l', col = cols[4], - xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), - xaxs = "i", yaxs = "i", bty = "l") -} - -add_intervention_lines <- function(plot, events) { - plot - abline(v = events$timestep, lty = 2, lwd = 2.5) - text(x = events$timestep - 20, y = 0.4, events$name, - cex = 1, col = cols[1], srt = 90) -} -``` - -## Adding indoor residual spraying (IRS) - -Then we can run the simulation for a variety of IRS strategies. In the example below, there are two rounds of IRS, each 3 months prior to peak transmission for that year. -```{r} -sprayingparams <- simparams - -peak <- peak_season_offset(sprayingparams) -spraying_events = data.frame( - timestep = c(1, 2) * year + peak - 3 * month, # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. - name=c("Spraying 1", "Spraying 2") # These are labels for the two rounds of IRS -) - -sprayingparams <- set_spraying( - sprayingparams, - timesteps = spraying_events$timestep, - coverages = rep(.8, 2), # # Each round covers 80% of the population - ls_theta = matrix(c(2.025, 2.025), nrow=2, ncol=1), # Matrix of mortality parameters - ls_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1), # Matrix of mortality parameters per timestep - ks_theta = matrix(c(-2.222, -2.222), nrow=2, ncol=1), # Matrix of feeding success parameters - ks_gamma = matrix(c(0.008, 0.008), nrow=2, ncol=1), # Matrix of feeding success parameters per timestep - ms_theta = matrix(c(-1.232, -1.232), nrow=2, ncol=1), # Matrix of deterrence parameters - ms_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1) # Matrix of deterrence parameters per timestep -) - -output <- run_simulation(sim_length, sprayingparams) - -add_intervention_lines(plot_prevalence(output), spraying_events) -``` - -## Additional species -It is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. If you have specified more than 1 species, then the arguments for `set_spraying()` and `set_bednets()` must be populated with values for each species at each time point. - -We will run the same model with IRS as above, but this time with 3 species of mosquitoes. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. Each column corresponds to a species of mosquito, and each row corresponds to the timestep when a round of IRS occurred. Here, we are assuming the same values for each species at each timepoint for simplicity, but the matrix could be edited to have different values by species or over time. -```{r} -# Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae -simparams <- set_species( - simparams, - species = list(arab_params, fun_params, gamb_params), - proportions = c(0.25, 0.25, 0.5) -) - -sprayingparams <- simparams - -peak <- peak_season_offset(sprayingparams) -spraying_events = data.frame( - timestep = c(1, 2) * year + peak - 3 * month, # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. - name=c("Spraying 1", "Spraying 2") # These are labels for the two rounds of IRS -) - -sprayingparams <- set_spraying( - sprayingparams, - timesteps = spraying_events$timestep, - coverages = rep(.8, 2), # # Each round covers 80% of the population - ls_theta = matrix(c(rep(2.025, sim_length/year), - rep(2.025, sim_length/year), - rep(2.025, sim_length/year), - nrow=sim_length/year, ncol=3)), # Matrix of mortality parameters - ls_gamma = matrix(c(rep(-0.009, sim_length/year), - rep(-0.009, sim_length/year), - rep(-0.009, sim_length/year)), - nrow=sim_length/year, ncol=3), # Matrix of mortality parameters per timestep - ks_theta = matrix(c(rep(-2.222, sim_length/year), - rep(-2.222, sim_length/year), - rep(-2.222, sim_length/year)), - nrow=sim_length/year, ncol=3), # Matrix of feeding success parameters - ks_gamma = matrix(c(rep(0.008, sim_length/year), - rep(0.008, sim_length/year), - rep(0.008, sim_length/year)), - nrow=sim_length/year, ncol=3), # Matrix of feeding success parameters per timestep - ms_theta = matrix(c(rep(-1.232, sim_length/year), - rep(-1.232, sim_length/year), - rep(-1.232, sim_length/year)), - nrow=sim_length/year, ncol=3), # Matrix of deterrence parameters - ms_gamma = matrix(c(rep(-0.009, sim_length/year), - rep(-0.009, sim_length/year), - rep(-0.009, sim_length/year)), - nrow=sim_length/year, ncol=3) # Matrix of deterrence parameters per timestep -) - -output <- run_simulation(sim_length, sprayingparams) - -add_intervention_lines(plot_prevalence(output), spraying_events) -``` From fb11fecc59a0dc79b0886099dd453bfc887fb92d Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 3 Mar 2023 12:30:28 +0000 Subject: [PATCH 054/164] Revert vector control changes --- vignettes/VectorControl.Rmd | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index 733ddb27..7c29d75f 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -31,6 +31,7 @@ month <- 30 sim_length <- 3 * year human_population <- 1000 starting_EIR <- 50 + simparams <- get_parameters( list( human_population = human_population, @@ -42,13 +43,16 @@ simparams <- get_parameters( severe_incidence_rendering_max_ages = 10*year ) ) + simparams <- set_equilibrium(simparams, starting_EIR) + # Plotting functions plot_prevalence <- function(output) { ggplot(output) + geom_line( aes(x = timestep, y = (n_inc_severe_730_3650 / n_730_3650))) + labs(x = "timestep", y = "Severe incidence") } + add_intervention_lines <- function(plot, events) { plot + geom_vline( data = events, @@ -74,10 +78,12 @@ characteristics of the bed nets on each distribution... ```{r} bednetparams <- simparams + bednet_events = data.frame( timestep = c(1, 2) * year, name=c("Bednets 1", "Bednets 2") ) + bednetparams <- set_bednets( bednetparams, timesteps = bednet_events$timestep, @@ -88,7 +94,9 @@ bednetparams <- set_bednets( rnm = matrix(c(.24, .24), nrow=2, ncol=1), gamman = rep(2.64 * 365, 2) ) + output <- run_simulation(sim_length, bednetparams) + add_intervention_lines(plot_prevalence(output), bednet_events) ``` @@ -98,11 +106,13 @@ We can do the same for IRS... ```{r} sprayingparams <- simparams + peak <- peak_season_offset(sprayingparams) spraying_events = data.frame( timestep = c(1, 2) * year + peak - 3 * month, name=c("Spraying 1", "Spraying 2") ) + sprayingparams <- set_spraying( sprayingparams, timesteps = spraying_events$timestep, @@ -114,6 +124,8 @@ sprayingparams <- set_spraying( ms_theta = matrix(c(-1.232, -1.232), nrow=2, ncol=1), ms_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1) ) + output <- run_simulation(sim_length, sprayingparams) + add_intervention_lines(plot_prevalence(output), spraying_events) ``` \ No newline at end of file From abdc9ebcd4dd4786ec63effe7078527b69a0926e Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 3 Mar 2023 12:36:44 +0000 Subject: [PATCH 055/164] last change to revert.. --- vignettes/VectorControl.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index 7c29d75f..67e07881 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -128,4 +128,4 @@ sprayingparams <- set_spraying( output <- run_simulation(sim_length, sprayingparams) add_intervention_lines(plot_prevalence(output), spraying_events) -``` \ No newline at end of file +``` From 1ed953fa97533c0b08513e7866e04213e2b7928c Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Fri, 3 Mar 2023 15:55:21 +0000 Subject: [PATCH 056/164] Treatment Finished? --- vignettes/Treatment.Rmd | 132 ++++++++++++++++++++++++++-------------- 1 file changed, 87 insertions(+), 45 deletions(-) diff --git a/vignettes/Treatment.Rmd b/vignettes/Treatment.Rmd index f866691c..f40250fd 100644 --- a/vignettes/Treatment.Rmd +++ b/vignettes/Treatment.Rmd @@ -25,40 +25,77 @@ This vignette describes how to implement clinical drug treatments in malariasimu The malariasimulation package contains in-built parameters sets for three anti-malarial drugs: -1. AL_params: artemether-lumefantrine -2. DHA_PQP_params: dihydroartemisinin and piperaquine -3. SP_AQ: sulfadoxine-pyrimethamine and amodiaquine +1. `AL_params`: artemether-lumefantrine (AL) +2. `DHA_PQP_params`: dihydroartemisinin and piperaquine (DHA-PQP) +3. `SP_AQ_params`: sulfadoxine-pyrimethamine and amodiaquine (SP-AQ) -which can be included using the `set_drugs()` function. Multiple drugs can be used simultaneously, input as a list as shown in the below example. +While all these drugs can be used to treat malaria, DHA-PQP and SP-AQ remain in the body for some time following treatment, making them good candidates for chemoprevention in mass drug administrations (see [Mass Drug Administration](https://mrc-ide.github.io/malariasimulation/articles/MDA.html). Any of these drugs can be included in the parameter list using the `set_drugs()` function (see [drugs_parameters.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/drug_parameters.R) for full parameter details). -Each drug parameter set is a vector of length four, that represent the `drug efficacy`, ***drug_rel_c***, ***drug_prophylaxis_shape***, and ***drug_prophylaxis_scale***. ***I don't fully know the impact of changing these parameters, or what they mean exactly, e.g. rel_c is relative concentration? prophylaxis_shape? Scale? What does that look like*** \ +Each drug parameter set is a vector of length four, that represent the drug efficacy, the infectiousness following treatment relative to an untreated infection, and parameters that determine the protection against reinfection ($P$): shape ($w$) and scale ($\lambda$) using an exponential decrease as follows: -For example: +$$P = e^{{(-t/\lambda)}^w}$$ + +The $P$ for each drug following treatment through time is plotted below. + +```{r, echo = FALSE, fig.align = 'center', fig.height = 5, fig.width = 7} +cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") + +calc_P <- function(w, lambda, t){ + P <- exp(-(t/lambda)^w) +} + +t <- 1:70 + +P_matrix <- lapply(list(AL_params, DHA_PQP_params, SP_AQ_params), function(x){ + calc_P(w = x[3], lambda = x[4], t = t) +}) + +plot(x = t, y = P_matrix[[1]], type = "l", col = cols[1], + xlab = "Days", ylab = expression(paste("Protection against reinfection (",italic(P),")"))) +grid() + +# +invisible(sapply(2:3, function(x){ + points(x = t, y = P_matrix[[x]], type = "l", col = cols[x]) +})) + +# Add legend +legend("topright", legend = c("AL","DHA-PQP","SP-AQ"), col = cols, lty = 1) -```{r} -AL_params ``` +For more details, please see: + +Okell, L., Cairns, M., Griffin, J. *et al.* Contrasting benefits of different artemisinin combination therapies as first-line malaria treatments using model-based cost-effectiveness analysis. *Nat Commun* **5**, 5606 (2014). . + + +## Functions + Drug parameters can be incorporated into a complete parameter set: ```{r} Intro_parms <- set_drugs(parameters = get_parameters(), drugs = AL_params) ``` -A treatment regiment for each drug can then be described using the `set_clinical_treatment()` function which takes the drug index, a vector of timesteps for each change in coverage and a vector of coverages for the drug, as well as the complete parameter set. This function must be used for each drug included (e.g., if there are two drugs, `set_clinical_treatment()` must be called twice). +A treatment regimen for each drug can then be described using the `set_clinical_treatment()` function which takes the drug index, a vector of timesteps at which a change in coverage occurs (where the initial coverage is 0 until the first timestep specified) and a vector of coverages for the drug that correspond with the timestep changes, as well as the complete parameter set. + +In this example, the AL coverage would be at 0% from the start until day 9, 20% during days 10-14, 50% during days 15-19 and 100% from day 20 until the end of the simulation. ```{r} -Intro_parms <- set_clinical_treatment(parameters = Intro_parms, drug = 1, - timesteps = c(10,15,20), coverages = c(0.2,0.5,1)) +Intro_params <- set_clinical_treatment(parameters = Intro_parms, + drug = 1, + timesteps = c(10,15,20), + coverages = c(0.2,0.5,1)) ``` -\ +Multiple drugs can be modelled simultaneously, with treatment coverage that can be specified for each drug. This function must be used for each drug included (e.g., if there are two drugs, `set_clinical_treatment()` must be called twice). + # Example -## Parameterisation +## Parameterisation and simulation -Set up some initial parameters: +We will run several simulations that vary the coverages of drug programs for AL and DHA-PQ that begin on day one. For simplicity, the coverages will match for each drug. These simulations will last for two years for a population of one thousand individuals. In each simulation, the function `set_equilibrium` must also be used to generate equilibrium values for the human and mosquito populations. ```{r} # Daily simulation timesteps for two years @@ -67,58 +104,59 @@ sim_length <- 2 * year # With a population size of 1000 human_population <- 1000 -simparams <- get_parameters(list(human_population = human_population)) -``` -Update parameter set with chosen drug-specific parameters: +# Set human population size +simparams <- get_parameters(overrides = list(human_population = human_population)) -```{r} -# Incorporate drug parameters (AL and DHA/PQP) into complete parameter set +# Update parameter set with chosen drug-specific parameters (AL and DHA/PQP) simparams <- set_drugs(simparams, list(AL_params, DHA_PQP_params)) -``` - -\ - -## Simulation +# Choose initial EIR to 10 +starting_EIR <- 10 -This simulation will be run for 2 years for different drug coverage programs: - -```{r} -outputs <- list() # Create an empty list for results -starting_EIR <- 10 # Set initial EIR to 10 - -# We will vary coverage values between 0 and 0.5 +# And choose coverage values between 0 and 50% covs <- seq(0, 0.5, by = 0.1) +# Create an empty list for results +outputs <- list() + # Iterate over coverage values for (cov in covs) { - # Set treatment programs for each drug (1 and 2), starting on day 1: - simparams <- set_clinical_treatment(simparams, 1, 1, cov) # Set treatment program for AL - simparams <- set_clinical_treatment(simparams, 2, 1, cov) # Set treatment program for DHA/PQP + ## Set treatment programs for each drug (1 and 2), starting on day 1: + # Set treatment program for AL + simparams <- set_clinical_treatment( + parameters = simparams, + drug = 1, # First drug specified (AL) + timesteps = 1, # Treatment will begin on day 1 + coverages = cov) # Coverage as found in covs vector + + # Set treatment program for DHA-PQP + simparams <- set_clinical_treatment( + parameters = simparams, + drug = 2, # Second drug specified (DHA-PQP) + timesteps = 1, # Treatment will begin on day 1 + coverages = cov) # Coverage as found in covs vector # Use set_equilibrium to update the parameter set for a given initial EIR - simparams2 <- set_equilibrium(simparams, starting_EIR) + simparams <- set_equilibrium(simparams, starting_EIR) # Run simulation: output <- run_simulation(sim_length, simparams) + # remove the first year (which can be considered a warmup) output <- output[output$timestep > year,] + # Add output to outputs list outputs[[length(outputs) + 1]] <- output } ``` -\ - ## Visualisation -We will plot the effect of drug treatment coverage on *Pf*PR~2-10~ through time using the n_detect_730_3650 and n_730_3650 outputs. - -```{r} -Rich_cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") +Following simulation of malaria transmission under 0-50% drug treatment coverages, we can now visualise the effect of coverage on *Pf*PR~2-10~ through time using the `n_detect_730_3650` and `n_730_3650` outputs. +```{r, fig.align = 'center', fig.height = 5, fig.width = 7} # Join listed results into a single data frame df <- do.call('rbind', lapply(seq_along(outputs), function(i) { @@ -134,7 +172,8 @@ df <- do.call('rbind', lapply(seq_along(outputs), function(i) { # return results df })) - + +# Create plot function Treatment_plot_function <- function(df){ # Set figure margins and sections @@ -144,18 +183,21 @@ Treatment_plot_function <- function(df){ with(df[df$coverage==unique(df$coverage)[1],], expr = plot(x = timestep, y = PfPR2_10, type = "l", xlab = "Days", ylab = expression(paste(italic(Pf),"PR"[2-10])), - ylim = c(min(df$PfPR2_10),max(df$PfPR2_10)), col = Rich_cols[1])) + ylim = c(min(df$PfPR2_10),max(df$PfPR2_10)), col = cols[1])) + + # Add grid lines + grid() # Add remaining results invisible(sapply(2:length(unique(df$coverage)), function(x){ with(df[df$coverage==unique(df$coverage)[x],], - expr = points(x = timestep, y = PfPR2_10, type = "l",col = Rich_cols[x])) + expr = points(x = timestep, y = PfPR2_10, type = "l",col = cols[x])) })) # Add figure legend par(fig=c(0.9,1,0,1), cex = 0.8, new = T, xpd = T, mai = c(0,0,0,0)) legend("right", legend = paste0(100*unique(df$coverage),"%"), - col = Rich_cols, bty = "n", lty = 1, title = "Coverage") + col = cols, bty = "n", lty = 1, title = "Coverage") } Treatment_plot_function(df) From e7d907c47e33d2c836b3888f275b69da3333db9a Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Tue, 7 Mar 2023 09:56:29 +0000 Subject: [PATCH 057/164] Almost finished --- vignettes/Model.Rmd | 195 +++-- vignettes/Model_human.svg | 641 +++++++------- .../{Model_mos_figure.svg => Model_mos.svg} | 802 ++++++++++-------- 3 files changed, 876 insertions(+), 762 deletions(-) rename vignettes/{Model_mos_figure.svg => Model_mos.svg} (61%) diff --git a/vignettes/Model.Rmd b/vignettes/Model.Rmd index 2073f2d1..c3fee2c0 100644 --- a/vignettes/Model.Rmd +++ b/vignettes/Model.Rmd @@ -23,7 +23,7 @@ This is an individual based model for *P. falciparum* and malaria interventions. The human variables are documented in [R/variables.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/variables.R). -The human biological processes are spread out between the following files: +The functions governing the human flow of infection and immunity processes are described in the following files: 1. [R/human_infection.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/human_infection.R) 2. [R/disease_progression.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/disease_progression.R) @@ -37,33 +37,73 @@ Modelled human states are Susceptible (*S*), Treated (*Tr*), Clinical disease (* ### Parameters -Parameters shown on the infographic include: the force of infection ($\Lambda_i$), the probability of clinical disease ($\phi_i$), the probability of receiving treatment ($f_T$, or force of treatment), and rates of recovery from clinical disease to asymptomatic infection ($r_D$), asymptomatic infection to sub-patent infection ($r_A$), sub-patent infection and treated disease to complete recovery ($r_T$ and $r_U$). Superinfection may occur in individuals with asymptomatic or sub-patent infections at the same rates as standard infection (dashed arrows). +Parameters shown on the infographic include: -The force of infection ($\Lambda_i$) is impacted by pre-erythrocytic immunity, mosquito biting rate and population size and level of infectivity (specific details can be found in the references below). All default parameters can be found using [get_parameters()](https://mrc-ide.github.io/malariasimulation/reference/get_parameters.html) where the rate parameters shown here represent delays are input into the model by first converting to duration in days, e.g. for the input `dr`, $dr = \frac{1}{r_D}$. +- $\Lambda_i$: the age-specific (*i*) force of infection +- $\phi_i$: the age-specific (*i*) probability of clinical disease +- $f_T$: the probability of receiving treatment (or force of treatment) + +with the rates of recovery: + +- $r_D$: from clinical disease to asymptomatic infection +- $r_A$: from asymptomatic infection to sub-patent infection +- $r_U$: from sub-patent infection to complete recovery +- $r_T$: from treated clinical disease to complete recovery + +Superinfection may occur in individuals with asymptomatic or sub-patent infections at the same rates as standard infection (dashed arrows). + +The force of infection ($\Lambda_i$) is impacted by pre-erythrocytic immunity, mosquito biting rate and population size and level of infectivity (specific details can be found in the references below). All default parameters can be found in the documentation for the function `get_parameters()`. Please also note that while the infographic above displays rate parameters, the parameter list uses delays durations, e.g. the rate $r_D$ is the inverse of the delay from state *D* to *A* (`dr` in the model): + +$$r_D=dr^{-1}$$ To maintain a constant population size during simulations, the birth rate of new susceptible individuals is set to be equal to the overall death rate. ## Mosquito Biology -The mosquito biological processes are spread out between the following files: +The functions governing mosquito biological processes and dynamics are spread out between the following files: 1. [src/mosquito_ode.cpp]() ***Can't find a file with this name*** 2. [src/mosquito_emergence.cpp]() ***Can't find a file with this name***'' 3. [R/mosquito_biology.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/mosquito_biology.R) - + ### States -Modelled mosquito states are separated into early (*E*) and late (*L*) larval stages, the pupal stage (*P*) and three adult states for susceptible (*Sm*), incubating (*Pm*) and infectious individuals (*Im*). +Modelled mosquito states are separated into three juvenile stages: early (*E*) and late (*L*) larval stages, the pupal stage (*P*), and three adult states: susceptible (*S*M), incubating (*P*M) and infectious individuals (*I*M). Mosquitoes in any state may die, where they enter the NonExistent state. The model tracks both male and female juvenile mosquitoes, but only female adult mosquitoes. ### Parameters -Parameters shown on the infographic include: mosquito developmental rates from early to late larval stages ($r_{EL}$), to the pupal stage ($r_{L}$) and to adult stage ($r_P$). Susceptible adults (*Sm*) may become infected (***These rates are not clear to me and it would be good to add these to the model infographic and to this text***) with a latent period (*Pm*) before becoming infectious (*Im*). Larval and pupal stages die at a rate of $\mu_p$ while adults die at a density dependent rate of $\mu_m$, where they then enter the *NonExistent* state. ***I need to read up on this density dependence.*** +Parameters shown on the infographic include mosquito developmental rates: + +- $r_{EL}$: from early to late larval stage + +- $r_{L}$: from late larval stage to pupal stage + +- $r_P$: from pupal stage to adult stage + +Mosquito infection and incubation rates: + +- $\Lambda_M$: the force of mosquito infection (FOIM) + +- $r_{EM}$: extrinsic incubation period + +And mortality rates: + +- $\mu_E(t)$: the early larval stage death rate + +- $\mu_L(t)$: the late larval stage death rate -***Density dependence of mosquito deaths*** +- $\mu_P$: the pupal death rate -***Could show how these models are connected together in a bit more detail*** +- $\mu_M$: the adult mosquito death rate + +Larval mosquitoes experience density dependent mortality due to a carrying capacity, $K(t)$, which may change seasonally with rainfall and where $\gamma$ is the effect of density-dependence on late stage larvae compared with early stage larvae as follows: + +$$ +\mu_E = \mu_E^0(1+\frac{E(t)+L(t)}{K(t)}) \\ +\mu_L = \mu_L^0(1+\gamma\frac{E(t)+L(t)}{K(t)}) +$$ ## Model References @@ -81,16 +121,16 @@ Griffin, J. T., Bhatt, S., Sinka, M. E., Gething, P. W., Lynch, M., Patouillard, ### Simulation code -The key package function is `run_simulation()` which, in its most basic form, simply requires a number of timesteps in days. Default parameter settings assume a human population of size of 100, an initial mosquito population size of 1000 with all species in equal proportions, with no treatment interventions and no seasonality. The full parameters list can be seen using [get_parameters()](https://mrc-ide.github.io/malariasimulation/reference/get_parameters.html). +The key package function is `run_simulation()` which, in its most basic form, simply requires a number of timesteps in days. Default parameter settings assume a human population of size of 100, an initial mosquito population size of 1000 with all species in equal proportions, with no treatment interventions and no seasonality. The full parameters list can be seen in the documentation for `get_parameters()`. ```{r, output.lines=6} library(malariasimulation) -Test_Sim <- run_simulation(timesteps = 100) +test_sim <- run_simulation(timesteps = 100) ``` ### Output -The model then simulates a malaria epidemic and returns key outputs such as: +The `run_simulation()` function then simulates malaria transmission dynamics and returns a dataframe for the following parameters through time: - `infectivity`: human infectiousness - `EIR_All`: the entomological inoculation rate @@ -113,12 +153,16 @@ The model then simulates a malaria epidemic and returns key outputs such as: - `mosquito_deaths`: mosquito deaths ```{r, output.lines=6} -head(Test_Sim, n = 3) +head(test_sim, n = 3) ``` +Additional output details can be found in the `run_simulation()` documentation. + +In your bit in bold about mu_All - I wonder if it relates to all mosquito species across all adult female mosquito infectious states? I guess the same applies to the L/L/P/Sm/Pm/Im_All_count values too? + ### Additional outputs -**Age stratified** results for **incidence**, **clinical incidence** and **severe case incidence** may also be included in the output if desired and must be specified in the parameter list (see [get_parameters()](https://mrc-ide.github.io/malariasimulation/reference/get_parameters.html) for more details and [Demography](https://mrc-ide.github.io/malariasimulation/articles/Demography.html) for an example). These inputs will add extra columns to the output for the number of infections (**`n_`**) and the sum of probabilities of infection (**`p_`**) for the relevant total, clinical or severe incidences for each specified age group. +**Age stratified** results for **incidence**, **clinical incidence** and **severe case incidence** may also be included in the output if desired and must be specified in the parameter list (see `get_parameters()` for more details and [Demography](https://mrc-ide.github.io/malariasimulation/articles/Demography.html) for an example). These inputs will add extra columns to the output for the number of infections (**`n_`**) and the sum of probabilities of infection (**`p_`**) for the relevant total, clinical or severe incidences for each specified age group. Where **treatments** are specified, `n_treated` will report the number that have received treatment. Where **bed nets** are distributed, `net_usage` specifies the number sleeping under a bednet. @@ -128,28 +172,59 @@ Where **treatments** are specified, `n_treated` will report the number that have These outputs can then be visualised, such as the population changes in states. Another key output is the prevalence of detectable infections between the ages of 2-10 (*Pf*PR~2-10~), which can be obtained by dividing `n_detect_730_3650` by `n_730_3650`. -```{r, out.width = "45%", echo = FALSE} -cols_to_plot <- paste0(c("S","A","D","U","Tr"),"_count") -Rich_cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") +```{r, fig.align = 'center', fig.height = 5, fig.width = 7} +# Set color palette +cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") + +# Define vector of column names to plot +cols_to_plot <- paste0(c("S","D","A","U","Tr"),"_count") + +# Create plotting function states_plot <- function(){ - plot(x = Test_Sim$timestep, y = Test_Sim[,cols_to_plot[1]], type = "l", col = Rich_cols[1], ylim = c(0,80), ylab = "Population size", xlab = "Days") - sapply(2:5, function(x){points(x = Test_Sim$timestep, y = Test_Sim[,cols_to_plot[x]], type = "l", col = Rich_cols[x])}) - legend("topleft", legend = c("S","A","D","U","Tr"), col = Rich_cols, lty = 1, bty = "n", ncol = 5) + + # Set up plot with first state + plot(x = test_sim$timestep, y = test_sim[,cols_to_plot[1]], + type = "l", col = cols[1], ylim = c(0,80), + ylab = "Population size", xlab = "Days") + + # Add remaining states + sapply(2:5, function(x){ + points(x = test_sim$timestep, y = test_sim[,cols_to_plot[x]], type = "l", col = cols[x])}) + + # Add legend + legend("topleft", legend = c("S","D","A","U","Tr"), col = cols, lty = 1, bty = "n", ncol = 5) } states_plot() -plot(x = Test_Sim$timestep, y = Test_Sim$n_detect_730_3650/Test_Sim$n_730_3650, type = "l", col = Rich_cols[7], ylim = c(0,1), ylab = expression(paste(italic(Pf),"PR"[2-10])), xlab = "Days") -``` -\ +# Calculate Pf PR 2-10 +test_sim$PfPR2_10 <- test_sim$n_detect_730_3650/test_sim$n_730_3650 + + +# Plot Pf PR 2-10 +plot(x = test_sim$timestep, y = test_sim$PfPR2_10, type = "l", + col = cols[7], ylim = c(0,1), + ylab = expression(paste(italic(Pf),"PR"[2-10])), xlab = "Days") +``` # Changing parameters +The `get_parameters()` function generates a complete parameter set that may be fed into `run_simulation()`. A number of **helper functions** have been designed to assist in changing and setting key parameters, which are explained across the remaining vignettes. + +Some parameters (e.g. population size, age group rendering, setting seasonality) must still be replaced directly. When this is the case, care must be taken to ensure the replacement parameters are in the same class as the default parameters (e.g. if the parameter is a numeric, its replacement must also be numeric, if logical, the replacement must also be logical). Parameters are replaced by passing a list of named parameters to the `get_parameters()` function using the `overrides` argument. An example showing how to change the `human_population` parameter is given below. + +```{r} +# Use get_parameters(overrides = list(...))) to set new parameters +new_params <- get_parameters(overrides = list(human_population = 200)) +``` + +While other parameters can be changed individually, we do not generally recommended adjusting these without close attention and a detailed understanding of how this will impact the model assumptions. We strongly encourage users to stick with the parameter setting functions and methods described in these vignettes when adjusting parameter settings. + ## Mosquito modelling ### Species distribution -`malariasimulation` contains in built parameter sets for three mosquito species: *A. arabiensis* (`arab_params`), *A. funestus* (`fun_params`) and *A. gambiae* (`gamb_params`). Each parameter set contains feeding rates, foraging time etc. +`malariasimulation` contains in built parameter sets for three mosquito species: *A. arabiensis* (`arab_params`), *A. funestus* (`fun_params`) and *A. gambiae* (`gamb_params`). Each parameter set contains feeding rates, foraging time etc. Full details can be found in the [vector_parameters.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/vector_parameters.R) file. ```{r} unlist(arab_params) @@ -157,12 +232,14 @@ unlist(arab_params) The proportion of each species can be set using the `set_species()` function, requiring a full parameter set and arguments of a list of species parameter sets and a vector of relative species proportions. -```{r} +```{r, fig.align = 'center', fig.height = 5, fig.width = 7} # Create list of default parameters params <- get_parameters() # Update parameter list with species distributions -params_species <- set_species(parameters = params, species = list(arab_params, fun_params, gamb_params), proportions = c(0.1,0.3,0.6)) +params_species <- set_species(parameters = params, + species = list(arab_params, fun_params, gamb_params), + proportions = c(0.1,0.3,0.6)) # Run simulation species_simulation <- run_simulation(timesteps = 100, parameters = params_species) @@ -177,13 +254,18 @@ Mos_sp_dist_sim <- cbind(species_simulation$timestep, rowSums(species_simulation[,arab_cols]), rowSums(species_simulation[,fun_cols]), rowSums(species_simulation[,gamb_cols])) - -cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") species_plot <- function(Mos_pops){ - plot(x = Mos_pops[,1], y = Mos_pops[,2], type = "l", col = cols[2], ylim = c(0,140000), ylab = "Mosquito population size", xlab = "Days") - sapply(3:4, function(x){points(x = Mos_pops[,1], y = Mos_pops[,x], type = "l", col = cols[x])}) - legend("topright", legend = c("A. arab","A. fun","A. gamb"), col = cols[-1], lty = 1, bty = "n", ncol = 1) + plot(x = Mos_pops[,1], y = Mos_pops[,2], type = "l", col = cols[2], + ylim = c(0,140000), ylab = "Mosquito population size", xlab = "Days") + + grid() + + sapply(3:4, function(x){ + points(x = Mos_pops[,1], y = Mos_pops[,x], type = "l", col = cols[x])}) + + legend("topright", legend = c("A. arab","A. fun","A. gamb"), + col = cols[-1], lty = 1, bty = "n", ncol = 1) } species_plot(Mos_sp_dist_sim) @@ -191,9 +273,11 @@ species_plot(Mos_sp_dist_sim) ### Seasonality -We can also include the impact of seasonality on mosquito prevalence. To do this, we must set the parameter `model_seasonality = TRUE` and assign values to parameters that determine seasonality: `g0`, `g` and `h`. These parameters must be set directly using the `overrides` argument of `get_parameters()`. `overrides` takes a list of named parameters that can be overwritten. +The `malariasimulation` package has the capacity to simulate malaria transmission for a range of seasonal transmission profiles. This is achieved by specifying an annual rainfall profile that shapes mosquito population dynamics, thereby impacting malaria transmission. -```{r} +To include seasonality, we must set the parameter `model_seasonality = TRUE` and assign values to parameters that determine seasonality: `g0`, `g` and `h`. These parameters must be set directly by passing a list of named parameters to the `overrides` argument of the `get_parameters()` function. + +```{r, fig.align = 'center', fig.height = 5, fig.width = 7} # Set parameters, inclusing seasonality parameters params_seasons <- get_parameters(overrides = list( model_seasonality = TRUE, @@ -208,14 +292,18 @@ seasonality_simulation <- run_simulation(timesteps = 600, parameters = params_se All_mos_cols <- paste0(c("E","L","P","Sm","Pm", "Im", "NonExistent"),"_All_count") # Plot results -plot(seasonality_simulation[,1], rowSums(seasonality_simulation[,All_mos_cols]), ylim = c(0, 200000), type = "l", xlab = "Days", ylab = "Mosquito population size") - +plot(seasonality_simulation[,1], rowSums(seasonality_simulation[,All_mos_cols]), + ylim = c(0, 200000), type = "l", xlab = "Days", ylab = "Mosquito population size") +grid() ### Run simulation using seasonality over previous species distribution # Update seasonality parameter set to include species distributions -params_seasons_species <- set_species(parameters = params_seasons, species = list(arab_params, fun_params, gamb_params), proportions = c(0.1,0.3,0.6)) +params_seasons_species <- set_species(parameters = params_seasons, + species = list(arab_params, fun_params, gamb_params), + proportions = c(0.1,0.3,0.6)) # Run simulation -seasonality_species_simulation <- run_simulation(timesteps = 600, parameters = params_seasons_species) +seasonality_species_simulation <- run_simulation(timesteps = 600, + parameters = params_seasons_species) # Collect results Mos_season_species_sim <- cbind(seasonality_species_simulation$timestep, @@ -226,12 +314,19 @@ Mos_season_species_sim <- cbind(seasonality_species_simulation$timestep, # Plot results species_plot(Mos_season_species_sim) - ``` -### Individual or deterministic life +The mosquito population size is no longer constant and follows the patterns set by rainfall. + +### Individual or deterministic mosquitoes + +Mosquitoes may also be modelled deterministically, rather than individually (which is the default). + +This can be done by setting `individual_mosquitoes` to `FALSE` in the `overrides` argument of `get_parameters()`. -## +```{r, fig.align = 'center', fig.height = 5, fig.width = 7} +simparams <- get_parameters(overrides = list(individual_mosquitoes = FALSE)) +``` ## Vignettes @@ -251,8 +346,11 @@ The remaining vignettes describe how to adjust sets of parameters through a numb 3. [MDA and Chemoprevention](https://mrc-ide.github.io/malariasimulation/articles/MDA.html) - `set_mda()`: implementation of mass drug administration interventions + - `set_smc()`: implementation of seasonal malarial chemoprevention interventions + - `set_pmc()`: implementation of perrenial malarial chemoprevention interventions + - `peak_season_offset()`: correlating timed interventions with seasonal malaria 4. [Vaccines](https://mrc-ide.github.io/malariasimulation/articles/Vaccines.html) @@ -277,23 +375,8 @@ The remaining vignettes describe how to adjust sets of parameters through a numb 8. [Metapopulation Modelling](https://mrc-ide.github.io/malariasimulation/articles/Metapopulation.html) - - `run_metapop_simulation()`: to model multiple areas simulateously + - `run_metapop_simulation()`: to model multiple areas simultaneously 9. [Variation](https://mrc-ide.github.io/malariasimulation/articles/Variation.html) - `run_simulation_with_repetitions()`: running simulations with replicates - -## Changing other parameters - -It is not recommended that parameters are adjusted without using these functions without close and detailed attention, but if this is necessary, any parameter may be changed using the `overrides` argument in the `get_parameters()` function. The `get_parameters()` function generates a complete parameter set that may be fed into `run_simulation()`. New parameters must be in the same class as the parameters they replace (e.g. if the parameter is a numeric, its replacement must also be numeric, if logical, the replacement must also be logical) and inputs must be given as a list. An example is given below. - -This simple example shows how to change the human population size. The parameter name for human population size is `human_population`. - -```{r} -# Use get_parameters(overrides = list(...))) to set new parameters -new_params <- get_parameters(overrides = list(human_population = 200)) -``` - -### - -***Which parameters don't get addressed in the vignettes? What do these parameters do?*** Correlation_Parameters find_birthrates() get_correlation_parameters() parameterise_mosquito_equilibrium() parameterise_total_M() diff --git a/vignettes/Model_human.svg b/vignettes/Model_human.svg index be311bdb..470ba600 100644 --- a/vignettes/Model_human.svg +++ b/vignettes/Model_human.svg @@ -28,9 +28,9 @@ inkscape:pagecheckerboard="0" inkscape:document-units="pt" showgrid="false" - inkscape:zoom="1.288623" - inkscape:cx="-107.86708" - inkscape:cy="75.662159" + inkscape:zoom="3.1183718" + inkscape:cx="105.50378" + inkscape:cy="84.819905" inkscape:window-width="1846" inkscape:window-height="1016" inkscape:window-x="74" @@ -39,27 +39,202 @@ inkscape:current-layer="svg173" height="145pt" /> + %0 + + + + y2 + Infection + "human_infection.R" + + + + y4 + Superinfection + "human_infection.R" + + + + g2 + Disease progression + "disease_progression.R" + + + + y1 + + + + y1->y2 + + + + + + y3 + + + + y1->y3 + + + + y3->y4 + + + + + + g1 + + + + y3->g1 + + + + g1->g2 + + + + + + transform="matrix(0.60049093,0,0,0.60049093,2.6767739,85.347506)"> %0 + id="title951">%0 + points="170.3986,4 -4,4 -4,-142 170.3986,-142 " + id="polygon953" /> S + id="title955">S + id="path957" /> S + id="text959">S i + id="title962">i S->i + id="title967">S->i + id="path969" /> + id="polygon971" /> Λ - + id="text973">Λ i + id="text975">i D + id="title978">D + d="m 159.0653,-138 c 0,0 -7.3334,0 -7.3334,0 -3.6666,0 -7.3333,3.6667 -7.3333,7.3333 0,0 0,7.3334 0,7.3334 0,3.6666 3.6667,7.3333 7.3333,7.3333 0,0 7.3334,0 7.3334,0 3.6666,0 7.3333,-3.6667 7.3333,-7.3333 0,0 0,-7.3334 0,-7.3334 0,-3.6666 -3.6667,-7.3333 -7.3333,-7.3333" + id="path980" /> D + id="text982">D A + id="title985">A + d="m 159.0653,-80 c 0,0 -7.3334,0 -7.3334,0 -3.6666,0 -7.3333,3.6667 -7.3333,7.3333 0,0 0,7.3334 0,7.3334 0,3.6666 3.6667,7.3333 7.3333,7.3333 0,0 7.3334,0 7.3334,0 3.6666,0 7.3333,-3.6667 7.3333,-7.3333 0,0 0,-7.3334 0,-7.3334 0,-3.6666 -3.6667,-7.3333 -7.3333,-7.3333" + id="path987" /> A + id="text989">A D->A + id="title992">D->A + d="m 155.3986,-115.8513 c 0,8.9771 0,21.6895 0,31.6077" + id="path994" /> + points="155.3986,-80.183 153.9987,-84.183 156.7987,-84.1829 " + id="polygon996" /> r + id="text998">r D + id="text1000">D U + id="title1003">U + d="m 159.0653,-22 c 0,0 -7.3334,0 -7.3334,0 -3.6666,0 -7.3333,3.6667 -7.3333,7.3333 0,0 0,7.3334 0,7.3334 0,3.6666 3.6667,7.3333 7.3333,7.3333 0,0 7.3334,0 7.3334,0 3.6666,0 7.3333,-3.6667 7.3333,-7.3333 0,0 0,-7.3334 0,-7.3334 0,-3.6666 -3.6667,-7.3333 -7.3333,-7.3333" + id="path1005" /> U + id="text1007">U A->U + id="title1010">A->U + d="m 155.3986,-57.8513 c 0,8.9771 0,21.6895 0,31.6077" + id="path1012" /> + points="155.3986,-22.183 153.9987,-26.183 156.7987,-26.1829 " + id="polygon1014" /> r + id="text1016">r A + id="text1018">A A:sw->i:se + id="title1021">A:sw->i:se + d="m 144.3986,-58 c -19.149,19.149 -41.5922,20.1962 -61.1015,3.1416" + id="path1023" /> + id="polygon1025" /> Λ + id="text1027">Λ - i + id="text1029">i U:w->S:s + id="title1032">U:w->S:s + d="M 144.3986,-11 C 83.953,-11 14.3464,9.8819 11.1168,-46.7846" + id="path1034" /> + points="11,-51 12.5103,-47.0403 9.7114,-46.9627 " + id="polygon1036" /> r + id="text1038">r U + id="text1040">U U->i:s + id="title1043">U->i:s + d="M 144.3505,-12.1365 C 123.5414,-14.9198 80.254,-24.0175 76.2416,-51.7687" + id="path1045" /> - Λ + points="75.9419,-56 77.6211,-52.1089 74.8281,-51.9111 " + id="polygon1047" /> + id="text1049">Λ i + id="text1051">i Tr + id="title1054">Tr + id="path1056" /> Tr + id="text1058">Tr Tr:w->S:n + id="title1061">Tr:w->S:n + id="path1063" /> + id="polygon1065" /> r + id="text1067">r T + id="text1069">T i->D + id="title1072">i->D + d="m 80.2138,-65.4947 c 11.2418,-9.1963 42.0522,-34.401 60.557,-49.5389" + id="path1074" /> + points="144.2982,-117.9193 142.0886,-114.3029 140.3157,-116.4701 " + id="polygon1076" /> ϕ + id="text1078">ϕ i + id="text1080">i (1-f + id="text1082">(1-f T + id="text1084">T ) + id="text1086">) i->A + id="title1089">i->A + d="m 81.6882,-63.22 c 5.8286,-1.1832 15.1245,-2.9218 23.2537,-3.78 11.7479,-1.2402 25.108,-1.7289 35.1282,-1.9136" + id="path1091" /> + points="144.1456,-68.9755 140.1673,-67.5149 140.1248,-70.3145 " + id="polygon1093" /> 1-ϕ + id="text1095">1-ϕ i + id="text1097">i i->Tr + id="title1100">i->Tr + id="path1102" /> + id="polygon1104" /> ϕ + id="text1106">ϕ i + id="text1108">i f + id="text1110">f T - - - - %0 - - - - y2 - Infection - "human_infection.R" - - - - y4 - Superinfection - "human_infection.R" - - - - g2 - Disease progression - "disease_progression.R" - - - - y1 - - - - y1->y2 - - - - - - y3 - - - - y1->y3 - - - - y3->y4 - - - - - - g1 - - - - y3->g1 - - - - g1->g2 - - + id="text1112">T diff --git a/vignettes/Model_mos_figure.svg b/vignettes/Model_mos.svg similarity index 61% rename from vignettes/Model_mos_figure.svg rename to vignettes/Model_mos.svg index 3e174868..35bf4d6e 100644 --- a/vignettes/Model_mos_figure.svg +++ b/vignettes/Model_mos.svg @@ -10,7 +10,7 @@ viewBox="0 0 254.9846 174" version="1.1" id="svg184" - sodipodi:docname="Model_mos_figure.svg" + sodipodi:docname="Model_mos_figure_complete.svg" inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" @@ -65,15 +65,15 @@ showgrid="false" showguides="false" width="166pt" - inkscape:zoom="1.5450901" - inkscape:cx="163.09729" - inkscape:cy="146.5934" + inkscape:zoom="2.1694281" + inkscape:cx="176.08327" + inkscape:cy="126.07009" inkscape:window-width="1846" inkscape:window-height="1016" inkscape:window-x="74" inkscape:window-y="27" inkscape:window-maximized="1" - inkscape:current-layer="node1-9" /> + inkscape:current-layer="svg184" /> + transform="matrix(0.64684629,0,0,0.64684629,162.58238,105.71913)"> %0 - + id="title6146">%0 + + NonExistent - + id="title6150">g2 NonExistent + id="text6152">Development + + + + y2 Adultmosquitoes + id="text6157">Infection + + + + r2 + Mortality + + + + y1 + + + + y1->y2 + + + + + + r1 + + + + y1->r1 + + + + r1->r2 + + + + + + g1 + + + + g1->g2 + + + + + + g1->y1 + + + + %0 + + + NonExistent + Juvenilemosquitoes + id="text2670">NonExistent P + id="title2673">P + d="m 139.3743,-130 c 0,0 -7.3333,0 -7.3333,0 -3.6667,0 -7.3333,3.6667 -7.3333,7.3333 0,0 0,7.3334 0,7.3334 0,3.6666 3.6666,7.3333 7.3333,7.3333 0,0 7.3333,0 7.3333,0 3.6667,0 7.3334,-3.6667 7.3334,-7.3333 0,0 0,-7.3334 0,-7.3334 0,-3.6666 -3.6667,-7.3333 -7.3334,-7.3333" + id="path2675" /> P + id="text2677">P NonExistent->P + id="title2680">NonExistent->P + d="m 95.4747,-95.7715 c 9.828,-5.6742 20.9707,-12.1074 29.0336,-16.7625" + id="path2682" /> + points="95.8643,-94.784 92.7412,-94.1933 94.8142,-96.6027 " + id="polygon2684" /> µ + id="text2686">µ p + id="text2688">P L + id="title2691">L + d="m 77.0205,-166 c 0,0 -7.3333,0 -7.3333,0 -3.6667,0 -7.3334,3.6667 -7.3334,7.3333 0,0 0,7.3334 0,7.3334 0,3.6666 3.6667,7.3333 7.3334,7.3333 0,0 7.3333,0 7.3333,0 3.6667,0 7.3333,-3.6667 7.3333,-7.3333 0,0 0,-7.3334 0,-7.3334 0,-3.6666 -3.6666,-7.3333 -7.3333,-7.3333" + id="path2693" /> L + id="text2695">L NonExistent->L + id="title2698">NonExistent->L + d="m 73.3538,-97.5567 c 0,-13.5829 0,-33.5737 0,-46.0347" + id="path2700" /> + points="74.4039,-97.25 73.3538,-94.25 72.3039,-97.25 " + id="polygon2702" /> µ + id="text2704">µ p + id="text2706">L + (t) + E + id="title2713">E + d="m 14.6667,-130 c 0,0 -7.3334,0 -7.3334,0 -3.6666,0 -7.3333,3.6667 -7.3333,7.3333 0,0 0,7.3334 0,7.3334 0,3.6666 3.6667,7.3333 7.3333,7.3333 0,0 7.3334,0 7.3334,0 3.6666,0 7.3333,-3.6667 7.3333,-7.3333 0,0 0,-7.3334 0,-7.3334 C 22,-126.3333 18.3333,-130 14.6667,-130" + id="path2715" /> E + id="text2717">E NonExistent->E + id="title2720">NonExistent->E + d="m 51.233,-95.7715 c -9.828,-5.6742 -20.9708,-12.1074 -29.0336,-16.7625" + id="path2722" /> + points="51.8934,-96.6027 53.9665,-94.1933 50.8434,-94.784 " + id="polygon2724" />    + µ + id="text2728">µ p + id="text2730">E + (t) Im + id="title2735">Im + d="m 14.6667,-58 c 0,0 -7.3334,0 -7.3334,0 C 3.6667,-58 0,-54.3333 0,-50.6667 c 0,0 0,7.3334 0,7.3334 0,3.6666 3.6667,7.3333 7.3333,7.3333 0,0 7.3334,0 7.3334,0 3.6666,0 7.3333,-3.6667 7.3333,-7.3333 0,0 0,-7.3334 0,-7.3334 C 22,-54.3333 18.3333,-58 14.6667,-58" + id="path2737" /> Im + id="text2739">I + M NonExistent->Im + id="title2744">NonExistent->Im + d="m 51.233,-70.2285 c -9.828,5.6742 -20.9708,12.1074 -29.0336,16.7625" + id="path2746" /> + points="50.8434,-71.216 53.9665,-71.8067 51.8934,-69.3973 " + id="polygon2748" /> µ + id="text2750">µ m + id="text2752">M + Pm + id="title2757">Pm + d="m 77.0205,-22 c 0,0 -7.3333,0 -7.3333,0 -3.6667,0 -7.3334,3.6667 -7.3334,7.3333 0,0 0,7.3334 0,7.3334 0,3.6666 3.6667,7.3333 7.3334,7.3333 0,0 7.3333,0 7.3333,0 3.6667,0 7.3333,-3.6667 7.3333,-7.3333 0,0 0,-7.3334 0,-7.3334 0,-3.6666 -3.6666,-7.3333 -7.3333,-7.3333" + id="path2759" /> Pm + id="text2761">P + M NonExistent->Pm + id="title2766">NonExistent->Pm + d="m 73.3538,-68.4433 c 0,13.5829 0,33.5737 0,46.0347" + id="path2768" /> + points="72.3039,-68.75 73.3538,-71.75 74.4039,-68.75 " + id="polygon2770" /> µ + id="text2772">µ m + id="text2774">M + Sm + id="title2779">Sm + d="m 139.3743,-58 c 0,0 -7.3333,0 -7.3333,0 -3.6667,0 -7.3333,3.6667 -7.3333,7.3333 0,0 0,7.3334 0,7.3334 0,3.6666 3.6666,7.3333 7.3333,7.3333 0,0 7.3333,0 7.3333,0 3.6667,0 7.3334,-3.6667 7.3334,-7.3333 0,0 0,-7.3334 0,-7.3334 0,-3.6666 -3.6667,-7.3333 -7.3334,-7.3333" + id="path2781" /> Sm + id="text2783">S + M NonExistent->Sm + id="title2788">NonExistent->Sm + d="m 95.4747,-70.2285 c 9.828,5.6742 20.9707,12.1074 29.0336,16.7625" + id="path2790" /> + points="94.8142,-69.3973 92.7412,-71.8067 95.8643,-71.216 " + id="polygon2792" /> µ + id="text2794">µ m + id="text2796">M P->Sm + id="title2799">P->Sm + d="m 135.7077,-107.75 c 0,12.1866 0,31.7071 0,45.3208" + id="path2801" /> + points="137.1078,-62.4086 135.7077,-58.4086 134.3078,-62.4086 " + id="polygon2803" /> r + id="text2805">r P + id="text2807">P L->P + id="title2810">L->P + d="m 84.5014,-148.5639 c 10.197,5.8872 25.351,14.6364 36.5295,21.0903" + id="path2812" /> + points="121.8925,-128.5928 124.6566,-125.3804 120.4924,-126.168 " + id="polygon2814" /> r + id="text2816">r L + id="text2818">L E->L + id="title2821">E->L + d="m 22.1476,-125.4361 c 10.1969,-5.8872 25.351,-14.6364 36.5295,-21.0903" + id="path2823" /> + points="58.1386,-147.832 62.3027,-148.6196 59.5386,-145.4072 " + id="polygon2825" /> r + id="text2827">r EL + id="text2829">EL Im->E + id="title2832">Im->E Pm->Im + id="title2835">Pm->Im + d="M 62.2062,-17.4361 C 52.0093,-23.3233 36.8552,-32.0725 25.6768,-38.5264" + id="path2837" /> + points="24.8152,-37.4072 22.0511,-40.6196 26.2152,-39.832 " + id="polygon2839" /> ???? - + id="text2841">r ???? + id="text2843">EM Sm->Pm + id="title2846">Sm->Pm + d="m 124.56,-40.5639 c -10.1969,5.8872 -25.3509,14.6364 -36.5294,21.0903" + id="path2848" /> + points="88.5691,-18.168 84.4049,-17.3804 87.169,-20.5928 " + id="polygon2850" /> ???? + id="text2852">Λ - ???? - - - - %0 - - - - g2 - Development - - - - y2 - Infection - - - - r2 - Mortality - - - - y1 - - - - y1->y2 - - - - - - r1 - - - - y1->r1 - - - - r1->r2 - - - - - - g1 - - - - g1->g2 - - - - - - g1->y1 + id="text2854">M + Juvenilemosquitoes + + Adultmosquitoes From 53fb6be00aa6d528c083a179167e50d65abbc1d3 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Wed, 8 Mar 2023 15:38:53 +0000 Subject: [PATCH 058/164] First easy edits to address comments --- vignettes/VectorControl_Bednets.Rmd | 138 ++++++++++++++++++++++++++++ vignettes/VectorControl_IRS.Rmd | 21 ++--- 2 files changed, 147 insertions(+), 12 deletions(-) create mode 100644 vignettes/VectorControl_Bednets.Rmd diff --git a/vignettes/VectorControl_Bednets.Rmd b/vignettes/VectorControl_Bednets.Rmd new file mode 100644 index 00000000..7c44da1b --- /dev/null +++ b/vignettes/VectorControl_Bednets.Rmd @@ -0,0 +1,138 @@ +--- +title: "Vector Control: Bednets" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Vector Control: Bednets} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +```{r setup} +library(malariasimulation) +library(malariaEquilibrium) +``` + +Long-lasting insecticidal bednets are highly effective and relatively cheap interventions to prevent malaria. The effects of insecticidal bed net distribution campsigns can be simulated using malariasimulation. The model provides the user with the flexibility to specify parameters that describe the net distribution campaign (e.g. timing, coverage, and target population), the bed nets distributed (e.g. efficacy, longevity), and the relative densities of the mosquito species present in the target population. We will illustrate this through an example with two bednet distributions, once per year. + +### Plotting functions +We can create a few plotting functions to visualise the output. +```{r} +cols <- c("#E69F00", "#56B4E9", "#009E73", + "#F0E442", "#0072B2", "#D55E00", "#CC79A7") + +# Plotting functions +plot_prev <- function() { + plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, + type = 'l', col = cols[3], lwd = 2.5, + xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), + xaxs = "i", yaxs = "i", bty = "l", ylim = c(0.15, 0.93)) + lines(x = output_control$timestep, y = output_control$n_detect_730_3650/output_control$n_730_3650, + col = cols[5], lwd = 2.5) + abline(v = bednetstimesteps, col = 'black', lty = 2, lwd = 2.5) + grid(lty = 2, col = 'grey80', lwd = 1) + legend('bottomleft', box.lty = 0, legend = c('Bednets','Prevalence for bednet scenario','Prevalence for control scenario'), + col = c('black', cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) +} +``` + +### Parameterisation + +Use the `get_parameters()` function to generate the list of parameters for a seasonal profile, accepting the default values to run the simulation from an equilibrium starting point. The seasonality will drive mosquito dynamics in the absence of interventions. + +```{r} +year <- 365 +sim_length <- 3 * year +human_population <- 1000 +starting_EIR <- 50 + +simparams <- get_parameters( + list( + human_population = human_population, + # seasonality parameters + model_seasonality = TRUE, # Let's try a bi-modal model + g0 = 0.28605, + g = c(0.20636, -0.0740318, -0.0009293), + h = c(0.173743, -0.0730962, -0.116019), + # Here, we are asking for the output to contain information on severe incidence in children 2-10 years old. + clinical_incidence_rendering_min_ages = 2*year, + clinical_incidence_rendering_max_ages = 10*year + ) +) + +# Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae +simparams <- set_species( + simparams, + species = list(arab_params, fun_params, gamb_params), + proportions = c(0.25, 0.25, 0.5) +) + +simparams <- set_equilibrium(simparams, starting_EIR) + +output_control <- run_simulation(sim_length, simparams) +``` + +## Simulation + +Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bednets once a year for two years, the first round to 80% of the population and the second round to 50% of the population. It is possible to change the characteristics of the bednets for each distribution timestep by modifying the values for `dn0`, `rn`, `rnm`, and `gamman`. Because there are 3 mosquito species specified in `set_species()` above and two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 3 columns and 2 rows. + +```{r, fig.align='center', fig.height=4, fig.width=6} +bednetstimesteps <- c(1, 2) * year # The bednets will be distributed at the end of the first and the second year. + +bednetparams <- set_bednets( + simparams, + timesteps = bednetstimesteps, + coverages = c(.8, .5), # The first round is distributed to 80% of the population and the second round to 50%. + retention = 5 * year, # Nets are kept on average 5 years + dn0 = matrix(c(.533, .45), nrow=2, ncol=3), # Matrix of death probabilities for each mosquito species over time + rn = matrix(c(.56, .5), nrow=2, ncol=3), # Matrix of repelling probabilities for each mosquito species over time + rnm = matrix(c(.24, .24), nrow=2, ncol=3), # Matrix of minimum repelling probabilities for each mosquito species over time + gamman = rep(2.64 * 365, 2) # Vector of bednet half-lives for each distribution timestep +) + +output <- run_simulation(sim_length, bednetparams) +``` + +### Plot prevalence +```{r, fig.align='center', fig.height=5, fig.width=7} +plot_prev() +``` + +## Visualisation + +It is important to understand the difference between the input `coverages` argument of `malariasimulation::set_bednets()` and the resulting population bednet usage over time in the model. In the above example, bednets are distributed to a specified percentage of the population at each distribution round; however, the level of bednet usage may be different. + +The average population bednet usage will be influenced by: + +* The size and frequency of distributions specified in `set_bednets()` +* The assumed net retention half life (`gamman`) +* Correlations in the recipients of nets between rounds + +The output from `malariasimulation::run_simulation()` has a variable `n_use_net` that shows the number of people using bednets at any given timestep. We can visualise the proportion of the population using bednets over time to understand how bednet usage changes. + +```{r, fig.align='center', fig.height=5, fig.width=7} +output$prop_use_net <- output$n_use_net / human_population + +plot(x = output$timestep, y = output$prop_use_net, type = 'l', + col = cols[3], lwd = 2.5, ylim = c(0,1), + xlab = 'Timestep (days)', ylab = 'Proportion of population using bednets', + xaxs = "i", yaxs = "i", bty = "l") +grid(lty = 2, col = 'grey80', lwd = 1) +axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") +``` + +## Using the `netz` package to estimate coverage inputs needed to achieve target population usage + +The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool to help set up bednets in `malariasimulation`. `malariasimulation` takes as input the proportion of the population who were distributed a bednet at specific time points, but available data for a specific region or country do not always have this information. `netz` allows for simple conversions between bednet metrics like crop, access, distribution, and usage. + +See the vignettes from the `netz` package that explain these concepts more comprehensively: + +* [This vignette](https://mrc-ide.github.io/netz/articles/overview.html) explains how to estimate the distribution coverage from a specified bednet usage. +* [This vignette](https://mrc-ide.github.io/netz/articles/population_usage.html) demonstrates how to estimate population bednet usage from an input distribution. + diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index c4e3d67a..a9902ba7 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -19,7 +19,7 @@ library(malariasimulation) library(malariaEquilibrium) ``` -Indoor Residual Spraying (IRS) involves periodically treating indoor walls with insecticides to eliminate adult female mosquitoes that rest indoors. `malariasimulation` can be used to investigate the effect of malaria control strategies that deploy IRS. The model has the functionality to allow users to specify a range of IRS campaigns, including different timings and coverages and in settings with specified proportions of mosquito species with the help of the `set_spraying()` function. +Indoor Residual Spraying (IRS) involves periodically treating indoor walls with insecticides to eliminate adult female mosquitoes that rest indoors. `malariasimulation` can be used to investigate the effect of malaria control strategies that deploy IRS. Users can set IRS in the model using the set_spraying() function to parameterize timing of spraying campaigns and coverage levels. ### Plotting functions We will create a few plotting functions to visualise the output. @@ -44,7 +44,7 @@ plot_prev <- function() { ### Parameterisation -Use the `get_parameters()` function to generate the list of parameters for a seasonal profile, accepting the default values to run the simulation from an equilibrium starting point. The seasonality will drive mosquito dynamics in the absence of interventions. +Use the `get_parameters()` function to generate a list of parameters, accepting most of the default values, but modifying seasonality values to model a seasonal setting. Then, we use the `set_equilibrium()` function to to initialise the model at a given entomological innoculation rate (EIR). ```{r} year <- 365 @@ -57,25 +57,22 @@ simparams <- get_parameters( list( human_population = human_population, # seasonality parameters - model_seasonality = TRUE, # Let's try a bi-modal model - g0 = 0.28605, - g = c(0.20636, -0.0740318, -0.0009293), - h = c(0.173743, -0.0730962, -0.116019), - # Here, we are asking for the output to contain information on severe incidence in children 2-10 years old. - clinical_incidence_rendering_min_ages = 2*year, - clinical_incidence_rendering_max_ages = 10*year + model_seasonality = TRUE, + g0 = 0.285277, + g = c(-0.0248801, -0.0529426, -0.0168910), + h = c(-0.0216681, -0.0242904, -0.0073646), ) ) simparams <- set_equilibrium(simparams, starting_EIR) # Running simulation with no IRS -output_control <- run_simulation(sim_length, simparams) +output_control <- run_simulation(timesteps = sim_length, parameters = simparams) ``` ## Simulation -Then we can run the simulation for a variety of IRS strategies. In the example below, there are two rounds of IRS at 80% coverage, each 3 months prior to peak rainfall for that year. The function `peak_season_offset()` outputs a timestep when peak rainfall will be observed. Notice that the matrices specified for the parameters for `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` have two rows, one for each timestep where IRS occurs, and 1 column for all mosquitoes, not divided by species. +Then we can run the simulations for a variety of IRS strategies. In the example below, there are two rounds of IRS at 80% coverage, each 3 months prior to peak rainfall for that year. The function `peak_season_offset()` outputs a timestep when peak rainfall will be observed based on the seasonality profile we set above. Notice that the matrices specified for the parameters for `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` have two rows, one for each timestep where IRS occurs, and 1 column for all mosquitoes, not divided by species. ```{r, fig.align='center', fig.height=4, fig.width=6} peak <- peak_season_offset(simparams) @@ -85,7 +82,7 @@ sprayingtimesteps <- c(1, 2) * year + peak - 3 * month # There is a round of IRS sprayingparams <- set_spraying( simparams, timesteps = sprayingtimesteps, - coverages = rep(.8, 2), # # Each round covers 80% of the population + coverages = rep(.8, 2), # Each round covers 80% of the population ls_theta = matrix(c(2.025, 2.025), nrow=2, ncol=1), # Matrix of mortality parameters ls_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1), # Matrix of mortality parameters per timestep ks_theta = matrix(c(-2.222, -2.222), nrow=2, ncol=1), # Matrix of feeding success parameters From bb25014ae787af60458323182da4289cf5c5358b Mon Sep 17 00:00:00 2001 From: lhaile Date: Thu, 9 Mar 2023 14:21:32 +0000 Subject: [PATCH 059/164] added section on parameter variation --- vignettes/Variation.Rmd | 51 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index e965ee31..ebf1a4ab 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -129,3 +129,54 @@ title('95% Confidence interval') legend('bottomleft', inset = 0, legend = c('Mean','95% CI'), col = c(cols[3],'grey90'), lwd = 5, xpd = TRUE, horiz = TRUE, cex = 1, seg.len=1, bty = 'n') ``` + + + +## Estimating variation in parameters + +Default parameters for the malariasimulation model were obtained from the joint posterior of MCMC fitting. + +```{r plot parasite prevalence with default model parameters} + +simparams <- get_parameters(list( + human_population = 100, + individual_mosquitoes = FALSE +)) + +# obtain 50 random draws from the model parameter posterior distribution + +# Default (mdedian) model parameters +sim <- run_simulation(timesteps= 1000, simparams) + +# plot the default median parameter +plot(sim$timestep, sim$n_detect_730_3650 / sim$n_730_3650, t = "l", ylim = c(0, 1), ylab = "PfPr", xlab = "Time in days") + +``` + +If needed, we can estimate the variation in model parameters using the draws from this joint posterior using `set_parameter_draw`. This function will override the default model parameters with a sample from one of 1000 draws from the joint posterior. + +Keep in mind that `set_parameter_draw` must be called prior to `set_equilibrium`, as the model must be calibrated to new model parameters. + +```{r run simulation on different samples of the joint posterior distribution} + +# Default (mdedian) model parameters +sim <- run_simulation(timesteps= 1000, simparams) + +# plot the default median parameter +plot(sim$timestep, sim$n_detect_730_3650 / sim$n_730_3650, t = "l", ylim = c(0, 1), ylab = "PfPr", xlab = "Time in days") + +cols<- rainbow(50) +for (i in 1:50){ + +message(paste0('obtaining parameter draw ', i)) +param_draw<- simparams |> + set_parameter_draw(sample(1:1000, 1)) |> + set_equilibrium(init_EIR= 5) + +sim<- run_simulation(timesteps= 1000, param_draw) + +lines(sim$timestep, sim$n_detect_730_3650 / sim$n_730_3650, col = cols[i]) + +} + +``` From cc820b53032ba6597f58cc9b8f35b763566f90fe Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 9 Mar 2023 15:55:47 +0000 Subject: [PATCH 060/164] New set species vignette, removing multi-species runs from nets/IRS, editing text --- vignettes/SetSpecies.Rmd | 175 ++++++++++++++++++++++++++++ vignettes/VectorControl_Bednets.Rmd | 75 ++++++------ vignettes/VectorControl_IRS.Rmd | 102 +++++----------- 3 files changed, 242 insertions(+), 110 deletions(-) create mode 100644 vignettes/SetSpecies.Rmd diff --git a/vignettes/SetSpecies.Rmd b/vignettes/SetSpecies.Rmd new file mode 100644 index 00000000..a4696773 --- /dev/null +++ b/vignettes/SetSpecies.Rmd @@ -0,0 +1,175 @@ +--- +title: "Setting mosquito species" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Vector Control: IRS} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +```{r setup} +library(malariasimulation) +library(malariaEquilibrium) +``` + +### Plotting functions +We will create a few plotting functions to visualise the output. +```{r} +cols <- c("#E69F00", "#56B4E9", "#009E73", + "#F0E442", "#0072B2", "#D55E00", "#CC79A7") + +# Plotting functions +plot_prev <- function() { + plot(x = output$timestep, y = output$n_detect_730_3650 / output$n_730_3650, + type = "l", col = cols[3], lwd = 2.5, + xlab = "Time (days)", ylab = expression(paste(italic(Pf),"PR"[2-10])), + xaxs = "i", yaxs = "i", bty = "l", ylim = c(0,1)) + lines(x = output_all$timestep, y = output_all$n_detect_730_3650 / output_all$n_730_3650, + col = cols[5], lwd = 2.5) + abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = "black") + grid(lty = 2, col = "grey80", lwd = 1) + legend("bottomleft", box.lty = 0, legend = c("Spraying", "Prevalence for all mosquitoes scenario","Prevalence for species-specific scenario"), + col = c("black", cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) +} +``` + +As alluded to in the IRS and Bednet vignettes, it is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. IRS and bednets could be expected to have different impacts depending on the proportion of each mosquito species because of variations in indoor resting, insecticide resistance, and proportion of bites on humans versus animals by species. If you have specified more than 1 species, then the arguments for `set_spraying()` and/or `set_bednets()` must be populated with values for each species at each timestep that the intervention is implemented. + +There are preset parameters for *An. gambiae*, *An. arabiensis*, and *An. funestus* that can be set by the helper functions `gamb_params()`, `arab_params()`, and `fun_params()`, respectively. The default values for each species in these helper functions are from 10.1073/pnas.1820646116. The parameters are: + +* `blood_meal_rates`: the blood meal rates for each species +* `foraging_time`: time spent taking blood meals +* `Q0`: proportion of blood meals taken on humans +* `phi_bednets`: proportion of bites taken in bed +* `phi_indoors`: proportion of bites taken indoors + +We will demonstrate how to specify different mosquito species and how this could alter intervention impact using an example with IRS. + +## IRS with default mosquito settings + +Use the `get_parameters()` function to generate a list of parameters, accepting most of the default values, but modifying seasonality values to model a seasonal setting. We will model IRS with the default mosquito settings, which is to model all mosquito species together. Then, we use the `set_equilibrium()` function to to initialise the model at a given entomological inoculation rate (EIR). + +```{r} +year <- 365 +month <- 30 +sim_length <- 3 * year +human_population <- 1000 +starting_EIR <- 50 + +simparams <- get_parameters( + list( + human_population = human_population, + # seasonality parameters + model_seasonality = TRUE, + g0 = 0.285277, + g = c(-0.0248801, -0.0529426, -0.0168910), + h = c(-0.0216681, -0.0242904, -0.0073646) + ) +) + +peak <- peak_season_offset(simparams) + +sprayingtimesteps <- c(1, 2) * year + peak - 3 * month # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. + +simparams <- set_spraying( + simparams, + timesteps = sprayingtimesteps, + coverages = rep(.8, 2), # # Each round covers 80% of the population + # nrows=length(timesteps), ncols=length(species) + ls_theta = matrix(2.025, nrow=length(sprayingtimesteps), ncol=1), # Matrix of mortality parameters per round of IRS and per species + ls_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=1), # Matrix of mortality parameters per round of IRS and per species + ks_theta = matrix(-2.222, nrow=length(sprayingtimesteps), ncol=1), # Matrix of feeding success parameters per round of IRS and per species + ks_gamma = matrix(0.008, nrow=length(sprayingtimesteps), ncol=1), # Matrix of feeding success parameters per round of IRS and per species + ms_theta = matrix(-1.232, nrow=length(sprayingtimesteps), ncol=1), # Matrix of deterrence parameters per round of IRS and per species + ms_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=1) # Matrix of deterrence parameters per round of IRS and per species +) + +simparams <- set_equilibrium(simparams, starting_EIR) + +# Running simulation with no IRS +output_all <- run_simulation(timesteps = sim_length, parameters = simparams) +``` + +The default setting is to model all mosquito species together. +```{r} +simparams$species +simparams$species_proportions +``` + +### Plot species over time +```{r,fig.align="center", fig.height=5, fig.width=7} +plot(x = output_all$timestep, y = output_all$Im_All_count, + type = "l", col = cols[5], lwd = 2.5, + xlab = "Time (days)", ylab = "N mosquitoes", + xaxs = "i", yaxs = "i", bty = "l") +abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = "black") +grid(lty = 2, col = "grey80", lwd = 1) +legend("topright", box.lty = 0, legend = c("Spraying", "All mosquitoes"), col = c("black", cols[5]), lty = c(2, 1), lwd = 2.5) +``` + + +## IRS with multiple mosquito species + +We will run the same model with IRS as above, but this time with 3 species of mosquitoes. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. Each column corresponds to a species of mosquito, and each row corresponds to the timestep when a round of IRS occurred. Here, we are assuming the same values for each species at each IRS round for simplicity, but the matrix could be edited to have different values by species or over time by adding new columns or rows. + +```{r, fig.align="center", fig.height=4, fig.width=6} +## Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae +simparams <- set_species( + simparams, + species = list(arab_params, fun_params, gamb_params), + proportions = c(0.25, 0.25, 0.5) +) + +peak <- peak_season_offset(simparams) + +sprayingtimesteps <- c(1, 2) * year + peak - 3 * month # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. + +simparams <- set_spraying( + simparams, + timesteps = sprayingtimesteps, + coverages = rep(.8, 2), # # Each round covers 80% of the population + ls_theta = matrix(2.025, nrow=length(sprayingtimesteps), ncol=3), # Matrix of mortality parameters; nrows=length(timesteps), ncols=length(species) + ls_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=3), # Matrix of mortality parameters per round of IRS and per species + ks_theta = matrix(-2.222, nrow=length(sprayingtimesteps), ncol=3), # Matrix of feeding success parameters per round of IRS and per species + ks_gamma = matrix(0.008, nrow=length(sprayingtimesteps), ncol=3), # Matrix of feeding success parameters per round of IRS and per species + ms_theta = matrix(-1.232, nrow=length(sprayingtimesteps), ncol=3), # Matrix of deterrence parameters per round of IRS and per species + ms_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=3) # Matrix of deterrence parameters per round of IRS and per species +) + +output <- run_simulation(timesteps = sim_length, parameters = simparams) +``` + +Here we can see that now there are 3 species of mosquitoes at the proportions we specified in `set_species()`. +```{r} +simparams$species +simparams$species_proportions +``` + + +### Plot prevalence +```{r,fig.align="center", fig.height=5, fig.width=7} +plot_prev() +``` + +### Plot adult female infectious mosquitoes by species over time +```{r,fig.align="center", fig.height=5, fig.width=7} +plot(x = output$timestep, y = output$Im_gamb_count, + type = "l", col = cols[5], lwd = 2.5, + xlab = "Time (days)", ylab = "N mosquitoes", + xaxs = "i", yaxs = "i", bty = "l") +abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = "black") +lines(x = output$timestep, y = output$Im_fun_count, + col = cols[6], lwd = 2.5) +lines(x = output$timestep, y = output$Im_arab_count, + col = cols[3], lwd = 2.5) +grid(lty = 2, col = "grey80", lwd = 1) +legend("topright", box.lty = 0, legend = c("Spraying", expression(italic("An. gambiae")), expression(italic("An. funestus")),expression(italic("An. arabiensis"))), col = c("black", cols[5], cols[6], cols[3]), lty = c(2, 1, 1, 1), lwd = 2.5) +``` + diff --git a/vignettes/VectorControl_Bednets.Rmd b/vignettes/VectorControl_Bednets.Rmd index 7c44da1b..e5fcee67 100644 --- a/vignettes/VectorControl_Bednets.Rmd +++ b/vignettes/VectorControl_Bednets.Rmd @@ -19,7 +19,7 @@ library(malariasimulation) library(malariaEquilibrium) ``` -Long-lasting insecticidal bednets are highly effective and relatively cheap interventions to prevent malaria. The effects of insecticidal bed net distribution campsigns can be simulated using malariasimulation. The model provides the user with the flexibility to specify parameters that describe the net distribution campaign (e.g. timing, coverage, and target population), the bed nets distributed (e.g. efficacy, longevity), and the relative densities of the mosquito species present in the target population. We will illustrate this through an example with two bednet distributions, once per year. +Long-lasting insecticide-treated bednets is a highly effective intervention to prevent malaria. The effects of insecticidal bednet distribution campaigns can be simulated using `malariasimulation`. The model provides the user with the flexibility to specify parameters that describe the net distribution campaign (e.g. timing, coverage, and target population) and the bednets distributed (e.g. efficacy, longevity). We will illustrate this through an example with two bednet distributions, once per year. ### Plotting functions We can create a few plotting functions to visualise the output. @@ -29,22 +29,22 @@ cols <- c("#E69F00", "#56B4E9", "#009E73", # Plotting functions plot_prev <- function() { - plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, - type = 'l', col = cols[3], lwd = 2.5, - xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), - xaxs = "i", yaxs = "i", bty = "l", ylim = c(0.15, 0.93)) - lines(x = output_control$timestep, y = output_control$n_detect_730_3650/output_control$n_730_3650, + plot(x = output$timestep, y = output$n_detect_730_3650 / output$n_730_3650, + type = "l", col = cols[3], lwd = 2.5, + xlab = "Time (days)", ylab = expression(paste(italic(Pf),"PR"[2-10])), + xaxs = "i", yaxs = "i", bty = "l", ylim = c(0, 1)) + lines(x = output_control$timestep, y = output_control$n_detect_730_3650 / output_control$n_730_3650, col = cols[5], lwd = 2.5) - abline(v = bednetstimesteps, col = 'black', lty = 2, lwd = 2.5) - grid(lty = 2, col = 'grey80', lwd = 1) - legend('bottomleft', box.lty = 0, legend = c('Bednets','Prevalence for bednet scenario','Prevalence for control scenario'), - col = c('black', cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) + abline(v = bednetstimesteps, col = "black", lty = 2, lwd = 2.5) + grid(lty = 2, col = "grey80", lwd = 1) + legend("bottomleft", box.lty = 0, legend = c("Bednets","Prevalence for bednet scenario","Prevalence for control scenario"), + col = c("black", cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) } ``` ### Parameterisation -Use the `get_parameters()` function to generate the list of parameters for a seasonal profile, accepting the default values to run the simulation from an equilibrium starting point. The seasonality will drive mosquito dynamics in the absence of interventions. +Use the `get_parameters()` function to generate the list of parameters for a perennial profile, accepting the default values to run the simulation from an equilibrium starting point. ```{r} year <- 365 @@ -53,17 +53,7 @@ human_population <- 1000 starting_EIR <- 50 simparams <- get_parameters( - list( - human_population = human_population, - # seasonality parameters - model_seasonality = TRUE, # Let's try a bi-modal model - g0 = 0.28605, - g = c(0.20636, -0.0740318, -0.0009293), - h = c(0.173743, -0.0730962, -0.116019), - # Here, we are asking for the output to contain information on severe incidence in children 2-10 years old. - clinical_incidence_rendering_min_ages = 2*year, - clinical_incidence_rendering_max_ages = 10*year - ) + list(human_population = human_population) ) # Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae @@ -73,16 +63,26 @@ simparams <- set_species( proportions = c(0.25, 0.25, 0.5) ) -simparams <- set_equilibrium(simparams, starting_EIR) +simparams <- set_equilibrium(parameters = simparams, init_EIR = starting_EIR) -output_control <- run_simulation(sim_length, simparams) +output_control <- run_simulation(timesteps = sim_length, parameters = simparams) ``` +#### A note on mosquito species +It is also possible to use the `set_species()` function to account for 3 different mosquito species in the simulation. In this case, the matrices would need to have additional column corresponding to each mosquito species. For example, if we specified that there were 3 species of mosquitoes in the model and nets were distributed at two timesteps, then the matrices would have 2 rows and 3 columns. If you are not already familiar with the `set_species()` function, see the Set Species vignette. + +The default setting is to model all mosquito species together. +```{r} +simparams$species +simparams$species_proportions +``` + ## Simulation -Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bednets once a year for two years, the first round to 80% of the population and the second round to 50% of the population. It is possible to change the characteristics of the bednets for each distribution timestep by modifying the values for `dn0`, `rn`, `rnm`, and `gamman`. Because there are 3 mosquito species specified in `set_species()` above and two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 3 columns and 2 rows. +Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bednets once a year for two years, the first round to 80% of the population and the second round to 50% of the population. It is possible to change the characteristics of the bednets for each distribution timestep if different types of bednets are distributed that have different insecticides, different levels of insecticide resistance, etc. This can be done by modifying the matrices for `dn0`, `rn`, `rnm`, and `gamman`. Because there are 3 mosquito species specified in `set_species()` above and two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 3 columns and 2 rows. + -```{r, fig.align='center', fig.height=4, fig.width=6} +```{r, fig.align="center", fig.height=4, fig.width=6} bednetstimesteps <- c(1, 2) * year # The bednets will be distributed at the end of the first and the second year. bednetparams <- set_bednets( @@ -90,23 +90,23 @@ bednetparams <- set_bednets( timesteps = bednetstimesteps, coverages = c(.8, .5), # The first round is distributed to 80% of the population and the second round to 50%. retention = 5 * year, # Nets are kept on average 5 years - dn0 = matrix(c(.533, .45), nrow=2, ncol=3), # Matrix of death probabilities for each mosquito species over time - rn = matrix(c(.56, .5), nrow=2, ncol=3), # Matrix of repelling probabilities for each mosquito species over time - rnm = matrix(c(.24, .24), nrow=2, ncol=3), # Matrix of minimum repelling probabilities for each mosquito species over time + dn0 = matrix(c(.533, .533), nrow = 2, ncol = 3), # Matrix of death probabilities for each mosquito species over time + rn = matrix(c(.56, .56), nrow = 2, ncol = 3), # Matrix of repelling probabilities for each mosquito species over time + rnm = matrix(c(.24, .24), nrow = 2, ncol = 3), # Matrix of minimum repelling probabilities for each mosquito species over time gamman = rep(2.64 * 365, 2) # Vector of bednet half-lives for each distribution timestep ) -output <- run_simulation(sim_length, bednetparams) +output <- run_simulation(timesteps = sim_length, parameters = bednetparams) ``` ### Plot prevalence -```{r, fig.align='center', fig.height=5, fig.width=7} +```{r, fig.align="center", fig.height=5, fig.width=7} plot_prev() ``` -## Visualisation +## Comparing input coverage and population bednet usage -It is important to understand the difference between the input `coverages` argument of `malariasimulation::set_bednets()` and the resulting population bednet usage over time in the model. In the above example, bednets are distributed to a specified percentage of the population at each distribution round; however, the level of bednet usage may be different. +It is important to understand the difference between the input `coverages` argument of `malariasimulation::set_bednets()` and the resulting population bednet usage over time in the model. When we set coverages in the above example to 0.8, we are telling the model to distribute bednets to 80% of the population at year one, and to 50% of the population at year 2. However, the level of average bednet usage is not necessarily equal to 80% or 50%. Between these time points, bednet use will slowly decline over time (in reality this decline stems from things like disuse, holes in nets, lost nets, etc.). The average population bednet usage will be influenced by: @@ -116,14 +116,14 @@ The average population bednet usage will be influenced by: The output from `malariasimulation::run_simulation()` has a variable `n_use_net` that shows the number of people using bednets at any given timestep. We can visualise the proportion of the population using bednets over time to understand how bednet usage changes. -```{r, fig.align='center', fig.height=5, fig.width=7} +```{r, fig.align="center", fig.height=5, fig.width=7} output$prop_use_net <- output$n_use_net / human_population -plot(x = output$timestep, y = output$prop_use_net, type = 'l', +plot(x = output$timestep, y = output$prop_use_net, type = "l", col = cols[3], lwd = 2.5, ylim = c(0,1), - xlab = 'Timestep (days)', ylab = 'Proportion of population using bednets', + xlab = "Timestep (days)", ylab = "Proportion of population using bednets", xaxs = "i", yaxs = "i", bty = "l") -grid(lty = 2, col = 'grey80', lwd = 1) +grid(lty = 2, col = "grey80", lwd = 1) axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") ``` @@ -133,6 +133,5 @@ The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool See the vignettes from the `netz` package that explain these concepts more comprehensively: -* [This vignette](https://mrc-ide.github.io/netz/articles/overview.html) explains how to estimate the distribution coverage from a specified bednet usage. * [This vignette](https://mrc-ide.github.io/netz/articles/population_usage.html) demonstrates how to estimate population bednet usage from an input distribution. diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index a9902ba7..1f25185b 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -29,22 +29,22 @@ cols <- c("#E69F00", "#56B4E9", "#009E73", # Plotting functions plot_prev <- function() { - plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, - type = 'l', col = cols[3], lwd = 2.5, - xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), + plot(x = output$timestep, y = output$n_detect_730_3650 / output$n_730_3650, + type = "l", col = cols[3], lwd = 2.5, + xlab = "Time (days)", ylab = expression(paste(italic(Pf),"PR"[2-10])), xaxs = "i", yaxs = "i", bty = "l", ylim = c(0,1)) - lines(x = output_control$timestep, y = output_control$n_detect_730_3650/output_control$n_730_3650, + lines(x = output_control$timestep, y = output_control$n_detect_730_3650 / output_control$n_730_3650, col = cols[5], lwd = 2.5) - abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = 'black') - grid(lty = 2, col = 'grey80', lwd = 1) - legend('bottomleft', box.lty = 0, legend = c('Spraying', 'Prevalence for IRS scenario','Prevalence for control scenario'), - col = c('black', cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) + abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = "black") + grid(lty = 2, col = "grey80", lwd = 1) + legend("bottomleft", box.lty = 0, legend = c("Spraying", "Prevalence for IRS scenario","Prevalence for control scenario"), + col = c("black", cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) } ``` ### Parameterisation -Use the `get_parameters()` function to generate a list of parameters, accepting most of the default values, but modifying seasonality values to model a seasonal setting. Then, we use the `set_equilibrium()` function to to initialise the model at a given entomological innoculation rate (EIR). +Use the `get_parameters()` function to generate a list of parameters, accepting most of the default values, but modifying seasonality values to model a seasonal setting. Then, we use the `set_equilibrium()` function to to initialise the model at a given entomological innoculation rate (EIR). ```{r} year <- 365 @@ -60,96 +60,54 @@ simparams <- get_parameters( model_seasonality = TRUE, g0 = 0.285277, g = c(-0.0248801, -0.0529426, -0.0168910), - h = c(-0.0216681, -0.0242904, -0.0073646), + h = c(-0.0216681, -0.0242904, -0.0073646) ) ) -simparams <- set_equilibrium(simparams, starting_EIR) +simparams <- set_equilibrium(parameters = simparams, init_EIR = starting_EIR) # Running simulation with no IRS output_control <- run_simulation(timesteps = sim_length, parameters = simparams) ``` - -## Simulation - -Then we can run the simulations for a variety of IRS strategies. In the example below, there are two rounds of IRS at 80% coverage, each 3 months prior to peak rainfall for that year. The function `peak_season_offset()` outputs a timestep when peak rainfall will be observed based on the seasonality profile we set above. Notice that the matrices specified for the parameters for `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` have two rows, one for each timestep where IRS occurs, and 1 column for all mosquitoes, not divided by species. - -```{r, fig.align='center', fig.height=4, fig.width=6} -peak <- peak_season_offset(simparams) - -sprayingtimesteps <- c(1, 2) * year + peak - 3 * month # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. - -sprayingparams <- set_spraying( - simparams, - timesteps = sprayingtimesteps, - coverages = rep(.8, 2), # Each round covers 80% of the population - ls_theta = matrix(c(2.025, 2.025), nrow=2, ncol=1), # Matrix of mortality parameters - ls_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1), # Matrix of mortality parameters per timestep - ks_theta = matrix(c(-2.222, -2.222), nrow=2, ncol=1), # Matrix of feeding success parameters - ks_gamma = matrix(c(0.008, 0.008), nrow=2, ncol=1), # Matrix of feeding success parameters per timestep - ms_theta = matrix(c(-1.232, -1.232), nrow=2, ncol=1), # Matrix of deterrence parameters - ms_gamma = matrix(c(-0.009, -0.009), nrow=2, ncol=1) # Matrix of deterrence parameters per timestep -) - -output <- run_simulation(sim_length, sprayingparams) -``` +#### A note on mosquito species +It is also possible to use the `set_species()` function to account for 3 different mosquito species in the simulation. In this case, the matrices would need to have additional column corresponding to each mosquito species. For example, if we specified that there were 3 species of mosquitoes in the model and IRS was implemented at two timesteps, then the matrices would have 2 rows and 3 columns. If you are not already familiar with the `set_species()` function, see the Set Species vignette. -### Plot prevalence -```{r,fig.align='center', fig.height=5, fig.width=7} -plot_prev() +The default setting is to model all mosquito species together. +```{r} +simparams$species ``` -## Additional species -It is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. There are preset parameters for *An. gambiae*, *An. arabiensis*, and *An. funestus* that can be set by the helper functions `gamb_params()`, `arab_params()`, and `fun_params()`, respectively. IRS could be expected to have different impacts depending on the proportion of each mosquito species because of variations in indoor resting, insecticide resistance, and proportion of bites on humans versus animals by species. -If you have specified more than 1 species, then the arguments for `set_spraying()` and `set_bednets()` must be populated with values for each species at each time point. +## Simulation -We will run the same model with IRS as above, but this time with 3 species of mosquitoes. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. Each column corresponds to a species of mosquito, and each row corresponds to the timestep when a round of IRS occurred. Here, we are assuming the same values for each species at each timepoint for simplicity, but the matrix could be edited to have different values by species or over time. +Then we can run the simulations for a variety of IRS strategies. In the example below, there are two rounds of IRS at 80% coverage, each 3 months prior to peak rainfall for that year. The function `peak_season_offset()` outputs a timestep when peak rainfall will be observed based on the seasonality profile we set above. Notice that the matrices specified for the parameters for `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` have two rows, one for each timestep where IRS is implemented, and a number of columns corresponding to mosquito species. In this example, we only have 1 column because the species is set to "All" as we saw above. -```{r, fig.align='center', fig.height=4, fig.width=6} -## Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae -simparams <- set_species( - simparams, - species = list(arab_params, fun_params, gamb_params), - proportions = c(0.25, 0.25, 0.5) -) +The structure for IRS model is documented in the supplementary information from 10.1038/s41467-018-07357-w. +```{r, fig.align="center", fig.height=4, fig.width=6} peak <- peak_season_offset(simparams) -sprayingtimesteps <- c(1, 2) * year + peak - 3 * month # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. +sprayingtimesteps <- c(1, 2) * year + peak - 3 * month # A round of IRS is implemented in the 1st and second year 3 months prior to peak transmission. sprayingparams <- set_spraying( simparams, timesteps = sprayingtimesteps, coverages = rep(.8, 2), # # Each round covers 80% of the population - ls_theta = matrix(2.025, nrow=length(sprayingtimesteps), ncol=3), # Matrix of mortality parameters; nrows=length(timesteps), ncols=length(species) - ls_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=3), # Matrix of mortality parameters per timestep - ks_theta = matrix(-2.222, nrow=length(sprayingtimesteps), ncol=3), # Matrix of feeding success parameters - ks_gamma = matrix(0.008, nrow=length(sprayingtimesteps), ncol=3), # Matrix of feeding success parametersper timestep - ms_theta = matrix(-1.232, nrow=length(sprayingtimesteps), ncol=3), # Matrix of deterrence parameters - ms_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=3) # Matrix of deterrence parameters per timestep + ls_theta = matrix(2.025, nrow=length(sprayingtimesteps), ncol=1), # Matrix of mortality parameters; nrows=length(timesteps), ncols=length(species) + ls_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=1), # Matrix of mortality parameters per round of IRS and per species + ks_theta = matrix(-2.222, nrow=length(sprayingtimesteps), ncol=1), # Matrix of feeding success parameters per round of IRS and per species + ks_gamma = matrix(0.008, nrow=length(sprayingtimesteps), ncol=1), # Matrix of feeding success parameters per round of IRS and per species + ms_theta = matrix(-1.232, nrow=length(sprayingtimesteps), ncol=1), # Matrix of deterrence parameters per round of IRS and per species + ms_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=1) # Matrix of deterrence parameters per round of IRS and per species ) -output <- run_simulation(sim_length, sprayingparams) +output <- run_simulation(timesteps = sim_length, parameters = sprayingparams) ``` + ### Plot prevalence -```{r,fig.align='center', fig.height=5, fig.width=7} +```{r,fig.align="center", fig.height=5, fig.width=7} plot_prev() ``` -### Plot adult female infectious mosquitoes by species over time -```{r,fig.align='center', fig.height=5, fig.width=7} -plot(x = output$timestep, y = output$Im_gamb_count, - type = 'l', col = cols[5], lwd = 2.5, - xlab = 'Time (days)', ylab = 'N mosquitoes', - xaxs = "i", yaxs = "i", bty = "l") -lines(x = output$timestep, y = output$Im_fun_count, - col = cols[6], lwd = 2.5) -lines(x = output$timestep, y = output$Im_arab_count, - col = cols[3], lwd = 2.5) -grid(lty = 2, col = 'grey80', lwd = 1) -legend('topright', box.lty = 0, legend = c(expression(paste('N ', italic('An. gambiae'))), expression(paste('N ', italic('An. funestus'))),expression(paste('N ', italic('An. arabiensis')))), col = c(cols[5], cols[6], cols[3]), lty = c(1,1,1), lwd = 2.5) -``` - From 3f8182a2f22ad24eed8c341bde4d558785e641b8 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 9 Mar 2023 15:57:55 +0000 Subject: [PATCH 061/164] changes to bednet rmd before I renamed it --- vignettes/VectorControl.Rmd | 74 ++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd index 7c44da1b..4fefa3b4 100644 --- a/vignettes/VectorControl.Rmd +++ b/vignettes/VectorControl.Rmd @@ -19,7 +19,7 @@ library(malariasimulation) library(malariaEquilibrium) ``` -Long-lasting insecticidal bednets are highly effective and relatively cheap interventions to prevent malaria. The effects of insecticidal bed net distribution campsigns can be simulated using malariasimulation. The model provides the user with the flexibility to specify parameters that describe the net distribution campaign (e.g. timing, coverage, and target population), the bed nets distributed (e.g. efficacy, longevity), and the relative densities of the mosquito species present in the target population. We will illustrate this through an example with two bednet distributions, once per year. +Long-lasting insecticide-treated bednets is a highly effective intervention to prevent malaria. The effects of insecticidal bednet distribution campaigns can be simulated using `malariasimulation`. The model provides the user with the flexibility to specify parameters that describe the net distribution campaign (e.g. timing, coverage, and target population) and the bednets distributed (e.g. efficacy, longevity). We will illustrate this through an example with two bednet distributions, once per year. ### Plotting functions We can create a few plotting functions to visualise the output. @@ -29,22 +29,22 @@ cols <- c("#E69F00", "#56B4E9", "#009E73", # Plotting functions plot_prev <- function() { - plot(x = output$timestep, y = output$n_detect_730_3650/output$n_730_3650, - type = 'l', col = cols[3], lwd = 2.5, - xlab = 'Time (days)', ylab = expression(paste(italic(Pf),"PR"[2-10])), - xaxs = "i", yaxs = "i", bty = "l", ylim = c(0.15, 0.93)) - lines(x = output_control$timestep, y = output_control$n_detect_730_3650/output_control$n_730_3650, + plot(x = output$timestep, y = output$n_detect_730_3650 / output$n_730_3650, + type = "l", col = cols[3], lwd = 2.5, + xlab = "Time (days)", ylab = expression(paste(italic(Pf),"PR"[2-10])), + xaxs = "i", yaxs = "i", bty = "l", ylim = c(0, 1)) + lines(x = output_control$timestep, y = output_control$n_detect_730_3650 / output_control$n_730_3650, col = cols[5], lwd = 2.5) - abline(v = bednetstimesteps, col = 'black', lty = 2, lwd = 2.5) - grid(lty = 2, col = 'grey80', lwd = 1) - legend('bottomleft', box.lty = 0, legend = c('Bednets','Prevalence for bednet scenario','Prevalence for control scenario'), - col = c('black', cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) + abline(v = bednetstimesteps, col = "black", lty = 2, lwd = 2.5) + grid(lty = 2, col = "grey80", lwd = 1) + legend("bottomleft", box.lty = 0, legend = c("Bednets","Prevalence for bednet scenario","Prevalence for control scenario"), + col = c("black", cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) } ``` ### Parameterisation -Use the `get_parameters()` function to generate the list of parameters for a seasonal profile, accepting the default values to run the simulation from an equilibrium starting point. The seasonality will drive mosquito dynamics in the absence of interventions. +Use the `get_parameters()` function to generate the list of parameters for a perennial profile, accepting the default values to run the simulation from an equilibrium starting point. ```{r} year <- 365 @@ -53,17 +53,7 @@ human_population <- 1000 starting_EIR <- 50 simparams <- get_parameters( - list( - human_population = human_population, - # seasonality parameters - model_seasonality = TRUE, # Let's try a bi-modal model - g0 = 0.28605, - g = c(0.20636, -0.0740318, -0.0009293), - h = c(0.173743, -0.0730962, -0.116019), - # Here, we are asking for the output to contain information on severe incidence in children 2-10 years old. - clinical_incidence_rendering_min_ages = 2*year, - clinical_incidence_rendering_max_ages = 10*year - ) + list(human_population = human_population) ) # Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae @@ -73,16 +63,25 @@ simparams <- set_species( proportions = c(0.25, 0.25, 0.5) ) -simparams <- set_equilibrium(simparams, starting_EIR) +simparams <- set_equilibrium(parameters = simparams, init_EIR = starting_EIR) -output_control <- run_simulation(sim_length, simparams) +output_control <- run_simulation(timesteps = sim_length, parameters = simparams) ``` +#### A note on mosquito species +It is also possible to use the `set_species()` function to account for 3 different mosquito species in the simulation. In this case, the matrices would need to have additional column corresponding to each mosquito species. For example, if we specified that there were 3 species of mosquitoes in the model and nets were distributed at two timesteps, then the matrices would have 2 rows and 3 columns. If you are not already familiar with the `set_species()` function, see the Set Species vignette. + +The default parameters is to model all mosquito species together. +```{r} +simparams$species +``` + ## Simulation -Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bednets once a year for two years, the first round to 80% of the population and the second round to 50% of the population. It is possible to change the characteristics of the bednets for each distribution timestep by modifying the values for `dn0`, `rn`, `rnm`, and `gamman`. Because there are 3 mosquito species specified in `set_species()` above and two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 3 columns and 2 rows. +Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bednets once a year for two years, the first round to 80% of the population and the second round to 50% of the population. It is possible to change the characteristics of the bednets for each distribution timestep if different types of bednets are distributed that have different insecticides, different levels of insecticide resistance, etc. This can be done by modifying the matrices for `dn0`, `rn`, `rnm`, and `gamman`. Because there are 3 mosquito species specified in `set_species()` above and two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 3 columns and 2 rows. + -```{r, fig.align='center', fig.height=4, fig.width=6} +```{r, fig.align="center", fig.height=4, fig.width=6} bednetstimesteps <- c(1, 2) * year # The bednets will be distributed at the end of the first and the second year. bednetparams <- set_bednets( @@ -90,23 +89,23 @@ bednetparams <- set_bednets( timesteps = bednetstimesteps, coverages = c(.8, .5), # The first round is distributed to 80% of the population and the second round to 50%. retention = 5 * year, # Nets are kept on average 5 years - dn0 = matrix(c(.533, .45), nrow=2, ncol=3), # Matrix of death probabilities for each mosquito species over time - rn = matrix(c(.56, .5), nrow=2, ncol=3), # Matrix of repelling probabilities for each mosquito species over time - rnm = matrix(c(.24, .24), nrow=2, ncol=3), # Matrix of minimum repelling probabilities for each mosquito species over time + dn0 = matrix(c(.533, .533), nrow = 2, ncol = 3), # Matrix of death probabilities for each mosquito species over time + rn = matrix(c(.56, .56), nrow = 2, ncol = 3), # Matrix of repelling probabilities for each mosquito species over time + rnm = matrix(c(.24, .24), nrow = 2, ncol = 3), # Matrix of minimum repelling probabilities for each mosquito species over time gamman = rep(2.64 * 365, 2) # Vector of bednet half-lives for each distribution timestep ) -output <- run_simulation(sim_length, bednetparams) +output <- run_simulation(timesteps = sim_length, parameters = bednetparams) ``` ### Plot prevalence -```{r, fig.align='center', fig.height=5, fig.width=7} +```{r, fig.align="center", fig.height=5, fig.width=7} plot_prev() ``` -## Visualisation +## Comparing input coverage and population bednet usage -It is important to understand the difference between the input `coverages` argument of `malariasimulation::set_bednets()` and the resulting population bednet usage over time in the model. In the above example, bednets are distributed to a specified percentage of the population at each distribution round; however, the level of bednet usage may be different. +It is important to understand the difference between the input `coverages` argument of `malariasimulation::set_bednets()` and the resulting population bednet usage over time in the model. When we set coverages in the above example to 0.8, we are telling the model to distribute bednets to 80% of the population at year one, and to 50% of the population at year 2. However, the level of average bednet usage is not necessarily equal to 80% or 50%. Between these time points, bednet use will slowly decline over time (in reality this decline stems from things like disuse, holes in nets, lost nets, etc.). The average population bednet usage will be influenced by: @@ -116,14 +115,14 @@ The average population bednet usage will be influenced by: The output from `malariasimulation::run_simulation()` has a variable `n_use_net` that shows the number of people using bednets at any given timestep. We can visualise the proportion of the population using bednets over time to understand how bednet usage changes. -```{r, fig.align='center', fig.height=5, fig.width=7} +```{r, fig.align="center", fig.height=5, fig.width=7} output$prop_use_net <- output$n_use_net / human_population -plot(x = output$timestep, y = output$prop_use_net, type = 'l', +plot(x = output$timestep, y = output$prop_use_net, type = "l", col = cols[3], lwd = 2.5, ylim = c(0,1), - xlab = 'Timestep (days)', ylab = 'Proportion of population using bednets', + xlab = "Timestep (days)", ylab = "Proportion of population using bednets", xaxs = "i", yaxs = "i", bty = "l") -grid(lty = 2, col = 'grey80', lwd = 1) +grid(lty = 2, col = "grey80", lwd = 1) axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") ``` @@ -133,6 +132,5 @@ The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool See the vignettes from the `netz` package that explain these concepts more comprehensively: -* [This vignette](https://mrc-ide.github.io/netz/articles/overview.html) explains how to estimate the distribution coverage from a specified bednet usage. * [This vignette](https://mrc-ide.github.io/netz/articles/population_usage.html) demonstrates how to estimate population bednet usage from an input distribution. From 1014b8a343d09390e09fe5e2fe27c578b862614d Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 9 Mar 2023 16:05:29 +0000 Subject: [PATCH 062/164] deleting old bednet vignette --- vignettes/VectorControl.Rmd | 136 ------------------------------------ 1 file changed, 136 deletions(-) delete mode 100644 vignettes/VectorControl.Rmd diff --git a/vignettes/VectorControl.Rmd b/vignettes/VectorControl.Rmd deleted file mode 100644 index 4fefa3b4..00000000 --- a/vignettes/VectorControl.Rmd +++ /dev/null @@ -1,136 +0,0 @@ ---- -title: "Vector Control: Bednets" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{Vector Control: Bednets} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r, include = FALSE} -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>" -) -``` - -```{r setup} -library(malariasimulation) -library(malariaEquilibrium) -``` - -Long-lasting insecticide-treated bednets is a highly effective intervention to prevent malaria. The effects of insecticidal bednet distribution campaigns can be simulated using `malariasimulation`. The model provides the user with the flexibility to specify parameters that describe the net distribution campaign (e.g. timing, coverage, and target population) and the bednets distributed (e.g. efficacy, longevity). We will illustrate this through an example with two bednet distributions, once per year. - -### Plotting functions -We can create a few plotting functions to visualise the output. -```{r} -cols <- c("#E69F00", "#56B4E9", "#009E73", - "#F0E442", "#0072B2", "#D55E00", "#CC79A7") - -# Plotting functions -plot_prev <- function() { - plot(x = output$timestep, y = output$n_detect_730_3650 / output$n_730_3650, - type = "l", col = cols[3], lwd = 2.5, - xlab = "Time (days)", ylab = expression(paste(italic(Pf),"PR"[2-10])), - xaxs = "i", yaxs = "i", bty = "l", ylim = c(0, 1)) - lines(x = output_control$timestep, y = output_control$n_detect_730_3650 / output_control$n_730_3650, - col = cols[5], lwd = 2.5) - abline(v = bednetstimesteps, col = "black", lty = 2, lwd = 2.5) - grid(lty = 2, col = "grey80", lwd = 1) - legend("bottomleft", box.lty = 0, legend = c("Bednets","Prevalence for bednet scenario","Prevalence for control scenario"), - col = c("black", cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) -} -``` - -### Parameterisation - -Use the `get_parameters()` function to generate the list of parameters for a perennial profile, accepting the default values to run the simulation from an equilibrium starting point. - -```{r} -year <- 365 -sim_length <- 3 * year -human_population <- 1000 -starting_EIR <- 50 - -simparams <- get_parameters( - list(human_population = human_population) -) - -# Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae -simparams <- set_species( - simparams, - species = list(arab_params, fun_params, gamb_params), - proportions = c(0.25, 0.25, 0.5) -) - -simparams <- set_equilibrium(parameters = simparams, init_EIR = starting_EIR) - -output_control <- run_simulation(timesteps = sim_length, parameters = simparams) -``` - -#### A note on mosquito species -It is also possible to use the `set_species()` function to account for 3 different mosquito species in the simulation. In this case, the matrices would need to have additional column corresponding to each mosquito species. For example, if we specified that there were 3 species of mosquitoes in the model and nets were distributed at two timesteps, then the matrices would have 2 rows and 3 columns. If you are not already familiar with the `set_species()` function, see the Set Species vignette. - -The default parameters is to model all mosquito species together. -```{r} -simparams$species -``` - -## Simulation - -Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bednets once a year for two years, the first round to 80% of the population and the second round to 50% of the population. It is possible to change the characteristics of the bednets for each distribution timestep if different types of bednets are distributed that have different insecticides, different levels of insecticide resistance, etc. This can be done by modifying the matrices for `dn0`, `rn`, `rnm`, and `gamman`. Because there are 3 mosquito species specified in `set_species()` above and two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 3 columns and 2 rows. - - -```{r, fig.align="center", fig.height=4, fig.width=6} -bednetstimesteps <- c(1, 2) * year # The bednets will be distributed at the end of the first and the second year. - -bednetparams <- set_bednets( - simparams, - timesteps = bednetstimesteps, - coverages = c(.8, .5), # The first round is distributed to 80% of the population and the second round to 50%. - retention = 5 * year, # Nets are kept on average 5 years - dn0 = matrix(c(.533, .533), nrow = 2, ncol = 3), # Matrix of death probabilities for each mosquito species over time - rn = matrix(c(.56, .56), nrow = 2, ncol = 3), # Matrix of repelling probabilities for each mosquito species over time - rnm = matrix(c(.24, .24), nrow = 2, ncol = 3), # Matrix of minimum repelling probabilities for each mosquito species over time - gamman = rep(2.64 * 365, 2) # Vector of bednet half-lives for each distribution timestep -) - -output <- run_simulation(timesteps = sim_length, parameters = bednetparams) -``` - -### Plot prevalence -```{r, fig.align="center", fig.height=5, fig.width=7} -plot_prev() -``` - -## Comparing input coverage and population bednet usage - -It is important to understand the difference between the input `coverages` argument of `malariasimulation::set_bednets()` and the resulting population bednet usage over time in the model. When we set coverages in the above example to 0.8, we are telling the model to distribute bednets to 80% of the population at year one, and to 50% of the population at year 2. However, the level of average bednet usage is not necessarily equal to 80% or 50%. Between these time points, bednet use will slowly decline over time (in reality this decline stems from things like disuse, holes in nets, lost nets, etc.). - -The average population bednet usage will be influenced by: - -* The size and frequency of distributions specified in `set_bednets()` -* The assumed net retention half life (`gamman`) -* Correlations in the recipients of nets between rounds - -The output from `malariasimulation::run_simulation()` has a variable `n_use_net` that shows the number of people using bednets at any given timestep. We can visualise the proportion of the population using bednets over time to understand how bednet usage changes. - -```{r, fig.align="center", fig.height=5, fig.width=7} -output$prop_use_net <- output$n_use_net / human_population - -plot(x = output$timestep, y = output$prop_use_net, type = "l", - col = cols[3], lwd = 2.5, ylim = c(0,1), - xlab = "Timestep (days)", ylab = "Proportion of population using bednets", - xaxs = "i", yaxs = "i", bty = "l") -grid(lty = 2, col = "grey80", lwd = 1) -axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") -``` - -## Using the `netz` package to estimate coverage inputs needed to achieve target population usage - -The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool to help set up bednets in `malariasimulation`. `malariasimulation` takes as input the proportion of the population who were distributed a bednet at specific time points, but available data for a specific region or country do not always have this information. `netz` allows for simple conversions between bednet metrics like crop, access, distribution, and usage. - -See the vignettes from the `netz` package that explain these concepts more comprehensively: - -* [This vignette](https://mrc-ide.github.io/netz/articles/population_usage.html) demonstrates how to estimate population bednet usage from an input distribution. - From 9b6417d32c4ff6f27ae271ccc98df652cc103a36 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 9 Mar 2023 17:25:52 +0000 Subject: [PATCH 063/164] Improved plots, edits from Hillary, changed all '' to "" --- vignettes/Vaccines.Rmd | 167 ++++++++++++++++++++++------------------- 1 file changed, 88 insertions(+), 79 deletions(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 64a90284..688521ae 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -14,7 +14,7 @@ knitr::opts_chunk$set( ) ``` -In this tutorial, we will explore how to model different strategies for both pre-erythrocytic malaria vaccines and a theoretical malaria transmission blocking vaccine (TBV). Parameters for the pre-erythrocytic vaccine can be set for a routine Expanded Programme on Immunization (EPI) strategy or a mass vaccination strategy using the helper functions `set_rtss_epi()` and `set_mass_rtss()`, while parameters for a TBV can be set using `set_tbv()`. Under an EPI strategy, everybody within a certain age range will be vaccinated within the routine immunisation system. A mass vaccination strategy is typically a one-time event where everybody, or everybody within a certain age group, is targeted for vaccination during a relatively short window of time. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the expected peak of malaria prevalence given by `peak_season_offset()`. +In this tutorial, we will explore how to model different strategies for both pre-erythrocytic malaria vaccines and a theoretical malaria transmission blocking vaccine (TBV). Parameters for the pre-erythrocytic vaccine can be set for a routine age-based Expanded Programme on Immunization (EPI) strategy or a mass vaccination strategy using the helper functions `set_rtss_epi()` and `set_mass_rtss()`, while parameters for a TBV can be set using `set_tbv()`. Under an EPI strategy, everybody within a certain age range will be vaccinated within the routine immunisation system. A mass vaccination strategy is typically a one-time event where everybody, or everybody within a certain age group, is targeted for vaccination during a relatively short window of time. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the expected peak of malaria prevalence given by `peak_season_offset()`. ```{r setup, message=FALSE} library(malariasimulation) @@ -29,38 +29,38 @@ First, we will define a few functions to visualise the outputs. ```{r} # Plotting clinical incidence -plot_inci <- function(type = 'not seasonal'){ - if(type == 'seasonal'){ +plot_inci <- function(type = "not seasonal"){ + if(type == "seasonal"){ comparison <- output_seas_control vaccinetime <- round(year + (peak - month * 3.5), 0) / 365 } else { comparison <- output_control vaccinetime <- 1 } - output$clinical_incidence <- 1000 * output$n_inc_0_1825 / output$n_0_1825 + output$clinical_incidence <- 1000 * output$n_inc_clinical_0_1825 / output$n_0_1825 output$time_year <- output$timestep / year - comparison$clinical_incidence <- 1000 * comparison$n_inc_0_1825 / comparison$n_0_1825 + comparison$clinical_incidence <- 1000 * comparison$n_inc_clinical_0_1825 / comparison$n_0_1825 comparison$time_year <- comparison$timestep / year plot(x = output$time_year, y = output$clinical_incidence, - type = 'l', col = cols[2], - xlab = 'Time (years)', ylab = 'Clinical incidence (per 1000 children aged 0-5)', + type = "l", col = cols[2], + xlab = "Time (years)", ylab = "Clinical incidence (per 1000 children aged 0-5)", xaxs = "i", yaxs = "i", bty = "l", xaxs = "i", yaxs = "i") - grid(lty = 2, col = 'grey80', lwd = 1) - abline(v = vaccinetime, col = 'black', lty = 2, lwd = 2.5) - curve_values <- loess(clinical_incidence ~ time_year, data = output, span = 0.3, method = 'loess') + grid(lty = 2, col = "grey80", lwd = 1) + abline(v = vaccinetime, col = "black", lty = 2, lwd = 2.5) + curve_values <- loess(clinical_incidence ~ time_year, data = output, span = 0.3, method = "loess") lines(output$time_year, predict(curve_values), col = cols[5], lwd = 3) - curve_valuescomp <- loess(clinical_incidence ~ time_year, data = comparison, span = 0.3, method = 'loess') + curve_valuescomp <- loess(clinical_incidence ~ time_year, data = comparison, span = 0.3, method = "loess") lines(comparison$time_year, predict(curve_valuescomp), col = cols[6], lwd = 3) - legend('topright', box.lty = 0, legend = c('Start of vaccination', 'Incidence for vaccine scenario', 'Smoothed incidence for \nno intervention scenario'), - col = c('black', cols[5], cols[5]), lty = c(2,1,1), lwd = 2.5) + legend("topright", box.lty = 0, legend = c("Start of vaccination", "Incidence for vaccine scenario", "Smoothed incidence for \nno intervention scenario"), + col = c("black", cols[2], cols[5]), lty = c(2,1,1), lwd = 2.5) } # Plot parasite prevalence -plot_prev <- function(type = 'not seasonal'){ - if(type == 'seasonal'){ +plot_prev <- function(type = "not seasonal"){ + if(type == "seasonal"){ comparison <- output_seas_control vaccinetime <- round(year + (peak - month * 3.5), 0) / 365 } else { @@ -71,40 +71,40 @@ plot_prev <- function(type = 'not seasonal'){ comparison$time_year <- comparison$timestep / year plot(x = output$time_year, y = output$n_detect_730_3650/output$n_730_3650, - type = 'l', col = cols[3], ylim=c(0,1), - xlab = 'Time (years)', ylab = expression(paste(italic(Pf),"PR"[2-10])), + type = "l", col = cols[3], ylim=c(0,1), lwd = 3, + xlab = "Time (years)", ylab = expression(paste(italic(Pf),"PR"[2-10])), xaxs = "i", yaxs = "i", bty = "l", xaxs = "i", yaxs = "i") - grid(lty = 2, col = 'grey80', lwd = 1) + grid(lty = 2, col = "grey80", lwd = 1) lines(x = comparison$time_year, y = comparison$n_detect_730_3650/comparison$n_730_3650, - col = cols[6]) - abline(v = vaccinetime, col = 'black', lty = 2, lwd = 2.5) - legend('topright', box.lty = 0, legend = c('Start of vaccination', 'Prevalence for vaccine scenario', 'Prevalence for no intervention scenario'), - col = c('black', cols[3], cols[6]), lty = c(2,1,1), lwd = 2.5) + col = cols[6], lwd = 3,) + abline(v = vaccinetime, col = "black", lty = 2, lwd = 2.5) + legend("topright", box.lty = 0, legend = c("Start of vaccination", "Prevalence for vaccine scenario", "Prevalence for no intervention scenario"), + col = c("black", cols[3], cols[6]), lty = c(2, 1, 1), lwd = 2.5) } # Plot dose timing plot_doses <- function(){ output$month <- ceiling(output$timestep / month) - doses <- output[,c(2:5,38)] + doses <- output[,c(2:5, 38)] doses <- aggregate(cbind(doses[1:4]), by = list(doses$month), FUN = sum) - doses <- as.matrix(t(doses[,-1])) + doses <- as.matrix(t(doses[, -1])) barplot(doses, xlab = "Month", - ylab = 'Number of doses', + ylab = "Number of doses", col = cols[1:6],space = 0, beside = FALSE, xaxs = "i", yaxs = "i") - grid(lty = 2, col = 'grey80', lwd = 1) + grid(lty = 2, col = "grey80", lwd = 1) axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") - legend('topleft', box.lty = 0, legend = c('Dose 1','Dose 2','Dose 3','Booster 1'), + legend("topleft", box.lty = 0, legend = c("Dose 1","Dose 2","Dose 3","Booster 1"), col = cols[1:6], lty = rep(1, 4), lwd = 2.5, bg="transparent") } ``` ## Parameterisation -We will set the default parameters to run the simulation from an equilibrium starting point that has no seasonality using the `set_equilibrium()` function. +We use the `get_parameters()` function to generate a list of parameters, accepting most of the default values, and then use the `set_equilibrium()` function to to initialise the model at a given entomological inoculation rate (EIR) ```{r} year <- 365 @@ -115,23 +115,23 @@ starting_EIR <- 20 simparams <- get_parameters(list( human_population = human_population, - incidence_rendering_min_ages = 0, - incidence_rendering_max_ages = 5 * year, + clinical_incidence_rendering_min_ages = 0, + clinical_incidence_rendering_max_ages = 5 * year, individual_mosquitoes = FALSE ) ) -simparams <- set_equilibrium(simparams, starting_EIR) +simparams <- set_equilibrium(parameters = simparams, init_EIR = starting_EIR) # Run a model with no interventions in a setting with no seasonality -output_control <- run_simulation(sim_length * 2, simparams) +output_control <- run_simulation(timesteps = sim_length * 2, parameters = simparams) ``` Then we can run the simulation for a variety of vaccination strategies. ## Mass RTS,S -First, we will model a single round of RTS,S vaccine given in a mass vaccination strategy where those within a given age range will be vaccinated to a specified coverage level and during a short window of time. In this example, individuals aged between 5 months and 10 years are vaccinated with a primary series (3 doses) followed by a single booster 12 months after the initial vaccination. The age groups to be vaccinated as well as timing of all vaccinations can be modified within the `set_mass_rtss()` function. +First, we will model a single round of RTS,S vaccine given in a mass vaccination strategy where those within a given age range will be vaccinated to a specified coverage level and during a short window of time. In this example, individuals aged between 5 and 17 months are vaccinated with a primary series (3 doses) followed by a single booster 12 months after the initial vaccination. The age groups to be vaccinated as well as timing of all vaccinations can be modified within the `set_mass_rtss()` function. We specify that the intervention should use the RTS,S vaccine through the `profile` and `booster_profile` inputs. @@ -140,36 +140,38 @@ rtssparams <- set_mass_rtss( simparams, timesteps = 1 * year, # The single round of vaccination is at 1 year into the simulation. coverages = 1, # The vaccine is given to 100% of the population between the specified ages. - min_wait = 0, # The minimum acceptable time since the last vaccination is 0. + min_wait = 0, # The minimum acceptable time since the last vaccination is 0 because in our case we are only implementing one round of vaccination. min_ages = 5 * month, # The minimum age for the target population to be vaccinated. - max_ages = 10 * year, # The maximum age for the target population to be vaccinated. - boosters = 12 * month, # The booster is given at 12 months after the initial vaccination. + max_ages = 5 * year, # The maximum age for the target population to be vaccinated. + boosters = 12 * month, # The booster is given at 12 months after the primary series. booster_coverage = 0.95 # Coverage of the booster dose is 95%. ) -output <- run_simulation(sim_length, rtssparams) +output <- run_simulation(timesteps = sim_length, parameters = rtssparams) ``` -#### Plot clinical incidence and prevalence +#### Plot clinical incidence -```{r, fig.width = 8, fig.height = 4, fig.align = 'center'} -par(mfrow = c(1,2)) +```{r, fig.width = 7, fig.height = 5, fig.align = "center"} plot_inci() +``` + +#### Plot prevalence +```{r, fig.width = 7, fig.height = 5, fig.align = "center"} plot_prev() ``` -We see a much more gradual decrease in clinical incidence following EPI implementation compared to the mass vaccination strategy. - + #### Plot doses You can look at the distribution of doses using the `n_rtss_mass_dose_*` or `n_rtss_epi_dose_*` outputs. It is always a good idea to check the timing of vaccine doses to ensure that it is specified as intended. -```{r, fig.width = 6, fig.height = 4, fig.align = 'center', message=FALSE} +```{r, fig.width = 7, fig.height = 5, fig.align = "center", message=FALSE} plot_doses() ``` ### Seasonal mass vaccination -Mass vaccination can also be targeted seasonally. For example, we may want to have a mass vaccination campaign a few months prior to the peak transmission season. In the example below, we will create a parameter set with seasonality and first run a simulation with no vaccine, then run a simulation with a mass vaccination campaign targeting everyone between the ages of 5 months and 15 years. +Mass vaccination can also be targeted seasonally. For example, we may want to have a mass vaccination campaign take place a few months prior to the peak transmission season. In the example below, we will create a parameter set with seasonality and first run a simulation with no vaccine, then run a simulation with a mass vaccination campaign targeting everyone between the ages of 5 months and 15 years. We specify that the intervention should use the RTS,S vaccine through the `profile` and `booster_profile` inputs. @@ -178,13 +180,13 @@ We specify that the intervention should use the RTS,S vaccine through the `profi seas_simparams <- get_parameters( list( human_population = human_population, - incidence_rendering_min_ages = 0, - incidence_rendering_max_ages = 5 * year, + clinical_incidence_rendering_min_ages = 0, + clinical_incidence_rendering_max_ages = 5 * year, individual_mosquitoes = FALSE, - model_seasonality = TRUE, # Let's try a bi-modal model + model_seasonality = TRUE, g0 = 0.285505, - g = c(-0.325352,-0.0109352,0.0779865), - h = c(-0.132815,0.104675,-0.013919) + g = c(-0.325352, -0.0109352, 0.0779865), + h = c(-0.132815, 0.104675, -0.013919) ) ) @@ -203,8 +205,8 @@ seasmass_simparams <- set_mass_rtss( parameters = seas_simparams, timesteps = round(year + (peak - month * 3.5), 0),# The vaccination will begin 3.5 months prior to the peak seasonality in the second year. coverages = 1, # 100% of the population between min_ages and max_ages is vaccinated. - min_ages = 5 * month, # - max_ages = 15 * year, + min_ages = 5 * month, # The minimum age for the target population to be vaccinated. + max_ages = 5 * year, # The maximum age for the target population to be vaccinated. min_wait = 0, # There is no minimum wait between the last vaccination. boosters = round(c(12 * month + 2 * month)), # The booster is given 14 months after the first dose. booster_coverage = 1) # 100% of the vaccinated population is boosted. @@ -214,59 +216,66 @@ output <- run_simulation(sim_length * 2, seasmass_simparams) #### Plot clinical incidence -```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} -plot_inci(type = 'seasonal') +```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +plot_inci(type = "seasonal") ``` #### Plot prevalence -```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} -plot_prev(type = 'seasonal') +```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +plot_prev(type = "seasonal") ``` #### Plot doses -```{r, fig.width = 6, fig.height = 4, fig.align = 'center', message=FALSE} +```{r, fig.width = 7, fig.height = 5, fig.align = "center", message=FALSE} plot_doses() ``` ## RTS,S EPI -We can also opt to vaccinate using the EPI strategy, where individuals will be vaccinated once they reach a certain age. In the example below, individuals will be vaccinated once they reach 5 months of age. For this intervention, we see a much more gradual impact following implementation. +We can also opt to vaccinate using the EPI strategy, where individuals will be vaccinated once they reach a certain age. In the example below, individuals will be vaccinated once they reach 5 months of age. For this intervention, we see a much more gradual impact following implementation. Note: the model assumes that protection from the vaccine begins after the third dose. ```{r} # Add RTS,S strategy rtssepiparams <- set_rtss_epi( simparams, - timesteps = 1 * year, # Vaccination will begin at 1 year. + timesteps = 1 * year, # Vaccination will begin at 1 year into the simulation. coverages = 1, # Vaccine coverage is 100%. min_wait = 0, # There is no minimum wait since the last vaccination. age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. - boosters = 12 * month, # The booster is administered 12 months following the initial vaccination. + boosters = 12 * month, # The booster is administered 12 months following the third dose. booster_coverage = 0.95 # 95% of those vaccinated with the primary series will be boosted. ) output <- run_simulation(sim_length * 2, rtssepiparams) ``` +The default values for the `rtss_doses` variable shows that individuals will be vaccinated with dose one at day 0, or the day that the vaccine campaign begins (this is at 1 year in the example above), with dose two 45 days afterwards, and with dose three 90 days after the first dose. This will correspond to ages 5, 6.5, and 8 months for the primary series. The booster will be administered 12 months after dose three, at 20 months of age in the example above. +```{r} +rtssepiparams$rtss_doses +``` + + #### Plot clinical incidence -```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} +```{r, fig.width = 7, fig.height = 5, fig.align = "center"} plot_inci() ``` #### Plot prevalence -```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} +```{r, fig.width = 7, fig.height = 5, fig.align = "center"} plot_prev() ``` #### Plot doses -```{r, fig.width = 6, fig.height = 4, fig.align = 'center', message=FALSE} +```{r, fig.width = 7, fig.height = 5, fig.align = "center", message=FALSE} plot_doses() ``` - -### RTS,S seasonal boosters +We see a much more gradual decrease in clinical incidence following EPI implementation compared to the mass vaccination strategy. + +### RTS,S EPI with seasonal boosters In a seasonal setting, we can set booster timesteps relative to the start of the year instead of relative to the last dose. This allows us to consider seasonal dynamics and implement booster doses right before the start of the high transmission season to maximize impact. @@ -282,7 +291,7 @@ rtssepiseasonalparams <- set_rtss_epi( min_wait = 6 * month, # When seasonal_boosters = TRUE, this is the minimum time between an individual receiving the final dose and the first booster. age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. boosters = peak - month * 3.5 , # Because seasonal_boosters = TRUE, the timestep here is relative to the start of the year. Here, we will give a booster at 3.5 months prior to peak transmission. - booster_coverage = c(.7), # 70% of the vaccinated population is boosted. + booster_coverage = 0.95, # 95% of the vaccinated population is boosted. seasonal_boosters = TRUE ) @@ -291,24 +300,24 @@ output <- run_simulation(sim_length * 2, rtssepiseasonalparams) #### Plot clinical incidence -```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} -plot_inci(type = 'seasonal') +```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +plot_inci(type = "seasonal") ``` #### Plot prevalence -```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} -plot_prev(type = 'seasonal') +```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +plot_prev(type = "seasonal") ``` #### Plot doses -```{r, fig.width = 6, fig.height = 4, fig.align = 'center', message=FALSE} +```{r, fig.width = 7, fig.height = 5, fig.align = "center", message=FALSE} plot_doses() ``` ### RTS,S dosing -You can try different dosing schedules using the `pev_doses` parameter. Here we administer dose 1 at 5 months, dose 2 30 days after dose 1, and dose 3 60 days after dose 1. We also administer two booster doses 12 and 24 months following dose 3. As before, it is a good idea to visualise the timing of the vaccination strategy to ensure that you have implemented it as intended. +You can try different dosing schedules using the `pev_doses` parameter. Here we administer dose one at 5 months, dose two 30 days after dose one, and dose three 60 days after dose one. We also administer two booster doses 12 and 24 months following dose three. As before, it is a good idea to visualise the timing of the vaccination strategy to ensure that you have implemented it as intended. ```{r} rtssepiparams2 <- set_rtss_epi( @@ -328,18 +337,18 @@ output <- run_simulation(sim_length * 2, rtssepiparams2) #### Plot clinical incidence -```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} +```{r, fig.width = 7, fig.height = 5, fig.align = "center"} plot_inci() ``` #### Plot prevalence -```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} +```{r, fig.width = 7, fig.height = 5, fig.align = "center"} plot_prev() ``` #### Plot doses -```{r, fig.width = 6, fig.height = 4, fig.align = 'center', message=FALSE} +```{r, fig.width = 7, fig.height = 5, fig.align = "center", message=FALSE} output$month <- ceiling(output$timestep / month) doses <- output[,c(2:6,39)] doses <- aggregate(cbind(doses[1:5]), @@ -348,12 +357,12 @@ doses <- aggregate(cbind(doses[1:5]), doses <- as.matrix(t(doses[,-1])) barplot(doses, xlab = "Month", - ylab = 'Number of doses', + ylab = "Number of doses", col = cols[1:6],space = 0, beside = FALSE, xaxs = "i", yaxs = "i") -grid(lty = 2, col = 'grey80', lwd = 1) +grid(lty = 2, col = "grey80", lwd = 1) axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") -legend('topleft', box.lty = 0, legend = c('Dose 1','Dose 2','Dose 3','Booster 1', 'Booster 2'), +legend("topright", box.lty = 0, legend = c("Dose 1","Dose 2","Dose 3","Booster 1", "Booster 2"), col = cols[1:6], lty = rep(1, 4), lwd = 2.5,bg="transparent") ``` @@ -374,11 +383,11 @@ output <- run_simulation(sim_length, tbvparams) #### Plot clinical incidence -```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} +```{r, fig.width = 7, fig.height = 5, fig.align = "center"} plot_inci() ``` #### Plot prevalence -```{r, fig.width = 6, fig.height = 4 fig.align = 'center'} +```{r, fig.width = 7, fig.height = 5, fig.align = "center"} plot_prev() ``` From 3a5af92caabb358ca9ab6ff20f26c066ca3a08fa Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 10 Mar 2023 12:18:25 +0000 Subject: [PATCH 064/164] Edits from pete/hillary's comments; added incidence plot, cleaned up " vs. ', etc --- vignettes/Variation.Rmd | 116 +++++++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 48 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index e965ee31..bc683fca 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -1,5 +1,5 @@ --- -title: "Variation" +title: "Stochastic Variation" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Variation} @@ -11,7 +11,7 @@ vignette: > library(malariasimulation) ``` -`malariasimulation` is a stochastic, individual-based model and, as such, simulations run with identical parameterisations will generate non-identical, sometimes highly variable, outputs. To illustrate this, we will compare the prevalence of malaria over a year in simulations with a small and a larger population, where a smaller population is more likely to have wide variations between simulation runs. +`malariasimulation` is a stochastic, individual-based model and, as such, simulations run with identical parameterisations will generate non-identical, sometimes highly variable, outputs. To illustrate this, we will compare the prevalence and incidence of malaria over a year in simulations with a small and a larger population, where a smaller population and the incidence measure are both more likely to have wide variations between simulation runs. ### Plotting functions First, we will create a few plotting functions to visualise outputs. @@ -19,65 +19,86 @@ First, we will create a few plotting functions to visualise outputs. cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") -plot_n_detect <- function(output, ylab=TRUE){ - if (ylab==TRUE) { - ylab = "Cases detected in children aged 2-10 years" - } else {ylab=''} - plot(x = output$timestep, y = output$n_detect_730_3650, - type = 'l', col = cols[3], - xlab = 'Time (days)', ylab = ylab, +plot_prev <- function(output, ylab = TRUE){ + if (ylab == TRUE) { + ylab = "Prevalence in children aged 2-10 years" + } else {ylab = ""} + plot(x = output$timestep, y = output$n_detect_730_3650 / output$n_730_3650, + type = "l", col = cols[3], ylim = c(0, 1), + xlab = "Time (days)", ylab = ylab, lwd = 2, xaxs = "i", yaxs = "i", bty = "l") - grid(lty = 2, col = 'grey80', lwd = 1) + grid(lty = 2, col = "grey80", lwd = 1) +} + +plot_inci <- function(output, ylab = TRUE){ + if (ylab == TRUE) { + ylab = "Incidence in children aged 0-5 years" + } else {ylab = ""} + plot(x = output$timestep, y = output$n_inc_clinical_0_1825 / output$n_0_1825, + type = "l", col = cols[5], ylim = c(0, 0.1), + xlab = "Time (days)", ylab = ylab, lwd = 2, + xaxs = "i", yaxs = "i", bty = "l") + grid(lty = 2, col = "grey80", lwd = 1) } ``` -## Parameterisation -First, we will use the `get_parameters()` function to generate a list of parameters, accepting the default values, for two different population sizes. Then we will update the parameters to match equilibrium parameters and to achieve the initial EIR using `set_equilibrium()` +## Parameterisation +First, we will use the `get_parameters()` function to generate a list of parameters, accepting the default values, for two different population sizes and use the `set_equilibrium()` function to initialise the model at a given entomological inoculation rate (EIR). The only parameter which changes between the two parameter sets is the argument for `human_population`. ```{r} # A small population -simparams <- get_parameters(list( - human_population = 100, +simparams_small <- get_parameters(list( + human_population = 1000, + clinical_incidence_rendering_min_ages = 0, + clinical_incidence_rendering_max_ages = 5 * 365, individual_mosquitoes = FALSE )) -simparams <- set_equilibrium(simparams, init_EIR = 20) +simparams_small <- set_equilibrium(parameters = simparams_small, init_EIR = 50) # A larger population -simparams <- get_parameters(list( +simparams_big <- get_parameters(list( human_population = 10000, + clinical_incidence_rendering_min_ages = 0, + clinical_incidence_rendering_max_ages = 5 * 365, individual_mosquitoes = FALSE )) -simparams <- set_equilibrium(simparams, init_EIR = 20) +simparams_big <- set_equilibrium(parameters = simparams_big, init_EIR = 50) ``` ## Simulations -The `n_detect_730_3650` output below shows the total number of individuals in the age group rendered (here, 730-3650 timesteps or 2-10 years) who have microscopy-detectable malaria. Notice that the output is smoother at a higher population. +The `n_detect_730_3650` output below shows the total number of individuals in the age group rendered (here, 730-3650 timesteps or 2-10 years) who have microscopy-detectable malaria. Notice that the output is smoother at a higher population. -```{r, fig.align='center',fig.height=4, fig.width=10} +Some outcomes will be more sensitive than others to stochastic variation. In the plots below, prevalence is smoother than incidence even at the same population. + +```{r, fig.align="center",fig.height=6, fig.width=8} # A small population -output_small_pop <- run_simulation(365, simparams) +output_small_pop <- run_simulation(timesteps = 365, parameters = simparams_small) # A larger population -output_big_pop <- run_simulation(365, simparams) +output_big_pop <- run_simulation(timesteps = 365, parameters = simparams_big) # Plotting -par(mfrow = c(1,2)) -plot_n_detect(output_small_pop); title('n_detect at n = 100') -plot_n_detect(output_big_pop, ylab = FALSE); title('n_detect at n = 10,000') +par(mfrow = c(2,2)) +plot_prev(output_small_pop); title("Prevalence at n = 1,000") +plot_inci(output_small_pop); title("Incidence at n = 1,000") +plot_prev(output_big_pop, ylab = FALSE); title("Prevalence at n = 10,000") +plot_inci(output_big_pop); title("Incidence at n = 10,000") ``` -## Estimating variation +## Estimating stochastic variation -We can estimate the variation in the number of detectable cases by repeating the simulation several times with the function `run_simulation_with_repetitions()`, then plotting the IQR and 95% confidence intervals. Running multiple simulations is particularly important for simulations of a small population size, due to the disproportionate impact of stochasticity in small populations. +One way to estimate the variation in prevalence is by repeating the simulation several times with the function `run_simulation_with_repetitions()`, then plotting the IQR and 95% confidence intervals. Running multiple simulations is particularly important for simulations of a small population size, due to the disproportionate impact of stochasticity in small populations. -```{r, fig.align='center',fig.height=4, fig.width=10} +__However, it is important to note that while running a simulation with repetitions is an option that we illustrate in this example, for the majority of use cases, it is much preferable to increase population size to minimise stochastic variation or to use parameter draws, while also using a large enough population, to estimate uncertainty (see the Parameter Draws vignette for more information). The required population size might depend on the outcome of interest. For example, a larger population size would be needed if measuring the impact of an intervention given only to children, versus an intervention given to the entire population. Additionally, as demonstrated above, some outcomes will be more sensitive than others to stochastic variation.__ + +```{r, fig.align="center",fig.height=4, fig.width=10} outputs <- run_simulation_with_repetitions( - timesteps = 365, # We will run each simulation for 365 timesteps. - repetitions = 10, # The simulation will be run 10 times - overrides = simparams, # using the parameter list with the larger population that we created earlier. + timesteps = 365, # Each repetition will be run for 365 days. + repetitions = 10, # The simulation will be run 10 times. + overrides = simparams_big, # Using the parameter list with the larger population that we created earlier. parallel = TRUE # The runs will be done in parallel. ) @@ -91,8 +112,8 @@ output <- aggregate( lowq = unname(quantile(x, probs = .25)), highq = unname(quantile(x, probs = .75)), mean = mean(x), - lowci = mean(x) + 1.96*sd(x), - highci = mean(x) - 1.96*sd(x) + lowci = mean(x) + 1.96 * sd(x), + highci = mean(x) - 1.96 * sd(x) ) } ) @@ -100,32 +121,31 @@ output <- aggregate( output <- data.frame(cbind(timestep = output$Group.1, output$x)) # Plot the IQR and 95% CI -par(mfrow = c(1,2)) +par(mfrow = c(1, 2)) xx <- c(output$timestep, rev(output$timestep)) yy <- c(output$lowq, rev(output$highq)) plot(x = output$timestep, y = output$median, - type = 'n', xlim = c(-1,365),ylim = c(1400,1700), - xlab = 'Time (days)', ylab = "Cases detected in children aged 2-10 years", + type = "n", xlim = c(-1, 365), ylim = c(1400, 1700), + xlab = "Time (days)", ylab = "Cases detected in children aged 2-10 years", xaxs = "i", yaxs = "i", bty = "l") polygon(xx, yy, - col = 'grey90', border= 'grey95') + col = "grey90", border= "grey95") lines(x = output$timestep, y = output$median, col = cols[3], lwd = 2) -grid(lty = 2, col = 'grey80', lwd = 1) -title('IQR spread') -legend('bottomleft', legend = c('Median','IQR Spread'), col = c(cols[3],'grey90'), - lwd = 5, xpd = TRUE, horiz = TRUE, cex = 1, seg.len=1, bty = 'n') +grid(lty = 2, col = "grey80", lwd = 1) +title("IQR spread") +legend("bottomleft", legend = c("Median","IQR Spread"), col = c(cols[3], "grey90"), + lwd = 5, xpd = TRUE, horiz = TRUE, cex = 1, seg.len = 1, bty = "n") xx <- c(output$timestep, rev(output$timestep)) yy <- c(output$lowci, rev(output$highci)) plot(x = output$timestep, y = output$mean, - type = 'n', xlim = c(-1,365),ylim = c(1400,1700), - xlab = 'Time (days)', ylab = "", + type = "n", xlim = c(-1, 365), ylim = c(1400, 1700), + xlab = "Time (days)", ylab = "", xaxs = "i", yaxs = "i", bty = "l") -polygon(xx, yy, - col = 'grey90', border= 'grey95') +polygon(xx, yy, col = "grey90", border= "grey95") lines(x = output$timestep, y = output$mean, col = cols[3], lwd = 2) -grid(lty = 2, col = 'grey80', lwd = 1) -title('95% Confidence interval') -legend('bottomleft', inset = 0, legend = c('Mean','95% CI'), col = c(cols[3],'grey90'), - lwd = 5, xpd = TRUE, horiz = TRUE, cex = 1, seg.len=1, bty = 'n') +grid(lty = 2, col = "grey80", lwd = 1) +title("95% Confidence interval") +legend("bottomleft", inset = 0, legend = c("Mean", "95% CI"), col = c(cols[3], "grey90"), + lwd = 5, xpd = TRUE, horiz = TRUE, cex = 1, seg.len = 1, bty = "n") ``` From fd42b123884bf984bea6cb54c72b41d6c1350196 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 10 Mar 2023 12:20:11 +0000 Subject: [PATCH 065/164] Removed Lydia's section - she will make new vignette --- vignettes/Variation.Rmd | 53 +---------------------------------------- 1 file changed, 1 insertion(+), 52 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index 4eba72c5..a1ae13c7 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -148,55 +148,4 @@ grid(lty = 2, col = "grey80", lwd = 1) title("95% Confidence interval") legend("bottomleft", inset = 0, legend = c("Mean", "95% CI"), col = c(cols[3], "grey90"), lwd = 5, xpd = TRUE, horiz = TRUE, cex = 1, seg.len = 1, bty = "n") -``` - - - -## Estimating variation in parameters - -Default parameters for the malariasimulation model were obtained from the joint posterior of MCMC fitting. - -```{r plot parasite prevalence with default model parameters} - -simparams <- get_parameters(list( - human_population = 100, - individual_mosquitoes = FALSE -)) - -# obtain 50 random draws from the model parameter posterior distribution - -# Default (mdedian) model parameters -sim <- run_simulation(timesteps= 1000, simparams) - -# plot the default median parameter -plot(sim$timestep, sim$n_detect_730_3650 / sim$n_730_3650, t = "l", ylim = c(0, 1), ylab = "PfPr", xlab = "Time in days") - -``` - -If needed, we can estimate the variation in model parameters using the draws from this joint posterior using `set_parameter_draw`. This function will override the default model parameters with a sample from one of 1000 draws from the joint posterior. - -Keep in mind that `set_parameter_draw` must be called prior to `set_equilibrium`, as the model must be calibrated to new model parameters. - -```{r run simulation on different samples of the joint posterior distribution} - -# Default (mdedian) model parameters -sim <- run_simulation(timesteps= 1000, simparams) - -# plot the default median parameter -plot(sim$timestep, sim$n_detect_730_3650 / sim$n_730_3650, t = "l", ylim = c(0, 1), ylab = "PfPr", xlab = "Time in days") - -cols<- rainbow(50) -for (i in 1:50){ - -message(paste0('obtaining parameter draw ', i)) -param_draw<- simparams |> - set_parameter_draw(sample(1:1000, 1)) |> - set_equilibrium(init_EIR= 5) - -sim<- run_simulation(timesteps= 1000, param_draw) - -lines(sim$timestep, sim$n_detect_730_3650 / sim$n_730_3650, col = cols[i]) - -} - -``` +``` \ No newline at end of file From 2b057d097b7ebe0c5bf2da8d91d311b7e1d06d02 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 10 Mar 2023 13:25:40 +0000 Subject: [PATCH 066/164] changed last plots to plot prevalence / fixed y axes --- vignettes/Variation.Rmd | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index a1ae13c7..716ab97c 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -94,7 +94,7 @@ One way to estimate the variation in prevalence is by repeating the simulation s __However, it is important to note that while running a simulation with repetitions is an option that we illustrate in this example, for the majority of use cases, it is much preferable to increase population size to minimise stochastic variation or to use parameter draws, while also using a large enough population, to estimate uncertainty (see the Parameter Draws vignette for more information). The required population size might depend on the outcome of interest. For example, a larger population size would be needed if measuring the impact of an intervention given only to children, versus an intervention given to the entire population. Additionally, as demonstrated above, some outcomes will be more sensitive than others to stochastic variation.__ -```{r, fig.align="center",fig.height=4, fig.width=10} +```{r, fig.align="center",fig.height=5, fig.width=10} outputs <- run_simulation_with_repetitions( timesteps = 365, # Each repetition will be run for 365 days. repetitions = 10, # The simulation will be run 10 times. @@ -104,7 +104,7 @@ outputs <- run_simulation_with_repetitions( # Calculate IQR and 95% confidence intervals for each of the repetitions output <- aggregate( - outputs$n_detect_730_3650, + outputs$n_detect_730_3650 / outputs$n_730_3650, by = list(outputs$timestep), FUN = function(x) { c( @@ -125,8 +125,8 @@ par(mfrow = c(1, 2)) xx <- c(output$timestep, rev(output$timestep)) yy <- c(output$lowq, rev(output$highq)) plot(x = output$timestep, y = output$median, - type = "n", xlim = c(-1, 365), ylim = c(1400, 1700), - xlab = "Time (days)", ylab = "Cases detected in children aged 2-10 years", + type = "n", xlim = c(-1, 365), ylim = c(0.75, 0.85), + xlab = "Time (days)", ylab = "Prevalence in children aged 2-10 years", xaxs = "i", yaxs = "i", bty = "l") polygon(xx, yy, col = "grey90", border= "grey95") @@ -139,7 +139,7 @@ legend("bottomleft", legend = c("Median","IQR Spread"), col = c(cols[3], "grey90 xx <- c(output$timestep, rev(output$timestep)) yy <- c(output$lowci, rev(output$highci)) plot(x = output$timestep, y = output$mean, - type = "n", xlim = c(-1, 365), ylim = c(1400, 1700), + type = "n", xlim = c(-1, 365), ylim = c(0.75, 0.85), xlab = "Time (days)", ylab = "", xaxs = "i", yaxs = "i", bty = "l") polygon(xx, yy, col = "grey90", border= "grey95") From d8503756058a7e6926a4a5ac158ce40ab59218ce Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Fri, 17 Mar 2023 09:36:34 +0000 Subject: [PATCH 067/164] Finished Draft - ready for pull request --- vignettes/Model.Rmd | 20 +++++++------------- vignettes/Model_mos.svg | 24 ++++++++++++------------ 2 files changed, 19 insertions(+), 25 deletions(-) diff --git a/vignettes/Model.Rmd b/vignettes/Model.Rmd index c3fee2c0..96e65d95 100644 --- a/vignettes/Model.Rmd +++ b/vignettes/Model.Rmd @@ -62,11 +62,12 @@ To maintain a constant population size during simulations, the birth rate of new The functions governing mosquito biological processes and dynamics are spread out between the following files: -1. [src/mosquito_ode.cpp]() ***Can't find a file with this name*** -2. [src/mosquito_emergence.cpp]() ***Can't find a file with this name***'' -3. [R/mosquito_biology.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/mosquito_biology.R) +1. [src/adult_mosquito_eqs.cpp](https://github.com/mrc-ide/malariasimulation/blob/master/src/adult_mosquito.cpp) +2. [src/aquatic_mosquito_eqs.cpp](https://github.com/mrc-ide/malariasimulation/blob/master/src/aquatic_mosquito.cpp) +3. [src/mosquito_biology.cpp](https://github.com/mrc-ide/malariasimulation/blob/master/src/mosquito_biology.cpp) +4. [R/mosquito_biology.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/mosquito_biology.R) - + ### States @@ -135,7 +136,7 @@ The `run_simulation()` function then simulates malaria transmission dynamics and - `infectivity`: human infectiousness - `EIR_All`: the entomological inoculation rate - `FOIM`: the force of mosquito infection -- `mu_All`: adult mosquito death rate ***Why is this important? isn't this just mu_m? I suppose it's density dependent. Look into this in more detail*** +- `mu_All`: adult mosquito death rate - `n_bitten`: the number of infectious bites - `n_infections`: the number human infections - `natural_deaths`: deaths from old age @@ -158,16 +159,12 @@ head(test_sim, n = 3) Additional output details can be found in the `run_simulation()` documentation. -In your bit in bold about mu_All - I wonder if it relates to all mosquito species across all adult female mosquito infectious states? I guess the same applies to the L/L/P/Sm/Pm/Im_All_count values too? - ### Additional outputs **Age stratified** results for **incidence**, **clinical incidence** and **severe case incidence** may also be included in the output if desired and must be specified in the parameter list (see `get_parameters()` for more details and [Demography](https://mrc-ide.github.io/malariasimulation/articles/Demography.html) for an example). These inputs will add extra columns to the output for the number of infections (**`n_`**) and the sum of probabilities of infection (**`p_`**) for the relevant total, clinical or severe incidences for each specified age group. Where **treatments** are specified, `n_treated` will report the number that have received treatment. Where **bed nets** are distributed, `net_usage` specifies the number sleeping under a bednet. -***`rate_D_A`, `rate_A_U`, `rate_U_S`*** These are found in the help page for `run_simulation()` How are these output??? - ### Output visualisation These outputs can then be visualised, such as the population changes in states. Another key output is the prevalence of detectable infections between the ages of 2-10 (*Pf*PR~2-10~), which can be obtained by dividing `n_detect_730_3650` by `n_730_3650`. @@ -200,7 +197,6 @@ states_plot() # Calculate Pf PR 2-10 test_sim$PfPR2_10 <- test_sim$n_detect_730_3650/test_sim$n_730_3650 - # Plot Pf PR 2-10 plot(x = test_sim$timestep, y = test_sim$PfPR2_10, type = "l", col = cols[7], ylim = c(0,1), @@ -369,9 +365,7 @@ The remaining vignettes describe how to adjust sets of parameters through a numb 7. [Matching PfPR2-10 to EIR](https://mrc-ide.github.io/malariasimulation/articles/EIRprevmatch.html) - - ***Need to work out what this is doing and why*** - - malariaEquilibrium::human equilibrium (Is there anything else from this package that would be useful to describe?). Also, links to package information??? - - set an equilibrium \ (set_equilibrium) + - Using *Pf*PR~2-10~ data to estimate EIR 8. [Metapopulation Modelling](https://mrc-ide.github.io/malariasimulation/articles/Metapopulation.html) diff --git a/vignettes/Model_mos.svg b/vignettes/Model_mos.svg index 35bf4d6e..44ecd256 100644 --- a/vignettes/Model_mos.svg +++ b/vignettes/Model_mos.svg @@ -10,7 +10,7 @@ viewBox="0 0 254.9846 174" version="1.1" id="svg184" - sodipodi:docname="Model_mos_figure_complete.svg" + sodipodi:docname="Model_mos.svg" inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" @@ -73,7 +73,7 @@ inkscape:window-x="74" inkscape:window-y="27" inkscape:window-maximized="1" - inkscape:current-layer="svg184" /> + inkscape:current-layer="edge11" /> µ r r + style="stroke-width:0.75" /> Date: Fri, 17 Mar 2023 09:40:24 +0000 Subject: [PATCH 068/164] Ready for pull request --- vignettes/Treatment.Rmd | 2 -- 1 file changed, 2 deletions(-) diff --git a/vignettes/Treatment.Rmd b/vignettes/Treatment.Rmd index f40250fd..3cedd401 100644 --- a/vignettes/Treatment.Rmd +++ b/vignettes/Treatment.Rmd @@ -68,7 +68,6 @@ For more details, please see: Okell, L., Cairns, M., Griffin, J. *et al.* Contrasting benefits of different artemisinin combination therapies as first-line malaria treatments using model-based cost-effectiveness analysis. *Nat Commun* **5**, 5606 (2014). . - ## Functions Drug parameters can be incorporated into a complete parameter set: @@ -90,7 +89,6 @@ Intro_params <- set_clinical_treatment(parameters = Intro_parms, Multiple drugs can be modelled simultaneously, with treatment coverage that can be specified for each drug. This function must be used for each drug included (e.g., if there are two drugs, `set_clinical_treatment()` must be called twice). - # Example ## Parameterisation and simulation From 929896bbca5c6b8686132e18c28d1727466805c0 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 17 Mar 2023 13:23:48 +0000 Subject: [PATCH 069/164] Edits from Pete. Making difference in pfpr plot with species modification more obvious, small clarifications --- vignettes/SetSpecies.Rmd | 37 ++++++++++++++------------ vignettes/VectorControl_Bednets.Rmd | 40 ++++++++++++----------------- vignettes/VectorControl_IRS.Rmd | 6 ++--- 3 files changed, 40 insertions(+), 43 deletions(-) diff --git a/vignettes/SetSpecies.Rmd b/vignettes/SetSpecies.Rmd index a4696773..648e859f 100644 --- a/vignettes/SetSpecies.Rmd +++ b/vignettes/SetSpecies.Rmd @@ -1,5 +1,5 @@ --- -title: "Setting mosquito species" +title: "Mosquito species" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Vector Control: IRS} @@ -16,7 +16,6 @@ knitr::opts_chunk$set( ```{r setup} library(malariasimulation) -library(malariaEquilibrium) ``` ### Plotting functions @@ -35,14 +34,14 @@ plot_prev <- function() { col = cols[5], lwd = 2.5) abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = "black") grid(lty = 2, col = "grey80", lwd = 1) - legend("bottomleft", box.lty = 0, legend = c("Spraying", "Prevalence for all mosquitoes scenario","Prevalence for species-specific scenario"), + legend("bottomleft", box.lty = 0, legend = c("Spraying", "Prevalence for species-specific scenario", "Prevalence for default all mosquitoes scenario"), col = c("black", cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) } ``` -As alluded to in the IRS and Bednet vignettes, it is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. IRS and bednets could be expected to have different impacts depending on the proportion of each mosquito species because of variations in indoor resting, insecticide resistance, and proportion of bites on humans versus animals by species. If you have specified more than 1 species, then the arguments for `set_spraying()` and/or `set_bednets()` must be populated with values for each species at each timestep that the intervention is implemented. +As alluded to in the IRS and Bed net vignettes, it is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. IRS and bed nets could be expected to have different impacts depending on the proportion of each mosquito species because of variations in indoor resting, insecticide resistance, and proportion of bites on humans versus animals by species. If you have specified more than 1 species, then the arguments for `set_spraying()` and/or `set_bednets()` must be populated with values for each species at each timestep that the intervention is implemented. -There are preset parameters for *An. gambiae*, *An. arabiensis*, and *An. funestus* that can be set by the helper functions `gamb_params()`, `arab_params()`, and `fun_params()`, respectively. The default values for each species in these helper functions are from 10.1073/pnas.1820646116. The parameters are: +There are preset parameters for *An. gambiae*, *An. arabiensis*, and *An. funestus* that can be set by the helper functions `gamb_params()`, `arab_params()`, and `fun_params()`, respectively. The default values for each species in these helper functions are from [Sherrard-Smith et al., 2019](https://doi.org/10.1073/pnas.1820646116). The parameters are: * `blood_meal_rates`: the blood meal rates for each species * `foraging_time`: time spent taking blood meals @@ -115,16 +114,21 @@ legend("topright", box.lty = 0, legend = c("Spraying", "All mosquitoes"), col = ``` -## IRS with multiple mosquito species +## IRS with different mosquito species -We will run the same model with IRS as above, but this time with 3 species of mosquitoes. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. Each column corresponds to a species of mosquito, and each row corresponds to the timestep when a round of IRS occurred. Here, we are assuming the same values for each species at each IRS round for simplicity, but the matrix could be edited to have different values by species or over time by adding new columns or rows. +We will run the same model with IRS as above, but this time with 3 species of mosquitoes: *An. arabiensis*, *An. gambiae*, and an example mosquito species similar to *An. funestus*, but with a lower propensity to bite indoors. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. Each column corresponds to a species of mosquito, and each row corresponds to the timestep when a round of IRS occurred. Here, we are assuming the same values for each species at each IRS round for simplicity, but the matrix could be edited to have different values by species or over time by adding new columns or rows. ```{r, fig.align="center", fig.height=4, fig.width=6} -## Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae +# Create an example mosquito species with a low value for `phi_indoors` +example_mosquito_params <- fun_params +example_mosquito_params$phi_indoors <- 0.2 +example_mosquito_params$species <- 'example' + +## Set 3 species of mosquitoes, 10% An. arabiensis, 10% An. gambia, and 80% an example species with a lower propensity for indoor biting simparams <- set_species( simparams, - species = list(arab_params, fun_params, gamb_params), - proportions = c(0.25, 0.25, 0.5) + species = list(arab_params, gamb_params, example_mosquito_params), + proportions = c(0.2, 0.2, 0.6) ) peak <- peak_season_offset(simparams) @@ -154,22 +158,23 @@ simparams$species_proportions ### Plot prevalence +In the plot below, we can see that IRS is much more effective when the default mosquito species are used compared to the scenario where we added an example mosquito species with a lower propensity for biting indoors. In this case, IRS will not be as effective because a larger proportion of bites take place outside of the home. ```{r,fig.align="center", fig.height=5, fig.width=7} plot_prev() ``` ### Plot adult female infectious mosquitoes by species over time ```{r,fig.align="center", fig.height=5, fig.width=7} -plot(x = output$timestep, y = output$Im_gamb_count, - type = "l", col = cols[5], lwd = 2.5, +plot(x = output$timestep, y = output$Im_example_count, + type = "l", col = cols[5], lwd = 2.5, ylim = c(0, 600), xlab = "Time (days)", ylab = "N mosquitoes", - xaxs = "i", yaxs = "i", bty = "l") + xaxs = "i", yaxs = "i", bty = "l") abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = "black") -lines(x = output$timestep, y = output$Im_fun_count, - col = cols[6], lwd = 2.5) lines(x = output$timestep, y = output$Im_arab_count, + col = cols[6], lwd = 2.5) +lines(x = output$timestep, y = output$Im_gamb_count, col = cols[3], lwd = 2.5) grid(lty = 2, col = "grey80", lwd = 1) -legend("topright", box.lty = 0, legend = c("Spraying", expression(italic("An. gambiae")), expression(italic("An. funestus")),expression(italic("An. arabiensis"))), col = c("black", cols[5], cols[6], cols[3]), lty = c(2, 1, 1, 1), lwd = 2.5) +legend("topright", box.lty = 0, legend = c("Spraying", "Example mosquito species", expression(italic("An. arabiensis")), expression(italic("An. gambiae"))), col = c("black", cols[5], cols[6], cols[3]), lty = c(2, 1, 1, 1), lwd = 2.5) ``` diff --git a/vignettes/VectorControl_Bednets.Rmd b/vignettes/VectorControl_Bednets.Rmd index e5fcee67..2bd07992 100644 --- a/vignettes/VectorControl_Bednets.Rmd +++ b/vignettes/VectorControl_Bednets.Rmd @@ -1,8 +1,8 @@ --- -title: "Vector Control: Bednets" +title: "Vector Control: Bed nets" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Vector Control: Bednets} + %\VignetteIndexEntry{Vector Control: Bed nets} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -16,10 +16,9 @@ knitr::opts_chunk$set( ```{r setup} library(malariasimulation) -library(malariaEquilibrium) ``` -Long-lasting insecticide-treated bednets is a highly effective intervention to prevent malaria. The effects of insecticidal bednet distribution campaigns can be simulated using `malariasimulation`. The model provides the user with the flexibility to specify parameters that describe the net distribution campaign (e.g. timing, coverage, and target population) and the bednets distributed (e.g. efficacy, longevity). We will illustrate this through an example with two bednet distributions, once per year. +Long-lasting insecticide-treated bed nets is a highly effective intervention to prevent malaria. The effects of insecticidal bed net distribution campaigns can be simulated using `malariasimulation`. The model provides the user with the flexibility to specify parameters that describe the net distribution campaign (e.g. timing, coverage, and target population) and the bed nets distributed (e.g. efficacy, longevity). We will illustrate this through an example with two bed net distributions, once per year. ### Plotting functions We can create a few plotting functions to visualise the output. @@ -37,7 +36,7 @@ plot_prev <- function() { col = cols[5], lwd = 2.5) abline(v = bednetstimesteps, col = "black", lty = 2, lwd = 2.5) grid(lty = 2, col = "grey80", lwd = 1) - legend("bottomleft", box.lty = 0, legend = c("Bednets","Prevalence for bednet scenario","Prevalence for control scenario"), + legend("bottomleft", box.lty = 0, legend = c("Bed nets","Prevalence for bed net scenario","Prevalence for control scenario"), col = c("black", cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) } ``` @@ -56,20 +55,13 @@ simparams <- get_parameters( list(human_population = human_population) ) -# Setting 3 species of mosquitoes, 25% An. arabiensis, 25% An. funestus, and 50% An. gambiae -simparams <- set_species( - simparams, - species = list(arab_params, fun_params, gamb_params), - proportions = c(0.25, 0.25, 0.5) -) - simparams <- set_equilibrium(parameters = simparams, init_EIR = starting_EIR) output_control <- run_simulation(timesteps = sim_length, parameters = simparams) ``` #### A note on mosquito species -It is also possible to use the `set_species()` function to account for 3 different mosquito species in the simulation. In this case, the matrices would need to have additional column corresponding to each mosquito species. For example, if we specified that there were 3 species of mosquitoes in the model and nets were distributed at two timesteps, then the matrices would have 2 rows and 3 columns. If you are not already familiar with the `set_species()` function, see the Set Species vignette. +It is also possible to use the `set_species()` function to account for 3 different mosquito species in the simulation. In this case, the matrices would need to have additional column corresponding to each mosquito species. For example, if we specified that there were 3 species of mosquitoes in the model and nets were distributed at two timesteps, then the matrices would have 2 rows and 3 columns. If you are not already familiar with the `set_species()` function, see the Mosquito Species vignette. The default setting is to model all mosquito species together. ```{r} @@ -79,21 +71,21 @@ simparams$species_proportions ## Simulation -Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bednets once a year for two years, the first round to 80% of the population and the second round to 50% of the population. It is possible to change the characteristics of the bednets for each distribution timestep if different types of bednets are distributed that have different insecticides, different levels of insecticide resistance, etc. This can be done by modifying the matrices for `dn0`, `rn`, `rnm`, and `gamman`. Because there are 3 mosquito species specified in `set_species()` above and two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 3 columns and 2 rows. +Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bed nets once a year for two years, the first round to 80% of the population and the second round to 50% of the population. It is possible to change the characteristics of the bed nets for each distribution timestep if different types of bed nets are distributed that have different insecticides, different levels of insecticide resistance, etc. This can be done by modifying the matrices for `dn0`, `rn`, `rnm`, and `gamman`. Because there are 3 mosquito species specified in `set_species()` above and two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 3 columns and 2 rows. ```{r, fig.align="center", fig.height=4, fig.width=6} -bednetstimesteps <- c(1, 2) * year # The bednets will be distributed at the end of the first and the second year. +bednetstimesteps <- c(1, 2) * year # The bed nets will be distributed at the end of the first and the second year. bednetparams <- set_bednets( simparams, timesteps = bednetstimesteps, - coverages = c(.8, .5), # The first round is distributed to 80% of the population and the second round to 50%. + coverages = c(.5, .8), # The first round is distributed to 80% of the population and the second round to 50%. retention = 5 * year, # Nets are kept on average 5 years dn0 = matrix(c(.533, .533), nrow = 2, ncol = 3), # Matrix of death probabilities for each mosquito species over time rn = matrix(c(.56, .56), nrow = 2, ncol = 3), # Matrix of repelling probabilities for each mosquito species over time rnm = matrix(c(.24, .24), nrow = 2, ncol = 3), # Matrix of minimum repelling probabilities for each mosquito species over time - gamman = rep(2.64 * 365, 2) # Vector of bednet half-lives for each distribution timestep + gamman = rep(2.64 * 365, 2) # Vector of bed net half-lives for each distribution timestep ) output <- run_simulation(timesteps = sim_length, parameters = bednetparams) @@ -104,24 +96,24 @@ output <- run_simulation(timesteps = sim_length, parameters = bednetparams) plot_prev() ``` -## Comparing input coverage and population bednet usage +## Comparing input coverage and population bed net usage -It is important to understand the difference between the input `coverages` argument of `malariasimulation::set_bednets()` and the resulting population bednet usage over time in the model. When we set coverages in the above example to 0.8, we are telling the model to distribute bednets to 80% of the population at year one, and to 50% of the population at year 2. However, the level of average bednet usage is not necessarily equal to 80% or 50%. Between these time points, bednet use will slowly decline over time (in reality this decline stems from things like disuse, holes in nets, lost nets, etc.). +It is important to understand the difference between the input `coverages` argument of `set_bednets()` and the resulting population bed net usage over time in the model. When we set coverages in the above example to 0.8, we are telling the model to distribute bed nets to 80% of the population at year one, and to 50% of the population at year 2. However, the level of average bed net usage is not necessarily equal to 80% or 50%. Between these time points, bed net use will slowly decline over time (in reality this decline stems from things like disuse, holes in nets, lost nets, etc.). -The average population bednet usage will be influenced by: +The average population bed net usage will be influenced by: * The size and frequency of distributions specified in `set_bednets()` * The assumed net retention half life (`gamman`) * Correlations in the recipients of nets between rounds -The output from `malariasimulation::run_simulation()` has a variable `n_use_net` that shows the number of people using bednets at any given timestep. We can visualise the proportion of the population using bednets over time to understand how bednet usage changes. +The output from `malariasimulation::run_simulation()` has a variable `n_use_net` that shows the number of people using bed nets at any given timestep. We can visualise the proportion of the population using bed nets over time to understand how bed net usage changes. ```{r, fig.align="center", fig.height=5, fig.width=7} output$prop_use_net <- output$n_use_net / human_population plot(x = output$timestep, y = output$prop_use_net, type = "l", col = cols[3], lwd = 2.5, ylim = c(0,1), - xlab = "Timestep (days)", ylab = "Proportion of population using bednets", + xlab = "Timestep (days)", ylab = "Proportion of population using bed nets", xaxs = "i", yaxs = "i", bty = "l") grid(lty = 2, col = "grey80", lwd = 1) axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") @@ -129,9 +121,9 @@ axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = " ## Using the `netz` package to estimate coverage inputs needed to achieve target population usage -The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool to help set up bednets in `malariasimulation`. `malariasimulation` takes as input the proportion of the population who were distributed a bednet at specific time points, but available data for a specific region or country do not always have this information. `netz` allows for simple conversions between bednet metrics like crop, access, distribution, and usage. +The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool to help set up bed nets in `malariasimulation`. `malariasimulation` takes as input the proportion of the population who were distributed a bed net at specific time points, but available data for a specific region or country do not always have this information. `netz` has functionality to estimate modelled population usage over time in the simulation for a given set of input coverages. It can also help to fit the input coverages to usage data. See the vignettes from the `netz` package that explain these concepts more comprehensively: -* [This vignette](https://mrc-ide.github.io/netz/articles/population_usage.html) demonstrates how to estimate population bednet usage from an input distribution. +* [This vignette](https://mrc-ide.github.io/netz/articles/population_usage.html) demonstrates how to estimate population bed net usage from an input distribution. diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index 1f25185b..07fcb4cf 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -19,7 +19,7 @@ library(malariasimulation) library(malariaEquilibrium) ``` -Indoor Residual Spraying (IRS) involves periodically treating indoor walls with insecticides to eliminate adult female mosquitoes that rest indoors. `malariasimulation` can be used to investigate the effect of malaria control strategies that deploy IRS. Users can set IRS in the model using the set_spraying() function to parameterize timing of spraying campaigns and coverage levels. +Indoor Residual Spraying (IRS) involves periodically treating indoor walls with insecticides to eliminate adult female mosquitoes that rest indoors. `malariasimulation` can be used to investigate the effect of malaria control strategies that deploy IRS. Users can set IRS in the model using the `set_spraying()` function to parameterise the time and coverage of spraying campaigns. ### Plotting functions We will create a few plotting functions to visualise the output. @@ -83,7 +83,7 @@ simparams$species Then we can run the simulations for a variety of IRS strategies. In the example below, there are two rounds of IRS at 80% coverage, each 3 months prior to peak rainfall for that year. The function `peak_season_offset()` outputs a timestep when peak rainfall will be observed based on the seasonality profile we set above. Notice that the matrices specified for the parameters for `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` have two rows, one for each timestep where IRS is implemented, and a number of columns corresponding to mosquito species. In this example, we only have 1 column because the species is set to "All" as we saw above. -The structure for IRS model is documented in the supplementary information from 10.1038/s41467-018-07357-w. +The structure for IRS model is documented in the supplementary information from [Sherrard-Smith et al., 2018](https://doi.org/10.1038/s41467-018-07357-w). ```{r, fig.align="center", fig.height=4, fig.width=6} peak <- peak_season_offset(simparams) @@ -93,7 +93,7 @@ sprayingtimesteps <- c(1, 2) * year + peak - 3 * month # A round of IRS is imple sprayingparams <- set_spraying( simparams, timesteps = sprayingtimesteps, - coverages = rep(.8, 2), # # Each round covers 80% of the population + coverages = c(0.3, 0.8), # # The first round covers 30% of the population and the second covers 80%. ls_theta = matrix(2.025, nrow=length(sprayingtimesteps), ncol=1), # Matrix of mortality parameters; nrows=length(timesteps), ncols=length(species) ls_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=1), # Matrix of mortality parameters per round of IRS and per species ks_theta = matrix(-2.222, nrow=length(sprayingtimesteps), ncol=1), # Matrix of feeding success parameters per round of IRS and per species From 8d25d622e772592dd8adda9463e0729f3fda7f7d Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Tue, 21 Mar 2023 18:27:30 +0000 Subject: [PATCH 070/164] Fixing plots and removing error --- vignettes/Vaccines.Rmd | 50 +++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 688521ae..06bf00a7 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -54,8 +54,8 @@ plot_inci <- function(type = "not seasonal"){ curve_valuescomp <- loess(clinical_incidence ~ time_year, data = comparison, span = 0.3, method = "loess") lines(comparison$time_year, predict(curve_valuescomp), col = cols[6], lwd = 3) - legend("topright", box.lty = 0, legend = c("Start of vaccination", "Incidence for vaccine scenario", "Smoothed incidence for \nno intervention scenario"), - col = c("black", cols[2], cols[5]), lty = c(2,1,1), lwd = 2.5) + legend("topright", box.lty = 0, legend = c("Start of vaccination", "Unsmoothed incidence for vaccine scenario", "Smoothed incidence for vaccine scenario", "Smoothed incidence for no\nintervention scenario"), + col = c("black", cols[2], cols[5], cols[6]), lty = c(2, 1, 1, 1), lwd = 2.5) } # Plot parasite prevalence @@ -85,7 +85,7 @@ plot_prev <- function(type = "not seasonal"){ # Plot dose timing plot_doses <- function(){ output$month <- ceiling(output$timestep / month) - doses <- output[,c(2:5, 38)] + doses <- output[, c(grep("n_rtss" , names(output)), grep("month", names(output)))] doses <- aggregate(cbind(doses[1:4]), by = list(doses$month), FUN = sum) @@ -131,7 +131,7 @@ Then we can run the simulation for a variety of vaccination strategies. ## Mass RTS,S -First, we will model a single round of RTS,S vaccine given in a mass vaccination strategy where those within a given age range will be vaccinated to a specified coverage level and during a short window of time. In this example, individuals aged between 5 and 17 months are vaccinated with a primary series (3 doses) followed by a single booster 12 months after the initial vaccination. The age groups to be vaccinated as well as timing of all vaccinations can be modified within the `set_mass_rtss()` function. +First, we will model a single round of RTS,S vaccine given in a mass vaccination strategy where those within a given age range will be vaccinated to a specified coverage level and during a short window of time. In this example, individuals aged between 5 months and 50 years are vaccinated with a primary series (3 doses) followed by a single booster 12 months after the initial vaccination. The age groups to be vaccinated as well as timing of all vaccinations can be modified within the `set_mass_rtss()` function. The model assumes that protection starts following the 3rd dose of the primary series. We specify that the intervention should use the RTS,S vaccine through the `profile` and `booster_profile` inputs. @@ -142,7 +142,7 @@ rtssparams <- set_mass_rtss( coverages = 1, # The vaccine is given to 100% of the population between the specified ages. min_wait = 0, # The minimum acceptable time since the last vaccination is 0 because in our case we are only implementing one round of vaccination. min_ages = 5 * month, # The minimum age for the target population to be vaccinated. - max_ages = 5 * year, # The maximum age for the target population to be vaccinated. + max_ages = 50 * year, # The maximum age for the target population to be vaccinated. boosters = 12 * month, # The booster is given at 12 months after the primary series. booster_coverage = 0.95 # Coverage of the booster dose is 95%. ) @@ -152,12 +152,12 @@ output <- run_simulation(timesteps = sim_length, parameters = rtssparams) #### Plot clinical incidence -```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +```{r, fig.width = 8, fig.height = 5, fig.align = "center"} plot_inci() ``` #### Plot prevalence -```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +```{r, fig.width = 8, fig.height = 5, fig.align = "center"} plot_prev() ``` @@ -165,7 +165,7 @@ plot_prev() You can look at the distribution of doses using the `n_rtss_mass_dose_*` or `n_rtss_epi_dose_*` outputs. It is always a good idea to check the timing of vaccine doses to ensure that it is specified as intended. -```{r, fig.width = 7, fig.height = 5, fig.align = "center", message=FALSE} +```{r, fig.width = 8, fig.height = 5, fig.align = "center", message=FALSE} plot_doses() ``` @@ -206,7 +206,7 @@ seasmass_simparams <- set_mass_rtss( timesteps = round(year + (peak - month * 3.5), 0),# The vaccination will begin 3.5 months prior to the peak seasonality in the second year. coverages = 1, # 100% of the population between min_ages and max_ages is vaccinated. min_ages = 5 * month, # The minimum age for the target population to be vaccinated. - max_ages = 5 * year, # The maximum age for the target population to be vaccinated. + max_ages = 15 * year, # The maximum age for the target population to be vaccinated. min_wait = 0, # There is no minimum wait between the last vaccination. boosters = round(c(12 * month + 2 * month)), # The booster is given 14 months after the first dose. booster_coverage = 1) # 100% of the vaccinated population is boosted. @@ -216,18 +216,18 @@ output <- run_simulation(sim_length * 2, seasmass_simparams) #### Plot clinical incidence -```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +```{r, fig.width = 8, fig.height = 5, fig.align = "center"} plot_inci(type = "seasonal") ``` #### Plot prevalence -```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +```{r, fig.width = 8, fig.height = 5, fig.align = "center"} plot_prev(type = "seasonal") ``` #### Plot doses -```{r, fig.width = 7, fig.height = 5, fig.align = "center", message=FALSE} +```{r, fig.width = 8, fig.height = 5, fig.align = "center", message=FALSE} plot_doses() ``` @@ -259,18 +259,18 @@ rtssepiparams$rtss_doses #### Plot clinical incidence -```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +```{r, fig.width = 8, fig.height = 5, fig.align = "center"} plot_inci() ``` #### Plot prevalence -```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +```{r, fig.width = 8, fig.height = 5, fig.align = "center"} plot_prev() ``` #### Plot doses -```{r, fig.width = 7, fig.height = 5, fig.align = "center", message=FALSE} +```{r, fig.width = 8, fig.height = 5, fig.align = "center", message=FALSE} plot_doses() ``` We see a much more gradual decrease in clinical incidence following EPI implementation compared to the mass vaccination strategy. @@ -300,18 +300,18 @@ output <- run_simulation(sim_length * 2, rtssepiseasonalparams) #### Plot clinical incidence -```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +```{r, fig.width = 8, fig.height = 5, fig.align = "center"} plot_inci(type = "seasonal") ``` #### Plot prevalence -```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +```{r, fig.width = 8, fig.height = 5, fig.align = "center"} plot_prev(type = "seasonal") ``` #### Plot doses -```{r, fig.width = 7, fig.height = 5, fig.align = "center", message=FALSE} +```{r, fig.width = 8, fig.height = 5, fig.align = "center", message=FALSE} plot_doses() ``` @@ -337,18 +337,18 @@ output <- run_simulation(sim_length * 2, rtssepiparams2) #### Plot clinical incidence -```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +```{r, fig.width = 8, fig.height = 5, fig.align = "center"} plot_inci() ``` #### Plot prevalence -```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +```{r, fig.width = 8, fig.height = 5, fig.align = "center"} plot_prev() ``` #### Plot doses -```{r, fig.width = 7, fig.height = 5, fig.align = "center", message=FALSE} +```{r, fig.width = 8, fig.height = 5, fig.align = "center", message=FALSE} output$month <- ceiling(output$timestep / month) doses <- output[,c(2:6,39)] doses <- aggregate(cbind(doses[1:5]), @@ -362,8 +362,8 @@ barplot(doses, xlab = "Month", beside = FALSE, xaxs = "i", yaxs = "i") grid(lty = 2, col = "grey80", lwd = 1) axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") -legend("topright", box.lty = 0, legend = c("Dose 1","Dose 2","Dose 3","Booster 1", "Booster 2"), - col = cols[1:6], lty = rep(1, 4), lwd = 2.5,bg="transparent") +legend("topleft", box.lty = 0, legend = c("Dose 1","Dose 2","Dose 3","Booster 1", "Booster 2"), + col = cols[1:6], lty = rep(1, 4), lwd = 2.5, bg="transparent") ``` ## TBV @@ -383,11 +383,11 @@ output <- run_simulation(sim_length, tbvparams) #### Plot clinical incidence -```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +```{r, fig.width = 8, fig.height = 5, fig.align = "center"} plot_inci() ``` #### Plot prevalence -```{r, fig.width = 7, fig.height = 5, fig.align = "center"} +```{r, fig.width = 8, fig.height = 5, fig.align = "center"} plot_prev() ``` From 1583772744d890964591390ffe1de8b9d074e3a2 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Tue, 28 Mar 2023 18:08:39 +0100 Subject: [PATCH 071/164] remove Estimating stochastic variation, add stochastic elimination --- vignettes/Variation.Rmd | 119 +++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 70 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index 716ab97c..75b94f64 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -9,9 +9,10 @@ vignette: > ```{r setup} library(malariasimulation) +set.seed(123) ``` -`malariasimulation` is a stochastic, individual-based model and, as such, simulations run with identical parameterisations will generate non-identical, sometimes highly variable, outputs. To illustrate this, we will compare the prevalence and incidence of malaria over a year in simulations with a small and a larger population, where a smaller population and the incidence measure are both more likely to have wide variations between simulation runs. +`malariasimulation` is a stochastic, individual-based model and, as such, simulations run with identical parameterisations will generate non-identical, sometimes highly variable, outputs. To illustrate this, we will compare the prevalence and incidence of malaria over a year in simulations with a small and a larger population. The simulation with a smaller population compared to the larger population, and the incidence measure compared to the prevalence measure will have larger variation between simulation runs. ### Plotting functions First, we will create a few plotting functions to visualise outputs. @@ -19,23 +20,23 @@ First, we will create a few plotting functions to visualise outputs. cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") -plot_prev <- function(output, ylab = TRUE){ +plot_prev <- function(output, ylab = TRUE, ylim = c(0,1)){ if (ylab == TRUE) { ylab = "Prevalence in children aged 2-10 years" } else {ylab = ""} plot(x = output$timestep, y = output$n_detect_730_3650 / output$n_730_3650, - type = "l", col = cols[3], ylim = c(0, 1), + type = "l", col = cols[3], ylim = ylim, xlab = "Time (days)", ylab = ylab, lwd = 2, xaxs = "i", yaxs = "i", bty = "l") grid(lty = 2, col = "grey80", lwd = 1) } -plot_inci <- function(output, ylab = TRUE){ +plot_inci <- function(output, ylab = TRUE, ylim){ if (ylab == TRUE) { - ylab = "Incidence in children aged 0-5 years" + ylab = "Incidence per 1000 children aged 0-5 years" } else {ylab = ""} - plot(x = output$timestep, y = output$n_inc_clinical_0_1825 / output$n_0_1825, - type = "l", col = cols[5], ylim = c(0, 0.1), + plot(x = output$timestep, y = output$n_inc_clinical_0_1825 / output$n_0_1825 * 1000, + type = "l", col = cols[5], ylim = ylim, xlab = "Time (days)", ylab = ylab, lwd = 2, xaxs = "i", yaxs = "i", bty = "l") grid(lty = 2, col = "grey80", lwd = 1) @@ -82,70 +83,48 @@ output_big_pop <- run_simulation(timesteps = 365, parameters = simparams_big) # Plotting par(mfrow = c(2,2)) -plot_prev(output_small_pop); title("Prevalence at n = 1,000") -plot_inci(output_small_pop); title("Incidence at n = 1,000") -plot_prev(output_big_pop, ylab = FALSE); title("Prevalence at n = 10,000") -plot_inci(output_big_pop); title("Incidence at n = 10,000") +plot_prev(output_small_pop, ylim = c(0.6, 0.8)); title(expression(paste(italic(Pf),"PR"[2-10], " at n = 1,000"))) +plot_inci(output_small_pop, ylim = c(0, 25)); title("Incidence per 1000 children at n = 1,000") +plot_prev(output_big_pop, ylim = c(0.6, 0.8)); title(expression(paste(italic(Pf),"PR"[2-10], " at n = 10,000"))) +plot_inci(output_big_pop, ylim = c(0, 25)); title("Incidence per 1000 children at n = 10,000") ``` -## Estimating stochastic variation - -One way to estimate the variation in prevalence is by repeating the simulation several times with the function `run_simulation_with_repetitions()`, then plotting the IQR and 95% confidence intervals. Running multiple simulations is particularly important for simulations of a small population size, due to the disproportionate impact of stochasticity in small populations. - -__However, it is important to note that while running a simulation with repetitions is an option that we illustrate in this example, for the majority of use cases, it is much preferable to increase population size to minimise stochastic variation or to use parameter draws, while also using a large enough population, to estimate uncertainty (see the Parameter Draws vignette for more information). The required population size might depend on the outcome of interest. For example, a larger population size would be needed if measuring the impact of an intervention given only to children, versus an intervention given to the entire population. Additionally, as demonstrated above, some outcomes will be more sensitive than others to stochastic variation.__ - -```{r, fig.align="center",fig.height=5, fig.width=10} -outputs <- run_simulation_with_repetitions( - timesteps = 365, # Each repetition will be run for 365 days. - repetitions = 10, # The simulation will be run 10 times. - overrides = simparams_big, # Using the parameter list with the larger population that we created earlier. - parallel = TRUE # The runs will be done in parallel. -) - -# Calculate IQR and 95% confidence intervals for each of the repetitions -output <- aggregate( - outputs$n_detect_730_3650 / outputs$n_730_3650, - by = list(outputs$timestep), - FUN = function(x) { - c( - median = median(x), - lowq = unname(quantile(x, probs = .25)), - highq = unname(quantile(x, probs = .75)), - mean = mean(x), - lowci = mean(x) + 1.96 * sd(x), - highci = mean(x) - 1.96 * sd(x) - ) - } -) - -output <- data.frame(cbind(timestep = output$Group.1, output$x)) - -# Plot the IQR and 95% CI +## Stochastic elimination +With stochastic models, random elimination of malaria in a small population with low transmisison may happen. In the example below, we run two simulations: one with a very small population, and one with a larger population. There is stochastic fade out (elimination) in the smaller population, while the larger population has stable transmission over time. For this reason, it is important to run models with large-enough populations to avoid stochastic elimination or trends that are not realistic. +```{r} +# A small population +simparams_small <- get_parameters(list( + human_population = 50, + clinical_incidence_rendering_min_ages = 0, + clinical_incidence_rendering_max_ages = 5 * 365, + individual_mosquitoes = FALSE +)) + +simparams_small <- set_equilibrium(parameters = simparams_small, init_EIR = 1) + +# A larger population +simparams_big <- get_parameters(list( + human_population = 1000, + clinical_incidence_rendering_min_ages = 0, + clinical_incidence_rendering_max_ages = 5 * 365, + individual_mosquitoes = FALSE +)) + +simparams_big <- set_equilibrium(parameters = simparams_big, init_EIR = 1) +``` + +## Simulations + +```{r, fig.align="center",fig.height=6, fig.width=8} +set.seed(555) +# A small population +output_small_pop <- run_simulation(timesteps = 365 * 2, parameters = simparams_small) + +# A larger population +output_big_pop <- run_simulation(timesteps = 365 * 2, parameters = simparams_big) + +# Plotting par(mfrow = c(1, 2)) -xx <- c(output$timestep, rev(output$timestep)) -yy <- c(output$lowq, rev(output$highq)) -plot(x = output$timestep, y = output$median, - type = "n", xlim = c(-1, 365), ylim = c(0.75, 0.85), - xlab = "Time (days)", ylab = "Prevalence in children aged 2-10 years", - xaxs = "i", yaxs = "i", bty = "l") -polygon(xx, yy, - col = "grey90", border= "grey95") -lines(x = output$timestep, y = output$median, col = cols[3], lwd = 2) -grid(lty = 2, col = "grey80", lwd = 1) -title("IQR spread") -legend("bottomleft", legend = c("Median","IQR Spread"), col = c(cols[3], "grey90"), - lwd = 5, xpd = TRUE, horiz = TRUE, cex = 1, seg.len = 1, bty = "n") - -xx <- c(output$timestep, rev(output$timestep)) -yy <- c(output$lowci, rev(output$highci)) -plot(x = output$timestep, y = output$mean, - type = "n", xlim = c(-1, 365), ylim = c(0.75, 0.85), - xlab = "Time (days)", ylab = "", - xaxs = "i", yaxs = "i", bty = "l") -polygon(xx, yy, col = "grey90", border= "grey95") -lines(x = output$timestep, y = output$mean, col = cols[3], lwd = 2) -grid(lty = 2, col = "grey80", lwd = 1) -title("95% Confidence interval") -legend("bottomleft", inset = 0, legend = c("Mean", "95% CI"), col = c(cols[3], "grey90"), - lwd = 5, xpd = TRUE, horiz = TRUE, cex = 1, seg.len = 1, bty = "n") +plot_prev(output_small_pop, ylim = c(0, 1)); title(expression(paste(italic(Pf),"PR"[2-10], " at n = 50"))) +plot_prev(output_big_pop, ylab = FALSE, ylim = c(0, 1)); title(expression(paste(italic(Pf),"PR"[2-10], " at n = 1,000"))) ``` \ No newline at end of file From b1c98e38d6d6d010002d068e5c360f1f41fcfefa Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Wed, 29 Mar 2023 11:17:31 +0100 Subject: [PATCH 072/164] get_parameters now on a separate line, example simplified, weibull decay added to text --- vignettes/Treatment.Rmd | 134 +++++++++++----------------------------- 1 file changed, 36 insertions(+), 98 deletions(-) diff --git a/vignettes/Treatment.Rmd b/vignettes/Treatment.Rmd index 3cedd401..3643257f 100644 --- a/vignettes/Treatment.Rmd +++ b/vignettes/Treatment.Rmd @@ -16,7 +16,6 @@ knitr::opts_chunk$set( ```{r setup} library(malariasimulation) -library(malariaEquilibrium) ``` # Introduction @@ -31,7 +30,7 @@ The malariasimulation package contains in-built parameters sets for three anti-m While all these drugs can be used to treat malaria, DHA-PQP and SP-AQ remain in the body for some time following treatment, making them good candidates for chemoprevention in mass drug administrations (see [Mass Drug Administration](https://mrc-ide.github.io/malariasimulation/articles/MDA.html). Any of these drugs can be included in the parameter list using the `set_drugs()` function (see [drugs_parameters.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/drug_parameters.R) for full parameter details). -Each drug parameter set is a vector of length four, that represent the drug efficacy, the infectiousness following treatment relative to an untreated infection, and parameters that determine the protection against reinfection ($P$): shape ($w$) and scale ($\lambda$) using an exponential decrease as follows: +Each drug parameter set is a vector of length four, that represent the drug efficacy, the infectiousness following treatment relative to an untreated infection, and parameters that determine the protection against reinfection ($P$): shape ($w$) and scale ($\lambda$). The decay of protection against infection follows a weibull distribution as follows: $$P = e^{{(-t/\lambda)}^w}$$ @@ -70,35 +69,25 @@ Okell, L., Cairns, M., Griffin, J. *et al.* Contrasting benefits of different ar ## Functions -Drug parameters can be incorporated into a complete parameter set: - -```{r} -Intro_parms <- set_drugs(parameters = get_parameters(), drugs = AL_params) -``` +Drug parameters can be incorporated into a complete parameter set using the `set_drugs` function which takes the full parameter set and a list of drug parameter sets. A treatment regimen for each drug can then be described using the `set_clinical_treatment()` function which takes the drug index, a vector of timesteps at which a change in coverage occurs (where the initial coverage is 0 until the first timestep specified) and a vector of coverages for the drug that correspond with the timestep changes, as well as the complete parameter set. -In this example, the AL coverage would be at 0% from the start until day 9, 20% during days 10-14, 50% during days 15-19 and 100% from day 20 until the end of the simulation. - -```{r} -Intro_params <- set_clinical_treatment(parameters = Intro_parms, - drug = 1, - timesteps = c(10,15,20), - coverages = c(0.2,0.5,1)) -``` +Multiple drugs can be modelled simultaneously, with treatment coverage that can be specified for each drug. This function must be used for each drug included (e.g., if there are two drugs, `set_clinical_treatment()` must be called twice to specify the treatment plan). -Multiple drugs can be modelled simultaneously, with treatment coverage that can be specified for each drug. This function must be used for each drug included (e.g., if there are two drugs, `set_clinical_treatment()` must be called twice). # Example -## Parameterisation and simulation +We will run a simulation for one year using AL and DHA-PQP treatment regimens. We begin our AL treatment on day 100 at 40% coverage and provide this treatment for 200 days before the treatment stops. DHA-PQP treatment also has 40% coverage, but begins on day 200 and lasts for 100 days, also ending on day 300. Note that the sum of treatment coverages cannot exceed 100%. -We will run several simulations that vary the coverages of drug programs for AL and DHA-PQ that begin on day one. For simplicity, the coverages will match for each drug. These simulations will last for two years for a population of one thousand individuals. In each simulation, the function `set_equilibrium` must also be used to generate equilibrium values for the human and mosquito populations. +Prior to the simulation, the function `set_equilibrium` must also be used to generate equilibrium values for the human and mosquito populations. + +## Parameterisation and simulation ```{r} # Daily simulation timesteps for two years year <- 365 -sim_length <- 2 * year +sim_length <- 1 * year # With a population size of 1000 human_population <- 1000 @@ -107,96 +96,45 @@ human_population <- 1000 simparams <- get_parameters(overrides = list(human_population = human_population)) # Update parameter set with chosen drug-specific parameters (AL and DHA/PQP) -simparams <- set_drugs(simparams, list(AL_params, DHA_PQP_params)) +drug_params <- set_drugs(simparams, list(AL_params, DHA_PQP_params)) # Choose initial EIR to 10 starting_EIR <- 10 -# And choose coverage values between 0 and 50% -covs <- seq(0, 0.5, by = 0.1) - -# Create an empty list for results -outputs <- list() - -# Iterate over coverage values -for (cov in covs) { - - ## Set treatment programs for each drug (1 and 2), starting on day 1: - # Set treatment program for AL - simparams <- set_clinical_treatment( - parameters = simparams, - drug = 1, # First drug specified (AL) - timesteps = 1, # Treatment will begin on day 1 - coverages = cov) # Coverage as found in covs vector - - # Set treatment program for DHA-PQP - simparams <- set_clinical_treatment( - parameters = simparams, - drug = 2, # Second drug specified (DHA-PQP) - timesteps = 1, # Treatment will begin on day 1 - coverages = cov) # Coverage as found in covs vector - - # Use set_equilibrium to update the parameter set for a given initial EIR - simparams <- set_equilibrium(simparams, starting_EIR) - - # Run simulation: - output <- run_simulation(sim_length, simparams) +# Set treatment program for AL (drug index = 1) +treatment_params <- set_clinical_treatment( + parameters = drug_params, + drug = 1, + timesteps = c(100,300), # Treatment coverage changes on day 100 and day 200 + coverages = c(0.4,0)) # The initial treatment coverage (0%) is the default and does not need to be set + +# Set treatment program for DHA-PQP (drug index = 2) +treatment_params <- set_clinical_treatment( + parameters = treatment_params, + drug = 2, + timesteps = c(200,300), + coverages = c(0.3,0)) # Coverage as found in covs vector + +# Use set_equilibrium to update the parameter set for a given initial EIR +treatment_params <- set_equilibrium(treatment_params, starting_EIR) + +# Run simulation: +output <- run_simulation(sim_length, treatment_params) - # remove the first year (which can be considered a warmup) - output <- output[output$timestep > year,] - - # Add output to outputs list - outputs[[length(outputs) + 1]] <- output -} ``` ## Visualisation -Following simulation of malaria transmission under 0-50% drug treatment coverages, we can now visualise the effect of coverage on *Pf*PR~2-10~ through time using the `n_detect_730_3650` and `n_730_3650` outputs. +Following simulation of malaria transmission under this treatment regimen, we can now visualise the effect of the regimen on *Pf*PR~2-10~ through time using the `n_detect_730_3650` and `n_730_3650` outputs. ```{r, fig.align = 'center', fig.height = 5, fig.width = 7} -# Join listed results into a single data frame -df <- do.call('rbind', lapply(seq_along(outputs), function(i) { - - # Select variables of interest - df <- outputs[[i]][c('timestep', 'n_detect_730_3650', 'n_730_3650')] - - # Create a new variable for Pf Prevalence - df$PfPR2_10 <- df$n_detect_730_3650/df$n_730_3650 - - # Attach coverage value - df$coverage <- covs[[i]] - - # return results - df -})) +# Create a new variable for Pf Prevalence (Age 2-10) +output$PfPR2_10 <- output$n_detect_730_3650/output$n_730_3650 -# Create plot function -Treatment_plot_function <- function(df){ - - # Set figure margins and sections - par(fig=c(0,0.9,0,1), cex = 0.8, mai = c(0.8,0.8,0.3,0.1)) +# Plot results +plot(x = output$timestep, y = output$PfPR2_10, type = "l", + xlab = "Days", ylab = expression(paste(italic(Pf),"PR"[2-10])), col = cols[1]) - # Create initial plot with first set of results - with(df[df$coverage==unique(df$coverage)[1],], - expr = plot(x = timestep, y = PfPR2_10, type = "l", - xlab = "Days", ylab = expression(paste(italic(Pf),"PR"[2-10])), - ylim = c(min(df$PfPR2_10),max(df$PfPR2_10)), col = cols[1])) - - # Add grid lines - grid() - - # Add remaining results - invisible(sapply(2:length(unique(df$coverage)), function(x){ - with(df[df$coverage==unique(df$coverage)[x],], - expr = points(x = timestep, y = PfPR2_10, type = "l",col = cols[x])) -})) - - # Add figure legend - par(fig=c(0.9,1,0,1), cex = 0.8, new = T, xpd = T, mai = c(0,0,0,0)) - legend("right", legend = paste0(100*unique(df$coverage),"%"), - col = cols, bty = "n", lty = 1, title = "Coverage") -} - -Treatment_plot_function(df) +# Add grid lines +grid() ``` From 77b371c12daf1d247542e2dea053de7b0094b725 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 30 Mar 2023 14:49:53 +0100 Subject: [PATCH 073/164] Removing unclear sentence --- vignettes/Variation.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index 75b94f64..c0385587 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -12,7 +12,7 @@ library(malariasimulation) set.seed(123) ``` -`malariasimulation` is a stochastic, individual-based model and, as such, simulations run with identical parameterisations will generate non-identical, sometimes highly variable, outputs. To illustrate this, we will compare the prevalence and incidence of malaria over a year in simulations with a small and a larger population. The simulation with a smaller population compared to the larger population, and the incidence measure compared to the prevalence measure will have larger variation between simulation runs. +`malariasimulation` is a stochastic, individual-based model and, as such, simulations run with identical parameterisations will generate non-identical, sometimes highly variable, outputs. To illustrate this, we will compare the prevalence and incidence of malaria over a year in simulations with a small and a larger population. ### Plotting functions First, we will create a few plotting functions to visualise outputs. From 4cde9e78ca9c6ee3e43320ae0a6f538ee9f2f156 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 30 Mar 2023 15:48:54 +0100 Subject: [PATCH 074/164] responding to first few comments --- vignettes/SetSpecies.Rmd | 14 ++++++++------ vignettes/VectorControl_Bednets.Rmd | 18 ++++++++---------- vignettes/VectorControl_IRS.Rmd | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/vignettes/SetSpecies.Rmd b/vignettes/SetSpecies.Rmd index 648e859f..331c6c50 100644 --- a/vignettes/SetSpecies.Rmd +++ b/vignettes/SetSpecies.Rmd @@ -2,7 +2,7 @@ title: "Mosquito species" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Vector Control: IRS} + %\VignetteIndexEntry{Mosquito species} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -53,7 +53,9 @@ We will demonstrate how to specify different mosquito species and how this could ## IRS with default mosquito settings -Use the `get_parameters()` function to generate a list of parameters, accepting most of the default values, but modifying seasonality values to model a seasonal setting. We will model IRS with the default mosquito settings, which is to model all mosquito species together. Then, we use the `set_equilibrium()` function to to initialise the model at a given entomological inoculation rate (EIR). +Use the `get_parameters()` function to generate a list of parameters, accepting most of the default values, but modifying seasonality values to model a seasonal setting. We will model IRS with the default mosquito settings, which is to model all mosquito species together. Then, we use the `set_equilibrium()` function to to initialise the model at a given entomological inoculation rate (EIR). + +Use the `set_spraying()` function to set an IRS intervention. This function takes as arguments the parameter list, timesteps of spraying, coverage of IRS in the population and a series of paremters related to the insecticide used in the IRS. `ls` is the proportion of mosquitoes dying following entering a hut, which is dependent on the parameters `ls_theta`, is the initial efficacy, and `ls_gamma`, how it changes over time. `ks` is the proportion of mosquitoes successfully feeding, which is dependent on `ks_theta`, the initial impact of the insecticide in IRS, and `ks_gamma`, how the impact changes over time. Finally, `ms` is the proportion of mosquitoes being deterred away from a sprayed hut, depending on `ms_theta`, the initial impact of IRS, and `ms_gamma`, the change in impact over time. See a more comprehensive explanation in the Supplementary Information of [Sherrard-Smith et al., 2018](https://doi.org/10.1038/s41467-018-07357-w). ```{r} year <- 365 @@ -81,7 +83,7 @@ simparams <- set_spraying( simparams, timesteps = sprayingtimesteps, coverages = rep(.8, 2), # # Each round covers 80% of the population - # nrows=length(timesteps), ncols=length(species) + # nrows=length(timesteps), ncols=length(species) ls_theta = matrix(2.025, nrow=length(sprayingtimesteps), ncol=1), # Matrix of mortality parameters per round of IRS and per species ls_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=1), # Matrix of mortality parameters per round of IRS and per species ks_theta = matrix(-2.222, nrow=length(sprayingtimesteps), ncol=1), # Matrix of feeding success parameters per round of IRS and per species @@ -92,7 +94,7 @@ simparams <- set_spraying( simparams <- set_equilibrium(simparams, starting_EIR) -# Running simulation with no IRS +# Running simulation with IRS output_all <- run_simulation(timesteps = sim_length, parameters = simparams) ``` @@ -116,7 +118,7 @@ legend("topright", box.lty = 0, legend = c("Spraying", "All mosquitoes"), col = ## IRS with different mosquito species -We will run the same model with IRS as above, but this time with 3 species of mosquitoes: *An. arabiensis*, *An. gambiae*, and an example mosquito species similar to *An. funestus*, but with a lower propensity to bite indoors. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. Each column corresponds to a species of mosquito, and each row corresponds to the timestep when a round of IRS occurred. Here, we are assuming the same values for each species at each IRS round for simplicity, but the matrix could be edited to have different values by species or over time by adding new columns or rows. +We will run the same model with IRS as above, but this time with 3 species of mosquitoes: *An. arabiensis*, *An. gambiae*, and an example mosquito species similar to *An. funestus*, but with a lower propensity to bite indoors. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. Each column corresponds to a species of mosquito, and each row corresponds to the timestep when a round of IRS occurred. Here, we are assuming the same values for each species at each IRS round for simplicity, but the matrix could be edited to have different values by species or over time by editing columns or rows. ```{r, fig.align="center", fig.height=4, fig.width=6} # Create an example mosquito species with a low value for `phi_indoors` @@ -128,7 +130,7 @@ example_mosquito_params$species <- 'example' simparams <- set_species( simparams, species = list(arab_params, gamb_params, example_mosquito_params), - proportions = c(0.2, 0.2, 0.6) + proportions = c(1/3, 1/3, 1/3) ) peak <- peak_season_offset(simparams) diff --git a/vignettes/VectorControl_Bednets.Rmd b/vignettes/VectorControl_Bednets.Rmd index 2bd07992..d516c2cc 100644 --- a/vignettes/VectorControl_Bednets.Rmd +++ b/vignettes/VectorControl_Bednets.Rmd @@ -18,7 +18,7 @@ knitr::opts_chunk$set( library(malariasimulation) ``` -Long-lasting insecticide-treated bed nets is a highly effective intervention to prevent malaria. The effects of insecticidal bed net distribution campaigns can be simulated using `malariasimulation`. The model provides the user with the flexibility to specify parameters that describe the net distribution campaign (e.g. timing, coverage, and target population) and the bed nets distributed (e.g. efficacy, longevity). We will illustrate this through an example with two bed net distributions, once per year. +Long-lasting insecticide-treated bed nets are a highly effective intervention to prevent malaria. The effects of insecticide-treated bed net distribution campaigns can be simulated using `malariasimulation`. The model provides the user with the flexibility to specify parameters that describe the net distribution campaign (e.g. timing, coverage, and target population) and the bed nets distributed (e.g. efficacy, longevity). We will illustrate this through an example with two bed net distributions, once per year. ### Plotting functions We can create a few plotting functions to visualise the output. @@ -71,7 +71,7 @@ simparams$species_proportions ## Simulation -Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bed nets once a year for two years, the first round to 80% of the population and the second round to 50% of the population. It is possible to change the characteristics of the bed nets for each distribution timestep if different types of bed nets are distributed that have different insecticides, different levels of insecticide resistance, etc. This can be done by modifying the matrices for `dn0`, `rn`, `rnm`, and `gamman`. Because there are 3 mosquito species specified in `set_species()` above and two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 3 columns and 2 rows. +Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bed nets once a year for two years, the first round to 50% of the population and the second round to 80% of the population. It is possible to change the characteristics of the bed nets for each distribution timestep if different types of bed nets are distributed that have different insecticides, different levels of insecticide resistance, etc. This can be done by modifying the matrices for `dn0`, `rn`, `rnm`, and `gamman`. Because we are using the default proportions of mosquito species and there are two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 1 column and 2 rows. ```{r, fig.align="center", fig.height=4, fig.width=6} @@ -80,11 +80,11 @@ bednetstimesteps <- c(1, 2) * year # The bed nets will be distributed at the end bednetparams <- set_bednets( simparams, timesteps = bednetstimesteps, - coverages = c(.5, .8), # The first round is distributed to 80% of the population and the second round to 50%. + coverages = c(.5, .8), # The first round is distributed to 50% of the population and the second round to 80%. retention = 5 * year, # Nets are kept on average 5 years - dn0 = matrix(c(.533, .533), nrow = 2, ncol = 3), # Matrix of death probabilities for each mosquito species over time - rn = matrix(c(.56, .56), nrow = 2, ncol = 3), # Matrix of repelling probabilities for each mosquito species over time - rnm = matrix(c(.24, .24), nrow = 2, ncol = 3), # Matrix of minimum repelling probabilities for each mosquito species over time + dn0 = matrix(c(.533, .533), nrow = 2, ncol = 1), # Matrix of death probabilities for each mosquito species over time + rn = matrix(c(.56, .56), nrow = 2, ncol = 1), # Matrix of repelling probabilities for each mosquito species over time + rnm = matrix(c(.24, .24), nrow = 2, ncol = 1), # Matrix of minimum repelling probabilities for each mosquito species over time gamman = rep(2.64 * 365, 2) # Vector of bed net half-lives for each distribution timestep ) @@ -121,9 +121,7 @@ axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = " ## Using the `netz` package to estimate coverage inputs needed to achieve target population usage -The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool to help set up bed nets in `malariasimulation`. `malariasimulation` takes as input the proportion of the population who were distributed a bed net at specific time points, but available data for a specific region or country do not always have this information. `netz` has functionality to estimate modelled population usage over time in the simulation for a given set of input coverages. It can also help to fit the input coverages to usage data. +The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool to help set up bed nets in `malariasimulation`. `malariasimulation` takes as an input the proportion of the population who were distributed a bed net at specific time points, but net distribution or use data are now always available for a specific region or country. `netz` has functionality to estimate modelled population usage over time in the simulation for a given set of input distributions. It can also help to fit the input coverages to usage data. -See the vignettes from the `netz` package that explain these concepts more comprehensively: - -* [This vignette](https://mrc-ide.github.io/netz/articles/population_usage.html) demonstrates how to estimate population bed net usage from an input distribution. +See [this vignette](https://mrc-ide.github.io/netz/articles/population_usage.html) from the `netz` package that demonstrates how to estimate population bed net usage from an input distribution. diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index 07fcb4cf..4d92c148 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -81,9 +81,9 @@ simparams$species ## Simulation -Then we can run the simulations for a variety of IRS strategies. In the example below, there are two rounds of IRS at 80% coverage, each 3 months prior to peak rainfall for that year. The function `peak_season_offset()` outputs a timestep when peak rainfall will be observed based on the seasonality profile we set above. Notice that the matrices specified for the parameters for `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` have two rows, one for each timestep where IRS is implemented, and a number of columns corresponding to mosquito species. In this example, we only have 1 column because the species is set to "All" as we saw above. +Then we can run the simulations for a variety of IRS strategies. In the example below, there are two rounds of IRS, the first at 30% coverage and the second at 80% coverage, each 3 months prior to peak rainfall for that year. The function `peak_season_offset()` outputs a timestep when peak rainfall will be observed based on the seasonality profile we set above. Notice that the matrices specified for the parameters for `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` have two rows, one for each timestep where IRS is implemented, and a number of columns corresponding to mosquito species. In this example, we only have 1 column because the species is set to "All" as we saw above. -The structure for IRS model is documented in the supplementary information from [Sherrard-Smith et al., 2018](https://doi.org/10.1038/s41467-018-07357-w). +The structure for IRS model is documented in the supplementary information from Table S1.3 in [Sherrard-Smith et al., 2018](https://doi.org/10.1016/S2542-5196(21)00296-5). ```{r, fig.align="center", fig.height=4, fig.width=6} peak <- peak_season_offset(simparams) From dbd23230bf290755bd392dfe78f8e04af0a70cd6 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 30 Mar 2023 15:51:33 +0100 Subject: [PATCH 075/164] last edits --- vignettes/Variation.Rmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index c0385587..0f9c46da 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -72,7 +72,7 @@ simparams_big <- set_equilibrium(parameters = simparams_big, init_EIR = 50) The `n_detect_730_3650` output below shows the total number of individuals in the age group rendered (here, 730-3650 timesteps or 2-10 years) who have microscopy-detectable malaria. Notice that the output is smoother at a higher population. -Some outcomes will be more sensitive than others to stochastic variation. In the plots below, prevalence is smoother than incidence even at the same population. +Some outcomes will be more sensitive than others to stochastic variation even with the same population size. In the plots below, prevalence is smoother than incidence even at the same population. This is because prevalence is a measure of existing infection, while incidence is recording new cases per timestep. ```{r, fig.align="center",fig.height=6, fig.width=8} # A small population @@ -90,7 +90,7 @@ plot_inci(output_big_pop, ylim = c(0, 25)); title("Incidence per 1000 children a ``` ## Stochastic elimination -With stochastic models, random elimination of malaria in a small population with low transmisison may happen. In the example below, we run two simulations: one with a very small population, and one with a larger population. There is stochastic fade out (elimination) in the smaller population, while the larger population has stable transmission over time. For this reason, it is important to run models with large-enough populations to avoid stochastic elimination or trends that are not realistic. +With stochastic models, random elimination of malaria in a small population with low transmisison may happen. In the example below, we run two simulations: one with a very small population, and one with a larger population. There is stochastic fade out (elimination) in the smaller population, while the larger population has stable transmission over time. For this reason, it is important to run models with large-enough populations to avoid stochastic elimination. ```{r} # A small population simparams_small <- get_parameters(list( From 5cde86562ced759b124b1d58416b92c30af8d0e2 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 30 Mar 2023 17:17:36 +0100 Subject: [PATCH 076/164] text edits --- vignettes/SetSpecies.Rmd | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vignettes/SetSpecies.Rmd b/vignettes/SetSpecies.Rmd index 331c6c50..283e1899 100644 --- a/vignettes/SetSpecies.Rmd +++ b/vignettes/SetSpecies.Rmd @@ -39,7 +39,7 @@ plot_prev <- function() { } ``` -As alluded to in the IRS and Bed net vignettes, it is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. IRS and bed nets could be expected to have different impacts depending on the proportion of each mosquito species because of variations in indoor resting, insecticide resistance, and proportion of bites on humans versus animals by species. If you have specified more than 1 species, then the arguments for `set_spraying()` and/or `set_bednets()` must be populated with values for each species at each timestep that the intervention is implemented. +As alluded to in the Model Structure, Vector Control: IRS, and Vector Control: Bed net vignettes, it is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. IRS and bed nets could be expected to have different impacts depending on the proportion of each mosquito species because of variations in indoor resting, insecticide resistance, and proportion of bites on humans versus animals by species. If you have specified more than 1 species, then the arguments for `set_spraying()` and/or `set_bednets()` must be populated with values for each species at each timestep that the intervention is implemented. There are preset parameters for *An. gambiae*, *An. arabiensis*, and *An. funestus* that can be set by the helper functions `gamb_params()`, `arab_params()`, and `fun_params()`, respectively. The default values for each species in these helper functions are from [Sherrard-Smith et al., 2019](https://doi.org/10.1073/pnas.1820646116). The parameters are: @@ -55,7 +55,7 @@ We will demonstrate how to specify different mosquito species and how this could Use the `get_parameters()` function to generate a list of parameters, accepting most of the default values, but modifying seasonality values to model a seasonal setting. We will model IRS with the default mosquito settings, which is to model all mosquito species together. Then, we use the `set_equilibrium()` function to to initialise the model at a given entomological inoculation rate (EIR). -Use the `set_spraying()` function to set an IRS intervention. This function takes as arguments the parameter list, timesteps of spraying, coverage of IRS in the population and a series of paremters related to the insecticide used in the IRS. `ls` is the proportion of mosquitoes dying following entering a hut, which is dependent on the parameters `ls_theta`, is the initial efficacy, and `ls_gamma`, how it changes over time. `ks` is the proportion of mosquitoes successfully feeding, which is dependent on `ks_theta`, the initial impact of the insecticide in IRS, and `ks_gamma`, how the impact changes over time. Finally, `ms` is the proportion of mosquitoes being deterred away from a sprayed hut, depending on `ms_theta`, the initial impact of IRS, and `ms_gamma`, the change in impact over time. See a more comprehensive explanation in the Supplementary Information of [Sherrard-Smith et al., 2018](https://doi.org/10.1038/s41467-018-07357-w). +Use the `set_spraying()` function to set an IRS intervention. This function takes as arguments the parameter list, timesteps of spraying, coverage of IRS in the population and a series of parameters related to the insecticide used in the IRS. The proportion of mosquitoes dying following entering a hut is dependent on the parameters `ls_theta`, the initial efficacy, and `ls_gamma`, how it changes over time. The proportion of mosquitoes successfully feeding is dependent on `ks_theta`, the initial impact of the insecticide in IRS, and `ks_gamma`, how the impact changes over time. Finally, the proportion of mosquitoes being deterred away from a sprayed hut depends on `ms_theta`, the initial impact of IRS, and `ms_gamma`, the change in impact over time. See a more comprehensive explanation in the Supplementary Information of [Sherrard-Smith et al., 2018](https://doi.org/10.1038/s41467-018-07357-w). ```{r} year <- 365 @@ -118,7 +118,7 @@ legend("topright", box.lty = 0, legend = c("Spraying", "All mosquitoes"), col = ## IRS with different mosquito species -We will run the same model with IRS as above, but this time with 3 species of mosquitoes: *An. arabiensis*, *An. gambiae*, and an example mosquito species similar to *An. funestus*, but with a lower propensity to bite indoors. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. Each column corresponds to a species of mosquito, and each row corresponds to the timestep when a round of IRS occurred. Here, we are assuming the same values for each species at each IRS round for simplicity, but the matrix could be edited to have different values by species or over time by editing columns or rows. +We will run the same model with IRS as above, but this time with 3 species of mosquitoes: *An. arabiensis*, *An. gambiae*, and an example mosquito species similar to *An. funestus*, but with a lower propensity to bite indoors. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. See the Vector Control: IRS vignette for more information about setting IRS with different mosquito species. ```{r, fig.align="center", fig.height=4, fig.width=6} # Create an example mosquito species with a low value for `phi_indoors` From d8add829d6a28ebb8158298188038352524f106a Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Fri, 31 Mar 2023 10:14:56 +0100 Subject: [PATCH 077/164] Addressed Hillary's comments --- vignettes/Treatment.Rmd | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/vignettes/Treatment.Rmd b/vignettes/Treatment.Rmd index 3643257f..8791baec 100644 --- a/vignettes/Treatment.Rmd +++ b/vignettes/Treatment.Rmd @@ -22,15 +22,15 @@ library(malariasimulation) This vignette describes how to implement clinical drug treatments in malariasimulation. -The malariasimulation package contains in-built parameters sets for three anti-malarial drugs: +The malariasimulation package contains built-in parameters sets for three anti-malarial drugs: 1. `AL_params`: artemether-lumefantrine (AL) 2. `DHA_PQP_params`: dihydroartemisinin and piperaquine (DHA-PQP) 3. `SP_AQ_params`: sulfadoxine-pyrimethamine and amodiaquine (SP-AQ) -While all these drugs can be used to treat malaria, DHA-PQP and SP-AQ remain in the body for some time following treatment, making them good candidates for chemoprevention in mass drug administrations (see [Mass Drug Administration](https://mrc-ide.github.io/malariasimulation/articles/MDA.html). Any of these drugs can be included in the parameter list using the `set_drugs()` function (see [drugs_parameters.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/drug_parameters.R) for full parameter details). +While all these drugs can be used to treat malaria, DHA-PQP and SP-AQ remain in the body for some time following treatment, making them good candidates for chemoprevention in mass drug administrations (see [Mass Drug Administration](https://mrc-ide.github.io/malariasimulation/articles/MDA.html)). Any of these drugs can be included in the parameter list using the `set_drugs()` function (see [drugs_parameters.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/drug_parameters.R) for full parameter details). -Each drug parameter set is a vector of length four, that represent the drug efficacy, the infectiousness following treatment relative to an untreated infection, and parameters that determine the protection against reinfection ($P$): shape ($w$) and scale ($\lambda$). The decay of protection against infection follows a weibull distribution as follows: +Each drug parameter set is a vector of length four, with parameters that represent the drug efficacy, the infectiousness following treatment relative to an untreated infection, and parameters that determine the protection against reinfection ($P$): shape ($w$) and scale ($\lambda$). The decay of protection against infection follows a weibull distribution as follows: $$P = e^{{(-t/\lambda)}^w}$$ @@ -78,16 +78,16 @@ Multiple drugs can be modelled simultaneously, with treatment coverage that can # Example -We will run a simulation for one year using AL and DHA-PQP treatment regimens. We begin our AL treatment on day 100 at 40% coverage and provide this treatment for 200 days before the treatment stops. DHA-PQP treatment also has 40% coverage, but begins on day 200 and lasts for 100 days, also ending on day 300. Note that the sum of treatment coverages cannot exceed 100%. +We will run a simulation for two years using AL and DHA-PQP treatment regimens. We begin our AL and DHA-PQP treatments on day 300 at 40% and 30% coverage, respectively. We provide these treatments for 300 days before the regimen ends. Note that the sum of treatment coverages cannot exceed 100% at any timestep. -Prior to the simulation, the function `set_equilibrium` must also be used to generate equilibrium values for the human and mosquito populations. +Prior to the simulation, the function `set_equilibrium` can also be used to generate equilibrium values for the human and mosquito populations. ## Parameterisation and simulation ```{r} # Daily simulation timesteps for two years year <- 365 -sim_length <- 1 * year +sim_length <- 2 * year # With a population size of 1000 human_population <- 1000 @@ -105,36 +105,41 @@ starting_EIR <- 10 treatment_params <- set_clinical_treatment( parameters = drug_params, drug = 1, - timesteps = c(100,300), # Treatment coverage changes on day 100 and day 200 + timesteps = c(300,600), # Treatment coverage changes on day 300 and day 600 coverages = c(0.4,0)) # The initial treatment coverage (0%) is the default and does not need to be set # Set treatment program for DHA-PQP (drug index = 2) treatment_params <- set_clinical_treatment( parameters = treatment_params, drug = 2, - timesteps = c(200,300), - coverages = c(0.3,0)) # Coverage as found in covs vector + timesteps = c(300,600), + coverages = c(0.3,0)) # Use set_equilibrium to update the parameter set for a given initial EIR treatment_params <- set_equilibrium(treatment_params, starting_EIR) # Run simulation: output <- run_simulation(sim_length, treatment_params) - + ``` ## Visualisation -Following simulation of malaria transmission under this treatment regimen, we can now visualise the effect of the regimen on *Pf*PR~2-10~ through time using the `n_detect_730_3650` and `n_730_3650` outputs. +Following simulation of malaria transmission under this treatment regimen, we can now visualise the effect of the regimen on the number of detectable cases through time using the `n_detect_730_3650`. ```{r, fig.align = 'center', fig.height = 5, fig.width = 7} -# Create a new variable for Pf Prevalence (Age 2-10) -output$PfPR2_10 <- output$n_detect_730_3650/output$n_730_3650 - # Plot results -plot(x = output$timestep, y = output$PfPR2_10, type = "l", - xlab = "Days", ylab = expression(paste(italic(Pf),"PR"[2-10])), col = cols[1]) - +plot(x = output$timestep, y = output$n_detect_730_3650, type = "l", + xlab = "Days", ylab = "Detectable cases", col = cols[1], + ylim = c(min(output$n_detect_730_3650)-1, max(output$n_detect_730_3650)+7)) + +# Show treatment times +abline(v = 300, lty = 2) +text(x = 310, y = max(output$n_detect_730_3650)+4, labels = "Treatment\nbegins", adj = 0) +abline(v = 600, lty = 2) +text(x = 610, y = max(output$n_detect_730_3650)+4, labels = "Treatment\nends", adj = 0) + + # Add grid lines grid() ``` From a399a9e27bd60bb26be5d5e9564884bc1ef815e3 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Fri, 31 Mar 2023 10:17:31 +0100 Subject: [PATCH 078/164] Deleted an empty line that was bothering me --- vignettes/Treatment.Rmd | 1 - 1 file changed, 1 deletion(-) diff --git a/vignettes/Treatment.Rmd b/vignettes/Treatment.Rmd index 8791baec..d6763774 100644 --- a/vignettes/Treatment.Rmd +++ b/vignettes/Treatment.Rmd @@ -139,7 +139,6 @@ text(x = 310, y = max(output$n_detect_730_3650)+4, labels = "Treatment\nbegins", abline(v = 600, lty = 2) text(x = 610, y = max(output$n_detect_730_3650)+4, labels = "Treatment\nends", adj = 0) - # Add grid lines grid() ``` From 39275771f87112ab70dea894aba49fdc907fc50f Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 31 Mar 2023 11:58:10 +0100 Subject: [PATCH 079/164] Change to new vaccine functions --- vignettes/Vaccines.Rmd | 63 +++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 26 deletions(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 7ccf82fb..545e5b73 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -136,18 +136,20 @@ First, we will model a single round of RTS,S vaccine given in a mass vaccination We specify that the intervention should use the RTS,S vaccine through the `profile` and `booster_profile` inputs. ```{r} -rtssparams <- set_mass_rtss( +rtssmassparams <- set_mass_pev( simparams, + profile = rtss_profile, timesteps = 1 * year, # The single round of vaccination is at 1 year into the simulation. coverages = 1, # The vaccine is given to 100% of the population between the specified ages. min_wait = 0, # The minimum acceptable time since the last vaccination is 0 because in our case we are only implementing one round of vaccination. min_ages = 5 * month, # The minimum age for the target population to be vaccinated. max_ages = 50 * year, # The maximum age for the target population to be vaccinated. boosters = 12 * month, # The booster is given at 12 months after the primary series. - booster_coverage = 0.95 # Coverage of the booster dose is 95%. + booster_coverage = 0.95, # Coverage of the booster dose is 95%. + booster_profile = rtss_booster_profile ) -output <- run_simulation(timesteps = sim_length, parameters = rtssparams) +output <- run_simulation(timesteps = sim_length, parameters = rtssmassparams) ``` #### Plot clinical incidence @@ -190,10 +192,10 @@ seas_simparams <- get_parameters( ) ) -seas_simparams <- set_equilibrium(seas_simparams, starting_EIR) +seas_simparams <- set_equilibrium(parameters = seas_simparams, init_EIR = starting_EIR) # Run no vaccine scenario -output_seas_control <- run_simulation(sim_length *2, seas_simparams) +output_seas_control <- run_simulation(timesteps = sim_length *2, parameters = seas_simparams) ``` Next, we will run the scenario with a seasonal mass vaccination campaign implemented starting 3.5 months before the peak of the transmission season. @@ -201,17 +203,20 @@ Next, we will run the scenario with a seasonal mass vaccination campaign impleme # Find the peak seasonality peak <- peak_season_offset(seas_simparams) -seasmass_simparams <- set_mass_rtss( +seasmass_simparams <- set_mass_pev( parameters = seas_simparams, + profile = rtss_profile, timesteps = round(year + (peak - month * 3.5), 0),# The vaccination will begin 3.5 months prior to the peak seasonality in the second year. coverages = 1, # 100% of the population between min_ages and max_ages is vaccinated. min_ages = 5 * month, # The minimum age for the target population to be vaccinated. max_ages = 15 * year, # The maximum age for the target population to be vaccinated. min_wait = 0, # There is no minimum wait between the last vaccination. boosters = round(c(12 * month + 2 * month)), # The booster is given 14 months after the first dose. - booster_coverage = 1) # 100% of the vaccinated population is boosted. + booster_coverage = 1, # 100% of the vaccinated population is boosted. + booster_profile = rtss_booster_profile + ) -output <- run_simulation(sim_length * 2, seasmass_simparams) +output <- run_simulation(timesteps = sim_length * 2, parameters = seasmass_simparams) ``` #### Plot clinical incidence @@ -238,22 +243,24 @@ We can also opt to vaccinate using the EPI strategy, where individuals will be v ```{r} # Add RTS,S strategy -rtssepiparams <- set_rtss_epi( +rtssepiparams <- set_pev_epi( simparams, + profile = rtss_profile, timesteps = 1 * year, # Vaccination will begin at 1 year into the simulation. coverages = 1, # Vaccine coverage is 100%. min_wait = 0, # There is no minimum wait since the last vaccination. age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. boosters = 12 * month, # The booster is administered 12 months following the third dose. - booster_coverage = 0.95 # 95% of those vaccinated with the primary series will be boosted. + booster_coverage = 0.95, # 95% of those vaccinated with the primary series will be boosted. + booster_profile = rtss_booster_profile ) -output <- run_simulation(sim_length * 2, rtssepiparams) +output <- run_simulation(timesteps = sim_length * 2, parameters = rtssepiparams) ``` -The default values for the `rtss_doses` variable shows that individuals will be vaccinated with dose one at day 0, or the day that the vaccine campaign begins (this is at 1 year in the example above), with dose two 45 days afterwards, and with dose three 90 days after the first dose. This will correspond to ages 5, 6.5, and 8 months for the primary series. The booster will be administered 12 months after dose three, at 20 months of age in the example above. +The default values for the `pev_doses` variable shows that individuals will be vaccinated with dose one at day 0, or the day that the vaccine campaign begins (this is at 1 year in the example above), with dose two 45 days afterwards, and with dose three 90 days after the first dose. This will correspond to ages 5, 6.5, and 8 months for the primary series. The booster will be administered 12 months after dose three, at 20 months of age in the example above. ```{r} -rtssepiparams$rtss_doses +rtssepiparams$pev_doses ``` @@ -284,18 +291,20 @@ In a seasonal setting, we can set booster timesteps relative to the start of the peak <- peak_season_offset(seas_simparams) # Add RTS,S seasonal strategy -rtssepiseasonalparams <- set_rtss_epi( +rtssepiseasonalparams <- set_pev_epi( seas_simparams, + profile = rtss_profile, timesteps = 1 * year, # Vaccination begins 1 year after the start of the simulation. coverages = 1, # Vaccine coverage is 100%. min_wait = 6 * month, # When seasonal_boosters = TRUE, this is the minimum time between an individual receiving the final dose and the first booster. age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. boosters = peak - month * 3.5 , # Because seasonal_boosters = TRUE, the timestep here is relative to the start of the year. Here, we will give a booster at 3.5 months prior to peak transmission. booster_coverage = 0.95, # 95% of the vaccinated population is boosted. - seasonal_boosters = TRUE + seasonal_boosters = TRUE, + booster_profile = rtss_booster_profile ) -output <- run_simulation(sim_length * 2, rtssepiseasonalparams) +output <- run_simulation(timesteps = sim_length * 2, parameters = rtssepiseasonalparams) ``` #### Plot clinical incidence @@ -320,19 +329,21 @@ plot_doses() You can try different dosing schedules using the `pev_doses` parameter. Here we administer dose one at 5 months, dose two 30 days after dose one, and dose three 60 days after dose one. We also administer two booster doses 12 and 24 months following dose three. As before, it is a good idea to visualise the timing of the vaccination strategy to ensure that you have implemented it as intended. ```{r} -rtssepiparams2 <- set_rtss_epi( +rtssepiparams2 <- set_pev_epi( simparams, + profile = rtss_profile, timesteps = 1 * year, coverages = 1, age = 5 * month, min_wait = 0, boosters = c(12 * month, 24 * month), # Here, we are testing a strategy with 2 boosters. - booster_coverage = c(1, 1) + booster_coverage = c(1, 1), + booster_profile = rtss_booster_profile ) -rtssepiparams2$rtss_doses <- c(0, 30, 60) # setting the timesteps for the 3 doses in the primary series at 0, 1, 2 months +rtssepiparams2$pev_doses <- c(0, 30, 60) # setting the timesteps for the 3 doses in the primary series at 0, 1, 2 months -output <- run_simulation(sim_length * 2, rtssepiparams2) +output <- run_simulation(timesteps = sim_length * 2, parameters = rtssepiparams2) ``` #### Plot clinical incidence @@ -350,20 +361,20 @@ plot_prev() ```{r, fig.width = 8, fig.height = 5, fig.align = "center", message=FALSE} output$month <- ceiling(output$timestep / month) -doses <- output[,c(2:6,39)] +doses <- output[, c(2:6, 39)] doses <- aggregate(cbind(doses[1:5]), by = list(doses$month), FUN = sum) -doses <- as.matrix(t(doses[,-1])) +doses <- as.matrix(t(doses[, -1])) barplot(doses, xlab = "Month", ylab = "Number of doses", - col = cols[1:6],space = 0, - beside = FALSE, xaxs = "i", yaxs = "i") + col = cols[1:6], space = 0, + beside = FALSE, xaxs = "i", yaxs = "i") grid(lty = 2, col = "grey80", lwd = 1) axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") legend("topleft", box.lty = 0, legend = c("Dose 1","Dose 2","Dose 3","Booster 1", "Booster 2"), - col = cols[1:6], lty = rep(1, 4), lwd = 2.5, bg="transparent") + col = cols[1:6], lty = rep(1, 4), lwd = 2.5, bg = "transparent") ``` ## TBV @@ -378,7 +389,7 @@ tbvparams <- set_tbv( ages = 5:60 # The age range in years of those receiving the vaccine. ) -output <- run_simulation(sim_length, tbvparams) +output <- run_simulation(timesteps = sim_length, parameters = tbvparams) ``` #### Plot clinical incidence From ae845bd9acde2b7485d8edeb6f32b31c9c606e67 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 31 Mar 2023 15:36:45 +0100 Subject: [PATCH 080/164] edits to generic --- vignettes/Vaccines.Rmd | 60 ++++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 545e5b73..147c455b 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -14,7 +14,7 @@ knitr::opts_chunk$set( ) ``` -In this tutorial, we will explore how to model different strategies for both pre-erythrocytic malaria vaccines and a theoretical malaria transmission blocking vaccine (TBV). Parameters for the pre-erythrocytic vaccine can be set for a routine age-based Expanded Programme on Immunization (EPI) strategy or a mass vaccination strategy using the helper functions `set_rtss_epi()` and `set_mass_rtss()`, while parameters for a TBV can be set using `set_tbv()`. Under an EPI strategy, everybody within a certain age range will be vaccinated within the routine immunisation system. A mass vaccination strategy is typically a one-time event where everybody, or everybody within a certain age group, is targeted for vaccination during a relatively short window of time. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the expected peak of malaria prevalence given by `peak_season_offset()`. +In this tutorial, we will explore how to model different strategies for both pre-erythrocytic malaria vaccines and a theoretical malaria transmission blocking vaccine (TBV). Parameters for the pre-erythrocytic vaccine can be set for a routine age-based Expanded Programme on Immunization (EPI) strategy or a mass vaccination strategy using the helper functions `set_pev_epi()` and `set_mass_pev()`, while parameters for a TBV can be set using `set_tbv()`. Under an EPI strategy, everybody within a certain age range will be vaccinated within the routine immunisation system. A mass vaccination strategy is typically a one-time event where everybody, or everybody within a certain age group, is targeted for vaccination during a relatively short window of time. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the expected peak of malaria prevalence given by `peak_season_offset()`. ```{r setup, message=FALSE} library(malariasimulation) @@ -46,6 +46,8 @@ plot_inci <- function(type = "not seasonal"){ type = "l", col = cols[2], xlab = "Time (years)", ylab = "Clinical incidence (per 1000 children aged 0-5)", xaxs = "i", yaxs = "i", bty = "l", xaxs = "i", yaxs = "i") + lines(x = comparison$time_year, y = comparison$clinical_incidence, + type = "l", col = cols[1],) grid(lty = 2, col = "grey80", lwd = 1) abline(v = vaccinetime, col = "black", lty = 2, lwd = 2.5) curve_values <- loess(clinical_incidence ~ time_year, data = output, span = 0.3, method = "loess") @@ -54,8 +56,8 @@ plot_inci <- function(type = "not seasonal"){ curve_valuescomp <- loess(clinical_incidence ~ time_year, data = comparison, span = 0.3, method = "loess") lines(comparison$time_year, predict(curve_valuescomp), col = cols[6], lwd = 3) - legend("topright", box.lty = 0, legend = c("Start of vaccination", "Unsmoothed incidence for vaccine scenario", "Smoothed incidence for vaccine scenario", "Smoothed incidence for no\nintervention scenario"), - col = c("black", cols[2], cols[5], cols[6]), lty = c(2, 1, 1, 1), lwd = 2.5) + legend("topright", box.lty = 0, legend = c("Start of vaccination", "Unsmoothed incidence for vaccine scenario", "Smoothed incidence for vaccine scenario", "Unsmoothed incidence for no\nintervention scenario", "Smoothed incidence for no\nintervention scenario"), + col = c("black", cols[2], cols[5], cols[1], cols[6]), lty = c(2, 1, 1, 1), lwd = 2.5) } # Plot parasite prevalence @@ -104,7 +106,7 @@ plot_doses <- function(){ ## Parameterisation -We use the `get_parameters()` function to generate a list of parameters, accepting most of the default values, and then use the `set_equilibrium()` function to to initialise the model at a given entomological inoculation rate (EIR) +We use the `get_parameters()` function to generate a list of parameters, accepting most of the default values, and then use the `set_equilibrium()` function to to initialise the model at a given entomological inoculation rate (EIR). ```{r} year <- 365 @@ -131,14 +133,14 @@ Then we can run the simulation for a variety of vaccination strategies. ## Mass RTS,S -First, we will model a single round of RTS,S vaccine given in a mass vaccination strategy where those within a given age range will be vaccinated to a specified coverage level and during a short window of time. In this example, individuals aged between 5 months and 50 years are vaccinated with a primary series (3 doses) followed by a single booster 12 months after the initial vaccination. The age groups to be vaccinated as well as timing of all vaccinations can be modified within the `set_mass_rtss()` function. The model assumes that protection starts following the 3rd dose of the primary series. +First, we will model a single round of RTS,S vaccine given in a mass vaccination strategy where those within a given age range will be vaccinated to a specified coverage level and during a short window of time. In this example, individuals aged between 5 months and 50 years are vaccinated with a primary series (3 doses) followed by a single booster 12 months after the initial vaccination. The age groups to be vaccinated as well as timing of all vaccinations can be modified within the `set_mass_pev()` function. The model assumes that protection starts following the 3rd dose of the primary series. We specify that the intervention should use the RTS,S vaccine through the `profile` and `booster_profile` inputs. ```{r} rtssmassparams <- set_mass_pev( simparams, - profile = rtss_profile, + profile = rtss_profile, # We will model implementation of the RTSS vaccine. timesteps = 1 * year, # The single round of vaccination is at 1 year into the simulation. coverages = 1, # The vaccine is given to 100% of the population between the specified ages. min_wait = 0, # The minimum acceptable time since the last vaccination is 0 because in our case we are only implementing one round of vaccination. @@ -146,7 +148,7 @@ rtssmassparams <- set_mass_pev( max_ages = 50 * year, # The maximum age for the target population to be vaccinated. boosters = 12 * month, # The booster is given at 12 months after the primary series. booster_coverage = 0.95, # Coverage of the booster dose is 95%. - booster_profile = rtss_booster_profile + booster_profile = rtss_booster_profile # We will model implementation of the RTSS booster. ) output <- run_simulation(timesteps = sim_length, parameters = rtssmassparams) @@ -175,7 +177,7 @@ plot_doses() Mass vaccination can also be targeted seasonally. For example, we may want to have a mass vaccination campaign take place a few months prior to the peak transmission season. In the example below, we will create a parameter set with seasonality and first run a simulation with no vaccine, then run a simulation with a mass vaccination campaign targeting everyone between the ages of 5 months and 15 years. -We specify that the intervention should use the RTS,S vaccine through the `profile` and `booster_profile` inputs. +We specify that the intervention should use the RTS,S vaccine through the `profile` and `booster_profile` inputs to the `set_mass_pev()` function. ```{r} # Use the get_parameters() function to generate a new parameter set with a seasonal profile with malaria incidence in children aged 0-5 rendered in the model output: @@ -205,7 +207,7 @@ peak <- peak_season_offset(seas_simparams) seasmass_simparams <- set_mass_pev( parameters = seas_simparams, - profile = rtss_profile, + profile = rtss_profile, # We will model implementation of the RTSS vaccine. timesteps = round(year + (peak - month * 3.5), 0),# The vaccination will begin 3.5 months prior to the peak seasonality in the second year. coverages = 1, # 100% of the population between min_ages and max_ages is vaccinated. min_ages = 5 * month, # The minimum age for the target population to be vaccinated. @@ -213,7 +215,7 @@ seasmass_simparams <- set_mass_pev( min_wait = 0, # There is no minimum wait between the last vaccination. boosters = round(c(12 * month + 2 * month)), # The booster is given 14 months after the first dose. booster_coverage = 1, # 100% of the vaccinated population is boosted. - booster_profile = rtss_booster_profile + booster_profile = rtss_booster_profile # We will model implementation of the RTSS booster. ) output <- run_simulation(timesteps = sim_length * 2, parameters = seasmass_simparams) @@ -239,26 +241,26 @@ plot_doses() ## RTS,S EPI -We can also opt to vaccinate using the EPI strategy, where individuals will be vaccinated once they reach a certain age. In the example below, individuals will be vaccinated once they reach 5 months of age. For this intervention, we see a much more gradual impact following implementation. Note: the model assumes that protection from the vaccine begins after the third dose. +We can also opt to vaccinate using the EPI strategy, where individuals will be vaccinated once they reach a certain age. In the example below, individuals will be vaccinated once they reach 5 months of age. For this intervention, we see a much more gradual impact following implementation compared to the mass vaccination strategy. Note: the model assumes that protection from the vaccine begins after the third dose. ```{r} -# Add RTS,S strategy +# Add RTS,S EPI strategy rtssepiparams <- set_pev_epi( simparams, - profile = rtss_profile, + profile = rtss_profile, # We will model implementation of the RTSS vaccine. timesteps = 1 * year, # Vaccination will begin at 1 year into the simulation. coverages = 1, # Vaccine coverage is 100%. min_wait = 0, # There is no minimum wait since the last vaccination. age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. boosters = 12 * month, # The booster is administered 12 months following the third dose. booster_coverage = 0.95, # 95% of those vaccinated with the primary series will be boosted. - booster_profile = rtss_booster_profile + booster_profile = rtss_booster_profile # We will model implementation of the RTSS booster. ) output <- run_simulation(timesteps = sim_length * 2, parameters = rtssepiparams) ``` -The default values for the `pev_doses` variable shows that individuals will be vaccinated with dose one at day 0, or the day that the vaccine campaign begins (this is at 1 year in the example above), with dose two 45 days afterwards, and with dose three 90 days after the first dose. This will correspond to ages 5, 6.5, and 8 months for the primary series. The booster will be administered 12 months after dose three, at 20 months of age in the example above. +The default values for the `pev_doses` variable shows that individuals will be vaccinated with dose one at day 0, or the day that the vaccine campaign begins (at 1 year in the example above), with dose two 45 days afterwards, and with dose three 90 days after the first dose. This will correspond to ages 5, 6.5, and 8 months for the primary series. The booster will be administered 12 months after dose three, which is at 20 months of age in the example above. ```{r} rtssepiparams$pev_doses ``` @@ -280,11 +282,11 @@ plot_prev() ```{r, fig.width = 8, fig.height = 5, fig.align = "center", message=FALSE} plot_doses() ``` -We see a much more gradual decrease in clinical incidence following EPI implementation compared to the mass vaccination strategy. + ### RTS,S EPI with seasonal boosters -In a seasonal setting, we can set booster timesteps relative to the start of the year instead of relative to the last dose. This allows us to consider seasonal dynamics and implement booster doses right before the start of the high transmission season to maximize impact. +In a seasonal setting, we can set booster timesteps relative to the start of the year instead of relative to the last dose. This allows us to consider seasonal dynamics and implement booster doses right before the start of the high transmission season to maximise impact. ```{r} # Calculate the peak of the transmission season based on seasonality parameters above. @@ -293,15 +295,15 @@ peak <- peak_season_offset(seas_simparams) # Add RTS,S seasonal strategy rtssepiseasonalparams <- set_pev_epi( seas_simparams, - profile = rtss_profile, + profile = rtss_profile, # We will model implementation of the RTSS vaccine. timesteps = 1 * year, # Vaccination begins 1 year after the start of the simulation. coverages = 1, # Vaccine coverage is 100%. min_wait = 6 * month, # When seasonal_boosters = TRUE, this is the minimum time between an individual receiving the final dose and the first booster. age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. boosters = peak - month * 3.5 , # Because seasonal_boosters = TRUE, the timestep here is relative to the start of the year. Here, we will give a booster at 3.5 months prior to peak transmission. booster_coverage = 0.95, # 95% of the vaccinated population is boosted. - seasonal_boosters = TRUE, - booster_profile = rtss_booster_profile + seasonal_boosters = TRUE, # Boosters will be given based on a seasonal schedule, so the timing in the boosters= argument above will be relative to the start of the year instead of relative to the 3rd dose. + booster_profile = rtss_booster_profile # We will model implementation of the RTSS booster. ) output <- run_simulation(timesteps = sim_length * 2, parameters = rtssepiseasonalparams) @@ -326,19 +328,19 @@ plot_doses() ### RTS,S dosing -You can try different dosing schedules using the `pev_doses` parameter. Here we administer dose one at 5 months, dose two 30 days after dose one, and dose three 60 days after dose one. We also administer two booster doses 12 and 24 months following dose three. As before, it is a good idea to visualise the timing of the vaccination strategy to ensure that you have implemented it as intended. +You can implement different dosing schedules using the `pev_doses` parameter. Here we administer dose one at 5 months, dose two 30 days after dose one, and dose three 60 days after dose one. We also administer two booster doses 12 and 24 months following dose three. As before, it is a good idea to visualise the timing of the vaccination strategy to ensure that the vaccine is implemented as intended. ```{r} rtssepiparams2 <- set_pev_epi( simparams, - profile = rtss_profile, - timesteps = 1 * year, - coverages = 1, - age = 5 * month, - min_wait = 0, - boosters = c(12 * month, 24 * month), # Here, we are testing a strategy with 2 boosters. - booster_coverage = c(1, 1), - booster_profile = rtss_booster_profile + profile = rtss_profile, # We will model implementation of the RTSS vaccine. + timesteps = 1 * year, # Vaccination begins 1 year after the start of the simulation. + coverages = 1, # Vaccine coverage is 100%. + age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. + min_wait = 0, # When seasonal_boosters = FALSE, this is the minimum time between doses. + boosters = c(12 * month, 24 * month), # Here, we are testing a strategy with 2 boosters, one at 1 year after the 3rd dose and the second 2 years after the 3rd dose. + booster_coverage = c(1, 1), # For each of the two boosters, coverage is 100%. + booster_profile = rtss_booster_profile # We will model implementation of the RTSS booster. ) rtssepiparams2$pev_doses <- c(0, 30, 60) # setting the timesteps for the 3 doses in the primary series at 0, 1, 2 months From b61c815f06d6c3290355d52c27468045af2df8f6 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Mon, 3 Apr 2023 09:53:17 +0100 Subject: [PATCH 081/164] edits to text and final changes to work with new generic vaccine functions --- vignettes/Vaccines.Rmd | 57 +++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 147c455b..78e8fd9c 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -14,9 +14,10 @@ knitr::opts_chunk$set( ) ``` -In this tutorial, we will explore how to model different strategies for both pre-erythrocytic malaria vaccines and a theoretical malaria transmission blocking vaccine (TBV). Parameters for the pre-erythrocytic vaccine can be set for a routine age-based Expanded Programme on Immunization (EPI) strategy or a mass vaccination strategy using the helper functions `set_pev_epi()` and `set_mass_pev()`, while parameters for a TBV can be set using `set_tbv()`. Under an EPI strategy, everybody within a certain age range will be vaccinated within the routine immunisation system. A mass vaccination strategy is typically a one-time event where everybody, or everybody within a certain age group, is targeted for vaccination during a relatively short window of time. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the expected peak of malaria prevalence given by `peak_season_offset()`. +In this tutorial, we will explore how to model different strategies for both pre-erythrocytic malaria vaccines and a theoretical malaria transmission blocking vaccine (TBV). Parameters for a pre-erythrocytic vaccine can be set for a routine age-based Expanded Programme on Immunization (EPI) strategy or a mass vaccination strategy using the helper functions `set_pev_epi()` and `set_mass_pev()`, while parameters for a TBV can be set using `set_tbv()`. Under an EPI strategy, everybody within a certain age range will be vaccinated within the routine immunisation system. A mass vaccination strategy is typically a one-time event where everybody, or everybody within a certain age group, is targeted for vaccination during a relatively short window of time. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the expected peak of malaria prevalence given by `peak_season_offset()`. ```{r setup, message=FALSE} +remotes::install_github('mrc-ide/malariasimulation@dev') library(malariasimulation) cols <- c("#E69F00", "#56B4E9", "#009E73", @@ -46,8 +47,6 @@ plot_inci <- function(type = "not seasonal"){ type = "l", col = cols[2], xlab = "Time (years)", ylab = "Clinical incidence (per 1000 children aged 0-5)", xaxs = "i", yaxs = "i", bty = "l", xaxs = "i", yaxs = "i") - lines(x = comparison$time_year, y = comparison$clinical_incidence, - type = "l", col = cols[1],) grid(lty = 2, col = "grey80", lwd = 1) abline(v = vaccinetime, col = "black", lty = 2, lwd = 2.5) curve_values <- loess(clinical_incidence ~ time_year, data = output, span = 0.3, method = "loess") @@ -56,8 +55,8 @@ plot_inci <- function(type = "not seasonal"){ curve_valuescomp <- loess(clinical_incidence ~ time_year, data = comparison, span = 0.3, method = "loess") lines(comparison$time_year, predict(curve_valuescomp), col = cols[6], lwd = 3) - legend("topright", box.lty = 0, legend = c("Start of vaccination", "Unsmoothed incidence for vaccine scenario", "Smoothed incidence for vaccine scenario", "Unsmoothed incidence for no\nintervention scenario", "Smoothed incidence for no\nintervention scenario"), - col = c("black", cols[2], cols[5], cols[1], cols[6]), lty = c(2, 1, 1, 1), lwd = 2.5) + legend("topright", box.lty = 0, legend = c("Start of vaccination", "Unsmoothed incidence for vaccine scenario", "Smoothed incidence for vaccine scenario", "Smoothed incidence for no\nintervention scenario"), + col = c("black", cols[2], cols[5], cols[6]), lty = c(2, 1, 1), lwd = 2.5) } # Plot parasite prevalence @@ -78,7 +77,7 @@ plot_prev <- function(type = "not seasonal"){ xaxs = "i", yaxs = "i", bty = "l", xaxs = "i", yaxs = "i") grid(lty = 2, col = "grey80", lwd = 1) lines(x = comparison$time_year, y = comparison$n_detect_730_3650/comparison$n_730_3650, - col = cols[6], lwd = 3,) + col = cols[6], lwd = 3) abline(v = vaccinetime, col = "black", lty = 2, lwd = 2.5) legend("topright", box.lty = 0, legend = c("Start of vaccination", "Prevalence for vaccine scenario", "Prevalence for no intervention scenario"), col = c("black", cols[3], cols[6]), lty = c(2, 1, 1), lwd = 2.5) @@ -87,7 +86,7 @@ plot_prev <- function(type = "not seasonal"){ # Plot dose timing plot_doses <- function(){ output$month <- ceiling(output$timestep / month) - doses <- output[, c(grep("n_rtss" , names(output)), grep("month", names(output)))] + doses <- output[, c(grep("n_pev" , names(output)), grep("month", names(output)))] doses <- aggregate(cbind(doses[1:4]), by = list(doses$month), FUN = sum) @@ -95,8 +94,8 @@ plot_doses <- function(){ barplot(doses, xlab = "Month", ylab = "Number of doses", - col = cols[1:6],space = 0, - beside = FALSE, xaxs = "i", yaxs = "i") + col = cols[1:6], space = 0, + beside = FALSE, xaxs = "i", yaxs = "i") grid(lty = 2, col = "grey80", lwd = 1) axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") legend("topleft", box.lty = 0, legend = c("Dose 1","Dose 2","Dose 3","Booster 1"), @@ -133,7 +132,7 @@ Then we can run the simulation for a variety of vaccination strategies. ## Mass RTS,S -First, we will model a single round of RTS,S vaccine given in a mass vaccination strategy where those within a given age range will be vaccinated to a specified coverage level and during a short window of time. In this example, individuals aged between 5 months and 50 years are vaccinated with a primary series (3 doses) followed by a single booster 12 months after the initial vaccination. The age groups to be vaccinated as well as timing of all vaccinations can be modified within the `set_mass_pev()` function. The model assumes that protection starts following the 3rd dose of the primary series. +First, we will model a single round of RTS,S vaccine given in a mass vaccination strategy where those within a given age range will be vaccinated to a specified coverage level during a short window of time. In this example, individuals aged between 5 months and 50 years are vaccinated with a primary series (3 doses) followed by a single booster 12 months after the initial vaccination. The age groups to be vaccinated as well as timing of all vaccinations can be modified within the `set_mass_pev()` function. The model assumes that protection starts following the 3rd dose of the primary series. We specify that the intervention should use the RTS,S vaccine through the `profile` and `booster_profile` inputs. @@ -146,9 +145,9 @@ rtssmassparams <- set_mass_pev( min_wait = 0, # The minimum acceptable time since the last vaccination is 0 because in our case we are only implementing one round of vaccination. min_ages = 5 * month, # The minimum age for the target population to be vaccinated. max_ages = 50 * year, # The maximum age for the target population to be vaccinated. - boosters = 12 * month, # The booster is given at 12 months after the primary series. + booster_timestep = 12 * month, # The booster is given at 12 months after the primary series. booster_coverage = 0.95, # Coverage of the booster dose is 95%. - booster_profile = rtss_booster_profile # We will model implementation of the RTSS booster. + booster_profile = list(rtss_booster_profile) # We will model implementation of the RTSS booster. ) output <- run_simulation(timesteps = sim_length, parameters = rtssmassparams) @@ -175,7 +174,7 @@ plot_doses() ### Seasonal mass vaccination -Mass vaccination can also be targeted seasonally. For example, we may want to have a mass vaccination campaign take place a few months prior to the peak transmission season. In the example below, we will create a parameter set with seasonality and first run a simulation with no vaccine, then run a simulation with a mass vaccination campaign targeting everyone between the ages of 5 months and 15 years. +Mass vaccination can also be targeted seasonally. For example, we may want to have a mass vaccination campaign take place a few months prior to the peak transmission season. In the example below, we will create a parameter set with seasonality and first run a simulation with no vaccine, then run a simulation with a mass vaccination campaign targeting everyone between the ages of 5 months and 50 years. We specify that the intervention should use the RTS,S vaccine through the `profile` and `booster_profile` inputs to the `set_mass_pev()` function. @@ -197,7 +196,7 @@ seas_simparams <- get_parameters( seas_simparams <- set_equilibrium(parameters = seas_simparams, init_EIR = starting_EIR) # Run no vaccine scenario -output_seas_control <- run_simulation(timesteps = sim_length *2, parameters = seas_simparams) +output_seas_control <- run_simulation(timesteps = sim_length * 2, parameters = seas_simparams) ``` Next, we will run the scenario with a seasonal mass vaccination campaign implemented starting 3.5 months before the peak of the transmission season. @@ -211,11 +210,11 @@ seasmass_simparams <- set_mass_pev( timesteps = round(year + (peak - month * 3.5), 0),# The vaccination will begin 3.5 months prior to the peak seasonality in the second year. coverages = 1, # 100% of the population between min_ages and max_ages is vaccinated. min_ages = 5 * month, # The minimum age for the target population to be vaccinated. - max_ages = 15 * year, # The maximum age for the target population to be vaccinated. + max_ages = 50 * year, # The maximum age for the target population to be vaccinated. min_wait = 0, # There is no minimum wait between the last vaccination. - boosters = round(c(12 * month + 2 * month)), # The booster is given 14 months after the first dose. + booster_timestep = round(c(12 * month + 2 * month)), # The booster is given 14 months after the first dose. booster_coverage = 1, # 100% of the vaccinated population is boosted. - booster_profile = rtss_booster_profile # We will model implementation of the RTSS booster. + booster_profile = list(rtss_booster_profile) # We will model implementation of the RTSS booster. ) output <- run_simulation(timesteps = sim_length * 2, parameters = seasmass_simparams) @@ -252,15 +251,15 @@ rtssepiparams <- set_pev_epi( coverages = 1, # Vaccine coverage is 100%. min_wait = 0, # There is no minimum wait since the last vaccination. age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. - boosters = 12 * month, # The booster is administered 12 months following the third dose. + booster_timestep = 12 * month, # The booster is administered 12 months following the third dose. booster_coverage = 0.95, # 95% of those vaccinated with the primary series will be boosted. - booster_profile = rtss_booster_profile # We will model implementation of the RTSS booster. + booster_profile = list(rtss_booster_profile) # We will model implementation of the RTSS booster. ) output <- run_simulation(timesteps = sim_length * 2, parameters = rtssepiparams) ``` -The default values for the `pev_doses` variable shows that individuals will be vaccinated with dose one at day 0, or the day that the vaccine campaign begins (at 1 year in the example above), with dose two 45 days afterwards, and with dose three 90 days after the first dose. This will correspond to ages 5, 6.5, and 8 months for the primary series. The booster will be administered 12 months after dose three, which is at 20 months of age in the example above. +The default values for the `pev_doses` variable shows that individuals will be vaccinated with dose one at day 0, or the day that the vaccine campaign begins (at 1 year in the example above), with dose two 45 days after the first dose, and with dose three 90 days after the first dose. This will correspond to ages 5, 6.5, and 8 months for the primary series. The booster will be administered 12 months after dose three, which is at 20 months of age in the example above. ```{r} rtssepiparams$pev_doses ``` @@ -276,6 +275,8 @@ plot_inci() ```{r, fig.width = 8, fig.height = 5, fig.align = "center"} plot_prev() ``` + +A limited impact upon prevalence is observed because the target population for vaccination is small relative to the entire population, resulting only in direct protection of those vaccinated. #### Plot doses @@ -300,17 +301,16 @@ rtssepiseasonalparams <- set_pev_epi( coverages = 1, # Vaccine coverage is 100%. min_wait = 6 * month, # When seasonal_boosters = TRUE, this is the minimum time between an individual receiving the final dose and the first booster. age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. - boosters = peak - month * 3.5 , # Because seasonal_boosters = TRUE, the timestep here is relative to the start of the year. Here, we will give a booster at 3.5 months prior to peak transmission. + booster_timestep = peak - month * 3.5 , # Because seasonal_boosters = TRUE, the timestep here is relative to the start of the year. Here, we will give a booster at 3.5 months prior to peak transmission. booster_coverage = 0.95, # 95% of the vaccinated population is boosted. seasonal_boosters = TRUE, # Boosters will be given based on a seasonal schedule, so the timing in the boosters= argument above will be relative to the start of the year instead of relative to the 3rd dose. - booster_profile = rtss_booster_profile # We will model implementation of the RTSS booster. + booster_profile = list(rtss_booster_profile) # We will model implementation of the RTSS booster. ) output <- run_simulation(timesteps = sim_length * 2, parameters = rtssepiseasonalparams) ``` #### Plot clinical incidence - ```{r, fig.width = 8, fig.height = 5, fig.align = "center"} plot_inci(type = "seasonal") ``` @@ -321,14 +321,13 @@ plot_prev(type = "seasonal") ``` #### Plot doses - ```{r, fig.width = 8, fig.height = 5, fig.align = "center", message=FALSE} plot_doses() ``` ### RTS,S dosing -You can implement different dosing schedules using the `pev_doses` parameter. Here we administer dose one at 5 months, dose two 30 days after dose one, and dose three 60 days after dose one. We also administer two booster doses 12 and 24 months following dose three. As before, it is a good idea to visualise the timing of the vaccination strategy to ensure that the vaccine is implemented as intended. +We can implement different dosing schedules using the `pev_doses` parameter. Here we administer dose one at 5 months, dose two 30 days after dose one, and dose three 60 days after dose one. We also administer two booster doses 12 and 24 months following dose three. As before, it is a good idea to visualise the dose timing to ensure that the vaccine is implemented as intended. ```{r} rtssepiparams2 <- set_pev_epi( @@ -338,9 +337,9 @@ rtssepiparams2 <- set_pev_epi( coverages = 1, # Vaccine coverage is 100%. age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. min_wait = 0, # When seasonal_boosters = FALSE, this is the minimum time between doses. - boosters = c(12 * month, 24 * month), # Here, we are testing a strategy with 2 boosters, one at 1 year after the 3rd dose and the second 2 years after the 3rd dose. + booster_timestep = c(12 * month, 24 * month), # Here, we are testing a strategy with 2 boosters, one at 1 year after the 3rd dose and the second 2 years after the 3rd dose. booster_coverage = c(1, 1), # For each of the two boosters, coverage is 100%. - booster_profile = rtss_booster_profile # We will model implementation of the RTSS booster. + booster_profile = list(rtss_booster_profile, rtss_booster_profile) # We will model implementation of the RTSS booster. ) rtssepiparams2$pev_doses <- c(0, 30, 60) # setting the timesteps for the 3 doses in the primary series at 0, 1, 2 months @@ -363,7 +362,7 @@ plot_prev() ```{r, fig.width = 8, fig.height = 5, fig.align = "center", message=FALSE} output$month <- ceiling(output$timestep / month) -doses <- output[, c(2:6, 39)] +doses <- output[, c(2:6, 38)] doses <- aggregate(cbind(doses[1:5]), by = list(doses$month), FUN = sum) @@ -381,7 +380,7 @@ legend("topleft", box.lty = 0, legend = c("Dose 1","Dose 2","Dose 3","Booster 1" ## TBV -We can also model vaccines with completely different modes of actions. For example, a transmission blocking vaccine (TBV). This example shows 5 rounds of a TBV to 99% of the population aged 5 and 60. +We can also model a hypothetical transmission blocking vaccine (TBV). This example shows 5 rounds of a TBV to 99% of the population aged 5 and 60. ```{r} tbvparams <- set_tbv( From d425290e815daefe0930251ba995b837be5b6f8c Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Wed, 5 Apr 2023 14:19:16 +0100 Subject: [PATCH 082/164] Correction to references and more realistic scenario for bednets --- vignettes/SetSpecies.Rmd | 2 +- vignettes/VectorControl_Bednets.Rmd | 12 +++++++----- vignettes/VectorControl_IRS.Rmd | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/vignettes/SetSpecies.Rmd b/vignettes/SetSpecies.Rmd index 283e1899..9e621d1f 100644 --- a/vignettes/SetSpecies.Rmd +++ b/vignettes/SetSpecies.Rmd @@ -41,7 +41,7 @@ plot_prev <- function() { As alluded to in the Model Structure, Vector Control: IRS, and Vector Control: Bed net vignettes, it is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. IRS and bed nets could be expected to have different impacts depending on the proportion of each mosquito species because of variations in indoor resting, insecticide resistance, and proportion of bites on humans versus animals by species. If you have specified more than 1 species, then the arguments for `set_spraying()` and/or `set_bednets()` must be populated with values for each species at each timestep that the intervention is implemented. -There are preset parameters for *An. gambiae*, *An. arabiensis*, and *An. funestus* that can be set by the helper functions `gamb_params()`, `arab_params()`, and `fun_params()`, respectively. The default values for each species in these helper functions are from [Sherrard-Smith et al., 2019](https://doi.org/10.1073/pnas.1820646116). The parameters are: +There are preset parameters for *An. gambiae*, *An. arabiensis*, and *An. funestus* that can be set by the helper functions `gamb_params()`, `arab_params()`, and `fun_params()`, respectively. The default values for each species in these helper functions are from [Sherrard-Smith et al., 2018](https://doi.org/10.1038/s41467-018-07357-w). The parameters are: * `blood_meal_rates`: the blood meal rates for each species * `foraging_time`: time spent taking blood meals diff --git a/vignettes/VectorControl_Bednets.Rmd b/vignettes/VectorControl_Bednets.Rmd index d516c2cc..3c947698 100644 --- a/vignettes/VectorControl_Bednets.Rmd +++ b/vignettes/VectorControl_Bednets.Rmd @@ -47,7 +47,7 @@ Use the `get_parameters()` function to generate the list of parameters for a per ```{r} year <- 365 -sim_length <- 3 * year +sim_length <- 6 * year human_population <- 1000 starting_EIR <- 50 @@ -71,16 +71,18 @@ simparams$species_proportions ## Simulation -Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bed nets once a year for two years, the first round to 50% of the population and the second round to 80% of the population. It is possible to change the characteristics of the bed nets for each distribution timestep if different types of bed nets are distributed that have different insecticides, different levels of insecticide resistance, etc. This can be done by modifying the matrices for `dn0`, `rn`, `rnm`, and `gamman`. Because we are using the default proportions of mosquito species and there are two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 1 column and 2 rows. +Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bed nets to 50% of the population every three years. It is possible to change the characteristics of the bed nets for each distribution timestep if different types of bed nets are distributed that have different insecticides, different levels of insecticide resistance, etc. This can be done by modifying the matrices for `dn0`, `rn`, `rnm`, and `gamman`. Because we are using the default proportions of mosquito species and there are two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 1 column and 2 rows. + +The parameter values for pyrethroid-only and pyrethroid-PBO nets at various resistance levels can be found in Table S1.3 in the Supplementary Appendix 2 of [Sherrard-Smith, et al., 2022](https://doi.org/10.1016/S2542-5196(21)00296-5). ```{r, fig.align="center", fig.height=4, fig.width=6} -bednetstimesteps <- c(1, 2) * year # The bed nets will be distributed at the end of the first and the second year. +bednetstimesteps <- c(1, 4) * year # The bed nets will be distributed at the end of the first and the 4th year. bednetparams <- set_bednets( simparams, timesteps = bednetstimesteps, - coverages = c(.5, .8), # The first round is distributed to 50% of the population and the second round to 80%. + coverages = c(.5, .5), # Each round is distributed to 50% of the population. retention = 5 * year, # Nets are kept on average 5 years dn0 = matrix(c(.533, .533), nrow = 2, ncol = 1), # Matrix of death probabilities for each mosquito species over time rn = matrix(c(.56, .56), nrow = 2, ncol = 1), # Matrix of repelling probabilities for each mosquito species over time @@ -98,7 +100,7 @@ plot_prev() ## Comparing input coverage and population bed net usage -It is important to understand the difference between the input `coverages` argument of `set_bednets()` and the resulting population bed net usage over time in the model. When we set coverages in the above example to 0.8, we are telling the model to distribute bed nets to 80% of the population at year one, and to 50% of the population at year 2. However, the level of average bed net usage is not necessarily equal to 80% or 50%. Between these time points, bed net use will slowly decline over time (in reality this decline stems from things like disuse, holes in nets, lost nets, etc.). +It is important to understand the difference between the input `coverages` argument of `set_bednets()` and the resulting population bed net usage over time in the model. When we set coverages in the above example to 0.8, we are telling the model to distribute bed nets to 50% of the population at year one and to 50% of the population at year 4. However, the level of average bed net usage is not necessarily equal to 50%. Between these time points, bed net use will slowly decline over time (in reality this decline stems from things like disuse, holes in nets, lost nets, etc.). The average population bed net usage will be influenced by: diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index 4d92c148..6b869a40 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -83,7 +83,7 @@ simparams$species Then we can run the simulations for a variety of IRS strategies. In the example below, there are two rounds of IRS, the first at 30% coverage and the second at 80% coverage, each 3 months prior to peak rainfall for that year. The function `peak_season_offset()` outputs a timestep when peak rainfall will be observed based on the seasonality profile we set above. Notice that the matrices specified for the parameters for `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` have two rows, one for each timestep where IRS is implemented, and a number of columns corresponding to mosquito species. In this example, we only have 1 column because the species is set to "All" as we saw above. -The structure for IRS model is documented in the supplementary information from Table S1.3 in [Sherrard-Smith et al., 2018](https://doi.org/10.1016/S2542-5196(21)00296-5). +The structure for IRS model is documented in the supplementary information from Table 3 in the Supplementary Information of [Sherrard-Smith et al., 2018](https://doi.org/10.1038/s41467-018-07357-w). Table S2.1 in the Supplementary Appendix of [Sherrard-Smith et al., 2022](https://doi.org/10.1016/S2542-5196(21)00296-5) has parameter estimates for insecticide resistance for IRS. ```{r, fig.align="center", fig.height=4, fig.width=6} peak <- peak_season_offset(simparams) From f03b33cb1fa2378925526ca60f0a39165e2430de Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 21 Apr 2023 10:40:20 +0100 Subject: [PATCH 083/164] Remove line to install packages --- vignettes/Vaccines.Rmd | 1 - 1 file changed, 1 deletion(-) diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 78e8fd9c..44a752de 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -17,7 +17,6 @@ knitr::opts_chunk$set( In this tutorial, we will explore how to model different strategies for both pre-erythrocytic malaria vaccines and a theoretical malaria transmission blocking vaccine (TBV). Parameters for a pre-erythrocytic vaccine can be set for a routine age-based Expanded Programme on Immunization (EPI) strategy or a mass vaccination strategy using the helper functions `set_pev_epi()` and `set_mass_pev()`, while parameters for a TBV can be set using `set_tbv()`. Under an EPI strategy, everybody within a certain age range will be vaccinated within the routine immunisation system. A mass vaccination strategy is typically a one-time event where everybody, or everybody within a certain age group, is targeted for vaccination during a relatively short window of time. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the expected peak of malaria prevalence given by `peak_season_offset()`. ```{r setup, message=FALSE} -remotes::install_github('mrc-ide/malariasimulation@dev') library(malariasimulation) cols <- c("#E69F00", "#56B4E9", "#009E73", From 05da94cfc9e27a9acfb09289d8d7ef8588472814 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 21 Apr 2023 11:23:28 +0100 Subject: [PATCH 084/164] Changed plot so that beginning of sim is not 0% prev --- vignettes/Variation.Rmd | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index 0f9c46da..01ac82d3 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -9,7 +9,7 @@ vignette: > ```{r setup} library(malariasimulation) -set.seed(123) +set.seed(555) ``` `malariasimulation` is a stochastic, individual-based model and, as such, simulations run with identical parameterisations will generate non-identical, sometimes highly variable, outputs. To illustrate this, we will compare the prevalence and incidence of malaria over a year in simulations with a small and a larger population. @@ -116,7 +116,7 @@ simparams_big <- set_equilibrium(parameters = simparams_big, init_EIR = 1) ## Simulations ```{r, fig.align="center",fig.height=6, fig.width=8} -set.seed(555) +set.seed(444) # A small population output_small_pop <- run_simulation(timesteps = 365 * 2, parameters = simparams_small) @@ -125,6 +125,6 @@ output_big_pop <- run_simulation(timesteps = 365 * 2, parameters = simparams_big # Plotting par(mfrow = c(1, 2)) -plot_prev(output_small_pop, ylim = c(0, 1)); title(expression(paste(italic(Pf),"PR"[2-10], " at n = 50"))) -plot_prev(output_big_pop, ylab = FALSE, ylim = c(0, 1)); title(expression(paste(italic(Pf),"PR"[2-10], " at n = 1,000"))) +plot_prev(output_small_pop, ylim = c(0, 0.2)); title(expression(paste(italic(Pf),"PR"[2-10], " at n = 50"))) +plot_prev(output_big_pop, ylab = FALSE, ylim = c(0, 0.2)); title(expression(paste(italic(Pf),"PR"[2-10], " at n = 1,000"))) ``` \ No newline at end of file From ce353e8f8c3e5dc2bb8150c32e93e31538987620 Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Tue, 16 May 2023 12:14:07 +0100 Subject: [PATCH 085/164] Updated the EIRprevmatch vignette to give a clearer idea of why this is useful to users, improved the structure and added more detailed explanations and code comments. I also corrected an indexing error in the code chunk calculating PfPR210 from the malariaEquilibrium output. --- vignettes/EIRprevmatch.Rmd | 230 ++++++++++++++++++++++++++----------- 1 file changed, 160 insertions(+), 70 deletions(-) diff --git a/vignettes/EIRprevmatch.Rmd b/vignettes/EIRprevmatch.Rmd index e46b7e6c..1dbc0022 100644 --- a/vignettes/EIRprevmatch.Rmd +++ b/vignettes/EIRprevmatch.Rmd @@ -1,5 +1,5 @@ --- -title: "Matching PfPR2-10 to EIR" +title: "Matching *Pf*PR~2-10~ to EIR" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{EIRprevmatch} @@ -15,58 +15,105 @@ knitr::opts_chunk$set( ``` ```{r setup, message=F, warning=F} + +# Load in the requisite functions library(malariasimulation) +library(malariaEquilibrium) library(mgcv) + +# Define a colour palette for plotting: +plot_cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") + ``` -Begin by parameterizing the model you wish to run. Be sure to include any seasonality factors and interventions you want to include at baseline. +## Introduction +The entomological inoculation rate (EIR), defined as the number of infectious bites experienced per person per unit time, malaria prevalence, the proportion of the population with detectable malaria, are two metrics used widely to describe malaria transmission and status within an affected population. With respect to the latter, focus is often given to prevalence in the age groups 2-10 years old, denoted *Pf*PR~2-10~, the prevalence rate of *Plasmodium falciparum* in children aged two to ten. + +**Explanation for why a user might want to match *Pf*PR~2-10~ to EIR** + + +## Parameterisation + +To run `malariasimulation`, the first step is to generate a list of parameters using the `get_parameters()` function, which loads the default `malariasimulation` parameter list. Within this function call, we adapt the average age of the human population to flatten its demographic profile, specify seasonal malaria transmission, instruct the model to output malaria prevalence in the age range of 2-10 years old, and switch off the individual-based mosquito module. The `set_species()` function is then called to specify the composition of the vector community. The `set_drugs()` function is used to append the in-built parameters for Artemether Lumefantrine (AL) and, finally, the `set_clinical_treatment()` function is called to specify a treatment campaign that distribute AL to 45% of the population in the first time step (t = 1). ```{r parameters} + +# Specify the time frame over which to simulate and the human population size: year <- 365 human_population <- 5000 -params <- get_parameters(list( +# Use the get_parameters() function to establish a list of simulation parameters: +simparams <- get_parameters(list( + + # Set the population size human_population = human_population, - average_age = 8453.323, # to match flat_demog - model_seasonality = TRUE, # assign seasonality + + # Set the average age of the population + average_age = 8453.323, + + # Turn on a specfiy seasonal transmission pattern + model_seasonality = TRUE, g0 = 0.284596, g = c(-0.317878, -0.0017527, 0.116455), - h = c(-0.331361, 0.293128, -0.0617547), - prevalence_rendering_min_ages = 2 * year, # set prev age range + h = c(-0.331361, 0.293128, -0.0617547), + + # Instruct model to render prevalence in age group 2-10 + prevalence_rendering_min_ages = 2 * year, prevalence_rendering_max_ages = 10 * year, + + # Turn off the individual mosquitoes module individual_mosquitoes = FALSE)) - # set species / drugs / treatment parameters -params <- set_species(params, species = list(arab_params, fun_params, gamb_params), - proportions = c(0.25, 0.25, 0.5)) -params <- set_drugs(params, list(AL_params)) -params <- set_clinical_treatment(params, 1, c(1), c(0.45)) +# Use the set_species() function to specify the mosquito population (species and +# relative abundances) +simparams <- set_species(parameters = simparams, + species = list(arab_params, fun_params, gamb_params), + proportions = c(0.25, 0.25, 0.5)) + +# Use the set_drugs() function to append the in-built parameters for the +# drug Artemether Lumefantrine (AL) +simparams <- set_drugs(simparams, list(AL_params)) + +# Use the set_clinical_treatment() function to parameterise human +# population treatment with AL in the first timestep +simparams <- set_clinical_treatment(parameters = simparams, + drug = 1, + timesteps = c(1), + coverages = c(0.45)) ``` -Now run `malariasimulation` over a range of EIRs. The goal is to run enough points to generate a curve to which you can match PfPR2-10 to EIR effectively. +## *Pf*PR~2-10~ Matching using malariasimulation + +Having established a set of `malariasimulation` parameters, we are now ready to run simulations. In the following code chunk, we'll run the `run_simulation()` across a range of initial EIR values to generate sufficient points to fit a curve matching *Pf*PR~2-10~ to the initial EIR. For each initial EIR, we first use the `set_equilibrium()` to update the model parameter list with the human and vector population parameter values required to achieve the specified EIR at equilibrium. This updated parameter list is then used to run the simulation. + +The `run_simulation()` outputs an EIR per time step, per species, across the entire human population. We first convert these to get the number of infectious bites experienced, on average, by each individual across the final year across all vector species. Next, the average *Pf*PR~2-10~ across the final year of the simulation is calculated by dividing the total number of individuals aged 2-10 by the number (`n_730_3650`) of detectable cases of malaria in individuals aged 2-10 (`n_detect_730_3650`) on each day and calculating the mean of these values. Finally, initial EIR, output EIR, and *Pf*PR~2-10~ are stored in a data frame. ```{r model} -# loop over malariasimulation runs -init_EIR <- c(0.01, 0.1, 1, 5, 10, 25, 50) # set EIR values -# run model -outputs <- lapply( +# Establish a vector of initial EIR values to simulate over and generate matching +# PfPR2-10 values: +init_EIR <- c(0.01, 0.1, 1, 5, 10, 25, 50) + +# For each initial EIR, calculate equilibriual parameter set and run the simulation +malSim_outs <- lapply( init_EIR, function(init) { - p_i <- set_equilibrium(params, init) - run_simulation(5 * year, p_i) # sim time = 5 years + p_i <- set_equilibrium(simparams, init) + run_simulation(5 * year, p_i) } ) -# output EIR values -EIR <- lapply( - outputs, +# Convert the default EIR output (per vector species, per timestep, across +# the entire human population) to a cross-vector species average EIR per +# person per year across the final year of the simulation: +malSim_EIR <- lapply( + malSim_outs, function(output) { mean( rowSums( output[ - output$timestep %in% seq(4 * 365, 5 * 365), # just use data from the last year + output$timestep %in% seq(4 * 365, 5 * 365), grepl('EIR_', names(output)) ] / human_population * year ) @@ -74,9 +121,10 @@ EIR <- lapply( } ) -# output prev 2-10 values -prev <- lapply( - outputs, +# Calculate the average PfPR2-10 value across the final year for each initial +# EIR value +malSim_prev <- lapply( + malSim_outs, function(output) { mean( output[ @@ -89,85 +137,127 @@ prev <- lapply( ) } ) - -# create dataframe of initial EIR, output EIR, and prev 2-10 results -EIR_prev <- cbind.data.frame(init_EIR, output_EIR = unlist(EIR), prev = unlist(prev)) + +# Create dataframe of initial EIR, output EIR, and prev 2-10 results +malSim_P2E <- cbind.data.frame(init_EIR, EIR = unlist(malSim_EIR), prev = unlist(malSim_prev)) ``` -Now plot your results! Code is included to compare the results of matching PfPR2-10 to EIR based on `malariaEquilibrium` (blue line) versus matching based on parameterized `malariasimulation` runs (red line). Notice that the generated points do not form a smooth curve. We ran `malariasimulation` using a population of just 5,000. Increasing the population to 10,000 or even 100,000 will generate more accurate estimates, but will take longer to run. +## *Pf*PR~2-10~ Matching using malariaEquilibrium + +We can also use the `malariaEquilibrium` package function `human_equilibrium()` to calculate the canonical equilibrium state of the system for a range of EIRs and match the *Pf*PR~2-10~ (see for more information). This method does not involve running simulations and is therefore faster, so we first generate a larger vector of EIR values to generate matching *Pf*PR~2-10~ values for, and then load the package's default parameter set. For each EIR value, we run the `human_equilibrium()` function and calculate the *Pf*PR~2-10~ from the output by summing the number of positive cases in ages 2-10 by the number of people in the age classes 2-10. Finally, we store the matching EIR and *Pf*PR~2-10~ values in a data frame. + +```{r} -```{r plot} -# calculate EIR / prev 2-10 relationship from malariaEquilibrium -eir <- seq(from = 0.1, to = 50, by=.5) -eq_params <- malariaEquilibrium::load_parameter_set("Jamie_parameters.rds") +# Establish a range of EIR values to generate matching PfPR2-10 values for +malEq_EIR <- seq(from = 0.1, to = 50, by = 0.5) -prev <- vapply( # calculate prevalence between 2:10 for a bunch of EIRs - eir, +# Load the base malariaSimulation parameter set: +eq_simparams <- malariaEquilibrium::load_parameter_set("Jamie_parameters.rds") + +# Use human_equilibrium to calculate the PfPR2-10 values for the range of +# EIR values +malEq_prev <- vapply( + malEq_EIR, function(eir) { eq <- malariaEquilibrium::human_equilibrium( eir, - ft=0, - p=eq_params, - age=0:100 + ft = 0, + p = eq_simparams, + age = 0:100 ) - sum(eq$states[2:10, 'pos_M']) / sum(eq$states[2:10, 'prop']) + sum(eq$states[3:11, 'pos_M']) / sum(eq$states[3:11, 'prop']) }, numeric(1) ) -prevmatch <- cbind.data.frame(eir, prev) +# Establish a dataframe containing the matching EIR and PfPR2-10 values +malEq_P2E <- cbind.data.frame(EIR = malEq_EIR, prev = malEq_prev) + +``` + +## Predicting *Pf*PR~2-10~ using Initial EIR + +Having run `malariasimulation` simulations for a range of initial EIRs, we can fit a line of best fit through the initial EIR and *Pf*PR~2-10~ data and use it to predict the prevalence for a wider range of initial EIRs (given the set of parameters used). + +```{r} -# calculate best fit line through malariasimulation data -fit <- predict(gam(prev~s(init_EIR, k=5), data=EIR_prev), - newdata = data.frame(init_EIR=c(0,seq(0.1,50,0.1))), type="response") -fit <- cbind(fit, data.frame(init_EIR=c(0,seq(0.1,50,0.1)))) +# Fit a line of best fit through malariasimulation initial EIR and prevalence +malSim_fit <- predict(gam(prev~s(init_EIR, k = 5), data = malSim_P2E), + newdata = data.frame(init_EIR = c(0, seq(0.1, 50, 0.1))), + type = "response") -# plot -plot(x=1, type = "n", +# Append vector of initial EIR values to model fit to establish dataframe +# for plotting +malSim_fit <- cbind(malSim_fit, data.frame(init_EIR = c(0 ,seq(0.1, 50, 0.1)))) + +``` + +## Visualisation + +Now lets visually compare our two methods for matching EIR to *Pf*PR~2-10~ values. In the section below we open a blank plot, plot the intial EIR and resulting *Pf*PR~2-10~ points generated using `malariasimulation` runs, overlay the line of best fit (orange line). Also overlayed is a line mapping EIR and *Pf*PR~2-10~ values calculated using `malariaEquilibrium` (blue line). + +```{r, fig.width = 6.8, fig.height = 4} + +# Establish a plotting window: +plot(x = 1, type = "n", frame = F, - xlab = "initial EIR", - ylab = expression(paste(italic(Pf),"PR"[2-10])), - xlim = c(0,50), - ylim = c(0,.7)) + xlab = "Initial EIR", ylab = expression(paste(italic(Pf),"PR"[2-10])), + xlim = c(0,50), ylim = c(0, 1), + xaxs = "i", yaxs = "i") -points(x=EIR_prev$init_EIR, - y=EIR_prev$prev, +# Overlay the initial EIR and corresponding PfPR2-10 points from malariasimulation +points(x= malSim_P2E$init_EIR, + y= malSim_P2E$prev, pch = 19, col = 'black') -lines(x=fit$init_EIR, - y=fit$fit, - col = "red", +# Overlay the malariasimulation line of best fit: +lines(x = malSim_fit$init_EIR, + y = malSim_fit$malSim_fit, + col = plot_cols[1], + lwd = 2, type = "l", lty = 1) -lines(x=prevmatch$eir, - y=prevmatch$prev, - col = "blue", - type = "l", +# Overlay the malariaEquilibrium Initial EIR to PfPR2-10 line +lines(x = malEq_P2E$EIR, + y = malEq_P2E$prev, + col = plot_cols[2], + type = "l", + lwd = 2, lty = 1) -legend("bottomright", legend=c("malariasimulation", "malariaEquilibrium"), col=c("red", "blue"), lty = c(1,1), cex=0.8) +# Add a legend +legend("topright", + legend=c("malariasimulation", "malariaEquilibrium"), + col=c(plot_cols[1:2]), lty = c(1,1), cex=0.8) ``` -Now extract values from the fitted line to generate EIR estimates at your desired PfPR2-10 values. +## Matching EIR to *Pf*PR~2-10~ values + +We can also create a function that extracts EIR values from the fitted line for *Pf*PR~2-10~ values of interest. The function works by finding the closest *Pf*PR~2-10~ value from the model fit to that specified by the user, and then using that index to return the corresponding EIR value. ```{r table, warning=F} -# Pre-intervention baseline PfPR2-10 starting at values 10, 25, 35, 55 -PfPR <- c(.10, .25, .35, .45) -# match via stat_smooth predictions -match <- function(x){ +# Store some pre-intervention baseline PfPR2-10 values +PfPRs_to_match <- c(.10, .25, .35, .45) + +# Create a function to these baseline PfPR2-10 values to EIR values using +# our model fit: +match_EIR_to_PfPR <- function(x){ - m <- which.min(abs(fit$fit-x)) # index of closest prev match - fit[m,2] # print match + m <- which.min(abs(malSim_fit$malSim_fit-x)) + malSim_fit[m,2] } -eir <- unlist(lapply(PfPR, match)) +# Use the function to extract the EIR values for the specified +# PfPR2-10 values: +matched_EIRs <- unlist(lapply(PfPRs_to_match, match_EIR_to_PfPR)) -cbind.data.frame(PfPR, eir) +# Create a dataframe of matched PfPR2-10 and EIR values: +cbind.data.frame(PfPR = PfPRs_to_match, Matched_EIR = matched_EIRs) ``` From 51777ee5470b53aac61559228505095a6dd3dd30 Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Tue, 16 May 2023 16:02:17 +0100 Subject: [PATCH 086/164] Added an introduction to the vignette and made some grammatical fixes --- vignettes/EIRprevmatch.Rmd | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/vignettes/EIRprevmatch.Rmd b/vignettes/EIRprevmatch.Rmd index 1dbc0022..2fa50227 100644 --- a/vignettes/EIRprevmatch.Rmd +++ b/vignettes/EIRprevmatch.Rmd @@ -15,7 +15,6 @@ knitr::opts_chunk$set( ``` ```{r setup, message=F, warning=F} - # Load in the requisite functions library(malariasimulation) library(malariaEquilibrium) @@ -27,10 +26,10 @@ plot_cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", ``` ## Introduction -The entomological inoculation rate (EIR), defined as the number of infectious bites experienced per person per unit time, malaria prevalence, the proportion of the population with detectable malaria, are two metrics used widely to describe malaria transmission and status within an affected population. With respect to the latter, focus is often given to prevalence in the age groups 2-10 years old, denoted *Pf*PR~2-10~, the prevalence rate of *Plasmodium falciparum* in children aged two to ten. -**Explanation for why a user might want to match *Pf*PR~2-10~ to EIR** +The entomological inoculation rate (EIR), defined as the number of infectious bites experienced per person per unit time, and malaria prevalence, the proportion of the population with detectable malaria, are two metrics commonly used to measure and/or describe malaria transmission. With respect to the latter, focus is often given to prevalence in the age groups 2-10 years old, denoted *Pf*PR~2-10~, the prevalence rate of *Plasmodium falciparum* in children aged two to ten. When setting up a simulation run, users often need to specify a baseline EIR or *Pf*PR~2-10~ . While `malariasimulation` enables users to set and and calibrate to an initial EIR (using the `set_equilibrium()` function), establishing a user-defined baseline *Pf*PR~2-10~ requires additional steps, outlined in this vignette. +Briefly, the user establishes their set of baseline parameters and runs simulations for a range of initial EIR values for a duration sufficient for the model to reach equilibrium. The equilibrial *Pf*PR~2-10~ is then extracted from the simulation outputs and a curve fit relating these values to the initial EIR. Using this curve, the user can then estimate the initial EIR value required to yield the desired *Pf*PR~2-10~ (given the parameter set). This method is contrasted with an alternative, which uses the `malariaEquilibrium` package's `human_equilibrium()` function to calculate the equilibrial *Pf*PR~2-10~ for a given EIR using the canonical equilibrium solution for the `malariasimulation` model. An alternative method, not covered here, is to calibrate the model using the `cali` package (see for more information). ## Parameterisation @@ -178,7 +177,7 @@ malEq_P2E <- cbind.data.frame(EIR = malEq_EIR, prev = malEq_prev) ## Predicting *Pf*PR~2-10~ using Initial EIR -Having run `malariasimulation` simulations for a range of initial EIRs, we can fit a line of best fit through the initial EIR and *Pf*PR~2-10~ data and use it to predict the prevalence for a wider range of initial EIRs (given the set of parameters used). +Having run `malariasimulation` simulations for a range of initial EIRs, we can fit a line of best fit through the initial EIR and *Pf*PR~2-10~ data and use it to predict the prevalence for a wider range of initial EIRs (given the set of parameters used). Note that the `newdata` argument is used to generate a series of additional initial EIR and *Pf*PR~2-10~ pairs for plotting. ```{r} @@ -207,8 +206,8 @@ plot(x = 1, type = "n", xaxs = "i", yaxs = "i") # Overlay the initial EIR and corresponding PfPR2-10 points from malariasimulation -points(x= malSim_P2E$init_EIR, - y= malSim_P2E$prev, +points(x = malSim_P2E$init_EIR, + y = malSim_P2E$prev, pch = 19, col = 'black') @@ -237,7 +236,7 @@ legend("topright", ## Matching EIR to *Pf*PR~2-10~ values -We can also create a function that extracts EIR values from the fitted line for *Pf*PR~2-10~ values of interest. The function works by finding the closest *Pf*PR~2-10~ value from the model fit to that specified by the user, and then using that index to return the corresponding EIR value. +We can also create a function that extracts EIR values from the fitted line for *Pf*PR~2-10~ values of interest. The function works by finding the closest *Pf*PR~2-10~ value from the model fit to that specified by the user, and then using that index to return the corresponding initial EIR value. ```{r table, warning=F} From ab98ffc4c38b919b2176b631892efb2ef6243d68 Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Tue, 16 May 2023 16:37:11 +0100 Subject: [PATCH 087/164] Made grammatical corrections to the vignette --- vignettes/MDA.Rmd | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/vignettes/MDA.Rmd b/vignettes/MDA.Rmd index c3299116..15a14bf9 100644 --- a/vignettes/MDA.Rmd +++ b/vignettes/MDA.Rmd @@ -25,17 +25,17 @@ plot_cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", ## Introduction -Malaria chemoprevention encompasses a suite of strategies for reducing malaria morbidity, mortality, and transmission through the treatment of at-risk populations with antimalarial drugs. Three such strategies are mass drug administration (MDA), seasonal malaria chemoprevention (SMC), and perennial malaria chemoprevention (PMC). MDA attempts to simultaneously treat an entire population, irrespective of their infection risk or status. SMC targets children aged 3-59 months with a course of an antimalarial through the peak malaria transmission season. PMC is designed for settings with perennially high transmission and seeks to administer a full antimalarial course at defined intervals irrespective of age or disease status. +Malaria chemoprevention encompasses a suite of strategies for reducing malaria morbidity, mortality, and transmission through the treatment of at-risk populations with antimalarial drugs. Three such strategies are mass drug administration (MDA), seasonal malaria chemoprevention (SMC), and perennial malaria chemoprevention (PMC). MDA attempts to simultaneously treat an entire population, irrespective of their infection risk or status. SMC targets children aged 3-59 months with a course of an antimalarials through the peak malaria transmission season. PMC is designed for settings with perennially high transmission and seeks to administer a full antimalarial course at defined intervals irrespective of age or disease status. -`malariasimulation` enables users to simulate the effects of chemoprevention strategies on malaria transmission, and provides the flexibility to design and simulate a range of MDA/SMC/PMC campaigns for a suite of antimalarial drugs. Specifically, users are able to specify parameters describing both the characteristics of the antimalarial(s) (e.g. drug efficacy, prophylactic profile) and their distribution (e.g. coverage, distribution timing, and the section of the population to treat). This vignette provides simple, illustrative demonstrations of how MDA and SMC campaigns can be set-up and simulated using `malariasimulation`. **The functionality to simulate PMC campaigns is also built into `malariasimulation`, but we do not demonstrate that here (*can add*).** +`malariasimulation` enables users to simulate the effects of chemoprevention strategies on malaria transmission, and provides the flexibility to design and simulate a range of MDA/SMC/PMC campaigns for a suite of antimalarial drugs. Specifically, users are able to load or specify parameters describing both the characteristics of the antimalarial(s) (e.g. drug efficacy, prophylactic profile) and their distribution (e.g. coverage, distribution timing, and the section of the population to treat). This vignette provides simple, illustrative demonstrations of how MDA and SMC campaigns can be set-up and simulated using `malariasimulation`. The functionality to simulate PMC campaigns is also built into `malariasimulation`, but we do not demonstrate that here. ## Mass Drug Administration -To illustrate how MDA can be simulated using `malariasimulation` , we will implement a campaign that distributes a single dose of sulphadoxine-pyrimethamine amodiaquine (SP-AQ) to 80% of the entire population once a year over a two year period, initiated at the end of the first year. +To illustrate how MDA can be simulated using `malariasimulation`, we will implement a campaign that distributes a single dose of sulphadoxine-pyrimethamine amodiaquine (SP-AQ) to 80% of the entire population once a year over a two year period, initiated at the end of the first year. ### Parameterisation -The first step is to generate the list of requisite parameters using the `get_parameters()` function. Here, we'll use the default `malariasimulation` parameter set (run `?get_parameters()` to view), but specify the seasonality parameters to simulate a bimodal rainfall pattern (see plot of adult female mosquitoes below). To do this, we set `model_seasonality` to TRUE within `get_parameters()`, and then tune the rainfall pattern using the `g0`, `g`, and `h` parameters (which represent fourier coefficients) to generate the seasonal rainfall profile. Rainfall governs the time-varying mosquito population carrying capacity through density-dependent regulation and, therefore, annual patterns of malaria transmission. Next, we use the `set_equilibrium()` function to tune the initial human and mosquito populations to those required to observe the specified initial EIR. +The first step is to generate the list of `malariasimulation` parameters using the `get_parameters()` function. Here, we'll use the default `malariasimulation` parameter set (run `?get_parameters()` to view), but specify the seasonality parameters to simulate a bimodal rainfall pattern (illustrated in the plot of adult female mosquito population dynamics below). To do this, we set `model_seasonality` to TRUE within `get_parameters()`, and then tune the rainfall pattern using the `g0`, `g`, and `h` parameters (which represent fourier coefficients) to generate the seasonal rainfall profile. In the `malariasimulation` model, rainfall governs the time-varying mosquito population carrying capacity through density-dependent regulation and, therefore, annual patterns of malaria transmission. Next, we use the `set_equilibrium()` function to tune the initial human and mosquito populations to those required to observe the specified initial EIR. ```{r} # Establish the length of time over which to simulate: @@ -68,9 +68,7 @@ simparams <- set_equilibrium(simparams, starting_EIR) Having established a base set of parameters (`simparams`), the next step is to add the parameters specifying the MDA campaign. We first use the `get_drugs()` function to update `simparams` with the parameter values for the drug(s) we wish to simulate, in this case using the in-built parameter set for SP-AQ. Note that the `malariasimulation` package also contains in-built parameter sets for dihydroartemisinin-piperaquine (DHA_PQP_params) and artemether lumefantrine (AL_params), and users can also define their own drug parameters. -**Re-Add explanatnion of drug parameters** - -We then define the dates on which we want the MDA (stored here in the vector `mda_events` for legibility), and use the `set_mda()` function to update the parameter list with our MDA campaign parameters. `set_mda()` takes as its first two arguments the base parameter list and the time steps on which to schedule MDA events. This function also requires the user to specify the proportion of the population we want to treat using `coverages`, as well as the age-range of the population we want to treat using `min_ages` and `max_ages`, *for each day of scheduled MDA*. Note that this enables users to specify individual events to have different properties. The `drug` argument refers to the index of the drug we want to distribute in the MDA in the list of parameters (in this demonstration we have only added a single drug, SP-AQ, using `set_drugs()`, but we could have specified additional drugs). +We then define the dates on which we want the MDA to occur (stored here in the vector `mda_events` for legibility), and use the `set_mda()` function to update the parameter list with our MDA campaign parameters. `set_mda()` takes as its first two arguments the base parameter list and the time steps on which to schedule MDA events. This function also requires the user to specify the proportion of the population we want to treat using `coverages`, as well as the age-range of the population we want to treat using `min_ages` and `max_ages`, *for each day of scheduled MDA*. Note that this enables users to specify individual events to have different drug. coverage, and human-target properties. The `drug` argument refers to the index of the drug we want to distribute in the MDA in the list of parameters (in this demonstration we have only added a single drug, SP-AQ, using `set_drugs()`, but we could have specified additional drugs). ```{r} @@ -108,7 +106,7 @@ mda_output <- run_simulation(sim_length, mdaparams) ### Visualisation -The `run_simulation()` function returns a dataframe containing time series for a range of variables, including the number of human individuals in each infectious state, and the number of people and detected cases in children aged 2-10. The plots below illustrate how the effect of an MDA campaign on the malaria transmission dynamics can be visualised. The first presents the distribution of people in the amongt the infectious states. The second compares the prevalence of malaria in children aged 2-10 years old (*Pf*PR~2-10~) between the no-intervention and MDA scenarios simulated. +The `run_simulation()` function returns a dataframe containing time series for a range of variables, including the number of human individuals in each infectious state, and the number of people and detected cases in children aged 2-10. The plots below illustrate how the effect of an MDA campaign on the malaria transmission dynamics can be visualised. The first presents the distribution of people among the infectious states in the MDA simulation. The second compares the prevalence of malaria in children aged 2-10 years old (*Pf*PR~2-10~) between the no-intervention and MDA scenarios simulated. ```{r, fig.width=7.2, fig.height=4, fig.fullwidth=TRUE} @@ -178,7 +176,7 @@ legend(x = 870, y = 0.99, ## Seasonal Malaria Chemoprevention -To demonstrate how to simulate SMC in `malariasimulation` , in the following section we'll set-up and simulate a campaign that treats 80% of children aged 3-59 months old with four doses of SP-AQ per year. We will set the SMC campaign to begin in the second year, run for two years, and target the four SMC events to at monthly intervals, starting a month prior to the peak malaria season. +To demonstrate how to simulate SMC in `malariasimulation` , in the following section we'll set-up and simulate a campaign that treats 80% of children aged 3-59 months old with four doses of SP-AQ per year. We will set the SMC campaign to begin in the second year, run for two years, and specify the four SMC events to occur at monthly intervals, starting a month prior to the peak malaria season. ### Interventions From 367ad1c132c3d2d3802b7835626be17e54e6122d Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Tue, 16 May 2023 17:51:22 +0100 Subject: [PATCH 088/164] Made some improvements to the textual explanations --- vignettes/Demography.Rmd | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/vignettes/Demography.Rmd b/vignettes/Demography.Rmd index cf76b0a5..7536d641 100644 --- a/vignettes/Demography.Rmd +++ b/vignettes/Demography.Rmd @@ -21,15 +21,15 @@ library(malariasimulation) # Introduction -The dynamics of malaria transmission, and the efficacy of interventions designed to interrupt it, are highly context specific and an important consideration is the demography of the population(s) under investigation. To suit the research needs of the user, `malariasimulation` allows for the specification of custom human population demographics by allowing them to specify age-group specific death rates parameters. It also enables users to instruct the model to render output(s) with variables of interest (e.g. human population, number of cases detectable by microscopy, number of severe cases, etc.) presented by user-defined age groups. In this vignette we'll use simple, illustrative cases to demonstrate how to customise the output rendered by the `run_simulation()` function, specify a custom death rates, and, specify time-varying death rates. +The dynamics of malaria transmission, and the efficacy of interventions designed to interrupt it, are highly context specific and an important consideration is the demography of the population(s) under investigation. To suit the research needs of the user, `malariasimulation` allows for the specification of custom human population demographics by allowing them to specify age-group specific death rates parameters. It also enables users to instruct the model to render outputs with variables of interest (e.g. human population, number of cases detectable by microscopy, number of severe cases, etc.) presented by user-defined age groups. In this vignette we'll use simple, illustrative cases to demonstrate how to customise the output rendered by the `run_simulation()` function, specify both fixed and time-varying custom death rates. # Specifying human death rates by age group -The `malariasimulation` package allows users to capture different human population demographies by specifying age-specific death rates. In the first section, we'll demonstrate how to instruct the model to output population and disease metrics by user-defined age groups and how to establish and run simulations with age-specific death rates. We'll illustrate the effect this has by comparing the demographic make-up of this custom parameterisation with that produced using the default parameters. +The `malariasimulation` package allows users to capture different human population demographies by specifying age-specific death rates. In the first section, we'll demonstrate how to instruct the model to output population and disease metrics by user-defined age groups and how to establish and run simulations with age-specific death rates. We'll illustrate the effect this has by comparing the demographic make-up of this custom parameterisation with that produced using the demographic profile established by the default parameters. ## Default Parameterisation -First, we'll establish a base set of parameters using the `get_parameters()` function and accepting the default values. The `run_simulation()` function's default behaviour is to output only the number of individuals aged 2-10 years old (`output$n_730_3650`). However, the user can instruct the model to output the number of individuals in age groups of their choosing using the `age_group_rendering_min_ages` and `age_group_rendering_max_ages` parameters. These arguments take vectors containing the minimum and maximum ages (in daily time steps) of the groups to be captured. To allow us to see the effect of changing demographic parameters, we'll use this functionality to output the number of individuals in ages groups ranging from 0 to 85 at 5 year intervals. Note that the same is possible for other model outputs, including the number (`n_detect` , `p_detect`, `n_severe`, `n_inc`, `p_inc`, `n_inc_clinical`, `p_inc_clinical`, `n_inc_severe`, and `p_inc_severe` ) using their equivalent min/max age-class rendering arguments (run `?run_simulation()` for more detail). +First, we'll establish a base set of parameters using the `get_parameters()` function and accepting the default values. The `run_simulation()` function's default behaviour is to output only the number of individuals aged 2-10 years old (`output$n_730_3650`, where 730 and 3650 are the ages in days). However, the user can instruct the model to output the number of individuals in age groups of their choosing using the `age_group_rendering_min_ages` and `age_group_rendering_max_ages` parameters. These arguments take vectors containing the minimum and maximum ages (in daily time steps) of each group to be captured. To allow us to see the effect of changing demographic parameters, we'll use this functionality to output the number of individuals in ages groups ranging from 0 to 85 at 5 year intervals. Note that the same is possible for other model outputs, including the number (`n_detect` , `p_detect`, `n_severe`, `n_inc`, `p_inc`, `n_inc_clinical`, `p_inc_clinical`, `n_inc_severe`, and `p_inc_severe` ) using their equivalent min/max age-class rendering arguments (run `?run_simulation()` for more detail). We next use the `set_equilibrium()` function to tune the initial parameter set to that required to observe the specified initial entomological inoculation rate (`starting_EIR`). We now have a set of default parameters ready to use to run simulations. @@ -62,7 +62,7 @@ simparams <- set_equilibrium(simparams, starting_EIR) ## **Custom Demographic Parameterisation** -Next, we'll use the the in-built `set_demography()` function to specify human death rates by age group. This function takes as inputs a parameter list to update, a vector of the age groups (in days) for which we specify death rates, a vector of time steps in which we want the death rates to be updated, and a matrix containing the death rates for each age group in each timestep. The `set_demography()` function appends these to the parameter list and updates the `custom_demography` parameter to `TRUE`. +Next, we'll use the the in-built `set_demography()` function to specify human death rates by age group. This function accepts as inputs a parameter list to update, a vector of the age groups (in days) for which we specify death rates, a vector of time steps in which we want the death rates to be updated, and a matrix containing the death rates for each age group in each timestep. The `set_demography()` function appends these to the parameter list and updates the `custom_demography` parameter to `TRUE`. ```{r} @@ -111,14 +111,14 @@ custom_output$run <- 'custom' ## Visualisation -Using barplots, we can visualise the effect of altering the demographic parameters by comparing the distribution of people among the age-classes we instructed the model to output. The default parameterisation. +Using barplots, we can visualise the effect of altering the demographic parameters by comparing the distribution of people among the age-classes we instructed the model to output on the final day of the simulation. The default demography is depicted in blue, while the custom demography is given in orange. Under the custom demography, the frequency in individuals in older age classes declines almost linearly, while in the default demography the number of individuals in each age class declines exponentially with age. ```{r, fig.width = 7.2, fig.height = 4, fig.fullwidth = TRUE} # Combine the two dataframes: dem_output <- rbind(exp_output, custom_output) -# Select the final day of the simulation for each of the two demography runs: +# Subset the final day of the simulation for each of the two demography runs: dem_output <- dem_output[dem_output$timestep == 5 * 365,] # Extract the age variables and convert the dataframe to long format: @@ -172,7 +172,7 @@ barplot(height = dem_output[dem_output$run == "custom", c("n", "age_plot")]$n, # Dynamic demography: time-varying death rates -Using the `timesteps` and `deathrates` arguments, we can also use the `set_demography()` function to update the death rates of specific age groups through time. In the following example, we'll use this functionality to first set our own initial death rates by age group, then instruct the model to increase the death rates in the age groups 5-10, 10-15, and 15-20 years old by a factor of 10. We'll finish by plotting the number of individuals in each age class at the end of each year to visualise the effect of time-varying death rates on the human population age-structure. +Using the `timesteps` and `deathrates` arguments, we can also use the `set_demography()` function to update the death rates of specific age groups through time. In the following example, we'll use this functionality to first set our own initial death rates by age group, then instruct the model to increase the death rates in the age groups 5-10, 10-15, and 15-20 years old by a factor of 10 after 2 years. We'll finish by plotting the number of individuals in each age class at the end of each year to visualise the effect of time-varying death rates on the human population age-structure. ## Parameterisation @@ -198,6 +198,7 @@ dyn_dem_params <- set_demography( ``` ## Simulations +Having established the parameter list for the dynamic death rate simulation, we can now run the simulation using the `run_simulation()` function. ```{r} # Run the simulation for the dynamic death rate demography From 1a342a7a2f882e627b22cf544a9706c864a1acdd Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Tue, 16 May 2023 18:04:50 +0100 Subject: [PATCH 089/164] Type corrected --- vignettes/Demography.Rmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vignettes/Demography.Rmd b/vignettes/Demography.Rmd index 7536d641..c9d23855 100644 --- a/vignettes/Demography.Rmd +++ b/vignettes/Demography.Rmd @@ -197,7 +197,7 @@ dyn_dem_params <- set_demography( ``` -## Simulations +## Simulation Having established the parameter list for the dynamic death rate simulation, we can now run the simulation using the `run_simulation()` function. ```{r} @@ -208,7 +208,7 @@ dyn_dem_output <- run_simulation(sim_length, dyn_dem_params) ## Visualisation -Boxplots of the age structure of the human population at the end of each year show the marked effect that increasing the death rate within a small subset of age classes can have on the demography of the human population over time. +Bar plots of the age structure of the human population at the end of each year show the marked effect that increasing the death rate within a small subset of age classes can have on the demography of the human population over time. ```{r, fig.width = 7.2, fig.height = 3, fig.fullwidth = TRUE} From 736bb3606a0bf6a826abeba801bb5c872f3e92d6 Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Tue, 30 May 2023 15:02:13 +0100 Subject: [PATCH 090/164] I have updated the vignette to implement the changes requested on the pull request, as well as correcting some additional typographical errors. --- vignettes/MDA.Rmd | 84 +++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/vignettes/MDA.Rmd b/vignettes/MDA.Rmd index 15a14bf9..5a980cb5 100644 --- a/vignettes/MDA.Rmd +++ b/vignettes/MDA.Rmd @@ -16,18 +16,15 @@ knitr::opts_chunk$set( ```{r setup} # Load the requisite packages: -library(malariasimulation); library(malariaEquilibrium) - -# Define a colour palette for plotting: -plot_cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") +library(malariasimulation) ``` ## Introduction -Malaria chemoprevention encompasses a suite of strategies for reducing malaria morbidity, mortality, and transmission through the treatment of at-risk populations with antimalarial drugs. Three such strategies are mass drug administration (MDA), seasonal malaria chemoprevention (SMC), and perennial malaria chemoprevention (PMC). MDA attempts to simultaneously treat an entire population, irrespective of their infection risk or status. SMC targets children aged 3-59 months with a course of an antimalarials through the peak malaria transmission season. PMC is designed for settings with perennially high transmission and seeks to administer a full antimalarial course at defined intervals irrespective of age or disease status. +Malaria chemoprevention encompasses a suite of strategies for reducing malaria morbidity, mortality, and transmission through the treatment of at-risk populations with antimalarial drugs. Three such strategies are mass drug administration (MDA), seasonal malaria chemoprevention (SMC), and perennial malaria chemoprevention (PMC). MDA attempts to simultaneously treat an entire population, irrespective of their infection risk or status. SMC targets children aged 3-59 months with a course of an antimalarial through the peak malaria transmission season. PMC is designed for settings with perennially high transmission and seeks to administer a full antimalarial course at defined intervals irrespective of age or disease status. -`malariasimulation` enables users to simulate the effects of chemoprevention strategies on malaria transmission, and provides the flexibility to design and simulate a range of MDA/SMC/PMC campaigns for a suite of antimalarial drugs. Specifically, users are able to load or specify parameters describing both the characteristics of the antimalarial(s) (e.g. drug efficacy, prophylactic profile) and their distribution (e.g. coverage, distribution timing, and the section of the population to treat). This vignette provides simple, illustrative demonstrations of how MDA and SMC campaigns can be set-up and simulated using `malariasimulation`. The functionality to simulate PMC campaigns is also built into `malariasimulation`, but we do not demonstrate that here. +`malariasimulation` enables users to simulate the effects of chemoprevention strategies on malaria transmission, and provides the flexibility to design and simulate a range of MDA/SMC/PMC campaigns for a suite of antimalarial drugs. Specifically, users are able to load or specify parameters describing both the characteristics of the antimalarial(s) (e.g. drug efficacy, prophylactic profile) and their distribution (e.g. coverage, distribution timing, and the section of the population to treat). This vignette provides simple, illustrative demonstrations of how MDA and SMC campaigns can be set-up and simulated using `malariasimulation`. The functionality to simulate PMC campaigns is also built into `malariasimulation`, but we do not demonstrate the use of PMC in this vignette (for further information on their use, see https://mrc-ide.github.io/malariasimulation/reference/set_pmc.html). ## Mass Drug Administration @@ -35,11 +32,11 @@ To illustrate how MDA can be simulated using `malariasimulation`, we will implem ### Parameterisation -The first step is to generate the list of `malariasimulation` parameters using the `get_parameters()` function. Here, we'll use the default `malariasimulation` parameter set (run `?get_parameters()` to view), but specify the seasonality parameters to simulate a bimodal rainfall pattern (illustrated in the plot of adult female mosquito population dynamics below). To do this, we set `model_seasonality` to TRUE within `get_parameters()`, and then tune the rainfall pattern using the `g0`, `g`, and `h` parameters (which represent fourier coefficients) to generate the seasonal rainfall profile. In the `malariasimulation` model, rainfall governs the time-varying mosquito population carrying capacity through density-dependent regulation and, therefore, annual patterns of malaria transmission. Next, we use the `set_equilibrium()` function to tune the initial human and mosquito populations to those required to observe the specified initial EIR. +The first step is to generate the list of `malariasimulation` parameters using the `get_parameters()` function. Here, we'll use the default `malariasimulation` parameter set (run `?get_parameters()` to view), but specify the seasonality parameters to simulate a highly seasonal, unimodal rainfall pattern (illustrated in the plot of total adult female mosquito population dynamics below). To do this, we set `model_seasonality` to TRUE within `get_parameters()`, and then tune the rainfall pattern using the `g0`, `g`, and `h` parameters (which represent fourier coefficients). In the `malariasimulation` model, rainfall governs the time-varying mosquito population carrying capacity through density-dependent regulation of the larval population and, therefore, annual patterns of malaria transmission. Next, we use the `set_equilibrium()` function to tune the initial human and mosquito populations to those required to observe the specified initial EIR. ```{r} -# Establish the length of time over which to simulate: -# Set the simulation duration + +# Establish the length of time, in daily time steps, over which to simulate: year <- 365; years <- 3 sim_length <- years * year @@ -47,35 +44,37 @@ sim_length <- years * year human_population <- 1000 starting_EIR <- 50 -# Use the simparams() function to build the list of simulation parameters +# Use the simparams() function to build the list of simulation parameters and then specify +# a seasonal profile with a single peak using the g0, g, and h parameters. simparams <- get_parameters( list( human_population = human_population, - model_seasonality = TRUE, # Let's try a bi-modal model - g0 = 0.28605, - g = c(0.20636, -0.0740318, -0.0009293), - h = c(0.173743, -0.0730962, -0.116019) + model_seasonality = TRUE, + g0 = 0.284596, + g = c(-0.317878,-0.0017527,0.116455), + h = c(-0.331361,0.293128,-0.0617547) ) ) # Use the set_equilibrium() function to update the individual-based model parameters to those -# required to match the specified initial EIR (starting_EIR): +# required to match the specified initial EIR (starting_EIR) at equilibrium: simparams <- set_equilibrium(simparams, starting_EIR) ``` ### Interventions -Having established a base set of parameters (`simparams`), the next step is to add the parameters specifying the MDA campaign. We first use the `get_drugs()` function to update `simparams` with the parameter values for the drug(s) we wish to simulate, in this case using the in-built parameter set for SP-AQ. Note that the `malariasimulation` package also contains in-built parameter sets for dihydroartemisinin-piperaquine (DHA_PQP_params) and artemether lumefantrine (AL_params), and users can also define their own drug parameters. +Having established a base set of parameters (`simparams`), the next step is to add the parameters specifying the MDA campaign. We first use the `set_drugs()` function to update the parameter list (`simparams`) with the parameter values for the drug(s) we wish to simulate, in this case using the in-built parameter set for SP-AQ. Note that the `malariasimulation` package also contains in-built parameter sets for dihydroartemisinin-piperaquine (DHA_PQP_params) and artemether lumefantrine (AL_params), and users can also define their own drug parameters. -We then define the dates on which we want the MDA to occur (stored here in the vector `mda_events` for legibility), and use the `set_mda()` function to update the parameter list with our MDA campaign parameters. `set_mda()` takes as its first two arguments the base parameter list and the time steps on which to schedule MDA events. This function also requires the user to specify the proportion of the population we want to treat using `coverages`, as well as the age-range of the population we want to treat using `min_ages` and `max_ages`, *for each day of scheduled MDA*. Note that this enables users to specify individual events to have different drug. coverage, and human-target properties. The `drug` argument refers to the index of the drug we want to distribute in the MDA in the list of parameters (in this demonstration we have only added a single drug, SP-AQ, using `set_drugs()`, but we could have specified additional drugs). +We then define the time steps on which we want the MDA to occur (stored here in the vector `mda_events` for legibility), and use the `set_mda()` function to update the parameter list with our MDA campaign parameters. `set_mda()` takes as its first two arguments the base parameter list and the time steps on which to schedule MDA events. This function also requires the user to specify the proportion of the population they want to treat using `coverages`, as well as the age-range of the population we want to treat using `min_ages` and `max_ages`, *for each timestep on which MDA is scheduled*. Note that this enables users to specify individual events to have different drug, coverage, and human-target properties. The `drug` argument refers to the index of the drug we want to distribute in the MDA in the list of parameters (in this demonstration we have only added a single drug, SP-AQ, using `set_drugs()`, but we could have specified additional drugs). ```{r} # Make a copy of the base simulation parameters to which we can add the MDA campaign parameters: mdaparams <- simparams -# Update the parameter list with the default parameters for sulphadoxine-pyrimethamine amodiaquine (SP-AQ) +# Update the parameter list with the default parameters for sulphadoxine-pyrimethamine +# amodiaquine (SP-AQ) mdaparams <- set_drugs(mdaparams, list(SP_AQ_params)) # Specify the days on which to administer the SP-AQ @@ -114,6 +113,9 @@ The `run_simulation()` function returns a dataframe containing time series for a states <- c("S_Count", "D_count", "Tr_count", "A_count", "U_count") state_labels <- c("S", "D", "Tr", "A", "U") +# Define a colour palette for plotting: +plot_cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") + # Open a new plotting window: plot.new(); par(mar = c(4, 4, 1, 1), new = TRUE) @@ -129,13 +131,13 @@ for(i in 1:(length(states)-1)) { } # Add vlines to show when SP-AQ was administered: -abline(v = mda_events, lty = "dashed", lwd = 1) +abline(v = mda_events, lty = "dashed", lwd = 1.5) # Add gridlines: grid(lty = 1, col = "darkgrey", nx = NULL, ny = NULL, lwd = 0.5); box() # Add a legend: -legend(x = 930, y = 840, +legend(x = 20, y = 840, legend = c(state_labels, "MDA"), col = c(plot_cols[1:5], "black"), lty = c(rep(1, 5), 2), lwd = 1, cex = 0.8, box.col = "white") @@ -167,7 +169,7 @@ abline(v = mda_events, lty = "dashed", lwd = 1) grid(lty = 1, col = "darkgrey", nx = NULL, ny = NULL, lwd = 0.5); box() # Add a legend: -legend(x = 870, y = 0.99, +legend(x = 20, y = 0.99, legend = c("MDA", "No-Int", "MDA Day"), col= c(plot_cols[3:4], "black"), box.col = "white", lwd = 1, lty = c(1, 1, 2), cex = 0.8) @@ -176,15 +178,11 @@ legend(x = 870, y = 0.99, ## Seasonal Malaria Chemoprevention -To demonstrate how to simulate SMC in `malariasimulation` , in the following section we'll set-up and simulate a campaign that treats 80% of children aged 3-59 months old with four doses of SP-AQ per year. We will set the SMC campaign to begin in the second year, run for two years, and specify the four SMC events to occur at monthly intervals, starting a month prior to the peak malaria season. +To demonstrate how to simulate SMC in `malariasimulation` , in the following section we'll set-up and simulate a campaign that treats 80% of children aged 3-59 months old with four doses of SP-AQ per year. We will set the SMC campaign to begin in the second year, run for two years, and specify the four SMC events to occur at monthly intervals, starting two months prior to the peak malaria season. ### Interventions -While the first step would typically be to establish the base set of parameters, we can use those stored earlier in `simparams`. We first store a copy of these base parameters and then use `set_drugs()` to store the preset parameters for SP-AQ in the parameter list. - -As SMC is conducted during the peak malaria season, we need to use the `peak_season_offset()` function to determine when the peak malaria season occurs given our specified seasonal profile. This function reads in the parameter list, uses `g0`, `g`, `h`, and `rainfall_floor` to generate the rainfall profile for a single year, and returns the day on which the maximum value occurs. We can then take this calculated seasonal peak and time SMC events around it. Here, we've specified four monthly drug administration days per year starting one month before the seasonal peak. - -To illustrate this, we can plot the total adult mosquito population size through time, which in the absence of interventions targeting mosquitoes will closely matches the rainfall pattern, and overlay both the annual seasonal peak and planned SMC events. Once we're happy with our SMC campaign, we use the `set_smc()` function to update the parameter list with our `drug`, `timesteps`, `coverages` and target age group (`min_ages` and `max_ages`). +While the first step would typically be to establish the base set of parameters, we can use those stored earlier in `simparams`. We first store a copy of these base parameters and then use `set_drugs()` to store the preset parameters for SP-AQ in the parameter list. As SMC is conducted during the peak malaria season, we need to use the `peak_season_offset()` function to determine when the peak malaria season occurs given our specified seasonal profile. This function reads in the parameter list, uses `g0`, `g`, `h`, and `rainfall_floor` to generate the rainfall profile for a single year, and returns the day on which the maximum rainfall value occurs. We can then take this calculated seasonal peak and time SMC events around it. Here, we've specified four monthly drug administration days per year starting two months before the seasonal peak. To illustrate this, we can plot the total adult mosquito population size through time which, in the absence of interventions targeting mosquitoes, will closely matches the rainfall pattern, and overlay both the annual seasonal peak and planned SMC events. Once we're happy with our SMC campaign, we use the `set_smc()` function to update the parameter list with our `drug`, `timesteps`, `coverages` and target age group (`min_ages` and `max_ages`). ```{r, fig.width=7.2, fig.height=4, fig.fullwidth=TRUE} @@ -199,17 +197,22 @@ smcparams <- set_drugs(smcparams, list(SP_AQ_params)) peak <- peak_season_offset(smcparams) # Create a variable for total mosquito population through time: -noint_output$mosq_total = noint_output$Sm_All_count + noint_output$Im_All_count + noint_output$Pm_All_count +noint_output$mosq_total = noint_output$Sm_All_count + + noint_output$Im_All_count + + noint_output$Pm_All_count -# Set-up the times (in days) around the peak to schedule drug administration days: -admin_days <- c(-30, 0, 30, 60) +# Schedule drug administration times (in daily time steps) before, during and after the seasonal peak: +admin_days <- c(-60, -30, 0, 30) # Use the peak-offset, number of simulation years and number of drug admin. days to calculate the days # on which to administer drugs in each year smc_days <- rep((365 * seq(1, years-1, by = 1)), each = length(admin_days)) + peak + rep(admin_days, 2) -# Plot the total adult mosquito population through time: -# Open a new plotting window,set the margins and plot the mosquito population +# Turn off scientific notation for the plot: +options(scipen = 666) + +# Open a new plotting window,set the margins and plot the total adult female mosquito population +# through time: plot.new(); par(new = TRUE, mar = c(4, 4, 1, 1)) plot(x = noint_output$timestep, y = noint_output$mosq_total, xlab = "Time (days)", ylab = "Adult Female Mosquitos", @@ -218,7 +221,7 @@ plot(x = noint_output$timestep, y = noint_output$mosq_total, xaxs = "i", yaxs = "i", col = plot_cols[3]) -# Add grinlines +# Add gridlines grid(lty = 1, col = "darkgrey", nx = 11, ny = NULL, lwd = 0.5); box() # Overlay the SMC days and the calculated seasonal peak @@ -226,8 +229,9 @@ abline(v = smc_days, lty = "dashed", lwd = 2) abline(v = c(0, 1, 2) * 365 + peak, lty = 2, lwd = 2, col = plot_cols[4]) # Add a legend: -legend(x = (sim_length * 0.83), y = 61000, - legend = c(expression("M"["Tot"]), "MDA", "Peak"), +legend(legend = c(expression("M"["Tot"]), "MDA", "Peak"), + #x = (sim_length * 0.83), y = 61000, + x = (sim_length * 0.01), y = max(noint_output$mosq_total)*1.05, col= c(plot_cols[3], "black", plot_cols[4]), box.col = "white", lty = c(1, 2, 2), lwd = 2, cex = 0.9) @@ -255,7 +259,7 @@ smc_output <- run_simulation(sim_length, smcparams) ### Visualisation -We can now plot the model output to get an idea of the effect of our SMC campaign on malaria transmission dynamics, again focusing on the distribution of people in each of the infectious states and on malaria prevalence in children aged 2-10 (*Pf*PR~2-10~). +We can now plot the simulation output to visualise the effect of our SMC campaign on malaria transmission dynamics, again focusing on the distribution of people in each of the infectious states and on malaria prevalence in children aged 2-10 (*Pf*PR~2-10~). ```{r, fig.width=7.2, fig.height=4, fig.fullwidth=TRUE} @@ -280,7 +284,7 @@ abline(v = smc_days, lty = "dashed", lwd = 1) grid(lty = 1, col = "darkgrey", nx = NULL, ny = NULL, lwd = 0.5) # Add a legend: -legend(x = 920, y = 840, +legend(x = 20, y = 840, legend = c(state_labels, "SMC"), col = c(plot_cols[1:5], "black"), lty = c(rep(1, 5), 2), box.col = "white", lwd = 2, cex = 0.9) @@ -292,7 +296,7 @@ legend(x = 920, y = 840, # Open a new plotting window and add a grid: plot.new(); par(new = TRUE, mar = c(4, 4, 1, 1)) -# Recreate figure 2: +# Plot malaria prevalence in 2-10 years through time: plot(x = smc_output$timestep, y = smc_output$n_detect_730_3650/smc_output$n_730_3650, xlab = "Time (days)", ylab = expression(paste(italic(Pf),"PR"[2-10])), cex = 0.8, @@ -311,9 +315,9 @@ abline(v = smc_days, lty = "dashed", lwd = 1) grid(lty = 1, col = "darkgrey", nx = 11, ny = 10, lwd = 0.5) # Add a legend: -legend(x = 870, y = 0.99, +legend(x = 20, y = 0.99, legend = c("SMC", "No-Int", "SMC Day"), col= c(plot_cols[3:4], "black"), box.col = "white", lwd = 1, lty = c(1, 1, 2), cex = 0.8) -``` +``` \ No newline at end of file From 344c424de67394f58ababe0c97ec4d26753469e8 Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Tue, 30 May 2023 15:11:10 +0100 Subject: [PATCH 091/164] Updated paragraph two to explicitly reference the set_pmc function --- vignettes/MDA.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/MDA.Rmd b/vignettes/MDA.Rmd index 5a980cb5..1f9201c2 100644 --- a/vignettes/MDA.Rmd +++ b/vignettes/MDA.Rmd @@ -24,7 +24,7 @@ library(malariasimulation) Malaria chemoprevention encompasses a suite of strategies for reducing malaria morbidity, mortality, and transmission through the treatment of at-risk populations with antimalarial drugs. Three such strategies are mass drug administration (MDA), seasonal malaria chemoprevention (SMC), and perennial malaria chemoprevention (PMC). MDA attempts to simultaneously treat an entire population, irrespective of their infection risk or status. SMC targets children aged 3-59 months with a course of an antimalarial through the peak malaria transmission season. PMC is designed for settings with perennially high transmission and seeks to administer a full antimalarial course at defined intervals irrespective of age or disease status. -`malariasimulation` enables users to simulate the effects of chemoprevention strategies on malaria transmission, and provides the flexibility to design and simulate a range of MDA/SMC/PMC campaigns for a suite of antimalarial drugs. Specifically, users are able to load or specify parameters describing both the characteristics of the antimalarial(s) (e.g. drug efficacy, prophylactic profile) and their distribution (e.g. coverage, distribution timing, and the section of the population to treat). This vignette provides simple, illustrative demonstrations of how MDA and SMC campaigns can be set-up and simulated using `malariasimulation`. The functionality to simulate PMC campaigns is also built into `malariasimulation`, but we do not demonstrate the use of PMC in this vignette (for further information on their use, see https://mrc-ide.github.io/malariasimulation/reference/set_pmc.html). +`malariasimulation` enables users to simulate the effects of chemoprevention strategies on malaria transmission, and provides the flexibility to design and simulate a range of MDA/SMC/PMC campaigns for a suite of antimalarial drugs. Specifically, users are able to load or specify parameters describing both the characteristics of the antimalarial(s) (e.g. drug efficacy, prophylactic profile) and their distribution (e.g. coverage, distribution timing, and the section of the population to treat). This vignette provides simple, illustrative demonstrations of how MDA and SMC campaigns can be set-up and simulated using `malariasimulation`. The functionality to simulate PMC campaigns is also built into `malariasimulation` via the `set_pmc() function`, but we do not demonstrate the use of PMC in this vignette (for further information on their use, see https://mrc-ide.github.io/malariasimulation/reference/set_pmc.html). ## Mass Drug Administration From 0da6bb69e5d7a02cc8c990d373421539c870ff8d Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Tue, 30 May 2023 15:58:55 +0100 Subject: [PATCH 092/164] I have updated the Demography vignette to include the changes requested --- vignettes/Demography.Rmd | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/vignettes/Demography.Rmd b/vignettes/Demography.Rmd index c9d23855..2f599d7d 100644 --- a/vignettes/Demography.Rmd +++ b/vignettes/Demography.Rmd @@ -21,7 +21,7 @@ library(malariasimulation) # Introduction -The dynamics of malaria transmission, and the efficacy of interventions designed to interrupt it, are highly context specific and an important consideration is the demography of the population(s) under investigation. To suit the research needs of the user, `malariasimulation` allows for the specification of custom human population demographics by allowing them to specify age-group specific death rates parameters. It also enables users to instruct the model to render outputs with variables of interest (e.g. human population, number of cases detectable by microscopy, number of severe cases, etc.) presented by user-defined age groups. In this vignette we'll use simple, illustrative cases to demonstrate how to customise the output rendered by the `run_simulation()` function, specify both fixed and time-varying custom death rates. +The dynamics of malaria transmission, and the efficacy of interventions designed to interrupt it, are highly context specific and an important consideration is the demography of the population(s) under investigation. To suit the research needs of the user, `malariasimulation` allows for the specification of custom human population demographics by allowing them to specify age-group specific death rates parameters. It also enables users to instruct the model to render outputs with variables of interest (e.g. human population, number of cases detectable by microscopy, number of severe cases, etc.) presented by user-defined age groups. In this vignette, we use simple, illustrative cases to demonstrate how to customise the output rendered by the `run_simulation()` function, and how to specify both fixed and time-varying custom death rates. # Specifying human death rates by age group @@ -29,9 +29,9 @@ The `malariasimulation` package allows users to capture different human populati ## Default Parameterisation -First, we'll establish a base set of parameters using the `get_parameters()` function and accepting the default values. The `run_simulation()` function's default behaviour is to output only the number of individuals aged 2-10 years old (`output$n_730_3650`, where 730 and 3650 are the ages in days). However, the user can instruct the model to output the number of individuals in age groups of their choosing using the `age_group_rendering_min_ages` and `age_group_rendering_max_ages` parameters. These arguments take vectors containing the minimum and maximum ages (in daily time steps) of each group to be captured. To allow us to see the effect of changing demographic parameters, we'll use this functionality to output the number of individuals in ages groups ranging from 0 to 85 at 5 year intervals. Note that the same is possible for other model outputs, including the number (`n_detect` , `p_detect`, `n_severe`, `n_inc`, `p_inc`, `n_inc_clinical`, `p_inc_clinical`, `n_inc_severe`, and `p_inc_severe` ) using their equivalent min/max age-class rendering arguments (run `?run_simulation()` for more detail). +First, we'll establish a base set of parameters using the `get_parameters()` function and accept the default values. The `run_simulation()` function's default behaviour is to output only the number of individuals aged 2-10 years old (`output$n_730_3650`, where 730 and 3650 are the ages in days). However, the user can instruct the model to output the number of individuals in age groups of their choosing using the `age_group_rendering_min_ages` and `age_group_rendering_max_ages` parameters. These arguments take vectors containing the minimum and maximum ages (in daily time steps) of each age group to be rendered To allow us to see the effect of changing demographic parameters, we'll use this functionality to output the number of individuals in ages groups ranging from 0 to 85 at 5 year intervals. Note that the same is possible for other model outputs using their equivalent min/max age-class rendering arguments (`n_detect` , `p_detect`, `n_severe`, `n_inc`, `p_inc`, `n_inc_clinical`, `p_inc_clinical`, `n_inc_severe`, and `p_inc_severe`, run `?run_simulation()` for more detail). -We next use the `set_equilibrium()` function to tune the initial parameter set to that required to observe the specified initial entomological inoculation rate (`starting_EIR`). We now have a set of default parameters ready to use to run simulations. +We next use the `set_equilibrium()` function to tune the initial parameter set to those required to observe the specified initial entomological inoculation rate (`starting_EIR`) at equilibrium. We now have a set of default parameters ready to use to run simulations. ```{r} @@ -46,7 +46,8 @@ starting_EIR <- 5 age_min <- seq(0, 80, 5) * 365 age_max <- seq(5, 85, 5) * 365 -# Use the get_parameters() function to establish the default simulation parameters, specifying age categories from 0-85 in 5 year intervals. +# Use the get_parameters() function to establish the default simulation parameters, specifying +# age categories from 0-85 in 5 year intervals. simparams <- get_parameters( list( human_population = human_population, @@ -55,14 +56,15 @@ simparams <- get_parameters( ) ) -# Use set_equilibrium to tune the human and mosquito populations to those required for the defined EIR +# Use set_equilibrium to tune the human and mosquito populations to those required for the +# defined EIR simparams <- set_equilibrium(simparams, starting_EIR) ``` ## **Custom Demographic Parameterisation** -Next, we'll use the the in-built `set_demography()` function to specify human death rates by age group. This function accepts as inputs a parameter list to update, a vector of the age groups (in days) for which we specify death rates, a vector of time steps in which we want the death rates to be updated, and a matrix containing the death rates for each age group in each timestep. The `set_demography()` function appends these to the parameter list and updates the `custom_demography` parameter to `TRUE`. +Next, we'll use the the in-built `set_demography()` function to specify human death rates by age group. This function accepts as inputs a parameter list to update, a vector of the age groups (in days) for which we specify death rates, a vector of time steps in which we want the death rates to be updated, and a matrix containing the death rates for each age group in each timestep. The `set_demography()` function appends these to the parameter list and updates the `custom_demography` parameter to `TRUE`. Here, we instruct the model to implement these changes to the demographic parameters at the beginning of the simulation (`timesteps = 0`). ```{r} @@ -70,7 +72,8 @@ Next, we'll use the the in-built `set_demography()` function to specify human de dem_params <- simparams # We can set our own custom demography: -ages <- round(c(0.083333, 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 200) * year) +ages <- round(c(0.083333, 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, + 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 200) * year) # Set deathrates for each age group (looks like by taking annual values and dividing by 365: deathrates <- c( @@ -79,7 +82,9 @@ deathrates <- c( .0234852, .0988317, .046755, .1638875, .1148753, .3409079, .2239224, .8338688) / 365 -# Pass these custom ages and death rates through the in-built set_demography function +# Update the parameter list with the custom ages and death rates through the in-built +# set_demography() function, instructing the custom demography to be implemented at the +# beginning of the model run (timestep = 0): dem_params <- set_demography( dem_params, agegroups = ages, @@ -98,11 +103,11 @@ Having established parameter sets with both default and custom demographic param ```{r} -# Run the simulation with the default (?) demogaphic set-up +# Run the simulation with the default demographic set-up: exp_output <- run_simulation(sim_length, simparams) exp_output$run <- 'exponential' -# Run the simulation for the custom demographic set-up +# Run the simulation for the custom demographic set-up: custom_output <- run_simulation(sim_length, dem_params) custom_output$run <- 'custom' @@ -176,7 +181,7 @@ Using the `timesteps` and `deathrates` arguments, we can also use the `set_demog ## Parameterisation -We'll start by making a copy of the base parameters which have been instructed to output the population size through time (`simparams`). Next, we create a version of the `deathrates` vector created earlier updated to increase the death rates of the 5-10, 10-15, and 15-20 age groups by 1000%. Finally, we use `set_demography()` to update our parameter list and specify our custom demography. This is achieved providing the `timesteps` argument with a vector of days to update the death rates (0 and 730 days), and providing `deathrates` with a matrix of death rates where each row corresponds to a set of death rates for a given update. +We'll start by making a copy of the base parameters which have been instructed to output the population size through time (`simparams`). Next, we create a version of the `deathrates` vector created earlier updated to increase the death rates of the 5-10, 10-15, and 15-20 age groups by 10%. Finally, we use `set_demography()` to update our parameter list and specify our custom demography. This is achieved providing the `timesteps` argument with a vector of days to update the death rates (0 and 730 days), and providing `deathrates` with a matrix of death rates where each row corresponds to a set of death rates for a given update. ```{r} @@ -212,7 +217,8 @@ Bar plots of the age structure of the human population at the end of each year s ```{r, fig.width = 7.2, fig.height = 3, fig.fullwidth = TRUE} -# Filter out the end-of-year population sizes, add a column naming the run, and convert dataframe to long-form: +# Filter out the end-of-year population sizes, add a column naming the run, and convert +# dataframe to long-form: dyn_dem_output <- dyn_dem_output[dyn_dem_output$timestep %in% (1:5 * 365),] dyn_dem_output$run <- 'dynamic' dyn_dem_output <- convert_to_long(age_min, age_max, dyn_dem_output) From d21e4ce348786a51d23c0b81e99ca6356428ca16 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Wed, 31 May 2023 15:15:45 +0100 Subject: [PATCH 093/164] updated Model structure vignette - taken out mosquito parameter functions --- vignettes/Model.Rmd | 179 ++----- vignettes/Model_mos.svg | 1040 +++++++++++++++++++++------------------ 2 files changed, 597 insertions(+), 622 deletions(-) diff --git a/vignettes/Model.Rmd b/vignettes/Model.Rmd index 96e65d95..1eaa7369 100644 --- a/vignettes/Model.Rmd +++ b/vignettes/Model.Rmd @@ -1,7 +1,5 @@ --- title: "Model Structure" -header-includes: - -\usepackage{svg} output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Model Structure} @@ -12,8 +10,7 @@ vignette: > ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, - comment = "#>", - dev="svglite" + comment = "#>" ) ``` @@ -52,7 +49,7 @@ with the rates of recovery: Superinfection may occur in individuals with asymptomatic or sub-patent infections at the same rates as standard infection (dashed arrows). -The force of infection ($\Lambda_i$) is impacted by pre-erythrocytic immunity, mosquito biting rate and population size and level of infectivity (specific details can be found in the references below). All default parameters can be found in the documentation for the function `get_parameters()`. Please also note that while the infographic above displays rate parameters, the parameter list uses delays durations, e.g. the rate $r_D$ is the inverse of the delay from state *D* to *A* (`dr` in the model): +The force of infection ($\Lambda_i$) is impacted by pre-erythrocytic immunity, mosquito biting rate and population size and level of infectivity (specific details can be found in the references below). All default parameters can be found in the documentation for the function `get_parameters()`. Please also note that while the infographic above displays rate parameters, the parameter list uses delay durations, e.g. the rate $r_D$ is the inverse of the delay from state *D* to *A* (`dr` in the model): $$r_D=dr^{-1}$$ @@ -67,7 +64,7 @@ The functions governing mosquito biological processes and dynamics are spread ou 3. [src/mosquito_biology.cpp](https://github.com/mrc-ide/malariasimulation/blob/master/src/mosquito_biology.cpp) 4. [R/mosquito_biology.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/mosquito_biology.R) - + ### States @@ -85,7 +82,7 @@ Parameters shown on the infographic include mosquito developmental rates: Mosquito infection and incubation rates: -- $\Lambda_M$: the force of mosquito infection (FOIM) +- $\Lambda_M$: the force of infection on mosquitos (FOIM, i.e. from human to mosquito) - $r_{EM}$: extrinsic incubation period @@ -106,7 +103,7 @@ $$ \mu_L = \mu_L^0(1+\gamma\frac{E(t)+L(t)}{K(t)}) $$ -## Model References +## Key Model References (structure and dynamics) Griffin JT, Hollingsworth TD, Okell LC, Churcher TS, White M, et al. (2010) Reducing *Plasmodium falciparum* Malaria Transmission in Africa: A Model-Based Evaluation of Intervention Strategies. PLOS Medicine 7(8): e1000324. @@ -120,7 +117,7 @@ Griffin, J. T., Bhatt, S., Sinka, M. E., Gething, P. W., Lynch, M., Patouillard, # Basic simulation -### Simulation code +### Code The key package function is `run_simulation()` which, in its most basic form, simply requires a number of timesteps in days. Default parameter settings assume a human population of size of 100, an initial mosquito population size of 1000 with all species in equal proportions, with no treatment interventions and no seasonality. The full parameters list can be seen in the documentation for `get_parameters()`. @@ -151,7 +148,7 @@ The `run_simulation()` function then simulates malaria transmission dynamics and - `n_detect_730_3650`: number with possible detection through microscopy of a given age group - `p_detect_730_3650`: the sum of probabilities of detection through microscopy of a given age group - `E_All_count`, `L_All_count`, `P_All_count`, `Sm_All_count`, `Pm_All_count`, `Im_All_count`, `NonExistent_All_count`: mosquito population sizes in each state -- `mosquito_deaths`: mosquito deaths +- `total_M_All`: number of adult mosquitoes ```{r, output.lines=6} head(test_sim, n = 3) @@ -177,22 +174,23 @@ cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#C cols_to_plot <- paste0(c("S","D","A","U","Tr"),"_count") # Create plotting function -states_plot <- function(){ +states_plot <- function(sim){ # Set up plot with first state - plot(x = test_sim$timestep, y = test_sim[,cols_to_plot[1]], + plot(x = sim$timestep, y = sim[,cols_to_plot[1]], type = "l", col = cols[1], ylim = c(0,80), ylab = "Population size", xlab = "Days") # Add remaining states sapply(2:5, function(x){ - points(x = test_sim$timestep, y = test_sim[,cols_to_plot[x]], type = "l", col = cols[x])}) + points(x = sim$timestep, y = sim[,cols_to_plot[x]], type = "l", col = cols[x])}) # Add legend legend("topleft", legend = c("S","D","A","U","Tr"), col = cols, lty = 1, bty = "n", ncol = 5) } -states_plot() +par(mfrow = c(1,2)) +states_plot(test_sim) # Calculate Pf PR 2-10 test_sim$PfPR2_10 <- test_sim$n_detect_730_3650/test_sim$n_730_3650 @@ -203,126 +201,42 @@ plot(x = test_sim$timestep, y = test_sim$PfPR2_10, type = "l", ylab = expression(paste(italic(Pf),"PR"[2-10])), xlab = "Days") ``` -# Changing parameters - -The `get_parameters()` function generates a complete parameter set that may be fed into `run_simulation()`. A number of **helper functions** have been designed to assist in changing and setting key parameters, which are explained across the remaining vignettes. +Note that the model will not begin simulations from an equilibrium state as default. In the case of our simulation that means that the population in each state and the prevalence (*Pf*PR~2-10~) move towards an equilibrium. To begin the simulation at approximate equilibrium conditions, please use the `set_equilibrium()` function, which requires you to specify an initial EIR value: -Some parameters (e.g. population size, age group rendering, setting seasonality) must still be replaced directly. When this is the case, care must be taken to ensure the replacement parameters are in the same class as the default parameters (e.g. if the parameter is a numeric, its replacement must also be numeric, if logical, the replacement must also be logical). Parameters are replaced by passing a list of named parameters to the `get_parameters()` function using the `overrides` argument. An example showing how to change the `human_population` parameter is given below. +```{r, fig.align = 'center', fig.height = 5, fig.width = 7} +params <- get_parameters() |> + set_equilibrium(init_EIR = 5) -```{r} -# Use get_parameters(overrides = list(...))) to set new parameters -new_params <- get_parameters(overrides = list(human_population = 200)) -``` +test_sim_eq <- run_simulation(timesteps = 100, parameters = params) -While other parameters can be changed individually, we do not generally recommended adjusting these without close attention and a detailed understanding of how this will impact the model assumptions. We strongly encourage users to stick with the parameter setting functions and methods described in these vignettes when adjusting parameter settings. +par(mfrow = c(1,2)) +states_plot(test_sim_eq) -## Mosquito modelling +# Calculate Pf PR 2-10 +test_sim_eq$PfPR2_10 <- test_sim_eq$n_detect_730_3650/test_sim_eq$n_730_3650 -### Species distribution +# Plot Pf PR 2-10 +plot(x = test_sim_eq$timestep, y = test_sim_eq$PfPR2_10, type = "l", + col = cols[7], ylim = c(0,1), + ylab = expression(paste(italic(Pf),"PR"[2-10])), xlab = "Days") -`malariasimulation` contains in built parameter sets for three mosquito species: *A. arabiensis* (`arab_params`), *A. funestus* (`fun_params`) and *A. gambiae* (`gamb_params`). Each parameter set contains feeding rates, foraging time etc. Full details can be found in the [vector_parameters.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/vector_parameters.R) file. -```{r} -unlist(arab_params) ``` -The proportion of each species can be set using the `set_species()` function, requiring a full parameter set and arguments of a list of species parameter sets and a vector of relative species proportions. - -```{r, fig.align = 'center', fig.height = 5, fig.width = 7} -# Create list of default parameters -params <- get_parameters() - -# Update parameter list with species distributions -params_species <- set_species(parameters = params, - species = list(arab_params, fun_params, gamb_params), - proportions = c(0.1,0.3,0.6)) - -# Run simulation -species_simulation <- run_simulation(timesteps = 100, parameters = params_species) - -## Plot species distributions -# Collect species column names -arab_cols <- paste0(c("E","L","P","Sm","Pm", "Im", "NonExistent"),"_arab_count") -fun_cols <- paste0(c("E","L","P","Sm","Pm", "Im", "NonExistent"),"_fun_count") -gamb_cols <- paste0(c("E","L","P","Sm","Pm", "Im", "NonExistent"),"_gamb_count") - -Mos_sp_dist_sim <- cbind(species_simulation$timestep, - rowSums(species_simulation[,arab_cols]), - rowSums(species_simulation[,fun_cols]), - rowSums(species_simulation[,gamb_cols])) - -species_plot <- function(Mos_pops){ - plot(x = Mos_pops[,1], y = Mos_pops[,2], type = "l", col = cols[2], - ylim = c(0,140000), ylab = "Mosquito population size", xlab = "Days") - - grid() - - sapply(3:4, function(x){ - points(x = Mos_pops[,1], y = Mos_pops[,x], type = "l", col = cols[x])}) - - legend("topright", legend = c("A. arab","A. fun","A. gamb"), - col = cols[-1], lty = 1, bty = "n", ncol = 1) -} - -species_plot(Mos_sp_dist_sim) -``` - -### Seasonality - -The `malariasimulation` package has the capacity to simulate malaria transmission for a range of seasonal transmission profiles. This is achieved by specifying an annual rainfall profile that shapes mosquito population dynamics, thereby impacting malaria transmission. +# Changing parameters -To include seasonality, we must set the parameter `model_seasonality = TRUE` and assign values to parameters that determine seasonality: `g0`, `g` and `h`. These parameters must be set directly by passing a list of named parameters to the `overrides` argument of the `get_parameters()` function. +The `get_parameters()` function generates a complete parameter set that may be fed into `run_simulation()`. A number of **helper functions** have been designed to assist in changing and setting key parameters, which are explained across the remaining vignettes. -```{r, fig.align = 'center', fig.height = 5, fig.width = 7} -# Set parameters, inclusing seasonality parameters -params_seasons <- get_parameters(overrides = list( - model_seasonality = TRUE, - g0 = 0.28, - g = c(0.2, -0.07, -0.001), - h = c(0.2, -0.07, -0.1))) - -# Run simulation -seasonality_simulation <- run_simulation(timesteps = 600, parameters = params_seasons) - -# Collect results -All_mos_cols <- paste0(c("E","L","P","Sm","Pm", "Im", "NonExistent"),"_All_count") - -# Plot results -plot(seasonality_simulation[,1], rowSums(seasonality_simulation[,All_mos_cols]), - ylim = c(0, 200000), type = "l", xlab = "Days", ylab = "Mosquito population size") -grid() -### Run simulation using seasonality over previous species distribution -# Update seasonality parameter set to include species distributions -params_seasons_species <- set_species(parameters = params_seasons, - species = list(arab_params, fun_params, gamb_params), - proportions = c(0.1,0.3,0.6)) - -# Run simulation -seasonality_species_simulation <- run_simulation(timesteps = 600, - parameters = params_seasons_species) - -# Collect results -Mos_season_species_sim <- cbind(seasonality_species_simulation$timestep, - rowSums(seasonality_species_simulation[,arab_cols]), - rowSums(seasonality_species_simulation[,fun_cols]), - rowSums(seasonality_species_simulation[,gamb_cols])) - -# Plot results -species_plot(Mos_season_species_sim) +Some parameters (e.g. population size, age group rendering, setting seasonality) must still be replaced directly. When this is the case, care must be taken to ensure the replacement parameters are in the same class as the default parameters (e.g. if the parameter is a numeric, its replacement must also be numeric, if logical, the replacement must also be logical). Parameters are replaced by passing a list of named parameters to the `get_parameters()` function using the `overrides` argument. An example showing how to change the `human_population` parameter is given below. +```{r} +# Use get_parameters(overrides = list(...))) to set new parameters +new_params <- get_parameters(overrides = list(human_population = 200)) ``` -The mosquito population size is no longer constant and follows the patterns set by rainfall. - -### Individual or deterministic mosquitoes +While other parameters can be changed individually, we do not generally recommended adjusting these without close attention and a detailed understanding of how this will impact the model assumptions. We strongly encourage users to stick with the parameter setting functions and methods described in these vignettes when adjusting parameter settings. -Mosquitoes may also be modelled deterministically, rather than individually (which is the default). -This can be done by setting `individual_mosquitoes` to `FALSE` in the `overrides` argument of `get_parameters()`. - -```{r, fig.align = 'center', fig.height = 5, fig.width = 7} -simparams <- get_parameters(overrides = list(individual_mosquitoes = FALSE)) -``` ## Vignettes @@ -332,14 +246,19 @@ The remaining vignettes describe how to adjust sets of parameters through a numb - Age group rendering - `set_demography()`: setting demographies - - `set_equilibrium()`: establishing initial human and mosquito populations to achieve initial equilibrium conditions -2. [Treatment](https://mrc-ide.github.io/malariasimulation/articles/Treatment.html) +2. [Carrying capacity](https://mrc-ide.github.io/malariasimulation/articles/Carrying-capacity.html) + + - Seasonality + - `set_carrying_capacity()`: changes mosquito carrying capacity, e.g. to model larval source management impact + - `set_species`: to model multiple species and species invasion + +3. [Treatment](https://mrc-ide.github.io/malariasimulation/articles/Treatment.html) - `set_drugs()`: for drug-specific parameters (with in-built parameter sets) - `set_clinical_treatment()`: implemention of clinical treatment interventions -3. [MDA and Chemoprevention](https://mrc-ide.github.io/malariasimulation/articles/MDA.html) +4. [MDA and Chemoprevention](https://mrc-ide.github.io/malariasimulation/articles/MDA.html) - `set_mda()`: implementation of mass drug administration interventions @@ -349,28 +268,28 @@ The remaining vignettes describe how to adjust sets of parameters through a numb - `peak_season_offset()`: correlating timed interventions with seasonal malaria -4. [Vaccines](https://mrc-ide.github.io/malariasimulation/articles/Vaccines.html) +5. [Vaccines](https://mrc-ide.github.io/malariasimulation/articles/Vaccines.html) - - `set_mass_rtss()`: implementation of a RTS,S vaccination intervention - - `set_rtss_epi()`: Implementation of RTS,S vaccination intervention from a certain age - - `set_tbv()`: implementation of a tbv vaccination intervention + - `set_mass_pev()`: implementation of a pre-erythrocytic vaccination intervention + - `set_pev_epi()`: Implementation of a pre-erythrocytic vaccination intervention from a certain age + - `set_tbv()`: implementation of a transmission blocking vaccination intervention -5. [Vector Control: Bednets](https://mrc-ide.github.io/malariasimulation/articles/VectorControl.html) +6. [Vector Control: Bednets](https://mrc-ide.github.io/malariasimulation/articles/VectorControl.html) - `set_bednets()`: implementation of bednet distribution intervention -6. [Vector Control: Indoor Residual Spraying](https://mrc-ide.github.io/malariasimulation/articles/VectorControl.html) +7. [Vector Control: Indoor Residual Spraying](https://mrc-ide.github.io/malariasimulation/articles/VectorControl.html) - `set_spraying()`: implementation of an indoor residual spraying intervention -7. [Matching PfPR2-10 to EIR](https://mrc-ide.github.io/malariasimulation/articles/EIRprevmatch.html) +8. [Matching PfPR2-10 to EIR](https://mrc-ide.github.io/malariasimulation/articles/EIRprevmatch.html) - Using *Pf*PR~2-10~ data to estimate EIR -8. [Metapopulation Modelling](https://mrc-ide.github.io/malariasimulation/articles/Metapopulation.html) +9. [Metapopulation Modelling](https://mrc-ide.github.io/malariasimulation/articles/Metapopulation.html) - `run_metapop_simulation()`: to model multiple areas simultaneously -9. [Variation](https://mrc-ide.github.io/malariasimulation/articles/Variation.html) +10. [Variation](https://mrc-ide.github.io/malariasimulation/articles/Variation.html) - `run_simulation_with_repetitions()`: running simulations with replicates diff --git a/vignettes/Model_mos.svg b/vignettes/Model_mos.svg index 44ecd256..beee55cb 100644 --- a/vignettes/Model_mos.svg +++ b/vignettes/Model_mos.svg @@ -5,19 +5,19 @@ + id="defs236"> + inkscape:current-layer="svg232" /> + d="m 196.4653,7.2378955 h 130.47382 a 11.25,11.25 45 0 1 11.25,11.2499995 V 38.20895 a 11.25,11.25 135 0 1 -11.25,11.25 H 196.4653 a 11.25,11.25 45 0 1 -11.25,-11.25 V 18.487895 a 11.25,11.25 135 0 1 11.25,-11.2499995 z" /> + sodipodi:type="rect" + d="M 15.556859,7.2378955 H 149.63968 a 11.25,11.25 45 0 1 11.25,11.2499995 V 38.20895 a 11.25,11.25 135 0 1 -11.25,11.25 H 15.556859 a 11.25,11.25 45 0 1 -11.25,-11.25 V 18.487895 a 11.25,11.25 135 0 1 11.25,-11.2499995 z" /> + transform="translate(10.031579,90.49474)"> %0 - - + id="title2">%0 + g2 + id="title4">E + Development + id="text8">E - + y2 + id="title11">L + Infection + id="text15">L - + + id="edge1" + class="edge"> r2 + id="title18">E->L + + Mortality + id="text24">r + EL - + y1 + id="title29">I1 - + y1->y2 - - + id="title32">E->I1 - + r1 + id="title35">I2 - + y1->r1 - - - - r1->r2 + id="title38">E->I2 + d="m 24.0974,-48.6725 c 9.9715,7.8419 24.6134,19.3569 35.0817,27.5896" + id="path40" /> - - - - g1 - - - - g1->g2 - - - - - - g1->y1 - - - - %0 - - - NonExistent - + points="58.9475,-20.3745 59.8129,-21.475 60.9523,-19.6884 " + id="polygon42" /> µ + NonExistent + id="text46">E + (t) P + id="title51">P + d="m 137.6667,-68.4 c 0,0 -7.3334,0 -7.3334,0 -3.6666,0 -7.3333,3.6667 -7.3333,7.3333 0,0 0,7.3334 0,7.3334 0,3.6666 3.6667,7.3333 7.3333,7.3333 0,0 7.3334,0 7.3334,0 3.6666,0 7.3333,-3.6667 7.3333,-7.3333 0,0 0,-7.3334 0,-7.3334 0,-3.6666 -3.6667,-7.3333 -7.3333,-7.3333" + id="path53" /> P + id="text55">P - + NonExistent->P + id="title58">L->P + stroke="#00cd00" + d="m 83.0844,-57.4 c 10.4492,0 26.1337,0 37.331,0" + id="path60" /> + fill="#00cd00" + stroke="#00cd00" + points="120.5921,-56.7001 120.5922,-58.1001 122.5921,-57.4 " + id="polygon62" /> µ + id="text64">r P + id="text66">L - + + + L->I2 + + L - - L + id="title72">I3 - + NonExistent->L + id="title75">L->I3 + d="m 83.2631,-49.1046 c 10.9297,8.0498 27.4963,20.2512 38.9238,28.6677" + id="path77" /> + points="121.8089,-19.846 122.6391,-20.9733 123.8344,-19.2236 " + id="polygon79" /> µ + id="text81">µ L + id="text83">L (t) + id="text85">(t) + id="text87" /> - + E + id="title90">Sm + d="m 195.6667,-68.4 c 0,0 -7.3334,0 -7.3334,0 -3.6666,0 -7.3333,3.6667 -7.3333,7.3333 0,0 0,7.3334 0,7.3334 0,3.6666 3.6667,7.3333 7.3333,7.3333 0,0 7.3334,0 7.3334,0 3.6666,0 7.3333,-3.6667 7.3333,-7.3333 0,0 0,-7.3334 0,-7.3334 0,-3.6666 -3.6667,-7.3333 -7.3333,-7.3333" + id="path92" /> E + id="text94">S + M - + NonExistent->E + id="title99">P->Sm + stroke="#00cd00" + d="m 145.183,-57.4 c 9.5483,0 23.304,0 33.4352,0" + id="path101" /> -    + fill="#00cd00" + stroke="#00cd00" + points="178.8513,-56.7001 178.8514,-58.1001 180.8513,-57.4 " + id="polygon103" /> µ + id="text105">r E - (t) + id="text107">P - + + P->I3 + + + Im - - I - M + id="title113">I4 - + NonExistent->Im + id="title116">P->I4 + d="m 145.183,-48.4536 c 9.6286,7.7028 23.5355,18.8284 33.6899,26.9519" + id="path118" /> + points="178.8523,-20.6217 179.7269,-21.715 180.8513,-19.9189 " + id="polygon120" /> µ + id="text122">µ M - + id="text124">P Pm + id="title127">Pm + d="m 253.6667,-68.4 c 0,0 -7.3334,0 -7.3334,0 -3.6666,0 -7.3333,3.6667 -7.3333,7.3333 0,0 0,7.3334 0,7.3334 0,3.6666 3.6667,7.3333 7.3333,7.3333 0,0 7.3334,0 7.3334,0 3.6666,0 7.3333,-3.6667 7.3333,-7.3333 0,0 0,-7.3334 0,-7.3334 0,-3.6666 -3.6667,-7.3333 -7.3333,-7.3333" + id="path129" /> P + id="text131">P M + id="text133">M - + NonExistent->Pm + id="title136">Sm->Pm + stroke="#ffa500" + d="m 203.183,-57.4 c 9.5483,0 23.304,0 33.4352,0" + id="path138" /> + fill="#ffa500" + stroke="#ffa500" + points="236.8513,-56.7001 236.8514,-58.1001 238.8513,-57.4 " + id="polygon140" /> µ + id="text142">Λ M - + id="text144">M - + + Sm->I4 + + + Sm - - S - M + id="title150">I5 - + NonExistent->Sm + id="title153">Sm->I5 + d="m 203.183,-48.4536 c 9.6286,7.7028 23.5355,18.8284 33.6899,26.9519" + id="path155" /> + points="236.8523,-20.6217 237.7269,-21.715 238.8513,-19.9189 " + id="polygon157" /> µ + id="text159">µ M + id="text161">M - + + id="node6" + class="node"> P->Sm + id="title164">Im - + stroke="#000000" + d="m 311.6667,-68.4 c 0,0 -7.3334,0 -7.3334,0 -3.6666,0 -7.3333,3.6667 -7.3333,7.3333 0,0 0,7.3334 0,7.3334 0,3.6666 3.6667,7.3333 7.3333,7.3333 0,0 7.3334,0 7.3334,0 3.6666,0 7.3333,-3.6667 7.3333,-7.3333 0,0 0,-7.3334 0,-7.3334 0,-3.6666 -3.6667,-7.3333 -7.3333,-7.3333" + id="path166" /> r + id="text168">I P + id="text170">M - + L->P + id="title173">Pm->Im + stroke="#ffa500" + d="m 261.183,-57.4 c 9.5483,0 23.304,0 33.4352,0" + id="path175" /> + fill="#ffa500" + stroke="#ffa500" + points="294.8513,-56.7001 294.8514,-58.1001 296.8513,-57.4 " + id="polygon177" /> r + id="text179">r L + id="text181">EM - + E->L + id="title184">Pm->I5 + + + + I6 + + + + Pm->I6 + stroke="#ff0000" + d="m 261.183,-48.4536 c 9.6286,7.7028 23.5355,18.8284 33.6899,26.9519" + id="path192" /> + fill="#ff0000" + stroke="#ff0000" + points="294.8523,-20.6217 295.7269,-21.715 296.8513,-19.9189 " + id="polygon194" /> r + id="text196">µ EL + id="text198">M + - + Im->E + id="title203">Im->I6 - + + I7 + + + Pm->Im + id="title209">Im->I7 + stroke="#ff0000" + d="m 319.183,-48.4536 c 9.6286,7.7028 23.5355,18.8284 33.6899,26.9519" + id="path211" /> + fill="#ff0000" + stroke="#ff0000" + points="352.8523,-20.6217 353.7269,-21.715 354.8513,-19.9189 " + id="polygon213" /> r + id="text215">µ EM + id="text217">M + - + + I8 + + + Sm->Pm - - + id="title225">Im->I8 + + + + I8->I7 + + + + %0 + + + + g2 Λ + id="text1059">Development + + + + y2 Infection + + + + r2 + M + id="text1069">Mortality + + + + y1 + + + + y1->y2 + + + + + + r1 + + + + y1->r1 + + + + r1->r2 + + + + + + g1 + + + + g1->g2 + + + + + + g1->y1 Juvenilemosquitoes - + style="text-align:center;text-anchor:middle;stroke-width:0.165781" + x="45.657978" + y="16.598707" + id="tspan5685">Juvenile mosquitoes Adultmosquitoes + style="text-align:center;text-anchor:middle;stroke-width:0.165781" + x="220.77356" + y="16.598707" + id="tspan5685-4">Adult mosquitoes From 0c3dbfe8341e54e744b12f88fe53354fe836344e Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Wed, 31 May 2023 17:13:11 +0100 Subject: [PATCH 094/164] change example SetSpecies; small edits --- vignettes/SetSpecies.Rmd | 100 +++++++++++----------------- vignettes/VectorControl_Bednets.Rmd | 2 +- vignettes/VectorControl_IRS.Rmd | 5 +- 3 files changed, 44 insertions(+), 63 deletions(-) diff --git a/vignettes/SetSpecies.Rmd b/vignettes/SetSpecies.Rmd index 9e621d1f..511d2c9c 100644 --- a/vignettes/SetSpecies.Rmd +++ b/vignettes/SetSpecies.Rmd @@ -18,23 +18,23 @@ knitr::opts_chunk$set( library(malariasimulation) ``` -### Plotting functions -We will create a few plotting functions to visualise the output. +### Plotting function +We will create a plotting function to visualise the output. ```{r} cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") # Plotting functions plot_prev <- function() { - plot(x = output$timestep, y = output$n_detect_730_3650 / output$n_730_3650, + plot(x = output_endophilic$timestep, y = output_endophilic$n_detect_730_3650 / output_endophilic$n_730_3650, type = "l", col = cols[3], lwd = 2.5, xlab = "Time (days)", ylab = expression(paste(italic(Pf),"PR"[2-10])), xaxs = "i", yaxs = "i", bty = "l", ylim = c(0,1)) - lines(x = output_all$timestep, y = output_all$n_detect_730_3650 / output_all$n_730_3650, + lines(x = output_exophilic$timestep, y = output_exophilic$n_detect_730_3650 / output_exophilic$n_730_3650, col = cols[5], lwd = 2.5) abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = "black") grid(lty = 2, col = "grey80", lwd = 1) - legend("bottomleft", box.lty = 0, legend = c("Spraying", "Prevalence for species-specific scenario", "Prevalence for default all mosquitoes scenario"), + legend("bottomleft", box.lty = 0, legend = c("Spraying", "Prevalence for endophilic mosquitoes", "Prevalence for exophilic mosquitoes"), col = c("black", cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) } ``` @@ -51,11 +51,11 @@ There are preset parameters for *An. gambiae*, *An. arabiensis*, and *An. funest We will demonstrate how to specify different mosquito species and how this could alter intervention impact using an example with IRS. -## IRS with default mosquito settings +## IRS with single endophilic mosquito species -Use the `get_parameters()` function to generate a list of parameters, accepting most of the default values, but modifying seasonality values to model a seasonal setting. We will model IRS with the default mosquito settings, which is to model all mosquito species together. Then, we use the `set_equilibrium()` function to to initialise the model at a given entomological inoculation rate (EIR). +Use the `get_parameters()` function to generate a list of parameters, accepting most of the default values, but modifying seasonality values to model a seasonal setting. We will use `set_species` to model mosquitoes similar to *An. funestus* but with a higher propensity to bite indoors. Then, we use the `set_equilibrium()` function to to initialise the model at a given entomological inoculation rate (EIR). -Use the `set_spraying()` function to set an IRS intervention. This function takes as arguments the parameter list, timesteps of spraying, coverage of IRS in the population and a series of parameters related to the insecticide used in the IRS. The proportion of mosquitoes dying following entering a hut is dependent on the parameters `ls_theta`, the initial efficacy, and `ls_gamma`, how it changes over time. The proportion of mosquitoes successfully feeding is dependent on `ks_theta`, the initial impact of the insecticide in IRS, and `ks_gamma`, how the impact changes over time. Finally, the proportion of mosquitoes being deterred away from a sprayed hut depends on `ms_theta`, the initial impact of IRS, and `ms_gamma`, the change in impact over time. See a more comprehensive explanation in the Supplementary Information of [Sherrard-Smith et al., 2018](https://doi.org/10.1038/s41467-018-07357-w). +We used the `set_spraying()` function to set an IRS intervention. This function takes as arguments the parameter list, timesteps of spraying, coverage of IRS in the population and a series of parameters related to the insecticide used in the IRS. The proportion of mosquitoes dying following entering a hut is dependent on the parameters `ls_theta`, the initial efficacy, and `ls_gamma`, how it changes over time. The proportion of mosquitoes successfully feeding is dependent on `ks_theta`, the initial impact of the insecticide in IRS, and `ks_gamma`, how the impact changes over time. Finally, the proportion of mosquitoes being deterred away from a sprayed hut depends on `ms_theta`, the initial impact of IRS, and `ms_gamma`, the change in impact over time. See a more comprehensive explanation in the Supplementary Information of [Sherrard-Smith et al., 2018](https://doi.org/10.1038/s41467-018-07357-w). ```{r} year <- 365 @@ -77,13 +77,25 @@ simparams <- get_parameters( peak <- peak_season_offset(simparams) +# Create an example mosquito species with a high value for `phi_indoors` +endophilic_mosquito_params <- fun_params +endophilic_mosquito_params$phi_indoors <- 0.9 +endophilic_mosquito_params$species <- 'endophilic' + +## Set mosquito species with a high propensity for indoor biting +simparams <- set_species( + simparams, + species = list(endophilic_mosquito_params), + proportions = c(1) +) + sprayingtimesteps <- c(1, 2) * year + peak - 3 * month # There is a round of IRS in the 1st and second year 3 months prior to peak transmission. simparams <- set_spraying( simparams, timesteps = sprayingtimesteps, coverages = rep(.8, 2), # # Each round covers 80% of the population - # nrows=length(timesteps), ncols=length(species) + # nrows=length(timesteps), ncols=length(species) ls_theta = matrix(2.025, nrow=length(sprayingtimesteps), ncol=1), # Matrix of mortality parameters per round of IRS and per species ls_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=1), # Matrix of mortality parameters per round of IRS and per species ks_theta = matrix(-2.222, nrow=length(sprayingtimesteps), ncol=1), # Matrix of feeding success parameters per round of IRS and per species @@ -95,42 +107,31 @@ simparams <- set_spraying( simparams <- set_equilibrium(simparams, starting_EIR) # Running simulation with IRS -output_all <- run_simulation(timesteps = sim_length, parameters = simparams) +output_endophilic <- run_simulation(timesteps = sim_length, parameters = simparams) ``` -The default setting is to model all mosquito species together. +We can see below that only the endophilic species is modelled. ```{r} simparams$species simparams$species_proportions ``` -### Plot species over time -```{r,fig.align="center", fig.height=5, fig.width=7} -plot(x = output_all$timestep, y = output_all$Im_All_count, - type = "l", col = cols[5], lwd = 2.5, - xlab = "Time (days)", ylab = "N mosquitoes", - xaxs = "i", yaxs = "i", bty = "l") -abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = "black") -grid(lty = 2, col = "grey80", lwd = 1) -legend("topright", box.lty = 0, legend = c("Spraying", "All mosquitoes"), col = c("black", cols[5]), lty = c(2, 1), lwd = 2.5) -``` - -## IRS with different mosquito species +## IRS with single exophilic mosquito species -We will run the same model with IRS as above, but this time with 3 species of mosquitoes: *An. arabiensis*, *An. gambiae*, and an example mosquito species similar to *An. funestus*, but with a lower propensity to bite indoors. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. See the Vector Control: IRS vignette for more information about setting IRS with different mosquito species. +We will run the same model with IRS as above, but this time with an example mosquito species similar to *An. funestus*, but with a lower propensity to bite indoors. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. See the Vector Control: IRS vignette for more information about setting IRS with different mosquito species. ```{r, fig.align="center", fig.height=4, fig.width=6} # Create an example mosquito species with a low value for `phi_indoors` -example_mosquito_params <- fun_params -example_mosquito_params$phi_indoors <- 0.2 -example_mosquito_params$species <- 'example' +exophilic_mosquito_params <- fun_params +exophilic_mosquito_params$phi_indoors <- 0.2 +exophilic_mosquito_params$species <- 'exophilic' ## Set 3 species of mosquitoes, 10% An. arabiensis, 10% An. gambia, and 80% an example species with a lower propensity for indoor biting simparams <- set_species( simparams, - species = list(arab_params, gamb_params, example_mosquito_params), - proportions = c(1/3, 1/3, 1/3) + species = list(exophilic_mosquito_params), + proportions = c(1) ) peak <- peak_season_offset(simparams) @@ -141,42 +142,21 @@ simparams <- set_spraying( simparams, timesteps = sprayingtimesteps, coverages = rep(.8, 2), # # Each round covers 80% of the population - ls_theta = matrix(2.025, nrow=length(sprayingtimesteps), ncol=3), # Matrix of mortality parameters; nrows=length(timesteps), ncols=length(species) - ls_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=3), # Matrix of mortality parameters per round of IRS and per species - ks_theta = matrix(-2.222, nrow=length(sprayingtimesteps), ncol=3), # Matrix of feeding success parameters per round of IRS and per species - ks_gamma = matrix(0.008, nrow=length(sprayingtimesteps), ncol=3), # Matrix of feeding success parameters per round of IRS and per species - ms_theta = matrix(-1.232, nrow=length(sprayingtimesteps), ncol=3), # Matrix of deterrence parameters per round of IRS and per species - ms_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=3) # Matrix of deterrence parameters per round of IRS and per species + # nrows=length(timesteps), ncols=length(species) + ls_theta = matrix(2.025, nrow=length(sprayingtimesteps), ncol=1), # Matrix of mortality parameters + ls_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=1), # Matrix of mortality parameters per round of IRS and per species + ks_theta = matrix(-2.222, nrow=length(sprayingtimesteps), ncol=1), # Matrix of feeding success parameters per round of IRS and per species + ks_gamma = matrix(0.008, nrow=length(sprayingtimesteps), ncol=1), # Matrix of feeding success parameters per round of IRS and per species + ms_theta = matrix(-1.232, nrow=length(sprayingtimesteps), ncol=1), # Matrix of deterrence parameters per round of IRS and per species + ms_gamma = matrix(-0.009, nrow=length(sprayingtimesteps), ncol=1) # Matrix of deterrence parameters per round of IRS and per species ) -output <- run_simulation(timesteps = sim_length, parameters = simparams) -``` - -Here we can see that now there are 3 species of mosquitoes at the proportions we specified in `set_species()`. -```{r} -simparams$species -simparams$species_proportions -``` - - -### Plot prevalence -In the plot below, we can see that IRS is much more effective when the default mosquito species are used compared to the scenario where we added an example mosquito species with a lower propensity for biting indoors. In this case, IRS will not be as effective because a larger proportion of bites take place outside of the home. -```{r,fig.align="center", fig.height=5, fig.width=7} -plot_prev() +output_exophilic <- run_simulation(timesteps = sim_length, parameters = simparams) ``` ### Plot adult female infectious mosquitoes by species over time +In the plot below, we can see that IRS is much more effective when the endophilic mosquito species is modelled compared to the scenario where an exophilic species is modelled. In this case, IRS will not be as effective because a larger proportion of bites take place outside of the home. ```{r,fig.align="center", fig.height=5, fig.width=7} -plot(x = output$timestep, y = output$Im_example_count, - type = "l", col = cols[5], lwd = 2.5, ylim = c(0, 600), - xlab = "Time (days)", ylab = "N mosquitoes", - xaxs = "i", yaxs = "i", bty = "l") -abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = "black") -lines(x = output$timestep, y = output$Im_arab_count, - col = cols[6], lwd = 2.5) -lines(x = output$timestep, y = output$Im_gamb_count, - col = cols[3], lwd = 2.5) -grid(lty = 2, col = "grey80", lwd = 1) -legend("topright", box.lty = 0, legend = c("Spraying", "Example mosquito species", expression(italic("An. arabiensis")), expression(italic("An. gambiae"))), col = c("black", cols[5], cols[6], cols[3]), lty = c(2, 1, 1, 1), lwd = 2.5) +plot_prev() ``` diff --git a/vignettes/VectorControl_Bednets.Rmd b/vignettes/VectorControl_Bednets.Rmd index 3c947698..40058d62 100644 --- a/vignettes/VectorControl_Bednets.Rmd +++ b/vignettes/VectorControl_Bednets.Rmd @@ -100,7 +100,7 @@ plot_prev() ## Comparing input coverage and population bed net usage -It is important to understand the difference between the input `coverages` argument of `set_bednets()` and the resulting population bed net usage over time in the model. When we set coverages in the above example to 0.8, we are telling the model to distribute bed nets to 50% of the population at year one and to 50% of the population at year 4. However, the level of average bed net usage is not necessarily equal to 50%. Between these time points, bed net use will slowly decline over time (in reality this decline stems from things like disuse, holes in nets, lost nets, etc.). +It is important to understand the difference between the input `coverages` argument of `set_bednets()` and the resulting population bed net usage over time in the model. When we set coverages in the above example to 0.5, we are telling the model to distribute bed nets to 50% of the population at year one and to 50% of the population at year 4. However, the level of average bed net usage is not necessarily equal to 50%. Between these time points, bed net use will slowly decline over time (in reality this decline stems from things like disuse, holes in nets, lost nets, etc.). The average population bed net usage will be influenced by: diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index 6b869a40..deff5ada 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -70,12 +70,13 @@ simparams <- set_equilibrium(parameters = simparams, init_EIR = starting_EIR) output_control <- run_simulation(timesteps = sim_length, parameters = simparams) ``` -#### A note on mosquito species -It is also possible to use the `set_species()` function to account for 3 different mosquito species in the simulation. In this case, the matrices would need to have additional column corresponding to each mosquito species. For example, if we specified that there were 3 species of mosquitoes in the model and IRS was implemented at two timesteps, then the matrices would have 2 rows and 3 columns. If you are not already familiar with the `set_species()` function, see the Set Species vignette. +#### A note on mosquito species +It is also possible to use the `set_species()` function to account for 3 different mosquito species in the simulation. In this case, the matrices would need to have additional column corresponding to each mosquito species. For example, if we specified that there were 3 species of mosquitoes in the model and nets were distributed at two timesteps, then the matrices would have 2 rows and 3 columns. If you are not already familiar with the `set_species()` function, see the Mosquito Species vignette. The default setting is to model all mosquito species together. ```{r} simparams$species +simparams$species_proportions ``` From 9172e9a17996ca6ef04704e043f1d178c451ba16 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Wed, 31 May 2023 17:35:18 +0100 Subject: [PATCH 095/164] corrected misalignment, one mos species default --- vignettes/Model.Rmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vignettes/Model.Rmd b/vignettes/Model.Rmd index 1eaa7369..a39c850e 100644 --- a/vignettes/Model.Rmd +++ b/vignettes/Model.Rmd @@ -119,7 +119,7 @@ Griffin, J. T., Bhatt, S., Sinka, M. E., Gething, P. W., Lynch, M., Patouillard, ### Code -The key package function is `run_simulation()` which, in its most basic form, simply requires a number of timesteps in days. Default parameter settings assume a human population of size of 100, an initial mosquito population size of 1000 with all species in equal proportions, with no treatment interventions and no seasonality. The full parameters list can be seen in the documentation for `get_parameters()`. +The key package function is `run_simulation()` which, in its most basic form, simply requires a number of timesteps in days. Default parameter settings assume a human population of size of 100, an initial mosquito population size of 1000 of a single species, with no treatment interventions and no seasonality. The full parameters list can be seen in the documentation for `get_parameters()`. ```{r, output.lines=6} library(malariasimulation) @@ -290,6 +290,6 @@ The remaining vignettes describe how to adjust sets of parameters through a numb - `run_metapop_simulation()`: to model multiple areas simultaneously -10. [Variation](https://mrc-ide.github.io/malariasimulation/articles/Variation.html) +9. [Variation](https://mrc-ide.github.io/malariasimulation/articles/Variation.html) - `run_simulation_with_repetitions()`: running simulations with replicates From d6aa15195ecbe64ca733f5297bb37730a8503520 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Thu, 1 Jun 2023 11:52:03 +0100 Subject: [PATCH 096/164] clarify random 50% of pop receiving nets --- vignettes/VectorControl_Bednets.Rmd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vignettes/VectorControl_Bednets.Rmd b/vignettes/VectorControl_Bednets.Rmd index 40058d62..17fafa90 100644 --- a/vignettes/VectorControl_Bednets.Rmd +++ b/vignettes/VectorControl_Bednets.Rmd @@ -71,7 +71,7 @@ simparams$species_proportions ## Simulation -Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bed nets to 50% of the population every three years. It is possible to change the characteristics of the bed nets for each distribution timestep if different types of bed nets are distributed that have different insecticides, different levels of insecticide resistance, etc. This can be done by modifying the matrices for `dn0`, `rn`, `rnm`, and `gamman`. Because we are using the default proportions of mosquito species and there are two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 1 column and 2 rows. +Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bed nets to a random 50% of the population every three years. It is possible to change the characteristics of the bed nets for each distribution timestep if different types of bed nets are distributed that have different insecticides, different levels of insecticide resistance, etc. This can be done by modifying the matrices for `dn0`, `rn`, `rnm`, and `gamman`. Because we are using the default proportions of mosquito species and there are two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 1 column and 2 rows. The parameter values for pyrethroid-only and pyrethroid-PBO nets at various resistance levels can be found in Table S1.3 in the Supplementary Appendix 2 of [Sherrard-Smith, et al., 2022](https://doi.org/10.1016/S2542-5196(21)00296-5). @@ -100,7 +100,7 @@ plot_prev() ## Comparing input coverage and population bed net usage -It is important to understand the difference between the input `coverages` argument of `set_bednets()` and the resulting population bed net usage over time in the model. When we set coverages in the above example to 0.5, we are telling the model to distribute bed nets to 50% of the population at year one and to 50% of the population at year 4. However, the level of average bed net usage is not necessarily equal to 50%. Between these time points, bed net use will slowly decline over time (in reality this decline stems from things like disuse, holes in nets, lost nets, etc.). +It is important to understand the difference between the input `coverages` argument of `set_bednets()` and the resulting population bed net usage over time in the model. When we set coverages in the above example to 0.5, we are telling the model to distribute bed nets to a random 50% of the population at year one and to a random 50% of the population at year 4. However, the level of average bed net usage is not necessarily equal to 50%. Between these time points, bed net use will slowly decline over time (in reality this decline stems from things like disuse, holes in nets, lost nets, etc.). The average population bed net usage will be influenced by: From 5333fbf178bf09ac140b711f5fb4ebaf792ddcce Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Tue, 6 Jun 2023 12:17:14 +0100 Subject: [PATCH 097/164] Updated the EIRprevmatch vignette to implement the structure recommended. --- vignettes/EIRprevmatch.Rmd | 225 ++++++++++++++++++++++++++++--------- 1 file changed, 172 insertions(+), 53 deletions(-) diff --git a/vignettes/EIRprevmatch.Rmd b/vignettes/EIRprevmatch.Rmd index 2fa50227..e0fca1a0 100644 --- a/vignettes/EIRprevmatch.Rmd +++ b/vignettes/EIRprevmatch.Rmd @@ -1,8 +1,8 @@ --- -title: "Matching *Pf*PR~2-10~ to EIR" +title: "Matching EIR to *Pf*PR~2-10~" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{EIRprevmatch} + %\VignetteIndexEntry{Matching EIR to *Pf*PR~2-10~} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -18,20 +18,57 @@ knitr::opts_chunk$set( # Load in the requisite functions library(malariasimulation) library(malariaEquilibrium) +library(cali) library(mgcv) -# Define a colour palette for plotting: -plot_cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") - ``` ## Introduction -The entomological inoculation rate (EIR), defined as the number of infectious bites experienced per person per unit time, and malaria prevalence, the proportion of the population with detectable malaria, are two metrics commonly used to measure and/or describe malaria transmission. With respect to the latter, focus is often given to prevalence in the age groups 2-10 years old, denoted *Pf*PR~2-10~, the prevalence rate of *Plasmodium falciparum* in children aged two to ten. When setting up a simulation run, users often need to specify a baseline EIR or *Pf*PR~2-10~ . While `malariasimulation` enables users to set and and calibrate to an initial EIR (using the `set_equilibrium()` function), establishing a user-defined baseline *Pf*PR~2-10~ requires additional steps, outlined in this vignette. +The entomological inoculation rate (EIR), defined as the number of infectious bites experienced per person per unit time, and malaria prevalence, the proportion of the population with detectable malaria, are two metrics commonly used to measure and/or describe malaria transmission. With respect to the latter, focus is often given to prevalence in the age group 2-10 years old, denoted *Pf*PR~2-10~, the prevalence rate of *Plasmodium falciparum* in children aged two to ten years old. When setting up a simulation run, users often need to specify a baseline EIR or *Pf*PR~2-10~ . While `malariasimulation` enables users to set and and calibrate to an initial EIR (using the `set_equilibrium()` function), establishing a user-defined baseline *Pf*PR~2-10~ requires to identify the EIR value that would yield the target baseline *Pf*PR~2-10~ value. + +In this vignette, three methods for matching the EIR to a target *Pf*PR~2-10~ are outlined and compared. The first uses the `malariaEquilibrium` package's `human_equilibrium()` function to quickly calculate the equilibrial *Pf*PR~2-10~ for a given EIR using the canonical equilibrium solution for the `malariasimulation` model. The second method involves running `malariasimualtion` simulations across a range of initial EIR values, extracting the *Pf*PR~2-10~ from each simulation run, fitting a model relating initial EIR to *Pf*PR~2-10~, and using the model to predict the initial EIR value required to yield the desired *Pf*PR~2-10~. The third approach is to calibrate the model using the `cali` package's (see for more information) `calibrate()` function, which searches a user-defined initial EIR parameter space and identifies the value which yields a target *Pf*PR~2-10~ within a defined tolerance. + +## *Pf*PR~2-10~ matching using malariaEquilibrium + +The `malariaEquilibrium` package function `human_equilibrium()` can be used to return the canonical equilibrium solution of the system for a given EIR and the matching *Pf*PR~2-10~ calculated from the output (see for more information). First, we generate a large vector of EIR values for which we want to generate matching *Pf*PR~2-10~ values. Next, we load the package's default parameter set (`Jamie_parameters.rds`) and, for each EIR value generated, run the `human_equilibrium()` function. The `human_equilibrium()` function returns a dataframe containing the proportion of each age class in each state variables at equilibrium. The *Pf*PR~2-10~ is then calculated from the output for each EIR value by summing the proportion of people aged 2-10 with cases of malaria (`pos_M`) to get the proportion of individuals aged 2-10 with malaria, and dividing this proportion by the proportion of the population between the ages 2-10 (`prop`). Finally, we store the matching EIR and *Pf*PR~2-10~ values in a data frame. + +```{r} + +# Establish a range of EIR values to generate matching PfPR2-10 values for +malEq_EIR <- seq(from = 0.1, to = 50, by = 0.5) + +# Load the base malariaSimulation parameter set: +eq_simparams <- malariaEquilibrium::load_parameter_set("Jamie_parameters.rds") + +# Use human_equilibrium to calculate the PfPR2-10 values for the range of +# EIR values +malEq_prev <- vapply( + malEq_EIR, + function(eir) { + eq <- malariaEquilibrium::human_equilibrium( + eir, + ft = 0, + p = eq_simparams, + age = 0:100 + ) + sum(eq$states[3:11, 'pos_M']) / sum(eq$states[3:11, 'prop']) + }, + numeric(1) +) + +# Establish a dataframe containing the matching EIR and PfPR2-10 values +malEq_P2E <- cbind.data.frame(EIR = malEq_EIR, prev = malEq_prev) + +``` + +This method does not involve running simulations and can therefore be used to return matching *Pf*PR~2-10~ for a wide range of EIR values very quickly. However, it is only viable for systems at steady state and with a fixed set of parameter values and with limited options for capturing the effects of interventions designed to combat malaria transmission. Often, when running `malariasimulation` simulations, one or both of these conditions are not met and, therefore, a different solution is required. -Briefly, the user establishes their set of baseline parameters and runs simulations for a range of initial EIR values for a duration sufficient for the model to reach equilibrium. The equilibrial *Pf*PR~2-10~ is then extracted from the simulation outputs and a curve fit relating these values to the initial EIR. Using this curve, the user can then estimate the initial EIR value required to yield the desired *Pf*PR~2-10~ (given the parameter set). This method is contrasted with an alternative, which uses the `malariaEquilibrium` package's `human_equilibrium()` function to calculate the equilibrial *Pf*PR~2-10~ for a given EIR using the canonical equilibrium solution for the `malariasimulation` model. An alternative method, not covered here, is to calibrate the model using the `cali` package (see for more information). +## *Pf*PR~2-10~ matching using malariasimulation -## Parameterisation +Where the `malariaEquilibrium` method is not viable, a slower, more flexible alternative is to run `malariasimulation` simulations over a smaller range of initial EIR values, extract the PfPR2-10 from each run, fit a model relating initial EIR to PfPR2-10, and use the model to predict the initial EIR value required to yield the desired PfPR2-10. An example of this method is outlined below. + +### Establish malariasimulation parameters To run `malariasimulation`, the first step is to generate a list of parameters using the `get_parameters()` function, which loads the default `malariasimulation` parameter list. Within this function call, we adapt the average age of the human population to flatten its demographic profile, specify seasonal malaria transmission, instruct the model to output malaria prevalence in the age range of 2-10 years old, and switch off the individual-based mosquito module. The `set_species()` function is then called to specify the composition of the vector community. The `set_drugs()` function is used to append the in-built parameters for Artemether Lumefantrine (AL) and, finally, the `set_clinical_treatment()` function is called to specify a treatment campaign that distribute AL to 45% of the population in the first time step (t = 1). @@ -51,10 +88,10 @@ simparams <- get_parameters(list( average_age = 8453.323, # Turn on a specfiy seasonal transmission pattern - model_seasonality = TRUE, - g0 = 0.284596, - g = c(-0.317878, -0.0017527, 0.116455), - h = c(-0.331361, 0.293128, -0.0617547), + #model_seasonality = TRUE, + #g0 = 0.284596, + #g = c(-0.317878, -0.0017527, 0.116455), + #h = c(-0.331361, 0.293128, -0.0617547), # Instruct model to render prevalence in age group 2-10 prevalence_rendering_min_ages = 2 * year, @@ -82,9 +119,9 @@ simparams <- set_clinical_treatment(parameters = simparams, ``` -## *Pf*PR~2-10~ Matching using malariasimulation +### Run simulations and calculate *Pf*PR~2-10~ -Having established a set of `malariasimulation` parameters, we are now ready to run simulations. In the following code chunk, we'll run the `run_simulation()` across a range of initial EIR values to generate sufficient points to fit a curve matching *Pf*PR~2-10~ to the initial EIR. For each initial EIR, we first use the `set_equilibrium()` to update the model parameter list with the human and vector population parameter values required to achieve the specified EIR at equilibrium. This updated parameter list is then used to run the simulation. +Having established a set of `malariasimulation` parameters, we are now ready to run simulations. In the following code chunk, we'll run the `run_simulation()` function across a range of initial EIR values to generate sufficient points to fit a curve matching *Pf*PR~2-10~ to the initial EIR. For each initial EIR, we first use the `set_equilibrium()` to update the model parameter list with the human and vector population parameter values required to achieve the specified EIR at equilibrium. This updated parameter list is then used to run the simulation. The `run_simulation()` outputs an EIR per time step, per species, across the entire human population. We first convert these to get the number of infectious bites experienced, on average, by each individual across the final year across all vector species. Next, the average *Pf*PR~2-10~ across the final year of the simulation is calculated by dividing the total number of individuals aged 2-10 by the number (`n_730_3650`) of detectable cases of malaria in individuals aged 2-10 (`n_detect_730_3650`) on each day and calculating the mean of these values. Finally, initial EIR, output EIR, and *Pf*PR~2-10~ are stored in a data frame. @@ -94,7 +131,7 @@ The `run_simulation()` outputs an EIR per time step, per species, across the ent # PfPR2-10 values: init_EIR <- c(0.01, 0.1, 1, 5, 10, 25, 50) -# For each initial EIR, calculate equilibriual parameter set and run the simulation +# For each initial EIR, calculate equilibrial parameter set and run the simulation malSim_outs <- lapply( init_EIR, function(init) { @@ -142,40 +179,7 @@ malSim_P2E <- cbind.data.frame(init_EIR, EIR = unlist(malSim_EIR), prev = unlist ``` -## *Pf*PR~2-10~ Matching using malariaEquilibrium - -We can also use the `malariaEquilibrium` package function `human_equilibrium()` to calculate the canonical equilibrium state of the system for a range of EIRs and match the *Pf*PR~2-10~ (see for more information). This method does not involve running simulations and is therefore faster, so we first generate a larger vector of EIR values to generate matching *Pf*PR~2-10~ values for, and then load the package's default parameter set. For each EIR value, we run the `human_equilibrium()` function and calculate the *Pf*PR~2-10~ from the output by summing the number of positive cases in ages 2-10 by the number of people in the age classes 2-10. Finally, we store the matching EIR and *Pf*PR~2-10~ values in a data frame. - -```{r} - -# Establish a range of EIR values to generate matching PfPR2-10 values for -malEq_EIR <- seq(from = 0.1, to = 50, by = 0.5) - -# Load the base malariaSimulation parameter set: -eq_simparams <- malariaEquilibrium::load_parameter_set("Jamie_parameters.rds") - -# Use human_equilibrium to calculate the PfPR2-10 values for the range of -# EIR values -malEq_prev <- vapply( - malEq_EIR, - function(eir) { - eq <- malariaEquilibrium::human_equilibrium( - eir, - ft = 0, - p = eq_simparams, - age = 0:100 - ) - sum(eq$states[3:11, 'pos_M']) / sum(eq$states[3:11, 'prop']) - }, - numeric(1) -) - -# Establish a dataframe containing the matching EIR and PfPR2-10 values -malEq_P2E <- cbind.data.frame(EIR = malEq_EIR, prev = malEq_prev) - -``` - -## Predicting *Pf*PR~2-10~ using Initial EIR +### Fit line of best fit relating initial EIR values to *Pf*PR~2-10~ Having run `malariasimulation` simulations for a range of initial EIRs, we can fit a line of best fit through the initial EIR and *Pf*PR~2-10~ data and use it to predict the prevalence for a wider range of initial EIRs (given the set of parameters used). Note that the `newdata` argument is used to generate a series of additional initial EIR and *Pf*PR~2-10~ pairs for plotting. @@ -194,10 +198,13 @@ malSim_fit <- cbind(malSim_fit, data.frame(init_EIR = c(0 ,seq(0.1, 50, 0.1)))) ## Visualisation -Now lets visually compare our two methods for matching EIR to *Pf*PR~2-10~ values. In the section below we open a blank plot, plot the intial EIR and resulting *Pf*PR~2-10~ points generated using `malariasimulation` runs, overlay the line of best fit (orange line). Also overlayed is a line mapping EIR and *Pf*PR~2-10~ values calculated using `malariaEquilibrium` (blue line). +Let's visually compare our the `malariaEquilibrium` and `malariasimulation` methods for matching EIR to *Pf*PR~2-10~ values. In the section below we open a blank plot, plot the initial EIR and resulting *Pf*PR~2-10~ points generated using `malariasimulation` runs, overlay the line of best fit (orange line). Also overlayed is a line mapping EIR and *Pf*PR~2-10~ values calculated using `malariaEquilibrium` (blue line). ```{r, fig.width = 6.8, fig.height = 4} +# Define a colour palette for plotting: +plot_cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") + # Establish a plotting window: plot(x = 1, type = "n", frame = F, @@ -229,14 +236,16 @@ lines(x = malEq_P2E$EIR, # Add a legend legend("topright", - legend=c("malariasimulation", "malariaEquilibrium"), - col=c(plot_cols[1:2]), lty = c(1,1), cex=0.8) + legend = c("malariasimulation", "malariaEquilibrium"), + col = c(plot_cols[1:2]), lty = c(1, 1), cex=0.8, box.col = "white") ``` +Looking at the plot, we can see that, to achieve a given *Pf*PR~2-10~, the `malariaEquilibrium` and `malariasimulation` approaches recommend a quite different EIR value, with the `malariaEquilibrium` method typically requiring a much lower EIR value to achieve a given *Pf*PR~2-10~ (given the `malariasimulation` parameter set used). + ## Matching EIR to *Pf*PR~2-10~ values -We can also create a function that extracts EIR values from the fitted line for *Pf*PR~2-10~ values of interest. The function works by finding the closest *Pf*PR~2-10~ value from the model fit to that specified by the user, and then using that index to return the corresponding initial EIR value. +Using the fitted relationship between initial EIR and *Pf*PR~2-10~, we can create a function that returns the EIR value(s) estimated to yield a target *Pf*PR~2-10~ given the model parameters. The function below works by finding the closest *Pf*PR~2-10~ value from the values generated when we fit the model to the target value input by the user, and then using that index to return the corresponding initial EIR value. ```{r table, warning=F} @@ -260,3 +269,113 @@ matched_EIRs <- unlist(lapply(PfPRs_to_match, match_EIR_to_PfPR)) cbind.data.frame(PfPR = PfPRs_to_match, Matched_EIR = matched_EIRs) ``` + +## Calibrating *Pf*PR~2,10~ using the cali package + +A final option is to use the `calibrate()` function from the `cali` package (for details see: ) to return the EIR required to yield a target *Pf*PR~2-10~. Rather than manually running a series of simulations with varied EIRs, this package contains the `calibrate()` function, which calibrates `malariasimulation` simulation outputs to a target *Pf*PR~2-10~ value within a user-specified tolerance by trying a series of EIR values. + +The `calibrate()` function accepts as inputs a list of `malariasimulation` parameters, a summary function that takes the `malariasimulation` output and returns a vector of the target variable (e.g. a function that returns the *Pf*PR\~2-10), a tolerance within which to accept the output target variable value and terminate the routine. To reduce the time taken by the `calibrate()` function, the user can also specify upper and lower bounds for the model to vary the EIR between. The function then runs through a series of `malariasimulation` simulations, trying different EIRs and hoing in on the target value of the target variable, terminating when the target value output falls within the tolerance specified. + +```{r, echo = T, results = 'hide'} + +# Prepare a summary function that returns the mean PfPR2-10 from the final +summary_mean_pfpr_2_10 <- function (x) { + + # calculate the PfPR2-10 + prev_2_10 <- mean(x$n_detect_730_3650/x$n_730_3650) + + # Return the calculated PfPR2-10 + return(prev_2_10) +} + +# Establish a target value +target_pfpr <- 0.3 + +# Add a parameter to the parameter list specifying the number of timesteps to +# simulate over. Note, increasing the number of steps gives the simulation longer +# to stablise/equilibrate, but will increase the time runtime for calibrate(). +simparams$timesteps <- 3 * 365 + +# Use the match_EIR_to_PfPR() function to return the EIR predicted to be required under the +# malariasimulation method +malsim_EIR <- match_EIR_to_PfPR(x = target_pfpr) + +# Establish a tolerance value: +pfpr_tolerance <- 0.01 + +# Set upper and lower EIR bounds for the calibrate function to check (remembering EIR is +# the variable that is used to tune to the target PfPR): +lower_EIR <- 8; upper_EIR <- 12 + +# Run the calibrate() function: +cali_EIR <- calibrate(target = target_pfpr, + summary_function = summary_mean_pfpr_2_10, + parameters = simparams, + tolerance = pfpr_tolerance, + low = lower_EIR, high = upper_EIR) + +``` + +The `calibrate()` function is a useful tool, but be aware that it relies on the user selecting and accurately coding an effective summary function, providing reasonable bounds on the EIR space to explore, and selecting a population size sufficiently large to limit the influence of stochasticity. + +As a final exercise, let's compare graphically the `calibrate()` approach with the `malariasimulation` method when the same parameter set is used. The plot below shows the change in *Pf*PR~2,10~ over the duration of the simulation under the initial EIR values recommended by the a) `cali` and b) `malariasimulation` methods. The blue horizontal line represents the target *Pf*PR~2,10~ the methods were attempting to match to, and the black lines either side the upper and lower tolerance limits specified for the `cali` method. + +```{r, fig.width = 6.8, fig.height = 4} + +# Use the set_equilibrium() function to equilibriate the simparams to the calibrated EIR: +simparams_cali <- set_equilibrium(simparams, init_EIR = cali_EIR) +simparams_malsim <- set_equilibrium(simparams, init_EIR = malsim_EIR) + +# Run the simulation: +cali_sim <- run_simulation(timesteps = (simparams_cali$timesteps), + parameters = simparams_cali) +malsim_sim <- run_simulation(timesteps = (simparams_malsim$timesteps), + parameters = simparams_malsim) + +# Extract the PfPR2-10 values for the cali and malsim simulation outputs: +cali_pfpr2_10 <- cali_sim$n_detect_730_3650 / cali_sim$n_730_3650 +malsim_pfpr2_10 <- malsim_sim$n_detect_730_3650 / malsim_sim$n_730_3650 + +# Store the PfPR2-10 from the two methods for the two methods: +df <- data.frame(timestep = seq(1, length(cali_pfpr2_10)), + cali_pfpr = cali_pfpr2_10, + malsim_pfpr = malsim_pfpr2_10) + +# Set the plotting window +par(mfrow = c(1, 2), mar = c(4, 4, 1, 1)) + +# Plot the PfPR2-10 under the EIR recommended by the cali method +plot(x = df$timestep, + y = df$malsim_pfpr, + type = "b", + ylab = expression(paste(italic(Pf),"PR"[2-10])), + xlab = "Time (days)", + ylim = c(target_pfpr - 0.2, target_pfpr + 0.2), + #ylim = c(0, 1), + col = plot_cols[3]) + +# Add textual identifier and lines indicating target PfPR2-10 with tolerance bounds +text(x = 10, y = 0.47, pos = 4, cex = 0.9, + paste0("a) cali \n init_EIR = ", round(cali_EIR, digits = 3))) +abline(h = target_pfpr, col = "dodgerblue", lwd = 2) +abline(h = target_pfpr - pfpr_tolerance, lwd = 2) +abline(h = target_pfpr + pfpr_tolerance, lwd = 2) + +# Plot the PfPR2-10 under the EIR recommended by the malariasimulation method +plot(x = df$timestep, + y = df$cali_pfpr, + type = "b", + xlab = "Time (days)", + ylab = "", + ylim = c(target_pfpr - 0.2, target_pfpr + 0.2), + #ylim = c(0, 1), + col = plot_cols[1]) + +# Add textual identifier and lines indicating target PfPR2-10 with tolerance bounds +text(x = 10, y = 0.47, pos = 4, cex = 0.9, + paste0("b) malariasimulation \n init_EIR = ", round(malsim_EIR, digits = 3))) +abline(h = target_pfpr, col = "dodgerblue", lwd = 2) +abline(h = target_pfpr - pfpr_tolerance, lwd = 2) +abline(h = target_pfpr + pfpr_tolerance, lwd = 2) + +``` From ebd0f6559f1164e6b2f21696284a8bf5bdc559c6 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Tue, 6 Jun 2023 14:31:21 +0100 Subject: [PATCH 098/164] Final(?) changes following feedback. --- vignettes/Model.Rmd | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/vignettes/Model.Rmd b/vignettes/Model.Rmd index a39c850e..cef9eb2c 100644 --- a/vignettes/Model.Rmd +++ b/vignettes/Model.Rmd @@ -119,7 +119,7 @@ Griffin, J. T., Bhatt, S., Sinka, M. E., Gething, P. W., Lynch, M., Patouillard, ### Code -The key package function is `run_simulation()` which, in its most basic form, simply requires a number of timesteps in days. Default parameter settings assume a human population of size of 100, an initial mosquito population size of 1000 of a single species, with no treatment interventions and no seasonality. The full parameters list can be seen in the documentation for `get_parameters()`. +The key package function is `run_simulation()` which, in its most basic form, simply requires a number of timesteps in days. Default parameter settings assume a human population of size of 100, an initial mosquito population size of 1000 of a single species (default set to *Anopheles gambiae* parameters), with no treatment interventions and no seasonality. The full parameters list can be seen in the documentation for `get_parameters()`. ```{r, output.lines=6} library(malariasimulation) @@ -131,9 +131,9 @@ test_sim <- run_simulation(timesteps = 100) The `run_simulation()` function then simulates malaria transmission dynamics and returns a dataframe for the following parameters through time: - `infectivity`: human infectiousness -- `EIR_All`: the entomological inoculation rate -- `FOIM`: the force of mosquito infection -- `mu_All`: adult mosquito death rate +- `EIR_All`: the entomological inoculation rate (for all mosquito species) +- `FOIM`: the force of infection on mosquitoes +- `mu_All`: adult mosquito death rate (for all species) - `n_bitten`: the number of infectious bites - `n_infections`: the number human infections - `natural_deaths`: deaths from old age @@ -186,7 +186,7 @@ states_plot <- function(sim){ points(x = sim$timestep, y = sim[,cols_to_plot[x]], type = "l", col = cols[x])}) # Add legend - legend("topleft", legend = c("S","D","A","U","Tr"), col = cols, lty = 1, bty = "n", ncol = 5) + legend("topleft", legend = c("S","D","A","U","Tr"), col = cols, lty = 1, bty = "n", ncol = 2) } par(mfrow = c(1,2)) @@ -236,8 +236,6 @@ new_params <- get_parameters(overrides = list(human_population = 200)) While other parameters can be changed individually, we do not generally recommended adjusting these without close attention and a detailed understanding of how this will impact the model assumptions. We strongly encourage users to stick with the parameter setting functions and methods described in these vignettes when adjusting parameter settings. - - ## Vignettes The remaining vignettes describe how to adjust sets of parameters through a number of functions as follows: @@ -245,11 +243,11 @@ The remaining vignettes describe how to adjust sets of parameters through a numb 1. [Population Demography](https://mrc-ide.github.io/malariasimulation/articles/Demography.html) - Age group rendering - - `set_demography()`: setting demographies + - `set_demography()`: setting demographies and time-varying death rates 2. [Carrying capacity](https://mrc-ide.github.io/malariasimulation/articles/Carrying-capacity.html) - - Seasonality + - Setting seasonality parameters - `set_carrying_capacity()`: changes mosquito carrying capacity, e.g. to model larval source management impact - `set_species`: to model multiple species and species invasion @@ -290,6 +288,6 @@ The remaining vignettes describe how to adjust sets of parameters through a numb - `run_metapop_simulation()`: to model multiple areas simultaneously -9. [Variation](https://mrc-ide.github.io/malariasimulation/articles/Variation.html) +10. [Variation](https://mrc-ide.github.io/malariasimulation/articles/Variation.html) - `run_simulation_with_repetitions()`: running simulations with replicates From de37c073c7a0a729923dea7786877e3a64e32470 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Tue, 6 Jun 2023 15:19:00 +0100 Subject: [PATCH 099/164] Changed mum parameter for consistency with single vector species (gambiae, rather than current: 'All') --- R/parameters.R | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/R/parameters.R b/R/parameters.R index 65779314..8a96989a 100644 --- a/R/parameters.R +++ b/R/parameters.R @@ -18,7 +18,7 @@ #' * dl - the delay for mosquitoes to move from state L to P; default = 3.72 #' * dpl - the delay mosquitoes to move from state P to Sm; default = 0.643 #' * mup - the rate at which pupal mosquitoes die; default = 0.249 -#' * mum - the rate at which developed mosquitoes die; default = 0.1253333 +#' * mum - the rate at which developed mosquitoes die; default (An. gambiae) = .132 #' #' immunity decay rates: #' @@ -135,9 +135,9 @@ #' * beta - the average number of eggs laid per female mosquito per day; default = 21.2 #' * total_M - the initial number of adult mosquitos in the simulation; default = 1000 #' * init_foim - the FOIM used to calculate the equilibrium state for mosquitoes; default = 0 -#' * species - names of the species in the simulation; default = "All" +#' * species - names of the species in the simulation; default = "gamb" #' * species_proportions - the relative proportions of each species; default = 1 -#' * blood_meal_rates - the blood meal rates for each species; default = 0.3333333333 +#' * blood_meal_rates - the blood meal rates for each species; default = 1/3 #' * Q0 - proportion of blood meals taken on humans; default = 0.92 #' * foraging_time - time spent taking blood meals; default = 0.69 #' @@ -234,7 +234,7 @@ get_parameters <- function(overrides = list()) { dl = 3.72, dpl = .643, mup = .249, - mum = .1253333, + mum = .132, sigma_squared = 1.67, n_heterogeneity_groups = 5, # immunity decay rates @@ -317,8 +317,8 @@ get_parameters <- function(overrides = list()) { beta = 21.2, total_M = 1000, init_foim= 0, - # order of species: An gambiae s.s, An arabiensis, An funestus - species = 'All', + # species-specific vector biology (default is An. gambiae s.s) + species = 'gamb', species_proportions = 1, blood_meal_rates = 1/3, Q0 = .92, From 68ea05ec6a8a37345ec63324d12e2a3e331ce1b1 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Wed, 7 Jun 2023 09:05:19 +0100 Subject: [PATCH 100/164] Removed mosquito species 'All' replaced with 'gamb' --- vignettes/Carrying-capacity.Rmd | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vignettes/Carrying-capacity.Rmd b/vignettes/Carrying-capacity.Rmd index 82fd77d2..4525ccb8 100644 --- a/vignettes/Carrying-capacity.Rmd +++ b/vignettes/Carrying-capacity.Rmd @@ -70,8 +70,8 @@ s_seasonal <- run_simulation(timesteps = timesteps, parameters = p_seasonal) s_seasonal$pfpr <- s_seasonal$n_detect_730_3650 / s_seasonal$n_730_3650 par(mfrow = c(1, 2)) -plot(s$EIR_All ~ s$timestep, t = "l", ylim = c(0, 200), xlab = "Time", ylab = "EIR") -lines(s_seasonal$EIR_All ~ s_seasonal$timestep, col = "darkorchid3") +plot(s$EIR_gamb ~ s$timestep, t = "l", ylim = c(0, 200), xlab = "Time", ylab = "EIR") +lines(s_seasonal$EIR_gamb ~ s_seasonal$timestep, col = "darkorchid3") plot(s$pfpr ~ s$timestep, t = "l", ylim = c(0, 1), xlab = "Time", ylab = "PfPr") lines(s_seasonal$pfpr ~ s_seasonal$timestep, col = "darkorchid3") ``` @@ -111,8 +111,8 @@ s_lsm <- run_simulation(timesteps = timesteps, parameters = p_lsm) s_lsm$pfpr <- s_lsm$n_detect_730_3650 / s_lsm$n_730_3650 par(mfrow = c(1, 2)) -plot(s$EIR_All ~ s$timestep, t = "l", ylim = c(0, 150), xlab = "Time", ylab = "EIR") -lines(s_lsm$EIR_All ~ s_lsm$timestep, col = "darkorchid3") +plot(s$EIR_gamb ~ s$timestep, t = "l", ylim = c(0, 150), xlab = "Time", ylab = "EIR") +lines(s_lsm$EIR_gamb ~ s_lsm$timestep, col = "darkorchid3") abline(v = 365, lty = 2, col = "grey60") plot(s$pfpr ~ s$timestep, t = "l", ylim = c(0, 1), xlab = "Time", ylab = "PfPr") lines(s_lsm$pfpr ~ s_lsm$timestep, col = "darkorchid3") @@ -176,8 +176,8 @@ s_flexible <- run_simulation(timesteps = timesteps, parameters = p_flexible) s_flexible$pfpr <- s_flexible$n_detect_730_3650 / s_flexible$n_730_3650 par(mfrow = c(1, 2)) -plot(s$EIR_All ~ s$timestep, t = "l", ylim = c(0, 150), xlab = "Time", ylab = "EIR") -lines(s_flexible$EIR_All ~ s_flexible$timestep, col = "darkorchid3") +plot(s$EIR_gamb ~ s$timestep, t = "l", ylim = c(0, 150), xlab = "Time", ylab = "EIR") +lines(s_flexible$EIR_gamb ~ s_flexible$timestep, col = "darkorchid3") abline(v = 365, lty = 2, col = "grey60") plot(s$pfpr ~ s$timestep, t = "l", ylim = c(0, 1), xlab = "Time", ylab = "PfPr") lines(s_flexible$pfpr ~ s_flexible$timestep, col = "darkorchid3") From 336bf712f527e5b31437753869c83f0978f30c2b Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Wed, 7 Jun 2023 10:06:48 +0100 Subject: [PATCH 101/164] Changed mosquito species 'All' to 'gamb' in testfiles --- tests/testthat/test-biting-integration.R | 4 ++-- tests/testthat/test-vector-control.R | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/testthat/test-biting-integration.R b/tests/testthat/test-biting-integration.R index 8a076b96..66bf5b72 100644 --- a/tests/testthat/test-biting-integration.R +++ b/tests/testthat/test-biting-integration.R @@ -84,8 +84,8 @@ test_that('simulate_bites integrates eir calculation and mosquito side effects', c(rep('Im', 10), rep('Sm', 15), rep('NonExistent', 75)) ) variables$species <- individual::CategoricalVariable$new( - c('All'), - rep('All', 100) + c('gamb'), + rep('gamb', 100) ) lambda_mock <- mockery::mock(c(.5, .5, .5, .5)) diff --git a/tests/testthat/test-vector-control.R b/tests/testthat/test-vector-control.R index 6001eeac..34f9d6ef 100644 --- a/tests/testthat/test-vector-control.R +++ b/tests/testthat/test-vector-control.R @@ -363,13 +363,13 @@ test_that('usage renderer outputs correct values', { test_that('set_carrying_capacity works',{ p <- list() - p$species <- "All" + p$species <- "gamb" p_out <- set_carrying_capacity(p, 1, matrix(0.1)) expect_equal( p_out, list( - species = "All", + species = "gamb", carrying_capacity = TRUE, carrying_capacity_timesteps = 1, carrying_capacity_values = matrix(0.1) From 38dcae73ed3e6c96964815cc38dde0b2dcd86c7e Mon Sep 17 00:00:00 2001 From: Giovanni Charles Date: Mon, 12 Jun 2023 11:30:03 +0100 Subject: [PATCH 102/164] Update compartmental test to be less brittle: * calculate foim and total_M based on vector parameters using set_equilibrium --- src/RcppExports.cpp | 2 +- tests/testthat/test-compartmental.R | 15 +++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index affb233d..f5c226fd 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -260,7 +260,7 @@ BEGIN_RCPP END_RCPP } -RcppExport SEXP run_testthat_tests(void); +RcppExport SEXP run_testthat_tests(); static const R_CallMethodDef CallEntries[] = { {"_malariasimulation_create_adult_mosquito_model", (DL_FUNC) &_malariasimulation_create_adult_mosquito_model, 5}, diff --git a/tests/testthat/test-compartmental.R b/tests/testthat/test-compartmental.R index 410b3be4..a4fb3b6a 100644 --- a/tests/testthat/test-compartmental.R +++ b/tests/testthat/test-compartmental.R @@ -31,12 +31,8 @@ test_that('ODE stays at equilibrium with a constant total_M', { }) test_that('Adult ODE stays at equilibrium with a constant foim and mu', { - foim <- 0.5 - parameters <- get_parameters(list( - individual_mosquitoes = FALSE, - init_foim = foim - )) - total_M <- 1000 + parameters <- get_parameters() + parameters <- set_equilibrium(parameters, 100.) f <- parameters$blood_meal_rates timesteps <- 365 * 10 models <- parameterise_mosquito_models(parameters, timesteps) @@ -50,25 +46,24 @@ test_that('Adult ODE stays at equilibrium with a constant foim and mu', { adult_mosquito_model_update( models[[1]], parameters$mum, - foim, + parameters$init_foim, states[ADULT_ODE_INDICES['Sm']], f ) solver_step(solvers[[1]]) } - + expected <- c() equilibrium <- initial_mosquito_counts( parameters, 1, parameters$init_foim, - total_M + parameters$total_M ) for (t in seq(timesteps)) { expected <- rbind(expected, c(t, equilibrium)) } - expect_equal(counts, expected, tolerance=1e-4) }) From f67fc22426a5f1e52b51421655a19f66c7bde1e0 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Mon, 12 Jun 2023 16:36:05 +0100 Subject: [PATCH 103/164] Extra 'All' to 'gamb' change --- tests/testthat/test-emergence-integration.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-emergence-integration.R b/tests/testthat/test-emergence-integration.R index 226ad484..fa7464be 100644 --- a/tests/testthat/test-emergence-integration.R +++ b/tests/testthat/test-emergence-integration.R @@ -5,14 +5,14 @@ test_that('emergence process fails when there are not enough individuals', { c(rep('Im', 1000), rep('Sm', 1000)) ) species <- individual::CategoricalVariable$new( - c('All'), - rep('All', 2000) + c('gamb'), + rep('gamb', 2000) ) emergence_process <- create_mosquito_emergence_process( list(), state, species, - c('All'), + c('gamb'), parameters$dpl ) mockery::stub( From 37460795f7d8cd75470cf949bb746173c93679e0 Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Wed, 14 Jun 2023 13:44:35 +0100 Subject: [PATCH 104/164] I have implmemented the changes requested following the last pull request, and have also updated the parameterisation for the malariaEquilibrium example so that the treatment now approximately matches that of the malariasimulation example. --- vignettes/EIRprevmatch.Rmd | 171 ++++++++++++++++++------------- vignettes/EIRprevmatch_Fig_1.png | Bin 0 -> 5110 bytes vignettes/EIRprevmatch_Fig_2.png | Bin 0 -> 9423 bytes 3 files changed, 97 insertions(+), 74 deletions(-) create mode 100644 vignettes/EIRprevmatch_Fig_1.png create mode 100644 vignettes/EIRprevmatch_Fig_2.png diff --git a/vignettes/EIRprevmatch.Rmd b/vignettes/EIRprevmatch.Rmd index e0fca1a0..738d55da 100644 --- a/vignettes/EIRprevmatch.Rmd +++ b/vignettes/EIRprevmatch.Rmd @@ -15,40 +15,50 @@ knitr::opts_chunk$set( ``` ```{r setup, message=F, warning=F} + # Load in the requisite functions library(malariasimulation) library(malariaEquilibrium) -library(cali) -library(mgcv) + +# The cali and mgcv packages are required but not loaded. To run the code manually load these: +# packages. +#library(mgcv) +#library(cali) ``` ## Introduction -The entomological inoculation rate (EIR), defined as the number of infectious bites experienced per person per unit time, and malaria prevalence, the proportion of the population with detectable malaria, are two metrics commonly used to measure and/or describe malaria transmission. With respect to the latter, focus is often given to prevalence in the age group 2-10 years old, denoted *Pf*PR~2-10~, the prevalence rate of *Plasmodium falciparum* in children aged two to ten years old. When setting up a simulation run, users often need to specify a baseline EIR or *Pf*PR~2-10~ . While `malariasimulation` enables users to set and and calibrate to an initial EIR (using the `set_equilibrium()` function), establishing a user-defined baseline *Pf*PR~2-10~ requires to identify the EIR value that would yield the target baseline *Pf*PR~2-10~ value. +The entomological inoculation rate (EIR), defined as the number of infectious bites experienced per person per unit time, and malaria prevalence, the proportion of the population with detectable malaria, are two metrics used to measure and/or describe malaria transmission. With respect to the latter, the focus is often on the prevalence rate of *Plasmodium falciparum* in children aged two to ten years old, denoted *Pf*PR~2-10~. + +When setting up a simulation, `malariasimulation` users often need to calibrate the model run to an observed level of transmission. Calibrating to an EIR value can be done directly using the `set_equilibrium()` function, but EIR is difficult to measure and in practice *Pf*PR~2-10~ is more commonly recorded/reported as a measure of transmission. However, `malariasimulation` does not allow users to calibrate directly to an *Pf*PR~2-10~ value. To calibrate to a target *Pf*PR~2-10~, users must instead identify and input the EIR value that yields the target *Pf*PR~2-10~ value. In this vignette, three methods for matching the EIR to a target *Pf*PR~2-10~ are outlined and compared. -In this vignette, three methods for matching the EIR to a target *Pf*PR~2-10~ are outlined and compared. The first uses the `malariaEquilibrium` package's `human_equilibrium()` function to quickly calculate the equilibrial *Pf*PR~2-10~ for a given EIR using the canonical equilibrium solution for the `malariasimulation` model. The second method involves running `malariasimualtion` simulations across a range of initial EIR values, extracting the *Pf*PR~2-10~ from each simulation run, fitting a model relating initial EIR to *Pf*PR~2-10~, and using the model to predict the initial EIR value required to yield the desired *Pf*PR~2-10~. The third approach is to calibrate the model using the `cali` package's (see for more information) `calibrate()` function, which searches a user-defined initial EIR parameter space and identifies the value which yields a target *Pf*PR~2-10~ within a defined tolerance. +The first and fastest method uses the `malariaEquilibrium` package function `human_equilibrium()` to calculate the equilibrium *Pf*PR~2-10~ for a given EIR using the canonical equilibrium solution for the `malariasimulation` model. The second method involves running `malariasimulation` simulations across a small set of initial EIR values, extracting the *Pf*PR~2-10~ from each simulation run, and fitting a model relating initial EIR to *Pf*PR~2-10~ to allow users to predict the initial EIR value required to yield the desired *Pf*PR~2-10~. The third approach is to calibrate the model using the `cali` package function (see https://github.com/mrc-ide/cali for more information) `calibrate()` , which searches a user-defined EIR parameter space and identifies the value which yields the target *Pf*PR~2-10~ to a defined tolerance. + +The code chunks demonstrating the latter two methods call functions from the `mgcv` and `cali` packages. To reduce the number of dependencies when installing the `malariasimulation` package we have commented out the lines loading these packages and instructed these chunks not to run. However, users wishing to run and/or experiment with these examples, need simply uncomment the lines loading the `cali` and `mgcv` packages. ## *Pf*PR~2-10~ matching using malariaEquilibrium -The `malariaEquilibrium` package function `human_equilibrium()` can be used to return the canonical equilibrium solution of the system for a given EIR and the matching *Pf*PR~2-10~ calculated from the output (see for more information). First, we generate a large vector of EIR values for which we want to generate matching *Pf*PR~2-10~ values. Next, we load the package's default parameter set (`Jamie_parameters.rds`) and, for each EIR value generated, run the `human_equilibrium()` function. The `human_equilibrium()` function returns a dataframe containing the proportion of each age class in each state variables at equilibrium. The *Pf*PR~2-10~ is then calculated from the output for each EIR value by summing the proportion of people aged 2-10 with cases of malaria (`pos_M`) to get the proportion of individuals aged 2-10 with malaria, and dividing this proportion by the proportion of the population between the ages 2-10 (`prop`). Finally, we store the matching EIR and *Pf*PR~2-10~ values in a data frame. +The `malariaEquilibrium` package function `human_equilibrium()` returns the canonical equilibrium solution for a given EIR and the *Pf*PR~2-10~ can be calculated the output (see for more information). The first step is to generate a large range of EIR values to generate matching *Pf*PR~2-10~ values for. Next, we load the package's default parameter set (`Jamie_parameters.rds`), specify an effective clinical treatment coverage (`ft`) of 0.45 and, for each EIR value generated, run the `human_equilibrium()` function. + +The `human_equilibrium()` function returns a dataframe containing the proportion of each age class in each state variable at equilibrium. The *Pf*PR~2-10~ can be calculated from the output for each EIR value by summing the proportion of people aged 2-10 with cases of malaria (`pos_M`) and dividing this proportion by the proportion of the population between the ages 2-10 (`prop`). Finally, we store the matching EIR and *Pf*PR~2-10~ values in a data frame. ```{r} -# Establish a range of EIR values to generate matching PfPR2-10 values for +# Establish a range of EIR values to generate matching PfPR2-10 values for: malEq_EIR <- seq(from = 0.1, to = 50, by = 0.5) # Load the base malariaSimulation parameter set: eq_simparams <- malariaEquilibrium::load_parameter_set("Jamie_parameters.rds") -# Use human_equilibrium to calculate the PfPR2-10 values for the range of -# EIR values +# Use human_equilibrium() to calculate the PfPR2-10 values for the range of +# EIR values: malEq_prev <- vapply( malEq_EIR, function(eir) { eq <- malariaEquilibrium::human_equilibrium( eir, - ft = 0, + ft = 0.45, p = eq_simparams, age = 0:100 ) @@ -57,22 +67,25 @@ malEq_prev <- vapply( numeric(1) ) -# Establish a dataframe containing the matching EIR and PfPR2-10 values +# Establish a dataframe containing the matching EIR and PfPR2-10 values: malEq_P2E <- cbind.data.frame(EIR = malEq_EIR, prev = malEq_prev) +# View the dataframe containing the EIR and matching PfPR2-10 values: +head(malEq_P2E, n = 7) + ``` -This method does not involve running simulations and can therefore be used to return matching *Pf*PR~2-10~ for a wide range of EIR values very quickly. However, it is only viable for systems at steady state and with a fixed set of parameter values and with limited options for capturing the effects of interventions designed to combat malaria transmission. Often, when running `malariasimulation` simulations, one or both of these conditions are not met and, therefore, a different solution is required. +As this method does not involve running simulations it can return matching *Pf*PR~2-10~ for a wide range of EIR values very quickly. However, it is only viable for systems at steady state, with a fixed set of parameter values, and only enables the user to capture the effects of the clinical treatment of cases. Often when running `malariasimulation` simulations, one or both of these conditions are not met. In this example, we have set the proportion of cases effectively treated (`ft`) to 0.45 to capture the effect of clinical treatment with antimalarial drugs. However, the user may, for example, also wish to include the effects of a broader suite of interventions (e.g. bed nets, vaccines, etc.), or to capture changes in the proportion of people clinically treated over time. In these cases, a different solution would therefore be required. ## *Pf*PR~2-10~ matching using malariasimulation -Where the `malariaEquilibrium` method is not viable, a slower, more flexible alternative is to run `malariasimulation` simulations over a smaller range of initial EIR values, extract the PfPR2-10 from each run, fit a model relating initial EIR to PfPR2-10, and use the model to predict the initial EIR value required to yield the desired PfPR2-10. An example of this method is outlined below. +Where the `malariaEquilibrium` method is not viable, an alternative is to run `malariasimulation` simulations over a smaller range of initial EIR values, extract the PfPR2-10 from each run, fit a model relating initial EIR to PfPR2-10, and use the model to predict the initial EIR value required to yield the desired PfPR2-10. This approach allows users to benefit from the tremendous flexibility in human population, mosquito population, and intervention package parameters afforded by the `malariasimulation` package. An example of this method is outlined below. ### Establish malariasimulation parameters -To run `malariasimulation`, the first step is to generate a list of parameters using the `get_parameters()` function, which loads the default `malariasimulation` parameter list. Within this function call, we adapt the average age of the human population to flatten its demographic profile, specify seasonal malaria transmission, instruct the model to output malaria prevalence in the age range of 2-10 years old, and switch off the individual-based mosquito module. The `set_species()` function is then called to specify the composition of the vector community. The `set_drugs()` function is used to append the in-built parameters for Artemether Lumefantrine (AL) and, finally, the `set_clinical_treatment()` function is called to specify a treatment campaign that distribute AL to 45% of the population in the first time step (t = 1). +To run `malariasimulation`, the first step is to generate a list of parameters using the `get_parameters()` function, which loads the default `malariasimulation` parameter list. Within this function call, we adapt the average age of the human population to flatten its demographic profile, instruct the model to output malaria prevalence in the age range of 2-10 years old, and switch off the individual-based mosquito module. The `set_species()` function is then called to specify a vector community composed of *An. gambiae*, *An. funestus*, and *An arabiensis* at a ratio of 2:1:1. The `set_drugs()` function is used to append the built-in parameters for artemether lumefantrine (AL) and, finally, the `set_clinical_treatment()` function is called to specify a treatment campaign that distributes AL to 45% of the population in the first time step (t = 1). -```{r parameters} +```{r} # Specify the time frame over which to simulate and the human population size: year <- 365 @@ -81,37 +94,31 @@ human_population <- 5000 # Use the get_parameters() function to establish a list of simulation parameters: simparams <- get_parameters(list( - # Set the population size + # Set the population size: human_population = human_population, - # Set the average age of the population + # Set the average age (days) of the population: average_age = 8453.323, - # Turn on a specfiy seasonal transmission pattern - #model_seasonality = TRUE, - #g0 = 0.284596, - #g = c(-0.317878, -0.0017527, 0.116455), - #h = c(-0.331361, 0.293128, -0.0617547), - - # Instruct model to render prevalence in age group 2-10 + # Instruct model to render prevalence in age group 2-10: prevalence_rendering_min_ages = 2 * year, prevalence_rendering_max_ages = 10 * year, - # Turn off the individual mosquitoes module + # Turn off the individual mosquitoes module: individual_mosquitoes = FALSE)) # Use the set_species() function to specify the mosquito population (species and -# relative abundances) +# relative abundances): simparams <- set_species(parameters = simparams, species = list(arab_params, fun_params, gamb_params), proportions = c(0.25, 0.25, 0.5)) # Use the set_drugs() function to append the in-built parameters for the -# drug Artemether Lumefantrine (AL) +# drug artemether lumefantrine (AL): simparams <- set_drugs(simparams, list(AL_params)) # Use the set_clinical_treatment() function to parameterise human -# population treatment with AL in the first timestep +# population treatment with AL in the first timestep: simparams <- set_clinical_treatment(parameters = simparams, drug = 1, timesteps = c(1), @@ -119,19 +126,19 @@ simparams <- set_clinical_treatment(parameters = simparams, ``` -### Run simulations and calculate *Pf*PR~2-10~ +### Run the simulations and calculate *Pf*PR~2-10~ Having established a set of `malariasimulation` parameters, we are now ready to run simulations. In the following code chunk, we'll run the `run_simulation()` function across a range of initial EIR values to generate sufficient points to fit a curve matching *Pf*PR~2-10~ to the initial EIR. For each initial EIR, we first use the `set_equilibrium()` to update the model parameter list with the human and vector population parameter values required to achieve the specified EIR at equilibrium. This updated parameter list is then used to run the simulation. The `run_simulation()` outputs an EIR per time step, per species, across the entire human population. We first convert these to get the number of infectious bites experienced, on average, by each individual across the final year across all vector species. Next, the average *Pf*PR~2-10~ across the final year of the simulation is calculated by dividing the total number of individuals aged 2-10 by the number (`n_730_3650`) of detectable cases of malaria in individuals aged 2-10 (`n_detect_730_3650`) on each day and calculating the mean of these values. Finally, initial EIR, output EIR, and *Pf*PR~2-10~ are stored in a data frame. -```{r model} +```{r} # Establish a vector of initial EIR values to simulate over and generate matching -# PfPR2-10 values: +# PfPR2-10 values for: init_EIR <- c(0.01, 0.1, 1, 5, 10, 25, 50) -# For each initial EIR, calculate equilibrial parameter set and run the simulation +# For each initial EIR, calculate equilibrium parameter set and run the simulation: malSim_outs <- lapply( init_EIR, function(init) { @@ -158,7 +165,7 @@ malSim_EIR <- lapply( ) # Calculate the average PfPR2-10 value across the final year for each initial -# EIR value +# EIR value: malSim_prev <- lapply( malSim_outs, function(output) { @@ -174,33 +181,37 @@ malSim_prev <- lapply( } ) -# Create dataframe of initial EIR, output EIR, and prev 2-10 results +# Create dataframe of initial EIR, output EIR, and PfPR2-10 results: malSim_P2E <- cbind.data.frame(init_EIR, EIR = unlist(malSim_EIR), prev = unlist(malSim_prev)) +# View the dataframe containing the EIR and matching PfPR2-10 values: +malSim_P2E + ``` ### Fit line of best fit relating initial EIR values to *Pf*PR~2-10~ -Having run `malariasimulation` simulations for a range of initial EIRs, we can fit a line of best fit through the initial EIR and *Pf*PR~2-10~ data and use it to predict the prevalence for a wider range of initial EIRs (given the set of parameters used). Note that the `newdata` argument is used to generate a series of additional initial EIR and *Pf*PR~2-10~ pairs for plotting. +Having run `malariasimulation` simulations for a range of initial EIRs, we can fit a line of best fit through the initial EIR and *Pf*PR~2-10~ data using the `gam()` function (`mgcv`) and then use the `predict()` function to return the *Pf*PR~2-10~ for a wider range of initial EIRs (given the set of parameters used). -```{r} +```{r, eval = F} -# Fit a line of best fit through malariasimulation initial EIR and prevalence +# Fit a line of best fit through malariasimulation initial EIR and PfPR2-10 +# and use it to predict a series of PfPR2-10 values for initial EIRs ranging +# from 0.1 to 50: malSim_fit <- predict(gam(prev~s(init_EIR, k = 5), data = malSim_P2E), newdata = data.frame(init_EIR = c(0, seq(0.1, 50, 0.1))), type = "response") -# Append vector of initial EIR values to model fit to establish dataframe -# for plotting +# Create a dataframe of initial EIR values and PfPR2-10 values: malSim_fit <- cbind(malSim_fit, data.frame(init_EIR = c(0 ,seq(0.1, 50, 0.1)))) ``` ## Visualisation -Let's visually compare our the `malariaEquilibrium` and `malariasimulation` methods for matching EIR to *Pf*PR~2-10~ values. In the section below we open a blank plot, plot the initial EIR and resulting *Pf*PR~2-10~ points generated using `malariasimulation` runs, overlay the line of best fit (orange line). Also overlayed is a line mapping EIR and *Pf*PR~2-10~ values calculated using `malariaEquilibrium` (blue line). +Let's visually compare our the `malariaEquilibrium` and `malariasimulation` methods for matching EIR to *Pf*PR~2-10~ values. In the section below we open a blank plot, plot the initial EIR and resulting *Pf*PR~2-10~ points generated using `malariasimulation` runs and overlay the line of best fit (orange line). Also overlayed is a line mapping EIR and *Pf*PR~2-10~ values calculated using `malariaEquilibrium` (blue line). -```{r, fig.width = 6.8, fig.height = 4} +```{r, eval = F} # Define a colour palette for plotting: plot_cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") @@ -212,7 +223,7 @@ plot(x = 1, type = "n", xlim = c(0,50), ylim = c(0, 1), xaxs = "i", yaxs = "i") -# Overlay the initial EIR and corresponding PfPR2-10 points from malariasimulation +# Overlay the initial EIR and corresponding PfPR2-10 points from malariasimulation: points(x = malSim_P2E$init_EIR, y = malSim_P2E$prev, pch = 19, @@ -226,7 +237,7 @@ lines(x = malSim_fit$init_EIR, type = "l", lty = 1) -# Overlay the malariaEquilibrium Initial EIR to PfPR2-10 line +# Overlay the malariaEquilibrium EIR to PfPR2-10 line: lines(x = malEq_P2E$EIR, y = malEq_P2E$prev, col = plot_cols[2], @@ -234,26 +245,31 @@ lines(x = malEq_P2E$EIR, lwd = 2, lty = 1) -# Add a legend +# Add a legend: legend("topright", legend = c("malariasimulation", "malariaEquilibrium"), - col = c(plot_cols[1:2]), lty = c(1, 1), cex=0.8, box.col = "white") + col = c(plot_cols[1:2]), + lty = c(1,1), + box.col = "white", + cex = 0.8) ``` -Looking at the plot, we can see that, to achieve a given *Pf*PR~2-10~, the `malariaEquilibrium` and `malariasimulation` approaches recommend a quite different EIR value, with the `malariaEquilibrium` method typically requiring a much lower EIR value to achieve a given *Pf*PR~2-10~ (given the `malariasimulation` parameter set used). + + +We can see that the `malariaEquilibrium` provides a reasonable approximation when the target *Pf*PR~2-10~ is low, but recommends slightly different initial EIR values for intermediate *Pf*PR~2-10~ values. However, in our example we only simulated clinical treatment covering 45% of the population. If we needed to identify the EIR to yield a target *Pf*PR~2-10~ value in a scenario in which additional interventions, such as bed nets or vaccines, had been deployed, the difference between the EIR value recommended by these methods would be likely to increase significantly. ## Matching EIR to *Pf*PR~2-10~ values -Using the fitted relationship between initial EIR and *Pf*PR~2-10~, we can create a function that returns the EIR value(s) estimated to yield a target *Pf*PR~2-10~ given the model parameters. The function below works by finding the closest *Pf*PR~2-10~ value from the values generated when we fit the model to the target value input by the user, and then using that index to return the corresponding initial EIR value. +Using the fitted relationship between initial EIR and *Pf*PR~2-10~, we can create a function that returns the EIR value(s) estimated to yield a target *Pf*PR~2-10~ given the model parameters. The function works by finding the closest *Pf*PR~2-10~ value from the values generated when we fit the model to a target value input by the user, and then using that index to return the corresponding initial EIR value. -```{r table, warning=F} +```{r, eval = F} -# Store some pre-intervention baseline PfPR2-10 values -PfPRs_to_match <- c(.10, .25, .35, .45) +# Store some target PfPR2-10 values to match to: +PfPRs_to_match <- c(0.10, 0.25, 0.35, 0.45) -# Create a function to these baseline PfPR2-10 values to EIR values using -# our model fit: +# Create a function to match these baseline PfPR2-10 values to EIR values +# using the model fit: match_EIR_to_PfPR <- function(x){ m <- which.min(abs(malSim_fit$malSim_fit-x)) @@ -270,42 +286,38 @@ cbind.data.frame(PfPR = PfPRs_to_match, Matched_EIR = matched_EIRs) ``` -## Calibrating *Pf*PR~2,10~ using the cali package +## Calibrating *Pf*PR~2-10~ using the cali package -A final option is to use the `calibrate()` function from the `cali` package (for details see: ) to return the EIR required to yield a target *Pf*PR~2-10~. Rather than manually running a series of simulations with varied EIRs, this package contains the `calibrate()` function, which calibrates `malariasimulation` simulation outputs to a target *Pf*PR~2-10~ value within a user-specified tolerance by trying a series of EIR values. +The third option is to use the `calibrate()` function from the `cali` package (for details see: https://github.com/mrc-ide/cali) to return the EIR required to yield a target *Pf*PR~2-10~. Rather than manually running a series of simulations with varied, user-defined EIRs, this package contains the `calibrate()` function, which calibrates `malariasimulation` simulation outputs to a target *Pf*PR~2-10~ value within a user-specified tolerance by trying a series of EIR values within a defined range. -The `calibrate()` function accepts as inputs a list of `malariasimulation` parameters, a summary function that takes the `malariasimulation` output and returns a vector of the target variable (e.g. a function that returns the *Pf*PR\~2-10), a tolerance within which to accept the output target variable value and terminate the routine. To reduce the time taken by the `calibrate()` function, the user can also specify upper and lower bounds for the model to vary the EIR between. The function then runs through a series of `malariasimulation` simulations, trying different EIRs and hoing in on the target value of the target variable, terminating when the target value output falls within the tolerance specified. +The `calibrate()` function accepts as inputs a list of `malariasimulation` parameters, a summary function that takes the `malariasimulation` output and returns a vector of the target variable (e.g. a function that returns the *Pf*PR~2-10~), and a tolerance within which to accept the output target variable value and terminate the routine. To reduce the time taken by the `calibrate()` function, the user can also specify upper and lower bounds for the EIR space the function will search. The function runs through a series of `malariasimulation` simulations, trying different EIRs and honing in on the target value of the target variable, terminating when the target value output falls within the tolerance specified. -```{r, echo = T, results = 'hide'} +```{r, eval = F} -# Prepare a summary function that returns the mean PfPR2-10 from the final +# Prepare a summary function that returns the mean PfPR2-10 from each simulation output: summary_mean_pfpr_2_10 <- function (x) { - # calculate the PfPR2-10 + # Calculate the PfPR2-10: prev_2_10 <- mean(x$n_detect_730_3650/x$n_730_3650) - # Return the calculated PfPR2-10 + # Return the calculated PfPR2-10: return(prev_2_10) } -# Establish a target value +# Establish a target PfPR2-10 value: target_pfpr <- 0.3 # Add a parameter to the parameter list specifying the number of timesteps to # simulate over. Note, increasing the number of steps gives the simulation longer -# to stablise/equilibrate, but will increase the time runtime for calibrate(). +# to stablise/equilibrate, but will increase the runtime for calibrate(). simparams$timesteps <- 3 * 365 -# Use the match_EIR_to_PfPR() function to return the EIR predicted to be required under the -# malariasimulation method -malsim_EIR <- match_EIR_to_PfPR(x = target_pfpr) - # Establish a tolerance value: pfpr_tolerance <- 0.01 # Set upper and lower EIR bounds for the calibrate function to check (remembering EIR is # the variable that is used to tune to the target PfPR): -lower_EIR <- 8; upper_EIR <- 12 +lower_EIR <- 5; upper_EIR <- 8 # Run the calibrate() function: cali_EIR <- calibrate(target = target_pfpr, @@ -314,15 +326,22 @@ cali_EIR <- calibrate(target = target_pfpr, tolerance = pfpr_tolerance, low = lower_EIR, high = upper_EIR) +# Use the match_EIR_to_PfPR() function to return the EIR predicted to be required under the +# malariasimulation method: +malsim_EIR <- match_EIR_to_PfPR(x = target_pfpr) + ``` The `calibrate()` function is a useful tool, but be aware that it relies on the user selecting and accurately coding an effective summary function, providing reasonable bounds on the EIR space to explore, and selecting a population size sufficiently large to limit the influence of stochasticity. -As a final exercise, let's compare graphically the `calibrate()` approach with the `malariasimulation` method when the same parameter set is used. The plot below shows the change in *Pf*PR~2,10~ over the duration of the simulation under the initial EIR values recommended by the a) `cali` and b) `malariasimulation` methods. The blue horizontal line represents the target *Pf*PR~2,10~ the methods were attempting to match to, and the black lines either side the upper and lower tolerance limits specified for the `cali` method. +As a final exercise, let's compare graphically the `calibrate()` approach with the `malariasimulation` method when the same parameter set is used. The plot below shows the change in *Pf*PR~2-10~ over the duration of the simulation under the initial EIR values recommended by the a) `cali` and b) `malariasimulation` methods to achieve the target *Pf*PR~2-10~ value of 0.3. The blue horizontal line represents the target *Pf*PR~2-10~ and the black lines either side the upper and lower tolerance limits specified for the `cali` method. -```{r, fig.width = 6.8, fig.height = 4} +```{r, eval = F} -# Use the set_equilibrium() function to equilibriate the simparams to the calibrated EIR: +# Define a colour palette for plotting: +plot_cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") + +# Use the set_equilibrium() function to calibrate the simulation parameters to the EIR: simparams_cali <- set_equilibrium(simparams, init_EIR = cali_EIR) simparams_malsim <- set_equilibrium(simparams, init_EIR = malsim_EIR) @@ -336,15 +355,15 @@ malsim_sim <- run_simulation(timesteps = (simparams_malsim$timesteps), cali_pfpr2_10 <- cali_sim$n_detect_730_3650 / cali_sim$n_730_3650 malsim_pfpr2_10 <- malsim_sim$n_detect_730_3650 / malsim_sim$n_730_3650 -# Store the PfPR2-10 from the two methods for the two methods: +# Store the PfPR2-10 in each time step for the two methods: df <- data.frame(timestep = seq(1, length(cali_pfpr2_10)), cali_pfpr = cali_pfpr2_10, malsim_pfpr = malsim_pfpr2_10) -# Set the plotting window +# Set the plotting window: par(mfrow = c(1, 2), mar = c(4, 4, 1, 1)) -# Plot the PfPR2-10 under the EIR recommended by the cali method +# Plot the PfPR2-10 under the EIR recommended by the cali method: plot(x = df$timestep, y = df$malsim_pfpr, type = "b", @@ -354,14 +373,15 @@ plot(x = df$timestep, #ylim = c(0, 1), col = plot_cols[3]) -# Add textual identifier and lines indicating target PfPR2-10 with tolerance bounds +# Add a textual identifier and lines indicating target PfPR2-10 with +# tolerance bounds: text(x = 10, y = 0.47, pos = 4, cex = 0.9, paste0("a) cali \n init_EIR = ", round(cali_EIR, digits = 3))) abline(h = target_pfpr, col = "dodgerblue", lwd = 2) abline(h = target_pfpr - pfpr_tolerance, lwd = 2) abline(h = target_pfpr + pfpr_tolerance, lwd = 2) -# Plot the PfPR2-10 under the EIR recommended by the malariasimulation method +# Plot the PfPR2-10 under the EIR recommended by the malariasimulation method: plot(x = df$timestep, y = df$cali_pfpr, type = "b", @@ -371,7 +391,8 @@ plot(x = df$timestep, #ylim = c(0, 1), col = plot_cols[1]) -# Add textual identifier and lines indicating target PfPR2-10 with tolerance bounds +# Add a textual identifier and lines indicating target PfPR2-10 with +# tolerance bounds text(x = 10, y = 0.47, pos = 4, cex = 0.9, paste0("b) malariasimulation \n init_EIR = ", round(malsim_EIR, digits = 3))) abline(h = target_pfpr, col = "dodgerblue", lwd = 2) @@ -379,3 +400,5 @@ abline(h = target_pfpr - pfpr_tolerance, lwd = 2) abline(h = target_pfpr + pfpr_tolerance, lwd = 2) ``` + + diff --git a/vignettes/EIRprevmatch_Fig_1.png b/vignettes/EIRprevmatch_Fig_1.png new file mode 100644 index 0000000000000000000000000000000000000000..1a98e4f6a93406d77dbec42767beba4f984fa498 GIT binary patch literal 5110 zcmdT|dpK16x1TP*=qA!ziE&A}6=EvPxa3VP3^vBlopKu?jqBS>gpk{? zjZ5VoM!m>oW(dPz%qF*C#GGC4@0{m3|Gnpr^E~J5=ezfM*7~l`TI;*Mv)1hIetOy5 zXz#8gyATM(UK3*jO9Wyogg|Ur65Iw$Y_L~f!leDOsr3bzA`oZ<0*gSS5oq{HL}1A< z4>M>4_NVOUMMM+fK}Hj4wiVOZU)op%7M{kUu`q#eES88R!h?(@!-Iw;^NDB#5k_JW zzr;i$nMS0Mi8T1hCu0$0BAQIZl3_6!9`Hqj=gBl0nNKG3`7|P$MugRWN`E4L5gLsT zLuq{eWEKK80W0xg5&x$;pU)3B+$Ik%W#?UEdmI8G)cEt>((3!>CIYd)$HYM2Iyjxf z*qb$Gh;hH-kELi%mU2Sm(v89?xNNca(5Mi4wN>>nxp|8inrqW=1c@y+(` z@-4MxpLDFE7Yv<75G_q|Tn0}#WMzJKv>g#X$gFoPo=MZ{5sMMd#%wQ5r`R=Oa6rs+ zMgoabrmfyM5O-y)`d3E&LUChcQHNzTvMK1hWm@m|wGy6VEDirFPn0vL)|4D&BWxQ| zv3v$sRUh~xfu5jFiw8O#e1rr$%DNqjiZ}88MxTQ7cfpBv`+j3pt_`{6&WN7V2Jf%A z^o`=pyI&?S_R_%i&s9C;bOBkQdWAPB{u&$dyv{K@BRqQQVit2 znfnr)zIHVroF5RDuFL8$jmY=a);`4L2Ng?sMAAox*kR=EXsq*ycIq7sIT~-$$JGYe02O~{PLdvOin>E4jb6-BHnhXz<0A=-K@0g{#lb5^DT;A;s z!3^K)P;09iN&i7Acu1$7+BM)fqRn(7c!v{kXKUDpazgdT+Q+F*1#tF1r&D~BYWS}X zM@Op`rbUAI<;u-UZR^1>2errG`U=NtF??|PzOlbRvFv~QNgE;T4kGNNR{5)kqr;=~ ze|Ug3t8J3-W;i@uIyM=-j}o-+5>u#u_8>yatvJ3?qY>9_cz!M$F*NO=ozF2l$ZJ2=qTVZC~_YLi6+ofh%IHv!yp)?BNcC*glZPR|W z7?HmVwLj(kO(;&Sj9p%@;L*cp^6w*^(SG4mlL!rK*6gets<|ywtwvV) zlNCgp*hmx`UL^MyFyn|$N{(~BgC4~(r0lLOgxYjA?_3W%Pj%@jRrNPQ15XI(NbZpsupVwK?Pd(sTJd;m6X#>dY1`0?5^G;d zyE%s}Vx4#R3RNG!Iw2qx5BZib>#wI+y?8;wfY}efB}kp&^knYSSLI7=Eh4VKVb zPf&;3kg4&d+OZ!k<}Gb1gx$bI`58f}VbS&tm&|XM!#_+vYZGHL_78G1^}nU!2_f%0xxy-&|;bf3sJtIb!di6~0xywgy-;wcy1B_mn&aP1hnB)yYi z#}D>$Z1<_tdc-=psCaxhXT8%JoB^sNlR{zHd;CPc`ygO|wYd6Yd+-Hv#op+rRly#}+(ujgtGB14Vkb^@>XRCcni~K7@_oUf34! z-Y;WU4RYxcbexuFLP~It40kl^rjmw0B;8siP@&-)krJK12i*5rJL_btsE!QR;AMO* zJ~bT^mMUumnYj2!K0&9Oj<;xGYkY*xN=RzRF9}_plWezVJuKd#&vHz_yLdN-lnjY| zR<^l~?VXv_!T1UtVx(3D6lG*9Z#$qjHVa)Tc@j{mmA<&Bltjf}?h7H%%%^YHX-W81 z96z&szwJf`T|Dif;gsi5pw$6smxGgPV<2}dF%u};IvrXb&?Eh<&=~?Bk3JZtH*n`> zNUzMku=Fw{9%$b&-)i()>N>DkaX0#}JgcFN4#s3I)n+h!dp9`*Y9U9CxW(ylOTbn24Jc4H)WeWD>>59+9N31pH zNszQOssqp#pFFc-ATuE=fLHrjTxzbma}Z-BlqI?YMF>BvU66IhXLd*2Ow9DO<>b*b zGf)-vtcK4+OOHP@(Hr06vIwj5@@W=xj%!mr)wsDV^sD%X1;siq0yVo$Bm2&bcQH(6 zpsa)G1-OWf+QxO$kdWct=~$@oI>1l=rk{bY+6{T9@MMd6KGpfcK4fpEtcN#%;X@Bf zC(PMpQ_GOv+VTj+Sx3_^MJ_{d$Emr>pD~8t%_+jf)S?h)};z$M0p=Dj+Fk z-BJzfmh${QuA^kx^(v`K2@|M7rMI-3zp-{n>{1iY^u|=!k{2ylL*j`V;Uax0 zBy7FCeKM@nJ7cY*x6NK;5V*?a#t5e;(Y;+gOtVf>bOE+FE87GGTr+Af=zd%O_3m)c zm(lIGD$+YqUen-`edf;LTNq@R7kIsb`iIIrv#g21W3gnbi@C{|qVe7UBY^#tpeNJh zp#_vY;V!YD47a>MlUd$dz3$#nnLGpkxn6Xu3zIbF$5koqsWGS5}b-r)P9edPy^E#ibT>ewtyISAFL#Sk-FIzIEm=I?XjN z&;iv#zit$Ctu;`#v+gxa&Bi-67GUI*%T3T(a?lgWh&jQ%RJk~FAR|_ZyIU4h)c7&j z-xoQ!!P#$xN~Npzn$NyF{emtwIQm}GpMUG7$EP@5!-Vw^PE%aCA#uHVKxbB7$5TtiNikcMSfomzrS zQ1$a$Q0vfBB$PvffziicRYv>4Ey^G0`$WZDBi*JaocgKSJE+H#DfNp?;161!| zi{Yg_a?t=vj*h4#)9Cp~{Q*gmVjhZ8*+Vzu)Jg6fFdnVOoX2c6kp{es6m)RFs%7%i zJrDd)HHF*Qk?Iw)=>v&kUPkBqU_;y8`&mAY=JwaH5IHS7=#e}3Y+}K%Z5Lbo;aR(; z@ae4s_f+c+iX0f#(}v$CDrGBlFE#C2`?f7%?hW!o^AUy_hZ*#j74{eDAE)bU$T3@7TuUC5)KAn;%p34;!txVpBNIN5LI+Zym2-_K%^sfIH;FMJ%y2fY)zebxlC^ zwmgv2IG#W{3fqMd)YcTDL>3(U{&8i1T6TXaxHDrY;fOPcO4ff6HVFmwym!g;&kM?F zvw$2##7!2G;o$V0{5_N&o?iRJ;9$4NhcV&ck|OEOZOEq!M2glLf+$U)1GnAjdX>J= zV|s#8A^qQf_`BiVIo9!?hp4a+oa!FPIK>QpKPjjuRhfFcK`P?3YZ5V**k29cE4UuL zslD=j4^0|=O47OS z!1W>en-vvanpFF6J3)!!F{d(jE5QEfK@qSVFamnf$|BKG^g&8C2BIj7ln-N+dXCafReD896qSNW5pTL>Isvl`TP-*lU;b9jYe*8`Ctt9f(5xXw3aa@^)h z=0_jLS+yR$B?U^qN3}X8c6qV8D|B7~A3?Cmz0V_;M}}m6O4RRJe^H*ov|zFhn7+~AzLLzF%oR}()HW?Szy zQwsoKidEj#L}0PVFl-mEhf*4pm8Q3#iSO?b%)lqXtKiu*wv5SJKt4gv4VJOx>kQtg z7Ik=8QSr|SC#B6PS*A*ex>Y7gX3XMTgMU;hP~H=qNLtY9v=fm-sX5Dk1zSTaZ6yQa zS4BTZFx6HvZRFGA%DI+bLLa3RsO>Yb1&u;?El&e~&es1(q{{7&BBGRsx+6q6-g2U=En|29jFOJ7j`}0DsyTR9pYv2`!vAM-mabyg++VoRpEyEKVd?aC{}x0VG732KB(84R&HBL38Q|B~6Z1a>bCbX&LV_1~9! z9Kfwr_ZNb8{oc(ka5R^oiRF5lJPPYFVnAu3RlxS7Ch9d~AlmC|4qXHa^IXnurevo* zv~CtiXE@0ES#5M|d~fSyxQ$oiTLN1C^^eNuA00o5{B5Jkt}UfecLaZazcaaDZczNY H%Y**_W#?g& literal 0 HcmV?d00001 diff --git a/vignettes/EIRprevmatch_Fig_2.png b/vignettes/EIRprevmatch_Fig_2.png new file mode 100644 index 0000000000000000000000000000000000000000..723c32d3513f61a1b00946ab1cb41bc3bb559a73 GIT binary patch literal 9423 zcmd6NdpK0z+xH;nQz=P85mHGArZMlX@Avz>@9%lu=epkKkKc8@`&zU2tb46>ueI*=+3Vi>bMNTurUv{x zhj}0n2*2S~{hJU7D*%D8Y;duG5=)p(DtIAYH@3J8ULg<-2m}Vv(12)w=L8501IfBC zk-!9{phyD(`(5(;NYF?C6GkI}1pCtf27$r;6vH%N;6E5F0hRzJ3=9J%5)8vk(10X> z&0vr};)DbYDS?DZAc1El1_r?-XkZdx7*LD>6L^roatw)tVPY^$CMiLKlmJ%$E&bi% z&xJ%{f=x+G=4>_uQ~_3Ef+FVc>P#l{um-XjoDKKAtG4$c5P^o@KbB^{4{i|1QHY`b zMT-X+%bC2$sakmC%y6+~ms^c^R}g7K`I@>(@q3>U@q8aON5kY5Ce!?~5Q6o%@AR=~ zYG~H#&;hRR&1E@kd-ovt9(fJj$c8}HS;!YJ>msi2>lU}z6UZt2Kh7TL59Q2w9ivn) z5p&97pDSJx>opd-+Nk}*&yoe@dU2??rH@fX9}2y{Z`{qoYJV^&+TYsC2utXJhBEH2 zu;@D3?A@|h3;c`^J2>v7m5qLmODZlux>T40FJLLremF)QlI1W}hS2)E!sQI?_2ny`~L=IB(d`@g^ zzLk~mHdaw%NvB6*%!mMJO?pb-sxk8;EE7^N7cqdLs|YnNcW9(+vmHwtz^Jk1xBpt7 zp@fBcUP^s{pV}!|@2V!c2p_kny(@1QWHTEgDM#nl1Uk!Fl+ZV45`)z=C3M>OP547J z?P$l8?P#Bo3u~bgTNJuv5N^&ual%#*|8r}XA{k`%*;1#n*O#_2@Va};+iZHZ)SRxm zKA4p*neHbshoEnyr@%h5C!mokKj}n$sv-LJoi-UiSe(g(B6*xrk;~wkCgsxiin@kB z{q^n{V`uHx{2ElJD!lhn*Jr$>o$X9lhk>CS20z|7Qf2}JqMGF;KJV6PFZLj#T}(f6 zN=fF1fAYs$(;`oL>pZXP--%jd$Hu=pxHZrW7>ST&WxT=;+6wsPZ`b(Te9Is*ua*D- zI(YctmN!r6&-x7^)aL;1mL_ug!J_Cd441GI2yigRH*1u9WM*B%t2&pj>_R7UMaD7D zVzNoE-k|be^_5Y^BFWuW&$7Z#1zLwI z1ciircmTJi`#90e`}STGi+(wPUBB~uxm!D-wjAyDejMu!D(4~hJEMCC3veTXtuYtZ z+nt@$#x!cM+^q|?zJHWz#7ZFs1FgZT*T~yl%S>v?0Dd81OfVCi3mR>Q1L6f6$v8>U z*_C&Uk=TUQebV}%;zdOIx9_k^Yd{#GClHv4C~X-2kB9x_LDW46@0olA(ndR#}0nqG-GyJ z(W^(vTz9@)+jIPHRP)+JyA;;!F|H4=lKKE$QYq2T*-RPn7FrZ+J{3xv+4;dM8F8;K zd?D^MbZ{H4w;Qg>tvX3d6~iWTy@+%qhS>2=PXVkdz~q^yg3eFzSyslKr$T>)LcN)i z*&-oHEP0X$k?Ci6+{=5H3HukvoGvWO?v6tlrhc(>{}d5t1vj(hDte=HxD`{~n(--k zStzF$?>4k4KZ<^2gMdcm(Fzw|B58&vsWCS+8HpkXn3Xc)dQBhTiU+qa8_0Qy>!?~r ze!9urRjF*t(PdoF`JJ;FD4e=s#}hGx7rFgeX7&EB1ND0F!E{t+t$9gQPn!+4GM{)Y zpwgI}R8Np14d&o#(bZpnS*Sv<(6MOho8~pRATNE>{j2EhZ1{XBtDj5YJ3cZF`r5A} zm%W^a+}sdm+r-NDwOF4Gb1jDG;7rg{*>Ct5>~{5l=<`pKzsz1; z9?g8s1$M@NMy2ObyYcY@y^NoBx(Jx*RQ#ZMiD17j#cJe6qmo*Je-{^R$`>bc{vpDP!hr6*! z37NR{APz&fBXxD4@$`2?Xui+C^tK!YBtFi8jz#`oZ1NW}x-&WEO<4mASg?Pa>i=VL z0$NjI1$E`m!YIR=*`WJdc|qrRH4AvK$Kj+c=yc6nd&LER8q1tI&4oO9hwQ0KG1UtK z;y6QO|HHFRuw;9>MS><}n*z>(2KfvAxiKKnx(F$I5ptJ7ST?`X+*_CAqJKJ)`1tBm z?O5VKW;|aGDq2PnR4lbEt%aUSCq%{cm$LHyT0J?Jz70uxQlgdp6VIiGIXUtgp)oSmv|**B$qtQY)z(mQ(u@9{D2a0@tfF62iHP$s++F7UFhz^z3MY-T3n=od}O|N99zUv-68t zfX;vxyf;yrA{*DXy-W3XgLN@k)XD(94x9^=OdGL2>!BP$DB1(|K8G*jlTLi{H4!zK zXqlWR03pL?my4v*fAC>|8Z%qG1qISVRt0aEvl&E(PcJ{p9C3+H6lD)U2sH)JNaNFP z$`9R<^QDgyMTM@wyRh$yEC-4N#@SVBfU7W#*^|UyYJz{=LY0A>_XX)e7%%>HiiCq!f#O3PXbKNr2!5HMlojTv> z(`4!TQai+{4KD#APItY-}=Grsy+jknO=shJS<$@@uMulreZHSApH_ zc;`?1-2FTFsD*m8Hy7*?m7!%Lh#Ej{j2kN%DaQ;lf0~V&*X9=oje&?YCO0(rE;t1X zQ2Q8b8%=TXu&EvzP2YT#i;-7FTj&^wxyq*>5Wp$b&@h%HjPouI*&0S{(PPa z(+uhA)s|hlGp4#0=qHv!q00g+gPJ3*h$^ZAiY-ye6%p5=i>Ox6qse~$%tW!Ps(cTe zce?e$=FSkw1Fa#HcG#anNQx;|x-V2l8q~Dl_aZr&vPJ^It;QBZjdpt;_6m@rYPQeA zZ?mOj7PL>_AuA<6az|L+t_M2Fx%6&~5NCHJEQcPmneKz^z|iN24@j{aY)iDgPP+b< zmR%F4meCrZ8BT8R>2)zZCar?JaNeB$c29nwAeZJ84TgC0(%mBmHyU(jM~46nZ(<=f z;l0M^?vl4PZdsYCta6{;&(xj%a*o!=wuD?Tt~Tr_#;!j;)L%d7MIXhcH(7r=vGNJa zTg=kB)6&lfJ0zN|E>KRbp(c0ocJ^tXS$g8jF3_?4Daqy-3Y-0{%8(k%G0Rfi6xvng zU1FISjFMMg5+`ROEd>o`7s7N}?nF6sz;1DrkGYoIcTqN?&6guq<{tDdA;*rh`s{jk zJIIt=puRs~p?T_j_zN3@>q8eND^$D5qg&3oml7&KY-K#;(wg;BDGTwveR{rtgm6&nb_nJps_l&W1vqn~iz$ZftbU-8O-r*-M9|cM zZtc{Taxt4&q$L3-w{I!PEPOjkO2l%R?WY(G`%yH_pC&Nx>w{x<8TAH*tfRx3_gC4L zhO?G4N9H8FOio{>wS7c%?U{h7_USN4 zK+b#Tfa(tR_Z?*9{c-QsDRK?sSHGDK!zdR=8!f@1A2-+1jW@GV@Cw7}HBy(imbIm% zvzg36{mpOWtxtq%X-`fmT-g~}sDjroth&)&(?E!-i7}&j(JuD3D;AwzQxoe+`gh``{dbeY!YQBs$cReR<4QaV31nT0rg`&nAFyFeRP zZ(}YBnjg{45!%v*t2M}#R@8+!KLU!?w?pX!K@+K;pTikpPvmd;KF1ZUUC_86yW2|v z?Dinn3FbtU|3$5Hl_{lNfdahUWE)nT(74E3&CMzlJ}e&*$9Co-EwXKd#=c-$OLzt6 zc8Qcea|MyIl9VMX-`07zNOvi`Nh@_Pdsm6wORn~vBw}&0(p~oi+Iz^Vzo0Xy#E%Ea!x<*%V24+CVM^GS z{bRXwH_m(IDeZZ0v>r@6M#dsdu-2OiKN{!HBq3PGy@4XNA!!wo&sa*HX3r&z-HjN=AyLVdfY@aLIBX zMY(2?`eE!~zolw7T&J=_Ar-4n=Cm8cZ&h=3ll3?4Pyu0@r_B*%elu`&k9OjKvr`q| zuUb_^IL}{1 zVX(bd^(>znlX)Y_-?EHB$HpqL!kwYd%-_2uRI4X^WGlho3ya)Wr7J^5lRTF9M)ymu zEHoIun^BoY)y}uYG_qcEQ^o%{RIwJDr6PPSJI2@G4e+eN*QGNPHUF_U(D6xPT7e%q z;#BWk^lJVa3n3rEz7d7uFMDIp+P|nBtPEBasG?F2hMx#+ZndXPw^b*KcI-?qeu_F_ zmsj-Q!D)F-gcaZLq$%&w2imzTwh>cl>TjDwhh43{EuI zNbjJeRookVC(q)`fsm&v+m6%NQFQ2DlMnP0{#eQz(Yn~+3oRK?6k#F@RlQ;|;1T0* zEE^|Mj9c}57gsgpkChudN)A3bkV)dsNV7Stna(|zgWd`W9X zp};+|L3YuAO0mNGLDbC(N=#?dlnS2OC53ek!WF1@c~@Y)1BPSk3UN0bocP=;N`4Xi zfU#{3^SO6Hyc&@GR0+zHd)(lAqGN*s4rcarC+lq;ReF&Ajs}rHG}d7y5xDq{`_QV2 zij6i7lS;Vy2I=L?w@L(Wzsz!#Zk>DeA5puW>mtf<#Unwn>%(M%cUjcQMbr%xqvBXL z7p1Jv`u=;M*}!>WNKMK8$~WU`))4CEZQBP{%WdvWBSFKq^O8-QSJq1x5(|(E<&^on z<S>eNmFxDwgyStM78^-XO%q_f&0g#w%`T2}VL23Z*FG;l^aH12Ph z%(EC$F!o-`wg^zZ_k&=~Cg%IJ**7+s$}xy+bVNU>Jb7>ct1{~;Ouigcjygd|`ZVYD%m0W;cV_iKAT<+=s77=%^FLfw)CLG!BFb zDqN=>jMq?NT)lC_&nm{zh}!K~2;_eNT|%^bq)h74PF>C<{RXMa%6vq`jDIDy{)OXA zdJ|mjlW$Eoey2~gb$u=B*&P{H@q$yoo~>lPv+B9tkB?AcJfT2$Za2bD{_=*|98W6I zKkBcVh1J^%!pUnl=e*m@j3qL~P0_CAuxcj0uD-WSf3FiN(!hy!%BeYH{Z@!@x`7{a z|E2R0&HNhD+pdWs2ftdl4tDGNZ!Zj$2FBkcuMNUa7RB7=Ne`1U4l-+85a}Sx;XJ=5 zo@h^DO->RiA@Uqy$IH1AKZ_m=J_0-9Sw}14d3{1ap=9|z;2Mb=zjEo4)_~Y0t9OHi z`ImPFbITJzZmK)K+HJLN)(a!Y+g>J+%Q=G} zwmJN&#YGzpU9ZvpNb~4!@y-A7sqDpA7#sD~*YeYPh^fhh5?orkJL<0Ld;_*}A6dc3 zF*Y;@Xi`iNd82!6kh=GbJtDv6hn7mI^)`BCkc5PvJ>A~z*wAfiTC3XkrVOC%*u)ti zvbZX~`isKsy=r>2OBh(1O*-)Al}Ep_ph@|vT1U}MoUd)}h2v8Lj*_pH;ItzF{8-v6 zo*pbBP6@}oWz>?I6}>?kt=KP`8giRiEIwx0Uj$c=kvIYm>>~D~tI+}!)|JrB^%Zqs z>P~H8|w06YP?yc}<$M%>i5h zIhG&ql=EJ!QswaN<8tFc$ZMvbU1<_-Ggw|3d?jBX88vpQ`lJbk<+;i&ybq(&eJ6iJ zbso5GN18a-mSWXn%bxqPCnh`neHF@$pOA0$0jaaP_f@d{?cKK-k9v(R1l*;;4aCbz zjA#V4+a{HH$<;I2th;J~F_om^8wgdycEUZK*22=3{Wmn>aL`ib_eaZ{3=fE^#_ToUXBW&Sz`tgS#$mOsvp74{ML16);T0fBj%Z50G7LyAVxF#728h zYRTkTGQ+orcSzB;9${ZoMqg1rX94Q+EWdsxiA_(6DDi*r zaG(GeR;E^I+2`SX*-hCv^o-5s+QZbcq#{$VX|j9PoE2PsK-r~zJ@gqC?W$|gjy^oE z#5|JR_Tu#5r9d5ev(LuKZL{=#vJzDUE23v)7t?u?*SyabwPUCf_NzqtOvpCxA^2S@ z8s0zM0C(ABLP|p}wwiJ#`J6h3n@DF{Dv9RXz5>K-!m=*#+`|;%ma>alPt`MIh6oqQ z)!Rx+n3wSpVFl{tr4@*jo+NPIlR>;wyT0B*8uI9Y%+33vjK)-p_hq<5pQt`nho+F` zyY`56(}LY=v4O?*h|nV4AWIni^iGyc5scUwrB;fo7RIK$OipNcL|OZJ6p?XN?f^ILYZd# z&p^SSqsNCqvQ~cjcjRaa`hyKxa}@({A$k7h+)9CtUV-0ag1e=aFbb^c=_aTT)njhV zhG!^D0fZIP_>JRT04Dv>j zq%vn_Ol|YuH0a|N;PBQeC3_$31Q@s2w{`AX6(AVb^&EMC-3}31Zjh9YTfZ~zRMHx( zY1ldJlR_L7cQum^cY9BFz)N-$za?lZN0b-*3r}|47_otRd*b)}d8&YOIq-ks#slD= zC9$qfqe7Afe|X3MMU`ke?_M8SUfV{pCTnEtIq{J)dr|Dzk^v{$uA=ad^jmOrsj zGs`3W>hCD1{#s!3enInA9*`Kl1~Ru?E!MW?3c=5jqoGIs5@rUWV9s{VyD`1&)qGBT4i6!F4Y zC&WL6pWa`<;wtIEN>+@QcD@oHrla*DBdxmyY~eJL{0wX%ahYU*juQ6E`WEKNDrxa+ zYov5wNKtGHZN^p)T|=wC9>m-Ct^CxwxwP~B6WWYQ_}zA_I3ns71j3g2`&$5~^x7z4 zsuN!+BkTd@8o%)8K<^S-JIC%~(xdXIr}$5Ra?Y`5l2k+6u)EE@gUpTRNSjp(U7d25 z<7Ino)Pc`SP>lELR{Isk;bJg+(A~dJr56<|rT$-_fqmb~MYpO3t+SVF0)v|3&MjKvar*+}quW}VT1_rUd ztjS$YiQVouiYSlzwfGL}te+x3QJmh`Aw9YKZG7c%wN4tYxxlS_4`l#9S#Blp&05$*nP72pFkQbo zYpQL?c*y!aG9qNG|EOHW?rQh<@|2(ov%U4Q^#n_@-$&uYFK~BXemRlOMfZaHu_8ma zqh>GqbtI*c=G33}C!uV_>TJ2Tqhx_*V1c;&idHbUHQY%)b7$<*u>O#BDZSU8R#h`= zDARGjeAPHerM>oQ+mR>FqI^U z^~gPvJvKtPv2Kp*rK@lD6_s*vx$Jj!t^=}BzrI%=(n|0VD9rMyA8Ec8D2a|2{7yo1 zh0vN=SwLlC-yOA%mn!t$)oQKPdDV(wu6}38$4RCWgcP~R5#Z3&-{Gh{Kf*(rQ zE6pSCwq2sRsO{TYo)7C)e00ZfI2d=s;xQ-VAUTcxn!}HRvoyMLACAK;ifs7RYP$kw_(ZojE2SZHB Zl;f!nuLygx{{Aq@@Up3Xsh-P|{{`hj6zc#0 literal 0 HcmV?d00001 From bc06727deca4e55a24e5a52503138a077bdffe74 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Fri, 16 Jun 2023 13:43:52 +0100 Subject: [PATCH 105/164] Corrected order of states to match input order in calculate_initial_counts. Note that in eq_states treated is "T" not "Tr. --- R/variables.R | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/R/variables.R b/R/variables.R index c5825606..0931b3f7 100644 --- a/R/variables.R +++ b/R/variables.R @@ -87,7 +87,7 @@ create_variables <- function(parameters) { } states <- c('S', 'D', 'A', 'U', 'Tr') - initial_states <- initial_state(parameters, initial_age, groups, eq) + initial_states <- initial_state(parameters, initial_age, groups, eq, states) state <- individual::CategoricalVariable$new(states, initial_states) birth <- individual::IntegerVariable$new(-initial_age) last_boosted_ib <- individual::DoubleVariable$new(rep(-1, size)) @@ -316,10 +316,10 @@ initial_immunity <- function( rep(parameter, length(age)) } -initial_state <- function(parameters, age, groups, eq) { - ibm_states <- c('S', 'A', 'D', 'U', 'Tr') +initial_state <- function(parameters, age, groups, eq, states) { + ibm_states <- states if (!is.null(eq)) { - eq_states <- c('S', 'A', 'D', 'U', 'T') + eq_states <- c('S', 'D', 'A', 'U', 'T') age <- age / 365 return(vcapply( seq_along(age), From db3cc96bafb1b54ef681063870bd76cdaf00c1d0 Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Fri, 16 Jun 2023 14:53:31 +0100 Subject: [PATCH 106/164] Removed the in-text reference to Jamie_parameter.rds and changed the name of the object which stores them to q_simparams. Made the way average_age is specified in the get_parameters() call clearer and, finally, removed the individual_mosquitoes = FALSE from the get_parameters() call as this is the default setting --- vignettes/EIRprevmatch.Rmd | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/vignettes/EIRprevmatch.Rmd b/vignettes/EIRprevmatch.Rmd index 738d55da..a063524d 100644 --- a/vignettes/EIRprevmatch.Rmd +++ b/vignettes/EIRprevmatch.Rmd @@ -39,7 +39,7 @@ The code chunks demonstrating the latter two methods call functions from the `mg ## *Pf*PR~2-10~ matching using malariaEquilibrium -The `malariaEquilibrium` package function `human_equilibrium()` returns the canonical equilibrium solution for a given EIR and the *Pf*PR~2-10~ can be calculated the output (see for more information). The first step is to generate a large range of EIR values to generate matching *Pf*PR~2-10~ values for. Next, we load the package's default parameter set (`Jamie_parameters.rds`), specify an effective clinical treatment coverage (`ft`) of 0.45 and, for each EIR value generated, run the `human_equilibrium()` function. +The `malariaEquilibrium` package function `human_equilibrium()` returns the canonical equilibrium solution for a given EIR and the *Pf*PR~2-10~ can be calculated the output (see for more information). The first step is to generate a large range of EIR values to generate matching *Pf*PR~2-10~ values for. Next, we load the package's default parameter set, specify an effective clinical treatment coverage (`ft`) of 0.45 and, for each EIR value generated, run the `human_equilibrium()` function. The `human_equilibrium()` function returns a dataframe containing the proportion of each age class in each state variable at equilibrium. The *Pf*PR~2-10~ can be calculated from the output for each EIR value by summing the proportion of people aged 2-10 with cases of malaria (`pos_M`) and dividing this proportion by the proportion of the population between the ages 2-10 (`prop`). Finally, we store the matching EIR and *Pf*PR~2-10~ values in a data frame. @@ -49,7 +49,7 @@ The `human_equilibrium()` function returns a dataframe containing the proportion malEq_EIR <- seq(from = 0.1, to = 50, by = 0.5) # Load the base malariaSimulation parameter set: -eq_simparams <- malariaEquilibrium::load_parameter_set("Jamie_parameters.rds") +q_simparams <- malariaEquilibrium::load_parameter_set("Jamie_parameters.rds") # Use human_equilibrium() to calculate the PfPR2-10 values for the range of # EIR values: @@ -59,7 +59,7 @@ malEq_prev <- vapply( eq <- malariaEquilibrium::human_equilibrium( eir, ft = 0.45, - p = eq_simparams, + p = q_simparams, age = 0:100 ) sum(eq$states[3:11, 'pos_M']) / sum(eq$states[3:11, 'prop']) @@ -98,14 +98,11 @@ simparams <- get_parameters(list( human_population = human_population, # Set the average age (days) of the population: - average_age = 8453.323, + average_age = 23 * year, # Instruct model to render prevalence in age group 2-10: prevalence_rendering_min_ages = 2 * year, - prevalence_rendering_max_ages = 10 * year, - - # Turn off the individual mosquitoes module: - individual_mosquitoes = FALSE)) + prevalence_rendering_max_ages = 10 * year)) # Use the set_species() function to specify the mosquito population (species and # relative abundances): From 0214c890164c827c193f118d88309e92fa698c90 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Mon, 26 Jun 2023 12:55:11 +0100 Subject: [PATCH 107/164] Vignettes made consistent --- DESCRIPTION | 24 ++++ README.md | 2 + _pkgdown.yml | 100 ++++++++++++++++ vignettes/Demography.Rmd | 80 +++++-------- vignettes/EIRprevmatch.Rmd | 55 +++------ vignettes/EIRprevmatch_Fig_1.png | Bin 5110 -> 5833 bytes vignettes/EIRprevmatch_Fig_2.png | Bin 9423 -> 9414 bytes vignettes/MDA.Rmd | 117 ++++++++----------- vignettes/Metapopulation.Rmd | 41 ++++--- vignettes/Model.Rmd | 170 +++++++++++++++++++--------- vignettes/Parameter_variation.Rmd | 80 +++++++++++++ vignettes/SetSpecies.Rmd | 109 +++++++++++++----- vignettes/Treatment.Rmd | 46 ++++---- vignettes/Vaccines.Rmd | 167 ++++++++++++++++----------- vignettes/Variation.Rmd | 111 ++++++++++++++---- vignettes/VectorControl_Bednets.Rmd | 52 +++++---- vignettes/VectorControl_IRS.Rmd | 43 +++---- 17 files changed, 781 insertions(+), 416 deletions(-) create mode 100644 vignettes/Parameter_variation.Rmd diff --git a/DESCRIPTION b/DESCRIPTION index 290724d7..eb5c35cc 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -32,6 +32,30 @@ Authors@R: c( role = c('aut'), email = 'r.fitzjohn@imperial.ac.uk' ), + person( + given = "Richard", + family = "Sheppard", + role = c('aut'), + email = 'r.sheppard11@imperial.ac.uk' + ), + person( + given = "Tom", + family = "Brewer", + role = c('aut'), + email = 'thomas.brewer16@imperial.ac.uk' + ), + person( + given = "Kelly", + family = "McCain", + role = c('aut'), + email = 'k.mccain22@imperial.ac.uk' + ), + person( + given = "Lydia", + family = "Haile", + role = c('aut'), + email = 'l.haile@imperial.ac.uk' + ), person( given = "Imperial College of Science, Technology and Medicine", family = "", diff --git a/README.md b/README.md index 6d8f5915..b86f6ac3 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,8 @@ library('malariasimulation') output <- run_simulation(100) ``` +Please see [vignettes](https://mrc-ide.github.io/malariasimulation/articles/Model.html) for more detailed use. + ## Code organisation *model.R* - is the entry point for the model. It creates the different diff --git a/_pkgdown.yml b/_pkgdown.yml index 6ef5f5a6..1cc68395 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1 +1,101 @@ destination: docs + +navbar: + title: "malariasimulation" + structure: + left: [vignettes, functions, news] + right: [icon] + components: + vignettes: + text: "Vignettes" + menu: + - text: "Model Introduction" + href: articles/Model.html + - text: "Demography" + href: articles/Demography.html + - text: "Treatment" + href: articles/Treatment.html + - text: "MDA and Chemoprevention" + href: articles/MDA.html + - text: "Vaccines" + href: articles/Vaccines.html + - text: "Vector Control: Bednets" + href: articles/VectorControl_Bednets.html + - text: "Vector Control: Indoor Residual Spraying" + href: articles/VectorControl_IRS.html + - text: "Mosquito Species" + href: articles/SetSpecies.html + - text: "Carrying Capacity" + href: articles/Carrying-capacity.html + - text: "Matching PfPR2-10 to EIR" + href: articles/EIRprevmatch.html + - text: "Metapopulation Modelling" + href: articles/Metapopulation.html + - text: "Stochastic Variation" + href: articles/Variation.html + - text: "Parameter Variation" + href: articles/Parameter_variation.html + functions: + text: "Functions" + href: reference/index.html + icon: + icon: fa-github + href: https://github.com/mrc-ide/malariasimulation + +reference: +- title: "Run functions" + contents: + - run_simulation + - run_metapop_simulation + - run_simulation_with_repetitions +- title: "Parameter functions" + contents: + - get_parameters + - get_correlation_parameters + - set_parameter_draw + - set_equilibrium +- title: "Demography functions" + contents: + - set_demography +- title: "Mosquito species functions and parameters" + contents: + - set_species + # - set_carrying_capacity + - arab_params + - fun_params + - gamb_params + # - steph_params +- title: "Intervention functions" +- subtitle: "Drug treatments" + contents: + - set_drugs + - set_clinical_treatment + - AL_params + - DHA_PQP_params + - SP_AQ_params +- subtitle: "MDA and chemoprevention" + contents: + - set_mda + - set_pmc + - set_smc + - peak_season_offset +- subtitle: "Vaccines" + contents: + - set_mass_pev + - set_pev_epi + - set_tbv +- subtitle: "Vector control" + contents: + - set_bednets + - set_spraying +- title: "Non-user functions" + contents: + - CorrelationParameters + - create_pev_profile + - create_progress_process + - find_birthrates + - parameter_draws + - parameterise_mosquito_equilibrium + - parameterise_total_M + - rtss_booster_profile + - rtss_profile \ No newline at end of file diff --git a/vignettes/Demography.Rmd b/vignettes/Demography.Rmd index 2f599d7d..c57175f9 100644 --- a/vignettes/Demography.Rmd +++ b/vignettes/Demography.Rmd @@ -15,26 +15,21 @@ knitr::opts_chunk$set( ``` ```{r setup} -# Load in the requisite package(s): +# Load the requisite packages: library(malariasimulation) +# Set colour palette: +cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") ``` -# Introduction +The dynamics of malaria transmission, and the efficacy of interventions designed to interrupt it, are highly context specific and an important consideration is the demography of the population(s) under investigation. To suit the research needs of the user, `malariasimulation` allows for the specification of custom human population demographics by allowing them to specify age-group specific death rate parameters. It also enables users to instruct the model to render outputs with variables of interest (e.g. human population, number of cases detectable by microscopy, number of severe cases, etc.) presented by user-defined age groups. In this vignette, we use simple, illustrative cases to demonstrate how to customise the output rendered by the `run_simulation()` function, and how to specify both fixed and time-varying custom death rates. -The dynamics of malaria transmission, and the efficacy of interventions designed to interrupt it, are highly context specific and an important consideration is the demography of the population(s) under investigation. To suit the research needs of the user, `malariasimulation` allows for the specification of custom human population demographics by allowing them to specify age-group specific death rates parameters. It also enables users to instruct the model to render outputs with variables of interest (e.g. human population, number of cases detectable by microscopy, number of severe cases, etc.) presented by user-defined age groups. In this vignette, we use simple, illustrative cases to demonstrate how to customise the output rendered by the `run_simulation()` function, and how to specify both fixed and time-varying custom death rates. - -# Specifying human death rates by age group - -The `malariasimulation` package allows users to capture different human population demographies by specifying age-specific death rates. In the first section, we'll demonstrate how to instruct the model to output population and disease metrics by user-defined age groups and how to establish and run simulations with age-specific death rates. We'll illustrate the effect this has by comparing the demographic make-up of this custom parameterisation with that produced using the demographic profile established by the default parameters. - -## Default Parameterisation +## Age group rendering First, we'll establish a base set of parameters using the `get_parameters()` function and accept the default values. The `run_simulation()` function's default behaviour is to output only the number of individuals aged 2-10 years old (`output$n_730_3650`, where 730 and 3650 are the ages in days). However, the user can instruct the model to output the number of individuals in age groups of their choosing using the `age_group_rendering_min_ages` and `age_group_rendering_max_ages` parameters. These arguments take vectors containing the minimum and maximum ages (in daily time steps) of each age group to be rendered To allow us to see the effect of changing demographic parameters, we'll use this functionality to output the number of individuals in ages groups ranging from 0 to 85 at 5 year intervals. Note that the same is possible for other model outputs using their equivalent min/max age-class rendering arguments (`n_detect` , `p_detect`, `n_severe`, `n_inc`, `p_inc`, `n_inc_clinical`, `p_inc_clinical`, `n_inc_severe`, and `p_inc_severe`, run `?run_simulation()` for more detail). We next use the `set_equilibrium()` function to tune the initial parameter set to those required to observe the specified initial entomological inoculation rate (`starting_EIR`) at equilibrium. We now have a set of default parameters ready to use to run simulations. ```{r} - # Set the timespan over which to simulate year <- 365; years <- 5; sim_length <- year * years @@ -59,15 +54,13 @@ simparams <- get_parameters( # Use set_equilibrium to tune the human and mosquito populations to those required for the # defined EIR simparams <- set_equilibrium(simparams, starting_EIR) - ``` -## **Custom Demographic Parameterisation** +## Set custom demography Next, we'll use the the in-built `set_demography()` function to specify human death rates by age group. This function accepts as inputs a parameter list to update, a vector of the age groups (in days) for which we specify death rates, a vector of time steps in which we want the death rates to be updated, and a matrix containing the death rates for each age group in each timestep. The `set_demography()` function appends these to the parameter list and updates the `custom_demography` parameter to `TRUE`. Here, we instruct the model to implement these changes to the demographic parameters at the beginning of the simulation (`timesteps = 0`). ```{r} - # Copy the simulation parameters as demography parameters: dem_params <- simparams @@ -94,15 +87,13 @@ dem_params <- set_demography( # Confirm that the custom demography has been set: dem_params$custom_demography - ``` -## Simulations +### Simulation Having established parameter sets with both default and custom demographic parameterisations, we can now run a simulation for each using the `run_simulation()` function. We'll also add a column to each identify the runs. ```{r} - # Run the simulation with the default demographic set-up: exp_output <- run_simulation(sim_length, simparams) exp_output$run <- 'exponential' @@ -110,16 +101,13 @@ exp_output$run <- 'exponential' # Run the simulation for the custom demographic set-up: custom_output <- run_simulation(sim_length, dem_params) custom_output$run <- 'custom' - - ``` -## Visualisation +### Visualisation Using barplots, we can visualise the effect of altering the demographic parameters by comparing the distribution of people among the age-classes we instructed the model to output on the final day of the simulation. The default demography is depicted in blue, while the custom demography is given in orange. Under the custom demography, the frequency in individuals in older age classes declines almost linearly, while in the default demography the number of individuals in each age class declines exponentially with age. -```{r, fig.width = 7.2, fig.height = 4, fig.fullwidth = TRUE} - +```{r, fig.align = 'center', out.width='100%', fig.asp=0.5} # Combine the two dataframes: dem_output <- rbind(exp_output, custom_output) @@ -146,45 +134,39 @@ convert_to_long <- function(age_min, age_max, output) { # Convert the output for plotting: dem_output <- convert_to_long(age_min, age_max, dem_output) -# Define a colour palette for plotting: -dem_cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") - # Define the plotting window par(mfrow = c(1, 2), mar = c(4, 4, 1, 1)) # a) Default/Exponentially-distributed demography -plot.new(); grid(lty = 1, col = "darkgrey", nx = 17, ny = 10, lwd = 0.5); par(new = TRUE) +plot.new(); grid(lty = 2, col = "grey80", lwd = 0.5, ny = 5, nx = 6); par(new = TRUE) barplot(height = dem_output[dem_output$run == "exponential", c("n", "age_plot")]$n, - names = dem_output[dem_output$run == "exponential", c("n", "age_plot")]$age_plot, + names = c(paste0(seq(0,75, by = 5),"-",seq(0,75, by = 5)+4), "80+"), axes = TRUE, space = 0, ylim = c(0, 250), xaxs = "i", yaxs = "i", main = "Default", xlab = "Age Group", ylab = "Individuals", - cex.axis = 0.8, cex.lab = 1, cex.main = 1, - col = dem_cols[2]); box() + cex.axis = 0.8, cex.names = 0.8, cex.lab = 1, cex.main = 1, las = 2, + col = cols[2]); box() # b) Custom demography plot.new() -grid(lty = 1, col = "darkgrey", nx = 17, ny = 10, lwd = 0.5) +grid(lty = 2, col = "grey80", lwd = 0.5, ny = 5, nx = 6) par(new = TRUE) barplot(height = dem_output[dem_output$run == "custom", c("n", "age_plot")]$n, - names = dem_output[dem_output$run == "custom", c("n", "age_plot")]$age_plot, + names = c(paste0(seq(0,75, by = 5),"-",seq(0,75, by = 5)+4), "80+"), axes = TRUE, space = 0, ylim = c(0, 250), xaxs = "i", yaxs = "i", main = "Custom", xlab = "Age Group", - cex.axis = 0.8, cex.lab = 1, cex.main = 1, - col = dem_cols[1]); box() - - + cex.axis = 0.8, cex.names = 0.8, cex.lab = 1, cex.main = 1, las = 2, + col = cols[1]); box() ``` -# Dynamic demography: time-varying death rates +## Set dynamic demography Using the `timesteps` and `deathrates` arguments, we can also use the `set_demography()` function to update the death rates of specific age groups through time. In the following example, we'll use this functionality to first set our own initial death rates by age group, then instruct the model to increase the death rates in the age groups 5-10, 10-15, and 15-20 years old by a factor of 10 after 2 years. We'll finish by plotting the number of individuals in each age class at the end of each year to visualise the effect of time-varying death rates on the human population age-structure. -## Parameterisation +### Parameterisation We'll start by making a copy of the base parameters which have been instructed to output the population size through time (`simparams`). Next, we create a version of the `deathrates` vector created earlier updated to increase the death rates of the 5-10, 10-15, and 15-20 age groups by 10%. Finally, we use `set_demography()` to update our parameter list and specify our custom demography. This is achieved providing the `timesteps` argument with a vector of days to update the death rates (0 and 730 days), and providing `deathrates` with a matrix of death rates where each row corresponds to a set of death rates for a given update. ```{r} - # Store the simulation parameters in a new object for modification dyn_dem_params <- simparams @@ -199,48 +181,44 @@ dyn_dem_params <- set_demography( timesteps = c(0, 2*365), deathrates = matrix(c(deathrates, deathrates_increased), nrow = 2, byrow = TRUE) ) - ``` -## Simulation +### Simulation Having established the parameter list for the dynamic death rate simulation, we can now run the simulation using the `run_simulation()` function. ```{r} # Run the simulation for the dynamic death rate demography dyn_dem_output <- run_simulation(sim_length, dyn_dem_params) - ``` -## Visualisation +### Visualisation Bar plots of the age structure of the human population at the end of each year show the marked effect that increasing the death rate within a small subset of age classes can have on the demography of the human population over time. -```{r, fig.width = 7.2, fig.height = 3, fig.fullwidth = TRUE} - +```{r, fig.align = 'center', out.width='100%', fig.asp=0.35} # Filter out the end-of-year population sizes, add a column naming the run, and convert # dataframe to long-form: -dyn_dem_output <- dyn_dem_output[dyn_dem_output$timestep %in% (1:5 * 365),] +dyn_dem_output <- dyn_dem_output[dyn_dem_output$timestep %in% (c(1,3,5) * 365),] dyn_dem_output$run <- 'dynamic' dyn_dem_output <- convert_to_long(age_min, age_max, dyn_dem_output) # Set a 1x5 plotting window: -par(mfrow = c(1,5), mar = c(4, 4, 1, 1)) +par(mfrow = c(1,3), mar = c(4, 4, 1, 1)) # Loop through the years to plot: -for(i in 1:5) { +for(i in c(1,3,5)) { plot.new() - grid(lty = 1, col = "darkgrey", nx = 11, ny = 10, lwd = 0.5) + grid(lty = 2, col = "grey80", lwd = 0.5, ny = 5, nx = 6) par(new = TRUE) barplot(height = dyn_dem_output[dyn_dem_output$timestep/365 == i,c("n", "age_plot")]$n, - names = dyn_dem_output[dyn_dem_output$timestep/365 == i,c("n", "age_plot")]$age_plot, + names = c(paste0(seq(0,75, by = 5),"-",seq(0,75, by = 5)+4), "80+"), axes = TRUE, space = 0, ylim = c(0, 500), main = paste0("Year ", i), cex.main = 1.4, xlab = ifelse(i == 3, "Age Group", ""), ylab = ifelse(i == 1, "Individuals", ""), - xaxs = "i", yaxs = "i", - cex.axis = 0.8, cex.lab = 1, cex.main = 1, col = dem_cols[3]) + xaxs = "i", yaxs = "i", las = 2, + cex.axis = 0.8, cex.names = 0.8, cex.lab = 1, cex.main = 1, col = cols[3]) box() } - ``` diff --git a/vignettes/EIRprevmatch.Rmd b/vignettes/EIRprevmatch.Rmd index a063524d..9299bded 100644 --- a/vignettes/EIRprevmatch.Rmd +++ b/vignettes/EIRprevmatch.Rmd @@ -15,28 +15,20 @@ knitr::opts_chunk$set( ``` ```{r setup, message=F, warning=F} - -# Load in the requisite functions +# Load the requisite packages: library(malariasimulation) library(malariaEquilibrium) - -# The cali and mgcv packages are required but not loaded. To run the code manually load these: -# packages. -#library(mgcv) -#library(cali) +# Set colour palette: +cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") ``` -## Introduction - The entomological inoculation rate (EIR), defined as the number of infectious bites experienced per person per unit time, and malaria prevalence, the proportion of the population with detectable malaria, are two metrics used to measure and/or describe malaria transmission. With respect to the latter, the focus is often on the prevalence rate of *Plasmodium falciparum* in children aged two to ten years old, denoted *Pf*PR~2-10~. When setting up a simulation, `malariasimulation` users often need to calibrate the model run to an observed level of transmission. Calibrating to an EIR value can be done directly using the `set_equilibrium()` function, but EIR is difficult to measure and in practice *Pf*PR~2-10~ is more commonly recorded/reported as a measure of transmission. However, `malariasimulation` does not allow users to calibrate directly to an *Pf*PR~2-10~ value. To calibrate to a target *Pf*PR~2-10~, users must instead identify and input the EIR value that yields the target *Pf*PR~2-10~ value. In this vignette, three methods for matching the EIR to a target *Pf*PR~2-10~ are outlined and compared. The first and fastest method uses the `malariaEquilibrium` package function `human_equilibrium()` to calculate the equilibrium *Pf*PR~2-10~ for a given EIR using the canonical equilibrium solution for the `malariasimulation` model. The second method involves running `malariasimulation` simulations across a small set of initial EIR values, extracting the *Pf*PR~2-10~ from each simulation run, and fitting a model relating initial EIR to *Pf*PR~2-10~ to allow users to predict the initial EIR value required to yield the desired *Pf*PR~2-10~. The third approach is to calibrate the model using the `cali` package function (see https://github.com/mrc-ide/cali for more information) `calibrate()` , which searches a user-defined EIR parameter space and identifies the value which yields the target *Pf*PR~2-10~ to a defined tolerance. -The code chunks demonstrating the latter two methods call functions from the `mgcv` and `cali` packages. To reduce the number of dependencies when installing the `malariasimulation` package we have commented out the lines loading these packages and instructed these chunks not to run. However, users wishing to run and/or experiment with these examples, need simply uncomment the lines loading the `cali` and `mgcv` packages. - ## *Pf*PR~2-10~ matching using malariaEquilibrium The `malariaEquilibrium` package function `human_equilibrium()` returns the canonical equilibrium solution for a given EIR and the *Pf*PR~2-10~ can be calculated the output (see for more information). The first step is to generate a large range of EIR values to generate matching *Pf*PR~2-10~ values for. Next, we load the package's default parameter set, specify an effective clinical treatment coverage (`ft`) of 0.45 and, for each EIR value generated, run the `human_equilibrium()` function. @@ -44,7 +36,6 @@ The `malariaEquilibrium` package function `human_equilibrium()` returns the cano The `human_equilibrium()` function returns a dataframe containing the proportion of each age class in each state variable at equilibrium. The *Pf*PR~2-10~ can be calculated from the output for each EIR value by summing the proportion of people aged 2-10 with cases of malaria (`pos_M`) and dividing this proportion by the proportion of the population between the ages 2-10 (`prop`). Finally, we store the matching EIR and *Pf*PR~2-10~ values in a data frame. ```{r} - # Establish a range of EIR values to generate matching PfPR2-10 values for: malEq_EIR <- seq(from = 0.1, to = 50, by = 0.5) @@ -72,7 +63,6 @@ malEq_P2E <- cbind.data.frame(EIR = malEq_EIR, prev = malEq_prev) # View the dataframe containing the EIR and matching PfPR2-10 values: head(malEq_P2E, n = 7) - ``` As this method does not involve running simulations it can return matching *Pf*PR~2-10~ for a wide range of EIR values very quickly. However, it is only viable for systems at steady state, with a fixed set of parameter values, and only enables the user to capture the effects of the clinical treatment of cases. Often when running `malariasimulation` simulations, one or both of these conditions are not met. In this example, we have set the proportion of cases effectively treated (`ft`) to 0.45 to capture the effect of clinical treatment with antimalarial drugs. However, the user may, for example, also wish to include the effects of a broader suite of interventions (e.g. bed nets, vaccines, etc.), or to capture changes in the proportion of people clinically treated over time. In these cases, a different solution would therefore be required. @@ -86,7 +76,6 @@ Where the `malariaEquilibrium` method is not viable, an alternative is to run `m To run `malariasimulation`, the first step is to generate a list of parameters using the `get_parameters()` function, which loads the default `malariasimulation` parameter list. Within this function call, we adapt the average age of the human population to flatten its demographic profile, instruct the model to output malaria prevalence in the age range of 2-10 years old, and switch off the individual-based mosquito module. The `set_species()` function is then called to specify a vector community composed of *An. gambiae*, *An. funestus*, and *An arabiensis* at a ratio of 2:1:1. The `set_drugs()` function is used to append the built-in parameters for artemether lumefantrine (AL) and, finally, the `set_clinical_treatment()` function is called to specify a treatment campaign that distributes AL to 45% of the population in the first time step (t = 1). ```{r} - # Specify the time frame over which to simulate and the human population size: year <- 365 human_population <- 5000 @@ -120,7 +109,6 @@ simparams <- set_clinical_treatment(parameters = simparams, drug = 1, timesteps = c(1), coverages = c(0.45)) - ``` ### Run the simulations and calculate *Pf*PR~2-10~ @@ -130,7 +118,6 @@ Having established a set of `malariasimulation` parameters, we are now ready to The `run_simulation()` outputs an EIR per time step, per species, across the entire human population. We first convert these to get the number of infectious bites experienced, on average, by each individual across the final year across all vector species. Next, the average *Pf*PR~2-10~ across the final year of the simulation is calculated by dividing the total number of individuals aged 2-10 by the number (`n_730_3650`) of detectable cases of malaria in individuals aged 2-10 (`n_detect_730_3650`) on each day and calculating the mean of these values. Finally, initial EIR, output EIR, and *Pf*PR~2-10~ are stored in a data frame. ```{r} - # Establish a vector of initial EIR values to simulate over and generate matching # PfPR2-10 values for: init_EIR <- c(0.01, 0.1, 1, 5, 10, 25, 50) @@ -183,7 +170,6 @@ malSim_P2E <- cbind.data.frame(init_EIR, EIR = unlist(malSim_EIR), prev = unlist # View the dataframe containing the EIR and matching PfPR2-10 values: malSim_P2E - ``` ### Fit line of best fit relating initial EIR values to *Pf*PR~2-10~ @@ -191,6 +177,7 @@ malSim_P2E Having run `malariasimulation` simulations for a range of initial EIRs, we can fit a line of best fit through the initial EIR and *Pf*PR~2-10~ data using the `gam()` function (`mgcv`) and then use the `predict()` function to return the *Pf*PR~2-10~ for a wider range of initial EIRs (given the set of parameters used). ```{r, eval = F} +library(mgcv) # Fit a line of best fit through malariasimulation initial EIR and PfPR2-10 # and use it to predict a series of PfPR2-10 values for initial EIRs ranging @@ -201,7 +188,6 @@ malSim_fit <- predict(gam(prev~s(init_EIR, k = 5), data = malSim_P2E), # Create a dataframe of initial EIR values and PfPR2-10 values: malSim_fit <- cbind(malSim_fit, data.frame(init_EIR = c(0 ,seq(0.1, 50, 0.1)))) - ``` ## Visualisation @@ -209,16 +195,11 @@ malSim_fit <- cbind(malSim_fit, data.frame(init_EIR = c(0 ,seq(0.1, 50, 0.1)))) Let's visually compare our the `malariaEquilibrium` and `malariasimulation` methods for matching EIR to *Pf*PR~2-10~ values. In the section below we open a blank plot, plot the initial EIR and resulting *Pf*PR~2-10~ points generated using `malariasimulation` runs and overlay the line of best fit (orange line). Also overlayed is a line mapping EIR and *Pf*PR~2-10~ values calculated using `malariaEquilibrium` (blue line). ```{r, eval = F} - -# Define a colour palette for plotting: -plot_cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") - # Establish a plotting window: plot(x = 1, type = "n", - frame = F, xlab = "Initial EIR", ylab = expression(paste(italic(Pf),"PR"[2-10])), xlim = c(0,50), ylim = c(0, 1), - xaxs = "i", yaxs = "i") + xaxs = "i", yaxs = "i");grid(lty = 2, col = "grey80", lwd = 0.5) # Overlay the initial EIR and corresponding PfPR2-10 points from malariasimulation: points(x = malSim_P2E$init_EIR, @@ -229,7 +210,7 @@ points(x = malSim_P2E$init_EIR, # Overlay the malariasimulation line of best fit: lines(x = malSim_fit$init_EIR, y = malSim_fit$malSim_fit, - col = plot_cols[1], + col = cols[1], lwd = 2, type = "l", lty = 1) @@ -237,7 +218,7 @@ lines(x = malSim_fit$init_EIR, # Overlay the malariaEquilibrium EIR to PfPR2-10 line: lines(x = malEq_P2E$EIR, y = malEq_P2E$prev, - col = plot_cols[2], + col = cols[2], type = "l", lwd = 2, lty = 1) @@ -245,11 +226,10 @@ lines(x = malEq_P2E$EIR, # Add a legend: legend("topright", legend = c("malariasimulation", "malariaEquilibrium"), - col = c(plot_cols[1:2]), + col = c(cols[1:2]), lty = c(1,1), box.col = "white", cex = 0.8) - ``` @@ -261,7 +241,6 @@ We can see that the `malariaEquilibrium` provides a reasonable approximation whe Using the fitted relationship between initial EIR and *Pf*PR~2-10~, we can create a function that returns the EIR value(s) estimated to yield a target *Pf*PR~2-10~ given the model parameters. The function works by finding the closest *Pf*PR~2-10~ value from the values generated when we fit the model to a target value input by the user, and then using that index to return the corresponding initial EIR value. ```{r, eval = F} - # Store some target PfPR2-10 values to match to: PfPRs_to_match <- c(0.10, 0.25, 0.35, 0.45) @@ -280,7 +259,6 @@ matched_EIRs <- unlist(lapply(PfPRs_to_match, match_EIR_to_PfPR)) # Create a dataframe of matched PfPR2-10 and EIR values: cbind.data.frame(PfPR = PfPRs_to_match, Matched_EIR = matched_EIRs) - ``` ## Calibrating *Pf*PR~2-10~ using the cali package @@ -290,6 +268,7 @@ The third option is to use the `calibrate()` function from the `cali` package (f The `calibrate()` function accepts as inputs a list of `malariasimulation` parameters, a summary function that takes the `malariasimulation` output and returns a vector of the target variable (e.g. a function that returns the *Pf*PR~2-10~), and a tolerance within which to accept the output target variable value and terminate the routine. To reduce the time taken by the `calibrate()` function, the user can also specify upper and lower bounds for the EIR space the function will search. The function runs through a series of `malariasimulation` simulations, trying different EIRs and honing in on the target value of the target variable, terminating when the target value output falls within the tolerance specified. ```{r, eval = F} +library(cali) # Prepare a summary function that returns the mean PfPR2-10 from each simulation output: summary_mean_pfpr_2_10 <- function (x) { @@ -326,7 +305,6 @@ cali_EIR <- calibrate(target = target_pfpr, # Use the match_EIR_to_PfPR() function to return the EIR predicted to be required under the # malariasimulation method: malsim_EIR <- match_EIR_to_PfPR(x = target_pfpr) - ``` The `calibrate()` function is a useful tool, but be aware that it relies on the user selecting and accurately coding an effective summary function, providing reasonable bounds on the EIR space to explore, and selecting a population size sufficiently large to limit the influence of stochasticity. @@ -334,10 +312,6 @@ The `calibrate()` function is a useful tool, but be aware that it relies on the As a final exercise, let's compare graphically the `calibrate()` approach with the `malariasimulation` method when the same parameter set is used. The plot below shows the change in *Pf*PR~2-10~ over the duration of the simulation under the initial EIR values recommended by the a) `cali` and b) `malariasimulation` methods to achieve the target *Pf*PR~2-10~ value of 0.3. The blue horizontal line represents the target *Pf*PR~2-10~ and the black lines either side the upper and lower tolerance limits specified for the `cali` method. ```{r, eval = F} - -# Define a colour palette for plotting: -plot_cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") - # Use the set_equilibrium() function to calibrate the simulation parameters to the EIR: simparams_cali <- set_equilibrium(simparams, init_EIR = cali_EIR) simparams_malsim <- set_equilibrium(simparams, init_EIR = malsim_EIR) @@ -368,7 +342,10 @@ plot(x = df$timestep, xlab = "Time (days)", ylim = c(target_pfpr - 0.2, target_pfpr + 0.2), #ylim = c(0, 1), - col = plot_cols[3]) + col = cols[3]) + +# Add grid lines +grid(lty = 2, col = "grey80", lwd = 0.5) # Add a textual identifier and lines indicating target PfPR2-10 with # tolerance bounds: @@ -386,7 +363,10 @@ plot(x = df$timestep, ylab = "", ylim = c(target_pfpr - 0.2, target_pfpr + 0.2), #ylim = c(0, 1), - col = plot_cols[1]) + col = cols[1]) + +# Add grid lines +grid(lty = 2, col = "grey80", lwd = 0.5) # Add a textual identifier and lines indicating target PfPR2-10 with # tolerance bounds @@ -395,7 +375,6 @@ text(x = 10, y = 0.47, pos = 4, cex = 0.9, abline(h = target_pfpr, col = "dodgerblue", lwd = 2) abline(h = target_pfpr - pfpr_tolerance, lwd = 2) abline(h = target_pfpr + pfpr_tolerance, lwd = 2) - ``` diff --git a/vignettes/EIRprevmatch_Fig_1.png b/vignettes/EIRprevmatch_Fig_1.png index 1a98e4f6a93406d77dbec42767beba4f984fa498..c205e827fea6d6a142482f9964eb06a722214f1a 100644 GIT binary patch literal 5833 zcmds5dpK0A#$?+_wn7QXWl9Xnr7{f0P}xPstxa+rw-8-y zmj-LhP?9ppn2^RANyH3ma>-yYXN~odCvLgtmj>8z3Y9~_wv5q@ArK_ z-}kP)t<|QDKW{`J5Sy$|Se!v1)>#5!^4mBrr8sA{os?z+5EU6balUfhpjpWM$KlDtJJ0S5LSEBM^$s(tAy7 z&?7GdLOI{s!t88V&Sb7UiT@$|ct}p&+{qGaf4pu0$Dm97h;_EjCWhC~J5=W-jb$JI z+`M*ASNhzkh`tCa`sKL^Rii7+8Ncd#RoEK}E)yDv&58t>U0ujOekE>R3!2IPzxnu! zL#}vIRiQ z=5z+hkv9%rO#9H$?(Z|wuJ9arTy6&XWj)-74Z)$&>-M}l74i<@`J)pN*X&XipM^T= zaTE!Te7?_NyKDb@l`$4IpYpa#7v0>TZqZ~HGI%Jk!?X}%(d2-xb~UNnsn{gPj1ZkN zXj~*k5WDv@6_mR*TsH<-Et;i8^nX^b@D&U5F|s$IU;Ze8W}(7-x|<0=A2`x>H9eoc ze@t678PX;u=;rJj(~d8Je%T1?IHvfUFW*+Ey%FYBL}ww36nx|W$}Q;nl(k@G>iZRe z-2-UsTZTGJY`Pl^Pz#=6X94Er`Iv-Ek^K9{fkP`(M@aK;BpJcZUJI{fUBN{zZeY1= z<*h%nAp>WKx)jEm05XOFqhviX<#&(EE~GOJ_7qFT+|=f1tNCtfZ!5+@J3m?RC}>58L%T zw~+@0t$O9+DRvLCbkELTiS_dqA@6piT+;lr=RUAlW+WVIa2KVvevv5XMS%(yaKB!N zVR7A)cdf241AGuCuVyT2E~6YMBFO=zX6Ei3FCEHaWW)2Ir8M!9HIXy)go4>Y(vKh# zbj(D0zK`gxUj6SVx5y38O;_IMWF9s6RiGvACswpFraKyrqGO^f%;&*!wAIsOKC$|W}*uwxcn7wk@7t&u(o<4 z$o821)2z(s!;jS-%k%`#wGP?ng~aNOF?Uz-LAB{vlT5(?xfe{(t3aI;(|T)QSY+XJQgrN2~@;QJQOb$)F1y5RO+Ian!#ega`9FGw-)3y zd0Kuk6O|K9weOhBLE*zI*OrVOR$NyHE|q6|wqq2JA8l>))w*Mnn^|U@KV3WKaSJLc z8Qv@20FMX-xv9j}QGFg(oLvlgI$i$r&!*kce zYI_h2gNyJ5&CG4lV^<+F;^~GlkDTc;6ZihnNVBNqp@A5v(0(;qup;R8d`xVxB0wpD z!|J!gLdD-;XCHDE>7&tQa3IJ$gIqceYBXL__NK?Dxdu2_dekmCRc98!1gk*;Xn+*! zH}V=s1xItPbh+z+oYs@E0&zgqUQ_(q(@TeT@3#)#vL^0x(A{&^SvIeJ-PR$Ej4bFe zv7(Js$iTpSNLiUjRLS}^??VY1*p2P1cy-DI2<+=Isc*htPB%(>+jVe z3*gZIq1b;J$p4AY-z>9$nEh}7!?RFOhGEcs{}Z3Thy6cRjY`1r7?3HddV)ns9da|5 zPJ)%_7j@0Bt9m<|uIdH>GAPAQ>iuH6 zbn!YfF4SjA7tqx64fc!TpBP!0RXRb-O|$&{`j2y#k{r_}51t8p?%oms9^{Hdp5mwv zP9hN>BvL-7b|>d~P(5pq+CQ8XS(oIg&WJ?S$i*?{GW5K1TnNaI4_4Ki6#d(EhM~E zS5;5AKZ@OCT2KMS96R&;?QJ3e!HjS=+q7L*%mK^&Yi{JK@X%KscCY4sa71?m~r8Evx^*e*Ay&Z#?;DrIgA%U^G}??eGlyCpRn}@arbDRZ-Q!2aJZ>%gI(4yh zI~yEHI(^4Rj^d)aZbo}eC1*MIg(GN8Jo%yHux`tC)DF;edR>oB`tB}u)_mrmPDLK=!WTfv^;5Cd zKo}u!c|LDtV443yFmb>Il(`5#kqNWy+LWD{IVjm{I=jSvFc=#7s&zP7y_96tlZijM zjb-O3nHCEZryG|pJ&2u9nXFDPde3lmZ2e9cuZ;U7S(zlg*yoAdkzq^KB)%&e2T7IG zR}G{GDz6JmH02Egz;{+?jjL~lu)VJBR`zfKiw-eL+=DE0l!t8ph7g@8eNN8*mz z!uu>$j+sA6_~s{w>IsQo44Wz>g&VxRMRWMQgiFU&2yES)A*#j)x&{v94$eHTq8}8r zy*y0b6O?vPaqc6`KP=v+;!{l zCFW@tBZA!xmHy0_%cSfJAEev&H$PwP@~v_c*}0#5W9}gBI_xr6M!ER&@%5IVeE$wR zM89_mhe5!WF8Fn@Z%>MmbSbi z2*Yl~!&`4^cW(doy3RC$RcPG{g7o?JETJ|v7e-X%-GHl8s8q@y(D6AMtH5KuRC>O+ z`uXJ8v#etgAn6TCjC}x)QpUb5@CxRU?qyK3zY=Mzi(h>Mx*i~N~kbC?~MU(5`#7PgVg|w9%uk_0p>W*n=q3Qsi zRa9`lW3K_II{rW~P7Sg&Wz)l)?H@=Nd@lQL7TKrVZAD zq{&a|e}qKOacW}@kMkkUs@c6lg7kDD8!3HhIo+AdcGt(A29s5Xzjf1K+ec&p;-{09 zgTa17UCZcA+|1N9#Jy$ouOAhw9zMdbxG%QK@ll_u&q_ULmY{SRrq{zB1!JDT`4D^d zJwb_6E9K$|$Qb`_3AfY`d|GtE_8kB-Z?12A_z)xDzCg>3qyC~vtzKG0dSm+o>^2VF zj1TMmr1r)B1je9>3t<)qfmm#d)Xy~vF&Z^@Hb2ZKrF(~H4jXLv^v8NaML;Pn#^<7Rf+%~{+wswIZP+^YSrCbXz zSAN;0Fco5$n({``?8I+G|JcJ8eGGr^0mZ1T(&4QqBzLV2#vd&DkOY;F-wTO00O-hi zd8s3~i}uG#XB_1$Izfv$$POW5w3_q_`AL(T(=&iZD~>csu!WHDd(Zbl^;`W?bA1=mga)rsQZxxWmk!l3f}G>mdbhPrZRzlE{Mm~6Gc!1Et} z;Ntl?7&FzZ{Lg&y}sb37z>mkAY*r&V9amlV@f0oP4qDpJjTXCRmM&q=V* zEg{KcQd5h2$)Ew8Fg}dcxcbjSg2aRFi!I4}kznbMb^r@0AE>jX`sYslFY+e(HJsfrYGTN7)BseEdv$+$LAk8o}`9-R~1l}oU~ zs0?`Q#_PkGkMv`0g4%!c=;i?sR0Zb&%~SsK^Nac)9riO{h_@YzBFiRzU(um#s5;Wk zQU;Vj4wBD&J7aJ!aBi)i(XAl&T78ZQx@ov3dapQsB7%OYZeEG(SEXY1d5YOl ziO!xV3me*!cdP8s)aOK~vb#?t$r7M6$nJ8yqhJBlVyYD|*gtowjP$DXuLe@0YGbDa znVd##&EmnVrn9FXl?4MBkkxy@X~v`BeVpBkNRpw`Qpvn#a%$j5*&}2~+eXT>h zZ~}2_w9%Qwt&Oe&jV;!Or4QpuNY*RPYG%X{e2EF#{1vfj=h0UubbcGwM~?)DgU+&CFNmYamNO5%c6hX6 zW>|lkceB_}yi^A2oalm{ZGU}k$4uVWk-0COlJMo>ClAa=NR_kIb) z4Z^jtp5>^OAJZq`ICRV!FsAarV}QN*5D-!{i#oaGq>!f-C+s3T^GSz45^z5KU>?df zB>M34Jg3*2#!v|=AcfURcI#mPftm_GfH7%n-EZ@GcY!&z)JHWK3hm2uS zpYfTwN4AWwB`Celgv8$ZLJzk+*IbsbN9SZNOm}Axah%RN#Q*BK=V!^9m#i}-A207B RN{^(iEp08H{dVEjzX24P4}$;z literal 5110 zcmdT|dpK16x1TP*=qA!ziE&A}6=EvPxa3VP3^vBlopKu?jqBS>gpk{? zjZ5VoM!m>oW(dPz%qF*C#GGC4@0{m3|Gnpr^E~J5=ezfM*7~l`TI;*Mv)1hIetOy5 zXz#8gyATM(UK3*jO9Wyogg|Ur65Iw$Y_L~f!leDOsr3bzA`oZ<0*gSS5oq{HL}1A< z4>M>4_NVOUMMM+fK}Hj4wiVOZU)op%7M{kUu`q#eES88R!h?(@!-Iw;^NDB#5k_JW zzr;i$nMS0Mi8T1hCu0$0BAQIZl3_6!9`Hqj=gBl0nNKG3`7|P$MugRWN`E4L5gLsT zLuq{eWEKK80W0xg5&x$;pU)3B+$Ik%W#?UEdmI8G)cEt>((3!>CIYd)$HYM2Iyjxf z*qb$Gh;hH-kELi%mU2Sm(v89?xNNca(5Mi4wN>>nxp|8inrqW=1c@y+(` z@-4MxpLDFE7Yv<75G_q|Tn0}#WMzJKv>g#X$gFoPo=MZ{5sMMd#%wQ5r`R=Oa6rs+ zMgoabrmfyM5O-y)`d3E&LUChcQHNzTvMK1hWm@m|wGy6VEDirFPn0vL)|4D&BWxQ| zv3v$sRUh~xfu5jFiw8O#e1rr$%DNqjiZ}88MxTQ7cfpBv`+j3pt_`{6&WN7V2Jf%A z^o`=pyI&?S_R_%i&s9C;bOBkQdWAPB{u&$dyv{K@BRqQQVit2 znfnr)zIHVroF5RDuFL8$jmY=a);`4L2Ng?sMAAox*kR=EXsq*ycIq7sIT~-$$JGYe02O~{PLdvOin>E4jb6-BHnhXz<0A=-K@0g{#lb5^DT;A;s z!3^K)P;09iN&i7Acu1$7+BM)fqRn(7c!v{kXKUDpazgdT+Q+F*1#tF1r&D~BYWS}X zM@Op`rbUAI<;u-UZR^1>2errG`U=NtF??|PzOlbRvFv~QNgE;T4kGNNR{5)kqr;=~ ze|Ug3t8J3-W;i@uIyM=-j}o-+5>u#u_8>yatvJ3?qY>9_cz!M$F*NO=ozF2l$ZJ2=qTVZC~_YLi6+ofh%IHv!yp)?BNcC*glZPR|W z7?HmVwLj(kO(;&Sj9p%@;L*cp^6w*^(SG4mlL!rK*6gets<|ywtwvV) zlNCgp*hmx`UL^MyFyn|$N{(~BgC4~(r0lLOgxYjA?_3W%Pj%@jRrNPQ15XI(NbZpsupVwK?Pd(sTJd;m6X#>dY1`0?5^G;d zyE%s}Vx4#R3RNG!Iw2qx5BZib>#wI+y?8;wfY}efB}kp&^knYSSLI7=Eh4VKVb zPf&;3kg4&d+OZ!k<}Gb1gx$bI`58f}VbS&tm&|XM!#_+vYZGHL_78G1^}nU!2_f%0xxy-&|;bf3sJtIb!di6~0xywgy-;wcy1B_mn&aP1hnB)yYi z#}D>$Z1<_tdc-=psCaxhXT8%JoB^sNlR{zHd;CPc`ygO|wYd6Yd+-Hv#op+rRly#}+(ujgtGB14Vkb^@>XRCcni~K7@_oUf34! z-Y;WU4RYxcbexuFLP~It40kl^rjmw0B;8siP@&-)krJK12i*5rJL_btsE!QR;AMO* zJ~bT^mMUumnYj2!K0&9Oj<;xGYkY*xN=RzRF9}_plWezVJuKd#&vHz_yLdN-lnjY| zR<^l~?VXv_!T1UtVx(3D6lG*9Z#$qjHVa)Tc@j{mmA<&Bltjf}?h7H%%%^YHX-W81 z96z&szwJf`T|Dif;gsi5pw$6smxGgPV<2}dF%u};IvrXb&?Eh<&=~?Bk3JZtH*n`> zNUzMku=Fw{9%$b&-)i()>N>DkaX0#}JgcFN4#s3I)n+h!dp9`*Y9U9CxW(ylOTbn24Jc4H)WeWD>>59+9N31pH zNszQOssqp#pFFc-ATuE=fLHrjTxzbma}Z-BlqI?YMF>BvU66IhXLd*2Ow9DO<>b*b zGf)-vtcK4+OOHP@(Hr06vIwj5@@W=xj%!mr)wsDV^sD%X1;siq0yVo$Bm2&bcQH(6 zpsa)G1-OWf+QxO$kdWct=~$@oI>1l=rk{bY+6{T9@MMd6KGpfcK4fpEtcN#%;X@Bf zC(PMpQ_GOv+VTj+Sx3_^MJ_{d$Emr>pD~8t%_+jf)S?h)};z$M0p=Dj+Fk z-BJzfmh${QuA^kx^(v`K2@|M7rMI-3zp-{n>{1iY^u|=!k{2ylL*j`V;Uax0 zBy7FCeKM@nJ7cY*x6NK;5V*?a#t5e;(Y;+gOtVf>bOE+FE87GGTr+Af=zd%O_3m)c zm(lIGD$+YqUen-`edf;LTNq@R7kIsb`iIIrv#g21W3gnbi@C{|qVe7UBY^#tpeNJh zp#_vY;V!YD47a>MlUd$dz3$#nnLGpkxn6Xu3zIbF$5koqsWGS5}b-r)P9edPy^E#ibT>ewtyISAFL#Sk-FIzIEm=I?XjN z&;iv#zit$Ctu;`#v+gxa&Bi-67GUI*%T3T(a?lgWh&jQ%RJk~FAR|_ZyIU4h)c7&j z-xoQ!!P#$xN~Npzn$NyF{emtwIQm}GpMUG7$EP@5!-Vw^PE%aCA#uHVKxbB7$5TtiNikcMSfomzrS zQ1$a$Q0vfBB$PvffziicRYv>4Ey^G0`$WZDBi*JaocgKSJE+H#DfNp?;161!| zi{Yg_a?t=vj*h4#)9Cp~{Q*gmVjhZ8*+Vzu)Jg6fFdnVOoX2c6kp{es6m)RFs%7%i zJrDd)HHF*Qk?Iw)=>v&kUPkBqU_;y8`&mAY=JwaH5IHS7=#e}3Y+}K%Z5Lbo;aR(; z@ae4s_f+c+iX0f#(}v$CDrGBlFE#C2`?f7%?hW!o^AUy_hZ*#j74{eDAE)bU$T3@7TuUC5)KAn;%p34;!txVpBNIN5LI+Zym2-_K%^sfIH;FMJ%y2fY)zebxlC^ zwmgv2IG#W{3fqMd)YcTDL>3(U{&8i1T6TXaxHDrY;fOPcO4ff6HVFmwym!g;&kM?F zvw$2##7!2G;o$V0{5_N&o?iRJ;9$4NhcV&ck|OEOZOEq!M2glLf+$U)1GnAjdX>J= zV|s#8A^qQf_`BiVIo9!?hp4a+oa!FPIK>QpKPjjuRhfFcK`P?3YZ5V**k29cE4UuL zslD=j4^0|=O47OS z!1W>en-vvanpFF6J3)!!F{d(jE5QEfK@qSVFamnf$|BKG^g&8C2BIj7ln-N+dXCafReD896qSNW5pTL>Isvl`TP-*lU;b9jYe*8`Ctt9f(5xXw3aa@^)h z=0_jLS+yR$B?U^qN3}X8c6qV8D|B7~A3?Cmz0V_;M}}m6O4RRJe^H*ov|zFhn7+~AzLLzF%oR}()HW?Szy zQwsoKidEj#L}0PVFl-mEhf*4pm8Q3#iSO?b%)lqXtKiu*wv5SJKt4gv4VJOx>kQtg z7Ik=8QSr|SC#B6PS*A*ex>Y7gX3XMTgMU;hP~H=qNLtY9v=fm-sX5Dk1zSTaZ6yQa zS4BTZFx6HvZRFGA%DI+bLLa3RsO>Yb1&u;?El&e~&es1(q{{7&BBGRsx+6q6-g2U=En|29jFOJ7j`}0DsyTR9pYv2`!vAM-mabyg++VoRpEyEKVd?aC{}x0VG732KB(84R&HBL38Q|B~6Z1a>bCbX&LV_1~9! z9Kfwr_ZNb8{oc(ka5R^oiRF5lJPPYFVnAu3RlxS7Ch9d~AlmC|4qXHa^IXnurevo* zv~CtiXE@0ES#5M|d~fSyxQ$oiTLN1C^^eNuA00o5{B5Jkt}UfecLaZazcaaDZczNY H%Y**_W#?g& diff --git a/vignettes/EIRprevmatch_Fig_2.png b/vignettes/EIRprevmatch_Fig_2.png index 723c32d3513f61a1b00946ab1cb41bc3bb559a73..3d1b6ca990ca55c51c346429d58434522f3d113e 100644 GIT binary patch literal 9414 zcmeHtXIN89*EW`;$8x9&0s?{}(nUn1!=WhB6hxX7!2|&*0U=6A5DOhaL3$At5HN&L zLL`KsQjS#Vfg}V_iUf9~MhK91hv%H{y`Jy--XGte_t&$pJ-f`znwhosT5Hzav*WH> zU;5*q*g+m1o;`yvcCGxr2h6dDI%a~miK~{^O~E@4k2VhvSOdzVt<9qi zUQ>9WIG+3v$rO$Xk1bdR=4$gmxrN*#MLPvNaoQ;q=nf5(2MXOOhH68>Cnz)pngX6U zC=NU+P#h;knecXr~SJh&8XTnZEimf*k>JSbol9EF18 z;BXvHCnlt`6Re2o?ChkZXj4)^YHkf~13Nbgg+t-sC>+jo0S^ZUpAD-%QR(lL7*htpGVxMaAjX#<%2pITi305k$&Y@t0J9t(l-@!1o4i8B8yUZJT!? z5oxcs*3yiEmz@v*({B?f50PDeCh9p`)BxhX&WCPylD8o3cY8&e=vAss!Hh@GvErsw zHQ`BKZ1W`Qfsetd_p+x#G!+Elt&-5V=B*RjD70QvC+*!uswm=>EHA4g!IE+zyUWe$ z&1=tF^M&!BU9%#6bIO~kN%8Sdu`%&z9kaVM>G%p7AuQVTZGkK<%zNG_ot&Q)7CZ*^ z%8O|SE8azlA~K(D0mlxpY0|=z&#?UP*r#|erDh3Fa{-oM+6h257VmX010NYfF3mWB zFEEHyt3bF0Am+wuP6M9TeHADZA>Tr~0w6wmVksLPF+Map>h`=L<5PQu%;CxtL3J%- z@0ZstzPf8R(OLv6Gg_1wliO?fk@F`{5p05uXrWYPrZa1v{72>c1U6k47a~U>)AhGK zs~=p{&{Us&Lx=OJ8gN>sX_yMkGsA0Q3!RjAIb zFRM!V(G7pJpwy{3iD98XOTr?)*S}i-eLh`?)$+Ctm9+V)d3){G)x3(%M&#ye6OI(^ zbBD#A@`$qh^bp^nV;j!Yp1$ED>KPe~oI9)uzv^Myo#RSGa-d7+`PA(C9>dT_{c(8J zch?mAx9@min1(kvDrLDBHju1J`70*RgMDF`Y}t4lf7(%ZVxK0)p4570pG!EF&d&<} zNw6MYdQIO`?rKdHNsUG%-QEKeVb_KR2!}Brt8iOzDqW1F=e#JEhrYG>?D~Fqd@SP8 zO(`LkpHji--unLR$M1Ybr{=Rhd|9)n=8!e+vS$e~yII?VWnsfI)F28bIeddLiQ4)`mt<70KAY2i@%iyh zYieNC*7nH)ziexbqIy7h=8Vz5|dGMy|h}w{o1hC<+iJXnx&gl1;jFj#LBb3CjD4$gi?Vx z?uYg`EpRrh4f1hG)P5n&HFlTq??9qnsg`g4L4s^$Ms(j|L zh{tEV+6z-PYL+-T$t!T2wW4|eANLinzV-!@uwba=?%R55qXG*+1)1)gt(;*Xy&#%> zC3jTE`kp$z<>Ex+7Afn=+$FIF%8vSumXysdhn?Ara|O(?WkCCNXBE#o-bs+ z942QfgcGSZH?wK==Eqdy+w^C|xEt5lg8ZxxNg8&uqguz`*x0)O3ne8D=ZZDA8eJAy z9J1(5Rq67b9wgY~5?}ov;(PopZ*KQ>7pot6&W8ljRlnF9*sYEdRRV63%(RKrjDbF^ zl>VmK*3uI|_5=_jp3_eBgN}XIN?ok6^COv-tGKYfpPtBiDF~=wHQisGcoVw)yOq_K z$!)6ZptFT4wB}rJB7$=UQWQ^6UNc7YMmw&075CTJwG#QI<-@ybOHs zF7^C<4)J(J)3>GBBc+FGM~RSpJ@x2?w$?FCx!Punrcq>oS2(aLyK5;6$e-%DA`(@a zIDgu|j*}FVb-&Da6m@Stw5IFj#n5@rFL&v6|5nx&AB^{b5R(s6u-{NytMSPbZSOsLXV1X%M5pLi@D;k`3%J^b4_ zNrN5>7ULMJ)A}d%AHOAQO0~H92%mA{Kg9o|z|uc%Ei8_#9SPC&6`+a|FyJ(@+;29w zRldv%<=SHU8E|rWCtDS2;IBW(QKodJy}~;lL%i}#$Xf1?!F1BxpJUIiooyKg2ypjI zLfvbxTl3P+JrhP#=B0!WF;S4SMM(9i?bJJ>5X*K;>)^-Oynuqt30gj=s6RH`mpecGg2<&qlxAL;571Xs6m-5U~Kwh}>_WSDu zA-F4OSrcc4n*RjDh&6(-lKiCGBeMD)0kFlqd{L%iHUQRmL!o;Y7v_Dotp8`Ay8){O zAPNyCx{qs6Rb~ueL@V{5c7ysG!uD0_Fh?NAJV2}K5M#yaZdjfA3v|qfU~SwnC8JK3 zb4$4aLrr&S8RzRb{kP>#t>FXf8q??hJX{IJ zACROWS_X^z^8OLwxMS#UeXi3euK~su*js++YxZLSX8j6i9hj8QAJoC%=mt$s#+@aB6p7A zvSNt0fffA2_A|ueb!_%*Dz~uX3cflJ`s!uS@PyVMe5T%~3RJ5Xo{XIy2ZJ!tR)m*31ABkIY|g&p zHg{}#RI3^xRu<&r!Hf1?pr&%28<`1y);Pkh`>C>A0VrDXKuL*4<3q%O?ktTU)A;P^dvy{B3KNOG8c|cm+78+EjMNG9J!j9g0_*){OG_;4yg6|d}*}xUUQ@k

k_42)8JW~k&ZznSJ}9J_3H-SV%7r412td*rn=;2 zp_o+mf)#b6f~IJM2u-tl6h}Zhb@E2QdbnZV`vgM6DfY#NaQkaqrMmH9B6L4Nk;$C| zoJ8S;UPbO-N))&}rQ!=N)Q%w+=`;^7R2PD4z~EQd8A!T3RaLcTH8Rj(V~%8i^lC<) zIRZRd_3hkIpW+|`&M*6Q)vLQ%?MRs*E};kBVaVkN1RQWnQ78v`fI6c2=0F@F3I5G8 zo85PN0gO7YE>zqzd-2PxbR0F1K8B=!SI|>e02)RRC(i(_)5s-ZFIL}A%o9Qu+`^^6 z)f80ey{zr3;%_i_r$9AmuI-INbugxd)eTX9Y`9@mSZ_%G8;=c~M@OMk%W z4axfUgYj^q`|y{kY^?PeokO@VW>m()hiF1K&i`iFIwPVZcf~WKqr2cux9wn(laCyr z*?Sxqd=+YNkV^TXA<=vZCS-qz$$mplTaGFcL6GKGq@hpDDdbqV8rB1p!2CYP7axhk zZs^%$+NGv(6^%R&xhsz@HRbYgwJH5eP(Vy!Eqfi~sgTtk%f6xX^H_MjW|SYRJ=oOU zrq-Fp7i2Kka+O6-;=Ed1j5+2FOBS=W*Mv3^$DiF-0)&V5v!XP0Dd8=`_hth(MM^JW zHdpL+<3+yc9Ao*`hZekOb|qauwGZwd0zbYB@o2meUDJvL&HCy6hq6Xg)*IQ=-NK)cz+xwwb+<3ZmqG9ZG()tDCww^37MVA z#brK2Kvhqp!^)iHYXXn{Ty6ZaFu;|f#V5Q?M?3++(7)Jwgl1qT{7ub<+48Q|%-+vm zZa|m5)$xqRW3e00$9$p}LzoEAsBihvwDv}*>)TD`G4J~Wytjf?p*U0{{#ZbW46(KeB1BrIBkJz)_ zp4)#BzLqfU0f*zJb$%k=MeyI(eb;=8my=1Z{H!mJ%u4-~vQZc0iXO6gm}dr%JoBXe zl{yDgM`~)<0;IPCE8SAj>>h@^`b}#L@OU;+vXcrW1u-<9O zN!C>n0&uHs#5FfOX@Hh&(-SjNUX{~2wctfeM}HRu41HeLrQ=ZU<~2#(Po@v|UQV=UCna&{B#$CYAZ7iR8-bi332yc;-VxTjGv&L>MMtN3xHQW$B@#HpW^ zC-R_7Opsu{=Zg02mvYJNT~#qBbuV>k1{AT6)}Zg3>u4|7nKXLsyQEiofa+}_DwhSz z$hABVNIV$C8?CQHgizds1wsjeW7*j`EmB-Ejp%uxg>Jm3ZpJ?cb(I!81Ria%MjZK z9SkNJ$T{+}9-|Y+ZRArMK0)R!z8o2}GdOrOJX!R^F0K-P@`TJkKL^3h9`bO!u=!JD z@H0MBO=M+sbiwehd(_IHHROlRHI`?%S$XzA=vuX3a+;HxI{I4M#&wZG)5iY97Pn~G zXSVjDmWT&U?TH->l7=dCcJTQCXS871YBE47b}&s^Hm+$Y=qD_|;#-F_e1omiV-F+2q+o>iOCpZ#*xJn7{rgd*K^ z@`>%dGyCpW-i~^!Z&DNZe1uZ>!9+dlXjIO&mLldt?CLUQJv65O$h2;&zc>to2&GH9 z-ZzNFzDxDL+Wvz5FbO@1J=ant!rG!-_E|w}TuQVK=-9mEc!Sct+Iops{b{RYkth}U z7SXzP#ofuJ1=r^L%R<9BAWPlO`;K`2jZiRLy_5u1^iYZ-%)dIWayRVkd&BdW(K+X( zsv+orY8RcK*Dk7v5DE^{(w5{oL$1tI=O4Nxp~{Giv5YqZ42q7-Ovwj_xy}A}AFh<$ ztwlH}x55Y90G6h-9UH5^5qAr)klxkdvNU_o}h<`}({sKG0M;ls4UX zj?X}rTz|=`I;8P%kZRmQ8^?xYCU710kw3-qIpy)Fx1s(oB3@%fkK_W&4XZ_FI^Cb1v(37KYhM%lY!ZgeZh zPgjb*pCv_d+eVb~qtqx*@-O z>QUD;t$-7d6@U5yJT4t)5b$e(o$XjpwsVU4BP9omNAWl%$O>dy z2S$OKT!0&IeKz2%@}1CAH>SQUpb36-ktGK*o6nCl@fD1S4@>YxjgkjvK9kp+#ef^5 zEjl0fv&y{dsv6@g9mJhU-nRl85xddsU-jNk*LdrZBizX|J#84xA!vsR^>Q zG`?$fl?|8lTGjx?bs6ypjr-~zD$Jh)4?n>|FcoBy7VgbK;|8HLV~BM#Le z{J~9nM@xBJ#C~Xz?j1%7Q%MN{gC$}7@;bnR&}T8@rxDF7x(jwE9B_3>xcFPrF!+nU ziOFx*#-w@iBv+g3^ev^O%W`4-rJ~drKlpo=vEH|m-_nI#Dqq|k?QV!Abz&Bgq^sUy#IieQrb?ot@%c;WtR1)*MfN+xg^1df#Pw^KH^_>|4V8TwZ><4RA z>AeM2iDhn)k^x~ZMOs~Q=VU_qUY{G;EO7}Ble^#nfmg<_S(7h(b8jsHJK9*bR<&b4 z_5S8Pj~|A2xEq>JRiqmcA>|peUc)@_{{5d~mn){|EborFBTtU_u};APbLQdzt7@OX z58Yp%Ay!xr3jFLF@#uGHMq+?n5!*yfU0XigBOQ7E&mja-j-M?mA`fUcfJp{ElS zhUiI^84_8y8ja9!lo@kCtUDHHTT=6;+&foTgyZdC#Kw+f2O3g`)B858D^Ab_?C=g7 z5B^-fs!!j_hBETYB6OfnzSNLo*@2OjBX=8F!0>j=H12WpDaGXVIV6=&of;2YDHrT? zc%3H)R0xX1D9KRX%}JrysbcE|+kmjnWlOkSEfxh3J+oVmb6(Joa6S7kl=27&fDKfc zFi?X))CYu<@Ew|BE8ri8rV(m-Y{aJluekR#E^gK6UA%RZ*l-puWpS_PuooY;k}lzO zi=@;1LI#jMV+5|aJ@M6-IxQ?(K9Py{%7>6AYe{qU9zC2vPT-T1UaVvZ*UsBqPzVIa zxcCAW^7%hIM>@*j&QYCGa&sOw#>q1#>jLf9n7M8&`Cky3Oib1>L?)!reDAQs_-BV1 ziOw@zw7tVp#$!G|9a0?Y8tR#xnJk;@oS?YCp$P~m8!JCYv!_}F;eWMWvE8v> zY)j|V)W^ub?Yp;@?Xx^j+@qi^+$wo0zsyrf*Z%3h?KKE!P2T}DZ?d}Op+$;CjD}qjgk8G==PCa2y6>X(ticc+H3y*v6 z3ls2i@1Dd0x0XwhL4th3S9db`z1+V}HUd+o#mHYj2WRf5k8oU_r(4JwHNQGz(~L(- zrt}^9EpFR)G#q2U5XJ#l|Mh_3;?a&KDp1%?1JxDyK93J(r&~;J)Z$~Ys@`ATVKQHP zno>(2nf!mGy-maqYgJht;iGrQkiC+YcZNHEzgO3w7jS_Oh0wamH$T$0wANMrAT-0^ z4n%G3U=(|5D%>PS`$hk%(H181Y@wa{t|3}*eFX}&G}=+(Ux7>x3*P!+=fOZ(AE zt!{ouD!AhaUz*tRL*#V>g)jI{-$Rv!!0T!h?=KV)u{HJ6iBkh(5)CD1z#jwlL~{QH z@Mx&-kgCBQLnvQgKp}@?)v~WK(#`V_qi1}kwo5{2HeUsR~cz(T<=&w)qs;bW+tA8e@ zZ`PNaOEe>s$uWK_3gD-$6p5K}>?)N`B$WZa@5oT$V>)J@=q#5+~>*;BP zcym&!BFyId#=gHu??ULc?wwTX-1g6}5w#(Hx0Zo2Labg0m5%fw&7-%YUu^hQez#)h zJYk4W70l_NhDjQ9Z*qj{P4<-HQbM-89EjCsecLV-G|2C<3H?sX19IF)F-9Xqc3-ae zAW5S**?l9h+}EM-_&pJ<_cL~gY-EkHnaFKB<2AaEtp;787xmuF;Bt?R%&)bU*W5~U z0bmj_nH@U!bbl7RHZy{QNnWtPvac5?hAIley}|zAPYBL@b6u9CvGrw)NeQ#UtpKkB za!Qh-_RR6b+M2layc`X5s-V2==-@LgF|5}2+o5AUMzDXIB2-{~*o|{;QC5`B+=A?} zs%gT#sXD>f`-sx)yAetq|+Y1to*mmAparfUQOSCss4xjf|%oiWtP z;4Ni^tEFwAv{|W|`x0tHPJz*_b6gv$4lh0fY0&dE3NiaWc|~`Pv%ji%nWK3?UZ49v OlDVn1NyVQYkNykyHxBy% literal 9423 zcmd6NdpK0z+xH;nQz=P85mHGArZMlX@Avz>@9%lu=epkKkKc8@`&zU2tb46>ueI*=+3Vi>bMNTurUv{x zhj}0n2*2S~{hJU7D*%D8Y;duG5=)p(DtIAYH@3J8ULg<-2m}Vv(12)w=L8501IfBC zk-!9{phyD(`(5(;NYF?C6GkI}1pCtf27$r;6vH%N;6E5F0hRzJ3=9J%5)8vk(10X> z&0vr};)DbYDS?DZAc1El1_r?-XkZdx7*LD>6L^roatw)tVPY^$CMiLKlmJ%$E&bi% z&xJ%{f=x+G=4>_uQ~_3Ef+FVc>P#l{um-XjoDKKAtG4$c5P^o@KbB^{4{i|1QHY`b zMT-X+%bC2$sakmC%y6+~ms^c^R}g7K`I@>(@q3>U@q8aON5kY5Ce!?~5Q6o%@AR=~ zYG~H#&;hRR&1E@kd-ovt9(fJj$c8}HS;!YJ>msi2>lU}z6UZt2Kh7TL59Q2w9ivn) z5p&97pDSJx>opd-+Nk}*&yoe@dU2??rH@fX9}2y{Z`{qoYJV^&+TYsC2utXJhBEH2 zu;@D3?A@|h3;c`^J2>v7m5qLmODZlux>T40FJLLremF)QlI1W}hS2)E!sQI?_2ny`~L=IB(d`@g^ zzLk~mHdaw%NvB6*%!mMJO?pb-sxk8;EE7^N7cqdLs|YnNcW9(+vmHwtz^Jk1xBpt7 zp@fBcUP^s{pV}!|@2V!c2p_kny(@1QWHTEgDM#nl1Uk!Fl+ZV45`)z=C3M>OP547J z?P$l8?P#Bo3u~bgTNJuv5N^&ual%#*|8r}XA{k`%*;1#n*O#_2@Va};+iZHZ)SRxm zKA4p*neHbshoEnyr@%h5C!mokKj}n$sv-LJoi-UiSe(g(B6*xrk;~wkCgsxiin@kB z{q^n{V`uHx{2ElJD!lhn*Jr$>o$X9lhk>CS20z|7Qf2}JqMGF;KJV6PFZLj#T}(f6 zN=fF1fAYs$(;`oL>pZXP--%jd$Hu=pxHZrW7>ST&WxT=;+6wsPZ`b(Te9Is*ua*D- zI(YctmN!r6&-x7^)aL;1mL_ug!J_Cd441GI2yigRH*1u9WM*B%t2&pj>_R7UMaD7D zVzNoE-k|be^_5Y^BFWuW&$7Z#1zLwI z1ciircmTJi`#90e`}STGi+(wPUBB~uxm!D-wjAyDejMu!D(4~hJEMCC3veTXtuYtZ z+nt@$#x!cM+^q|?zJHWz#7ZFs1FgZT*T~yl%S>v?0Dd81OfVCi3mR>Q1L6f6$v8>U z*_C&Uk=TUQebV}%;zdOIx9_k^Yd{#GClHv4C~X-2kB9x_LDW46@0olA(ndR#}0nqG-GyJ z(W^(vTz9@)+jIPHRP)+JyA;;!F|H4=lKKE$QYq2T*-RPn7FrZ+J{3xv+4;dM8F8;K zd?D^MbZ{H4w;Qg>tvX3d6~iWTy@+%qhS>2=PXVkdz~q^yg3eFzSyslKr$T>)LcN)i z*&-oHEP0X$k?Ci6+{=5H3HukvoGvWO?v6tlrhc(>{}d5t1vj(hDte=HxD`{~n(--k zStzF$?>4k4KZ<^2gMdcm(Fzw|B58&vsWCS+8HpkXn3Xc)dQBhTiU+qa8_0Qy>!?~r ze!9urRjF*t(PdoF`JJ;FD4e=s#}hGx7rFgeX7&EB1ND0F!E{t+t$9gQPn!+4GM{)Y zpwgI}R8Np14d&o#(bZpnS*Sv<(6MOho8~pRATNE>{j2EhZ1{XBtDj5YJ3cZF`r5A} zm%W^a+}sdm+r-NDwOF4Gb1jDG;7rg{*>Ct5>~{5l=<`pKzsz1; z9?g8s1$M@NMy2ObyYcY@y^NoBx(Jx*RQ#ZMiD17j#cJe6qmo*Je-{^R$`>bc{vpDP!hr6*! z37NR{APz&fBXxD4@$`2?Xui+C^tK!YBtFi8jz#`oZ1NW}x-&WEO<4mASg?Pa>i=VL z0$NjI1$E`m!YIR=*`WJdc|qrRH4AvK$Kj+c=yc6nd&LER8q1tI&4oO9hwQ0KG1UtK z;y6QO|HHFRuw;9>MS><}n*z>(2KfvAxiKKnx(F$I5ptJ7ST?`X+*_CAqJKJ)`1tBm z?O5VKW;|aGDq2PnR4lbEt%aUSCq%{cm$LHyT0J?Jz70uxQlgdp6VIiGIXUtgp)oSmv|**B$qtQY)z(mQ(u@9{D2a0@tfF62iHP$s++F7UFhz^z3MY-T3n=od}O|N99zUv-68t zfX;vxyf;yrA{*DXy-W3XgLN@k)XD(94x9^=OdGL2>!BP$DB1(|K8G*jlTLi{H4!zK zXqlWR03pL?my4v*fAC>|8Z%qG1qISVRt0aEvl&E(PcJ{p9C3+H6lD)U2sH)JNaNFP z$`9R<^QDgyMTM@wyRh$yEC-4N#@SVBfU7W#*^|UyYJz{=LY0A>_XX)e7%%>HiiCq!f#O3PXbKNr2!5HMlojTv> z(`4!TQai+{4KD#APItY-}=Grsy+jknO=shJS<$@@uMulreZHSApH_ zc;`?1-2FTFsD*m8Hy7*?m7!%Lh#Ej{j2kN%DaQ;lf0~V&*X9=oje&?YCO0(rE;t1X zQ2Q8b8%=TXu&EvzP2YT#i;-7FTj&^wxyq*>5Wp$b&@h%HjPouI*&0S{(PPa z(+uhA)s|hlGp4#0=qHv!q00g+gPJ3*h$^ZAiY-ye6%p5=i>Ox6qse~$%tW!Ps(cTe zce?e$=FSkw1Fa#HcG#anNQx;|x-V2l8q~Dl_aZr&vPJ^It;QBZjdpt;_6m@rYPQeA zZ?mOj7PL>_AuA<6az|L+t_M2Fx%6&~5NCHJEQcPmneKz^z|iN24@j{aY)iDgPP+b< zmR%F4meCrZ8BT8R>2)zZCar?JaNeB$c29nwAeZJ84TgC0(%mBmHyU(jM~46nZ(<=f z;l0M^?vl4PZdsYCta6{;&(xj%a*o!=wuD?Tt~Tr_#;!j;)L%d7MIXhcH(7r=vGNJa zTg=kB)6&lfJ0zN|E>KRbp(c0ocJ^tXS$g8jF3_?4Daqy-3Y-0{%8(k%G0Rfi6xvng zU1FISjFMMg5+`ROEd>o`7s7N}?nF6sz;1DrkGYoIcTqN?&6guq<{tDdA;*rh`s{jk zJIIt=puRs~p?T_j_zN3@>q8eND^$D5qg&3oml7&KY-K#;(wg;BDGTwveR{rtgm6&nb_nJps_l&W1vqn~iz$ZftbU-8O-r*-M9|cM zZtc{Taxt4&q$L3-w{I!PEPOjkO2l%R?WY(G`%yH_pC&Nx>w{x<8TAH*tfRx3_gC4L zhO?G4N9H8FOio{>wS7c%?U{h7_USN4 zK+b#Tfa(tR_Z?*9{c-QsDRK?sSHGDK!zdR=8!f@1A2-+1jW@GV@Cw7}HBy(imbIm% zvzg36{mpOWtxtq%X-`fmT-g~}sDjroth&)&(?E!-i7}&j(JuD3D;AwzQxoe+`gh``{dbeY!YQBs$cReR<4QaV31nT0rg`&nAFyFeRP zZ(}YBnjg{45!%v*t2M}#R@8+!KLU!?w?pX!K@+K;pTikpPvmd;KF1ZUUC_86yW2|v z?Dinn3FbtU|3$5Hl_{lNfdahUWE)nT(74E3&CMzlJ}e&*$9Co-EwXKd#=c-$OLzt6 zc8Qcea|MyIl9VMX-`07zNOvi`Nh@_Pdsm6wORn~vBw}&0(p~oi+Iz^Vzo0Xy#E%Ea!x<*%V24+CVM^GS z{bRXwH_m(IDeZZ0v>r@6M#dsdu-2OiKN{!HBq3PGy@4XNA!!wo&sa*HX3r&z-HjN=AyLVdfY@aLIBX zMY(2?`eE!~zolw7T&J=_Ar-4n=Cm8cZ&h=3ll3?4Pyu0@r_B*%elu`&k9OjKvr`q| zuUb_^IL}{1 zVX(bd^(>znlX)Y_-?EHB$HpqL!kwYd%-_2uRI4X^WGlho3ya)Wr7J^5lRTF9M)ymu zEHoIun^BoY)y}uYG_qcEQ^o%{RIwJDr6PPSJI2@G4e+eN*QGNPHUF_U(D6xPT7e%q z;#BWk^lJVa3n3rEz7d7uFMDIp+P|nBtPEBasG?F2hMx#+ZndXPw^b*KcI-?qeu_F_ zmsj-Q!D)F-gcaZLq$%&w2imzTwh>cl>TjDwhh43{EuI zNbjJeRookVC(q)`fsm&v+m6%NQFQ2DlMnP0{#eQz(Yn~+3oRK?6k#F@RlQ;|;1T0* zEE^|Mj9c}57gsgpkChudN)A3bkV)dsNV7Stna(|zgWd`W9X zp};+|L3YuAO0mNGLDbC(N=#?dlnS2OC53ek!WF1@c~@Y)1BPSk3UN0bocP=;N`4Xi zfU#{3^SO6Hyc&@GR0+zHd)(lAqGN*s4rcarC+lq;ReF&Ajs}rHG}d7y5xDq{`_QV2 zij6i7lS;Vy2I=L?w@L(Wzsz!#Zk>DeA5puW>mtf<#Unwn>%(M%cUjcQMbr%xqvBXL z7p1Jv`u=;M*}!>WNKMK8$~WU`))4CEZQBP{%WdvWBSFKq^O8-QSJq1x5(|(E<&^on z<S>eNmFxDwgyStM78^-XO%q_f&0g#w%`T2}VL23Z*FG;l^aH12Ph z%(EC$F!o-`wg^zZ_k&=~Cg%IJ**7+s$}xy+bVNU>Jb7>ct1{~;Ouigcjygd|`ZVYD%m0W;cV_iKAT<+=s77=%^FLfw)CLG!BFb zDqN=>jMq?NT)lC_&nm{zh}!K~2;_eNT|%^bq)h74PF>C<{RXMa%6vq`jDIDy{)OXA zdJ|mjlW$Eoey2~gb$u=B*&P{H@q$yoo~>lPv+B9tkB?AcJfT2$Za2bD{_=*|98W6I zKkBcVh1J^%!pUnl=e*m@j3qL~P0_CAuxcj0uD-WSf3FiN(!hy!%BeYH{Z@!@x`7{a z|E2R0&HNhD+pdWs2ftdl4tDGNZ!Zj$2FBkcuMNUa7RB7=Ne`1U4l-+85a}Sx;XJ=5 zo@h^DO->RiA@Uqy$IH1AKZ_m=J_0-9Sw}14d3{1ap=9|z;2Mb=zjEo4)_~Y0t9OHi z`ImPFbITJzZmK)K+HJLN)(a!Y+g>J+%Q=G} zwmJN&#YGzpU9ZvpNb~4!@y-A7sqDpA7#sD~*YeYPh^fhh5?orkJL<0Ld;_*}A6dc3 zF*Y;@Xi`iNd82!6kh=GbJtDv6hn7mI^)`BCkc5PvJ>A~z*wAfiTC3XkrVOC%*u)ti zvbZX~`isKsy=r>2OBh(1O*-)Al}Ep_ph@|vT1U}MoUd)}h2v8Lj*_pH;ItzF{8-v6 zo*pbBP6@}oWz>?I6}>?kt=KP`8giRiEIwx0Uj$c=kvIYm>>~D~tI+}!)|JrB^%Zqs z>P~H8|w06YP?yc}<$M%>i5h zIhG&ql=EJ!QswaN<8tFc$ZMvbU1<_-Ggw|3d?jBX88vpQ`lJbk<+;i&ybq(&eJ6iJ zbso5GN18a-mSWXn%bxqPCnh`neHF@$pOA0$0jaaP_f@d{?cKK-k9v(R1l*;;4aCbz zjA#V4+a{HH$<;I2th;J~F_om^8wgdycEUZK*22=3{Wmn>aL`ib_eaZ{3=fE^#_ToUXBW&Sz`tgS#$mOsvp74{ML16);T0fBj%Z50G7LyAVxF#728h zYRTkTGQ+orcSzB;9${ZoMqg1rX94Q+EWdsxiA_(6DDi*r zaG(GeR;E^I+2`SX*-hCv^o-5s+QZbcq#{$VX|j9PoE2PsK-r~zJ@gqC?W$|gjy^oE z#5|JR_Tu#5r9d5ev(LuKZL{=#vJzDUE23v)7t?u?*SyabwPUCf_NzqtOvpCxA^2S@ z8s0zM0C(ABLP|p}wwiJ#`J6h3n@DF{Dv9RXz5>K-!m=*#+`|;%ma>alPt`MIh6oqQ z)!Rx+n3wSpVFl{tr4@*jo+NPIlR>;wyT0B*8uI9Y%+33vjK)-p_hq<5pQt`nho+F` zyY`56(}LY=v4O?*h|nV4AWIni^iGyc5scUwrB;fo7RIK$OipNcL|OZJ6p?XN?f^ILYZd# z&p^SSqsNCqvQ~cjcjRaa`hyKxa}@({A$k7h+)9CtUV-0ag1e=aFbb^c=_aTT)njhV zhG!^D0fZIP_>JRT04Dv>j zq%vn_Ol|YuH0a|N;PBQeC3_$31Q@s2w{`AX6(AVb^&EMC-3}31Zjh9YTfZ~zRMHx( zY1ldJlR_L7cQum^cY9BFz)N-$za?lZN0b-*3r}|47_otRd*b)}d8&YOIq-ks#slD= zC9$qfqe7Afe|X3MMU`ke?_M8SUfV{pCTnEtIq{J)dr|Dzk^v{$uA=ad^jmOrsj zGs`3W>hCD1{#s!3enInA9*`Kl1~Ru?E!MW?3c=5jqoGIs5@rUWV9s{VyD`1&)qGBT4i6!F4Y zC&WL6pWa`<;wtIEN>+@QcD@oHrla*DBdxmyY~eJL{0wX%ahYU*juQ6E`WEKNDrxa+ zYov5wNKtGHZN^p)T|=wC9>m-Ct^CxwxwP~B6WWYQ_}zA_I3ns71j3g2`&$5~^x7z4 zsuN!+BkTd@8o%)8K<^S-JIC%~(xdXIr}$5Ra?Y`5l2k+6u)EE@gUpTRNSjp(U7d25 z<7Ino)Pc`SP>lELR{Isk;bJg+(A~dJr56<|rT$-_fqmb~MYpO3t+SVF0)v|3&MjKvar*+}quW}VT1_rUd ztjS$YiQVouiYSlzwfGL}te+x3QJmh`Aw9YKZG7c%wN4tYxxlS_4`l#9S#Blp&05$*nP72pFkQbo zYpQL?c*y!aG9qNG|EOHW?rQh<@|2(ov%U4Q^#n_@-$&uYFK~BXemRlOMfZaHu_8ma zqh>GqbtI*c=G33}C!uV_>TJ2Tqhx_*V1c;&idHbUHQY%)b7$<*u>O#BDZSU8R#h`= zDARGjeAPHerM>oQ+mR>FqI^U z^~gPvJvKtPv2Kp*rK@lD6_s*vx$Jj!t^=}BzrI%=(n|0VD9rMyA8Ec8D2a|2{7yo1 zh0vN=SwLlC-yOA%mn!t$)oQKPdDV(wu6}38$4RCWgcP~R5#Z3&-{Gh{Kf*(rQ zE6pSCwq2sRsO{TYo)7C)e00ZfI2d=s;xQ-VAUTcxn!}HRvoyMLACAK;ifs7RYP$kw_(ZojE2SZHB Zl;f!nuLygx{{Aq@@Up3Xsh-P|{{`hj6zc#0 diff --git a/vignettes/MDA.Rmd b/vignettes/MDA.Rmd index 1f9201c2..1993c60e 100644 --- a/vignettes/MDA.Rmd +++ b/vignettes/MDA.Rmd @@ -17,14 +17,13 @@ knitr::opts_chunk$set( ```{r setup} # Load the requisite packages: library(malariasimulation) - +# Set colour palette: +cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") ``` -## Introduction - Malaria chemoprevention encompasses a suite of strategies for reducing malaria morbidity, mortality, and transmission through the treatment of at-risk populations with antimalarial drugs. Three such strategies are mass drug administration (MDA), seasonal malaria chemoprevention (SMC), and perennial malaria chemoprevention (PMC). MDA attempts to simultaneously treat an entire population, irrespective of their infection risk or status. SMC targets children aged 3-59 months with a course of an antimalarial through the peak malaria transmission season. PMC is designed for settings with perennially high transmission and seeks to administer a full antimalarial course at defined intervals irrespective of age or disease status. -`malariasimulation` enables users to simulate the effects of chemoprevention strategies on malaria transmission, and provides the flexibility to design and simulate a range of MDA/SMC/PMC campaigns for a suite of antimalarial drugs. Specifically, users are able to load or specify parameters describing both the characteristics of the antimalarial(s) (e.g. drug efficacy, prophylactic profile) and their distribution (e.g. coverage, distribution timing, and the section of the population to treat). This vignette provides simple, illustrative demonstrations of how MDA and SMC campaigns can be set-up and simulated using `malariasimulation`. The functionality to simulate PMC campaigns is also built into `malariasimulation` via the `set_pmc() function`, but we do not demonstrate the use of PMC in this vignette (for further information on their use, see https://mrc-ide.github.io/malariasimulation/reference/set_pmc.html). +`malariasimulation` enables users to simulate the effects of chemoprevention strategies on malaria transmission, and provides the flexibility to design and simulate a range of MDA/SMC/PMC campaigns for a suite of antimalarial drugs. Specifically, users are able to load or specify parameters describing both the characteristics of the antimalarial(s) (e.g. drug efficacy, prophylactic profile) and their distribution (e.g. coverage, distribution timing, and the section of the population to treat). This vignette provides simple, illustrative demonstrations of how MDA and SMC campaigns can be set-up and simulated using `malariasimulation`. The functionality to simulate PMC campaigns is also built into `malariasimulation` via the `set_pmc()` function, but we do not demonstrate the use of PMC in this vignette (for further information on their use, see [set_pmc](https://mrc-ide.github.io/malariasimulation/reference/set_pmc.html)). ## Mass Drug Administration @@ -32,10 +31,9 @@ To illustrate how MDA can be simulated using `malariasimulation`, we will implem ### Parameterisation -The first step is to generate the list of `malariasimulation` parameters using the `get_parameters()` function. Here, we'll use the default `malariasimulation` parameter set (run `?get_parameters()` to view), but specify the seasonality parameters to simulate a highly seasonal, unimodal rainfall pattern (illustrated in the plot of total adult female mosquito population dynamics below). To do this, we set `model_seasonality` to TRUE within `get_parameters()`, and then tune the rainfall pattern using the `g0`, `g`, and `h` parameters (which represent fourier coefficients). In the `malariasimulation` model, rainfall governs the time-varying mosquito population carrying capacity through density-dependent regulation of the larval population and, therefore, annual patterns of malaria transmission. Next, we use the `set_equilibrium()` function to tune the initial human and mosquito populations to those required to observe the specified initial EIR. +The first step is to generate the list of `malariasimulation` parameters using the `get_parameters()` function. Here, we'll use the default `malariasimulation` parameter set (run `?get_parameters()` to view), but specify the seasonality parameters to simulate a highly seasonal, unimodal rainfall pattern (illustrated in the plot of total adult female mosquito population dynamics below). To do this, we set `model_seasonality` to `TRUE` within `get_parameters()`, and then tune the rainfall pattern using the `g0`, `g`, and `h` parameters (which represent fourier coefficients). In the `malariasimulation` model, rainfall governs the time-varying mosquito population carrying capacity through density-dependent regulation of the larval population and, therefore, annual patterns of malaria transmission. Next, we use the `set_equilibrium()` function to tune the initial human and mosquito populations to those required to observe the specified initial EIR. ```{r} - # Establish the length of time, in daily time steps, over which to simulate: year <- 365; years <- 3 sim_length <- years * year @@ -59,17 +57,15 @@ simparams <- get_parameters( # Use the set_equilibrium() function to update the individual-based model parameters to those # required to match the specified initial EIR (starting_EIR) at equilibrium: simparams <- set_equilibrium(simparams, starting_EIR) - ``` ### Interventions -Having established a base set of parameters (`simparams`), the next step is to add the parameters specifying the MDA campaign. We first use the `set_drugs()` function to update the parameter list (`simparams`) with the parameter values for the drug(s) we wish to simulate, in this case using the in-built parameter set for SP-AQ. Note that the `malariasimulation` package also contains in-built parameter sets for dihydroartemisinin-piperaquine (DHA_PQP_params) and artemether lumefantrine (AL_params), and users can also define their own drug parameters. +Having established a base set of parameters (`simparams`), the next step is to add the parameters specifying the MDA campaign. We first use the `set_drugs()` function to update the parameter list (`simparams`) with the parameter values for the drug(s) we wish to simulate, in this case using the in-built parameter set for SP-AQ (`SP_AQ_params`). Note that the `malariasimulation` package also contains in-built parameter sets for dihydroartemisinin-piperaquine (`DHA_PQP_params`) and artemether lumefantrine (`AL_params`), and users can also define their own drug parameters. We then define the time steps on which we want the MDA to occur (stored here in the vector `mda_events` for legibility), and use the `set_mda()` function to update the parameter list with our MDA campaign parameters. `set_mda()` takes as its first two arguments the base parameter list and the time steps on which to schedule MDA events. This function also requires the user to specify the proportion of the population they want to treat using `coverages`, as well as the age-range of the population we want to treat using `min_ages` and `max_ages`, *for each timestep on which MDA is scheduled*. Note that this enables users to specify individual events to have different drug, coverage, and human-target properties. The `drug` argument refers to the index of the drug we want to distribute in the MDA in the list of parameters (in this demonstration we have only added a single drug, SP-AQ, using `set_drugs()`, but we could have specified additional drugs). ```{r} - # Make a copy of the base simulation parameters to which we can add the MDA campaign parameters: mdaparams <- simparams @@ -88,7 +84,6 @@ mdaparams <- set_mda(mdaparams, coverages = rep(.8, 2), min_ages = rep(0, length(mda_events)), max_ages = rep(200 * 365, length(mda_events))) - ``` Having generated a base, no-intervention parameter set (`simparams`) and a version updated to define an MDA campaign (`mdaparams`), we can now use the `run_simulation()` function to run simulations for scenarios without interventions and with our MDA campaign. @@ -107,45 +102,40 @@ mda_output <- run_simulation(sim_length, mdaparams) The `run_simulation()` function returns a dataframe containing time series for a range of variables, including the number of human individuals in each infectious state, and the number of people and detected cases in children aged 2-10. The plots below illustrate how the effect of an MDA campaign on the malaria transmission dynamics can be visualised. The first presents the distribution of people among the infectious states in the MDA simulation. The second compares the prevalence of malaria in children aged 2-10 years old (*Pf*PR~2-10~) between the no-intervention and MDA scenarios simulated. -```{r, fig.width=7.2, fig.height=4, fig.fullwidth=TRUE} - +```{r, fig.align = 'center', out.width='100%'} # Store the state names, and labels and colours with which to plot them: states <- c("S_Count", "D_count", "Tr_count", "A_count", "U_count") state_labels <- c("S", "D", "Tr", "A", "U") -# Define a colour palette for plotting: -plot_cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") - # Open a new plotting window: plot.new(); par(mar = c(4, 4, 1, 1), new = TRUE) # Plot the time series plot(x = mda_output$timestep, y = mda_output$S_count, - type = "l", col = plot_cols[1], lwd = 2, - ylim = c(0, 850), ylab = "Individuals", xlab = "Time (days)", + type = "l", col = cols[1], lwd = 2, + ylim = c(0, 950), ylab = "Individuals", xlab = "Time (days)", xaxs = "i", yaxs = "i", cex = 0.8) # Overlay the time-series for other states for(i in 1:(length(states)-1)) { - lines(mda_output[,states[i+1]], col = plot_cols[i+1], lwd = 2) + lines(mda_output[,states[i+1]], col = cols[i+1], lwd = 2) } # Add vlines to show when SP-AQ was administered: abline(v = mda_events, lty = "dashed", lwd = 1.5) +text(x = mda_events+10, y = 900, labels = "MDA int.", adj = 0, cex = 0.8) # Add gridlines: -grid(lty = 1, col = "darkgrey", nx = NULL, ny = NULL, lwd = 0.5); box() +grid(lty = 2, col = "grey80", nx = NULL, ny = NULL, lwd = 0.5); box() # Add a legend: -legend(x = 20, y = 840, - legend = c(state_labels, "MDA"), - col = c(plot_cols[1:5], "black"), lty = c(rep(1, 5), 2), - lwd = 1, cex = 0.8, box.col = "white") - +legend("topleft", + legend = c(state_labels), + col = c(cols[1:5]), lty = c(rep(1, 5)), + lwd = 1, cex = 0.8, box.col = "white", ncol = 2, x.intersp = 0.5) ``` -```{r, fig.width = 7.2, fig.height = 4, fig.fullwidth = TRUE} - +```{r, fig.align = 'center', out.width='100%'} # Open a new plotting window and add a grid: plot.new(); par(mar = c(4, 4, 1, 1), new = TRUE) @@ -155,25 +145,24 @@ plot(x = mda_output$timestep, xlab = "Time (days)", ylab = expression(paste(italic(Pf),"PR"[2-10])), cex = 0.8, ylim = c(0, 1), type = "l", lwd = 2, xaxs = "i", yaxs = "i", - col = plot_cols[3]) + col = cols[3]) # Add the dynamics for no-intervention simulation lines(x = noint_output$timestep, y = noint_output$n_detect_730_3650/noint_output$n_730_3650, - col = plot_cols[4]) + col = cols[4]) # Add vlines to indicate when SP-AQ were administered: abline(v = mda_events, lty = "dashed", lwd = 1) +text(x = mda_events+10, y = 0.95, labels = "MDA int.", adj = 0, cex = 0.8) # Add gridlines: -grid(lty = 1, col = "darkgrey", nx = NULL, ny = NULL, lwd = 0.5); box() +grid(lty = 2, col = "grey80", nx = NULL, ny = NULL, lwd = 0.5); box() # Add a legend: -legend(x = 20, y = 0.99, - legend = c("MDA", "No-Int", "MDA Day"), - col= c(plot_cols[3:4], "black"), box.col = "white", - lwd = 1, lty = c(1, 1, 2), cex = 0.8) - +legend(x = 20, y = 0.99, legend = c("MDA", "No-Int"), + col= c(cols[3:4]), box.col = "white", + lwd = 1, lty = c(1, 1), cex = 0.8) ``` ## Seasonal Malaria Chemoprevention @@ -184,8 +173,7 @@ To demonstrate how to simulate SMC in `malariasimulation` , in the following sec While the first step would typically be to establish the base set of parameters, we can use those stored earlier in `simparams`. We first store a copy of these base parameters and then use `set_drugs()` to store the preset parameters for SP-AQ in the parameter list. As SMC is conducted during the peak malaria season, we need to use the `peak_season_offset()` function to determine when the peak malaria season occurs given our specified seasonal profile. This function reads in the parameter list, uses `g0`, `g`, `h`, and `rainfall_floor` to generate the rainfall profile for a single year, and returns the day on which the maximum rainfall value occurs. We can then take this calculated seasonal peak and time SMC events around it. Here, we've specified four monthly drug administration days per year starting two months before the seasonal peak. To illustrate this, we can plot the total adult mosquito population size through time which, in the absence of interventions targeting mosquitoes, will closely matches the rainfall pattern, and overlay both the annual seasonal peak and planned SMC events. Once we're happy with our SMC campaign, we use the `set_smc()` function to update the parameter list with our `drug`, `timesteps`, `coverages` and target age group (`min_ages` and `max_ages`). -```{r, fig.width=7.2, fig.height=4, fig.fullwidth=TRUE} - +```{r, fig.align = 'center', out.width='100%'} # Copy the original simulation parameters smcparams <- simparams @@ -214,25 +202,24 @@ options(scipen = 666) # Open a new plotting window,set the margins and plot the total adult female mosquito population # through time: plot.new(); par(new = TRUE, mar = c(4, 4, 1, 1)) -plot(x = noint_output$timestep, y = noint_output$mosq_total, +plot(x = noint_output$timestep, noint_output$mosq_total, xlab = "Time (days)", ylab = "Adult Female Mosquitos", ylim = c(0, max(noint_output$mosq_total)*1.1), type = "l", lwd = 2, cex = 0.8, xaxs = "i", yaxs = "i", - col = plot_cols[3]) + col = cols[3]) # Add gridlines -grid(lty = 1, col = "darkgrey", nx = 11, ny = NULL, lwd = 0.5); box() +grid(lty = 2, col = "grey80", nx = 11, ny = NULL, lwd = 0.5); box() # Overlay the SMC days and the calculated seasonal peak abline(v = smc_days, lty = "dashed", lwd = 2) -abline(v = c(0, 1, 2) * 365 + peak, lty = 2, lwd = 2, col = plot_cols[4]) +abline(v = c(0, 1, 2) * 365 + peak, lty = 2, lwd = 2, col = cols[4]) # Add a legend: -legend(legend = c(expression("M"["Tot"]), "MDA", "Peak"), - #x = (sim_length * 0.83), y = 61000, - x = (sim_length * 0.01), y = max(noint_output$mosq_total)*1.05, - col= c(plot_cols[3], "black", plot_cols[4]), box.col = "white", +legend("topleft", + legend = c(expression("M"["Tot"]), "SMC", "Peak"), + col= c(cols[3], "black", cols[4]), box.col = "white", lty = c(1, 2, 2), lwd = 2, cex = 0.9) # Update the SMC parameters list: @@ -244,7 +231,6 @@ smcparams <- set_smc( min_ages = rep(3 * 30, length(smc_days)), max_ages = rep(59 * 30, length(smc_days)) ) - ``` ### Simulations @@ -254,45 +240,42 @@ Having generated our SMC parameter list, we can run the simulation using the `ru ```{r} # Run the SMC simulation smc_output <- run_simulation(sim_length, smcparams) - ``` ### Visualisation We can now plot the simulation output to visualise the effect of our SMC campaign on malaria transmission dynamics, again focusing on the distribution of people in each of the infectious states and on malaria prevalence in children aged 2-10 (*Pf*PR~2-10~). -```{r, fig.width=7.2, fig.height=4, fig.fullwidth=TRUE} - +```{r, fig.align = 'center', out.width='100%'} # Open a new plotting window and add a grid: plot.new(); par(new = TRUE, mar = c(4, 4, 1, 1)) # Plot the time series of human infectious states through time under the SMC campaign plot(x = smc_output$timestep, y = smc_output$S_count, - type = "l", col = plot_cols[1], lwd = 2, - ylim = c(0, 850), ylab = "Individuals", xlab = "Time (days)", + type = "l", col = cols[1], lwd = 2, + ylim = c(0, 950), ylab = "Individuals", xlab = "Time (days)", xaxs = "i", yaxs = "i", cex = 0.8) # Overlay the time-series for other human infection states for(i in 1:(length(states)-1)) { - lines(smc_output[,states[i+1]], col = plot_cols[i+1], lwd = 2) + lines(smc_output[,states[i+1]], col = cols[i+1], lwd = 2) } # Add vlines to indicate when SMC drugs were administered: abline(v = smc_days, lty = "dashed", lwd = 1) +text(x = smc_days[c(4,8)]+10, y = 900, labels = "SMC\nint.", adj = 0, cex = 0.8) # Add gridlines: -grid(lty = 1, col = "darkgrey", nx = NULL, ny = NULL, lwd = 0.5) +grid(lty = 2, col = "grey80", nx = NULL, ny = NULL, lwd = 0.5) # Add a legend: -legend(x = 20, y = 840, - legend = c(state_labels, "SMC"), - col = c(plot_cols[1:5], "black"), lty = c(rep(1, 5), 2), - box.col = "white", lwd = 2, cex = 0.9) - +legend("topleft", + legend = c(state_labels), + col = c(cols[1:5]), lty = c(rep(1, 5)), + box.col = "white", lwd = 2, cex = 0.8, ncol = 2, x.intersp = 0.5) ``` -```{r, fig.width=7.2, fig.height=4, fig.fullwidth=TRUE} - +```{r, fig.align = 'center', out.width='100%'} # Open a new plotting window and add a grid: plot.new(); par(new = TRUE, mar = c(4, 4, 1, 1)) @@ -301,23 +284,23 @@ plot(x = smc_output$timestep, y = smc_output$n_detect_730_3650/smc_output$n_730_ xlab = "Time (days)", ylab = expression(paste(italic(Pf),"PR"[2-10])), cex = 0.8, ylim = c(0, 1), type = "l", lwd = 2, xaxs = "i", yaxs = "i", - col = plot_cols[3]) + col = cols[3]) # Add the dynamics for no-intervention simulation lines(x = noint_output$timestep, y = noint_output$n_detect_730_3650/noint_output$n_730_3650, - col = plot_cols[4]) + col = cols[4]) # Add lines to indicate SMC events: abline(v = smc_days, lty = "dashed", lwd = 1) +text(x = smc_days[c(4,8)]+10, y = 0.95, labels = "SMC\nint.", adj = 0, cex = 0.8) # Add gridlines: -grid(lty = 1, col = "darkgrey", nx = 11, ny = 10, lwd = 0.5) +grid(lty = 2, col = "grey80", nx = 11, ny = 10, lwd = 0.5) # Add a legend: -legend(x = 20, y = 0.99, - legend = c("SMC", "No-Int", "SMC Day"), - col= c(plot_cols[3:4], "black"), box.col = "white", - lwd = 1, lty = c(1, 1, 2), cex = 0.8) - +legend("topleft", + legend = c("SMC", "No-Int"), + col= c(cols[3:4]), box.col = "white", + lwd = 1, lty = c(1, 1), cex = 0.8) ``` \ No newline at end of file diff --git a/vignettes/Metapopulation.Rmd b/vignettes/Metapopulation.Rmd index 31692ad1..e249591f 100644 --- a/vignettes/Metapopulation.Rmd +++ b/vignettes/Metapopulation.Rmd @@ -15,16 +15,21 @@ knitr::opts_chunk$set( ``` ```{r setup} +# Load the requisite packages: library(malariasimulation) library(malariaEquilibrium) +# Set colour palette: +cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") ``` -# Parameterisation - The metapopulation model runs the individual-based model for multiple parameterized units (countries, regions, admins, etc.) simultaneously. The inputted mixing matrix allows for the transmission of one unit to affect the transmission of another unit. 'Mixing' in the model occurs through the variables `foim_m` and `EIR`. Here we will set up a case study of three distinct units and compare output with various transmission mixing patterns. +## Run metapopulation simulation + +### Parameterisation + ```{r} # set variables year <- 365 @@ -51,10 +56,9 @@ ms_parameterize <- function(x){ # index of EIR # creating a list of three parameter lists paramslist <- lapply(seq(1, length(EIR_vector), 1), ms_parameterize) - ``` -# Modelling +### Simulation Our parameters for the three distinct units are stored in the object `paramslist`. Next we will run the metapopulation model with these parameters. We will plug in three mixing matrices - A) isolated, B) semi-mixed, C) perfectly mixed. @@ -105,16 +109,13 @@ output$prev2to10 = output$p_detect_730_3650 / output$n_730_3650 output$year = ceiling(output$timestep / 365) output$mix = factor(output$mix, levels = c('isolated', 'semi-mixed', 'perfectly-mixed')) output <- aggregate(prev2to10 ~ mix + EIR + year, data = output, FUN = mean) - ``` -Now let's visualize the results of mixing on PfPR2-10: - -```{r} +### Visualisation -colorBlindBlack8 <- c("#000000", "#E69F00", "#56B4E9", "#009E73", - "#F0E442", "#0072B2", "#D55E00", "#CC79A7") +Now let's visualize the results of mixing on PfPR2-10: +```{r, fig.align = 'center', out.width='100%', fig.asp = 0.4} Panel_spec <- rbind(c(0,0.37,0,1), c(0.37,0.635,0,1), c(0.635,0.9,0,1), @@ -136,20 +137,28 @@ Plot_Mixing <- function(output){ for(i in 1:3){ par(fig=Panel_spec[i,], cex = 0.8, mai = Margin_spec[i,], new = New_vec[i]) with(subset(output,output$mix == Mix_vec[i] & output$EIR == EIR_vec[1]),{ - plot(x = year, y = prev2to10, type = "l", col = colorBlindBlack8[1], ylim = c(0,0.36), yaxt = "n", xaxs = "i", yaxs = "i", ylab = Ylab_vec[i], xlab = Xlab_vec[i]) + plot(x = year, y = prev2to10, type = "l", col = cols[1], lwd = 2, + ylim = c(0,0.36), yaxt = "n", + xaxs = "i", yaxs = "i", + ylab = Ylab_vec[i], xlab = Xlab_vec[i]) + abline(h = seq(0.05,0.25, by = 0.05), lty = 2, col = "grey80", lwd = 0.5) + sapply(2:4, function(x){segments(x0 = x, x1 = x, y0 = 0, y1 = 0.3, + lty = 2, col = "grey80",lwd = 0.5)}) + # grid(lty = 2, col = "grey80", lwd = 0.5) if(i ==1){axis(side = 2, at = seq(0,0.4,by=0.1))} - title(gsub("(^[[:alpha:]])", "\\U\\1", Mix_vec[i], perl=TRUE), line = -1.5) - abline(h = 0.325) + title(gsub("(^[[:alpha:]])", "\\U\\1", Mix_vec[i], perl=TRUE), line = -1.4, cex.main = 0.9) + abline(h = 0.3) }) for(j in 2:3){ - with(subset(output,output$mix == Mix_vec[i] & output$EIR == EIR_vec[j]), points(x = year, y = prev2to10, type = "l", col = colorBlindBlack8[j])) + with(subset(output,output$mix == Mix_vec[i] & output$EIR == EIR_vec[j]), + points(x = year, y = prev2to10, type = "l", col = cols[j], lwd = 2)) } } par(fig=c(0.9,1,0,1), cex = 0.8, new = T, xpd = T, mai = c(0,0,0,0)) - legend("left", legend = EIR_vec, col = colorBlindBlack8[1:3], bty = "n", lty = 1, title = "EIR") + legend("left", legend = EIR_vec, col = cols[1:3], lwd = 2, + bty = "n", lty = 1, title = "EIR", y.intersp = 2) } Plot_Mixing(output) - ``` diff --git a/vignettes/Model.Rmd b/vignettes/Model.Rmd index cef9eb2c..7fc8bfff 100644 --- a/vignettes/Model.Rmd +++ b/vignettes/Model.Rmd @@ -1,8 +1,8 @@ --- -title: "Model Structure" +title: "Model Introduction" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Model Structure} + %\VignetteIndexEntry{Model Introduction} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -14,9 +14,18 @@ knitr::opts_chunk$set( ) ``` -This is an individual based model for *P. falciparum* and malaria interventions. +```{r, output.lines=6} +# Load the requisite packages: +library(malariasimulation) +# Set colour palette: +cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") +``` + +This vignette gives a high-level overview of the individual-based malariasimulation model. It then gives a basic example of how the model can be used, how to initiate the model with equilibrium conditions, and demonstrates how to change named parameter inputs, including setting seasonality parameters. Finally, it lists and broadly describes the content of the remaining vignettes, summarising parameter and intervention setting functions. -## Human Biology +## Model structure + +### Human Biology The human variables are documented in [R/variables.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/variables.R). @@ -28,11 +37,11 @@ The functions governing the human flow of infection and immunity processes are d -### States +#### States Modelled human states are Susceptible (*S*), Treated (*Tr*), Clinical disease (*D*), Asymptomatic infection (*A*) and Sub-patent infection (*U*). -### Parameters +#### Parameters Parameters shown on the infographic include: @@ -55,22 +64,21 @@ $$r_D=dr^{-1}$$ To maintain a constant population size during simulations, the birth rate of new susceptible individuals is set to be equal to the overall death rate. -## Mosquito Biology +### Mosquito Biology The functions governing mosquito biological processes and dynamics are spread out between the following files: -1. [src/adult_mosquito_eqs.cpp](https://github.com/mrc-ide/malariasimulation/blob/master/src/adult_mosquito.cpp) -2. [src/aquatic_mosquito_eqs.cpp](https://github.com/mrc-ide/malariasimulation/blob/master/src/aquatic_mosquito.cpp) -3. [src/mosquito_biology.cpp](https://github.com/mrc-ide/malariasimulation/blob/master/src/mosquito_biology.cpp) -4. [R/mosquito_biology.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/mosquito_biology.R) +1. [R/mosquito_biology.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/mosquito_biology.R) +2. [R/biting_process.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/biting_process.R) +3. [R/compartmental.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/compartmental.R) -### States +#### States Modelled mosquito states are separated into three juvenile stages: early (*E*) and late (*L*) larval stages, the pupal stage (*P*), and three adult states: susceptible (*S*M), incubating (*P*M) and infectious individuals (*I*M). Mosquitoes in any state may die, where they enter the NonExistent state. The model tracks both male and female juvenile mosquitoes, but only female adult mosquitoes. -### Parameters +#### Parameters Parameters shown on the infographic include mosquito developmental rates: @@ -103,7 +111,7 @@ $$ \mu_L = \mu_L^0(1+\gamma\frac{E(t)+L(t)}{K(t)}) $$ -## Key Model References (structure and dynamics) +### Key Model References (structure and dynamics) Griffin JT, Hollingsworth TD, Okell LC, Churcher TS, White M, et al. (2010) Reducing *Plasmodium falciparum* Malaria Transmission in Africa: A Model-Based Evaluation of Intervention Strategies. PLOS Medicine 7(8): e1000324. @@ -115,20 +123,19 @@ Griffin, J. T., Déirdre Hollingsworth, T., Reyburn, H., Drakeley, C. J., Riley, Griffin, J. T., Bhatt, S., Sinka, M. E., Gething, P. W., Lynch, M., Patouillard, E., Shutes, E., Newman, R. D., Alonso, P., Cibulskis, R. E., & Ghani, A. C. (2016). Potential for reduction of burden and local elimination of malaria by reducing Plasmodium falciparum malaria transmission: A mathematical modelling study. The Lancet Infectious Diseases, 16(4), 465--472. [https://doi.org/10.1016/S1473-3099(15)00423-5](https://doi.org/10.1016/S1473-3099(15)00423-5) -# Basic simulation +## Run simulation ### Code -The key package function is `run_simulation()` which, in its most basic form, simply requires a number of timesteps in days. Default parameter settings assume a human population of size of 100, an initial mosquito population size of 1000 of a single species (default set to *Anopheles gambiae* parameters), with no treatment interventions and no seasonality. The full parameters list can be seen in the documentation for `get_parameters()`. +The key package function is `run_simulation()` which simply requires, in its most basic form, a number of timesteps in days. Default parameter settings assume a human population size of 100, an initial mosquito population size of 1000 (where the default species is set to *Anopheles gambiae*), with no treatment interventions and no seasonality and models the spread of *Plasmodium falciparum*. The full parameters list can be seen in the documentation for `get_parameters()`. ```{r, output.lines=6} -library(malariasimulation) test_sim <- run_simulation(timesteps = 100) ``` ### Output -The `run_simulation()` function then simulates malaria transmission dynamics and returns a dataframe for the following parameters through time: +The `run_simulation()` function then simulates malaria transmission dynamics and returns a dataframe containing the following outputs through time: - `infectivity`: human infectiousness - `EIR_All`: the entomological inoculation rate (for all mosquito species) @@ -147,8 +154,8 @@ The `run_simulation()` function then simulates malaria transmission dynamics and - `n_730_3650`: population size of an age group of interest (where the default is set to 730-3650 days old, or 2-10 years, but which may be adjusted (see [Demography](https://mrc-ide.github.io/malariasimulation/articles/Demography.html) vignette for more details) - `n_detect_730_3650`: number with possible detection through microscopy of a given age group - `p_detect_730_3650`: the sum of probabilities of detection through microscopy of a given age group -- `E_All_count`, `L_All_count`, `P_All_count`, `Sm_All_count`, `Pm_All_count`, `Im_All_count`, `NonExistent_All_count`: mosquito population sizes in each state -- `total_M_All`: number of adult mosquitoes +- `E_gamb_count`, `L_gamb_count`, `P_gamb_count`, `Sm_gamb_count`, `Pm_gamb_count`, `Im_gamb_count`: species-specific mosquito population sizes in each state (default set to *An. gambiae*) +- `total_M_gamb`: species-specific number of adult mosquitoes (default set to *An. gambiae*) ```{r, output.lines=6} head(test_sim, n = 3) @@ -166,10 +173,7 @@ Where **treatments** are specified, `n_treated` will report the number that have These outputs can then be visualised, such as the population changes in states. Another key output is the prevalence of detectable infections between the ages of 2-10 (*Pf*PR~2-10~), which can be obtained by dividing `n_detect_730_3650` by `n_730_3650`. -```{r, fig.align = 'center', fig.height = 5, fig.width = 7} -# Set color palette -cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") - +```{r, fig.align = 'center', out.width='100%', fig.asp=0.55} # Define vector of column names to plot cols_to_plot <- paste0(c("S","D","A","U","Tr"),"_count") @@ -179,14 +183,17 @@ states_plot <- function(sim){ # Set up plot with first state plot(x = sim$timestep, y = sim[,cols_to_plot[1]], type = "l", col = cols[1], ylim = c(0,80), - ylab = "Population size", xlab = "Days") + ylab = "Population size", xlab = "Days", + xaxs = "i", yaxs = "i", lwd = 2) # Add remaining states sapply(2:5, function(x){ - points(x = sim$timestep, y = sim[,cols_to_plot[x]], type = "l", col = cols[x])}) - + points(x = sim$timestep, y = sim[,cols_to_plot[x]], + type = "l", lwd = 2, col = cols[x])}) + grid(lty = 2, col = "grey80", lwd = 0.5) # Add legend - legend("topleft", legend = c("S","D","A","U","Tr"), col = cols, lty = 1, bty = "n", ncol = 2) + legend("topleft", legend = c("S","D","A","U","Tr"), col = cols, + lty = 1, lwd = 2, bty = "n", ncol = 3, cex = 0.7) } par(mfrow = c(1,2)) @@ -197,13 +204,17 @@ test_sim$PfPR2_10 <- test_sim$n_detect_730_3650/test_sim$n_730_3650 # Plot Pf PR 2-10 plot(x = test_sim$timestep, y = test_sim$PfPR2_10, type = "l", - col = cols[7], ylim = c(0,1), - ylab = expression(paste(italic(Pf),"PR"[2-10])), xlab = "Days") + col = cols[7], ylim = c(0,1), lwd = 2, + ylab = expression(paste(italic(Pf),"PR"[2-10])), xlab = "Days", + xaxs = "i", yaxs = "i") +grid(lty = 2, col = "grey80", lwd = 0.5) ``` -Note that the model will not begin simulations from an equilibrium state as default. In the case of our simulation that means that the population in each state and the prevalence (*Pf*PR~2-10~) move towards an equilibrium. To begin the simulation at approximate equilibrium conditions, please use the `set_equilibrium()` function, which requires you to specify an initial EIR value: +## Set equilibrium -```{r, fig.align = 'center', fig.height = 5, fig.width = 7} +Note that the model will not begin simulations from an equilibrium state as default (as in the simulation above). To begin the simulation at approximate equilibrium conditions, please use the `set_equilibrium()` function, which requires you to specify an initial EIR value: + +```{r, fig.align = 'center', out.width='100%', fig.asp=0.55} params <- get_parameters() |> set_equilibrium(init_EIR = 5) @@ -218,45 +229,80 @@ test_sim_eq$PfPR2_10 <- test_sim_eq$n_detect_730_3650/test_sim_eq$n_730_3650 # Plot Pf PR 2-10 plot(x = test_sim_eq$timestep, y = test_sim_eq$PfPR2_10, type = "l", col = cols[7], ylim = c(0,1), - ylab = expression(paste(italic(Pf),"PR"[2-10])), xlab = "Days") - + ylab = expression(paste(italic(Pf),"PR"[2-10])), xlab = "Days", + xaxs = "i", yaxs = "i", lwd = 2) +grid(lty = 2, col = "grey80", lwd = 0.5) ``` -# Changing parameters +## Override parameters The `get_parameters()` function generates a complete parameter set that may be fed into `run_simulation()`. A number of **helper functions** have been designed to assist in changing and setting key parameters, which are explained across the remaining vignettes. -Some parameters (e.g. population size, age group rendering, setting seasonality) must still be replaced directly. When this is the case, care must be taken to ensure the replacement parameters are in the same class as the default parameters (e.g. if the parameter is a numeric, its replacement must also be numeric, if logical, the replacement must also be logical). Parameters are replaced by passing a list of named parameters to the `get_parameters()` function using the `overrides` argument. An example showing how to change the `human_population` parameter is given below. +Some parameters (e.g. population size, age group rendering, setting seasonality) must still be replaced directly. When this is the case, care must be taken to ensure the replacement parameters are in the same class as the default parameters (e.g. if the parameter is a numeric, its replacement must also be numeric, if logical, the replacement must also be logical). Parameters are replaced by passing a list of named parameters to the `get_parameters()` function using the `overrides` argument. The following example shows how to change the `human_population` parameter. ```{r} # Use get_parameters(overrides = list(...))) to set new parameters new_params <- get_parameters(overrides = list(human_population = 200)) ``` -While other parameters can be changed individually, we do not generally recommended adjusting these without close attention and a detailed understanding of how this will impact the model assumptions. We strongly encourage users to stick with the parameter setting functions and methods described in these vignettes when adjusting parameter settings. +While other parameters can be changed individually, we do not generally recommended adjusting these without a detailed understanding of how this will impact the model assumptions. We strongly encourage users to stick with the parameter setting functions and methods described in these vignettes when adjusting parameter settings. -## Vignettes +## Seasonality -The remaining vignettes describe how to adjust sets of parameters through a number of functions as follows: +The `malariasimulation` package has the capacity to simulate malaria transmission for a range of seasonal transmission profiles. This is achieved by specifying an annual rainfall profile that shapes mosquito population dynamics, thereby impacting malaria transmission. Please see the [Umbrella](https://github.com/mrc-ide/umbrella) package for instructions on generating seasonality parameters. -1. [Population Demography](https://mrc-ide.github.io/malariasimulation/articles/Demography.html) +To include seasonality, we must set the parameter `model_seasonality = TRUE` and assign values to parameters that determine seasonality: `g0`, `g` and `h` (which represent fourier coefficients). These parameters must be set directly by passing a list of named parameters to the `overrides` argument of the `get_parameters()` function. - - Age group rendering - - `set_demography()`: setting demographies and time-varying death rates +```{r, fig.align = 'center', out.width='100%'} +# Set parameters, inclusing seasonality parameters +params_seasons <- get_parameters(overrides = list( + model_seasonality = TRUE, + g0 = 0.28, + g = c(0.2, -0.07, -0.001), + h = c(0.2, -0.07, -0.1))) -2. [Carrying capacity](https://mrc-ide.github.io/malariasimulation/articles/Carrying-capacity.html) +# Run simulation +seasonality_simulation <- run_simulation(timesteps = 600, parameters = params_seasons) - - Setting seasonality parameters - - `set_carrying_capacity()`: changes mosquito carrying capacity, e.g. to model larval source management impact - - `set_species`: to model multiple species and species invasion +# Collect results +All_mos_cols <- paste0(c("E","L","P","Sm","Pm", "Im"),"_All_count") + +# Plot results +plot(seasonality_simulation[,1], rowSums(seasonality_simulation[,All_mos_cols]), lwd = 2, + ylim = c(0, 120000), type = "l", xlab = "Days", ylab = "Mosquito population size") +grid() +``` -3. [Treatment](https://mrc-ide.github.io/malariasimulation/articles/Treatment.html) +The mosquito population size is no longer constant and follows the patterns set by rainfall. + +## Individual mosquitoes + +Mosquitoes may also be modelled deterministically (the default) or individually. + +To model individual mosquitoes, set `individual_mosquitoes` to `TRUE` in the `overrides` argument of `get_parameters()`. + +```{r} +simparams <- get_parameters(overrides = list(individual_mosquitoes = TRUE)) +``` + +## Vignettes + +The remaining vignettes describe how to adjust sets of parameters through a number of methods and functions as follows: + +1. [Demography](https://mrc-ide.github.io/malariasimulation/articles/Demography.html) + + - Population age group rendering + + - `set_demography()`: setting population demographies and time-varying death rates + +2. [Treatment](https://mrc-ide.github.io/malariasimulation/articles/Treatment.html) - `set_drugs()`: for drug-specific parameters (with in-built parameter sets) + - `set_clinical_treatment()`: implemention of clinical treatment interventions -4. [MDA and Chemoprevention](https://mrc-ide.github.io/malariasimulation/articles/MDA.html) +3. [MDA and Chemoprevention](https://mrc-ide.github.io/malariasimulation/articles/MDA.html) - `set_mda()`: implementation of mass drug administration interventions @@ -266,28 +312,42 @@ The remaining vignettes describe how to adjust sets of parameters through a numb - `peak_season_offset()`: correlating timed interventions with seasonal malaria -5. [Vaccines](https://mrc-ide.github.io/malariasimulation/articles/Vaccines.html) +4. [Vaccines](https://mrc-ide.github.io/malariasimulation/articles/Vaccines.html) - `set_mass_pev()`: implementation of a pre-erythrocytic vaccination intervention - - `set_pev_epi()`: Implementation of a pre-erythrocytic vaccination intervention from a certain age + + - `set_pev_epi()`: implementation of a pre-erythrocytic vaccination intervention from a certain age + - `set_tbv()`: implementation of a transmission blocking vaccination intervention -6. [Vector Control: Bednets](https://mrc-ide.github.io/malariasimulation/articles/VectorControl.html) +5. [Vector Control: Bednets](https://mrc-ide.github.io/malariasimulation/articles/VectorControl_Bednets.html) - `set_bednets()`: implementation of bednet distribution intervention -7. [Vector Control: Indoor Residual Spraying](https://mrc-ide.github.io/malariasimulation/articles/VectorControl.html) +6. [Vector Control: Indoor Residual Spraying](https://mrc-ide.github.io/malariasimulation/articles/VectorControl_IRS.html) - `set_spraying()`: implementation of an indoor residual spraying intervention -8. [Matching PfPR2-10 to EIR](https://mrc-ide.github.io/malariasimulation/articles/EIRprevmatch.html) +7. [Mosquito Species](https://mrc-ide.github.io/malariasimulation/articles/SetSpecies.html) + + - `set_species()`: setting mosquito distribution + +8. [Carrying Capacity](https://mrc-ide.github.io/malariasimulation/articles/Carrying-capacity.html) + + - `set_carrying_capacity()`: changes mosquito carrying capacity, e.g. to model larval source management impact + +9. [Matching PfPR2-10 to EIR](https://mrc-ide.github.io/malariasimulation/articles/EIRprevmatch.html) - Using *Pf*PR~2-10~ data to estimate EIR 9. [Metapopulation Modelling](https://mrc-ide.github.io/malariasimulation/articles/Metapopulation.html) - - `run_metapop_simulation()`: to model multiple areas simultaneously + - `run_metapop_simulation()`: model multiple areas simultaneously -10. [Variation](https://mrc-ide.github.io/malariasimulation/articles/Variation.html) +11. [Stochastic Variation](https://mrc-ide.github.io/malariasimulation/articles/Variation.html) - `run_simulation_with_repetitions()`: running simulations with replicates + +12. [Parameter Variation](https://mrc-ide.github.io/malariasimulation/articles/ParameterVariation.html) + + - `set_parameter_draw()`: incorporating parameter variation diff --git a/vignettes/Parameter_variation.Rmd b/vignettes/Parameter_variation.Rmd new file mode 100644 index 00000000..69ad4da1 --- /dev/null +++ b/vignettes/Parameter_variation.Rmd @@ -0,0 +1,80 @@ +--- +title: "Parameter Variation" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Parameter Variation} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + + +```{r setup, echo= FALSE} +# Load the requisite packages: +library(malariasimulation) +# Set colour palette: +cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") +``` + +This vignette describes how variation in estimated model parameters can be incorporated into model simulations. + +## Estimating variation in parameters + +The malariasimulation transmission model was fit utilizing a Bayesian framework, which produced a posterior distribution of parameter sets. Default parameters for the model were taken as the median across 50 random sets of parameter draws. + +```{r, fig.align = 'center', out.width='100%'} +## plot parasite prevalence with default model parameters +simparams <- get_parameters(list( + human_population = 100, + individual_mosquitoes = FALSE +)) + +# Default (median) model parameters +sim <- run_simulation(timesteps = 1000, simparams) + +# plot the default median parameter +plot( + sim$timestep, + sim$n_detect_730_3650 / sim$n_730_3650, + t = "l", + ylim = c(0, 1), + ylab = "PfPr", + xlab = "Time in days", + xaxs = "i", yaxs = "i", + lwd = 2, main = 'Parasite prevalence over time with default model parameters', + cex.main = 0.9) +grid(lty = 2, col = "grey80", lwd = 0.5) +``` + +If needed, we can produce stochastic model outputs incorporating variation in model parameters. This is done with the `set_parameter_draw` function, which pulls parameter draws from this joint posterior of Markov chain Monte Carlo (MCMC) fitting. This function overrides the default model parameters with a sample from one of 1000 draws from the joint posterior. + +Keep in mind that `set_parameter_draw` must be called prior to `set_equilibrium`, as the baseline transmission intensity must be calibrated to new model parameters. + +```{r, fig.align = 'center', out.width='100%'} +## run simulation on different samples of the joint posterior distribution +# plot the default median parameter +plot( + sim$timestep[1:500], + sim$n_detect_730_3650[1:500] / sim$n_730_3650[1:500], + t = "l", + ylim = c(0, 1), + ylab = "PfPr", + xlab = "Time in days", + xaxs = "i", yaxs = "i", + main = 'Parasite prevalence over time for 8 sets of parameter draws', + cex.main = 0.9 +) +grid(lty = 2, col = "grey80", lwd = 0.5) + +for (i in 1:7) { + param_draw <- simparams |> + set_parameter_draw(sample(1:1000, 1)) |> + set_equilibrium(init_EIR = 5) + + sim <- run_simulation(timesteps = 500, param_draw) + + lines(sim$timestep, sim$n_detect_730_3650 / sim$n_730_3650, col = cols[i]) +} +``` + + +For more information on uncertainty in parameters, please refer to [The US President's Malaria Initiative, Plasmodium falciparum transmission and mortality: A modelling study](https://journals.plos.org/plosmedicine/article?id=10.1371/journal.pmed.1002448), Supplemental material, Section 4. \ No newline at end of file diff --git a/vignettes/SetSpecies.Rmd b/vignettes/SetSpecies.Rmd index 511d2c9c..50a86ecd 100644 --- a/vignettes/SetSpecies.Rmd +++ b/vignettes/SetSpecies.Rmd @@ -15,45 +15,62 @@ knitr::opts_chunk$set( ``` ```{r setup} +# Load the requisite packages: library(malariasimulation) +# Set colour palette: +cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") ``` - -### Plotting function + +As alluded to in the Model Structure, Vector Control: IRS, and Vector Control: Bed net vignettes, it is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. IRS and bed nets could be expected to have different impacts depending on the proportion of each mosquito species because of variations in indoor resting, insecticide resistance, and proportion of bites on humans versus animals by species. If you have specified more than 1 species, then the arguments for `set_spraying()` and/or `set_bednets()` must be populated with values for each species at each timestep that the intervention is implemented. + +There are preset parameters for *An. gambiae*, *An. arabiensis*, *An. funestus* and *An. stephensi* that can be set by the helper objects `gamb_params`, `arab_params`, `fun_params` and `steph_params`, respectively. The default values for each species in these helper functions are from [Sherrard-Smith et al., 2018](https://doi.org/10.1038/s41467-018-07357-w). The parameters are: + +* `species`: the mosquito species name or signifier +* `blood_meal_rates`: the blood meal rates for each species +* `foraging_time`: time spent taking blood meals +* `Q0`: proportion of blood meals taken on humans +* `phi_bednets`: proportion of bites taken in bed +* `phi_indoors`: proportion of bites taken indoors + +We will demonstrate how to specify different mosquito species and how this could alter intervention impact using an example with IRS. + We will create a plotting function to visualise the output. ```{r} -cols <- c("#E69F00", "#56B4E9", "#009E73", - "#F0E442", "#0072B2", "#D55E00", "#CC79A7") - # Plotting functions plot_prev <- function() { plot(x = output_endophilic$timestep, y = output_endophilic$n_detect_730_3650 / output_endophilic$n_730_3650, - type = "l", col = cols[3], lwd = 2.5, + type = "l", col = cols[3], lwd = 1, xlab = "Time (days)", ylab = expression(paste(italic(Pf),"PR"[2-10])), - xaxs = "i", yaxs = "i", bty = "l", ylim = c(0,1)) + xaxs = "i", yaxs = "i", ylim = c(0,1)) lines(x = output_exophilic$timestep, y = output_exophilic$n_detect_730_3650 / output_exophilic$n_730_3650, - col = cols[5], lwd = 2.5) + col = cols[5], lwd = 1) abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = "black") - grid(lty = 2, col = "grey80", lwd = 1) - legend("bottomleft", box.lty = 0, legend = c("Spraying", "Prevalence for endophilic mosquitoes", "Prevalence for exophilic mosquitoes"), - col = c("black", cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) + text(x = sprayingtimesteps + 10, y = 0.9, labels = "Spraying\nint.", adj = 0, cex = 0.8) + grid(lty = 2, col = "grey80", lwd = 0.5) + legend("bottomleft", box.lty = 0, + legend = c("Prevalence for endophilic mosquitoes", "Prevalence for exophilic mosquitoes"), + col = c(cols[3], cols[5]), lty = c(1,1), lwd = 2, cex = 0.8, y.intersp = 1.3) } -``` - -As alluded to in the Model Structure, Vector Control: IRS, and Vector Control: Bed net vignettes, it is possible to account for varying proportions of mosquito species in the setting you are modelling using the `set_species()` function. IRS and bed nets could be expected to have different impacts depending on the proportion of each mosquito species because of variations in indoor resting, insecticide resistance, and proportion of bites on humans versus animals by species. If you have specified more than 1 species, then the arguments for `set_spraying()` and/or `set_bednets()` must be populated with values for each species at each timestep that the intervention is implemented. -There are preset parameters for *An. gambiae*, *An. arabiensis*, and *An. funestus* that can be set by the helper functions `gamb_params()`, `arab_params()`, and `fun_params()`, respectively. The default values for each species in these helper functions are from [Sherrard-Smith et al., 2018](https://doi.org/10.1038/s41467-018-07357-w). The parameters are: +species_plot <- function(Mos_pops){ + plot(x = Mos_pops[,1], y = Mos_pops[,2], type = "l", col = cols[2], + ylim = c(0,max(Mos_pops[,-1]*1.25)), ylab = "Mosquito population size", xlab = "Days", + xaxs = "i", yaxs = "i", lwd = 2) + grid(lty = 2, col = "grey80", lwd = 0.5) + sapply(3:4, function(x){ + points(x = Mos_pops[,1], y = Mos_pops[,x], type = "l", col = cols[x])}) + legend("topright", legend = c("A. arab","A. fun","A. gamb"), + col = cols[-1], lty = 1, lwd = 2, ncol = 1, cex = 0.8, bty = "n") + } -* `blood_meal_rates`: the blood meal rates for each species -* `foraging_time`: time spent taking blood meals -* `Q0`: proportion of blood meals taken on humans -* `phi_bednets`: proportion of bites taken in bed -* `phi_indoors`: proportion of bites taken indoors +``` + +## Setting mosquito species parameters -We will demonstrate how to specify different mosquito species and how this could alter intervention impact using an example with IRS. -## IRS with single endophilic mosquito species +### Single endophilic mosquito species -Use the `get_parameters()` function to generate a list of parameters, accepting most of the default values, but modifying seasonality values to model a seasonal setting. We will use `set_species` to model mosquitoes similar to *An. funestus* but with a higher propensity to bite indoors. Then, we use the `set_equilibrium()` function to to initialise the model at a given entomological inoculation rate (EIR). +Use the `get_parameters()` function to generate a list of parameters, accepting most of the default values, but modifying seasonality values to model a seasonal setting. We will use `set_species` to model mosquitoes similar to *An. funestus* but with a higher propensity to bite indoors (which we will name "endophilic"). Then, we use the `set_equilibrium()` function to to initialise the model at a given entomological inoculation rate (EIR). We used the `set_spraying()` function to set an IRS intervention. This function takes as arguments the parameter list, timesteps of spraying, coverage of IRS in the population and a series of parameters related to the insecticide used in the IRS. The proportion of mosquitoes dying following entering a hut is dependent on the parameters `ls_theta`, the initial efficacy, and `ls_gamma`, how it changes over time. The proportion of mosquitoes successfully feeding is dependent on `ks_theta`, the initial impact of the insecticide in IRS, and `ks_gamma`, how the impact changes over time. Finally, the proportion of mosquitoes being deterred away from a sprayed hut depends on `ms_theta`, the initial impact of IRS, and `ms_gamma`, the change in impact over time. See a more comprehensive explanation in the Supplementary Information of [Sherrard-Smith et al., 2018](https://doi.org/10.1038/s41467-018-07357-w). @@ -77,7 +94,7 @@ simparams <- get_parameters( peak <- peak_season_offset(simparams) -# Create an example mosquito species with a high value for `phi_indoors` +# Create an example mosquito species (named endophilic) with a high value for `phi_indoors` endophilic_mosquito_params <- fun_params endophilic_mosquito_params$phi_indoors <- 0.9 endophilic_mosquito_params$species <- 'endophilic' @@ -116,18 +133,17 @@ simparams$species simparams$species_proportions ``` +### Single exophilic mosquito species -## IRS with single exophilic mosquito species +We will run the same model with IRS as above, but this time with an example mosquito species similar to *An. funestus*, but with a lower propensity to bite indoors (which we will name "exophilic"). Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. See the Vector Control: IRS vignette for more information about setting IRS with different mosquito species. -We will run the same model with IRS as above, but this time with an example mosquito species similar to *An. funestus*, but with a lower propensity to bite indoors. Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. See the Vector Control: IRS vignette for more information about setting IRS with different mosquito species. - -```{r, fig.align="center", fig.height=4, fig.width=6} -# Create an example mosquito species with a low value for `phi_indoors` +```{r, fig.align = 'center', out.width='100%'} +# Create an example mosquito species (named exophilic) with a low value for `phi_indoors` exophilic_mosquito_params <- fun_params exophilic_mosquito_params$phi_indoors <- 0.2 exophilic_mosquito_params$species <- 'exophilic' -## Set 3 species of mosquitoes, 10% An. arabiensis, 10% An. gambia, and 80% an example species with a lower propensity for indoor biting +## Set mosquito species with a low propensity for indoor biting simparams <- set_species( simparams, species = list(exophilic_mosquito_params), @@ -155,8 +171,39 @@ output_exophilic <- run_simulation(timesteps = sim_length, parameters = simparam ``` ### Plot adult female infectious mosquitoes by species over time + In the plot below, we can see that IRS is much more effective when the endophilic mosquito species is modelled compared to the scenario where an exophilic species is modelled. In this case, IRS will not be as effective because a larger proportion of bites take place outside of the home. -```{r,fig.align="center", fig.height=5, fig.width=7} +```{r, fig.align = 'center', out.width='100%'} plot_prev() ``` +## Setting multiple mosquito species + +Finally, we give an example of how to set multiple mosquito species. + + +```{r, fig.align = 'center', out.width='100%'} +# Update parameter list with species distributions +simparams <- get_parameters( + list( + human_population = human_population, + # seasonality parameters + model_seasonality = TRUE, + g0 = 0.285277, + g = c(-0.0248801, -0.0529426, -0.0168910), + h = c(-0.0216681, -0.0242904, -0.0073646) + ) +) + +params_species <- set_species(parameters = simparams, + species = list(arab_params, fun_params, gamb_params), + proportions = c(0.1,0.3,0.6)) + +# Run simulation +species_simulation <- run_simulation(timesteps = sim_length, parameters = params_species) + +## Plot species distributions +Mos_sp_dist_sim <- species_simulation[,c("timestep", "total_M_arab", "total_M_fun", "total_M_gamb")] +species_plot(Mos_sp_dist_sim) +``` + diff --git a/vignettes/Treatment.Rmd b/vignettes/Treatment.Rmd index d6763774..4f40b19b 100644 --- a/vignettes/Treatment.Rmd +++ b/vignettes/Treatment.Rmd @@ -15,11 +15,12 @@ knitr::opts_chunk$set( ``` ```{r setup} +# Load the requisite packages: library(malariasimulation) +# Set colour palette: +cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") ``` -# Introduction - This vignette describes how to implement clinical drug treatments in malariasimulation. The malariasimulation package contains built-in parameters sets for three anti-malarial drugs: @@ -28,7 +29,7 @@ The malariasimulation package contains built-in parameters sets for three anti-m 2. `DHA_PQP_params`: dihydroartemisinin and piperaquine (DHA-PQP) 3. `SP_AQ_params`: sulfadoxine-pyrimethamine and amodiaquine (SP-AQ) -While all these drugs can be used to treat malaria, DHA-PQP and SP-AQ remain in the body for some time following treatment, making them good candidates for chemoprevention in mass drug administrations (see [Mass Drug Administration](https://mrc-ide.github.io/malariasimulation/articles/MDA.html)). Any of these drugs can be included in the parameter list using the `set_drugs()` function (see [drugs_parameters.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/drug_parameters.R) for full parameter details). +While all these drugs can be used to treat malaria, DHA-PQP and SP-AQ remain in the body for some time following treatment, making them good candidates for chemoprevention in mass drug administrations (see [Mass Drug Administration and Chemoprevention](https://mrc-ide.github.io/malariasimulation/articles/MDA.html)). Any of these drugs can be included in the parameter list using the `set_drugs()` function (see [drugs_parameters.R](https://github.com/mrc-ide/malariasimulation/blob/master/R/drug_parameters.R) for full parameter details). Each drug parameter set is a vector of length four, with parameters that represent the drug efficacy, the infectiousness following treatment relative to an untreated infection, and parameters that determine the protection against reinfection ($P$): shape ($w$) and scale ($\lambda$). The decay of protection against infection follows a weibull distribution as follows: @@ -36,9 +37,7 @@ $$P = e^{{(-t/\lambda)}^w}$$ The $P$ for each drug following treatment through time is plotted below. -```{r, echo = FALSE, fig.align = 'center', fig.height = 5, fig.width = 7} -cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") - +```{r, fig.align = 'center', out.width='100%'} calc_P <- function(w, lambda, t){ P <- exp(-(t/lambda)^w) } @@ -50,40 +49,37 @@ P_matrix <- lapply(list(AL_params, DHA_PQP_params, SP_AQ_params), function(x){ }) plot(x = t, y = P_matrix[[1]], type = "l", col = cols[1], - xlab = "Days", ylab = expression(paste("Protection against reinfection (",italic(P),")"))) -grid() + xlab = "Days", ylab = expression(paste("Protection against reinfection (",italic(P),")")), + xaxs = "i", yaxs = "i", lwd = 2) +grid(lty = 2, col = "grey80", lwd = 0.5) # invisible(sapply(2:3, function(x){ - points(x = t, y = P_matrix[[x]], type = "l", col = cols[x]) + points(x = t, y = P_matrix[[x]], type = "l", col = cols[x], lwd = 2) })) # Add legend -legend("topright", legend = c("AL","DHA-PQP","SP-AQ"), col = cols, lty = 1) - +legend("topright", legend = c("AL","DHA-PQP","SP-AQ"), col = cols, lty = 1, lwd = 2, cex = 0.8) ``` For more details, please see: Okell, L., Cairns, M., Griffin, J. *et al.* Contrasting benefits of different artemisinin combination therapies as first-line malaria treatments using model-based cost-effectiveness analysis. *Nat Commun* **5**, 5606 (2014). . -## Functions +## Setting drugs and clinical treatment -Drug parameters can be incorporated into a complete parameter set using the `set_drugs` function which takes the full parameter set and a list of drug parameter sets. +Drug parameters can be incorporated into a complete parameter set using the `set_drugs()` function which takes the full parameter set and a list of drug parameter sets. A treatment regimen for each drug can then be described using the `set_clinical_treatment()` function which takes the drug index, a vector of timesteps at which a change in coverage occurs (where the initial coverage is 0 until the first timestep specified) and a vector of coverages for the drug that correspond with the timestep changes, as well as the complete parameter set. Multiple drugs can be modelled simultaneously, with treatment coverage that can be specified for each drug. This function must be used for each drug included (e.g., if there are two drugs, `set_clinical_treatment()` must be called twice to specify the treatment plan). - -# Example +### Parameterisation and simulation We will run a simulation for two years using AL and DHA-PQP treatment regimens. We begin our AL and DHA-PQP treatments on day 300 at 40% and 30% coverage, respectively. We provide these treatments for 300 days before the regimen ends. Note that the sum of treatment coverages cannot exceed 100% at any timestep. Prior to the simulation, the function `set_equilibrium` can also be used to generate equilibrium values for the human and mosquito populations. -## Parameterisation and simulation - ```{r} # Daily simulation timesteps for two years year <- 365 @@ -106,7 +102,8 @@ treatment_params <- set_clinical_treatment( parameters = drug_params, drug = 1, timesteps = c(300,600), # Treatment coverage changes on day 300 and day 600 - coverages = c(0.4,0)) # The initial treatment coverage (0%) is the default and does not need to be set + coverages = c(0.4,0)) # The initial treatment coverage (0%) is the default +# and does not need to be set # Set treatment program for DHA-PQP (drug index = 2) treatment_params <- set_clinical_treatment( @@ -123,22 +120,23 @@ output <- run_simulation(sim_length, treatment_params) ``` -## Visualisation +### Visualisation Following simulation of malaria transmission under this treatment regimen, we can now visualise the effect of the regimen on the number of detectable cases through time using the `n_detect_730_3650`. -```{r, fig.align = 'center', fig.height = 5, fig.width = 7} +```{r, fig.align = 'center', out.width='100%'} # Plot results plot(x = output$timestep, y = output$n_detect_730_3650, type = "l", xlab = "Days", ylab = "Detectable cases", col = cols[1], - ylim = c(min(output$n_detect_730_3650)-1, max(output$n_detect_730_3650)+7)) + ylim = c(min(output$n_detect_730_3650)-1, max(output$n_detect_730_3650)+7), + xaxs = "i", yaxs = "i") # Show treatment times abline(v = 300, lty = 2) -text(x = 310, y = max(output$n_detect_730_3650)+4, labels = "Treatment\nbegins", adj = 0) +text(x = 310, y = max(output$n_detect_730_3650), labels = "Treatment\nbegins", adj = 0, cex = 0.8) abline(v = 600, lty = 2) -text(x = 610, y = max(output$n_detect_730_3650)+4, labels = "Treatment\nends", adj = 0) +text(x = 610, y = max(output$n_detect_730_3650), labels = "Treatment\nends", adj = 0, cex = 0.8) # Add grid lines -grid() +grid(lty = 2, col = "grey80", nx = 11, ny = 10, lwd = 0.5) ``` diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 44a752de..583801b3 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -14,20 +14,18 @@ knitr::opts_chunk$set( ) ``` -In this tutorial, we will explore how to model different strategies for both pre-erythrocytic malaria vaccines and a theoretical malaria transmission blocking vaccine (TBV). Parameters for a pre-erythrocytic vaccine can be set for a routine age-based Expanded Programme on Immunization (EPI) strategy or a mass vaccination strategy using the helper functions `set_pev_epi()` and `set_mass_pev()`, while parameters for a TBV can be set using `set_tbv()`. Under an EPI strategy, everybody within a certain age range will be vaccinated within the routine immunisation system. A mass vaccination strategy is typically a one-time event where everybody, or everybody within a certain age group, is targeted for vaccination during a relatively short window of time. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the expected peak of malaria prevalence given by `peak_season_offset()`. - -```{r setup, message=FALSE} +```{r setup, message=FALSE, class.source = 'fold-hide'} +# Load the requisite packages: library(malariasimulation) - -cols <- c("#E69F00", "#56B4E9", "#009E73", - "#F0E442", "#0072B2", "#D55E00", "#CC79A7") +# Set colour palette: +cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") ``` -### Plotting functions +In this vignette, we will explore how to model different strategies for both pre-erythrocytic malaria vaccines and a theoretical malaria transmission blocking vaccine (TBV). Parameters for a pre-erythrocytic vaccine can be set for a routine age-based Expanded Programme on Immunization (EPI) strategy or a mass vaccination strategy using the helper functions `set_pev_epi()` and `set_mass_pev()`, while parameters for a TBV can be set using `set_tbv()`. Under an EPI strategy, everybody within a certain age range will be vaccinated within the routine immunisation system. A mass vaccination strategy is typically a one-time event where everybody, or everybody within a certain age group, is targeted for vaccination during a relatively short window of time. If you are modelling a seasonal setting, then it is also possible to schedule vaccination relative to the expected peak of malaria prevalence given by `peak_season_offset()`. First, we will define a few functions to visualise the outputs. -```{r} +```{r, class.source = 'fold-hide'} # Plotting clinical incidence plot_inci <- function(type = "not seasonal"){ if(type == "seasonal"){ @@ -42,20 +40,27 @@ plot_inci <- function(type = "not seasonal"){ comparison$clinical_incidence <- 1000 * comparison$n_inc_clinical_0_1825 / comparison$n_0_1825 comparison$time_year <- comparison$timestep / year - plot(x = output$time_year, y = output$clinical_incidence, + plot(x = output$time_year, y = output$clinical_incidence, type = "l", col = cols[2], xlab = "Time (years)", ylab = "Clinical incidence (per 1000 children aged 0-5)", - xaxs = "i", yaxs = "i", bty = "l", xaxs = "i", yaxs = "i") - grid(lty = 2, col = "grey80", lwd = 1) + ylim = c(0, max(output$clinical_incidence)*1.3), + xaxs = "i", yaxs = "i") + grid(lty = 2, col = "grey80", lwd = 0.5) abline(v = vaccinetime, col = "black", lty = 2, lwd = 2.5) - curve_values <- loess(clinical_incidence ~ time_year, data = output, span = 0.3, method = "loess") + text(x = vaccinetime + 0.05, y = max(output$clinical_incidence)*1.2, labels = "Start of\nvaccination", adj = 0, cex = 0.8) + curve_values <- loess(clinical_incidence ~ time_year, data = output, + span = 0.3, method = "loess") lines(output$time_year, predict(curve_values), col = cols[5], lwd = 3) - curve_valuescomp <- loess(clinical_incidence ~ time_year, data = comparison, span = 0.3, method = "loess") + curve_valuescomp <- loess(clinical_incidence ~ time_year, data = comparison, span = 0.3, + method = "loess") lines(comparison$time_year, predict(curve_valuescomp), col = cols[6], lwd = 3) - legend("topright", box.lty = 0, legend = c("Start of vaccination", "Unsmoothed incidence for vaccine scenario", "Smoothed incidence for vaccine scenario", "Smoothed incidence for no\nintervention scenario"), - col = c("black", cols[2], cols[5], cols[6]), lty = c(2, 1, 1), lwd = 2.5) + legend("topright", box.lty = 0, bg = "white", + legend = c("Unsmoothed incidence for\nvaccine scenario", + "Smoothed incidence for\nvaccine scenario", + "Smoothed incidence for no\nintervention scenario"), + col = c(cols[2], cols[5], cols[6]), lty = c(1, 1, 1), lwd = 2.5, cex = 0.8, y.intersp = 1.5) } # Plot parasite prevalence @@ -73,13 +78,17 @@ plot_prev <- function(type = "not seasonal"){ plot(x = output$time_year, y = output$n_detect_730_3650/output$n_730_3650, type = "l", col = cols[3], ylim=c(0,1), lwd = 3, xlab = "Time (years)", ylab = expression(paste(italic(Pf),"PR"[2-10])), - xaxs = "i", yaxs = "i", bty = "l", xaxs = "i", yaxs = "i") - grid(lty = 2, col = "grey80", lwd = 1) + xaxs = "i", yaxs = "i") + grid(lty = 2, col = "grey80", lwd = 0.5) lines(x = comparison$time_year, y = comparison$n_detect_730_3650/comparison$n_730_3650, col = cols[6], lwd = 3) abline(v = vaccinetime, col = "black", lty = 2, lwd = 2.5) - legend("topright", box.lty = 0, legend = c("Start of vaccination", "Prevalence for vaccine scenario", "Prevalence for no intervention scenario"), - col = c("black", cols[3], cols[6]), lty = c(2, 1, 1), lwd = 2.5) + text(x = vaccinetime + 0.05, y = 0.9, labels = "Start of\nvaccination", adj = 0, cex = 0.8) + legend("topright", box.lty = 0, + legend = c("Prevalence for\nvaccine scenario", + "Prevalence for no\nintervention scenario"), + col = c(cols[3], cols[6]), lty = c(1, 1), + lwd = 2.5, cex = 0.8, y.intersp = 1.5) } # Plot dose timing @@ -93,12 +102,13 @@ plot_doses <- function(){ barplot(doses, xlab = "Month", ylab = "Number of doses", - col = cols[1:6], space = 0, - beside = FALSE, xaxs = "i", yaxs = "i") - grid(lty = 2, col = "grey80", lwd = 1) - axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") + col = cols[1:6], space = 0, axes = T, + beside = FALSE, xaxs = "i", yaxs = "i", + ylim = c(0, max(colSums(doses))*1.1)) + grid(lty = 2, col = "grey80", lwd = 0.5);box() + axis(side = 1, lty = 1, col = "black", pos = 0) legend("topleft", box.lty = 0, legend = c("Dose 1","Dose 2","Dose 3","Booster 1"), - col = cols[1:6], lty = rep(1, 4), lwd = 2.5, bg="transparent") + fill = cols[1:6], bg="transparent", cex = 0.8, y.intersp = 1.5) } ``` @@ -135,6 +145,8 @@ First, we will model a single round of RTS,S vaccine given in a mass vaccination We specify that the intervention should use the RTS,S vaccine through the `profile` and `booster_profile` inputs. +### Simulation + ```{r} rtssmassparams <- set_mass_pev( simparams, @@ -152,31 +164,34 @@ rtssmassparams <- set_mass_pev( output <- run_simulation(timesteps = sim_length, parameters = rtssmassparams) ``` -#### Plot clinical incidence +### Visualisation -```{r, fig.width = 8, fig.height = 5, fig.align = "center"} +```{r, fig.align = 'center', out.width='100%'} +# Plot clinical incidence plot_inci() ``` -#### Plot prevalence -```{r, fig.width = 8, fig.height = 5, fig.align = "center"} + +```{r, fig.align = 'center', out.width='100%'} +# Plot prevalence plot_prev() ``` -#### Plot doses - You can look at the distribution of doses using the `n_pev_mass_dose_*` or `n_pev_epi_dose_*` outputs. It is always a good idea to check the timing of vaccine doses to ensure that it is specified as intended. -```{r, fig.width = 8, fig.height = 5, fig.align = "center", message=FALSE} +```{r, fig.align = 'center', out.width='100%', message=FALSE} +# Plot doses plot_doses() ``` -### Seasonal mass vaccination +## Seasonal mass vaccination Mass vaccination can also be targeted seasonally. For example, we may want to have a mass vaccination campaign take place a few months prior to the peak transmission season. In the example below, we will create a parameter set with seasonality and first run a simulation with no vaccine, then run a simulation with a mass vaccination campaign targeting everyone between the ages of 5 months and 50 years. We specify that the intervention should use the RTS,S vaccine through the `profile` and `booster_profile` inputs to the `set_mass_pev()` function. +### Simulation + ```{r} # Use the get_parameters() function to generate a new parameter set with a seasonal profile with malaria incidence in children aged 0-5 rendered in the model output: seas_simparams <- get_parameters( @@ -219,20 +234,20 @@ seasmass_simparams <- set_mass_pev( output <- run_simulation(timesteps = sim_length * 2, parameters = seasmass_simparams) ``` -#### Plot clinical incidence +### Visualisation -```{r, fig.width = 8, fig.height = 5, fig.align = "center"} +```{r, fig.align = 'center', out.width='100%'} +# Plot clinical incidence plot_inci(type = "seasonal") ``` -#### Plot prevalence -```{r, fig.width = 8, fig.height = 5, fig.align = "center"} +```{r, fig.align = 'center', out.width='100%'} +# Plot prevalence plot_prev(type = "seasonal") ``` -#### Plot doses - -```{r, fig.width = 8, fig.height = 5, fig.align = "center", message=FALSE} +```{r, fig.align = 'center', out.width='100%', message=FALSE} +# Plot doses plot_doses() ``` @@ -241,6 +256,8 @@ plot_doses() We can also opt to vaccinate using the EPI strategy, where individuals will be vaccinated once they reach a certain age. In the example below, individuals will be vaccinated once they reach 5 months of age. For this intervention, we see a much more gradual impact following implementation compared to the mass vaccination strategy. Note: the model assumes that protection from the vaccine begins after the third dose. +### Simulation + ```{r} # Add RTS,S EPI strategy rtssepiparams <- set_pev_epi( @@ -264,30 +281,33 @@ rtssepiparams$pev_doses ``` -#### Plot clinical incidence +### Visualisation -```{r, fig.width = 8, fig.height = 5, fig.align = "center"} +```{r, fig.align = 'center', out.width='100%'} +# Plot clinical incidence plot_inci() ``` -#### Plot prevalence -```{r, fig.width = 8, fig.height = 5, fig.align = "center"} +```{r, fig.align = 'center', out.width='100%'} +# Plot prevalence plot_prev() ``` A limited impact upon prevalence is observed because the target population for vaccination is small relative to the entire population, resulting only in direct protection of those vaccinated. -#### Plot doses -```{r, fig.width = 8, fig.height = 5, fig.align = "center", message=FALSE} +```{r, fig.align = 'center', out.width='100%', message=FALSE} +# Plot doses plot_doses() ``` -### RTS,S EPI with seasonal boosters +## RTS,S EPI with seasonal boosters In a seasonal setting, we can set booster timesteps relative to the start of the year instead of relative to the last dose. This allows us to consider seasonal dynamics and implement booster doses right before the start of the high transmission season to maximise impact. +### Simulation + ```{r} # Calculate the peak of the transmission season based on seasonality parameters above. peak <- peak_season_offset(seas_simparams) @@ -309,25 +329,29 @@ rtssepiseasonalparams <- set_pev_epi( output <- run_simulation(timesteps = sim_length * 2, parameters = rtssepiseasonalparams) ``` -#### Plot clinical incidence -```{r, fig.width = 8, fig.height = 5, fig.align = "center"} +### Visualisation + +```{r, fig.align = 'center', out.width='100%'} +# Plot clinical incidence plot_inci(type = "seasonal") ``` -#### Plot prevalence -```{r, fig.width = 8, fig.height = 5, fig.align = "center"} +```{r, fig.align = 'center', out.width='100%'} +# Plot prevalence plot_prev(type = "seasonal") ``` -#### Plot doses -```{r, fig.width = 8, fig.height = 5, fig.align = "center", message=FALSE} +```{r, fig.align = 'center', out.width='100%', message=FALSE} +# Plot doses plot_doses() ``` -### RTS,S dosing +## RTS,S dosing We can implement different dosing schedules using the `pev_doses` parameter. Here we administer dose one at 5 months, dose two 30 days after dose one, and dose three 60 days after dose one. We also administer two booster doses 12 and 24 months following dose three. As before, it is a good idea to visualise the dose timing to ensure that the vaccine is implemented as intended. +### Simulation + ```{r} rtssepiparams2 <- set_pev_epi( simparams, @@ -346,20 +370,21 @@ rtssepiparams2$pev_doses <- c(0, 30, 60) # setting the timesteps for the 3 doses output <- run_simulation(timesteps = sim_length * 2, parameters = rtssepiparams2) ``` -#### Plot clinical incidence +### Visualisation -```{r, fig.width = 8, fig.height = 5, fig.align = "center"} +```{r, fig.align = 'center', out.width='100%'} +# Plot clinical incidence plot_inci() ``` -#### Plot prevalence -```{r, fig.width = 8, fig.height = 5, fig.align = "center"} +```{r, fig.align = 'center', out.width='100%'} +# Plot prevalence plot_prev() ``` -#### Plot doses -```{r, fig.width = 8, fig.height = 5, fig.align = "center", message=FALSE} +```{r, fig.align = 'center', out.width='100%', message=FALSE} +# Plot doses output$month <- ceiling(output$timestep / month) doses <- output[, c(2:6, 38)] doses <- aggregate(cbind(doses[1:5]), @@ -369,18 +394,21 @@ doses <- as.matrix(t(doses[, -1])) barplot(doses, xlab = "Month", ylab = "Number of doses", - col = cols[1:6], space = 0, - beside = FALSE, xaxs = "i", yaxs = "i") -grid(lty = 2, col = "grey80", lwd = 1) -axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") -legend("topleft", box.lty = 0, legend = c("Dose 1","Dose 2","Dose 3","Booster 1", "Booster 2"), - col = cols[1:6], lty = rep(1, 4), lwd = 2.5, bg = "transparent") + col = cols[1:6], space = 0, axes = T, + beside = FALSE, xaxs = "i", yaxs = "i", + ylim = c(0, max(colSums(doses))*1.1)) + grid(lty = 2, col = "grey80", lwd = 0.5);box() + axis(side = 1, lty = 1, col = "black", pos = 0) + legend("topleft", box.lty = 0, legend = c("Dose 1","Dose 2","Dose 3","Booster 1", "Booster 2"), + fill = cols[1:6], y.intersp = 1.5, bg = "transparent", cex = 0.8) ``` ## TBV We can also model a hypothetical transmission blocking vaccine (TBV). This example shows 5 rounds of a TBV to 99% of the population aged 5 and 60. +### Simulation + ```{r} tbvparams <- set_tbv( simparams, @@ -392,13 +420,14 @@ tbvparams <- set_tbv( output <- run_simulation(timesteps = sim_length, parameters = tbvparams) ``` -#### Plot clinical incidence +### Visualisation -```{r, fig.width = 8, fig.height = 5, fig.align = "center"} +```{r, fig.align = 'center', out.width='100%'} +# Plot clinical incidence plot_inci() ``` -#### Plot prevalence -```{r, fig.width = 8, fig.height = 5, fig.align = "center"} +```{r, fig.align = 'center', out.width='100%'} +# Plot prevalence plot_prev() ``` diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index 01ac82d3..b0af0a36 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -2,33 +2,32 @@ title: "Stochastic Variation" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Variation} + %\VignetteIndexEntry{Stochastic Variation} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup} +# Load the requisite packages: library(malariasimulation) +# Set colour palette: +cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") set.seed(555) ``` -`malariasimulation` is a stochastic, individual-based model and, as such, simulations run with identical parameterisations will generate non-identical, sometimes highly variable, outputs. To illustrate this, we will compare the prevalence and incidence of malaria over a year in simulations with a small and a larger population. +`malariasimulation` is a stochastic, individual-based model and, as such, simulations run with identical parameterisations will generate non-identical, sometimes highly variable, outputs. To illustrate this, we will compare the prevalence and incidence of malaria over a year in simulations with a small and a larger population. Then we will demonstrate how this variation can be estimated by running multiple simulations using the `run_simulation_with_repetitions` function. -### Plotting functions First, we will create a few plotting functions to visualise outputs. ```{r} -cols <- c("#E69F00", "#56B4E9", "#009E73", - "#F0E442", "#0072B2", "#D55E00", "#CC79A7") - plot_prev <- function(output, ylab = TRUE, ylim = c(0,1)){ if (ylab == TRUE) { ylab = "Prevalence in children aged 2-10 years" } else {ylab = ""} plot(x = output$timestep, y = output$n_detect_730_3650 / output$n_730_3650, type = "l", col = cols[3], ylim = ylim, - xlab = "Time (days)", ylab = ylab, lwd = 2, - xaxs = "i", yaxs = "i", bty = "l") - grid(lty = 2, col = "grey80", lwd = 1) + xlab = "Time (days)", ylab = ylab, lwd = 1, + xaxs = "i", yaxs = "i") + grid(lty = 2, col = "grey80", lwd = 0.5) } plot_inci <- function(output, ylab = TRUE, ylim){ @@ -37,14 +36,47 @@ plot_inci <- function(output, ylab = TRUE, ylim){ } else {ylab = ""} plot(x = output$timestep, y = output$n_inc_clinical_0_1825 / output$n_0_1825 * 1000, type = "l", col = cols[5], ylim = ylim, - xlab = "Time (days)", ylab = ylab, lwd = 2, - xaxs = "i", yaxs = "i", bty = "l") - grid(lty = 2, col = "grey80", lwd = 1) + xlab = "Time (days)", ylab = ylab, lwd = 1, + xaxs = "i", yaxs = "i") + grid(lty = 2, col = "grey80", lwd = 0.5) +} + +aggregate_function <- function(df){ + tmp <- aggregate( + df$n_detect_730_3650, + by=list(df$timestep), + FUN = function(x) { + c(median = median(x), + lowq = unname(quantile(x, probs = .25)), + highq = unname(quantile(x, probs = .75)), + mean = mean(x), + lowci = mean(x) - 1.96*sd(x), + highci = mean(x) + 1.96*sd(x) + ) + } + ) + data.frame(cbind(t = tmp$Group.1, tmp$x)) +} + +plot_variation_function <- function(df, title_str){ + plot(type="n", xlim=c(0,max(df$t)), + c(1,1), + ylim = c(-4, 14), + xaxs = "i", yaxs = "i", + xlab = 'timestep', ylab ='n_detect', main = title_str, + font.main = 1) + grid(lty = 2, col = "grey80", lwd = 0.5) + polygon(x = c(df$t,rev(df$t)), y = c(df$highci, rev(df$lowci)), col = "lightgrey", border = "lightgrey") + polygon(x = c(df$t,rev(df$t)), y = c(df$highq, rev(df$lowq)), col = "darkgrey", border = "darkgrey") + points(x = df$t, y = df$median, type = "l", ylim = c(25,40), lwd = 2) } ``` -## Parameterisation -First, we will use the `get_parameters()` function to generate a list of parameters, accepting the default values, for two different population sizes and use the `set_equilibrium()` function to initialise the model at a given entomological inoculation rate (EIR). The only parameter which changes between the two parameter sets is the argument for `human_population`. +## Variation and population size + +### Parameterisation + +We will use the `get_parameters()` function to generate a list of parameters, accepting the default values, for two different population sizes and use the `set_equilibrium()` function to initialise the model at a given entomological inoculation rate (EIR). The only parameter which changes between the two parameter sets is the argument for `human_population`. ```{r} # A small population simparams_small <- get_parameters(list( @@ -68,13 +100,13 @@ simparams_big <- set_equilibrium(parameters = simparams_big, init_EIR = 50) ``` -## Simulations +### Simulations The `n_detect_730_3650` output below shows the total number of individuals in the age group rendered (here, 730-3650 timesteps or 2-10 years) who have microscopy-detectable malaria. Notice that the output is smoother at a higher population. Some outcomes will be more sensitive than others to stochastic variation even with the same population size. In the plots below, prevalence is smoother than incidence even at the same population. This is because prevalence is a measure of existing infection, while incidence is recording new cases per timestep. -```{r, fig.align="center",fig.height=6, fig.width=8} +```{r, fig.align = 'center', out.width='100%', fig.asp=1.15} # A small population output_small_pop <- run_simulation(timesteps = 365, parameters = simparams_small) @@ -83,10 +115,10 @@ output_big_pop <- run_simulation(timesteps = 365, parameters = simparams_big) # Plotting par(mfrow = c(2,2)) -plot_prev(output_small_pop, ylim = c(0.6, 0.8)); title(expression(paste(italic(Pf),"PR"[2-10], " at n = 1,000"))) -plot_inci(output_small_pop, ylim = c(0, 25)); title("Incidence per 1000 children at n = 1,000") -plot_prev(output_big_pop, ylim = c(0.6, 0.8)); title(expression(paste(italic(Pf),"PR"[2-10], " at n = 10,000"))) -plot_inci(output_big_pop, ylim = c(0, 25)); title("Incidence per 1000 children at n = 10,000") +plot_prev(output_small_pop, ylim = c(0.5, 0.8)); title(expression(paste(italic(Pf),"PR"[2-10], " at n = 1,000"))) +plot_inci(output_small_pop, ylim = c(0, 25)); title("Incidence per 1000 children at n = 1,000", cex.main = 1, font.main = 1) +plot_prev(output_big_pop, ylim = c(0.5, 0.8)); title(expression(paste(italic(Pf),"PR"[2-10], " at n = 10,000"))) +plot_inci(output_big_pop, ylim = c(0, 25)); title("Incidence per 1000 children at n = 10,000", cex.main = 1, font.main = 1) ``` ## Stochastic elimination @@ -113,9 +145,9 @@ simparams_big <- get_parameters(list( simparams_big <- set_equilibrium(parameters = simparams_big, init_EIR = 1) ``` -## Simulations +### Simulations -```{r, fig.align="center",fig.height=6, fig.width=8} +```{r, fig.align = 'center', out.width='100%', fig.asp=0.6} set.seed(444) # A small population output_small_pop <- run_simulation(timesteps = 365 * 2, parameters = simparams_small) @@ -127,4 +159,37 @@ output_big_pop <- run_simulation(timesteps = 365 * 2, parameters = simparams_big par(mfrow = c(1, 2)) plot_prev(output_small_pop, ylim = c(0, 0.2)); title(expression(paste(italic(Pf),"PR"[2-10], " at n = 50"))) plot_prev(output_big_pop, ylab = FALSE, ylim = c(0, 0.2)); title(expression(paste(italic(Pf),"PR"[2-10], " at n = 1,000"))) -``` \ No newline at end of file +``` + + +## Estimating variation + +We can estimate the variation in the number of detectable cases by repeating the simulation several times using the `run_simulation_with_repetitions()` function. The functions requires arguments for `repetitions` (the number of repeat simulations) and the option of whether to run simulations in parallel (where available: `parallel = T`), in addition to the standard timesteps and parameter list. + +```{r, fig.align = 'center', out.width='100%', fig.asp=0.55} +simparams <- get_parameters() |> set_equilibrium(init_EIR = 1) + +output_few_reps <- run_simulation_with_repetitions( + timesteps = 365, + repetitions = 5, + overrides = simparams, + parallel=TRUE +) + +output_many_reps <- run_simulation_with_repetitions( + timesteps = 365, + repetitions = 50, + overrides = simparams, + parallel=TRUE +) + +# Aggregate the data +df_few <- aggregate_function(output_few_reps) +df_many <- aggregate_function(output_many_reps) + +par(mfrow = c(1,2)) +plot_variation_function(df = df_few, title_str = "Repetitions = 5") +legend("topleft", legend = c("Median", "IQR", "95% CI"), ncol = 1, + fill = c("black", "darkgrey","lightgrey"), cex = 0.8, bty = "n") +plot_variation_function(df = df_many, title_str = "Repetitions = 50") +``` diff --git a/vignettes/VectorControl_Bednets.Rmd b/vignettes/VectorControl_Bednets.Rmd index 17fafa90..f65d5ca7 100644 --- a/vignettes/VectorControl_Bednets.Rmd +++ b/vignettes/VectorControl_Bednets.Rmd @@ -1,6 +1,7 @@ --- title: "Vector Control: Bed nets" -output: rmarkdown::html_vignette +output: + rmarkdown::html_vignette: vignette: > %\VignetteIndexEntry{Vector Control: Bed nets} %\VignetteEngine{knitr::rmarkdown} @@ -15,32 +16,35 @@ knitr::opts_chunk$set( ``` ```{r setup} +# Load the requisite packages: library(malariasimulation) +# Set colour palette: +cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") ``` Long-lasting insecticide-treated bed nets are a highly effective intervention to prevent malaria. The effects of insecticide-treated bed net distribution campaigns can be simulated using `malariasimulation`. The model provides the user with the flexibility to specify parameters that describe the net distribution campaign (e.g. timing, coverage, and target population) and the bed nets distributed (e.g. efficacy, longevity). We will illustrate this through an example with two bed net distributions, once per year. -### Plotting functions We can create a few plotting functions to visualise the output. ```{r} -cols <- c("#E69F00", "#56B4E9", "#009E73", - "#F0E442", "#0072B2", "#D55E00", "#CC79A7") - # Plotting functions plot_prev <- function() { plot(x = output$timestep, y = output$n_detect_730_3650 / output$n_730_3650, - type = "l", col = cols[3], lwd = 2.5, + type = "l", col = cols[3], lwd = 1, xlab = "Time (days)", ylab = expression(paste(italic(Pf),"PR"[2-10])), - xaxs = "i", yaxs = "i", bty = "l", ylim = c(0, 1)) + xaxs = "i", yaxs = "i", ylim = c(0, 1)) lines(x = output_control$timestep, y = output_control$n_detect_730_3650 / output_control$n_730_3650, - col = cols[5], lwd = 2.5) - abline(v = bednetstimesteps, col = "black", lty = 2, lwd = 2.5) - grid(lty = 2, col = "grey80", lwd = 1) - legend("bottomleft", box.lty = 0, legend = c("Bed nets","Prevalence for bed net scenario","Prevalence for control scenario"), - col = c("black", cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) + col = cols[5], lwd = 1) + abline(v = bednetstimesteps, col = "black", lty = 2, lwd = 1) + text(x = bednetstimesteps + 10, y = 0.95, labels = "Bed net int.", adj = 0, cex = 0.8) + grid(lty = 2, col = "grey80", lwd = 0.5) + legend("bottomleft", box.lty = 0, bg = "white", + legend = c("Prevalence for bed net scenario","Prevalence for control scenario"), + col = c(cols[3], cols[5]), lty = c(1,1), lwd = 2, cex = 0.8, y.intersp = 1.3) } ``` +## Setting bed net parameters + ### Parameterisation Use the `get_parameters()` function to generate the list of parameters for a perennial profile, accepting the default values to run the simulation from an equilibrium starting point. @@ -61,22 +65,22 @@ output_control <- run_simulation(timesteps = sim_length, parameters = simparams) ``` #### A note on mosquito species -It is also possible to use the `set_species()` function to account for 3 different mosquito species in the simulation. In this case, the matrices would need to have additional column corresponding to each mosquito species. For example, if we specified that there were 3 species of mosquitoes in the model and nets were distributed at two timesteps, then the matrices would have 2 rows and 3 columns. If you are not already familiar with the `set_species()` function, see the Mosquito Species vignette. +It is also possible to use the `set_species()` function to account for 3 different mosquito species in the simulation. In this case, the matrices would need to have additional column corresponding to each mosquito species. For example, if we specified that there were 3 species of mosquitoes in the model and nets were distributed at two timesteps, then the matrices would have 2 rows and 3 columns. If you are not already familiar with the `set_species()` function, see the [Mosquito Species](https://mrc-ide.github.io/malariasimulation/articles/SetSpecies.html) vignette. -The default setting is to model all mosquito species together. +The default parameters are set to model *Anopheles gambiae*. ```{r} simparams$species simparams$species_proportions ``` -## Simulation +### Simulation Having established a base set of parameters, we can now create a copy of this parameter list and update it to specify a net distribution campaign. In the example below, we distribute bed nets to a random 50% of the population every three years. It is possible to change the characteristics of the bed nets for each distribution timestep if different types of bed nets are distributed that have different insecticides, different levels of insecticide resistance, etc. This can be done by modifying the matrices for `dn0`, `rn`, `rnm`, and `gamman`. Because we are using the default proportions of mosquito species and there are two timesteps when nets are distributed, the matrices for `dn0`, `rn`, and `rnm` have 1 column and 2 rows. The parameter values for pyrethroid-only and pyrethroid-PBO nets at various resistance levels can be found in Table S1.3 in the Supplementary Appendix 2 of [Sherrard-Smith, et al., 2022](https://doi.org/10.1016/S2542-5196(21)00296-5). -```{r, fig.align="center", fig.height=4, fig.width=6} +```{r, fig.align = 'center', out.width='100%'} bednetstimesteps <- c(1, 4) * year # The bed nets will be distributed at the end of the first and the 4th year. bednetparams <- set_bednets( @@ -93,12 +97,14 @@ bednetparams <- set_bednets( output <- run_simulation(timesteps = sim_length, parameters = bednetparams) ``` -### Plot prevalence -```{r, fig.align="center", fig.height=5, fig.width=7} +### Visualisation + +```{r, fig.align = 'center', out.width='100%'} +# Plot prevalence plot_prev() ``` -## Comparing input coverage and population bed net usage +### Comparing coverage and population bed net usage It is important to understand the difference between the input `coverages` argument of `set_bednets()` and the resulting population bed net usage over time in the model. When we set coverages in the above example to 0.5, we are telling the model to distribute bed nets to a random 50% of the population at year one and to a random 50% of the population at year 4. However, the level of average bed net usage is not necessarily equal to 50%. Between these time points, bed net use will slowly decline over time (in reality this decline stems from things like disuse, holes in nets, lost nets, etc.). @@ -110,18 +116,18 @@ The average population bed net usage will be influenced by: The output from `malariasimulation::run_simulation()` has a variable `n_use_net` that shows the number of people using bed nets at any given timestep. We can visualise the proportion of the population using bed nets over time to understand how bed net usage changes. -```{r, fig.align="center", fig.height=5, fig.width=7} +```{r, fig.align = 'center', out.width='100%'} output$prop_use_net <- output$n_use_net / human_population plot(x = output$timestep, y = output$prop_use_net, type = "l", col = cols[3], lwd = 2.5, ylim = c(0,1), xlab = "Timestep (days)", ylab = "Proportion of population using bed nets", - xaxs = "i", yaxs = "i", bty = "l") -grid(lty = 2, col = "grey80", lwd = 1) + xaxs = "i", yaxs = "i") +grid(lty = 2, col = "grey80", lwd = 0.5) axis(side = 1, lty = 1, col = "black", pos = 0); axis(side = 2, lty = 1, col = "black") ``` -## Using the `netz` package to estimate coverage inputs needed to achieve target population usage +## Using the `netz` package The [`netz` package](https://mrc-ide.github.io/netz/index.html) is a useful tool to help set up bed nets in `malariasimulation`. `malariasimulation` takes as an input the proportion of the population who were distributed a bed net at specific time points, but net distribution or use data are now always available for a specific region or country. `netz` has functionality to estimate modelled population usage over time in the simulation for a given set of input distributions. It can also help to fit the input coverages to usage data. diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index deff5ada..2527c72a 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -2,7 +2,7 @@ title: "Vector Control: Indoor Residual Spraying" output: rmarkdown::html_vignette vignette: > - %\VignetteIndexEntry{Vector Control: IRS} + %\VignetteIndexEntry{Vector Control: Indoor Residual Spraying} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- @@ -15,33 +15,36 @@ knitr::opts_chunk$set( ``` ```{r setup} +# Load the requisite packages: library(malariasimulation) library(malariaEquilibrium) +# Set colour palette: +cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") ``` Indoor Residual Spraying (IRS) involves periodically treating indoor walls with insecticides to eliminate adult female mosquitoes that rest indoors. `malariasimulation` can be used to investigate the effect of malaria control strategies that deploy IRS. Users can set IRS in the model using the `set_spraying()` function to parameterise the time and coverage of spraying campaigns. -### Plotting functions We will create a few plotting functions to visualise the output. ```{r} -cols <- c("#E69F00", "#56B4E9", "#009E73", - "#F0E442", "#0072B2", "#D55E00", "#CC79A7") - # Plotting functions plot_prev <- function() { plot(x = output$timestep, y = output$n_detect_730_3650 / output$n_730_3650, - type = "l", col = cols[3], lwd = 2.5, + type = "l", col = cols[3], lwd = 1, xlab = "Time (days)", ylab = expression(paste(italic(Pf),"PR"[2-10])), - xaxs = "i", yaxs = "i", bty = "l", ylim = c(0,1)) + xaxs = "i", yaxs = "i", ylim = c(0,1)) lines(x = output_control$timestep, y = output_control$n_detect_730_3650 / output_control$n_730_3650, - col = cols[5], lwd = 2.5) - abline(v = sprayingtimesteps, lty = 2, lwd = 2.5, col = "black") - grid(lty = 2, col = "grey80", lwd = 1) - legend("bottomleft", box.lty = 0, legend = c("Spraying", "Prevalence for IRS scenario","Prevalence for control scenario"), - col = c("black", cols[3], cols[5]), lty = c(2,1,1), lwd = 2.5) + col = cols[5], lwd = 1) + abline(v = sprayingtimesteps, lty = 2, lwd = 1, col = "black") + text(x = sprayingtimesteps + 10, y = 0.9, labels = "Spraying\nint.", adj = 0, cex = 0.8) + grid(lty = 2, col = "grey80", lwd = 0.5) + legend("bottomleft", box.lty = 0, + legend = c("Prevalence for IRS scenario","Prevalence for control scenario"), + col = c(cols[3], cols[5]), lty = c(1,1), lwd = 2, cex = 0.8, y.intersp = 1.3) } ``` +## Setting IRS parameters + ### Parameterisation Use the `get_parameters()` function to generate a list of parameters, accepting most of the default values, but modifying seasonality values to model a seasonal setting. Then, we use the `set_equilibrium()` function to to initialise the model at a given entomological innoculation rate (EIR). @@ -71,22 +74,22 @@ output_control <- run_simulation(timesteps = sim_length, parameters = simparams) ``` #### A note on mosquito species -It is also possible to use the `set_species()` function to account for 3 different mosquito species in the simulation. In this case, the matrices would need to have additional column corresponding to each mosquito species. For example, if we specified that there were 3 species of mosquitoes in the model and nets were distributed at two timesteps, then the matrices would have 2 rows and 3 columns. If you are not already familiar with the `set_species()` function, see the Mosquito Species vignette. +It is also possible to use the `set_species()` function to account for 3 different mosquito species in the simulation. In this case, the matrices would need to have additional column corresponding to each mosquito species. For example, if we specified that there were 3 species of mosquitoes in the model and nets were distributed at two timesteps, then the matrices would have 2 rows and 3 columns. If you are not already familiar with the `set_species()` function, see the [Mosquito Species](https://mrc-ide.github.io/malariasimulation/articles/SetSpecies.html) vignette. -The default setting is to model all mosquito species together. +The default parameters are set to model *Anopheles gambiae*. ```{r} simparams$species simparams$species_proportions ``` -## Simulation +### Simulation -Then we can run the simulations for a variety of IRS strategies. In the example below, there are two rounds of IRS, the first at 30% coverage and the second at 80% coverage, each 3 months prior to peak rainfall for that year. The function `peak_season_offset()` outputs a timestep when peak rainfall will be observed based on the seasonality profile we set above. Notice that the matrices specified for the parameters for `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` have two rows, one for each timestep where IRS is implemented, and a number of columns corresponding to mosquito species. In this example, we only have 1 column because the species is set to "All" as we saw above. +Then we can run the simulations for a variety of IRS strategies. In the example below, there are two rounds of IRS, the first at 30% coverage and the second at 80% coverage, each 3 months prior to peak rainfall for that year. The function `peak_season_offset()` outputs a timestep when peak rainfall will be observed based on the seasonality profile we set above. Notice that the matrices specified for the parameters for `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` have two rows, one for each timestep where IRS is implemented, and a number of columns corresponding to mosquito species. In this example, we only have 1 column because the species is set to "gamb" as we saw above. The structure for IRS model is documented in the supplementary information from Table 3 in the Supplementary Information of [Sherrard-Smith et al., 2018](https://doi.org/10.1038/s41467-018-07357-w). Table S2.1 in the Supplementary Appendix of [Sherrard-Smith et al., 2022](https://doi.org/10.1016/S2542-5196(21)00296-5) has parameter estimates for insecticide resistance for IRS. -```{r, fig.align="center", fig.height=4, fig.width=6} +```{r, fig.align = 'center', out.width='100%'} peak <- peak_season_offset(simparams) sprayingtimesteps <- c(1, 2) * year + peak - 3 * month # A round of IRS is implemented in the 1st and second year 3 months prior to peak transmission. @@ -107,8 +110,10 @@ output <- run_simulation(timesteps = sim_length, parameters = sprayingparams) ``` -### Plot prevalence -```{r,fig.align="center", fig.height=5, fig.width=7} +#### Visualisation + +```{r, fig.align = 'center', out.width='100%'} +# Plot prevalence plot_prev() ``` From 1fc22dc2f6e044038976d5687a21da80e2323d35 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Tue, 27 Jun 2023 12:30:15 +0100 Subject: [PATCH 108/164] Typos corrected in vignettes --- vignettes/Demography.Rmd | 8 ++++---- vignettes/EIRprevmatch.Rmd | 6 +++--- vignettes/MDA.Rmd | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/vignettes/Demography.Rmd b/vignettes/Demography.Rmd index c57175f9..00e2246e 100644 --- a/vignettes/Demography.Rmd +++ b/vignettes/Demography.Rmd @@ -25,7 +25,7 @@ The dynamics of malaria transmission, and the efficacy of interventions designed ## Age group rendering -First, we'll establish a base set of parameters using the `get_parameters()` function and accept the default values. The `run_simulation()` function's default behaviour is to output only the number of individuals aged 2-10 years old (`output$n_730_3650`, where 730 and 3650 are the ages in days). However, the user can instruct the model to output the number of individuals in age groups of their choosing using the `age_group_rendering_min_ages` and `age_group_rendering_max_ages` parameters. These arguments take vectors containing the minimum and maximum ages (in daily time steps) of each age group to be rendered To allow us to see the effect of changing demographic parameters, we'll use this functionality to output the number of individuals in ages groups ranging from 0 to 85 at 5 year intervals. Note that the same is possible for other model outputs using their equivalent min/max age-class rendering arguments (`n_detect` , `p_detect`, `n_severe`, `n_inc`, `p_inc`, `n_inc_clinical`, `p_inc_clinical`, `n_inc_severe`, and `p_inc_severe`, run `?run_simulation()` for more detail). +First, we'll establish a base set of parameters using the `get_parameters()` function and accept the default values. The `run_simulation()` function's default behaviour is to output only the number of individuals aged 2-10 years old (`output$n_730_3650`, where 730 and 3650 are the ages in days). However, the user can instruct the model to output the number of individuals in age groups of their choosing using the `age_group_rendering_min_ages` and `age_group_rendering_max_ages` parameters. These arguments take vectors containing the minimum and maximum ages (in daily time steps) of each age group to be rendered. To allow us to see the effect of changing demographic parameters, we'll use this functionality to output the number of individuals in ages groups ranging from 0 to 85 at 5 year intervals. Note that the same is possible for other model outputs using their equivalent min/max age-class rendering arguments (`n_detect` , `p_detect`, `n_severe`, `n_inc`, `p_inc`, `n_inc_clinical`, `p_inc_clinical`, `n_inc_severe`, and `p_inc_severe`, run `?run_simulation()` for more detail). We next use the `set_equilibrium()` function to tune the initial parameter set to those required to observe the specified initial entomological inoculation rate (`starting_EIR`) at equilibrium. We now have a set of default parameters ready to use to run simulations. @@ -58,7 +58,7 @@ simparams <- set_equilibrium(simparams, starting_EIR) ## Set custom demography -Next, we'll use the the in-built `set_demography()` function to specify human death rates by age group. This function accepts as inputs a parameter list to update, a vector of the age groups (in days) for which we specify death rates, a vector of time steps in which we want the death rates to be updated, and a matrix containing the death rates for each age group in each timestep. The `set_demography()` function appends these to the parameter list and updates the `custom_demography` parameter to `TRUE`. Here, we instruct the model to implement these changes to the demographic parameters at the beginning of the simulation (`timesteps = 0`). +Next, we'll use the in-built `set_demography()` function to specify human death rates by age group. This function accepts as inputs a parameter list to update, a vector of the age groups (in days) for which we specify death rates, a vector of time steps in which we want the death rates to be updated, and a matrix containing the death rates for each age group in each timestep. The `set_demography()` function appends these to the parameter list and updates the `custom_demography` parameter to `TRUE`. Here, we instruct the model to implement these changes to the demographic parameters at the beginning of the simulation (`timesteps = 0`). ```{r} # Copy the simulation parameters as demography parameters: @@ -91,7 +91,7 @@ dem_params$custom_demography ### Simulation -Having established parameter sets with both default and custom demographic parameterisations, we can now run a simulation for each using the `run_simulation()` function. We'll also add a column to each identify the runs. +Having established parameter sets with both default and custom demographic parameterisations, we can now run a simulation for each using the `run_simulation()` function. We'll also add a column to each to identify the runs. ```{r} # Run the simulation with the default demographic set-up: @@ -105,7 +105,7 @@ custom_output$run <- 'custom' ### Visualisation -Using barplots, we can visualise the effect of altering the demographic parameters by comparing the distribution of people among the age-classes we instructed the model to output on the final day of the simulation. The default demography is depicted in blue, while the custom demography is given in orange. Under the custom demography, the frequency in individuals in older age classes declines almost linearly, while in the default demography the number of individuals in each age class declines exponentially with age. +Using barplots, we can visualise the effect of altering the demographic parameters by comparing the distribution of people among the age-classes we instructed the model to output on the final day of the simulation. The default demography is depicted in blue, while the custom demography is given in orange. Under the custom demography, the frequency of individuals in older age classes declines almost linearly, while in the default demography the number of individuals in each age class declines exponentially with age. ```{r, fig.align = 'center', out.width='100%', fig.asp=0.5} # Combine the two dataframes: diff --git a/vignettes/EIRprevmatch.Rmd b/vignettes/EIRprevmatch.Rmd index 9299bded..dd5e4a4d 100644 --- a/vignettes/EIRprevmatch.Rmd +++ b/vignettes/EIRprevmatch.Rmd @@ -31,7 +31,7 @@ The first and fastest method uses the `malariaEquilibrium` package function `hum ## *Pf*PR~2-10~ matching using malariaEquilibrium -The `malariaEquilibrium` package function `human_equilibrium()` returns the canonical equilibrium solution for a given EIR and the *Pf*PR~2-10~ can be calculated the output (see for more information). The first step is to generate a large range of EIR values to generate matching *Pf*PR~2-10~ values for. Next, we load the package's default parameter set, specify an effective clinical treatment coverage (`ft`) of 0.45 and, for each EIR value generated, run the `human_equilibrium()` function. +The `malariaEquilibrium` package function `human_equilibrium()` returns the canonical equilibrium solution for a given EIR and the *Pf*PR~2-10~ can be calculated from the output (see for more information). The first step is to generate a large range of EIR values to generate matching *Pf*PR~2-10~ values for. Next, we load the package's default parameter set, specify an effective clinical treatment coverage (`ft`) of 0.45 and, for each EIR value generated, run the `human_equilibrium()` function. The `human_equilibrium()` function returns a dataframe containing the proportion of each age class in each state variable at equilibrium. The *Pf*PR~2-10~ can be calculated from the output for each EIR value by summing the proportion of people aged 2-10 with cases of malaria (`pos_M`) and dividing this proportion by the proportion of the population between the ages 2-10 (`prop`). Finally, we store the matching EIR and *Pf*PR~2-10~ values in a data frame. @@ -69,7 +69,7 @@ As this method does not involve running simulations it can return matching *Pf*P ## *Pf*PR~2-10~ matching using malariasimulation -Where the `malariaEquilibrium` method is not viable, an alternative is to run `malariasimulation` simulations over a smaller range of initial EIR values, extract the PfPR2-10 from each run, fit a model relating initial EIR to PfPR2-10, and use the model to predict the initial EIR value required to yield the desired PfPR2-10. This approach allows users to benefit from the tremendous flexibility in human population, mosquito population, and intervention package parameters afforded by the `malariasimulation` package. An example of this method is outlined below. +Where the `malariaEquilibrium` method is not viable, an alternative is to run `malariasimulation` simulations over a smaller range of initial EIR values, extract the *Pf*PR~2-10~ from each run, fit a model relating initial EIR to *Pf*PR~2-10~, and use the model to predict the initial EIR value required to yield the desired *Pf*PR~2-10~. This approach allows users to benefit from the tremendous flexibility in human population, mosquito population, and intervention package parameters afforded by the `malariasimulation` package. An example of this method is outlined below. ### Establish malariasimulation parameters @@ -192,7 +192,7 @@ malSim_fit <- cbind(malSim_fit, data.frame(init_EIR = c(0 ,seq(0.1, 50, 0.1)))) ## Visualisation -Let's visually compare our the `malariaEquilibrium` and `malariasimulation` methods for matching EIR to *Pf*PR~2-10~ values. In the section below we open a blank plot, plot the initial EIR and resulting *Pf*PR~2-10~ points generated using `malariasimulation` runs and overlay the line of best fit (orange line). Also overlayed is a line mapping EIR and *Pf*PR~2-10~ values calculated using `malariaEquilibrium` (blue line). +Let's visually compare the `malariaEquilibrium` and `malariasimulation` methods for matching EIR to *Pf*PR~2-10~ values. In the section below we open a blank plot, plot the initial EIR and resulting *Pf*PR~2-10~ points generated using `malariasimulation` runs and overlay the line of best fit (orange line). Also overlayed is a line mapping EIR and *Pf*PR~2-10~ values calculated using `malariaEquilibrium` (blue line). ```{r, eval = F} # Establish a plotting window: diff --git a/vignettes/MDA.Rmd b/vignettes/MDA.Rmd index 1993c60e..95124c2d 100644 --- a/vignettes/MDA.Rmd +++ b/vignettes/MDA.Rmd @@ -171,7 +171,7 @@ To demonstrate how to simulate SMC in `malariasimulation` , in the following sec ### Interventions -While the first step would typically be to establish the base set of parameters, we can use those stored earlier in `simparams`. We first store a copy of these base parameters and then use `set_drugs()` to store the preset parameters for SP-AQ in the parameter list. As SMC is conducted during the peak malaria season, we need to use the `peak_season_offset()` function to determine when the peak malaria season occurs given our specified seasonal profile. This function reads in the parameter list, uses `g0`, `g`, `h`, and `rainfall_floor` to generate the rainfall profile for a single year, and returns the day on which the maximum rainfall value occurs. We can then take this calculated seasonal peak and time SMC events around it. Here, we've specified four monthly drug administration days per year starting two months before the seasonal peak. To illustrate this, we can plot the total adult mosquito population size through time which, in the absence of interventions targeting mosquitoes, will closely matches the rainfall pattern, and overlay both the annual seasonal peak and planned SMC events. Once we're happy with our SMC campaign, we use the `set_smc()` function to update the parameter list with our `drug`, `timesteps`, `coverages` and target age group (`min_ages` and `max_ages`). +While the first step would typically be to establish the base set of parameters, we can use those stored earlier in `simparams`. We first store a copy of these base parameters and then use `set_drugs()` to store the preset parameters for SP-AQ in the parameter list. As SMC is conducted during the peak malaria season, we need to use the `peak_season_offset()` function to determine when the peak malaria season occurs given our specified seasonal profile. This function reads in the parameter list, uses `g0`, `g`, `h`, and `rainfall_floor` to generate the rainfall profile for a single year, and returns the day on which the maximum rainfall value occurs. We can then take this calculated seasonal peak and time SMC events around it. Here, we've specified four monthly drug administration days per year starting two months before the seasonal peak. To illustrate this, we can plot the total adult mosquito population size through time which, in the absence of interventions targeting mosquitoes, will closely match the rainfall pattern, and overlay both the annual seasonal peak and planned SMC events. Once we're happy with our SMC campaign, we use the `set_smc()` function to update the parameter list with our `drug`, `timesteps`, `coverages` and target age group (`min_ages` and `max_ages`). ```{r, fig.align = 'center', out.width='100%'} # Copy the original simulation parameters From 8084690345a7496fd1d376ba07c78f892c1eac09 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Tue, 27 Jun 2023 12:39:10 +0100 Subject: [PATCH 109/164] Extra missing typo! --- vignettes/EIRprevmatch.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/EIRprevmatch.Rmd b/vignettes/EIRprevmatch.Rmd index dd5e4a4d..33609bde 100644 --- a/vignettes/EIRprevmatch.Rmd +++ b/vignettes/EIRprevmatch.Rmd @@ -31,7 +31,7 @@ The first and fastest method uses the `malariaEquilibrium` package function `hum ## *Pf*PR~2-10~ matching using malariaEquilibrium -The `malariaEquilibrium` package function `human_equilibrium()` returns the canonical equilibrium solution for a given EIR and the *Pf*PR~2-10~ can be calculated from the output (see for more information). The first step is to generate a large range of EIR values to generate matching *Pf*PR~2-10~ values for. Next, we load the package's default parameter set, specify an effective clinical treatment coverage (`ft`) of 0.45 and, for each EIR value generated, run the `human_equilibrium()` function. +The `malariaEquilibrium` package function `human_equilibrium()` returns the canonical equilibrium solution for a given EIR and the *Pf*PR~2-10~ can be calculated from the output (see for more information). The first step is to set a large range of EIR values to generate matching *Pf*PR~2-10~ values for. Next, we load the package's default parameter set, specify an effective clinical treatment coverage (`ft`) of 0.45 and, for each EIR value generated, run the `human_equilibrium()` function. The `human_equilibrium()` function returns a dataframe containing the proportion of each age class in each state variable at equilibrium. The *Pf*PR~2-10~ can be calculated from the output for each EIR value by summing the proportion of people aged 2-10 with cases of malaria (`pos_M`) and dividing this proportion by the proportion of the population between the ages 2-10 (`prop`). Finally, we store the matching EIR and *Pf*PR~2-10~ values in a data frame. From ace54d5aa5248cc1bd7e0856a1161c2f7f0ffb10 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Tue, 27 Jun 2023 16:52:47 +0100 Subject: [PATCH 110/164] Another typo and a vignette plot colour change --- vignettes/EIRprevmatch.Rmd | 2 +- vignettes/Variation.Rmd | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/vignettes/EIRprevmatch.Rmd b/vignettes/EIRprevmatch.Rmd index 33609bde..32123b5f 100644 --- a/vignettes/EIRprevmatch.Rmd +++ b/vignettes/EIRprevmatch.Rmd @@ -309,7 +309,7 @@ malsim_EIR <- match_EIR_to_PfPR(x = target_pfpr) The `calibrate()` function is a useful tool, but be aware that it relies on the user selecting and accurately coding an effective summary function, providing reasonable bounds on the EIR space to explore, and selecting a population size sufficiently large to limit the influence of stochasticity. -As a final exercise, let's compare graphically the `calibrate()` approach with the `malariasimulation` method when the same parameter set is used. The plot below shows the change in *Pf*PR~2-10~ over the duration of the simulation under the initial EIR values recommended by the a) `cali` and b) `malariasimulation` methods to achieve the target *Pf*PR~2-10~ value of 0.3. The blue horizontal line represents the target *Pf*PR~2-10~ and the black lines either side the upper and lower tolerance limits specified for the `cali` method. +As a final exercise, let's compare graphically the `calibrate()` approach with the `malariasimulation` method when the same parameter set is used. The plot below shows the change in *Pf*PR~2-10~ over the duration of the simulation under the initial EIR values recommended by the a) `cali` and b) `malariasimulation` methods to achieve the target *Pf*PR~2-10~ value of 0.3. The blue horizontal line represents the target *Pf*PR~2-10~ and the black lines either side are the upper and lower tolerance limits specified for the `cali` method. ```{r, eval = F} # Use the set_equilibrium() function to calibrate the simulation parameters to the EIR: diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index b0af0a36..a1157bae 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -63,12 +63,12 @@ plot_variation_function <- function(df, title_str){ c(1,1), ylim = c(-4, 14), xaxs = "i", yaxs = "i", - xlab = 'timestep', ylab ='n_detect', main = title_str, + xlab = 'timestep', ylab ='Light miscroscopy detectable infections', main = title_str, font.main = 1) grid(lty = 2, col = "grey80", lwd = 0.5) - polygon(x = c(df$t,rev(df$t)), y = c(df$highci, rev(df$lowci)), col = "lightgrey", border = "lightgrey") - polygon(x = c(df$t,rev(df$t)), y = c(df$highq, rev(df$lowq)), col = "darkgrey", border = "darkgrey") - points(x = df$t, y = df$median, type = "l", ylim = c(25,40), lwd = 2) + polygon(x = c(df$t,rev(df$t)), y = c(df$highci, rev(df$lowci)), col = cols[2], border = cols[2]) + polygon(x = c(df$t,rev(df$t)), y = c(df$highq, rev(df$lowq)), col = cols[5], border = cols[5]) + points(x = df$t, y = df$median, type = "l", ylim = c(25,40), lwd = 2, col = "black") } ``` @@ -190,6 +190,6 @@ df_many <- aggregate_function(output_many_reps) par(mfrow = c(1,2)) plot_variation_function(df = df_few, title_str = "Repetitions = 5") legend("topleft", legend = c("Median", "IQR", "95% CI"), ncol = 1, - fill = c("black", "darkgrey","lightgrey"), cex = 0.8, bty = "n") + fill = c("black", cols[5], cols[2]), cex = 0.8, bty = "n") plot_variation_function(df = df_many, title_str = "Repetitions = 50") ``` From 9bfdcfee86b7eb6dc51e3d7919582237b90bf45d Mon Sep 17 00:00:00 2001 From: Hillary Topazian <80535782+htopazian@users.noreply.github.com> Date: Wed, 28 Jun 2023 12:07:38 +0100 Subject: [PATCH 111/164] fixing typo in PMC parameters --- R/mda_parameters.R | 8 ++++---- man/CorrelationParameters.Rd | 36 ++++++++++++++++++------------------ man/set_pmc.Rd | 4 ++-- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/R/mda_parameters.R b/R/mda_parameters.R index a07d7e70..6e48cea2 100644 --- a/R/mda_parameters.R +++ b/R/mda_parameters.R @@ -26,7 +26,7 @@ set_mda <- function( if(length(max_ages) != length(timesteps)){ stop("maximum ages and timesteps do no align") } - + parameters$mda <- TRUE parameters$mda_drug <- drug parameters$mda_timesteps <- timesteps @@ -64,7 +64,7 @@ set_smc <- function( if(length(max_ages) != length(timesteps)){ stop("maximum ages and timesteps do no align") } - + parameters$smc <- TRUE parameters$smc_drug <- drug parameters$smc_timesteps <- timesteps @@ -74,7 +74,7 @@ set_smc <- function( parameters } -#' @title Parameterise a perennial malaria chemoprevention (PMC, formerly IPIi) +#' @title Parameterise a perennial malaria chemoprevention (PMC, formerly IPTi) #' @param parameters a list of parameters to modify #' @param drug the index of the drug to administer #' @param timesteps a vector of timesteps for each round of PMC @@ -95,7 +95,7 @@ set_pmc <- function( } # check that the drug is valid stopifnot((drug > 0) && (drug <= length(parameters$drug_rel_c))) - + parameters$pmc <- TRUE parameters$pmc_drug <- drug parameters$pmc_timesteps <- timesteps diff --git a/man/CorrelationParameters.Rd b/man/CorrelationParameters.Rd index b1d22578..c2e6ada7 100644 --- a/man/CorrelationParameters.Rd +++ b/man/CorrelationParameters.Rd @@ -14,17 +14,17 @@ Describes an event in the simulation \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{CorrelationParameters$new()}} -\item \href{#method-inter_round_rho}{\code{CorrelationParameters$inter_round_rho()}} -\item \href{#method-inter_intervention_rho}{\code{CorrelationParameters$inter_intervention_rho()}} -\item \href{#method-sigma}{\code{CorrelationParameters$sigma()}} -\item \href{#method-mvnorm}{\code{CorrelationParameters$mvnorm()}} -\item \href{#method-clone}{\code{CorrelationParameters$clone()}} +\item \href{#method-CorrelationParameters-new}{\code{CorrelationParameters$new()}} +\item \href{#method-CorrelationParameters-inter_round_rho}{\code{CorrelationParameters$inter_round_rho()}} +\item \href{#method-CorrelationParameters-inter_intervention_rho}{\code{CorrelationParameters$inter_intervention_rho()}} +\item \href{#method-CorrelationParameters-sigma}{\code{CorrelationParameters$sigma()}} +\item \href{#method-CorrelationParameters-mvnorm}{\code{CorrelationParameters$mvnorm()}} +\item \href{#method-CorrelationParameters-clone}{\code{CorrelationParameters$clone()}} } } \if{html}{\out{


}} -\if{html}{\out{
}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-CorrelationParameters-new}{}}} \subsection{Method \code{new()}}{ initialise correlation parameters \subsection{Usage}{ @@ -40,8 +40,8 @@ initialise correlation parameters } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-inter_round_rho}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-CorrelationParameters-inter_round_rho}{}}} \subsection{Method \code{inter_round_rho()}}{ Add rho between rounds \subsection{Usage}{ @@ -60,8 +60,8 @@ the intervention} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-inter_intervention_rho}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-CorrelationParameters-inter_intervention_rho}{}}} \subsection{Method \code{inter_intervention_rho()}}{ Add rho between interventions \subsection{Usage}{ @@ -83,8 +83,8 @@ the intervention} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-sigma}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-CorrelationParameters-sigma}{}}} \subsection{Method \code{sigma()}}{ Standard deviation of each intervention between rounds \subsection{Usage}{ @@ -93,8 +93,8 @@ Standard deviation of each intervention between rounds } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-mvnorm}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-CorrelationParameters-mvnorm}{}}} \subsection{Method \code{mvnorm()}}{ multivariate norm draws for these parameters \subsection{Usage}{ @@ -103,8 +103,8 @@ multivariate norm draws for these parameters } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-CorrelationParameters-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/set_pmc.Rd b/man/set_pmc.Rd index 62625c04..bae5269a 100644 --- a/man/set_pmc.Rd +++ b/man/set_pmc.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/mda_parameters.R \name{set_pmc} \alias{set_pmc} -\title{Parameterise a perennial malaria chemoprevention (PMC, formerly IPIi)} +\title{Parameterise a perennial malaria chemoprevention (PMC, formerly IPTi)} \usage{ set_pmc(parameters, drug, timesteps, coverages, ages) } @@ -19,5 +19,5 @@ round} \item{ages}{a vector of ages at which PMC is administered (in timesteps)} } \description{ -Parameterise a perennial malaria chemoprevention (PMC, formerly IPIi) +Parameterise a perennial malaria chemoprevention (PMC, formerly IPTi) } From 42d49e9312ed3eceb57e1194e01fd37d265ad303 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Wed, 28 Jun 2023 14:46:06 +0100 Subject: [PATCH 112/164] Corrected a number of vignette typos. Colours of variation vignette plot. --- vignettes/Demography.Rmd | 2 +- vignettes/MDA.Rmd | 2 +- vignettes/Model.Rmd | 8 ++++---- vignettes/VectorControl_IRS.Rmd | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/vignettes/Demography.Rmd b/vignettes/Demography.Rmd index 00e2246e..b42e243f 100644 --- a/vignettes/Demography.Rmd +++ b/vignettes/Demography.Rmd @@ -68,7 +68,7 @@ dem_params <- simparams ages <- round(c(0.083333, 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 200) * year) -# Set deathrates for each age group (looks like by taking annual values and dividing by 365: +# Set deathrates for each age group (divide annual values by 365: deathrates <- c( .4014834, .0583379, .0380348, .0395061, .0347255, .0240849, .0300902, .0357914, .0443123, .0604932, .0466799, .0426199, .0268332, .049361, diff --git a/vignettes/MDA.Rmd b/vignettes/MDA.Rmd index 95124c2d..95a724da 100644 --- a/vignettes/MDA.Rmd +++ b/vignettes/MDA.Rmd @@ -167,7 +167,7 @@ legend(x = 20, y = 0.99, legend = c("MDA", "No-Int"), ## Seasonal Malaria Chemoprevention -To demonstrate how to simulate SMC in `malariasimulation` , in the following section we'll set-up and simulate a campaign that treats 80% of children aged 3-59 months old with four doses of SP-AQ per year. We will set the SMC campaign to begin in the second year, run for two years, and specify the four SMC events to occur at monthly intervals, starting two months prior to the peak malaria season. +To demonstrate how to simulate SMC in `malariasimulation` , in the following section we'll set-up and simulate a campaign that treats 90% of children aged 3-59 months old with four doses of SP-AQ per year. We will set the SMC campaign to begin in the second year, run for two years, and specify the four SMC events to occur at monthly intervals, starting two months prior to the peak malaria season. ### Interventions diff --git a/vignettes/Model.Rmd b/vignettes/Model.Rmd index 7fc8bfff..43249d45 100644 --- a/vignettes/Model.Rmd +++ b/vignettes/Model.Rmd @@ -308,15 +308,15 @@ The remaining vignettes describe how to adjust sets of parameters through a numb - `set_smc()`: implementation of seasonal malarial chemoprevention interventions - - `set_pmc()`: implementation of perrenial malarial chemoprevention interventions + - `set_pmc()`: implementation of perennial malarial chemoprevention interventions - `peak_season_offset()`: correlating timed interventions with seasonal malaria 4. [Vaccines](https://mrc-ide.github.io/malariasimulation/articles/Vaccines.html) - - `set_mass_pev()`: implementation of a pre-erythrocytic vaccination intervention + - `set_mass_pev()`: implementation of a pre-erythrocytic vaccination intervention via a mass distribution strategy - - `set_pev_epi()`: implementation of a pre-erythrocytic vaccination intervention from a certain age + - `set_pev_epi()`: implementation of a pre-erythrocytic vaccination intervention via an age-based distribution strategy - `set_tbv()`: implementation of a transmission blocking vaccination intervention @@ -342,7 +342,7 @@ The remaining vignettes describe how to adjust sets of parameters through a numb 9. [Metapopulation Modelling](https://mrc-ide.github.io/malariasimulation/articles/Metapopulation.html) - - `run_metapop_simulation()`: model multiple areas simultaneously + - `run_metapop_simulation()`: run multiple interacting models simultaneously 11. [Stochastic Variation](https://mrc-ide.github.io/malariasimulation/articles/Variation.html) diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index 2527c72a..9b5ebd07 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -87,7 +87,7 @@ simparams$species_proportions Then we can run the simulations for a variety of IRS strategies. In the example below, there are two rounds of IRS, the first at 30% coverage and the second at 80% coverage, each 3 months prior to peak rainfall for that year. The function `peak_season_offset()` outputs a timestep when peak rainfall will be observed based on the seasonality profile we set above. Notice that the matrices specified for the parameters for `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` have two rows, one for each timestep where IRS is implemented, and a number of columns corresponding to mosquito species. In this example, we only have 1 column because the species is set to "gamb" as we saw above. -The structure for IRS model is documented in the supplementary information from Table 3 in the Supplementary Information of [Sherrard-Smith et al., 2018](https://doi.org/10.1038/s41467-018-07357-w). Table S2.1 in the Supplementary Appendix of [Sherrard-Smith et al., 2022](https://doi.org/10.1016/S2542-5196(21)00296-5) has parameter estimates for insecticide resistance for IRS. +The structure for the IRS model is documented in the supplementary information from Table 3 in the Supplementary Information of [Sherrard-Smith et al., 2018](https://doi.org/10.1038/s41467-018-07357-w). Table S2.1 in the Supplementary Appendix of [Sherrard-Smith et al., 2022](https://doi.org/10.1016/S2542-5196(21)00296-5) has parameter estimates for insecticide resistance for IRS. ```{r, fig.align = 'center', out.width='100%'} peak <- peak_season_offset(simparams) From 370ec0c99795643d05a5c7977cb132d7bac5b253 Mon Sep 17 00:00:00 2001 From: RJSheppard Date: Thu, 29 Jun 2023 10:39:52 +0100 Subject: [PATCH 113/164] Added nrow/ncol clarifier in set species vignette --- vignettes/SetSpecies.Rmd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vignettes/SetSpecies.Rmd b/vignettes/SetSpecies.Rmd index 50a86ecd..f8ee8d7d 100644 --- a/vignettes/SetSpecies.Rmd +++ b/vignettes/SetSpecies.Rmd @@ -135,7 +135,7 @@ simparams$species_proportions ### Single exophilic mosquito species -We will run the same model with IRS as above, but this time with an example mosquito species similar to *An. funestus*, but with a lower propensity to bite indoors (which we will name "exophilic"). Note that now there are 3 columns for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments. See the Vector Control: IRS vignette for more information about setting IRS with different mosquito species. +We will run the same model with IRS as above, but this time with an example mosquito species similar to *An. funestus*, but with a lower propensity to bite indoors (which we will name "exophilic"). Note that now there are two rows for the `ls_theta`, `ls_gamma`, `ks_theta`, `ks_gamma`, `ms_theta`, and `ms_gamma` arguments (rows represent timesteps where changes occur, columns represent additional species). See the Vector Control: IRS vignette for more information about setting IRS with different mosquito species. ```{r, fig.align = 'center', out.width='100%'} # Create an example mosquito species (named exophilic) with a low value for `phi_indoors` From bc497d7e54c3fcf6e17f4c6671e18e392dd50948 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 30 Jun 2023 14:30:16 +0100 Subject: [PATCH 114/164] Clarifying the booster coverage argument --- R/pev_parameters.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/pev_parameters.R b/R/pev_parameters.R index e54967fb..0a465a43 100644 --- a/R/pev_parameters.R +++ b/R/pev_parameters.R @@ -73,7 +73,7 @@ rtss_booster_profile <- create_pev_profile( #' both set_mass_pev and set_pev_epi, this represents the minimum time between #' an individual being vaccinated under one scheme and vaccinated under another. #' @param booster_timestep the timesteps (following the final dose) at which booster vaccinations are administered -#' @param booster_coverage the proportion of the vaccinated population who will +#' @param booster_coverage the proportion of the vaccinated population relative to the last vaccination whether booster or primary series who will #' receive each booster vaccine #' @param booster_profile list of booster vaccine profiles, of type #' PEVProfile, for each timestep in booster_timeteps @@ -149,7 +149,7 @@ set_pev_epi <- function( #' @param min_ages for the target population, inclusive (in timesteps) #' @param max_ages for the target population, inclusive (in timesteps) #' @param booster_timestep the timesteps (following the initial vaccination) at which booster vaccinations are administered -#' @param booster_coverage the proportion of the vaccinated population who will +#' @param booster_coverage the proportion of the vaccinated population relative to the last vaccination whether booster or primary series who will #' receive each booster vaccine #' @param booster_profile list of booster vaccine profiles, of type #' PEVProfile, for each timestep in booster_timeteps From 235fc42f1085f6d7ebcd007f9c587f62268fc745 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 30 Jun 2023 14:31:56 +0100 Subject: [PATCH 115/164] clarifying booster coverage argument --- R/pev_parameters.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/pev_parameters.R b/R/pev_parameters.R index 0a465a43..4a828738 100644 --- a/R/pev_parameters.R +++ b/R/pev_parameters.R @@ -149,7 +149,7 @@ set_pev_epi <- function( #' @param min_ages for the target population, inclusive (in timesteps) #' @param max_ages for the target population, inclusive (in timesteps) #' @param booster_timestep the timesteps (following the initial vaccination) at which booster vaccinations are administered -#' @param booster_coverage the proportion of the vaccinated population relative to the last vaccination whether booster or primary series who will +#' @param booster_coverage the proportion of the vaccinated population relative to the last vaccination whether booster or primary series who will #' receive each booster vaccine #' @param booster_profile list of booster vaccine profiles, of type #' PEVProfile, for each timestep in booster_timeteps From ce6a0a9fe88574805e3ecd4e0a4cd89681a4c0f8 Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 30 Jun 2023 15:08:58 +0100 Subject: [PATCH 116/164] Update documentation --- man/get_parameters.Rd | 6 +++--- man/set_mass_pev.Rd | 2 +- man/set_pev_epi.Rd | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/man/get_parameters.Rd b/man/get_parameters.Rd index 7ada2861..54188c01 100644 --- a/man/get_parameters.Rd +++ b/man/get_parameters.Rd @@ -20,7 +20,7 @@ fixed state transitions: \item dl - the delay for mosquitoes to move from state L to P; default = 3.72 \item dpl - the delay mosquitoes to move from state P to Sm; default = 0.643 \item mup - the rate at which pupal mosquitoes die; default = 0.249 -\item mum - the rate at which developed mosquitoes die; default = 0.1253333 +\item mum - the rate at which developed mosquitoes die; default (An. gambiae) = .132 } immunity decay rates: @@ -151,9 +151,9 @@ species specific values are vectors \item beta - the average number of eggs laid per female mosquito per day; default = 21.2 \item total_M - the initial number of adult mosquitos in the simulation; default = 1000 \item init_foim - the FOIM used to calculate the equilibrium state for mosquitoes; default = 0 -\item species - names of the species in the simulation; default = "All" +\item species - names of the species in the simulation; default = "gamb" \item species_proportions - the relative proportions of each species; default = 1 -\item blood_meal_rates - the blood meal rates for each species; default = 0.3333333333 +\item blood_meal_rates - the blood meal rates for each species; default = 1/3 \item Q0 - proportion of blood meals taken on humans; default = 0.92 \item foraging_time - time spent taking blood meals; default = 0.69 } diff --git a/man/set_mass_pev.Rd b/man/set_mass_pev.Rd index dfb44c66..78d979d7 100644 --- a/man/set_mass_pev.Rd +++ b/man/set_mass_pev.Rd @@ -36,7 +36,7 @@ time between an individual being vaccinated under one scheme and vaccinated unde \item{booster_timestep}{the timesteps (following the initial vaccination) at which booster vaccinations are administered} -\item{booster_coverage}{the proportion of the vaccinated population who will +\item{booster_coverage}{the proportion of the vaccinated population relative to the last vaccination whether booster or primary series who will receive each booster vaccine} \item{booster_profile}{list of booster vaccine profiles, of type diff --git a/man/set_pev_epi.Rd b/man/set_pev_epi.Rd index b728e923..e015f474 100644 --- a/man/set_pev_epi.Rd +++ b/man/set_pev_epi.Rd @@ -37,7 +37,7 @@ an individual being vaccinated under one scheme and vaccinated under another.} \item{booster_timestep}{the timesteps (following the final dose) at which booster vaccinations are administered} -\item{booster_coverage}{the proportion of the vaccinated population who will +\item{booster_coverage}{the proportion of the vaccinated population relative to the last vaccination whether booster or primary series who will receive each booster vaccine} \item{booster_profile}{list of booster vaccine profiles, of type From 54955d0680a67b4ab4db8894aa936d620a3c635d Mon Sep 17 00:00:00 2001 From: Kelly McCain Date: Fri, 30 Jun 2023 16:25:19 +0100 Subject: [PATCH 117/164] Change wording --- R/pev_parameters.R | 6 ++---- man/set_mass_pev.Rd | 3 +-- man/set_pev_epi.Rd | 3 +-- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/R/pev_parameters.R b/R/pev_parameters.R index 4a828738..aeb6bd5b 100644 --- a/R/pev_parameters.R +++ b/R/pev_parameters.R @@ -73,8 +73,7 @@ rtss_booster_profile <- create_pev_profile( #' both set_mass_pev and set_pev_epi, this represents the minimum time between #' an individual being vaccinated under one scheme and vaccinated under another. #' @param booster_timestep the timesteps (following the final dose) at which booster vaccinations are administered -#' @param booster_coverage the proportion of the vaccinated population relative to the last vaccination whether booster or primary series who will -#' receive each booster vaccine +#' @param booster_coverage the proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series) #' @param booster_profile list of booster vaccine profiles, of type #' PEVProfile, for each timestep in booster_timeteps #' @param seasonal_boosters logical, if TRUE the first booster timestep is @@ -149,8 +148,7 @@ set_pev_epi <- function( #' @param min_ages for the target population, inclusive (in timesteps) #' @param max_ages for the target population, inclusive (in timesteps) #' @param booster_timestep the timesteps (following the initial vaccination) at which booster vaccinations are administered -#' @param booster_coverage the proportion of the vaccinated population relative to the last vaccination whether booster or primary series who will -#' receive each booster vaccine +#' @param booster_coverage the proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series) #' @param booster_profile list of booster vaccine profiles, of type #' PEVProfile, for each timestep in booster_timeteps #' @export diff --git a/man/set_mass_pev.Rd b/man/set_mass_pev.Rd index 78d979d7..7c28547f 100644 --- a/man/set_mass_pev.Rd +++ b/man/set_mass_pev.Rd @@ -36,8 +36,7 @@ time between an individual being vaccinated under one scheme and vaccinated unde \item{booster_timestep}{the timesteps (following the initial vaccination) at which booster vaccinations are administered} -\item{booster_coverage}{the proportion of the vaccinated population relative to the last vaccination whether booster or primary series who will -receive each booster vaccine} +\item{booster_coverage}{the proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series)} \item{booster_profile}{list of booster vaccine profiles, of type PEVProfile, for each timestep in booster_timeteps} diff --git a/man/set_pev_epi.Rd b/man/set_pev_epi.Rd index e015f474..4dea14ed 100644 --- a/man/set_pev_epi.Rd +++ b/man/set_pev_epi.Rd @@ -37,8 +37,7 @@ an individual being vaccinated under one scheme and vaccinated under another.} \item{booster_timestep}{the timesteps (following the final dose) at which booster vaccinations are administered} -\item{booster_coverage}{the proportion of the vaccinated population relative to the last vaccination whether booster or primary series who will -receive each booster vaccine} +\item{booster_coverage}{the proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series)} \item{booster_profile}{list of booster vaccine profiles, of type PEVProfile, for each timestep in booster_timeteps} From cc4d2a8ccb1c53aa5841de73d4ee9d1547ceba23 Mon Sep 17 00:00:00 2001 From: Giovanni Charles Date: Fri, 30 Jun 2023 11:56:20 +0100 Subject: [PATCH 118/164] Include carrying capacity vignette Fix vignette bugs: * set figure width and dpi * fix references to "All" vector Fix width in carrying capacity vignette --- .Rbuildignore | 2 ++ .gitignore | 2 ++ _pkgdown.yml | 6 +++--- vignettes/Carrying-capacity.Rmd | 12 +++++++----- vignettes/Demography.Rmd | 4 +++- vignettes/EIRprevmatch.Rmd | 4 +++- vignettes/MDA.Rmd | 10 ++++++---- vignettes/Metapopulation.Rmd | 4 +++- vignettes/Model.Rmd | 10 ++++++---- vignettes/Parameter_variation.Rmd | 6 ++++++ vignettes/SetSpecies.Rmd | 4 +++- vignettes/Treatment.Rmd | 4 +++- vignettes/Vaccines.Rmd | 4 +++- vignettes/Variation.Rmd | 6 ++++++ vignettes/VectorControl_Bednets.Rmd | 4 +++- vignettes/VectorControl_IRS.Rmd | 4 +++- 16 files changed, 62 insertions(+), 24 deletions(-) diff --git a/.Rbuildignore b/.Rbuildignore index 1a56f843..3e91f6fd 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -10,3 +10,5 @@ LICENSE.md codecov.yml .github ^data-raw$ +^doc$ +^Meta$ diff --git a/.gitignore b/.gitignore index ee50e62b..eb4ff0ee 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,5 @@ malariasimulation_*.tar.gz /build/ doc inst/doc +/doc/ +/Meta/ diff --git a/_pkgdown.yml b/_pkgdown.yml index 1cc68395..28a83e81 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -60,11 +60,11 @@ reference: - title: "Mosquito species functions and parameters" contents: - set_species - # - set_carrying_capacity + - set_carrying_capacity - arab_params - fun_params - gamb_params - # - steph_params + - steph_params - title: "Intervention functions" - subtitle: "Drug treatments" contents: @@ -98,4 +98,4 @@ reference: - parameterise_mosquito_equilibrium - parameterise_total_M - rtss_booster_profile - - rtss_profile \ No newline at end of file + - rtss_profile diff --git a/vignettes/Carrying-capacity.Rmd b/vignettes/Carrying-capacity.Rmd index 4525ccb8..c0cfcf7c 100644 --- a/vignettes/Carrying-capacity.Rmd +++ b/vignettes/Carrying-capacity.Rmd @@ -13,7 +13,9 @@ editor_options: ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, - comment = "#>" + comment = "#>", + dpi=300, + fig.width=7 ) ``` @@ -61,7 +63,7 @@ p_seasonal <- p_seasonal |> and can run the simulations and compare the outputs -```{r, fig.width = 7, fig.height = 4} +```{r, fig.width = 7, fig.height = 4, out.width='100%'} set.seed(123) s <- run_simulation(timesteps = timesteps, parameters = p) s$pfpr <- s$n_detect_730_3650 / s$n_730_3650 @@ -97,7 +99,7 @@ The impact of larval source management (LSM) is captured by reducing the carrying capacity. The helper function `set_carrying_capacity()` can be used to specify this intervention -```{r, fig.width = 7, fig.height = 4} +```{r, fig.width = 7, fig.height = 4, out.width='100%'} # Specify the LSM coverage lsm_coverage <- 0.8 # Set LSM by reducing the carrying capacity by (1 - coverage) @@ -128,7 +130,7 @@ changes to the carrying capacity to be made. Here we will demonstrate using carrying capacity rescaling to capture the invasion of _Anopheles stephensi_. -```{r, fig.width = 7, fig.height = 4} +```{r, fig.width = 7, fig.height = 4, out.width='100%'} # First initialise the mosquito species so that the invasive species starts with # a negligible, but non-zero proportion. p_stephensi <- p |> @@ -164,7 +166,7 @@ specific carrying capacity changes over time. We can demonstrate this below by arbitrarily stepping the carrying capacity up and down over time -```{r, fig.width = 7, fig.height = 4} +```{r, fig.width = 7, fig.height = 4, out.width='100%'} p_flexible <- p |> set_carrying_capacity( carrying_capacity = cc * matrix(c(0.1, 2, 0.1, 0.5, 0.9), ncol = 1), diff --git a/vignettes/Demography.Rmd b/vignettes/Demography.Rmd index b42e243f..d8c96a93 100644 --- a/vignettes/Demography.Rmd +++ b/vignettes/Demography.Rmd @@ -10,7 +10,9 @@ vignette: > ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, - comment = "#>" + comment = "#>", + dpi=300, + fig.width=7 ) ``` diff --git a/vignettes/EIRprevmatch.Rmd b/vignettes/EIRprevmatch.Rmd index 32123b5f..f519faa5 100644 --- a/vignettes/EIRprevmatch.Rmd +++ b/vignettes/EIRprevmatch.Rmd @@ -10,7 +10,9 @@ vignette: > ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, - comment = "#>" + comment = "#>", + dpi=300, + fig.width=7 ) ``` diff --git a/vignettes/MDA.Rmd b/vignettes/MDA.Rmd index 95a724da..d464c533 100644 --- a/vignettes/MDA.Rmd +++ b/vignettes/MDA.Rmd @@ -10,7 +10,9 @@ vignette: > ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, - comment = "#>" + comment = "#>", + dpi=300, + fig.width=7 ) ``` @@ -185,9 +187,9 @@ smcparams <- set_drugs(smcparams, list(SP_AQ_params)) peak <- peak_season_offset(smcparams) # Create a variable for total mosquito population through time: -noint_output$mosq_total = noint_output$Sm_All_count + - noint_output$Im_All_count + - noint_output$Pm_All_count +noint_output$mosq_total = noint_output$Sm_gamb_count + + noint_output$Im_gamb_count + + noint_output$Pm_gamb_count # Schedule drug administration times (in daily time steps) before, during and after the seasonal peak: admin_days <- c(-60, -30, 0, 30) diff --git a/vignettes/Metapopulation.Rmd b/vignettes/Metapopulation.Rmd index e249591f..bece7840 100644 --- a/vignettes/Metapopulation.Rmd +++ b/vignettes/Metapopulation.Rmd @@ -10,7 +10,9 @@ vignette: > ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, - comment = "#>" + comment = "#>", + dpi=300, + fig.width=7 ) ``` diff --git a/vignettes/Model.Rmd b/vignettes/Model.Rmd index 43249d45..c09932c2 100644 --- a/vignettes/Model.Rmd +++ b/vignettes/Model.Rmd @@ -10,7 +10,9 @@ vignette: > ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, - comment = "#>" + comment = "#>", + dpi=300, + fig.width=7 ) ``` @@ -173,7 +175,7 @@ Where **treatments** are specified, `n_treated` will report the number that have These outputs can then be visualised, such as the population changes in states. Another key output is the prevalence of detectable infections between the ages of 2-10 (*Pf*PR~2-10~), which can be obtained by dividing `n_detect_730_3650` by `n_730_3650`. -```{r, fig.align = 'center', out.width='100%', fig.asp=0.55} +```{r, fig.align = 'center', out.width='100%', fig.asp=0.55, } # Define vector of column names to plot cols_to_plot <- paste0(c("S","D","A","U","Tr"),"_count") @@ -255,7 +257,7 @@ The `malariasimulation` package has the capacity to simulate malaria transmissio To include seasonality, we must set the parameter `model_seasonality = TRUE` and assign values to parameters that determine seasonality: `g0`, `g` and `h` (which represent fourier coefficients). These parameters must be set directly by passing a list of named parameters to the `overrides` argument of the `get_parameters()` function. ```{r, fig.align = 'center', out.width='100%'} -# Set parameters, inclusing seasonality parameters +# Set parameters, including seasonality parameters params_seasons <- get_parameters(overrides = list( model_seasonality = TRUE, g0 = 0.28, @@ -266,7 +268,7 @@ params_seasons <- get_parameters(overrides = list( seasonality_simulation <- run_simulation(timesteps = 600, parameters = params_seasons) # Collect results -All_mos_cols <- paste0(c("E","L","P","Sm","Pm", "Im"),"_All_count") +All_mos_cols <- paste0(c("E","L","P","Sm","Pm", "Im"),"_gamb_count") # Plot results plot(seasonality_simulation[,1], rowSums(seasonality_simulation[,All_mos_cols]), lwd = 2, diff --git a/vignettes/Parameter_variation.Rmd b/vignettes/Parameter_variation.Rmd index 69ad4da1..a0eef828 100644 --- a/vignettes/Parameter_variation.Rmd +++ b/vignettes/Parameter_variation.Rmd @@ -13,6 +13,12 @@ vignette: > library(malariasimulation) # Set colour palette: cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + dpi=300, + fig.width=7 +) ``` This vignette describes how variation in estimated model parameters can be incorporated into model simulations. diff --git a/vignettes/SetSpecies.Rmd b/vignettes/SetSpecies.Rmd index f8ee8d7d..10b1676d 100644 --- a/vignettes/SetSpecies.Rmd +++ b/vignettes/SetSpecies.Rmd @@ -10,7 +10,9 @@ vignette: > ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, - comment = "#>" + comment = "#>", + dpi=300, + fig.width=7 ) ``` diff --git a/vignettes/Treatment.Rmd b/vignettes/Treatment.Rmd index 4f40b19b..d325aa74 100644 --- a/vignettes/Treatment.Rmd +++ b/vignettes/Treatment.Rmd @@ -10,7 +10,9 @@ vignette: > ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, - comment = "#>" + comment = "#>", + dpi=300, + fig.width=7 ) ``` diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 583801b3..51bffd0e 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -10,7 +10,9 @@ vignette: > ```{r, include = FALSE, message=FALSE} knitr::opts_chunk$set( collapse = TRUE, - comment = "#>" + comment = "#>", + dpi=300, + fig.width=7 ) ``` diff --git a/vignettes/Variation.Rmd b/vignettes/Variation.Rmd index a1157bae..7146d47f 100644 --- a/vignettes/Variation.Rmd +++ b/vignettes/Variation.Rmd @@ -13,6 +13,12 @@ library(malariasimulation) # Set colour palette: cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7") set.seed(555) +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>", + dpi=300, + fig.width=7 +) ``` `malariasimulation` is a stochastic, individual-based model and, as such, simulations run with identical parameterisations will generate non-identical, sometimes highly variable, outputs. To illustrate this, we will compare the prevalence and incidence of malaria over a year in simulations with a small and a larger population. Then we will demonstrate how this variation can be estimated by running multiple simulations using the `run_simulation_with_repetitions` function. diff --git a/vignettes/VectorControl_Bednets.Rmd b/vignettes/VectorControl_Bednets.Rmd index f65d5ca7..ae6a62c4 100644 --- a/vignettes/VectorControl_Bednets.Rmd +++ b/vignettes/VectorControl_Bednets.Rmd @@ -11,7 +11,9 @@ vignette: > ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, - comment = "#>" + comment = "#>", + dpi=300, + fig.width=7 ) ``` diff --git a/vignettes/VectorControl_IRS.Rmd b/vignettes/VectorControl_IRS.Rmd index 9b5ebd07..3cf8ab7e 100644 --- a/vignettes/VectorControl_IRS.Rmd +++ b/vignettes/VectorControl_IRS.Rmd @@ -10,7 +10,9 @@ vignette: > ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, - comment = "#>" + comment = "#>", + dpi=300, + fig.width=7 ) ``` From 7b74c3d7b90cc7a8583ffa8111844fd1ce862eb4 Mon Sep 17 00:00:00 2001 From: Giovanni Date: Mon, 3 Jul 2023 15:08:34 +0100 Subject: [PATCH 119/164] Update NEWS.md --- NEWS.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index 5d619abd..826bf0d0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,12 +1,13 @@ # malariasimulation 1.6.0 * Fix MDA bug where undetectable asymptomatics are treated - -# malariasimulation 1.5.0 - + * New vignettes + * Progress bar for long simulations + * Individual mosquitoes off by default * New vaccination code: * pre-erythrocytic vaccine functions have been renamed to pev * pev functions have PEVProfiles for alternate pev vaccines and boosters + * Specify carrying capacity over time # malariasimulation 1.4.0 From fd58ea6454347f9e702803317e6a54dd12320f0c Mon Sep 17 00:00:00 2001 From: Peter Winskill Date: Wed, 12 Jul 2023 14:27:26 +0100 Subject: [PATCH 120/164] Specify timesteps in create process --- DESCRIPTION | 2 +- R/model.R | 6 ++++-- R/processes.R | 2 ++ src/RcppExports.cpp | 2 +- tests/testthat/test-process-integration.R | 22 ++++++++++++++++++++++ 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 3396705b..1d971723 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: malariasimulation Title: An individual based model for malaria -Version: 1.6.0 +Version: 1.6.1 Authors@R: c( person( given = "Giovanni", diff --git a/R/model.R b/R/model.R index 48af9af9..fb6ffef9 100644 --- a/R/model.R +++ b/R/model.R @@ -115,7 +115,8 @@ run_simulation <- function( solvers, correlations, list(create_lagged_eir(variables, solvers, parameters)), - list(create_lagged_infectivity(variables, parameters)) + list(create_lagged_infectivity(variables, parameters)), + timesteps ), variables = variables, events = unlist(events), @@ -206,6 +207,7 @@ run_metapop_simulation <- function( correlations[[i]], lagged_eir, lagged_infectivity, + timesteps, mixing[i,], i ) @@ -248,4 +250,4 @@ run_simulation_with_repetitions <- function( } ) do.call("rbind", dfs) -} \ No newline at end of file +} diff --git a/R/processes.R b/R/processes.R index 6109490f..d3b11fda 100644 --- a/R/processes.R +++ b/R/processes.R @@ -14,6 +14,7 @@ #' population and species in the simulation #' @param lagged_infectivity a list of LaggedValue objects for FOIM for each population #' in the simulation +#' @param timesteps Number of timesteps #' @param mixing a vector of mixing coefficients for the lagged transmission #' values (default: 1) #' @param mixing_index an index for this population's position in the @@ -29,6 +30,7 @@ create_processes <- function( correlations, lagged_eir, lagged_infectivity, + timesteps, mixing = 1, mixing_index = 1 ) { diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index f5c226fd..affb233d 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -260,7 +260,7 @@ BEGIN_RCPP END_RCPP } -RcppExport SEXP run_testthat_tests(); +RcppExport SEXP run_testthat_tests(void); static const R_CallMethodDef CallEntries[] = { {"_malariasimulation_create_adult_mosquito_model", (DL_FUNC) &_malariasimulation_create_adult_mosquito_model, 5}, diff --git a/tests/testthat/test-process-integration.R b/tests/testthat/test-process-integration.R index f259be5e..1b07f127 100644 --- a/tests/testthat/test-process-integration.R +++ b/tests/testthat/test-process-integration.R @@ -19,6 +19,28 @@ test_that('create_processes makes valid process functions', { } }) +test_that('create_processes makes valid process functions when progress bar specified', { + parameters <- get_parameters() + parameters$progress_bar <- TRUE + events <- create_events(parameters) + variables <- create_variables(parameters) + vector_models <- parameterise_mosquito_models(parameters, 1) + solvers <- parameterise_solvers(vector_models, parameters) + renderer <- individual::Render$new(1) + processes <- create_processes( + renderer, + variables, + events, + parameters, + vector_models, + solvers, + timesteps = 100 + ) + for (process in processes) { + expect(is.function(process) || inherits(process, 'externalptr'), 'Process is not a function') + } +}) + test_that('attach_event_listeners makes valid listeners', { parameters <- get_parameters() events <- create_events(parameters) From a7c7dd1f29d143b2f19404ae613e484d40e25788 Mon Sep 17 00:00:00 2001 From: Giovanni Charles Date: Mon, 18 Sep 2023 14:43:44 +0100 Subject: [PATCH 121/164] Fix competing hazards for mass and EPI pev: * Add tests for the EPI and mass vaccination processes/listeners * Add checks in the listeners to remove scheduled vaccinations * Update the news for the bug fix * RcppExports updated automatically --- NEWS.md | 5 +++ R/pev.R | 21 ++++++++++- src/RcppExports.cpp | 2 +- tests/testthat/test-pev-epi.R | 70 +++++++++++++++++++++++++++++++++++ tests/testthat/test-pev.R | 68 ++++++++++++++++++++++++++++++++++ 5 files changed, 163 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index 826bf0d0..538311c6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +# malariasimulation 1.6.1 (wip) + + * Fix bug in competing hazards between mass and EPI vaccines. Where individuals + can be enrolled onto both strategies if applied on the same timestep. + # malariasimulation 1.6.0 * Fix MDA bug where undetectable asymptomatics are treated diff --git a/R/pev.R b/R/pev.R index 4c735552..28eb2819 100644 --- a/R/pev.R +++ b/R/pev.R @@ -29,6 +29,14 @@ create_epi_pev_process <- function( to_vaccinate <- variables$birth$get_index_of( set = timestep - parameters$pev_epi_age ) + + #ignore those who are scheduled for mass vaccination + if (!is.null(events$mass_pev_doses)) { + to_vaccinate <- to_vaccinate$and( + events$mass_pev_doses[[1]]$get_scheduled()$not() + ) + } + if (parameters$pev_epi_min_wait == 0) { target <- to_vaccinate$to_vector() } else { @@ -81,13 +89,22 @@ create_mass_pev_listener <- function( in_age_group$or(variables$birth$get_index_of(a = min_birth, b = max_birth)) } if (parameters$mass_pev_min_wait == 0) { - target <- in_age_group$to_vector() + target <- in_age_group } else { not_recently_vaccinated <- variables$pev_timestep$get_index_of( a = max(timestep - parameters$mass_pev_min_wait, 0), b = timestep )$not(TRUE) - target <- in_age_group$and(not_recently_vaccinated)$to_vector() + target <- in_age_group$and(not_recently_vaccinated) + } + + #ignore those who are scheduled for EPI vaccination + if (!is.null(events$pev_epi_doses)) { + target <- target$and( + events$pev_epi_doses[[1]]$get_scheduled()$not() + )$to_vector() + } else { + target <- target$to_vector() } time_index = which(parameters$mass_pev_timesteps == timestep) diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index affb233d..f5c226fd 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -260,7 +260,7 @@ BEGIN_RCPP END_RCPP } -RcppExport SEXP run_testthat_tests(void); +RcppExport SEXP run_testthat_tests(); static const R_CallMethodDef CallEntries[] = { {"_malariasimulation_create_adult_mosquito_model", (DL_FUNC) &_malariasimulation_create_adult_mosquito_model, 5}, diff --git a/tests/testthat/test-pev-epi.R b/tests/testthat/test-pev-epi.R index 4eea8445..3dac524d 100644 --- a/tests/testthat/test-pev-epi.R +++ b/tests/testthat/test-pev-epi.R @@ -131,6 +131,76 @@ test_that('pev epi targets correct age and respects min_wait', { ) }) +test_that('EPI ignores individuals scheduled for mass vaccination', { + timestep <- 100 + parameters <- get_parameters(list(human_population = 5)) + parameters <- set_mass_pev( + parameters, + profile = rtss_profile, + timesteps = c(50, 100), + coverages = rep(0.8, 2), + min_wait = 0, + min_ages = c(1, 2, 3, 18) * 365, + max_ages = (c(1, 2, 3, 18) + 1) * 365 - 1, + booster_timestep = c(18, 36) * 30, + booster_coverage = c(.9, .8), + booster_profile = list(rtss_booster_profile, rtss_booster_profile) + ) + parameters <- set_pev_epi( + parameters, + profile = rtss_profile, + timesteps = 10, + coverages = 0.8, + min_wait = 0, + age = 18 * 365, + booster_timestep = c(18, 36) * 30, + booster_coverage = c(.9, .8), + booster_profile = list(rtss_booster_profile, rtss_booster_profile) + ) + events <- create_events(parameters) + variables <- create_variables(parameters) + variables$birth <- individual::IntegerVariable$new( + -c(18, 8, 2.9, 3.2, 18) * 365 + 100 + ) + variables$pev_timestep <- mock_integer( + c(-1, -1, -1, 50, 50) + ) + + correlations <- get_correlation_parameters(parameters) + + process <- create_epi_pev_process( + variables, + events, + parameters, + correlations, + parameters$pev_epi_coverages, + parameters$pev_epi_timesteps + ) + + sample_mock <- mockery::mock(c(TRUE)) + + mockery::stub( + process, + 'sample_intervention', + sample_mock + ) + + # schedule id #1 for epi vaccination + events$mass_pev_doses[[1]]$schedule(1, 0) + + process(timestep) + + mockery::expect_args( + sample_mock, + 1, + 5, + 'pev', + .8, + correlations + ) +}) + + test_that('pev EPI respects min_wait when scheduling seasonal boosters', { timestep <- 5 * 365 parameters <- get_parameters(list(human_population = 5)) diff --git a/tests/testthat/test-pev.R b/tests/testthat/test-pev.R index 5cb09c5d..c80dc457 100644 --- a/tests/testthat/test-pev.R +++ b/tests/testthat/test-pev.R @@ -209,6 +209,74 @@ test_that('Mass vaccinations update vaccination time', { ) }) +test_that('Mass vaccinations ignore EPI individuals', { + timestep <- 100 + parameters <- get_parameters(list(human_population = 5)) + parameters <- set_mass_pev( + parameters, + profile = rtss_profile, + timesteps = c(50, 100), + coverages = rep(0.8, 2), + min_wait = 0, + min_ages = c(1, 2, 3, 18) * 365, + max_ages = (c(1, 2, 3, 18) + 1) * 365 - 1, + booster_timestep = c(18, 36) * 30, + booster_coverage = c(.9, .8), + booster_profile = list(rtss_booster_profile, rtss_booster_profile) + ) + parameters <- set_pev_epi( + parameters, + profile = rtss_profile, + timesteps = 10, + coverages = 0.8, + min_wait = 2*365, + age = 18 * 365, + booster_timestep = c(18, 36) * 30, + booster_coverage = c(.9, .8), + booster_profile = list(rtss_booster_profile, rtss_booster_profile) + ) + events <- create_events(parameters) + variables <- create_variables(parameters) + variables$birth <- individual::IntegerVariable$new( + -c(18.3, 8, 2.9, 3.2, 18.4) * 365 + 100 + ) + variables$pev_timestep <- mock_integer( + c(-1, -1, -1, 50, 50) + ) + + correlations <- get_correlation_parameters(parameters) + + listener <- create_mass_pev_listener( + variables, + events, + parameters, + correlations + ) + + sample_mock <- mockery::mock(c(TRUE, TRUE, FALSE, FALSE)) + + mockery::stub( + listener, + 'sample_intervention', + sample_mock + ) + + # schedule id #1 for epi vaccination + events$pev_epi_doses[[1]]$schedule(1, 0) + + listener(timestep) + + mockery::expect_args( + sample_mock, + 1, + c(3, 4, 5), + 'pev', + .8, + correlations + ) +}) + + test_that('Mass boosters update profile params and reschedule correctly', { parameters <- get_parameters() parameters <- set_mass_pev( From e7b5c4d8db1ed586810de84045526844dd1af625 Mon Sep 17 00:00:00 2001 From: Giovanni Charles Date: Fri, 15 Sep 2023 12:07:26 +0100 Subject: [PATCH 122/164] Fix bug with pev min_wait: * Update pev-epi min_wait test to directly check sample population * Update pe-epi min_wait test to check that pev_timestep is being updated on the first dose * Copy pev-epi min_wait test to mass pev * Update pev and epi processes to calculate targets based on time of first dose * Update infection immunity function to calculate pev immunity only after 3rd dose --- NEWS.md | 2 + R/human_infection.R | 5 +- R/mortality_processes.R | 3 +- R/pev.R | 23 ++++- R/variables.R | 20 +++-- tests/testthat/test-infection-integration.R | 4 +- tests/testthat/test-pev-epi.R | 33 ++++---- tests/testthat/test-pev.R | 94 +++++++++++++++++++-- 8 files changed, 143 insertions(+), 41 deletions(-) diff --git a/NEWS.md b/NEWS.md index 538311c6..860567da 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,6 +2,8 @@ * Fix bug in competing hazards between mass and EPI vaccines. Where individuals can be enrolled onto both strategies if applied on the same timestep. + * Fix bug with min_wait. Min wait was working off of the final primary dose. It + now works of of the first dose. # malariasimulation 1.6.0 diff --git a/R/human_infection.R b/R/human_infection.R index b623a2d8..1cb521c4 100644 --- a/R/human_infection.R +++ b/R/human_infection.R @@ -129,9 +129,10 @@ calculate_infections <- function( # calculate vaccine efficacy vaccine_efficacy <- rep(0, length(source_vector)) - vaccine_times <- variables$pev_timestep$get_values(source_vector) - vaccinated <- vaccine_times > -1 + vaccine_times <- variables$last_eff_pev_timestep$get_values(source_vector) pev_profile <- variables$pev_profile$get_values(source_vector) + # get vector of individuals who have received their 3rd dose + vaccinated <- vaccine_times > -1 pev_profile <- pev_profile[vaccinated] if (length(vaccinated) > 0) { antibodies <- calculate_pev_antibodies( diff --git a/R/mortality_processes.R b/R/mortality_processes.R index 65b090cb..9d95a707 100644 --- a/R/mortality_processes.R +++ b/R/mortality_processes.R @@ -106,7 +106,8 @@ reset_target <- function(variables, events, target, state, timestep) { variables$drug_time$queue_update(-1, target) # vaccination - variables$pev_timestep$queue_update(-1, target) + variables$last_pev_timestep$queue_update(-1, target) + variables$last_eff_pev_timestep$queue_update(-1, target) variables$pev_profile$queue_update(-1, target) variables$tbv_vaccinated$queue_update(-1, target) diff --git a/R/pev.R b/R/pev.R index 28eb2819..039b6044 100644 --- a/R/pev.R +++ b/R/pev.R @@ -40,7 +40,7 @@ create_epi_pev_process <- function( if (parameters$pev_epi_min_wait == 0) { target <- to_vaccinate$to_vector() } else { - not_recently_vaccinated <- variables$pev_timestep$get_index_of( + not_recently_vaccinated <- variables$last_pev_timestep$get_index_of( a = max(timestep - parameters$pev_epi_min_wait, 0), b = timestep )$not(TRUE) @@ -56,6 +56,9 @@ create_epi_pev_process <- function( ) ] + # Update the latest vaccination time + variables$last_pev_timestep$queue_update(timestep, target) + schedule_vaccination( target, events, @@ -91,7 +94,7 @@ create_mass_pev_listener <- function( if (parameters$mass_pev_min_wait == 0) { target <- in_age_group } else { - not_recently_vaccinated <- variables$pev_timestep$get_index_of( + not_recently_vaccinated <- variables$last_pev_timestep$get_index_of( a = max(timestep - parameters$mass_pev_min_wait, 0), b = timestep )$not(TRUE) @@ -116,6 +119,11 @@ create_mass_pev_listener <- function( correlations ) ] + + # Update the latest vaccination time + variables$last_pev_timestep$queue_update(timestep, target) + + # Schedule future doses schedule_vaccination( target, events, @@ -162,7 +170,7 @@ schedule_vaccination <- function( create_pev_efficacy_listener <- function(variables, pev_profile_index) { function(timestep, target) { if (target$size() > 0) { - variables$pev_timestep$queue_update(timestep, target) + variables$last_eff_pev_timestep$queue_update(timestep, target) variables$pev_profile$queue_update(pev_profile_index, target) } } @@ -185,7 +193,8 @@ create_pev_booster_listener <- function( force(coverage) function(timestep, target) { target <- sample_bitset(target, coverage) - variables$pev_timestep$queue_update(timestep, target) + variables$last_pev_timestep$queue_update(timestep, target) + variables$last_eff_pev_timestep$queue_update(timestep, target) variables$pev_profile$queue_update(pev_profile_index, target) renderer$render(render_name, target$size(), timestep) @@ -240,6 +249,12 @@ attach_pev_dose_listeners <- function( dose_events[[d]]$add_listener( create_dosage_renderer(renderer, strategy, d) ) + # update last vaccination on every primary dose + dose_events[[d]]$add_listener( + function(t, target) { + variables$last_pev_timestep$queue_update(t, target) + } + ) if (d == length(dose_events)) { dose_events[[d]]$add_listener( create_pev_efficacy_listener( diff --git a/R/variables.R b/R/variables.R index 0931b3f7..b84074e4 100644 --- a/R/variables.R +++ b/R/variables.R @@ -1,5 +1,4 @@ -#' @title Define model variables -#' @description +#' @title Define model variables #' @description #' create_variables creates the human and mosquito variables for #' the model. Variables are used to track real data for each individual over #' time, they are read and updated by processes @@ -18,10 +17,13 @@ #' * ID - Acquired immunity to detectability #' * zeta - Heterogeneity of human individuals #' * zeta_group - Discretised heterogeneity of human individuals -#' * pev_timestep - The timestep of the last pev vaccination (-1 if there -#' haven't been any) -#' * pev_profile - The index of the profile of the last administered pev vaccine -#' (-1 if there haven't been any) +#' * last_pev_timestep - The timestep of the last pev vaccination (-1 if there +#' * last_eff_pev_timestep - The timestep of the last efficacious pev +#' vaccination, including final primary dose and booster doses (-1 if there have not been any) +#' * pev_profile - The index of the efficacy profile of any pev vaccinations. +#' Not set until the final primary dose. +#' This is only set on the final primary dose and subsequent booster doses +#' (-1 otherwise) #' * tbv_vaccinated - The timstep of the last tbv vaccination (-1 if there #' haven't been any #' * net_time - The timestep when a net was last put up (-1 if never) @@ -188,7 +190,8 @@ create_variables <- function(parameters) { drug <- individual::IntegerVariable$new(rep(0, size)) drug_time <- individual::IntegerVariable$new(rep(-1, size)) - pev_timestep <- individual::IntegerVariable$new(rep(-1, size)) + last_pev_timestep <- individual::IntegerVariable$new(rep(-1, size)) + last_eff_pev_timestep <- individual::IntegerVariable$new(rep(-1, size)) pev_profile <- individual::IntegerVariable$new(rep(-1, size)) tbv_vaccinated <- individual::DoubleVariable$new(rep(-1, size)) @@ -215,7 +218,8 @@ create_variables <- function(parameters) { infectivity = infectivity, drug = drug, drug_time = drug_time, - pev_timestep = pev_timestep, + last_pev_timestep = last_pev_timestep, + last_eff_pev_timestep = last_eff_pev_timestep, pev_profile = pev_profile, tbv_vaccinated = tbv_vaccinated, net_time = net_time, diff --git a/tests/testthat/test-infection-integration.R b/tests/testthat/test-infection-integration.R index a8e6033e..238a2ae6 100644 --- a/tests/testthat/test-infection-integration.R +++ b/tests/testthat/test-infection-integration.R @@ -133,7 +133,7 @@ test_that('calculate_infections works various combinations of drug and vaccinati ), drug = individual::DoubleVariable$new(c(1, 2, 0, 0)), drug_time = individual::DoubleVariable$new(c(20, 30, -1, -1)), - pev_timestep = individual::DoubleVariable$new(c(-1, 10, 40, -1)), + last_eff_pev_timestep = individual::DoubleVariable$new(c(-1, 10, 40, -1)), pev_profile = individual::IntegerVariable$new(c(-1, 1, 2, -1)), ib = individual::DoubleVariable$new(c(.2, .3, .5, .9)) ) @@ -366,7 +366,7 @@ test_that('prophylaxis is considered for medicated humans', { ), drug = individual::DoubleVariable$new(c(0, 2, 1, 0)), drug_time = individual::DoubleVariable$new(c(-1, 49, 40, -1)), - pev_timestep = individual::DoubleVariable$new(c(-1, -1, -1, -1)), + last_eff_pev_timestep = individual::DoubleVariable$new(c(-1, -1, -1, -1)), pev_profile = individual::IntegerVariable$new(c(-1, -1, -1, -1)), ib = individual::DoubleVariable$new(c(.2, .3, .5, .9)) ) diff --git a/tests/testthat/test-pev-epi.R b/tests/testthat/test-pev-epi.R index 3dac524d..ef9148a3 100644 --- a/tests/testthat/test-pev-epi.R +++ b/tests/testthat/test-pev-epi.R @@ -86,49 +86,48 @@ test_that('pev epi targets correct age and respects min_wait', { variables$birth <- individual::IntegerVariable$new( -c(18, 18, 2.9, 18, 18) * 365 + timestep ) - variables$pev_timestep <- mock_integer( + variables$last_pev_timestep <- mock_integer( c(50, -1, -1, 4*365, -1) ) + variables$pev_profile <- mock_integer( + c(1, -1, -1, 1, -1) + ) - events$pev_epi_doses <- lapply(events$pev_epi_doses, mock_event) - + correlations <- get_correlation_parameters(parameters) process <- create_epi_pev_process( variables, events, parameters, - get_correlation_parameters(parameters), + correlations, parameters$pev_epi_coverages, parameters$pev_epi_timesteps ) + sample_mock <- mockery::mock(c(TRUE, TRUE, FALSE)) mockery::stub( process, 'sample_intervention', - mockery::mock(c(TRUE, TRUE, FALSE)) + sample_mock ) process(timestep) mockery::expect_args( - events$pev_epi_doses[[1]]$schedule, + sample_mock, 1, - c(1, 2), - parameters$pev_doses[[1]] + c(1, 2, 5), + 'pev', + .8, + correlations ) mockery::expect_args( - events$pev_epi_doses[[2]]$schedule, + variables$last_pev_timestep$queue_update_mock(), 1, - c(1, 2), - parameters$pev_doses[[2]] + timestep, + c(1, 2) ) - mockery::expect_args( - events$pev_epi_doses[[3]]$schedule, - 1, - c(1, 2), - parameters$pev_doses[[3]] - ) }) test_that('EPI ignores individuals scheduled for mass vaccination', { diff --git a/tests/testthat/test-pev.R b/tests/testthat/test-pev.R index c80dc457..30007cd3 100644 --- a/tests/testthat/test-pev.R +++ b/tests/testthat/test-pev.R @@ -97,7 +97,7 @@ test_that('Infection considers pev efficacy', { variables$birth <- individual::IntegerVariable$new( -c(8, 2.9, 3.2, 18.4) * 365 - 100 ) - variables$pev_timestep <- individual::IntegerVariable$new( + variables$last_eff_pev_timestep <- individual::IntegerVariable$new( c(-1, -1, 50, 50 + 30) ) variables$pev_profile <- individual::IntegerVariable$new( @@ -299,7 +299,10 @@ test_that('Mass boosters update profile params and reschedule correctly', { variables$birth <- individual::IntegerVariable$new( -c(2.9, 3.2, 18.4) * 365 + 100 ) - variables$pev_timestep <- mock_double( + variables$last_pev_timestep <- mock_double( + c(50, 50, 50) + ) + variables$last_eff_pev_timestep <- mock_double( c(50, 50, 50) ) variables$pev_profile <- mock_integer( @@ -326,7 +329,13 @@ test_that('Mass boosters update profile params and reschedule correctly', { listener(timestep, individual::Bitset$new(3)$insert(c(1, 2, 3))) expect_bitset_update( - variables$pev_timestep$queue_update_mock(), + variables$last_pev_timestep$queue_update_mock(), + timestep, + c(1, 2, 3) + ) + + expect_bitset_update( + variables$last_eff_pev_timestep$queue_update_mock(), timestep, c(1, 2, 3) ) @@ -368,7 +377,10 @@ test_that('Mass booster coverages sample subpopulations correctly', { variables$birth <- individual::IntegerVariable$new( -c(2.9, 3.2, 18.4) * 365 + 100 ) - variables$pev_timestep <- mock_double( + variables$last_pev_timestep <- mock_double( + c(50, 50, 50) + ) + variables$last_eff_pev_timestep <- mock_double( c(50, 50, 50) ) variables$pev_profile <- mock_integer( @@ -395,7 +407,13 @@ test_that('Mass booster coverages sample subpopulations correctly', { mockery::expect_args(sample_mock, 1, target, .9) expect_bitset_update( - variables$pev_timestep$queue_update_mock(), + variables$last_pev_timestep$queue_update_mock(), + timestep, + c(2, 3) + ) + + expect_bitset_update( + variables$last_eff_pev_timestep$queue_update_mock(), timestep, c(2, 3) ) @@ -413,6 +431,68 @@ test_that('Mass booster coverages sample subpopulations correctly', { ) }) +test_that('mass pev targets correct age and respects min_wait', { + timestep <- 5*365 + parameters <- get_parameters(list(human_population = 5)) + parameters <- set_mass_pev( + parameters, + profile = rtss_profile, + timesteps = c(4, 5) * 365, + coverages = c(0.8, 0.8), + min_ages = 0, + max_ages = 19 * 365, + min_wait = 2*365, + booster_timestep = c(1, 6) * 30, + booster_coverage = c(.9, .8), + booster_profile = list(rtss_booster_profile, rtss_booster_profile) + ) + events <- create_events(parameters) + variables <- create_variables(parameters) + variables$birth <- individual::IntegerVariable$new( + -c(18, 18, 30, 18, 18) * 365 + timestep + ) + variables$last_pev_timestep <- mock_integer( + c(50, -1, -1, 4*365, -1) + ) + + variables$pev_profile <- mock_integer( + c(1, -1, -1, 1, -1) + ) + + correlations <- get_correlation_parameters(parameters) + listener <- create_mass_pev_listener( + variables, + events, + parameters, + get_correlation_parameters(parameters) + ) + + sample_mock <- mockery::mock(c(TRUE, TRUE, FALSE)) + mockery::stub( + listener, + 'sample_intervention', + sample_mock + ) + + listener(timestep) + + mockery::expect_args( + sample_mock, + 1, + c(1, 2, 5), + 'pev', + .8, + correlations + ) + + mockery::expect_args( + variables$last_pev_timestep$queue_update_mock(), + 1, + timestep, + c(1, 2) + ) +}) + test_that('Mass efficacy listener works correctly', { timestep <- 50 parameters <- get_parameters() @@ -430,7 +510,7 @@ test_that('Mass efficacy listener works correctly', { ) variables <- create_variables(parameters) - variables$pev_timestep <- mock_integer(c(-1, -1, -1)) + variables$last_eff_pev_timestep <- mock_integer(c(-1, -1, -1)) variables$pev_profile <- mock_integer(c(-1, -1, -1)) listener <- create_pev_efficacy_listener(variables, 1) @@ -438,7 +518,7 @@ test_that('Mass efficacy listener works correctly', { # vaccinated time expect_bitset_update( - variables$pev_timestep$queue_update_mock(), + variables$last_eff_pev_timestep$queue_update_mock(), timestep, c(1, 2, 3) ) From 5f174c43105c977d9bf48896ea90b151ceaeb7b3 Mon Sep 17 00:00:00 2001 From: Peter Winskill Date: Thu, 23 Nov 2023 13:34:13 +0000 Subject: [PATCH 123/164] Custom carrying capacity is set as a relative scaler, not absolute value --- R/compartmental.R | 2 +- R/vector_control_parameters.R | 15 ++++++++------- src/RcppExports.cpp | 2 +- tests/testthat/test-vector-control.R | 8 ++++---- vignettes/Carrying-capacity.Rmd | 26 +++++++++----------------- 5 files changed, 23 insertions(+), 30 deletions(-) diff --git a/R/compartmental.R b/R/compartmental.R index edba33a6..f3405728 100644 --- a/R/compartmental.R +++ b/R/compartmental.R @@ -16,7 +16,7 @@ parameterise_mosquito_models <- function(parameters, timesteps) { for(j in 1:length(parameters$carrying_capacity_timesteps)){ timeseries_push( k_timeseries, - parameters$carrying_capacity_values[j,i], + parameters$carrying_capacity_scalers[j,i] * k0, parameters$carrying_capacity_timesteps[j] ) } diff --git a/R/vector_control_parameters.R b/R/vector_control_parameters.R index 97c3ce56..43c7c854 100644 --- a/R/vector_control_parameters.R +++ b/R/vector_control_parameters.R @@ -143,23 +143,24 @@ set_spraying <- function( #' #' @param parameters the model parameters #' @param timesteps vector of timesteps for each rescale change -#' @param carrying_capacity matrix of baseline carrying_capacity for each species -#' With nrows = length(timesteps), ncols = length(species) +#' @param carrying_capacity_scalers matrix of scaling factors to scale the baseline +#' carrying capacity for each species with nrows = length(timesteps), +#' ncols = length(species) #' #' @export set_carrying_capacity <- function( parameters, timesteps, - carrying_capacity + carrying_capacity_scalers ){ - stopifnot(nrow(carrying_capacity) == length(timesteps)) - stopifnot(ncol(carrying_capacity) == length(parameters$species)) + stopifnot(nrow(carrying_capacity_scalers) == length(timesteps)) + stopifnot(ncol(carrying_capacity_scalers) == length(parameters$species)) stopifnot(min(timesteps) > 0) - stopifnot(min(carrying_capacity) >= 0) + stopifnot(min(carrying_capacity_scalers) >= 0) parameters$carrying_capacity <- TRUE parameters$carrying_capacity_timesteps <- timesteps - parameters$carrying_capacity_values <- carrying_capacity + parameters$carrying_capacity_scalers <- carrying_capacity_scalers parameters } diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index f5c226fd..affb233d 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -260,7 +260,7 @@ BEGIN_RCPP END_RCPP } -RcppExport SEXP run_testthat_tests(); +RcppExport SEXP run_testthat_tests(void); static const R_CallMethodDef CallEntries[] = { {"_malariasimulation_create_adult_mosquito_model", (DL_FUNC) &_malariasimulation_create_adult_mosquito_model, 5}, diff --git a/tests/testthat/test-vector-control.R b/tests/testthat/test-vector-control.R index 34f9d6ef..8c2e2d49 100644 --- a/tests/testthat/test-vector-control.R +++ b/tests/testthat/test-vector-control.R @@ -372,18 +372,18 @@ test_that('set_carrying_capacity works',{ species = "gamb", carrying_capacity = TRUE, carrying_capacity_timesteps = 1, - carrying_capacity_values = matrix(0.1) + carrying_capacity_scalers = matrix(0.1) ) ) expect_error( set_carrying_capacity(p, 1, matrix(c(0.1, 0.1), nrow = 2)), - "nrow(carrying_capacity) == length(timesteps) is not TRUE", + "nrow(carrying_capacity_scalers) == length(timesteps) is not TRUE", fixed = TRUE ) expect_error( set_carrying_capacity(p, 1, matrix(c(0.1, 0.1), ncol = 2)), - "ncol(carrying_capacity) == length(parameters$species) is not TRUE", + "ncol(carrying_capacity_scalers) == length(parameters$species) is not TRUE", fixed = TRUE ) expect_error( @@ -393,7 +393,7 @@ test_that('set_carrying_capacity works',{ ) expect_error( set_carrying_capacity(p, 1, matrix(-1)), - "min(carrying_capacity) >= 0", + "min(carrying_capacity_scalers) >= 0", fixed = TRUE ) }) diff --git a/vignettes/Carrying-capacity.Rmd b/vignettes/Carrying-capacity.Rmd index c0cfcf7c..fa53203d 100644 --- a/vignettes/Carrying-capacity.Rmd +++ b/vignettes/Carrying-capacity.Rmd @@ -81,17 +81,9 @@ lines(s_seasonal$pfpr ~ s_seasonal$timestep, col = "darkorchid3") ## Custom modification of the mosquito carrying capacity In malariasimulation, we can also modify the carrying capacity over time in a more -bespoke manner. Firstly it is helpful to start with our baseline (equilibrium) -carrying capacity. We can access this for our baseline parameters with: - -```{r} -cc <- get_init_carrying_capacity(p) -cc -``` - -We can then use this in combination with `set_carrying_capacity()` to provide -modified, species-specific carrying capacity values at given timepoints. This -allows us to model a number of useful things: +bespoke manner. We can use the `set_carrying_capacity()` helper function to provide +scalers to modify the species-specific carrying capacity values at given time points. +This allows us to model a number of useful things: ### Larval source management @@ -102,10 +94,10 @@ can be used to specify this intervention ```{r, fig.width = 7, fig.height = 4, out.width='100%'} # Specify the LSM coverage lsm_coverage <- 0.8 -# Set LSM by reducing the carrying capacity by (1 - coverage) +# Set LSM by scaling the carrying capacity by (1 - coverage) p_lsm <- p |> set_carrying_capacity( - carrying_capacity = matrix(cc * (1 - lsm_coverage), ncol = 1), + carrying_capacity_scalers = matrix(1 - lsm_coverage, ncol = 1), timesteps = 365 ) set.seed(123) @@ -136,13 +128,13 @@ invasion of _Anopheles stephensi_. p_stephensi <- p |> set_species(list(gamb_params, steph_params), c(0.995, 1 - 0.995)) |> set_equilibrium(init_EIR = 5) -cc_invasive <- get_init_carrying_capacity(p_stephensi) + # Next, at the time point of invasion, we scale up the carrying capacity for -# the invasive species by a factor that will be dependent on the proporties of +# the invasive species by a factor that will be dependent on the properties of # the invasion. p_stephensi <- p_stephensi |> set_carrying_capacity( - carrying_capacity = matrix(cc_invasive * c(1, 2000), ncol = 2), + carrying_capacity_scalers = matrix(c(1, 2000), ncol = 2), timesteps = 365 ) @@ -169,7 +161,7 @@ time ```{r, fig.width = 7, fig.height = 4, out.width='100%'} p_flexible <- p |> set_carrying_capacity( - carrying_capacity = cc * matrix(c(0.1, 2, 0.1, 0.5, 0.9), ncol = 1), + carrying_capacity = matrix(c(0.1, 2, 0.1, 0.5, 0.9), ncol = 1), timesteps = seq(100, 500, 100) ) From a109246385e0afa6f55e0f1db6dbc2e19fb8b05e Mon Sep 17 00:00:00 2001 From: Peter Winskill Date: Mon, 4 Dec 2023 14:41:37 +0000 Subject: [PATCH 124/164] Document and make suggested changes to carrying capacity vignette for clarity --- R/variables.R | 3 ++- man/set_carrying_capacity.Rd | 7 ++++--- vignettes/Carrying-capacity.Rmd | 12 ++++++++---- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/R/variables.R b/R/variables.R index b84074e4..f9c75e6e 100644 --- a/R/variables.R +++ b/R/variables.R @@ -1,4 +1,5 @@ -#' @title Define model variables #' @description +#' @title Define model variables +#' @description #' create_variables creates the human and mosquito variables for #' the model. Variables are used to track real data for each individual over #' time, they are read and updated by processes diff --git a/man/set_carrying_capacity.Rd b/man/set_carrying_capacity.Rd index eb453800..cf585c6b 100644 --- a/man/set_carrying_capacity.Rd +++ b/man/set_carrying_capacity.Rd @@ -4,15 +4,16 @@ \alias{set_carrying_capacity} \title{Parameterise custom baseline carrying capacity} \usage{ -set_carrying_capacity(parameters, timesteps, carrying_capacity) +set_carrying_capacity(parameters, timesteps, carrying_capacity_scalers) } \arguments{ \item{parameters}{the model parameters} \item{timesteps}{vector of timesteps for each rescale change} -\item{carrying_capacity}{matrix of baseline carrying_capacity for each species -With nrows = length(timesteps), ncols = length(species)} +\item{carrying_capacity_scalers}{matrix of scaling factors to scale the baseline +carrying capacity for each species with nrows = length(timesteps), +ncols = length(species)} } \description{ Allows the user to set a completely flexible and custom diff --git a/vignettes/Carrying-capacity.Rmd b/vignettes/Carrying-capacity.Rmd index fa53203d..39558355 100644 --- a/vignettes/Carrying-capacity.Rmd +++ b/vignettes/Carrying-capacity.Rmd @@ -81,9 +81,13 @@ lines(s_seasonal$pfpr ~ s_seasonal$timestep, col = "darkorchid3") ## Custom modification of the mosquito carrying capacity In malariasimulation, we can also modify the carrying capacity over time in a more -bespoke manner. We can use the `set_carrying_capacity()` helper function to provide -scalers to modify the species-specific carrying capacity values at given time points. -This allows us to model a number of useful things: +bespoke manner. We can use the `set_carrying_capacity()` helper function to +specify scalars that modify the species-specific carrying capacity through time, +relative to the baseline carrying capacity, at defined time steps. The baseline +carrying capacity is generated when calling `set_equilibrium()`, to match the +specified EIR and population size. + +This functionality allows us to model a number of useful things: ### Larval source management @@ -116,7 +120,7 @@ abline(v = 365, lty = 2, col = "grey60") ### Invasive species An invasive species may exploit a new niche, increase the carrying -capacity at the point of invasion. The functions +capacity at the point of invasion. The function `set_carrying_capacity()` gives complete freedom to allow changes to the carrying capacity to be made. Here we will demonstrate using carrying capacity rescaling to capture the From 73cbfb412ec5ccb32e3354c4c4e8084d2bb8a6b9 Mon Sep 17 00:00:00 2001 From: Giovanni Charles Date: Thu, 16 Nov 2023 16:50:30 +0000 Subject: [PATCH 125/164] Implement time varying coverage for PEV boosters: * Update documentation * Update parameterisation and tests * Update booster listener to incorporate timed coverage * Update attach_events to pass timed coverage parameters * Test timed coverage sampling * Bonus: fix a biology test --- R/events.R | 4 + R/pev.R | 18 ++++- R/pev_parameters.R | 19 +++++ man/CorrelationParameters.Rd | 36 ++++----- man/set_mass_pev.Rd | 6 ++ man/set_pev_epi.Rd | 6 ++ tests/testthat/test-biology.R | 4 +- tests/testthat/test-pev-epi.R | 41 ++++++++++ tests/testthat/test-pev.R | 148 ++++++++++++++++++++++++++++++++++ 9 files changed, 261 insertions(+), 21 deletions(-) diff --git a/R/events.R b/R/events.R index 879d72bd..21207e5d 100644 --- a/R/events.R +++ b/R/events.R @@ -133,6 +133,8 @@ attach_event_listeners <- function( events$mass_pev_boosters, parameters$mass_pev_booster_timestep, parameters$mass_pev_booster_coverage, + parameters$mass_pev_timed_booster_coverage, + parameters$mass_pev_timed_booster_coverage_timestep, parameters$mass_pev_profile_indices, 'mass', renderer @@ -147,6 +149,8 @@ attach_event_listeners <- function( events$pev_epi_boosters, parameters$pev_epi_booster_timestep, parameters$pev_epi_booster_coverage, + parameters$pev_epi_timed_booster_coverage, + parameters$pev_epi_timed_booster_coverage_timestep, parameters$pev_epi_profile_indices, 'epi', renderer diff --git a/R/pev.R b/R/pev.R index 039b6044..d37ff6d3 100644 --- a/R/pev.R +++ b/R/pev.R @@ -179,6 +179,8 @@ create_pev_efficacy_listener <- function(variables, pev_profile_index) { create_pev_booster_listener <- function( variables, coverage, + timed_coverage = NULL, + timed_coverage_timestep = NULL, booster_number, pev_profile_index, next_booster_event, @@ -192,7 +194,17 @@ create_pev_booster_listener <- function( force(next_booster_delay) force(coverage) function(timestep, target) { - target <- sample_bitset(target, coverage) + if (is.null(timed_coverage)) { + t_coverage <- 1 + } else { + t_coverage <- timed_coverage[ + match_timestep(timed_coverage_timestep, timestep) + ] + } + target <- sample_bitset( + target, + coverage * t_coverage + ) variables$last_pev_timestep$queue_update(timestep, target) variables$last_eff_pev_timestep$queue_update(timestep, target) variables$pev_profile$queue_update(pev_profile_index, target) @@ -240,6 +252,8 @@ attach_pev_dose_listeners <- function( booster_events, booster_delays, booster_coverages, + booster_timed_coverage, + booster_timed_coverage_timestep, pev_profile_indices, strategy, renderer @@ -303,6 +317,8 @@ attach_pev_dose_listeners <- function( create_pev_booster_listener( variables = variables, coverage = booster_coverages[[b]], + timed_coverage = booster_timed_coverage, + timed_coverage_timestep = booster_timed_coverage_timestep, booster_number = b, pev_profile_index = pev_profile_indices[[b + 1]], next_booster_event = next_booster_event, diff --git a/R/pev_parameters.R b/R/pev_parameters.R index aeb6bd5b..c74f3a94 100644 --- a/R/pev_parameters.R +++ b/R/pev_parameters.R @@ -74,6 +74,8 @@ rtss_booster_profile <- create_pev_profile( #' an individual being vaccinated under one scheme and vaccinated under another. #' @param booster_timestep the timesteps (following the final dose) at which booster vaccinations are administered #' @param booster_coverage the proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series) +#' @param booster_timed_coverage a time varying proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series), set in time with `booster_coverage_timestep` +#' @param booster_timed_coverage_timestep a vector of timesteps to change the time varying coverage specified in `booster_timed_coverage` #' @param booster_profile list of booster vaccine profiles, of type #' PEVProfile, for each timestep in booster_timeteps #' @param seasonal_boosters logical, if TRUE the first booster timestep is @@ -88,6 +90,8 @@ set_pev_epi <- function( min_wait, booster_timestep, booster_coverage, + booster_timed_coverage = NULL, + booster_timed_coverage_timestep = NULL, booster_profile, seasonal_boosters = FALSE ) { @@ -114,6 +118,9 @@ set_pev_epi <- function( if (!all(c(length(booster_coverage), length(booster_timestep), length(booster_profile)) == length(booster_timestep))) { stop('booster_timestep and booster_coverage and booster_profile does not align') } + if (length(booster_timed_coverage) != length(booster_timed_coverage_timestep)) { + stop("booster_coverage_timestep must be the same length as booster_coverage") + } # Index the new vaccine profiles profile_list <- c(list(profile), booster_profile) @@ -128,6 +135,9 @@ set_pev_epi <- function( parameters$pev_epi_booster_timestep <- booster_timestep parameters$pev_epi_min_wait <- min_wait parameters$pev_epi_booster_coverage <- booster_coverage + parameters$pev_epi_booster_timed_coverage <- booster_timed_coverage + parameters$pev_epi_booster_timed_coverage_timestep <- booster_timed_coverage_timestep + parameters$pev_epi_booster_coverage <- booster_coverage parameters$pev_epi_profile_indices <- profile_indices parameters$pev_epi_seasonal_boosters <- seasonal_boosters parameters @@ -149,6 +159,8 @@ set_pev_epi <- function( #' @param max_ages for the target population, inclusive (in timesteps) #' @param booster_timestep the timesteps (following the initial vaccination) at which booster vaccinations are administered #' @param booster_coverage the proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series) +#' @param booster_timed_coverage a time varying proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series), set in time with `booster_coverage_timestep` +#' @param booster_timed_coverage_timestep a vector of timesteps to change the time varying coverage specified in `booster_timed_coverage` #' @param booster_profile list of booster vaccine profiles, of type #' PEVProfile, for each timestep in booster_timeteps #' @export @@ -162,6 +174,8 @@ set_mass_pev <- function( min_wait, booster_timestep, booster_coverage, + booster_timed_coverage = NULL, + booster_timed_coverage_timestep = NULL, booster_profile ) { stopifnot(all(timesteps >= 1)) @@ -176,6 +190,9 @@ set_mass_pev <- function( if (!all(c(length(booster_coverage), length(booster_timestep), length(booster_profile)) == length(booster_timestep))) { stop('booster_timestep, booster_coverage and booster_profile does not align') } + if (length(booster_timed_coverage) != length(booster_timed_coverage_timestep)) { + stop("booster_coverage_timestep must be the same length as booster_coverage") + } # Index the new vaccine profiles profile_list <- c(list(profile), booster_profile) @@ -191,6 +208,8 @@ set_mass_pev <- function( parameters$mass_pev_min_wait <- min_wait parameters$mass_pev_booster_timestep <- booster_timestep parameters$mass_pev_booster_coverage <- booster_coverage + parameters$mass_pev_booster_timed_coverage <- booster_timed_coverage + parameters$mass_pev_booster_timed_coverage_timestep <- booster_timed_coverage_timestep parameters$mass_pev_profile_indices <- profile_indices parameters } diff --git a/man/CorrelationParameters.Rd b/man/CorrelationParameters.Rd index c2e6ada7..b1d22578 100644 --- a/man/CorrelationParameters.Rd +++ b/man/CorrelationParameters.Rd @@ -14,17 +14,17 @@ Describes an event in the simulation \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-CorrelationParameters-new}{\code{CorrelationParameters$new()}} -\item \href{#method-CorrelationParameters-inter_round_rho}{\code{CorrelationParameters$inter_round_rho()}} -\item \href{#method-CorrelationParameters-inter_intervention_rho}{\code{CorrelationParameters$inter_intervention_rho()}} -\item \href{#method-CorrelationParameters-sigma}{\code{CorrelationParameters$sigma()}} -\item \href{#method-CorrelationParameters-mvnorm}{\code{CorrelationParameters$mvnorm()}} -\item \href{#method-CorrelationParameters-clone}{\code{CorrelationParameters$clone()}} +\item \href{#method-new}{\code{CorrelationParameters$new()}} +\item \href{#method-inter_round_rho}{\code{CorrelationParameters$inter_round_rho()}} +\item \href{#method-inter_intervention_rho}{\code{CorrelationParameters$inter_intervention_rho()}} +\item \href{#method-sigma}{\code{CorrelationParameters$sigma()}} +\item \href{#method-mvnorm}{\code{CorrelationParameters$mvnorm()}} +\item \href{#method-clone}{\code{CorrelationParameters$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-CorrelationParameters-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-new}{}}} \subsection{Method \code{new()}}{ initialise correlation parameters \subsection{Usage}{ @@ -40,8 +40,8 @@ initialise correlation parameters } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-CorrelationParameters-inter_round_rho}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-inter_round_rho}{}}} \subsection{Method \code{inter_round_rho()}}{ Add rho between rounds \subsection{Usage}{ @@ -60,8 +60,8 @@ the intervention} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-CorrelationParameters-inter_intervention_rho}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-inter_intervention_rho}{}}} \subsection{Method \code{inter_intervention_rho()}}{ Add rho between interventions \subsection{Usage}{ @@ -83,8 +83,8 @@ the intervention} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-CorrelationParameters-sigma}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-sigma}{}}} \subsection{Method \code{sigma()}}{ Standard deviation of each intervention between rounds \subsection{Usage}{ @@ -93,8 +93,8 @@ Standard deviation of each intervention between rounds } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-CorrelationParameters-mvnorm}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-mvnorm}{}}} \subsection{Method \code{mvnorm()}}{ multivariate norm draws for these parameters \subsection{Usage}{ @@ -103,8 +103,8 @@ multivariate norm draws for these parameters } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-CorrelationParameters-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/set_mass_pev.Rd b/man/set_mass_pev.Rd index 7c28547f..e088e0bb 100644 --- a/man/set_mass_pev.Rd +++ b/man/set_mass_pev.Rd @@ -14,6 +14,8 @@ set_mass_pev( min_wait, booster_timestep, booster_coverage, + booster_timed_coverage = NULL, + booster_timed_coverage_timestep = NULL, booster_profile ) } @@ -38,6 +40,10 @@ time between an individual being vaccinated under one scheme and vaccinated unde \item{booster_coverage}{the proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series)} +\item{booster_timed_coverage}{a time varying proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series), set in time with \code{booster_coverage_timestep}} + +\item{booster_timed_coverage_timestep}{a vector of timesteps to change the time varying coverage specified in \code{booster_timed_coverage}} + \item{booster_profile}{list of booster vaccine profiles, of type PEVProfile, for each timestep in booster_timeteps} } diff --git a/man/set_pev_epi.Rd b/man/set_pev_epi.Rd index 4dea14ed..2f7e7ced 100644 --- a/man/set_pev_epi.Rd +++ b/man/set_pev_epi.Rd @@ -13,6 +13,8 @@ set_pev_epi( min_wait, booster_timestep, booster_coverage, + booster_timed_coverage = NULL, + booster_timed_coverage_timestep = NULL, booster_profile, seasonal_boosters = FALSE ) @@ -39,6 +41,10 @@ an individual being vaccinated under one scheme and vaccinated under another.} \item{booster_coverage}{the proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series)} +\item{booster_timed_coverage}{a time varying proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series), set in time with \code{booster_coverage_timestep}} + +\item{booster_timed_coverage_timestep}{a vector of timesteps to change the time varying coverage specified in \code{booster_timed_coverage}} + \item{booster_profile}{list of booster vaccine profiles, of type PEVProfile, for each timestep in booster_timeteps} diff --git a/tests/testthat/test-biology.R b/tests/testthat/test-biology.R index 5895d45b..c739f7e7 100644 --- a/tests/testthat/test-biology.R +++ b/tests/testthat/test-biology.R @@ -92,13 +92,13 @@ test_that('FOIM is consistent with equilibrium', { psi <- unique_biting_rate(age, parameters) zeta <- variables$zeta$get_values() .pi <- human_pi(psi, zeta) - calculate_foim(a, sum(.pi * variables$infectivity$get_values())) + calculate_foim(a, sum(.pi * variables$infectivity$get_values()), 1.) } ) expect_equal( expected_foim, actual_foim, - tolerance = 1e-4 + tolerance = 1e-3 ) }) diff --git a/tests/testthat/test-pev-epi.R b/tests/testthat/test-pev-epi.R index ef9148a3..26541b9c 100644 --- a/tests/testthat/test-pev-epi.R +++ b/tests/testthat/test-pev-epi.R @@ -51,6 +51,47 @@ test_that('pev epi strategy parameterisation works', { ) }) +test_that('I can add time varying booster coverage to the pev epi strategy', { + parameters <- get_parameters() + parameters <- set_pev_epi( + parameters, + profile = rtss_profile, + coverages = c(0.1, 0.8), + timesteps = c(10, 100), + min_wait = 0, + age = 5 * 30, + booster_timestep = c(18, 36) * 30, + booster_coverage = c(.9, .8), + booster_timed_coverage = c(.5, .7), + booster_timed_coverage_timestep = c(365, 2*365), + booster_profile = list(rtss_booster_profile, rtss_booster_profile) + ) + expect_equal(parameters$pev_epi_booster_timestep, c(18, 36) * 30) + expect_equal(parameters$pev_epi_booster_coverage, c(.9, .8)) + expect_equal(parameters$pev_epi_booster_timed_coverage, c(.5, .7)) + expect_equal(parameters$pev_epi_booster_timed_coverage_timestep, c(365, 2*365)) + expect_equal(parameters$pev_profiles, list(rtss_profile, rtss_booster_profile, rtss_booster_profile)) + + expect_error( + parameters <- set_pev_epi( + parameters, + profile = rtss_profile, + coverages = c(0.1, 0.8), + timesteps = c(10, 100), + min_wait = 0, + age = 5 * 30, + booster_timestep = c(18, 36) * 30, + booster_coverage = c(.9, .8), + booster_timed_coverage = c(.5, .7), + booster_timed_coverage_timestep = 365, + booster_profile = list(rtss_booster_profile, rtss_booster_profile) + ), + "booster_coverage_timestep must be the same length as booster_coverage", + fixed = TRUE + ) +}) + + test_that('pev epi fails pre-emptively with unaligned booster parameters', { parameters <- get_parameters() expect_error( diff --git a/tests/testthat/test-pev.R b/tests/testthat/test-pev.R index 30007cd3..16f65849 100644 --- a/tests/testthat/test-pev.R +++ b/tests/testthat/test-pev.R @@ -54,6 +54,49 @@ test_that('Mass vaccination strategy parameterisation works', { ) }) +test_that('I can add time varying booster coverage to the mass pev strategy', { + parameters <- get_parameters() + parameters <- set_mass_pev( + parameters, + profile = rtss_profile, + timesteps = 10, + coverages = 0.8, + min_wait = 0, + min_ages = 5 * 30, + max_ages = 17 * 30, + booster_timestep = c(18, 36) * 30, + booster_coverage = c(.9, .8), + booster_timed_coverage = c(.5, .7), + booster_timed_coverage_timestep = c(365, 2*365), + booster_profile = list(rtss_booster_profile, rtss_booster_profile) + ) + + expect_equal(parameters$mass_pev_booster_timestep, c(18, 36) * 30) + expect_equal(parameters$mass_pev_booster_timed_coverage, c(.5, .7)) + expect_equal(parameters$mass_pev_booster_timed_coverage_timestep, c(365, 2*365)) + expect_equal(parameters$pev_profiles, list(rtss_profile, rtss_booster_profile, rtss_booster_profile)) + + expect_error( + parameters <- set_mass_pev( + parameters, + profile = rtss_profile, + timesteps = 10, + coverages = 0.8, + min_wait = 0, + min_ages = 5 * 30, + max_ages = 17 * 30, + booster_timestep = c(18, 36) * 30, + booster_coverage = c(.9, .8), + booster_timed_coverage = c(.5, .7), + booster_timed_coverage_timestep = 365, + booster_profile = list(rtss_booster_profile, rtss_booster_profile) + ), + "booster_coverage_timestep must be the same length as booster_coverage", + fixed = TRUE + ) +}) + + test_that('Mass vaccination fails pre-emptively for unaligned booster parameters', { parameters <- get_parameters() expect_error( @@ -557,6 +600,8 @@ test_that('Mass dose events are not ruined by lazy evaluation', { booster_events = events$mass_pev_boosters, booster_delays = parameters$mass_pev_booster_timestep, booster_coverages = parameters$mass_pev_booster_coverage, + booster_timed_coverage = NULL, + booster_timed_coverage_timestep = NULL, pev_profile_indices = parameters$mass_pev_profile_indices, strategy = 'mass', renderer = mock_render(1) @@ -612,4 +657,107 @@ test_that('Efficacies are calculated correctly', { ) }) +test_that('pev timed booster coverage works with NULL', { + timestep <- 5 * 365 + parameters <- get_parameters(list(human_population = 5)) + parameters <- set_pev_epi( + parameters, + profile = rtss_profile, + timesteps = 10, + coverages = 0.8, + min_wait = 6 * 30, + age = 18 * 365, + booster_timestep = c(3, 12) * 30, + booster_coverage = c(.9, .8), + booster_timed_coverage = c(.5, .7), + booster_timed_coverage_timestep = c(timestep, timestep + 365), + booster_profile = list(rtss_booster_profile, rtss_booster_profile), + ) + events <- create_events(parameters) + + booster_event <- mock_event(events$pev_epi_boosters[[1]]) + + listener <- create_pev_booster_listener( + variables = create_variables(parameters), + coverage = .9, + timed_coverage = NULL, + timed_coverage_timestep = NULL, + booster_number = 1, + pev_profile_index = 2, + next_booster_event = booster_event, + next_booster_delay = 9 * 30, + renderer = mock_render(timestep), + strategy = 'epi' + ) + + target <- individual::Bitset$new(5)$insert(seq(5)) + + mock_sample_bitset = mockery::mock(individual::Bitset$new(5)$insert(c(1, 2))) + mockery::stub( + listener, + 'sample_bitset', + mock_sample_bitset + ) + + listener(timestep, target) + + mockery::expect_args( + mock_sample_bitset, + 1, + target, + .9 + ) +}) + + +test_that('pev boosters take into account the timed coverage', { + timestep <- 5 * 365 + parameters <- get_parameters(list(human_population = 5)) + parameters <- set_pev_epi( + parameters, + profile = rtss_profile, + timesteps = 10, + coverages = 0.8, + min_wait = 6 * 30, + age = 18 * 365, + booster_timestep = c(3, 12) * 30, + booster_coverage = c(.9, .8), + booster_timed_coverage = c(.5, .7), + booster_timed_coverage_timestep = c(timestep, timestep + 365), + booster_profile = list(rtss_booster_profile, rtss_booster_profile), + ) + events <- create_events(parameters) + + booster_event <- mock_event(events$pev_epi_boosters[[1]]) + + listener <- create_pev_booster_listener( + variables = create_variables(parameters), + coverage = .9, + timed_coverage = c(.5, .7), + timed_coverage_timestep = c(timestep, timestep + 365), + booster_number = 1, + pev_profile_index = 2, + next_booster_event = booster_event, + next_booster_delay = 9 * 30, + renderer = mock_render(timestep), + strategy = 'epi' + ) + + target <- individual::Bitset$new(5)$insert(seq(5)) + + mock_sample_bitset = mockery::mock(individual::Bitset$new(5)$insert(c(1, 2))) + mockery::stub( + listener, + 'sample_bitset', + mock_sample_bitset + ) + + listener(timestep, target) + mockery::expect_args( + mock_sample_bitset, + 1, + target, + .45 + ) +}) From d49c8dd75c09bffad38382eefeaf63cf0375f977 Mon Sep 17 00:00:00 2001 From: Giovanni Charles Date: Wed, 6 Dec 2023 16:36:55 +0000 Subject: [PATCH 126/164] Fix PEV EPI parameterisation bug --- R/pev_parameters.R | 4 ++-- tests/testthat/test-pev-epi.R | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/R/pev_parameters.R b/R/pev_parameters.R index c74f3a94..6648dd29 100644 --- a/R/pev_parameters.R +++ b/R/pev_parameters.R @@ -135,8 +135,8 @@ set_pev_epi <- function( parameters$pev_epi_booster_timestep <- booster_timestep parameters$pev_epi_min_wait <- min_wait parameters$pev_epi_booster_coverage <- booster_coverage - parameters$pev_epi_booster_timed_coverage <- booster_timed_coverage - parameters$pev_epi_booster_timed_coverage_timestep <- booster_timed_coverage_timestep + parameters$pev_epi_timed_booster_coverage <- booster_timed_coverage + parameters$pev_epi_timed_booster_coverage_timestep <- booster_timed_coverage_timestep parameters$pev_epi_booster_coverage <- booster_coverage parameters$pev_epi_profile_indices <- profile_indices parameters$pev_epi_seasonal_boosters <- seasonal_boosters diff --git a/tests/testthat/test-pev-epi.R b/tests/testthat/test-pev-epi.R index 26541b9c..a1c718cb 100644 --- a/tests/testthat/test-pev-epi.R +++ b/tests/testthat/test-pev-epi.R @@ -68,8 +68,8 @@ test_that('I can add time varying booster coverage to the pev epi strategy', { ) expect_equal(parameters$pev_epi_booster_timestep, c(18, 36) * 30) expect_equal(parameters$pev_epi_booster_coverage, c(.9, .8)) - expect_equal(parameters$pev_epi_booster_timed_coverage, c(.5, .7)) - expect_equal(parameters$pev_epi_booster_timed_coverage_timestep, c(365, 2*365)) + expect_equal(parameters$pev_epi_timed_booster_coverage, c(.5, .7)) + expect_equal(parameters$pev_epi_timed_booster_coverage_timestep, c(365, 2*365)) expect_equal(parameters$pev_profiles, list(rtss_profile, rtss_booster_profile, rtss_booster_profile)) expect_error( From 91247b4eee779c8b426bb7aa50b28cb4244b363b Mon Sep 17 00:00:00 2001 From: Giovanni Charles Date: Thu, 4 Jan 2024 15:44:27 +0000 Subject: [PATCH 127/164] Implement simplified pev booster interface: * rename booster_timesteps -> booster_spacing * make booster_coverage a matrix (timestep x booster doses) * update validation * update implementation of attach_booster_listener * fix regression tests * update documentation * update vignettes * fix correlation examples --- R/correlation.R | 2 +- R/events.R | 14 +- R/pev.R | 27 ++-- R/pev_parameters.R | 73 +++++----- man/get_correlation_parameters.Rd | 2 +- man/set_mass_pev.Rd | 17 +-- man/set_pev_epi.Rd | 19 +-- tests/testthat/test-infection-integration.R | 4 +- tests/testthat/test-pev-epi.R | 80 +++-------- tests/testthat/test-pev.R | 140 ++++++++------------ vignettes/Vaccines.Rmd | 20 +-- 11 files changed, 150 insertions(+), 248 deletions(-) diff --git a/R/correlation.R b/R/correlation.R index 41ea6a82..68119369 100644 --- a/R/correlation.R +++ b/R/correlation.R @@ -139,7 +139,7 @@ CorrelationParameters <- R6::R6Class( #' min_wait = 0, #' min_ages = 100, #' max_ages = 1000, -#' booster_timestep = numeric(0), +#' booster_spacing = numeric(0), #' booster_coverage = numeric(0), #' booster_profile = NULL #' ) diff --git a/R/events.R b/R/events.R index 21207e5d..d7ad3416 100644 --- a/R/events.R +++ b/R/events.R @@ -18,7 +18,7 @@ create_events <- function(parameters) { function(.) individual::TargetedEvent$new(parameters$human_population) ) mass_pev_boosters <- lapply( - seq_along(parameters$mass_pev_booster_timestep), + seq_along(parameters$mass_pev_booster_spacing), function(.) individual::TargetedEvent$new(parameters$human_population) ) events$mass_pev <- individual::Event$new() @@ -33,7 +33,7 @@ create_events <- function(parameters) { function(.) individual::TargetedEvent$new(parameters$human_population) ) pev_epi_boosters <- lapply( - seq_along(parameters$pev_epi_booster_timestep), + seq_along(parameters$pev_epi_booster_spacing), function(.) individual::TargetedEvent$new(parameters$human_population) ) events$pev_epi_doses <- pev_epi_doses @@ -129,12 +129,11 @@ attach_event_listeners <- function( attach_pev_dose_listeners( variables, parameters, + parameters$mass_pev_timesteps, events$mass_pev_doses, events$mass_pev_boosters, - parameters$mass_pev_booster_timestep, + parameters$mass_pev_booster_spacing, parameters$mass_pev_booster_coverage, - parameters$mass_pev_timed_booster_coverage, - parameters$mass_pev_timed_booster_coverage_timestep, parameters$mass_pev_profile_indices, 'mass', renderer @@ -145,12 +144,11 @@ attach_event_listeners <- function( attach_pev_dose_listeners( variables, parameters, + parameters$pev_epi_timesteps, events$pev_epi_doses, events$pev_epi_boosters, - parameters$pev_epi_booster_timestep, + parameters$pev_epi_booster_spacing, parameters$pev_epi_booster_coverage, - parameters$pev_epi_timed_booster_coverage, - parameters$pev_epi_timed_booster_coverage_timestep, parameters$pev_epi_profile_indices, 'epi', renderer diff --git a/R/pev.R b/R/pev.R index d37ff6d3..bc27fc9f 100644 --- a/R/pev.R +++ b/R/pev.R @@ -179,8 +179,7 @@ create_pev_efficacy_listener <- function(variables, pev_profile_index) { create_pev_booster_listener <- function( variables, coverage, - timed_coverage = NULL, - timed_coverage_timestep = NULL, + pev_distribution_timesteps, booster_number, pev_profile_index, next_booster_event, @@ -194,17 +193,11 @@ create_pev_booster_listener <- function( force(next_booster_delay) force(coverage) function(timestep, target) { - if (is.null(timed_coverage)) { - t_coverage <- 1 - } else { - t_coverage <- timed_coverage[ - match_timestep(timed_coverage_timestep, timestep) - ] - } - target <- sample_bitset( - target, - coverage * t_coverage - ) + cov_t <- coverage[ + match_timestep(pev_distribution_timesteps, timestep), + booster_number + ] + target <- sample_bitset(target, cov_t) variables$last_pev_timestep$queue_update(timestep, target) variables$last_eff_pev_timestep$queue_update(timestep, target) variables$pev_profile$queue_update(pev_profile_index, target) @@ -248,12 +241,11 @@ create_dosage_renderer <- function(renderer, strategy, dose) { attach_pev_dose_listeners <- function( variables, parameters, + pev_distribution_timesteps, dose_events, booster_events, booster_delays, booster_coverages, - booster_timed_coverage, - booster_timed_coverage_timestep, pev_profile_indices, strategy, renderer @@ -316,9 +308,8 @@ attach_pev_dose_listeners <- function( booster_events[[b]]$add_listener( create_pev_booster_listener( variables = variables, - coverage = booster_coverages[[b]], - timed_coverage = booster_timed_coverage, - timed_coverage_timestep = booster_timed_coverage_timestep, + coverage = booster_coverages, + pev_distribution_timesteps = pev_distribution_timesteps, booster_number = b, pev_profile_index = pev_profile_indices[[b + 1]], next_booster_event = next_booster_event, diff --git a/R/pev_parameters.R b/R/pev_parameters.R index 6648dd29..73947b29 100644 --- a/R/pev_parameters.R +++ b/R/pev_parameters.R @@ -62,7 +62,7 @@ rtss_booster_profile <- create_pev_profile( #' age. Efficacy will take effect after the last dose #' #' @param parameters a list of parameters to modify -#' @param profile primary vaccine profile of type PEVProfile +#' @param profile a list of details for the vaccine profile, create with `create_pev_profile` #' @param coverages a vector of coverages for the primary doses #' @param timesteps a vector of timesteps associated with coverages #' @param age the age when an individual will receive the first dose of the @@ -72,14 +72,11 @@ rtss_booster_profile <- create_pev_profile( #' between an individual receiving the final dose and the first booster. When using #' both set_mass_pev and set_pev_epi, this represents the minimum time between #' an individual being vaccinated under one scheme and vaccinated under another. -#' @param booster_timestep the timesteps (following the final dose) at which booster vaccinations are administered -#' @param booster_coverage the proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series) -#' @param booster_timed_coverage a time varying proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series), set in time with `booster_coverage_timestep` -#' @param booster_timed_coverage_timestep a vector of timesteps to change the time varying coverage specified in `booster_timed_coverage` -#' @param booster_profile list of booster vaccine profiles, of type -#' PEVProfile, for each timestep in booster_timeteps +#' @param booster_spacing the timesteps (following the final primary dose) at which booster vaccinations are administered +#' @param booster_coverage a matrix of coverages (timesteps x boosters) specifying the proportion the previously vaccinated population to continue receiving booster doses. The rows of the matrix must be the same size as `timesteps`. The columns of the matrix must be the same size as `booster_spacing`. +#' @param booster_profile list of lists representing each booster profile, the outer list must be the same length as `booster_spacing`. Create vaccine profiles with `create_pev_profile` #' @param seasonal_boosters logical, if TRUE the first booster timestep is -#' relative to the start of the year, otherwise they are relative to the last dose +#' relative to the start of the year, otherwise they are relative to the last primary dose #' @export set_pev_epi <- function( parameters, @@ -88,14 +85,13 @@ set_pev_epi <- function( timesteps, age, min_wait, - booster_timestep, + booster_spacing, booster_coverage, - booster_timed_coverage = NULL, - booster_timed_coverage_timestep = NULL, booster_profile, seasonal_boosters = FALSE ) { stopifnot(all(coverages >= 0) && all(coverages <= 1)) + stopifnot(is.matrix(booster_coverage)) # Check that the primary timing parameters make sense if(length(coverages) != length(timesteps)){ @@ -107,19 +103,22 @@ set_pev_epi <- function( stopifnot(age >= 0) stopifnot(is.logical(seasonal_boosters)) if (seasonal_boosters) { - if(booster_timestep[[1]] < 0) { - booster_timestep <- booster_timestep + 365 + if(booster_spacing[[1]] < 0) { + booster_spacing <- booster_spacing + 365 } } # Check that the booster timing parameters make sense - stopifnot((length(booster_timestep) == 0) || all(booster_timestep > 0)) + stopifnot((length(booster_spacing) == 0) || all(booster_spacing > 0)) stopifnot((length(booster_coverage)) == 0 || all(booster_coverage >= 0 & booster_coverage <= 1)) - if (!all(c(length(booster_coverage), length(booster_timestep), length(booster_profile)) == length(booster_timestep))) { - stop('booster_timestep and booster_coverage and booster_profile does not align') + if (!all(c(ncol(booster_coverage), length(booster_profile)) == length(booster_spacing))) { + stop('booster_spacing, booster_coverage and booster_profile do not align') } - if (length(booster_timed_coverage) != length(booster_timed_coverage_timestep)) { - stop("booster_coverage_timestep must be the same length as booster_coverage") + # Check that booster_coverage and timesteps align + if (length(booster_coverage) > 0) { + if (nrow(booster_coverage) != length(timesteps)) { + stop('booster_coverage and timesteps do not align') + } } # Index the new vaccine profiles @@ -132,12 +131,9 @@ set_pev_epi <- function( parameters$pev_epi_coverages <- coverages parameters$pev_epi_timesteps <- timesteps parameters$pev_epi_age <- age - parameters$pev_epi_booster_timestep <- booster_timestep + parameters$pev_epi_booster_spacing <- booster_spacing parameters$pev_epi_min_wait <- min_wait parameters$pev_epi_booster_coverage <- booster_coverage - parameters$pev_epi_timed_booster_coverage <- booster_timed_coverage - parameters$pev_epi_timed_booster_coverage_timestep <- booster_timed_coverage_timestep - parameters$pev_epi_booster_coverage <- booster_coverage parameters$pev_epi_profile_indices <- profile_indices parameters$pev_epi_seasonal_boosters <- seasonal_boosters parameters @@ -149,7 +145,7 @@ set_pev_epi <- function( #' Efficacy will take effect after the last dose #' #' @param parameters a list of parameters to modify -#' @param profile primary vaccine profile of type PEVProfile +#' @param profile a list of details for the vaccine profile, create with `create_pev_profile` #' @param timesteps a vector of timesteps for each round of vaccinations #' @param coverages the coverage for each round of vaccinations #' @param min_wait the minimum acceptable time since the last vaccination (in timesteps); @@ -157,12 +153,9 @@ set_pev_epi <- function( #' time between an individual being vaccinated under one scheme and vaccinated under another. #' @param min_ages for the target population, inclusive (in timesteps) #' @param max_ages for the target population, inclusive (in timesteps) -#' @param booster_timestep the timesteps (following the initial vaccination) at which booster vaccinations are administered -#' @param booster_coverage the proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series) -#' @param booster_timed_coverage a time varying proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series), set in time with `booster_coverage_timestep` -#' @param booster_timed_coverage_timestep a vector of timesteps to change the time varying coverage specified in `booster_timed_coverage` -#' @param booster_profile list of booster vaccine profiles, of type -#' PEVProfile, for each timestep in booster_timeteps +#' @param booster_spacing the timesteps (following the final primary dose) at which booster vaccinations are administered +#' @param booster_coverage a matrix of coverages (timesteps x boosters) specifying the proportion the previously vaccinated population to continue receiving booster doses. The rows of the matrix must be the same size as `timesteps`. The columns of the matrix must be the same size as `booster_spacing`. +#' @param booster_profile list of lists representing each booster profile, the outer list must be the same length as `booster_spacing`. Create vaccine profiles with `create_pev_profile` #' @export set_mass_pev <- function( parameters, @@ -172,26 +165,28 @@ set_mass_pev <- function( min_ages, max_ages, min_wait, - booster_timestep, + booster_spacing, booster_coverage, - booster_timed_coverage = NULL, - booster_timed_coverage_timestep = NULL, booster_profile ) { stopifnot(all(timesteps >= 1)) stopifnot(min_wait >= 0) stopifnot(all(coverages >= 0) && all(coverages <= 1)) stopifnot(all(min_ages >= 0 & max_ages >= 0)) - stopifnot(all(booster_timestep > 0)) + stopifnot(all(booster_spacing > 0)) stopifnot(all(booster_coverage >= 0 & booster_coverage <= 1)) if (length(min_ages) != length(max_ages)) { stop('min and max ages do not align') } - if (!all(c(length(booster_coverage), length(booster_timestep), length(booster_profile)) == length(booster_timestep))) { - stop('booster_timestep, booster_coverage and booster_profile does not align') + stopifnot((length(booster_coverage)) == 0 || all(booster_coverage >= 0 & booster_coverage <= 1)) + if (!all(c(ncol(booster_coverage), length(booster_profile)) == length(booster_spacing))) { + stop('booster_spacing, booster_coverage and booster_profile do not align') } - if (length(booster_timed_coverage) != length(booster_timed_coverage_timestep)) { - stop("booster_coverage_timestep must be the same length as booster_coverage") + # Check that booster_coverage and timesteps align + if (length(booster_coverage) > 0) { + if (nrow(booster_coverage) != length(timesteps)) { + stop('booster_coverage and timesteps do not align') + } } # Index the new vaccine profiles @@ -206,10 +201,8 @@ set_mass_pev <- function( parameters$mass_pev_min_ages <- min_ages parameters$mass_pev_max_ages <- max_ages parameters$mass_pev_min_wait <- min_wait - parameters$mass_pev_booster_timestep <- booster_timestep + parameters$mass_pev_booster_spacing <- booster_spacing parameters$mass_pev_booster_coverage <- booster_coverage - parameters$mass_pev_booster_timed_coverage <- booster_timed_coverage - parameters$mass_pev_booster_timed_coverage_timestep <- booster_timed_coverage_timestep parameters$mass_pev_profile_indices <- profile_indices parameters } diff --git a/man/get_correlation_parameters.Rd b/man/get_correlation_parameters.Rd index 21995b91..068aed64 100644 --- a/man/get_correlation_parameters.Rd +++ b/man/get_correlation_parameters.Rd @@ -27,7 +27,7 @@ parameters <- set_mass_pev( min_wait = 0, min_ages = 100, max_ages = 1000, - booster_timestep = numeric(0), + booster_spacing = numeric(0), booster_coverage = numeric(0), booster_profile = NULL ) diff --git a/man/set_mass_pev.Rd b/man/set_mass_pev.Rd index e088e0bb..ef3263e5 100644 --- a/man/set_mass_pev.Rd +++ b/man/set_mass_pev.Rd @@ -12,17 +12,15 @@ set_mass_pev( min_ages, max_ages, min_wait, - booster_timestep, + booster_spacing, booster_coverage, - booster_timed_coverage = NULL, - booster_timed_coverage_timestep = NULL, booster_profile ) } \arguments{ \item{parameters}{a list of parameters to modify} -\item{profile}{primary vaccine profile of type PEVProfile} +\item{profile}{a list of details for the vaccine profile, create with \code{create_pev_profile}} \item{timesteps}{a vector of timesteps for each round of vaccinations} @@ -36,16 +34,11 @@ set_mass_pev( When using both set_mass_pev and set_pev_epi, this represents the minimum time between an individual being vaccinated under one scheme and vaccinated under another.} -\item{booster_timestep}{the timesteps (following the initial vaccination) at which booster vaccinations are administered} +\item{booster_spacing}{the timesteps (following the final primary dose) at which booster vaccinations are administered} -\item{booster_coverage}{the proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series)} +\item{booster_coverage}{a matrix of coverages (timesteps x boosters) specifying the proportion the previously vaccinated population to continue receiving booster doses. The rows of the matrix must be the same size as \code{timesteps}. The columns of the matrix must be the same size as \code{booster_spacing}.} -\item{booster_timed_coverage}{a time varying proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series), set in time with \code{booster_coverage_timestep}} - -\item{booster_timed_coverage_timestep}{a vector of timesteps to change the time varying coverage specified in \code{booster_timed_coverage}} - -\item{booster_profile}{list of booster vaccine profiles, of type -PEVProfile, for each timestep in booster_timeteps} +\item{booster_profile}{list of lists representing each booster profile, the outer list must be the same length as \code{booster_spacing}. Create vaccine profiles with \code{create_pev_profile}} } \description{ distribute pre-erythrocytic vaccine to a population in an age range. diff --git a/man/set_pev_epi.Rd b/man/set_pev_epi.Rd index 2f7e7ced..a3a4d195 100644 --- a/man/set_pev_epi.Rd +++ b/man/set_pev_epi.Rd @@ -11,10 +11,8 @@ set_pev_epi( timesteps, age, min_wait, - booster_timestep, + booster_spacing, booster_coverage, - booster_timed_coverage = NULL, - booster_timed_coverage_timestep = NULL, booster_profile, seasonal_boosters = FALSE ) @@ -22,7 +20,7 @@ set_pev_epi( \arguments{ \item{parameters}{a list of parameters to modify} -\item{profile}{primary vaccine profile of type PEVProfile} +\item{profile}{a list of details for the vaccine profile, create with \code{create_pev_profile}} \item{coverages}{a vector of coverages for the primary doses} @@ -37,19 +35,14 @@ between an individual receiving the final dose and the first booster. When using both set_mass_pev and set_pev_epi, this represents the minimum time between an individual being vaccinated under one scheme and vaccinated under another.} -\item{booster_timestep}{the timesteps (following the final dose) at which booster vaccinations are administered} +\item{booster_spacing}{the timesteps (following the final primary dose) at which booster vaccinations are administered} -\item{booster_coverage}{the proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series)} +\item{booster_coverage}{a matrix of coverages (timesteps x boosters) specifying the proportion the previously vaccinated population to continue receiving booster doses. The rows of the matrix must be the same size as \code{timesteps}. The columns of the matrix must be the same size as \code{booster_spacing}.} -\item{booster_timed_coverage}{a time varying proportion of the vaccinated population relative to the last vaccination (whether a previous booster or the primary series), set in time with \code{booster_coverage_timestep}} - -\item{booster_timed_coverage_timestep}{a vector of timesteps to change the time varying coverage specified in \code{booster_timed_coverage}} - -\item{booster_profile}{list of booster vaccine profiles, of type -PEVProfile, for each timestep in booster_timeteps} +\item{booster_profile}{list of lists representing each booster profile, the outer list must be the same length as \code{booster_spacing}. Create vaccine profiles with \code{create_pev_profile}} \item{seasonal_boosters}{logical, if TRUE the first booster timestep is -relative to the start of the year, otherwise they are relative to the last dose} +relative to the start of the year, otherwise they are relative to the last primary dose} } \description{ distribute vaccine when an individual becomes a certain diff --git a/tests/testthat/test-infection-integration.R b/tests/testthat/test-infection-integration.R index 238a2ae6..0400a361 100644 --- a/tests/testthat/test-infection-integration.R +++ b/tests/testthat/test-infection-integration.R @@ -121,8 +121,8 @@ test_that('calculate_infections works various combinations of drug and vaccinati min_ages = 0, max_ages = 100 * 365, min_wait = 0, - booster_timestep = 365, - booster_coverage = 1, + booster_spacing = 365, + booster_coverage = matrix(1), booster_profile = list(rtss_booster_profile) ) diff --git a/tests/testthat/test-pev-epi.R b/tests/testthat/test-pev-epi.R index a1c718cb..56db32e7 100644 --- a/tests/testthat/test-pev-epi.R +++ b/tests/testthat/test-pev-epi.R @@ -7,8 +7,8 @@ test_that('pev epi strategy parameterisation works', { timesteps = c(10, 100), min_wait = 0, age = 5 * 30, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(c(.9, .8, .9, .8), nrow=2, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ) expect_equal(parameters$pev, TRUE) @@ -16,7 +16,7 @@ test_that('pev epi strategy parameterisation works', { expect_equal(parameters$pev_epi_timesteps, c(10, 100)) expect_equal(parameters$pev_epi_age, 5 * 30) expect_equal(parameters$pev_epi_min_wait, 0) - expect_equal(parameters$pev_epi_booster_timestep, c(18, 36) * 30) + expect_equal(parameters$pev_epi_booster_spacing, c(18, 36) * 30) expect_equal(parameters$pev_profiles, list(rtss_profile, rtss_booster_profile, rtss_booster_profile)) expect_equal(parameters$pev_epi_profile_indices, seq(3)) @@ -28,8 +28,8 @@ test_that('pev epi strategy parameterisation works', { timesteps = 10, min_wait = 0, age = 5 * 30, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(c(.9, .8, .9, .8), nrow=2, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ), "all(coverages >= 0) && all(coverages <= 1) is not TRUE", fixed = TRUE @@ -43,35 +43,16 @@ test_that('pev epi strategy parameterisation works', { timesteps = 10, min_wait = 0, age = 5 * 30, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(c(.9, .8, .9, .8), nrow=2, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ), "all(coverages >= 0) && all(coverages <= 1) is not TRUE", fixed = TRUE ) }) -test_that('I can add time varying booster coverage to the pev epi strategy', { +test_that('set_pev_epi checks booster coverage matrix shape', { parameters <- get_parameters() - parameters <- set_pev_epi( - parameters, - profile = rtss_profile, - coverages = c(0.1, 0.8), - timesteps = c(10, 100), - min_wait = 0, - age = 5 * 30, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), - booster_timed_coverage = c(.5, .7), - booster_timed_coverage_timestep = c(365, 2*365), - booster_profile = list(rtss_booster_profile, rtss_booster_profile) - ) - expect_equal(parameters$pev_epi_booster_timestep, c(18, 36) * 30) - expect_equal(parameters$pev_epi_booster_coverage, c(.9, .8)) - expect_equal(parameters$pev_epi_timed_booster_coverage, c(.5, .7)) - expect_equal(parameters$pev_epi_timed_booster_coverage_timestep, c(365, 2*365)) - expect_equal(parameters$pev_profiles, list(rtss_profile, rtss_booster_profile, rtss_booster_profile)) - expect_error( parameters <- set_pev_epi( parameters, @@ -80,34 +61,15 @@ test_that('I can add time varying booster coverage to the pev epi strategy', { timesteps = c(10, 100), min_wait = 0, age = 5 * 30, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), - booster_timed_coverage = c(.5, .7), - booster_timed_coverage_timestep = 365, + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(c(.9, .8), nrow=2, ncol=1), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ), - "booster_coverage_timestep must be the same length as booster_coverage", + 'booster_spacing, booster_coverage and booster_profile do not align', fixed = TRUE ) }) - -test_that('pev epi fails pre-emptively with unaligned booster parameters', { - parameters <- get_parameters() - expect_error( - set_pev_epi( - profile = rtss_profile, - coverages = c(0.1, 0.8), - timesteps = c(10, 100), - min_wait = 0, - age = 5 * 30, - booster_timestep = c(18, 36) * 30, - booster_coverage = .9, - booster_profile = list(rtss_booster_profile, rtss_booster_profile) - ) - ) -}) - test_that('pev epi targets correct age and respects min_wait', { timestep <- 5*365 parameters <- get_parameters(list(human_population = 5)) @@ -118,8 +80,8 @@ test_that('pev epi targets correct age and respects min_wait', { coverages = 0.8, min_wait = 2*365, age = 18 * 365, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(c(.9, .8), nrow=1, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ) events <- create_events(parameters) @@ -182,8 +144,8 @@ test_that('EPI ignores individuals scheduled for mass vaccination', { min_wait = 0, min_ages = c(1, 2, 3, 18) * 365, max_ages = (c(1, 2, 3, 18) + 1) * 365 - 1, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(c(.9, .8, .9, .8), nrow=2, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ) parameters <- set_pev_epi( @@ -193,8 +155,8 @@ test_that('EPI ignores individuals scheduled for mass vaccination', { coverages = 0.8, min_wait = 0, age = 18 * 365, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(c(.9, .8), nrow=1, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ) events <- create_events(parameters) @@ -251,8 +213,8 @@ test_that('pev EPI respects min_wait when scheduling seasonal boosters', { coverages = 0.8, min_wait = 6 * 30, age = 18 * 365, - booster_timestep = c(3, 12) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(3, 12) * 30, + booster_coverage = matrix(c(.9, .8), nrow=1, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile), seasonal_boosters = TRUE ) @@ -287,8 +249,8 @@ test_that('pev EPI schedules for the following year with seasonal boosters', { coverages = 0.8, min_wait = 6 * 30, age = 18 * 365, - booster_timestep = c(3, 12) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(3, 12) * 30, + booster_coverage = matrix(c(.9, .8), nrow=1, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile), seasonal_boosters = TRUE ) diff --git a/tests/testthat/test-pev.R b/tests/testthat/test-pev.R index 16f65849..11a9030b 100644 --- a/tests/testthat/test-pev.R +++ b/tests/testthat/test-pev.R @@ -8,8 +8,8 @@ test_that('Mass vaccination strategy parameterisation works', { min_wait = 0, min_ages = 5 * 30, max_ages = 17 * 30, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(c(.9, .8), nrow=1, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ) expect_equal(parameters$pev, TRUE) @@ -17,7 +17,7 @@ test_that('Mass vaccination strategy parameterisation works', { expect_equal(parameters$mass_pev_coverages, .8) expect_equal(parameters$mass_pev_min_ages, 5 * 30) expect_equal(parameters$mass_pev_max_ages, 17 * 30) - expect_equal(parameters$mass_pev_booster_timestep, c(18, 36) * 30) + expect_equal(parameters$mass_pev_booster_spacing, c(18, 36) * 30) expect_equal(parameters$pev_profiles, list(rtss_profile, rtss_booster_profile, rtss_booster_profile)) expect_equal(parameters$mass_pev_profile_indices, seq(3)) @@ -30,8 +30,8 @@ test_that('Mass vaccination strategy parameterisation works', { min_wait = 0, min_ages = 5 * 30, max_ages = 17 * 30, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(c(.9, .8), nrow=1, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ), "all(coverages >= 0) && all(coverages <= 1) is not TRUE", fixed = TRUE @@ -46,57 +46,34 @@ test_that('Mass vaccination strategy parameterisation works', { min_wait = 0, min_ages = 5 * 30, max_ages = 17 * 30, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(c(.9, .8), nrow=1, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ), "all(coverages >= 0) && all(coverages <= 1) is not TRUE", fixed = TRUE ) }) -test_that('I can add time varying booster coverage to the mass pev strategy', { +test_that('set_mass_pev checks booster coverage matrix shape', { parameters <- get_parameters() - parameters <- set_mass_pev( - parameters, - profile = rtss_profile, - timesteps = 10, - coverages = 0.8, - min_wait = 0, - min_ages = 5 * 30, - max_ages = 17 * 30, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), - booster_timed_coverage = c(.5, .7), - booster_timed_coverage_timestep = c(365, 2*365), - booster_profile = list(rtss_booster_profile, rtss_booster_profile) - ) - - expect_equal(parameters$mass_pev_booster_timestep, c(18, 36) * 30) - expect_equal(parameters$mass_pev_booster_timed_coverage, c(.5, .7)) - expect_equal(parameters$mass_pev_booster_timed_coverage_timestep, c(365, 2*365)) - expect_equal(parameters$pev_profiles, list(rtss_profile, rtss_booster_profile, rtss_booster_profile)) - expect_error( parameters <- set_mass_pev( parameters, profile = rtss_profile, - timesteps = 10, - coverages = 0.8, + coverages = c(0.1), + timesteps = c(10), min_wait = 0, min_ages = 5 * 30, max_ages = 17 * 30, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), - booster_timed_coverage = c(.5, .7), - booster_timed_coverage_timestep = 365, + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(c(.9, .8), nrow=2, ncol=1), booster_profile = list(rtss_booster_profile, rtss_booster_profile) - ), - "booster_coverage_timestep must be the same length as booster_coverage", - fixed = TRUE - ) + ), + 'booster_spacing, booster_coverage and booster_profile do not align', + fixed = TRUE + ) }) - test_that('Mass vaccination fails pre-emptively for unaligned booster parameters', { parameters <- get_parameters() expect_error( @@ -108,8 +85,8 @@ test_that('Mass vaccination fails pre-emptively for unaligned booster parameters min_wait = 0, min_ages = 5 * 30, max_ages = 17 * 30, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9), + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(.9, nrow=1, ncol=1), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ) ) @@ -126,8 +103,8 @@ test_that('Infection considers pev efficacy', { min_wait = 0, min_ages = 5 * 30, max_ages = 17 * 30, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(c(.9, .8), nrow=1, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ) events <- create_events(parameters) @@ -193,8 +170,8 @@ test_that('Mass vaccinations update vaccination time', { min_wait = 0, min_ages = c(1, 2, 3, 18) * 365, max_ages = (c(1, 2, 3, 18) + 1) * 365 - 1, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(c(.9, .8, .9, .8), nrow=2, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ) events <- create_events(parameters) @@ -263,8 +240,8 @@ test_that('Mass vaccinations ignore EPI individuals', { min_wait = 0, min_ages = c(1, 2, 3, 18) * 365, max_ages = (c(1, 2, 3, 18) + 1) * 365 - 1, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(c(.9, .8, .9, .8), nrow=2, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ) parameters <- set_pev_epi( @@ -274,8 +251,8 @@ test_that('Mass vaccinations ignore EPI individuals', { coverages = 0.8, min_wait = 2*365, age = 18 * 365, - booster_timestep = c(18, 36) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(18, 36) * 30, + booster_coverage = matrix(c(.9, .8), nrow=1, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ) events <- create_events(parameters) @@ -330,8 +307,8 @@ test_that('Mass boosters update profile params and reschedule correctly', { min_wait = 0, min_ages = c(1, 2, 3, 18) * 365, max_ages = (c(1, 2, 3, 18) + 1) * 365 - 1, - booster_timestep = c(1, 6) * 30, - booster_coverage = c(1, 1), + booster_spacing = c(1, 6) * 30, + booster_coverage = matrix(1, nrow=2, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ) events <- create_events(parameters) @@ -355,7 +332,8 @@ test_that('Mass boosters update profile params and reschedule correctly', { listener <- create_pev_booster_listener( variables = variables, - coverage = 1, + coverage = parameters$mass_pev_booster_coverage, + parameters$mass_pev_timesteps, booster_number = 1, pev_profile_index = 2, next_booster_event = events$mass_pev_boosters[[2]], @@ -406,8 +384,8 @@ test_that('Mass booster coverages sample subpopulations correctly', { min_ages = c(1, 2, 3, 18) * 365, max_ages = (c(1, 2, 3, 18) + 1) * 365 - 1, min_wait = 0, - booster_timestep = c(1, 6) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(1, 6) * 30, + booster_coverage = matrix(c(.9, .8), nrow=1, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ) @@ -432,7 +410,8 @@ test_that('Mass booster coverages sample subpopulations correctly', { listener <- create_pev_booster_listener( variables = variables, - coverage = .9, + coverage = parameters$mass_pev_booster_coverage, + pev_distribution_timesteps = parameters$mass_pev_timesteps, booster_number = 1, pev_profile_index = 2, next_booster_event = events$mass_pev_boosters[[2]], @@ -485,8 +464,8 @@ test_that('mass pev targets correct age and respects min_wait', { min_ages = 0, max_ages = 19 * 365, min_wait = 2*365, - booster_timestep = c(1, 6) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(1, 6) * 30, + booster_coverage = matrix(c(.9, .8, .9, .8), nrow=2, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ) events <- create_events(parameters) @@ -547,8 +526,8 @@ test_that('Mass efficacy listener works correctly', { min_ages = c(1, 2, 3, 18) * 365, max_ages = (c(1, 2, 3, 18) + 1) * 365 - 1, min_wait = 0, - booster_timestep = c(1, 6) * 30, - booster_coverage = c(.9, .8), + booster_spacing = c(1, 6) * 30, + booster_coverage = matrix(c(.9, .8), nrow=1, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile) ) @@ -585,8 +564,8 @@ test_that('Mass dose events are not ruined by lazy evaluation', { min_ages = c(1, 2, 3, 18) * 365, max_ages = (c(1, 2, 3, 18) + 1) * 365 - 1, min_wait = 0, - booster_timestep = c(1, 6, 12) * 30, - booster_coverage = c(.9, .8, .7), + booster_spacing = c(1, 6, 12) * 30, + booster_coverage = matrix(c(.9, .8, .7), nrow=1, ncol=3), booster_profile = list(rtss_booster_profile, rtss_booster_profile, rtss_booster_profile) ) @@ -596,12 +575,11 @@ test_that('Mass dose events are not ruined by lazy evaluation', { attach_pev_dose_listeners( variables = variables, parameters = parameters, + pev_distribution_timesteps = parameters$mass_pev_timesteps, dose_events = events$mass_pev_doses, booster_events = events$mass_pev_boosters, - booster_delays = parameters$mass_pev_booster_timestep, + booster_delays = parameters$mass_pev_booster_spacing, booster_coverages = parameters$mass_pev_booster_coverage, - booster_timed_coverage = NULL, - booster_timed_coverage_timestep = NULL, pev_profile_indices = parameters$mass_pev_profile_indices, strategy = 'mass', renderer = mock_render(1) @@ -622,8 +600,8 @@ test_that('Mass dose events are not ruined by lazy evaluation', { expect_equal( as.list(environment( events$mass_pev_boosters[[1]]$.listeners[[1]] - ))$coverage, - .9 + ))$booster_number, + 1 ) }) @@ -657,7 +635,7 @@ test_that('Efficacies are calculated correctly', { ) }) -test_that('pev timed booster coverage works with NULL', { +test_that('pev timed booster coverage can select the first coverage for the first booster', { timestep <- 5 * 365 parameters <- get_parameters(list(human_population = 5)) parameters <- set_pev_epi( @@ -667,10 +645,8 @@ test_that('pev timed booster coverage works with NULL', { coverages = 0.8, min_wait = 6 * 30, age = 18 * 365, - booster_timestep = c(3, 12) * 30, - booster_coverage = c(.9, .8), - booster_timed_coverage = c(.5, .7), - booster_timed_coverage_timestep = c(timestep, timestep + 365), + booster_spacing = c(3, 12) * 30, + booster_coverage = matrix(c(.9, .8), nrow=1, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile), ) events <- create_events(parameters) @@ -679,9 +655,8 @@ test_that('pev timed booster coverage works with NULL', { listener <- create_pev_booster_listener( variables = create_variables(parameters), - coverage = .9, - timed_coverage = NULL, - timed_coverage_timestep = NULL, + coverage = parameters$pev_epi_booster_coverage, + pev_distribution_timesteps = parameters$pev_epi_timesteps, booster_number = 1, pev_profile_index = 2, next_booster_event = booster_event, @@ -710,20 +685,18 @@ test_that('pev timed booster coverage works with NULL', { }) -test_that('pev boosters take into account the timed coverage', { +test_that('pev boosters can select the second coverage for the first booster', { timestep <- 5 * 365 parameters <- get_parameters(list(human_population = 5)) parameters <- set_pev_epi( parameters, profile = rtss_profile, - timesteps = 10, - coverages = 0.8, + timesteps = c(10, 30), + coverages = c(0.8, 0.4), min_wait = 6 * 30, age = 18 * 365, - booster_timestep = c(3, 12) * 30, - booster_coverage = c(.9, .8), - booster_timed_coverage = c(.5, .7), - booster_timed_coverage_timestep = c(timestep, timestep + 365), + booster_spacing = c(3, 12) * 30, + booster_coverage = matrix(c(.9, .45, .8, .8), nrow=2, ncol=2), booster_profile = list(rtss_booster_profile, rtss_booster_profile), ) events <- create_events(parameters) @@ -732,9 +705,8 @@ test_that('pev boosters take into account the timed coverage', { listener <- create_pev_booster_listener( variables = create_variables(parameters), - coverage = .9, - timed_coverage = c(.5, .7), - timed_coverage_timestep = c(timestep, timestep + 365), + coverage = parameters$pev_epi_booster_coverage, + pev_distribution_timesteps = parameters$pev_epi_timesteps, booster_number = 1, pev_profile_index = 2, next_booster_event = booster_event, diff --git a/vignettes/Vaccines.Rmd b/vignettes/Vaccines.Rmd index 51bffd0e..02eb9358 100644 --- a/vignettes/Vaccines.Rmd +++ b/vignettes/Vaccines.Rmd @@ -158,8 +158,8 @@ rtssmassparams <- set_mass_pev( min_wait = 0, # The minimum acceptable time since the last vaccination is 0 because in our case we are only implementing one round of vaccination. min_ages = 5 * month, # The minimum age for the target population to be vaccinated. max_ages = 50 * year, # The maximum age for the target population to be vaccinated. - booster_timestep = 12 * month, # The booster is given at 12 months after the primary series. - booster_coverage = 0.95, # Coverage of the booster dose is 95%. + booster_spacing = 12 * month, # The booster is given at 12 months after the primary series. + booster_coverage = matrix(0.95), # Coverage of the booster dose is 95%. booster_profile = list(rtss_booster_profile) # We will model implementation of the RTSS booster. ) @@ -228,8 +228,8 @@ seasmass_simparams <- set_mass_pev( min_ages = 5 * month, # The minimum age for the target population to be vaccinated. max_ages = 50 * year, # The maximum age for the target population to be vaccinated. min_wait = 0, # There is no minimum wait between the last vaccination. - booster_timestep = round(c(12 * month + 2 * month)), # The booster is given 14 months after the first dose. - booster_coverage = 1, # 100% of the vaccinated population is boosted. + booster_spacing = round(c(12 * month + 2 * month)), # The booster is given 14 months after the first dose. + booster_coverage = matrix(1), # 100% of the vaccinated population is boosted. booster_profile = list(rtss_booster_profile) # We will model implementation of the RTSS booster. ) @@ -269,8 +269,8 @@ rtssepiparams <- set_pev_epi( coverages = 1, # Vaccine coverage is 100%. min_wait = 0, # There is no minimum wait since the last vaccination. age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. - booster_timestep = 12 * month, # The booster is administered 12 months following the third dose. - booster_coverage = 0.95, # 95% of those vaccinated with the primary series will be boosted. + booster_spacing = 12 * month, # The booster is administered 12 months following the third dose. + booster_coverage = matrix(0.95), # 95% of those vaccinated with the primary series will be boosted. booster_profile = list(rtss_booster_profile) # We will model implementation of the RTSS booster. ) @@ -322,8 +322,8 @@ rtssepiseasonalparams <- set_pev_epi( coverages = 1, # Vaccine coverage is 100%. min_wait = 6 * month, # When seasonal_boosters = TRUE, this is the minimum time between an individual receiving the final dose and the first booster. age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. - booster_timestep = peak - month * 3.5 , # Because seasonal_boosters = TRUE, the timestep here is relative to the start of the year. Here, we will give a booster at 3.5 months prior to peak transmission. - booster_coverage = 0.95, # 95% of the vaccinated population is boosted. + booster_spacing = peak - month * 3.5 , # Because seasonal_boosters = TRUE, the timestep here is relative to the start of the year. Here, we will give a booster at 3.5 months prior to peak transmission. + booster_coverage = matrix(0.95), # 95% of the vaccinated population is boosted. seasonal_boosters = TRUE, # Boosters will be given based on a seasonal schedule, so the timing in the boosters= argument above will be relative to the start of the year instead of relative to the 3rd dose. booster_profile = list(rtss_booster_profile) # We will model implementation of the RTSS booster. ) @@ -362,8 +362,8 @@ rtssepiparams2 <- set_pev_epi( coverages = 1, # Vaccine coverage is 100%. age = 5 * month, # Individuals will be vaccinated once they reach 5 months of age. min_wait = 0, # When seasonal_boosters = FALSE, this is the minimum time between doses. - booster_timestep = c(12 * month, 24 * month), # Here, we are testing a strategy with 2 boosters, one at 1 year after the 3rd dose and the second 2 years after the 3rd dose. - booster_coverage = c(1, 1), # For each of the two boosters, coverage is 100%. + booster_spacing = c(12 * month, 24 * month), # Here, we are testing a strategy with 2 boosters, one at 1 year after the 3rd dose and the second 2 years after the 3rd dose. + booster_coverage = matrix(c(1, 1), nrow=1, ncol=2), # For each of the two boosters, coverage is 100%. booster_profile = list(rtss_booster_profile, rtss_booster_profile) # We will model implementation of the RTSS booster. ) From 45486addda5a53ef5f5756e84d173ac5e4185c79 Mon Sep 17 00:00:00 2001 From: Giovanni Charles Date: Tue, 9 Jan 2024 10:10:45 +0000 Subject: [PATCH 128/164] Check that booster_spacing is monotonically increasing --- R/pev_parameters.R | 15 +++++++++++++++ tests/testthat/test-pev-epi.R | 20 ++++++++++++++++++++ tests/testthat/test-pev.R | 20 ++++++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/R/pev_parameters.R b/R/pev_parameters.R index 73947b29..7edcb39c 100644 --- a/R/pev_parameters.R +++ b/R/pev_parameters.R @@ -98,6 +98,13 @@ set_pev_epi <- function( stop("coverages and timesteps must align") } + # Check that booster_spacing are monotonically increasing + if (length(booster_spacing) > 1) { + if (!all(diff(booster_spacing) > 0)) { + stop('booster_spacing must be monotonically increasing') + } + } + # Check that seasonal booster parameters make sense stopifnot(min_wait >= 0) stopifnot(age >= 0) @@ -178,6 +185,14 @@ set_mass_pev <- function( if (length(min_ages) != length(max_ages)) { stop('min and max ages do not align') } + + # Check that booster_spacing are monotonically increasing + if (length(booster_spacing) > 1) { + if (!all(diff(booster_spacing) > 0)) { + stop('booster_spacing must be monotonically increasing') + } + } + stopifnot((length(booster_coverage)) == 0 || all(booster_coverage >= 0 & booster_coverage <= 1)) if (!all(c(ncol(booster_coverage), length(booster_profile)) == length(booster_spacing))) { stop('booster_spacing, booster_coverage and booster_profile do not align') diff --git a/tests/testthat/test-pev-epi.R b/tests/testthat/test-pev-epi.R index 56db32e7..6555700c 100644 --- a/tests/testthat/test-pev-epi.R +++ b/tests/testthat/test-pev-epi.R @@ -70,6 +70,26 @@ test_that('set_pev_epi checks booster coverage matrix shape', { ) }) +test_that('set_pev_epi checks that booster_spacing are increasing', { + parameters <- get_parameters() + expect_error( + parameters <- set_pev_epi( + parameters, + profile = rtss_profile, + coverages = c(0.1, 0.8), + timesteps = c(10, 100), + min_wait = 0, + age = 5 * 30, + booster_spacing = c(5, 5) * 30, + booster_coverage = matrix(c(.9, .8), nrow=2, ncol=1), + booster_profile = list(rtss_booster_profile, rtss_booster_profile) + ), + 'booster_spacing must be monotonically increasing', + fixed = TRUE + ) +}) + + test_that('pev epi targets correct age and respects min_wait', { timestep <- 5*365 parameters <- get_parameters(list(human_population = 5)) diff --git a/tests/testthat/test-pev.R b/tests/testthat/test-pev.R index 11a9030b..88b95b35 100644 --- a/tests/testthat/test-pev.R +++ b/tests/testthat/test-pev.R @@ -74,6 +74,26 @@ test_that('set_mass_pev checks booster coverage matrix shape', { ) }) +test_that('set_mass_pev checks booster_spacing is increasing', { + parameters <- get_parameters() + expect_error( + parameters <- set_mass_pev( + parameters, + profile = rtss_profile, + coverages = c(0.1), + timesteps = c(10), + min_wait = 0, + min_ages = 5 * 30, + max_ages = 17 * 30, + booster_spacing = c(5, 5) * 30, + booster_coverage = matrix(c(.9, .8), nrow=2, ncol=1), + booster_profile = list(rtss_booster_profile, rtss_booster_profile) + ), + 'booster_spacing must be monotonically increasing', + fixed = TRUE + ) +}) + test_that('Mass vaccination fails pre-emptively for unaligned booster parameters', { parameters <- get_parameters() expect_error( From f1039ea8adbf0901ed265b74abd042f14a0c6ccc Mon Sep 17 00:00:00 2001 From: tbreweric Date: Mon, 15 Jan 2024 15:10:14 +0000 Subject: [PATCH 129/164] Changed the calculation of birth_ivm in sample_maternal_immunity(). The function now calculates the maternally-acquired immunity to severe disease (birth_ivm) using the acquired immunity to severe disease (iva) rather than the acquired immunity to clinical disease (ica) --- R/mortality_processes.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/mortality_processes.R b/R/mortality_processes.R index 9d95a707..f0f1b1f9 100644 --- a/R/mortality_processes.R +++ b/R/mortality_processes.R @@ -66,7 +66,7 @@ sample_maternal_immunity <- function(variables, target, timestep, parameters) { # set their maternal immunities birth_icm <- variables$ica$get_values(mothers) * parameters$pcm - birth_ivm <- variables$ica$get_values(mothers) * parameters$pvm + birth_ivm <- variables$iva$get_values(mothers) * parameters$pvm variables$icm$queue_update(birth_icm, target_group) variables$ivm$queue_update(birth_ivm, target_group) } From d8930d8edcf56c3047944554a862c501c0451159 Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Tue, 6 Jun 2023 15:49:43 +0100 Subject: [PATCH 130/164] Opened sub-branch of feat/antimalarial_resistance for developing the early treatment failure (ETF) component of the model. Also created a draft vignette for Antimalarial_Resistance on the feat/antimalarial_resistance branch --- vignettes/Antimalarial_Resistance.Rmd | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 vignettes/Antimalarial_Resistance.Rmd diff --git a/vignettes/Antimalarial_Resistance.Rmd b/vignettes/Antimalarial_Resistance.Rmd new file mode 100644 index 00000000..94c90fc5 --- /dev/null +++ b/vignettes/Antimalarial_Resistance.Rmd @@ -0,0 +1,21 @@ +--- +title: "Antimalarial Resistance" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Antimalarial Resistance} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +``` + +```{r setup} + +# Load the requisite packages +library(malariasimulation) +``` From 8efb863b6fe2f1ea2e9b41fd4a024dfc5e56425d Mon Sep 17 00:00:00 2001 From: tbreweric Date: Thu, 6 Jul 2023 11:57:16 +0100 Subject: [PATCH 131/164] Added first iteration of the set_antimalarial_resistance() function designed to parameterise antimalarial resistance for malariasimulation runs --- NAMESPACE | 1 + R/antimalarial_resistance.R | 87 ++++++++++++++++++++++++++++++ man/set_antimalarial_resistance.Rd | 43 +++++++++++++++ src/RcppExports.cpp | 2 +- 4 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 R/antimalarial_resistance.R create mode 100644 man/set_antimalarial_resistance.Rd diff --git a/NAMESPACE b/NAMESPACE index 4fd1b1da..4ba1e15d 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -18,6 +18,7 @@ export(rtss_profile) export(run_metapop_simulation) export(run_simulation) export(run_simulation_with_repetitions) +export(set_antimalarial_resistance) export(set_bednets) export(set_carrying_capacity) export(set_clinical_treatment) diff --git a/R/antimalarial_resistance.R b/R/antimalarial_resistance.R new file mode 100644 index 00000000..0d6bcd49 --- /dev/null +++ b/R/antimalarial_resistance.R @@ -0,0 +1,87 @@ +#' @title Parameterise antimalarial resistance +#' +#' @param parameters the model parameters +#' @param drug the index of the drug which resistance is being set for in the parameter list +#' @param timesteps vector of timesteps for each update to resistance proportion and/or phenotype probability +#' @param artemisinin_resistance vector of updates to the proportions of infections that are artemisinin resistant at time t +#' @param partner_drug_resistance vector of updates to the proportions of infections that are partner-drug resistant at time t +#' @param slow_parasite_clearance_prob vector of updates to the proportion of artemisinin-resistant infections that result in early treatment failure +#' @param early_treatment_failure_prob vector of updates to the proportion of artemisinin-resistant infections that result in slow parasite clearance +#' @param late_clinical_failure_prob vector of updates to the proportion of partner-drug-resistant infections that result in late clinical failure +#' @param late_parasitological_prob vector of updates to the proportion of partner-drug-resistant infections that result in late parasitologica; failure +#' @param reinfection_prob vector of updates to the proportion of partner-drug-resistant infections that result in reinfection during prophylaxis +#' @export +set_antimalarial_resistance <- function(parameters, + drug, + timesteps, + artemisinin_resistance, + partner_drug_resistance, + slow_parasite_clearance_prob, + early_treatment_failure_prob, + late_clinical_failure_prob, + late_parasitological_prob, + reinfection_prob) { + + # Check that the proportion of people with artemisinin and partner-drug resistance + # are bounded between 0 and 1: + if(artemisinin_resistance < 0 | artemisinin_resistance > 1 | + partner_drug_resistance < 0 | partner_drug_resistance > 1) { + stop("Artemisinin and partner-drug resistance proportions must fall between 0 and 1") + } else { + print("OK") + } + + # Ensure resistance phenotype probabilities bounded between 0 and 1: + if(slow_parasite_clearance_prob < 0 | slow_parasite_clearance_prob > 1 | + early_treatment_failure_prob < 0 | early_treatment_failure_prob > 1 | + late_clinical_failure_prob < 0 | late_clinical_failure_prob > 1 | + late_parasitological_prob < 0 | late_parasitological_prob > 1 | + reinfection_prob < 0 | reinfection_prob > 1) { + stop("Resistance phenotype probabilities must fall between 0 and 1") + } else { + print("OK") + } + + # Set antimalarial_resistance to TRUE + parameters$antimalarial_resistance <- TRUE + + # Store the number of drugs for which parameters are available in the parameter list: + n_drugs <- length(parameters$drug_efficacy) + + # If the drug index falls outside range 1:n_drugs, terminate the operation: + if (drug < 1 | drug > n_drugs) { + stop('Drug index is invalid, please set drugs using set_drugs') + } else { + print("OK") + } + + # Check the drug_index for the drug setting parameters for + drug_index <- which(parameters$antimalarial_resistance_drug == drug) + + # If drug_index is currently unpopulated + if (length(drug_index) == 0) { + drug_index <- length(parameters$antimalarial_resistance_drug) + 1 + } + + # Append the drug for which resistance is being assigned + parameters$antimalarial_resistance_drug[[drug_index]] <- drug + + # Append the timesteps on which the resistance proportions are to be updated + parameters$antimalarial_resistance_timesteps[[drug_index]] <- timesteps + + # Append the proportions of all malarial infections that are artemisinin or partner-drug + # resistant + parameters$prop_artemisinin_resistant[[drug_index]] <- artemisinin_resistance + parameters$prop_partner_drug_resistant[[drug_index]] <- partner_drug_resistance + + # Append the probabilities that + parameters$slow_parasite_clearance_prob[[drug_index]] <- slow_parasite_clearance_prob + parameters$early_treatment_failure_prob[[drug_index]] <- early_treatment_failure_prob + parameters$late_clinical_failure_prob[[drug_index]] <- late_clinical_failure_prob + parameters$late_parasitological_failure_prob[[drug_index]] <- late_parasitological_prob + parameters$reinfection_during_prophylaxis[[drug_index]] <- reinfection_prob + + # Return the parameter list: + parameters + +} \ No newline at end of file diff --git a/man/set_antimalarial_resistance.Rd b/man/set_antimalarial_resistance.Rd new file mode 100644 index 00000000..ac80d772 --- /dev/null +++ b/man/set_antimalarial_resistance.Rd @@ -0,0 +1,43 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/antimalarial_resistance.R +\name{set_antimalarial_resistance} +\alias{set_antimalarial_resistance} +\title{Parameterise antimalarial resistance} +\usage{ +set_antimalarial_resistance( + parameters, + drug, + timesteps, + artemisinin_resistance, + partner_drug_resistance, + slow_parasite_clearance_prob, + early_treatment_failure_prob, + late_clinical_failure_prob, + late_parasitological_prob, + reinfection_prob +) +} +\arguments{ +\item{parameters}{the model parameters} + +\item{drug}{the index of the drug which resistance is being set for in the parameter list} + +\item{timesteps}{vector of timesteps for each update to resistance proportion and/or phenotype probability} + +\item{artemisinin_resistance}{vector of updates to the proportions of infections that are artemisinin resistant at time t} + +\item{partner_drug_resistance}{vector of updates to the proportions of infections that are partner-drug resistant at time t} + +\item{slow_parasite_clearance_prob}{vector of updates to the proportion of artemisinin-resistant infections that result in early treatment failure} + +\item{early_treatment_failure_prob}{vector of updates to the proportion of artemisinin-resistant infections that result in slow parasite clearance} + +\item{late_clinical_failure_prob}{vector of updates to the proportion of partner-drug-resistant infections that result in late clinical failure} + +\item{late_parasitological_prob}{vector of updates to the proportion of partner-drug-resistant infections that result in late parasitologica; failure} + +\item{reinfection_prob}{vector of updates to the proportion of partner-drug-resistant infections that result in reinfection during prophylaxis} +} +\description{ +Parameterise antimalarial resistance +} diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index affb233d..f5c226fd 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -260,7 +260,7 @@ BEGIN_RCPP END_RCPP } -RcppExport SEXP run_testthat_tests(void); +RcppExport SEXP run_testthat_tests(); static const R_CallMethodDef CallEntries[] = { {"_malariasimulation_create_adult_mosquito_model", (DL_FUNC) &_malariasimulation_create_adult_mosquito_model, 5}, From 74a2a3be9750548ec9a75d90b0285cd6d1a662f4 Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Tue, 11 Jul 2023 12:41:21 +0100 Subject: [PATCH 132/164] Updated the set_antimalarial_resistance() function to allow for multiple-value entries for each parameter (e.g. updates to resistance proportions through time) and included an additional check to make sure the vectors for each input parameter are of equal length. I have also added antimalarial-resistance_development.R which is the script I've been using to amend/test functions and in the current commit includes an updated version of calculate_treated() function that simulates the effect of early treatment failure (artemisinin resistance outcome) --- R/antimalarial_resistance.R | 43 +- R/antimalarial_resistance_development.R | 553 ++++++++++++++++++++++++ 2 files changed, 583 insertions(+), 13 deletions(-) create mode 100644 R/antimalarial_resistance_development.R diff --git a/R/antimalarial_resistance.R b/R/antimalarial_resistance.R index 0d6bcd49..add8a2f3 100644 --- a/R/antimalarial_resistance.R +++ b/R/antimalarial_resistance.R @@ -22,24 +22,41 @@ set_antimalarial_resistance <- function(parameters, late_parasitological_prob, reinfection_prob) { - # Check that the proportion of people with artemisinin and partner-drug resistance - # are bounded between 0 and 1: - if(artemisinin_resistance < 0 | artemisinin_resistance > 1 | - partner_drug_resistance < 0 | partner_drug_resistance > 1) { - stop("Artemisinin and partner-drug resistance proportions must fall between 0 and 1") + # Check that the number of values input is equal for each resistance parameter + if(length(artemisinin_resistance) != length(timesteps) | + length(partner_drug_resistance) != length(timesteps) | + length(slow_parasite_clearance_prob) != length(timesteps) | + length(early_treatment_failure_prob) != length(timesteps) | + length(late_clinical_failure_prob) != length(timesteps) | + length(late_parasitological_prob) != length(timesteps) | + length(reinfection_prob) != length(timesteps)) { + stop("Number of resistance parameter vectors do not match time steps specified for update") } else { print("OK") } + # Check that the proportion of people with artemisinin and partner-drug resistance + # are bounded between 0 and 1: + for(i in length(artemisinin_resistance)) { + if(artemisinin_resistance[i] < 0 | artemisinin_resistance[i] > 1 | + partner_drug_resistance[i] < 0 | partner_drug_resistance[i] > 1) { + stop("Artemisinin and partner-drug resistance proportions must fall between 0 and 1") + } else { + print("OK") + } + } + # Ensure resistance phenotype probabilities bounded between 0 and 1: - if(slow_parasite_clearance_prob < 0 | slow_parasite_clearance_prob > 1 | - early_treatment_failure_prob < 0 | early_treatment_failure_prob > 1 | - late_clinical_failure_prob < 0 | late_clinical_failure_prob > 1 | - late_parasitological_prob < 0 | late_parasitological_prob > 1 | - reinfection_prob < 0 | reinfection_prob > 1) { - stop("Resistance phenotype probabilities must fall between 0 and 1") - } else { - print("OK") + for(i in 1:length(slow_parasite_clearance_prob)) { + if(slow_parasite_clearance_prob[i] < 0 | slow_parasite_clearance_prob[i] > 1 | + early_treatment_failure_prob[i] < 0 | early_treatment_failure_prob[i] > 1 | + late_clinical_failure_prob[i] < 0 | late_clinical_failure_prob[i] > 1 | + late_parasitological_prob[i] < 0 | late_parasitological_prob[i] > 1 | + reinfection_prob[i] < 0 | reinfection_prob[i] > 1) { + stop("Resistance phenotype probabilities must fall between 0 and 1") + } else { + print("OK") + } } # Set antimalarial_resistance to TRUE diff --git a/R/antimalarial_resistance_development.R b/R/antimalarial_resistance_development.R new file mode 100644 index 00000000..5122f77a --- /dev/null +++ b/R/antimalarial_resistance_development.R @@ -0,0 +1,553 @@ +# #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# +# #+++++ antimalarial_resistance/etf development script +++++# +# #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# +# +# ##' README: +# ##' THis script is designed as a place to develop and store the changes being implemented into the +# ##' malariasimulation package in support of integrating antimalarial resistance. This file is +# ##' designed to be deleted prior to any merge and is purely for development purposes. +# +# ##' CURENTLY WORKING ON: amending the calculate_treated() function to update +# ##' +# ##' +# ##' Use Ctrl + Shft + C to comment everything in/out for load_all() to work +# +# #----- 1) Preamble --------------------------------------------------------------------------------- +# +# # Load in the individual package: +# library(individual) +# library(devtools) +# +# # Load the malariasimualtion functions (make sure this script is commented out when you run this) +# devtools::load_all(".") +# +# #----- 2) Original calculate_treated() function ---------------------------------------------------- +# +# ##' This is the original calculate_treated() function, renamed to avoid any conflicts. +# calculate_treated <- function( +# variables, +# clinical_infections, +# parameters, +# timestep, +# renderer +# ) { +# +# # Gather the treatment coverage(s) in the current timestep: +# treatment_coverages <- get_treatment_coverages(parameters, timestep) +# +# # Sum to get the total treatment coverage in the current time step: +# ft <- sum(treatment_coverages) +# +# # If treatment = 0, return an empty Bitset for the treated individuals: +# if (ft == 0) { +# return(individual::Bitset$new(parameters$human_population)) +# } +# +# # Add the total treatment coverage to the renderer: +# renderer$render('ft', ft, timestep) +# +# # Sample individuals from clinically infected to seek treatment using treatment coverage: +# seek_treatment <- sample_bitset(clinical_infections, ft) +# +# # Store the number of people that seek treatment this time step: +# n_treat <- seek_treatment$size() +# +# # Add the number of people seeking treatment in the current time step to the renderer: +# renderer$render('n_treated', n_treat, timestep) +# +# # Assign each individual seeking treatment a drug based on their coverage(s): +# drugs <- as.numeric(parameters$clinical_treatment_drugs[ +# sample.int( +# length(parameters$clinical_treatment_drugs), +# n_treat, +# prob = treatment_coverages, +# replace = TRUE +# ) +# ]) +# +# # Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: +# successful <- bernoulli_multi_p(parameters$drug_efficacy[drugs]) +# +# # Subset the successfully treated people: +# treated_index <- bitset_at(seek_treatment, successful) +# +# # For those people who have been successfully treated: +# if (treated_index$size() > 0) { +# +# # Queue update to the infectious state to Tr: +# variables$state$queue_update('Tr', treated_index) +# +# # Queue update to the infectivity to reflect their new state (Tr): +# variables$infectivity$queue_update( +# parameters$cd * parameters$drug_rel_c[drugs[successful]], +# treated_index +# ) +# # Queue update to the last drug each successfully treated person received: +# variables$drug$queue_update( +# drugs[successful], +# treated_index +# ) +# # Queue update to the time step on which each successfully treated person last +# # received a drug: +# variables$drug_time$queue_update( +# timestep, +# treated_index +# ) +# } +# +# # Return the Bitset of treated individuals: +# treated_index +# } +# +# #----- 3) Function Development Set-up -------------------------------------------------------------- +# +# # Set an base parameter list +# simparams <- get_parameters() +# +# # Add AL and DHA_PQP drug parameters to parameter list +# simparams <- set_drugs(simparams, list(AL_params, DHA_PQP_params)) +# +# # Add clinical treatment events using set_clinical_treatment(): +# simparams <- set_clinical_treatment(parameters = simparams, drug = 2, +# timesteps = 25, coverages = 0.2) +# simparams <- set_clinical_treatment(parameters = simparams, drug = 1, +# timesteps = 50, coverages = 0.4) +# +# # Check the clinical treatment order and coverages: +# simparams$clinical_treatment_drugs +# simparams$clinical_treatment_coverages +# +# ##' AL is drug 1, used second clinically at a coverage of 0.4 +# ##' DHA-PQP is drug 2, used first clinically at a coverage of 0.2 +# +# # Add resistance using set_antimalarial_resistance() using same order as clinical treatment +# simparams <- set_antimalarial_resistance(parameters = simparams, +# drug = 2, +# timesteps = c(0, 25), +# artemisinin_resistance = c(0.3, 0.42), +# partner_drug_resistance = c(0, 0), +# slow_parasite_clearance_prob = rep(0.1, 2), +# early_treatment_failure_prob = rep(0.6, 2), +# late_clinical_failure_prob = rep(0.1, 2), +# late_parasitological_prob = rep(0.1, 2), +# reinfection_prob = rep(0.1, 2)) +# simparams <- set_antimalarial_resistance(parameters = simparams, +# drug = 1, +# timesteps = c(0, 50), +# artemisinin_resistance = c(0, 0), +# partner_drug_resistance = c(0, 0.5), +# slow_parasite_clearance_prob = rep(0.05, 2), +# early_treatment_failure_prob = rep(0.5, 2), +# late_clinical_failure_prob = rep(0.5, 2), +# late_parasitological_prob = rep(0.5, 2), +# reinfection_prob = rep(0.5, 2)) +# +# # Check the resistance parameters: +# simparams$antimalarial_resistance_drug +# simparams$antimalarial_resistance_timesteps +# simparams$prop_artemisinin_resistant; simparams$prop_partner_drug_resistant +# simparams$early_treatment_failure_prob; simparams$slow_parasite_clearance_prob +# simparams$late_clinical_failure_prob; simparams$late_parasitological_failure_prob; simparams$reinfection_during_prophylaxis +# +# # Set up the model variables: +# variables <- create_variables(parameters = simparams) +# +# # Establish Bitset of the human population +# current_pop <- Bitset$new(simparams$human_population, from = NULL) +# current_pop$insert(1:simparams$human_population); current_pop$to_vector() +# +# # Subset a group of clinically infected individuals from the population +# clinical_infections <- sample_bitset(b = current_pop, rate = 0.4) +# clinical_infections$to_vector(); clinical_infections$size() +# +# ##' TIMESTEP +# timesteps <- 100 +# current_timestep <- 50 +# +# ##' RENDERER +# renderer <- individual::Render$new(timesteps) +# renderer$to_dataframe() +# +# #----- 4) Individual Steps (Original) -------------------------------------------------------------- +# +# # Gather the treatment coverage(s) in the current timestep: +# treatment_coverages <- get_treatment_coverages(simparams, current_timestep) +# +# # Sum to get the total treatment coverage in the current time step: +# ft <- sum(treatment_coverages) +# +# # If treatment = 0, return an empty Bitset for the treated individuals: +# if (ft == 0) { +# return(individual::Bitset$new(simparams$human_population)) +# } else { +# print("OK") +# } +# +# # Add the total treatment coverage to the renderer: +# renderer$render('ft', ft, current_timestep) +# renderer$to_dataframe()[current_timestep,] +# +# # Sample individuals from clinically infected to seek treatment using treatment coverage: +# seek_treatment <- sample_bitset(clinical_infections, ft) +# seek_treatment$to_vector(); seek_treatment$size() +# +# # Store the number of people that seek treatment this time step: +# n_treat <- seek_treatment$size(); n_treat +# +# # Add the number of people seeking treatment in the current time step to the renderer: +# renderer$render('n_treated', n_treat, current_timestep) +# renderer$to_dataframe()[current_timestep,] +# +# # Assign each individual seeking treatment a drug based on their coverage(s): +# drugs <- as.numeric(simparams$clinical_treatment_drugs[ +# sample.int( +# length(simparams$clinical_treatment_drugs), +# n_treat, +# prob = treatment_coverages, +# replace = TRUE +# ) +# ]) +# drugs; length(drugs) == n_treat +# +# # Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: +# successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs]) +# successful; length(successful); (length(successful)/length(drugs))*100 +# +# # Subset the successfully treated people: +# treated_index <- bitset_at(seek_treatment, successful) +# treated_index$to_vector(); treated_index$size() +# +# +# # # For those people who have been successfully treated: +# # if (treated_index$size() > 0) { +# # +# # # Queue update to the infectious state to Tr: +# # variables$state$queue_update('Tr', treated_index) +# # +# # # Queue update to the infectivity to reflect their new state (Tr): +# # variables$infectivity$queue_update( +# # parameters$cd * parameters$drug_rel_c[drugs[successful]], +# # treated_index +# # ) +# # # Queue update to the last drug each successfully treated person received: +# # variables$drug$queue_update( +# # drugs[successful], +# # treated_index +# # ) +# # # Queue update to the time step on which each successfully treated person last +# # # received a drug: +# # variables$drug_time$queue_update( +# # timestep, +# # treated_index +# # ) +# # } +# +# # Return the Bitset of treated individuals: +# treated_index +# +# #----- 5) Individual Steps (Updated) --------------------------------------------------------------- +# +# # Gather the treatment coverage(s) in the current timestep: +# treatment_coverages <- get_treatment_coverages(simparams, current_timestep); treatment_coverages +# +# # Sum to get the total treatment coverage in the current time step: +# ft <- sum(treatment_coverages); ft +# +# # If treatment = 0, return an empty Bitset for the treated individuals: +# if (ft == 0) { +# return(individual::Bitset$new(simparams$human_population)) +# } else { +# print("OK") +# } +# +# # Add the total treatment coverage to the renderer: +# renderer$render('ft', ft, current_timestep) +# renderer$to_dataframe()[current_timestep,] +# +# # Sample individuals from clinically infected to seek treatment using treatment coverage: +# seek_treatment <- sample_bitset(clinical_infections, ft) +# seek_treatment$to_vector(); seek_treatment$size() +# paste0(((seek_treatment$size()/clinical_infections$size())*100), +# "% of clinically infected individuals sought treatment") +# +# # Store the number of people that seek treatment this time step: +# n_treat <- seek_treatment$size(); n_treat +# +# # Add the number of people seeking treatment in the current time step to the renderer: +# renderer$render('n_treated', n_treat, current_timestep) +# renderer$to_dataframe()[current_timestep,] +# +# # Assign each individual seeking treatment a drug based on their coverage(s): +# drugs <- as.numeric(simparams$clinical_treatment_drugs[ +# sample.int( +# length(simparams$clinical_treatment_drugs), +# n_treat, +# prob = treatment_coverages, +# replace = TRUE +# ) +# ]); drugs; length(drugs) == n_treat; table(drugs) +# +# #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# +# #+++++ RESISTANCE +# +# # Set the resistance drug index (each individuals drug): +# AM_drug_index <- as.numeric(simparams$antimalarial_resistance_drug[drugs]) +# drugs; AM_drug_index +# +# # Generate a vector containing the proportion of artemisinin resistance to the drug taken by each +# # individual and it's probability of manifesting as early treatment failure: +# art_resistance <- vector(); etf_prob <- vector() +# for(i in 1:n_treat) { +# +# # Identify the correct resistance index: +# last_resistance <- match_timestep(ts = simparams$antimalarial_resistance_timesteps[[AM_drug_index[i]]], +# t = current_timestep) +# +# # Retrieve the resistance value corresponding to the drug and time step: +# art_resistance[i] <- simparams$prop_artemisinin_resistant[[AM_drug_index[i]]][last_resistance] +# +# # Retrieve the ETF phenotype probability corresponding to the drug and time step: +# etf_prob[i] <- simparams$early_treatment_failure_prob[[AM_drug_index[i]]][last_resistance] +# +# } +# drugs; art_resistance; etf_prob +# +# # The probability that an individual fails is the product of the proportion of individuals with resistance +# # to the drug they've taken and the probability that early treatment failure manifests in cases of resistance +# # to that drug. The probability individuals are treated successfully is therefore 1 - this product. +# +# # Run bernoulli trials to determine which individuals fail treatment due to resistance to the drug +# # they have taken: +# susceptible <- bernoulli_multi_p(p = 1 - (art_resistance * etf_prob)) +# length(susceptible); (length(susceptible)/n_treat)*100 +# +# ##' Drug 1 is AL and Drug 2 is DHA-PQP. Drug 2 is set first in clinical treatment and resistance. +# ##' The proportion of individuals in the current timestep with artemisinin resistance to drug 1 is +# ##' 0, while the proportion of the population with artemisinin resistance to drug 2 is 0.42. The prob. +# ##' of early treatment failure for Drug 1 is 0.5, and is 0.6 for Drug 2. +# +# # Calculate the number of individuals who failed treatment due to early treatment failure: +# n_ETF <- n_treat - length(susceptible) +# +# # Add the number of Early Treatment Failures to the renderer: +# renderer$render('n_ETF', n_ETF, current_timestep) +# renderer$to_dataframe()[current_timestep,] +# +# # Remove the individuals who failed treatment due to resistance from the drugs vector: +# drugs[susceptible]; length(drugs[susceptible]); (length(drugs[susceptible])/n_treat)*100 +# drugs_2 <- drugs[susceptible] +# +# # Check which individuals failed and which drug they took (only modelled resistance to drug 2) +# res_fail_individuals <- which(!((1:n_treat) %in% susceptible)) +# drugs[res_fail_individuals]; table(drugs); table(drugs_2) +# drugs; drugs_2 +# +# # Subset the people who remained susceptible +# seek_treatment$to_vector(); seek_treatment$size() +# susceptible_index <- bitset_at(seek_treatment, susceptible) +# susceptible_index$to_vector(); susceptible_index$size() +# +# # So, we should now have a slightly shorter vector of drugs taken by each individual to account for +# # the individuals who gave failed treatment due to resistance. We can then use this to work out who +# # is successfully treated given the drug efficacy. +# +# #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# +# #+++++ DRUG EFFICACY +# # Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: +# successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs_2]) +# successful; length(successful); (length(successful)/length(drugs_2))*100 +# +# # Calculate the number of people who failed treatment due to efficacy: +# n_treat_eff_fail <- length(susceptible) - length(successful) +# +# # Add the number of treatment efficacy failures to the renderer: +# renderer$render('n_treat_eff_fail', n_treat_eff_fail, current_timestep) +# renderer$to_dataframe()[current_timestep,] +# +# # Subset the successfully treated people: +# treated_index <- bitset_at(susceptible_index, successful) +# treated_index$to_vector(); treated_index$size() +# +# # Compare the three bitsets: +# seek_treatment$to_vector(); seek_treatment$size() +# susceptible_index$to_vector(); susceptible_index$size() +# treated_index$to_vector(); treated_index$size() +# +# #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# +# +# # # For those people who have been successfully treated: +# # if (treated_index$size() > 0) { +# # +# # # Queue update to the infectious state to Tr: +# # variables$state$queue_update('Tr', treated_index) +# # +# # # Queue update to the infectivity to reflect their new state (Tr): +# # variables$infectivity$queue_update( +# # parameters$cd * parameters$drug_rel_c[drugs[successful]], +# # treated_index +# # ) +# # # Queue update to the last drug each successfully treated person received: +# # variables$drug$queue_update( +# # drugs[successful], +# # treated_index +# # ) +# # # Queue update to the time step on which each successfully treated person last +# # # received a drug: +# # variables$drug_time$queue_update( +# # timestep, +# # treated_index +# # ) +# # } +# +# # Return the Bitset of treated individuals: +# treated_index +# +# #----- 6a) Updated calculate_treated() function (V1): Resistance -> Efficacy ----------------------- +# +# calculate_treated_AM <- function( +# variables, +# clinical_infections, +# parameters, +# timestep, +# renderer +# ) { +# +# # Gather the treatment coverage(s) in the current timestep: +# treatment_coverages <- get_treatment_coverages(simparams, current_timestep) +# +# # Sum to get the total treatment coverage in the current time step: +# ft <- sum(treatment_coverages) +# +# # If treatment = 0, return an empty Bitset for the treated individuals: +# if (ft == 0) { +# return(individual::Bitset$new(simparams$human_population)) +# } +# +# # Add the total treatment coverage to the renderer: +# renderer$render('ft', ft, current_timestep) +# +# # Sample individuals from clinically infected to seek treatment using treatment coverage: +# seek_treatment <- sample_bitset(clinical_infections, ft) +# +# # Store the number of people that seek treatment this time step: +# n_treat <- seek_treatment$size() +# +# # Add the number of people seeking treatment in the current time step to the renderer: +# renderer$render('n_treated', n_treat, current_timestep) +# +# # Assign each individual seeking treatment a drug based on their coverage(s): +# drugs <- as.numeric(simparams$clinical_treatment_drugs[ +# sample.int( +# length(simparams$clinical_treatment_drugs), +# n_treat, +# prob = treatment_coverages, +# replace = TRUE +# ) +# ]) +# +# #+++ ANTIMALARIAL RESISTANCE +++# +# +# # Set the resistance drug index (each individuals drug): +# AM_drug_index <- as.numeric(simparams$antimalarial_resistance_drug[drugs]) +# +# # Open vectors to store the proportion of artemisinin resistance to the drug taken by each +# # individual and it's probability of manifesting as early treatment failure: +# art_resistance <- vector(); etf_prob <- vector() +# +# # For reach individual seeking treatment, retrieve the resistance and ETF probabilities corresponding +# # to the drug they have been administered: +# for(i in 1:n_treat) { +# +# # Identify the correct resistance index: +# last_resistance <- match_timestep(ts = simparams$antimalarial_resistance_timesteps[[AM_drug_index[i]]], +# t = current_timestep) +# +# # Retrieve the resistance value corresponding to the drug and time step: +# art_resistance[i] <- simparams$prop_artemisinin_resistant[[AM_drug_index[i]]][last_resistance] +# +# # Retrieve the ETF phenotype probability corresponding to the drug and time step: +# etf_prob[i] <- simparams$early_treatment_failure_prob[[AM_drug_index[i]]][last_resistance] +# +# } +# +# # Run bernoulli trials to determine which individuals experience early treatment failure given the +# # drug they have been administered: +# susceptible <- bernoulli_multi_p(p = 1 - (art_resistance * etf_prob)) +# +# # Calculate the number of individuals who failed treatment due to early treatment failure: +# n_ETF <- n_treat - length(susceptible) +# +# # Add the number of Early Treatment Failures to the renderer: +# renderer$render('n_ETF', n_ETF, current_timestep) +# +# # Remove the individuals who failed treatment due to resistance from the drugs vector: +# drugs <- drugs[susceptible] +# +# # Subset the people who remained susceptible +# susceptible_index <- bitset_at(seek_treatment, susceptible) +# +# #+++ DRUG EFFICACY +++# +# # Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: +# successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs]) +# +# # Calculate the number of people who failed treatment due to efficacy: +# n_treat_eff_fail <- length(susceptible) - length(successful) +# +# # Add the number of treatment efficacy failures to the renderer: +# renderer$render('n_treat_eff_fail', n_treat_eff_fail, current_timestep) +# +# # Subset the successfully treated people: +# treated_index <- bitset_at(susceptible_index, successful) +# +# # Add number of successfully treated individuals to the renderer +# renderer$render('n_treat_success', treated_index$size(), current_timestep) +# +# # For those people who have been successfully treated: +# if (treated_index$size() > 0) { +# +# # Queue update to the infectious state to Tr: +# variables$state$queue_update('Tr', treated_index) +# +# # Queue update to the infectivity to reflect their new state (Tr): +# variables$infectivity$queue_update( +# parameters$cd * parameters$drug_rel_c[drugs[successful]], +# treated_index +# ) +# # Queue update to the last drug each successfully treated person received: +# variables$drug$queue_update( +# drugs[successful], +# treated_index +# ) +# # Queue update to the time step on which each successfully treated person last +# # received a drug: +# variables$drug_time$queue_update( +# timestep, +# treated_index +# ) +# } +# +# # Return the Bitset of treated individuals: +# treated_index +# } +# +# #----- 6b) Updated calculate_treated() function (V1): Testing -------------------------------------- +# +# #----- X) Notes ------------------------------------------------------------------------------------ +# +# ##' If we are using a time-series of resistance proportions, we need a method for retrieving the up- +# ##' to-date proportions given the current time step and dates on which resistance values are updated. +# ##' For the time-varying deathrate, in create_mortality_process() (mortality_processes.R), the following +# ##' is used: +# ##' last_deathrate <- match_timestep(parameters$deathrate_timesteps, timestep) +# ##' +# ##' We can use the same method in the following way: +# ##' +# ##' latest_resistance <- match_timestep(unlist(parameters$antimalarial_resistance_timesteps), +# ##' current_timestep) +# ##' +# +# +# +# +# +# From acf145e4fa00fc6c5f67ef585e212e3f9cd91ae5 Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Thu, 13 Jul 2023 17:34:27 +0100 Subject: [PATCH 133/164] Removed the else{} arguments on the checks, condensed the first check using any(), removed for loops for second and third checks and used any() --- R/antimalarial_resistance.R | 50 ++++++++++++++----------------------- 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/R/antimalarial_resistance.R b/R/antimalarial_resistance.R index add8a2f3..a888442c 100644 --- a/R/antimalarial_resistance.R +++ b/R/antimalarial_resistance.R @@ -8,7 +8,7 @@ #' @param slow_parasite_clearance_prob vector of updates to the proportion of artemisinin-resistant infections that result in early treatment failure #' @param early_treatment_failure_prob vector of updates to the proportion of artemisinin-resistant infections that result in slow parasite clearance #' @param late_clinical_failure_prob vector of updates to the proportion of partner-drug-resistant infections that result in late clinical failure -#' @param late_parasitological_prob vector of updates to the proportion of partner-drug-resistant infections that result in late parasitologica; failure +#' @param late_parasitological_prob vector of updates to the proportion of partner-drug-resistant infections that result in late parasitological failure #' @param reinfection_prob vector of updates to the proportion of partner-drug-resistant infections that result in reinfection during prophylaxis #' @export set_antimalarial_resistance <- function(parameters, @@ -23,40 +23,30 @@ set_antimalarial_resistance <- function(parameters, reinfection_prob) { # Check that the number of values input is equal for each resistance parameter - if(length(artemisinin_resistance) != length(timesteps) | - length(partner_drug_resistance) != length(timesteps) | - length(slow_parasite_clearance_prob) != length(timesteps) | - length(early_treatment_failure_prob) != length(timesteps) | - length(late_clinical_failure_prob) != length(timesteps) | - length(late_parasitological_prob) != length(timesteps) | - length(reinfection_prob) != length(timesteps)) { + if(any(c(length(artemisinin_resistance), + length(partner_drug_resistance), + length(slow_parasite_clearance_prob), + length(early_treatment_failure_prob), + length(late_clinical_failure_prob), + length(late_parasitological_prob), + length(reinfection_prob)) != length(timesteps))) { stop("Number of resistance parameter vectors do not match time steps specified for update") - } else { - print("OK") } - # Check that the proportion of people with artemisinin and partner-drug resistance - # are bounded between 0 and 1: - for(i in length(artemisinin_resistance)) { - if(artemisinin_resistance[i] < 0 | artemisinin_resistance[i] > 1 | - partner_drug_resistance[i] < 0 | partner_drug_resistance[i] > 1) { - stop("Artemisinin and partner-drug resistance proportions must fall between 0 and 1") - } else { - print("OK") - } + # Ensure resistance proportions bounded between 0 and 1: + if(any(artemisinin_resistance < 0 | artemisinin_resistance > 1 | + partner_drug_resistance < 0 | partner_drug_resistance > 1)) { + stop("Artemisinin and partner-drug resistance proportions must fall between 0 and 1") } + # Ensure resistance phenotype probabilities bounded between 0 and 1: - for(i in 1:length(slow_parasite_clearance_prob)) { - if(slow_parasite_clearance_prob[i] < 0 | slow_parasite_clearance_prob[i] > 1 | - early_treatment_failure_prob[i] < 0 | early_treatment_failure_prob[i] > 1 | - late_clinical_failure_prob[i] < 0 | late_clinical_failure_prob[i] > 1 | - late_parasitological_prob[i] < 0 | late_parasitological_prob[i] > 1 | - reinfection_prob[i] < 0 | reinfection_prob[i] > 1) { - stop("Resistance phenotype probabilities must fall between 0 and 1") - } else { - print("OK") - } + if(any(slow_parasite_clearance_prob < 0 | slow_parasite_clearance_prob > 1 | + early_treatment_failure_prob < 0 | early_treatment_failure_prob > 1 | + late_clinical_failure_prob < 0 | late_clinical_failure_prob > 1 | + late_parasitological_prob < 0 | late_parasitological_prob > 1 | + reinfection_prob < 0 | reinfection_prob > 1)) { + stop("Resistance phenotype probabilities must fall between 0 and 1") } # Set antimalarial_resistance to TRUE @@ -68,8 +58,6 @@ set_antimalarial_resistance <- function(parameters, # If the drug index falls outside range 1:n_drugs, terminate the operation: if (drug < 1 | drug > n_drugs) { stop('Drug index is invalid, please set drugs using set_drugs') - } else { - print("OK") } # Check the drug_index for the drug setting parameters for From 856ec1e1ead712cbeceaaa679161490956bd9956 Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Thu, 13 Jul 2023 18:33:16 +0100 Subject: [PATCH 134/164] Added additional section for testing different versions of ETF version of model --- R/antimalarial_resistance_development.R | 1491 ++++++++++++++--------- 1 file changed, 944 insertions(+), 547 deletions(-) diff --git a/R/antimalarial_resistance_development.R b/R/antimalarial_resistance_development.R index 5122f77a..5e951745 100644 --- a/R/antimalarial_resistance_development.R +++ b/R/antimalarial_resistance_development.R @@ -1,553 +1,950 @@ -# #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# -# #+++++ antimalarial_resistance/etf development script +++++# -# #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# -# -# ##' README: -# ##' THis script is designed as a place to develop and store the changes being implemented into the -# ##' malariasimulation package in support of integrating antimalarial resistance. This file is -# ##' designed to be deleted prior to any merge and is purely for development purposes. -# -# ##' CURENTLY WORKING ON: amending the calculate_treated() function to update -# ##' -# ##' -# ##' Use Ctrl + Shft + C to comment everything in/out for load_all() to work -# -# #----- 1) Preamble --------------------------------------------------------------------------------- -# -# # Load in the individual package: -# library(individual) -# library(devtools) -# -# # Load the malariasimualtion functions (make sure this script is commented out when you run this) -# devtools::load_all(".") -# -# #----- 2) Original calculate_treated() function ---------------------------------------------------- -# -# ##' This is the original calculate_treated() function, renamed to avoid any conflicts. -# calculate_treated <- function( -# variables, -# clinical_infections, -# parameters, +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# +#+++++ antimalarial_resistance/etf development script +++++# +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# + +##' README: +##' THis script is designed as a place to develop and store the changes being implemented into the +##' malariasimulation package in support of integrating antimalarial resistance. This file is +##' designed to be deleted prior to any merge and is purely for development purposes. + +##' CURENTLY WORKING ON: amending the calculate_treated() function to update +##' +##' +##' Use Ctrl + Shft + C to comment everything in/out for load_all() to work + +#----- 1) Preamble --------------------------------------------------------------------------------- + +# Load in the individual package: +library(individual) +library(devtools) + +# Load the malariasimualtion functions (make sure this script is commented out when you run this) +devtools::load_all(".") + +#----- 2) Original calculate_treated() function ---------------------------------------------------- + +##' This is the original calculate_treated() function, renamed to avoid any conflicts. +calculate_treated <- function( + variables, + clinical_infections, + parameters, + timestep, + renderer +) { + + # Gather the treatment coverage(s) in the current timestep: + treatment_coverages <- get_treatment_coverages(parameters, timestep) + + # Sum to get the total treatment coverage in the current time step: + ft <- sum(treatment_coverages) + + # If treatment = 0, return an empty Bitset for the treated individuals: + if (ft == 0) { + return(individual::Bitset$new(parameters$human_population)) + } + + # Add the total treatment coverage to the renderer: + renderer$render('ft', ft, timestep) + + # Sample individuals from clinically infected to seek treatment using treatment coverage: + seek_treatment <- sample_bitset(clinical_infections, ft) + + # Store the number of people that seek treatment this time step: + n_treat <- seek_treatment$size() + + # Add the number of people seeking treatment in the current time step to the renderer: + renderer$render('n_treated', n_treat, timestep) + + # Assign each individual seeking treatment a drug based on their coverage(s): + drugs <- as.numeric(parameters$clinical_treatment_drugs[ + sample.int( + length(parameters$clinical_treatment_drugs), + n_treat, + prob = treatment_coverages, + replace = TRUE + ) + ]) + + # Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: + successful <- bernoulli_multi_p(parameters$drug_efficacy[drugs]) + + # Subset the successfully treated people: + treated_index <- bitset_at(seek_treatment, successful) + + # For those people who have been successfully treated: + if (treated_index$size() > 0) { + + # Queue update to the infectious state to Tr: + variables$state$queue_update('Tr', treated_index) + + # Queue update to the infectivity to reflect their new state (Tr): + variables$infectivity$queue_update( + parameters$cd * parameters$drug_rel_c[drugs[successful]], + treated_index + ) + # Queue update to the last drug each successfully treated person received: + variables$drug$queue_update( + drugs[successful], + treated_index + ) + # Queue update to the time step on which each successfully treated person last + # received a drug: + variables$drug_time$queue_update( + timestep, + treated_index + ) + } + + # Return the Bitset of treated individuals: + treated_index +} + +#----- 3) Function Development Set-up -------------------------------------------------------------- + +# Set an base parameter list +simparams <- get_parameters() + +# Add AL and DHA_PQP drug parameters to parameter list +simparams <- set_drugs(simparams, list(AL_params, DHA_PQP_params)) + +# Add clinical treatment events using set_clinical_treatment(): +simparams <- set_clinical_treatment(parameters = simparams, drug = 2, + timesteps = 5, coverages = 0.2) +simparams <- set_clinical_treatment(parameters = simparams, drug = 1, + timesteps = 10, coverages = 0.4) + +# Check the clinical treatment order and coverages: +simparams$clinical_treatment_drugs +simparams$clinical_treatment_coverages + +##' AL is drug 1, used second clinically at a coverage of 0.4 +##' DHA-PQP is drug 2, used first clinically at a coverage of 0.2 + +# Add resistance using set_antimalarial_resistance() using same order as clinical treatment +simparams <- set_antimalarial_resistance(parameters = simparams, + drug = 2, + timesteps = c(0, 25), + artemisinin_resistance = c(0.3, 0.42), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = rep(0.1, 2), + early_treatment_failure_prob = rep(0.6, 2), + late_clinical_failure_prob = rep(0.1, 2), + late_parasitological_prob = rep(0.1, 2), + reinfection_prob = rep(0.1, 2)) +simparams <- set_antimalarial_resistance(parameters = simparams, + drug = 1, + timesteps = c(0, 50), + artemisinin_resistance = c(0, 0), + partner_drug_resistance = c(0, 0.5), + slow_parasite_clearance_prob = rep(0.05, 2), + early_treatment_failure_prob = rep(0.5, 2), + late_clinical_failure_prob = rep(0.5, 2), + late_parasitological_prob = rep(0.5, 2), + reinfection_prob = rep(0.5, 2)) + +# Check the resistance parameters: +simparams$antimalarial_resistance_drug +simparams$antimalarial_resistance_timesteps +simparams$prop_artemisinin_resistant; simparams$prop_partner_drug_resistant +simparams$early_treatment_failure_prob; simparams$slow_parasite_clearance_prob +simparams$late_clinical_failure_prob; simparams$late_parasitological_failure_prob; simparams$reinfection_during_prophylaxis + +# Set up the model variables: +variables <- create_variables(parameters = simparams) + +# Establish Bitset of the human population +current_pop <- Bitset$new(simparams$human_population, from = NULL) +current_pop$insert(1:simparams$human_population); current_pop$to_vector() + +# Subset a group of clinically infected individuals from the population +clinical_infections <- sample_bitset(b = current_pop, rate = 0.4) +clinical_infections$to_vector(); clinical_infections$size() + +##' TIMESTEP +timesteps <- 100 +current_timestep <- 50 + +##' RENDERER +renderer <- individual::Render$new(timesteps) +renderer$to_dataframe() + +#----- 4) Individual Steps (Original) -------------------------------------------------------------- + +# Gather the treatment coverage(s) in the current timestep: +treatment_coverages <- get_treatment_coverages(simparams, current_timestep) + +# Sum to get the total treatment coverage in the current time step: +ft <- sum(treatment_coverages) + +# If treatment = 0, return an empty Bitset for the treated individuals: +if (ft == 0) { + return(individual::Bitset$new(simparams$human_population)) +} else { + print("OK") +} + +# Add the total treatment coverage to the renderer: +renderer$render('ft', ft, current_timestep) +renderer$to_dataframe()[current_timestep,] + +# Sample individuals from clinically infected to seek treatment using treatment coverage: +seek_treatment <- sample_bitset(clinical_infections, ft) +seek_treatment$to_vector(); seek_treatment$size() + +# Store the number of people that seek treatment this time step: +n_treat <- seek_treatment$size(); n_treat + +# Add the number of people seeking treatment in the current time step to the renderer: +renderer$render('n_treated', n_treat, current_timestep) +renderer$to_dataframe()[current_timestep,] + +# Assign each individual seeking treatment a drug based on their coverage(s): +drugs <- as.numeric(simparams$clinical_treatment_drugs[ + sample.int( + length(simparams$clinical_treatment_drugs), + n_treat, + prob = treatment_coverages, + replace = TRUE + ) +]) +drugs; length(drugs) == n_treat + +# Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: +successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs]) +successful; length(successful); (length(successful)/length(drugs))*100 + +# Subset the successfully treated people: +treated_index <- bitset_at(seek_treatment, successful) +treated_index$to_vector(); treated_index$size() + + +# # For those people who have been successfully treated: +# if (treated_index$size() > 0) { +# +# # Queue update to the infectious state to Tr: +# variables$state$queue_update('Tr', treated_index) +# +# # Queue update to the infectivity to reflect their new state (Tr): +# variables$infectivity$queue_update( +# parameters$cd * parameters$drug_rel_c[drugs[successful]], +# treated_index +# ) +# # Queue update to the last drug each successfully treated person received: +# variables$drug$queue_update( +# drugs[successful], +# treated_index +# ) +# # Queue update to the time step on which each successfully treated person last +# # received a drug: +# variables$drug_time$queue_update( # timestep, -# renderer -# ) { -# -# # Gather the treatment coverage(s) in the current timestep: -# treatment_coverages <- get_treatment_coverages(parameters, timestep) -# -# # Sum to get the total treatment coverage in the current time step: -# ft <- sum(treatment_coverages) -# -# # If treatment = 0, return an empty Bitset for the treated individuals: -# if (ft == 0) { -# return(individual::Bitset$new(parameters$human_population)) -# } -# -# # Add the total treatment coverage to the renderer: -# renderer$render('ft', ft, timestep) -# -# # Sample individuals from clinically infected to seek treatment using treatment coverage: -# seek_treatment <- sample_bitset(clinical_infections, ft) -# -# # Store the number of people that seek treatment this time step: -# n_treat <- seek_treatment$size() -# -# # Add the number of people seeking treatment in the current time step to the renderer: -# renderer$render('n_treated', n_treat, timestep) -# -# # Assign each individual seeking treatment a drug based on their coverage(s): -# drugs <- as.numeric(parameters$clinical_treatment_drugs[ -# sample.int( -# length(parameters$clinical_treatment_drugs), -# n_treat, -# prob = treatment_coverages, -# replace = TRUE -# ) -# ]) -# -# # Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: -# successful <- bernoulli_multi_p(parameters$drug_efficacy[drugs]) -# -# # Subset the successfully treated people: -# treated_index <- bitset_at(seek_treatment, successful) -# -# # For those people who have been successfully treated: -# if (treated_index$size() > 0) { -# -# # Queue update to the infectious state to Tr: -# variables$state$queue_update('Tr', treated_index) -# -# # Queue update to the infectivity to reflect their new state (Tr): -# variables$infectivity$queue_update( -# parameters$cd * parameters$drug_rel_c[drugs[successful]], -# treated_index -# ) -# # Queue update to the last drug each successfully treated person received: -# variables$drug$queue_update( -# drugs[successful], -# treated_index -# ) -# # Queue update to the time step on which each successfully treated person last -# # received a drug: -# variables$drug_time$queue_update( -# timestep, -# treated_index -# ) -# } -# -# # Return the Bitset of treated individuals: -# treated_index -# } -# -# #----- 3) Function Development Set-up -------------------------------------------------------------- -# -# # Set an base parameter list -# simparams <- get_parameters() -# -# # Add AL and DHA_PQP drug parameters to parameter list -# simparams <- set_drugs(simparams, list(AL_params, DHA_PQP_params)) -# -# # Add clinical treatment events using set_clinical_treatment(): -# simparams <- set_clinical_treatment(parameters = simparams, drug = 2, -# timesteps = 25, coverages = 0.2) -# simparams <- set_clinical_treatment(parameters = simparams, drug = 1, -# timesteps = 50, coverages = 0.4) -# -# # Check the clinical treatment order and coverages: -# simparams$clinical_treatment_drugs -# simparams$clinical_treatment_coverages -# -# ##' AL is drug 1, used second clinically at a coverage of 0.4 -# ##' DHA-PQP is drug 2, used first clinically at a coverage of 0.2 -# -# # Add resistance using set_antimalarial_resistance() using same order as clinical treatment -# simparams <- set_antimalarial_resistance(parameters = simparams, -# drug = 2, -# timesteps = c(0, 25), -# artemisinin_resistance = c(0.3, 0.42), -# partner_drug_resistance = c(0, 0), -# slow_parasite_clearance_prob = rep(0.1, 2), -# early_treatment_failure_prob = rep(0.6, 2), -# late_clinical_failure_prob = rep(0.1, 2), -# late_parasitological_prob = rep(0.1, 2), -# reinfection_prob = rep(0.1, 2)) -# simparams <- set_antimalarial_resistance(parameters = simparams, -# drug = 1, -# timesteps = c(0, 50), -# artemisinin_resistance = c(0, 0), -# partner_drug_resistance = c(0, 0.5), -# slow_parasite_clearance_prob = rep(0.05, 2), -# early_treatment_failure_prob = rep(0.5, 2), -# late_clinical_failure_prob = rep(0.5, 2), -# late_parasitological_prob = rep(0.5, 2), -# reinfection_prob = rep(0.5, 2)) -# -# # Check the resistance parameters: -# simparams$antimalarial_resistance_drug -# simparams$antimalarial_resistance_timesteps -# simparams$prop_artemisinin_resistant; simparams$prop_partner_drug_resistant -# simparams$early_treatment_failure_prob; simparams$slow_parasite_clearance_prob -# simparams$late_clinical_failure_prob; simparams$late_parasitological_failure_prob; simparams$reinfection_during_prophylaxis -# -# # Set up the model variables: -# variables <- create_variables(parameters = simparams) -# -# # Establish Bitset of the human population -# current_pop <- Bitset$new(simparams$human_population, from = NULL) -# current_pop$insert(1:simparams$human_population); current_pop$to_vector() -# -# # Subset a group of clinically infected individuals from the population -# clinical_infections <- sample_bitset(b = current_pop, rate = 0.4) -# clinical_infections$to_vector(); clinical_infections$size() -# -# ##' TIMESTEP -# timesteps <- 100 -# current_timestep <- 50 -# -# ##' RENDERER -# renderer <- individual::Render$new(timesteps) -# renderer$to_dataframe() -# -# #----- 4) Individual Steps (Original) -------------------------------------------------------------- -# -# # Gather the treatment coverage(s) in the current timestep: -# treatment_coverages <- get_treatment_coverages(simparams, current_timestep) -# -# # Sum to get the total treatment coverage in the current time step: -# ft <- sum(treatment_coverages) -# -# # If treatment = 0, return an empty Bitset for the treated individuals: -# if (ft == 0) { -# return(individual::Bitset$new(simparams$human_population)) -# } else { -# print("OK") -# } -# -# # Add the total treatment coverage to the renderer: -# renderer$render('ft', ft, current_timestep) -# renderer$to_dataframe()[current_timestep,] -# -# # Sample individuals from clinically infected to seek treatment using treatment coverage: -# seek_treatment <- sample_bitset(clinical_infections, ft) -# seek_treatment$to_vector(); seek_treatment$size() -# -# # Store the number of people that seek treatment this time step: -# n_treat <- seek_treatment$size(); n_treat -# -# # Add the number of people seeking treatment in the current time step to the renderer: -# renderer$render('n_treated', n_treat, current_timestep) -# renderer$to_dataframe()[current_timestep,] -# -# # Assign each individual seeking treatment a drug based on their coverage(s): -# drugs <- as.numeric(simparams$clinical_treatment_drugs[ -# sample.int( -# length(simparams$clinical_treatment_drugs), -# n_treat, -# prob = treatment_coverages, -# replace = TRUE +# treated_index # ) -# ]) -# drugs; length(drugs) == n_treat -# -# # Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: -# successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs]) -# successful; length(successful); (length(successful)/length(drugs))*100 -# -# # Subset the successfully treated people: -# treated_index <- bitset_at(seek_treatment, successful) -# treated_index$to_vector(); treated_index$size() -# -# -# # # For those people who have been successfully treated: -# # if (treated_index$size() > 0) { -# # -# # # Queue update to the infectious state to Tr: -# # variables$state$queue_update('Tr', treated_index) -# # -# # # Queue update to the infectivity to reflect their new state (Tr): -# # variables$infectivity$queue_update( -# # parameters$cd * parameters$drug_rel_c[drugs[successful]], -# # treated_index -# # ) -# # # Queue update to the last drug each successfully treated person received: -# # variables$drug$queue_update( -# # drugs[successful], -# # treated_index -# # ) -# # # Queue update to the time step on which each successfully treated person last -# # # received a drug: -# # variables$drug_time$queue_update( -# # timestep, -# # treated_index -# # ) -# # } -# -# # Return the Bitset of treated individuals: -# treated_index -# -# #----- 5) Individual Steps (Updated) --------------------------------------------------------------- -# -# # Gather the treatment coverage(s) in the current timestep: -# treatment_coverages <- get_treatment_coverages(simparams, current_timestep); treatment_coverages -# -# # Sum to get the total treatment coverage in the current time step: -# ft <- sum(treatment_coverages); ft -# -# # If treatment = 0, return an empty Bitset for the treated individuals: -# if (ft == 0) { -# return(individual::Bitset$new(simparams$human_population)) -# } else { -# print("OK") # } -# -# # Add the total treatment coverage to the renderer: -# renderer$render('ft', ft, current_timestep) -# renderer$to_dataframe()[current_timestep,] -# -# # Sample individuals from clinically infected to seek treatment using treatment coverage: -# seek_treatment <- sample_bitset(clinical_infections, ft) -# seek_treatment$to_vector(); seek_treatment$size() -# paste0(((seek_treatment$size()/clinical_infections$size())*100), -# "% of clinically infected individuals sought treatment") -# -# # Store the number of people that seek treatment this time step: -# n_treat <- seek_treatment$size(); n_treat -# -# # Add the number of people seeking treatment in the current time step to the renderer: -# renderer$render('n_treated', n_treat, current_timestep) -# renderer$to_dataframe()[current_timestep,] -# -# # Assign each individual seeking treatment a drug based on their coverage(s): -# drugs <- as.numeric(simparams$clinical_treatment_drugs[ -# sample.int( -# length(simparams$clinical_treatment_drugs), -# n_treat, -# prob = treatment_coverages, -# replace = TRUE + +# Return the Bitset of treated individuals: +treated_index + +#----- 5a) Individual Steps (Updated) Resistance First --------------------------------------------- + +# Gather the treatment coverage(s) in the current timestep: +treatment_coverages <- get_treatment_coverages(simparams, current_timestep); treatment_coverages + +# Sum to get the total treatment coverage in the current time step: +ft <- sum(treatment_coverages); ft + +# If treatment = 0, return an empty Bitset for the treated individuals: +if (ft == 0) { + return(individual::Bitset$new(simparams$human_population)) +} else { + print("OK") +} + +# Add the total treatment coverage to the renderer: +renderer$render('ft', ft, current_timestep) +renderer$to_dataframe()[current_timestep,] + +# Sample individuals from clinically infected to seek treatment using treatment coverage: +seek_treatment <- sample_bitset(clinical_infections, ft) +seek_treatment$to_vector(); seek_treatment$size() +paste0(((seek_treatment$size()/clinical_infections$size())*100), + "% of clinically infected individuals sought treatment") + +# Store the number of people that seek treatment this time step: +n_treat <- seek_treatment$size(); n_treat + +# Add the number of people seeking treatment in the current time step to the renderer: +renderer$render('n_treated', n_treat, current_timestep) +renderer$to_dataframe()[current_timestep,] + +# Assign each individual seeking treatment a drug based on their coverage(s): +drugs <- as.numeric(simparams$clinical_treatment_drugs[ + sample.int( + length(simparams$clinical_treatment_drugs), + n_treat, + prob = treatment_coverages, + replace = TRUE + ) +]); drugs; length(drugs) == n_treat; table(drugs) + +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# +#+++++ RESISTANCE + +# Set the resistance drug index (each individuals drug): +AM_drug_index <- as.numeric(simparams$antimalarial_resistance_drug[drugs]) +drugs; AM_drug_index + +# Generate a vector containing the proportion of artemisinin resistance to the drug taken by each +# individual and it's probability of manifesting as early treatment failure: +art_resistance <- vector(); etf_prob <- vector() +for(i in 1:n_treat) { + + # Identify the correct resistance index: + last_resistance <- match_timestep(ts = simparams$antimalarial_resistance_timesteps[[AM_drug_index[i]]], + t = current_timestep) + + # Retrieve the resistance value corresponding to the drug and time step: + art_resistance[i] <- simparams$prop_artemisinin_resistant[[AM_drug_index[i]]][last_resistance] + + # Retrieve the ETF phenotype probability corresponding to the drug and time step: + etf_prob[i] <- simparams$early_treatment_failure_prob[[AM_drug_index[i]]][last_resistance] + +} +drugs; art_resistance; etf_prob + +# The probability that an individual fails is the product of the proportion of individuals with resistance +# to the drug they've taken and the probability that early treatment failure manifests in cases of resistance +# to that drug. The probability individuals are treated successfully is therefore 1 - this product. + +# Run bernoulli trials to determine which individuals fail treatment due to resistance to the drug +# they have taken: +susceptible <- bernoulli_multi_p(p = 1 - (art_resistance * etf_prob)) +length(susceptible); (length(susceptible)/n_treat)*100 + +##' Drug 1 is AL and Drug 2 is DHA-PQP. Drug 2 is set first in clinical treatment and resistance. +##' The proportion of individuals in the current timestep with artemisinin resistance to drug 1 is +##' 0, while the proportion of the population with artemisinin resistance to drug 2 is 0.42. The prob. +##' of early treatment failure for Drug 1 is 0.5, and is 0.6 for Drug 2. + +# Calculate the number of individuals who failed treatment due to early treatment failure: +n_ETF <- n_treat - length(susceptible) + +# Add the number of Early Treatment Failures to the renderer: +renderer$render('n_ETF', n_ETF, current_timestep) +renderer$to_dataframe()[current_timestep,] + +# Remove the individuals who failed treatment due to resistance from the drugs vector: +drugs[susceptible]; length(drugs[susceptible]); (length(drugs[susceptible])/n_treat)*100 +drugs_2 <- drugs[susceptible] + +# Check which individuals failed and which drug they took (only modelled resistance to drug 2) +res_fail_individuals <- which(!((1:n_treat) %in% susceptible)) +drugs[res_fail_individuals]; table(drugs); table(drugs_2) +drugs; drugs_2 + +# Subset the people who remained susceptible +seek_treatment$to_vector(); seek_treatment$size() +susceptible_index <- bitset_at(seek_treatment, susceptible) +susceptible_index$to_vector(); susceptible_index$size() + +# So, we should now have a slightly shorter vector of drugs taken by each individual to account for +# the individuals who gave failed treatment due to resistance. We can then use this to work out who +# is successfully treated given the drug efficacy. + +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# +#+++++ DRUG EFFICACY +# Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: +successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs_2]) +successful; length(successful); (length(successful)/length(drugs_2))*100 + +# Calculate the number of people who failed treatment due to efficacy: +n_treat_eff_fail <- length(susceptible) - length(successful) + +# Add the number of treatment efficacy failures to the renderer: +renderer$render('n_treat_eff_fail', n_treat_eff_fail, current_timestep) +renderer$to_dataframe()[current_timestep,] + +# Subset the successfully treated people: +treated_index <- bitset_at(susceptible_index, successful) +treated_index$to_vector(); treated_index$size() + +# Compare the three bitsets: +seek_treatment$to_vector(); seek_treatment$size() +susceptible_index$to_vector(); susceptible_index$size() +treated_index$to_vector(); treated_index$size() + +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# + +# # For those people who have been successfully treated: +# if (treated_index$size() > 0) { +# +# # Queue update to the infectious state to Tr: +# variables$state$queue_update('Tr', treated_index) +# +# # Queue update to the infectivity to reflect their new state (Tr): +# variables$infectivity$queue_update( +# parameters$cd * parameters$drug_rel_c[drugs[successful]], +# treated_index # ) -# ]); drugs; length(drugs) == n_treat; table(drugs) -# -# #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# -# #+++++ RESISTANCE -# -# # Set the resistance drug index (each individuals drug): -# AM_drug_index <- as.numeric(simparams$antimalarial_resistance_drug[drugs]) -# drugs; AM_drug_index -# -# # Generate a vector containing the proportion of artemisinin resistance to the drug taken by each -# # individual and it's probability of manifesting as early treatment failure: -# art_resistance <- vector(); etf_prob <- vector() -# for(i in 1:n_treat) { -# -# # Identify the correct resistance index: -# last_resistance <- match_timestep(ts = simparams$antimalarial_resistance_timesteps[[AM_drug_index[i]]], -# t = current_timestep) -# -# # Retrieve the resistance value corresponding to the drug and time step: -# art_resistance[i] <- simparams$prop_artemisinin_resistant[[AM_drug_index[i]]][last_resistance] -# -# # Retrieve the ETF phenotype probability corresponding to the drug and time step: -# etf_prob[i] <- simparams$early_treatment_failure_prob[[AM_drug_index[i]]][last_resistance] -# -# } -# drugs; art_resistance; etf_prob -# -# # The probability that an individual fails is the product of the proportion of individuals with resistance -# # to the drug they've taken and the probability that early treatment failure manifests in cases of resistance -# # to that drug. The probability individuals are treated successfully is therefore 1 - this product. -# -# # Run bernoulli trials to determine which individuals fail treatment due to resistance to the drug -# # they have taken: -# susceptible <- bernoulli_multi_p(p = 1 - (art_resistance * etf_prob)) -# length(susceptible); (length(susceptible)/n_treat)*100 -# -# ##' Drug 1 is AL and Drug 2 is DHA-PQP. Drug 2 is set first in clinical treatment and resistance. -# ##' The proportion of individuals in the current timestep with artemisinin resistance to drug 1 is -# ##' 0, while the proportion of the population with artemisinin resistance to drug 2 is 0.42. The prob. -# ##' of early treatment failure for Drug 1 is 0.5, and is 0.6 for Drug 2. -# -# # Calculate the number of individuals who failed treatment due to early treatment failure: -# n_ETF <- n_treat - length(susceptible) -# -# # Add the number of Early Treatment Failures to the renderer: -# renderer$render('n_ETF', n_ETF, current_timestep) -# renderer$to_dataframe()[current_timestep,] -# -# # Remove the individuals who failed treatment due to resistance from the drugs vector: -# drugs[susceptible]; length(drugs[susceptible]); (length(drugs[susceptible])/n_treat)*100 -# drugs_2 <- drugs[susceptible] -# -# # Check which individuals failed and which drug they took (only modelled resistance to drug 2) -# res_fail_individuals <- which(!((1:n_treat) %in% susceptible)) -# drugs[res_fail_individuals]; table(drugs); table(drugs_2) -# drugs; drugs_2 -# -# # Subset the people who remained susceptible -# seek_treatment$to_vector(); seek_treatment$size() -# susceptible_index <- bitset_at(seek_treatment, susceptible) -# susceptible_index$to_vector(); susceptible_index$size() -# -# # So, we should now have a slightly shorter vector of drugs taken by each individual to account for -# # the individuals who gave failed treatment due to resistance. We can then use this to work out who -# # is successfully treated given the drug efficacy. -# -# #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# -# #+++++ DRUG EFFICACY -# # Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: -# successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs_2]) -# successful; length(successful); (length(successful)/length(drugs_2))*100 -# -# # Calculate the number of people who failed treatment due to efficacy: -# n_treat_eff_fail <- length(susceptible) - length(successful) -# -# # Add the number of treatment efficacy failures to the renderer: -# renderer$render('n_treat_eff_fail', n_treat_eff_fail, current_timestep) -# renderer$to_dataframe()[current_timestep,] -# -# # Subset the successfully treated people: -# treated_index <- bitset_at(susceptible_index, successful) -# treated_index$to_vector(); treated_index$size() -# -# # Compare the three bitsets: -# seek_treatment$to_vector(); seek_treatment$size() -# susceptible_index$to_vector(); susceptible_index$size() -# treated_index$to_vector(); treated_index$size() -# -# #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# -# -# # # For those people who have been successfully treated: -# # if (treated_index$size() > 0) { -# # -# # # Queue update to the infectious state to Tr: -# # variables$state$queue_update('Tr', treated_index) -# # -# # # Queue update to the infectivity to reflect their new state (Tr): -# # variables$infectivity$queue_update( -# # parameters$cd * parameters$drug_rel_c[drugs[successful]], -# # treated_index -# # ) -# # # Queue update to the last drug each successfully treated person received: -# # variables$drug$queue_update( -# # drugs[successful], -# # treated_index -# # ) -# # # Queue update to the time step on which each successfully treated person last -# # # received a drug: -# # variables$drug_time$queue_update( -# # timestep, -# # treated_index -# # ) -# # } -# -# # Return the Bitset of treated individuals: -# treated_index -# -# #----- 6a) Updated calculate_treated() function (V1): Resistance -> Efficacy ----------------------- -# -# calculate_treated_AM <- function( -# variables, -# clinical_infections, -# parameters, +# # Queue update to the last drug each successfully treated person received: +# variables$drug$queue_update( +# drugs[successful], +# treated_index +# ) +# # Queue update to the time step on which each successfully treated person last +# # received a drug: +# variables$drug_time$queue_update( # timestep, -# renderer -# ) { -# -# # Gather the treatment coverage(s) in the current timestep: -# treatment_coverages <- get_treatment_coverages(simparams, current_timestep) -# -# # Sum to get the total treatment coverage in the current time step: -# ft <- sum(treatment_coverages) -# -# # If treatment = 0, return an empty Bitset for the treated individuals: -# if (ft == 0) { -# return(individual::Bitset$new(simparams$human_population)) -# } -# -# # Add the total treatment coverage to the renderer: -# renderer$render('ft', ft, current_timestep) -# -# # Sample individuals from clinically infected to seek treatment using treatment coverage: -# seek_treatment <- sample_bitset(clinical_infections, ft) -# -# # Store the number of people that seek treatment this time step: -# n_treat <- seek_treatment$size() -# -# # Add the number of people seeking treatment in the current time step to the renderer: -# renderer$render('n_treated', n_treat, current_timestep) -# -# # Assign each individual seeking treatment a drug based on their coverage(s): -# drugs <- as.numeric(simparams$clinical_treatment_drugs[ -# sample.int( -# length(simparams$clinical_treatment_drugs), -# n_treat, -# prob = treatment_coverages, -# replace = TRUE -# ) -# ]) -# -# #+++ ANTIMALARIAL RESISTANCE +++# -# -# # Set the resistance drug index (each individuals drug): -# AM_drug_index <- as.numeric(simparams$antimalarial_resistance_drug[drugs]) -# -# # Open vectors to store the proportion of artemisinin resistance to the drug taken by each -# # individual and it's probability of manifesting as early treatment failure: -# art_resistance <- vector(); etf_prob <- vector() -# -# # For reach individual seeking treatment, retrieve the resistance and ETF probabilities corresponding -# # to the drug they have been administered: -# for(i in 1:n_treat) { -# -# # Identify the correct resistance index: -# last_resistance <- match_timestep(ts = simparams$antimalarial_resistance_timesteps[[AM_drug_index[i]]], -# t = current_timestep) -# -# # Retrieve the resistance value corresponding to the drug and time step: -# art_resistance[i] <- simparams$prop_artemisinin_resistant[[AM_drug_index[i]]][last_resistance] -# -# # Retrieve the ETF phenotype probability corresponding to the drug and time step: -# etf_prob[i] <- simparams$early_treatment_failure_prob[[AM_drug_index[i]]][last_resistance] -# -# } -# -# # Run bernoulli trials to determine which individuals experience early treatment failure given the -# # drug they have been administered: -# susceptible <- bernoulli_multi_p(p = 1 - (art_resistance * etf_prob)) -# -# # Calculate the number of individuals who failed treatment due to early treatment failure: -# n_ETF <- n_treat - length(susceptible) -# -# # Add the number of Early Treatment Failures to the renderer: -# renderer$render('n_ETF', n_ETF, current_timestep) -# -# # Remove the individuals who failed treatment due to resistance from the drugs vector: -# drugs <- drugs[susceptible] -# -# # Subset the people who remained susceptible -# susceptible_index <- bitset_at(seek_treatment, susceptible) -# -# #+++ DRUG EFFICACY +++# -# # Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: -# successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs]) -# -# # Calculate the number of people who failed treatment due to efficacy: -# n_treat_eff_fail <- length(susceptible) - length(successful) -# -# # Add the number of treatment efficacy failures to the renderer: -# renderer$render('n_treat_eff_fail', n_treat_eff_fail, current_timestep) -# -# # Subset the successfully treated people: -# treated_index <- bitset_at(susceptible_index, successful) -# -# # Add number of successfully treated individuals to the renderer -# renderer$render('n_treat_success', treated_index$size(), current_timestep) -# -# # For those people who have been successfully treated: -# if (treated_index$size() > 0) { -# -# # Queue update to the infectious state to Tr: -# variables$state$queue_update('Tr', treated_index) -# -# # Queue update to the infectivity to reflect their new state (Tr): -# variables$infectivity$queue_update( -# parameters$cd * parameters$drug_rel_c[drugs[successful]], -# treated_index -# ) -# # Queue update to the last drug each successfully treated person received: -# variables$drug$queue_update( -# drugs[successful], -# treated_index -# ) -# # Queue update to the time step on which each successfully treated person last -# # received a drug: -# variables$drug_time$queue_update( -# timestep, -# treated_index -# ) -# } -# -# # Return the Bitset of treated individuals: -# treated_index +# treated_index +# ) # } -# -# #----- 6b) Updated calculate_treated() function (V1): Testing -------------------------------------- -# -# #----- X) Notes ------------------------------------------------------------------------------------ -# -# ##' If we are using a time-series of resistance proportions, we need a method for retrieving the up- -# ##' to-date proportions given the current time step and dates on which resistance values are updated. -# ##' For the time-varying deathrate, in create_mortality_process() (mortality_processes.R), the following -# ##' is used: -# ##' last_deathrate <- match_timestep(parameters$deathrate_timesteps, timestep) -# ##' -# ##' We can use the same method in the following way: -# ##' -# ##' latest_resistance <- match_timestep(unlist(parameters$antimalarial_resistance_timesteps), -# ##' current_timestep) -# ##' -# -# -# -# -# -# + +# Return the Bitset of treated individuals: +treated_index + +#----- 5b) Individual Steps (Updated) Resistance Last ---------------------------------------------- + +# Retrieve the treatment coverages for the current time step: +treatment_coverages <- get_treatment_coverages(simparams, current_timestep); treatment_coverages + +# Calculate the total treatment coverage for the current time step: +ft <- sum(treatment_coverages); ft + +# If there is no treatment coverage, return an empty Bitset: +if (ft == 0) { + return(individual::Bitset$new(simparams$human_population)) +} + +# Store the total coverage in the current time step in the renderer: +renderer$render('ft', ft, current_timestep) +renderer$to_dataframe()[current_timestep,] + +# Use total coverage to sample people from the clinically infected who will seek treatment: +seek_treatment <- sample_bitset(clinical_infections, ft) +seek_treatment$to_vector(); seek_treatment$size() + +# Store the number of people seeking treatment in the current time step: +n_treat <- seek_treatment$size() + +# Add the number of people seeking treatment to the renderer: +renderer$render('n_treated', n_treat, current_timestep) +renderer$to_dataframe()[current_timestep,] + +# Assign each individual seeking treatment a drug based on relative coverages: +drugs <- as.numeric(simparams$clinical_treatment_drugs[ + sample.int( + length(simparams$clinical_treatment_drugs), + n_treat, + prob = treatment_coverages, + replace = TRUE + ) +]) +length(drugs) == n_treat; table(drugs) + +#+++++ DRUG EFFICACY +++++# + +# Determine the people who were successfully treated using bernoulli trials: +successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs]); successful +length(successful) + +# Subset out the successfully treated individuals: +successful_index <- bitset_at(seek_treatment, successful) +successful_index$to_vector(); successful_index$size() + +# Calculate the number of people who failed treatment due to efficacy: +n_treat_eff_fail <- n_treat - successful_index$size() +n_treat; length(successful); n_treat_eff_fail + +# Add the number of treatment efficacy failures to the renderer: +renderer$render('n_treat_eff_fail', n_treat_eff_fail, current_timestep) +renderer$to_dataframe()[current_timestep,] + +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# +#+++++ RESISTANCE + +# Subset out the drugs received by the people who's treatment didnt fail due to efficacy: +drugs <- drugs[successful] + +# Set the resistance drug index (each individuals drug): +AM_drug_index <- as.numeric(simparams$antimalarial_resistance_drug[drugs]) +drugs; AM_drug_index + +# Generate a vector containing the proportion of artemisinin resistance to the drug taken by each +# individual and it's probability of manifesting as early treatment failure: +art_resistance <- vector(); etf_prob <- vector() +for(i in 1:length(successful)) { + + # Identify the correct resistance index: + last_resistance <- match_timestep(ts = simparams$antimalarial_resistance_timesteps[[AM_drug_index[i]]], + t = current_timestep) + + # Retrieve the resistance value corresponding to the drug and time step: + art_resistance[i] <- simparams$prop_artemisinin_resistant[[AM_drug_index[i]]][last_resistance] + + # Retrieve the ETF phenotype probability corresponding to the drug and time step: + etf_prob[i] <- simparams$early_treatment_failure_prob[[AM_drug_index[i]]][last_resistance] + +} +drugs; art_resistance; etf_prob +length(drugs); length(art_resistance); length(etf_prob) + +# Run bernoulli trials to determine which individuals experience ETF: +treated <- bernoulli_multi_p(p = 1 - (art_resistance * etf_prob)) +length(treated); (length(treated)/length(successful))*100 + +# Calculate the number of individuals who failed treatment due to early treatment failure: +n_ETF <- length(successful) - length(treated) + +# Add the number of Early Treatment Failures to the renderer: +renderer$render('n_ETF', n_ETF, current_timestep) +renderer$to_dataframe()[current_timestep,] + +# Subset the people who remained susceptible +successful_index$to_vector(); successful_index$size() +treated_index <- bitset_at(successful_index, treated) +treated_index$to_vector(); treated_index$size() + +# Can visually check which individual failed treatment due to ETF +seek_treatment$to_vector(); successful_index$to_vector(); treated_index$to_vector() + +# Update the variables for those who have been successfully treated: +if (treated_index$size() > 0) { + variables$state$queue_update('Tr', treated_index) + variables$infectivity$queue_update( + simparams$cd * simparams$drug_rel_c[drugs[treated]], + treated_index + ) + variables$drug$queue_update( + drugs[treated], + treated_index + ) + variables$drug_time$queue_update( + timestep, + treated_index + ) +} + +treated_index + +#----- 6a) Updated calculate_treated() function (V1): Resistance -> Efficacy ----------------------- + +calculate_treated_AM <- function( + variables, + clinical_infections, + parameters, + timestep, + renderer +) { + + # Gather the treatment coverage(s) in the current timestep: + treatment_coverages <- get_treatment_coverages(simparams, timestep) + + # Sum to get the total treatment coverage in the current time step: + ft <- sum(treatment_coverages) + + # If treatment = 0, return an empty Bitset for the treated individuals: + if (ft == 0) { + return(individual::Bitset$new(simparams$human_population)) + } + + # Add the total treatment coverage to the renderer: + renderer$render('ft', ft, timestep) + + # Sample individuals from clinically infected to seek treatment using treatment coverage: + seek_treatment <- sample_bitset(clinical_infections, ft) + + # Store the number of people that seek treatment this time step: + n_treat <- seek_treatment$size() + + # Add the number of people seeking treatment in the current time step to the renderer: + renderer$render('n_treated', n_treat, timestep) + + # Assign each individual seeking treatment a drug based on their coverage(s): + drugs <- as.numeric(simparams$clinical_treatment_drugs[ + sample.int( + length(simparams$clinical_treatment_drugs), + n_treat, + prob = treatment_coverages, + replace = TRUE + ) + ]) + + #+++ ANTIMALARIAL RESISTANCE +++# + + # Set the resistance drug index (each individuals drug): + AM_drug_index <- as.numeric(simparams$antimalarial_resistance_drug[drugs]) + + # Open vectors to store the proportion of artemisinin resistance to the drug taken by each + # individual and it's probability of manifesting as early treatment failure: + art_resistance <- vector(); etf_prob <- vector() + + # For reach individual seeking treatment, retrieve the resistance and ETF probabilities corresponding + # to the drug they have been administered: + for(i in 1:n_treat) { + + # Identify the correct resistance index: + last_resistance <- match_timestep(ts = simparams$antimalarial_resistance_timesteps[[AM_drug_index[i]]], + t = timestep) + + # Retrieve the resistance value corresponding to the drug and time step: + art_resistance[i] <- simparams$prop_artemisinin_resistant[[AM_drug_index[i]]][last_resistance] + + # Retrieve the ETF phenotype probability corresponding to the drug and time step: + etf_prob[i] <- simparams$early_treatment_failure_prob[[AM_drug_index[i]]][last_resistance] + + } + + # Run bernoulli trials to determine which individuals experience early treatment failure given the + # drug they have been administered: + susceptible <- bernoulli_multi_p(p = 1 - (art_resistance * etf_prob)) + + # Calculate the number of individuals who failed treatment due to early treatment failure: + n_ETF <- n_treat - length(susceptible) + + # Add the number of Early Treatment Failures to the renderer: + renderer$render('n_ETF', n_ETF, timestep) + + # Remove the individuals who failed treatment due to resistance from the drugs vector: + drugs <- drugs[susceptible] + + # Subset the people who remained susceptible + susceptible_index <- bitset_at(seek_treatment, susceptible) + + #+++ DRUG EFFICACY +++# + # Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: + successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs]) + + # Calculate the number of people who failed treatment due to efficacy: + n_treat_eff_fail <- length(susceptible) - length(successful) + + # Add the number of treatment efficacy failures to the renderer: + renderer$render('n_treat_eff_fail', n_treat_eff_fail, timestep) + + # Subset the successfully treated people: + treated_index <- bitset_at(susceptible_index, successful) + + # Add number of successfully treated individuals to the renderer + renderer$render('n_treat_success', treated_index$size(), timestep) + + # For those people who have been successfully treated: + if (treated_index$size() > 0) { + + # Queue update to the infectious state to Tr: + variables$state$queue_update('Tr', treated_index) + + # Queue update to the infectivity to reflect their new state (Tr): + variables$infectivity$queue_update( + parameters$cd * parameters$drug_rel_c[drugs[successful]], + treated_index + ) + # Queue update to the last drug each successfully treated person received: + variables$drug$queue_update( + drugs[successful], + treated_index + ) + # Queue update to the time step on which each successfully treated person last + # received a drug: + variables$drug_time$queue_update( + timestep, + treated_index + ) + } + + # Return the Bitset of treated individuals: + treated_index +} + +#----- 6b) Updated calculate_treated_AM() function (V1): Testing -------------------------------------- + +##' RENDERER +test_render <- individual::Render$new(timesteps) + +# Make a copy of the renderer: +renderer_original <- test_render$clone() +renderer_updated <- test_render$clone() + +# Check the normal calculate_treated() function works +test_original_version <- calculate_treated(variables = variables, + clinical_infections = clinical_infections, + parameters = simparams, + timestep = current_timestep, + renderer = renderer_original) +# View the rendered dataframe (original) +renderer_original$to_dataframe()[current_timestep,] + +# Test the updated calculate_treated_AM() function: +test_updated_version <- calculate_treated_AM(variables = variables, + clinical_infections = clinical_infections, + parameters = simparams, + timestep = current_timestep, + renderer = renderer_updated) + +# View the rendered dataframe (original) +renderer_updated$to_dataframe()[current_timestep,] + +# Compare the output Bitsets: +test_original_version$to_vector(); test_original_version$size() +test_updated_version$to_vector(); test_updated_version$size() + +#----- 6c) Updated calculate_treated_AM() function (V1): Simulation Testing ------------------------ + +# Reset the environment +rm(list = ls()) + +# Set an base parameter list +simparams <- get_parameters() + +# Add AL and DHA_PQP drug parameters to parameter list +simparams <- set_drugs(simparams, list(AL_params, DHA_PQP_params)) + +# Add clinical treatment events using set_clinical_treatment(): +simparams <- set_clinical_treatment(parameters = simparams, drug = 2, + timesteps = c(15, 60, 75), coverages = c(0, 0.2, 0.17)) +simparams <- set_clinical_treatment(parameters = simparams, drug = 1, + timesteps = c(35, 55, 100), coverages = c(0, 0.4, 0.35)) + +# Add resistance using set_antimalarial_resistance() using same order as clinical treatment +simparams <- set_antimalarial_resistance(parameters = simparams, + drug = 2, + timesteps = c(0, 25), + artemisinin_resistance = c(0.3, 0.42), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = rep(0.1, 2), + early_treatment_failure_prob = rep(0.6, 2), + late_clinical_failure_prob = rep(0.1, 2), + late_parasitological_prob = rep(0.1, 2), + reinfection_prob = rep(0.1, 2)) +simparams <- set_antimalarial_resistance(parameters = simparams, + drug = 1, + timesteps = c(0, 50), + artemisinin_resistance = c(0, 0), + partner_drug_resistance = c(0, 0.5), + slow_parasite_clearance_prob = rep(0.05, 2), + early_treatment_failure_prob = rep(0.5, 2), + late_clinical_failure_prob = rep(0.5, 2), + late_parasitological_prob = rep(0.5, 2), + reinfection_prob = rep(0.5, 2)) + +# Run the simulation: +updated_calctreated_test_sim <- run_simulation(timesteps = 10, parameters = simparams) +updated_calctreated_test_sim <- run_simulation(timesteps = 15, parameters = simparams) +updated_calctreated_test_sim <- run_simulation(timesteps = 35, parameters = simparams) +updated_calctreated_test_sim <- run_simulation(timesteps = 56, parameters = simparams) + + +# View the output +updated_calctreated_test_sim + +#----- 7a) Updated calculate_treated() function (V1): Efficacy -> Resistance ----------------------- + +# Version of updated calculate_treated() function with drug efficacy and then resistance: +calculate_treated_AM_2 <- function( + variables, + clinical_infections, + parameters, + timestep, + renderer +) { + + # Retrieve the treatment coverages for the current time step: + treatment_coverages <- get_treatment_coverages(parameters, timestep) + + # Calculate the total treatment coverage for the current time step: + ft <- sum(treatment_coverages) + + # If there is no treatment coverage, return an empty Bitset: + if (ft == 0) { + return(individual::Bitset$new(parameters$human_population)) + } + + # Store the total coverage in the current time step in the renderer: + renderer$render('ft', ft, timestep) + + # Use total coverage to sample people from the clinically infected who will seek treatment: + seek_treatment <- sample_bitset(clinical_infections, ft) + + # Store the number of people seeking treatment in the current time step: + n_treat <- seek_treatment$size() + + # Add the number of people seeking treatment to the renderer: + renderer$render('n_treated', n_treat, timestep) + + # Assign each individual seeking treatment a drug based on relative coverages: + drugs <- as.numeric(parameters$clinical_treatment_drugs[ + sample.int( + length(parameters$clinical_treatment_drugs), + n_treat, + prob = treatment_coverages, + replace = TRUE + ) + ]) + + #+++++ DRUG EFFICACY +++++# + + # Determine the people who were successfully treated using bernoulli trials: + successful <- bernoulli_multi_p(parameters$drug_efficacy[drugs]) + + # Subset out the successfully treated individuals: + successful_index <- bitset_at(seek_treatment, successful) + + # Calculate the number of people who failed treatment due to efficacy: + n_treat_eff_fail <- n_treat - successful_index$size() + + # Add the number of treatment efficacy failures to the renderer: + renderer$render('n_treat_eff_fail', n_treat_eff_fail, timestep) + + #+++++ RESISTANCE +++++# + + # Subset out the drugs received by the people who's treatment didnt fail due to efficacy: + drugs <- drugs[successful] + + # Set the resistance drug index (each individuals drug): + AM_drug_index <- as.numeric(parameters$antimalarial_resistance_drug[drugs]) + + # Generate a vector containing the prop. artemisinin resistance to each drug for each + # individual and the prob. of experiencing as early treatment failure: + art_resistance <- vector(); etf_prob <- vector() + for(i in 1:length(successful)) { + + # Identify the correct resistance index: + last_resistance <- match_timestep(ts = parameters$antimalarial_resistance_timesteps[[AM_drug_index[i]]], + t = timestep) + + # Retrieve the resistance value corresponding to the drug and time step: + art_resistance[i] <- parameters$prop_artemisinin_resistant[[AM_drug_index[i]]][last_resistance] + + # Retrieve the ETF phenotype probability corresponding to the drug and time step: + etf_prob[i] <- parameters$early_treatment_failure_prob[[AM_drug_index[i]]][last_resistance] + + } + + # Run bernoulli trials to determine which individuals experience ETF: + treated <- bernoulli_multi_p(p = 1 - (art_resistance * etf_prob)) + + # Calculate the number of individuals who failed treatment due to early treatment failure: + n_ETF <- length(successful) - length(treated) + + # Add the number of Early Treatment Failures to the renderer: + renderer$render('n_ETF', n_ETF, timestep) + + # Subset the people who remained susceptible + treated_index <- bitset_at(successful_index, treated) + + # Add the number of successfully treated to the renderer: + renderer$render('successfully_treated', treated_index$size(), timestep) + + # Update the variables for those who have been successfully treated: + if (treated_index$size() > 0) { + variables$state$queue_update('Tr', treated_index) + variables$infectivity$queue_update( + parameters$cd * parameters$drug_rel_c[drugs[treated]], + treated_index + ) + variables$drug$queue_update( + drugs[treated], + treated_index + ) + variables$drug_time$queue_update( + timestep, + treated_index + ) + } + + treated_index +} + +#----- 7b) Updated calculate_treated_AM() function (V1): Testing -------------------------------------- + +##' RENDERER +test_render <- individual::Render$new(timesteps) + +# Make a copy of the renderer: +renderer_original <- test_render$clone() +renderer_updated <- test_render$clone() + +# Check the normal calculate_treated() function works +test_original_version <- calculate_treated(variables = variables, + clinical_infections = clinical_infections, + parameters = simparams, + timestep = current_timestep, + renderer = renderer_original) +# View the rendered dataframe (original) +renderer_original$to_dataframe()[current_timestep,] + +# Test the updated calculate_treated_AM() function: +test_updated_version <- calculate_treated_AM_2(variables = variables, + clinical_infections = clinical_infections, + parameters = simparams, + timestep = current_timestep, + renderer = renderer_updated) + +# View the rendered dataframe (original) +renderer_updated$to_dataframe()[current_timestep,] + +# Compare the output Bitsets: +test_original_version$to_vector(); test_original_version$size() +test_updated_version$to_vector(); test_updated_version$size() + +#----- 7c) Updated calculate_treated_AM() function (V1): Simulation Testing ------------------------ + +# Reset the environment +rm(list = ls()) + +# Set an base parameter list +simparams <- get_parameters() + +# Add AL and DHA_PQP drug parameters to parameter list +simparams <- set_drugs(simparams, list(AL_params, DHA_PQP_params)) + +# Add clinical treatment events using set_clinical_treatment(): +simparams <- set_clinical_treatment(parameters = simparams, drug = 2, + timesteps = c(15, 60, 75), coverages = c(0, 0.2, 0.17)) +simparams <- set_clinical_treatment(parameters = simparams, drug = 1, + timesteps = c(35, 55, 100), coverages = c(0, 0.4, 0.35)) + +# Add resistance using set_antimalarial_resistance() using same order as clinical treatment +simparams <- set_antimalarial_resistance(parameters = simparams, + drug = 2, + timesteps = c(0, 25), + artemisinin_resistance = c(0.3, 0.42), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = rep(0.1, 2), + early_treatment_failure_prob = rep(0.6, 2), + late_clinical_failure_prob = rep(0.1, 2), + late_parasitological_prob = rep(0.1, 2), + reinfection_prob = rep(0.1, 2)) +simparams <- set_antimalarial_resistance(parameters = simparams, + drug = 1, + timesteps = c(0, 50), + artemisinin_resistance = c(0, 0), + partner_drug_resistance = c(0, 0.5), + slow_parasite_clearance_prob = rep(0.05, 2), + early_treatment_failure_prob = rep(0.5, 2), + late_clinical_failure_prob = rep(0.5, 2), + late_parasitological_prob = rep(0.5, 2), + reinfection_prob = rep(0.5, 2)) + +# Run the simulation: +updated_calctreated_test_sim <- run_simulation(timesteps = 150, parameters = simparams) + + +#----- X) Notes ------------------------------------------------------------------------------------ + +##' If we are using a time-series of resistance proportions, we need a method for retrieving the up- +##' to-date proportions given the current time step and dates on which resistance values are updated. +##' For the time-varying deathrate, in create_mortality_process() (mortality_processes.R), the following +##' is used: +##' last_deathrate <- match_timestep(parameters$deathrate_timesteps, timestep) +##' +##' We can use the same method in the following way: +##' +##' latest_resistance <- match_timestep(unlist(parameters$antimalarial_resistance_timesteps), +##' current_timestep) +##' + + + + + + + From da94206be70fc9164bc44cf1c55b5436a2eb728d Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Thu, 13 Jul 2023 18:51:42 +0100 Subject: [PATCH 135/164] removed the extra versions of calculate_treated() from human_infection and removed additional space from set_antimalarial_resistance() in antimalarial_resistance.R --- R/antimalarial_resistance.R | 1 - R/human_infection.R | 108 +++++++++++++++++++++++++++++++----- 2 files changed, 93 insertions(+), 16 deletions(-) diff --git a/R/antimalarial_resistance.R b/R/antimalarial_resistance.R index a888442c..64728fda 100644 --- a/R/antimalarial_resistance.R +++ b/R/antimalarial_resistance.R @@ -39,7 +39,6 @@ set_antimalarial_resistance <- function(parameters, stop("Artemisinin and partner-drug resistance proportions must fall between 0 and 1") } - # Ensure resistance phenotype probabilities bounded between 0 and 1: if(any(slow_parasite_clearance_prob < 0 | slow_parasite_clearance_prob > 1 | early_treatment_failure_prob < 0 | early_treatment_failure_prob > 1 | diff --git a/R/human_infection.R b/R/human_infection.R index 1cb521c4..60e59761 100644 --- a/R/human_infection.R +++ b/R/human_infection.R @@ -253,6 +253,8 @@ update_severe_disease <- function( ) } +#===== Resistance -> Efficacy =====# + #' @title Calculate treated humans #' @description #' Sample treated humans from the clinically infected @@ -262,54 +264,130 @@ update_severe_disease <- function( #' @param timestep the current timestep #' @param renderer simulation renderer #' @noRd + calculate_treated <- function( - variables, - clinical_infections, - parameters, - timestep, - renderer - ) { - treatment_coverages <- get_treatment_coverages(parameters, timestep) + variables, + clinical_infections, + parameters, + timestep, + renderer +) { + + # Gather the treatment coverage(s) in the current timestep: + treatment_coverages <- get_treatment_coverages(simparams, timestep) + + # Sum to get the total treatment coverage in the current time step: ft <- sum(treatment_coverages) + # If total coverage = 0, return an empty Bitset for the treated individuals: if (ft == 0) { - return(individual::Bitset$new(parameters$human_population)) + return(individual::Bitset$new(simparams$human_population)) } + # Add the total treatment coverage to the renderer: renderer$render('ft', ft, timestep) + + # Sample individuals from clinically infected to seek treatment using treatment coverage: seek_treatment <- sample_bitset(clinical_infections, ft) + + # Store the number of people that seek treatment this time step: n_treat <- seek_treatment$size() - + + # Add the number of people seeking treatment in the current time step to the renderer: renderer$render('n_treated', n_treat, timestep) - - drugs <- as.numeric(parameters$clinical_treatment_drugs[ + + # Assign each individual seeking treatment a drug based on their coverage(s): + drugs <- as.numeric(simparams$clinical_treatment_drugs[ sample.int( - length(parameters$clinical_treatment_drugs), + length(simparams$clinical_treatment_drugs), n_treat, prob = treatment_coverages, replace = TRUE ) ]) - successful <- bernoulli_multi_p(parameters$drug_efficacy[drugs]) - treated_index <- bitset_at(seek_treatment, successful) + #+++++ RESISTANCE +++++# - # Update those who have been treated + # Set the resistance drug index (each individuals drug): + AM_drug_index <- as.numeric(simparams$antimalarial_resistance_drug)[drugs] + + # Open vectors to store the proportion of artemisinin resistance to the drug taken by each + # individual and it's probability of manifesting as early treatment failure: + art_resistance <- vector(); etf_prob <- vector() + + # For reach individual seeking treatment, retrieve the resistance and ETF probabilities corresponding + # to the drug they have been administered: + for(i in 1:n_treat) { + + # Identify the correct resistance index: + last_resistance <- match_timestep(ts = simparams$antimalarial_resistance_timesteps[[AM_drug_index[i]]], + t = timestep) + + # Retrieve the resistance value corresponding to the drug and time step: + art_resistance[i] <- simparams$prop_artemisinin_resistant[[AM_drug_index[i]]][last_resistance] + + # Retrieve the ETF phenotype probability corresponding to the drug and time step: + etf_prob[i] <- simparams$early_treatment_failure_prob[[AM_drug_index[i]]][last_resistance] + + } + + # Run bernoulli trials to determine which individuals experience early treatment failure given the + # drug they have been administered: + susceptible <- bernoulli_multi_p(p = 1 - (art_resistance * etf_prob)) + + # Calculate the number of individuals who failed treatment due to early treatment failure: + n_ETF <- n_treat - length(susceptible) + + # Add the number of Early Treatment Failures to the renderer: + renderer$render('n_ETF', n_ETF, timestep) + + # Remove the individuals who failed treatment due to resistance from the drugs vector: + drugs <- drugs[susceptible] + + # Subset the people who remained susceptible + susceptible_index <- bitset_at(seek_treatment, susceptible) + + #+++ DRUG EFFICACY +++# + # Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: + successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs]) + + # Calculate the number of people who failed treatment due to efficacy: + n_treat_eff_fail <- length(susceptible) - length(successful) + + # Add the number of treatment efficacy failures to the renderer: + renderer$render('n_treat_eff_fail', n_treat_eff_fail, timestep) + + # Subset the successfully treated people: + treated_index <- bitset_at(susceptible_index, successful) + + # Add number of successfully treated individuals to the renderer + renderer$render('n_treat_success', treated_index$size(), timestep) + + # Update the variables for those who have been successfully treated: if (treated_index$size() > 0) { + + # Queue update to the infectious state to Tr: variables$state$queue_update('Tr', treated_index) + + # Queue update to the infectivity to reflect their new state (Tr): variables$infectivity$queue_update( parameters$cd * parameters$drug_rel_c[drugs[successful]], treated_index ) + # Queue update to the last drug each successfully treated person received: variables$drug$queue_update( drugs[successful], treated_index ) + # Queue update to the time step on which each successfully treated person last + # received a drug: variables$drug_time$queue_update( timestep, treated_index ) } + + # Return the Bitset of treated individuals: treated_index } From 571a20cdedd1e2a8ea272574def1b343768ce537 Mon Sep 17 00:00:00 2001 From: tbreweric Date: Fri, 14 Jul 2023 11:32:30 +0100 Subject: [PATCH 136/164] removed all but resistance first, efficacy second version of calculate treated as part of improvement in development process --- R/human_infection.R | 1 - 1 file changed, 1 deletion(-) diff --git a/R/human_infection.R b/R/human_infection.R index 60e59761..f3f4d7fd 100644 --- a/R/human_infection.R +++ b/R/human_infection.R @@ -264,7 +264,6 @@ update_severe_disease <- function( #' @param timestep the current timestep #' @param renderer simulation renderer #' @noRd - calculate_treated <- function( variables, clinical_infections, From bfb6aa05afa5fc6d48a99475093f7406d78a0df6 Mon Sep 17 00:00:00 2001 From: tbreweric Date: Fri, 14 Jul 2023 12:11:41 +0100 Subject: [PATCH 137/164] Deleting the development script from the branch (will store development scripts outside of project following advice). --- R/antimalarial_resistance_development.R | 950 ------------------------ 1 file changed, 950 deletions(-) delete mode 100644 R/antimalarial_resistance_development.R diff --git a/R/antimalarial_resistance_development.R b/R/antimalarial_resistance_development.R deleted file mode 100644 index 5e951745..00000000 --- a/R/antimalarial_resistance_development.R +++ /dev/null @@ -1,950 +0,0 @@ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# -#+++++ antimalarial_resistance/etf development script +++++# -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# - -##' README: -##' THis script is designed as a place to develop and store the changes being implemented into the -##' malariasimulation package in support of integrating antimalarial resistance. This file is -##' designed to be deleted prior to any merge and is purely for development purposes. - -##' CURENTLY WORKING ON: amending the calculate_treated() function to update -##' -##' -##' Use Ctrl + Shft + C to comment everything in/out for load_all() to work - -#----- 1) Preamble --------------------------------------------------------------------------------- - -# Load in the individual package: -library(individual) -library(devtools) - -# Load the malariasimualtion functions (make sure this script is commented out when you run this) -devtools::load_all(".") - -#----- 2) Original calculate_treated() function ---------------------------------------------------- - -##' This is the original calculate_treated() function, renamed to avoid any conflicts. -calculate_treated <- function( - variables, - clinical_infections, - parameters, - timestep, - renderer -) { - - # Gather the treatment coverage(s) in the current timestep: - treatment_coverages <- get_treatment_coverages(parameters, timestep) - - # Sum to get the total treatment coverage in the current time step: - ft <- sum(treatment_coverages) - - # If treatment = 0, return an empty Bitset for the treated individuals: - if (ft == 0) { - return(individual::Bitset$new(parameters$human_population)) - } - - # Add the total treatment coverage to the renderer: - renderer$render('ft', ft, timestep) - - # Sample individuals from clinically infected to seek treatment using treatment coverage: - seek_treatment <- sample_bitset(clinical_infections, ft) - - # Store the number of people that seek treatment this time step: - n_treat <- seek_treatment$size() - - # Add the number of people seeking treatment in the current time step to the renderer: - renderer$render('n_treated', n_treat, timestep) - - # Assign each individual seeking treatment a drug based on their coverage(s): - drugs <- as.numeric(parameters$clinical_treatment_drugs[ - sample.int( - length(parameters$clinical_treatment_drugs), - n_treat, - prob = treatment_coverages, - replace = TRUE - ) - ]) - - # Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: - successful <- bernoulli_multi_p(parameters$drug_efficacy[drugs]) - - # Subset the successfully treated people: - treated_index <- bitset_at(seek_treatment, successful) - - # For those people who have been successfully treated: - if (treated_index$size() > 0) { - - # Queue update to the infectious state to Tr: - variables$state$queue_update('Tr', treated_index) - - # Queue update to the infectivity to reflect their new state (Tr): - variables$infectivity$queue_update( - parameters$cd * parameters$drug_rel_c[drugs[successful]], - treated_index - ) - # Queue update to the last drug each successfully treated person received: - variables$drug$queue_update( - drugs[successful], - treated_index - ) - # Queue update to the time step on which each successfully treated person last - # received a drug: - variables$drug_time$queue_update( - timestep, - treated_index - ) - } - - # Return the Bitset of treated individuals: - treated_index -} - -#----- 3) Function Development Set-up -------------------------------------------------------------- - -# Set an base parameter list -simparams <- get_parameters() - -# Add AL and DHA_PQP drug parameters to parameter list -simparams <- set_drugs(simparams, list(AL_params, DHA_PQP_params)) - -# Add clinical treatment events using set_clinical_treatment(): -simparams <- set_clinical_treatment(parameters = simparams, drug = 2, - timesteps = 5, coverages = 0.2) -simparams <- set_clinical_treatment(parameters = simparams, drug = 1, - timesteps = 10, coverages = 0.4) - -# Check the clinical treatment order and coverages: -simparams$clinical_treatment_drugs -simparams$clinical_treatment_coverages - -##' AL is drug 1, used second clinically at a coverage of 0.4 -##' DHA-PQP is drug 2, used first clinically at a coverage of 0.2 - -# Add resistance using set_antimalarial_resistance() using same order as clinical treatment -simparams <- set_antimalarial_resistance(parameters = simparams, - drug = 2, - timesteps = c(0, 25), - artemisinin_resistance = c(0.3, 0.42), - partner_drug_resistance = c(0, 0), - slow_parasite_clearance_prob = rep(0.1, 2), - early_treatment_failure_prob = rep(0.6, 2), - late_clinical_failure_prob = rep(0.1, 2), - late_parasitological_prob = rep(0.1, 2), - reinfection_prob = rep(0.1, 2)) -simparams <- set_antimalarial_resistance(parameters = simparams, - drug = 1, - timesteps = c(0, 50), - artemisinin_resistance = c(0, 0), - partner_drug_resistance = c(0, 0.5), - slow_parasite_clearance_prob = rep(0.05, 2), - early_treatment_failure_prob = rep(0.5, 2), - late_clinical_failure_prob = rep(0.5, 2), - late_parasitological_prob = rep(0.5, 2), - reinfection_prob = rep(0.5, 2)) - -# Check the resistance parameters: -simparams$antimalarial_resistance_drug -simparams$antimalarial_resistance_timesteps -simparams$prop_artemisinin_resistant; simparams$prop_partner_drug_resistant -simparams$early_treatment_failure_prob; simparams$slow_parasite_clearance_prob -simparams$late_clinical_failure_prob; simparams$late_parasitological_failure_prob; simparams$reinfection_during_prophylaxis - -# Set up the model variables: -variables <- create_variables(parameters = simparams) - -# Establish Bitset of the human population -current_pop <- Bitset$new(simparams$human_population, from = NULL) -current_pop$insert(1:simparams$human_population); current_pop$to_vector() - -# Subset a group of clinically infected individuals from the population -clinical_infections <- sample_bitset(b = current_pop, rate = 0.4) -clinical_infections$to_vector(); clinical_infections$size() - -##' TIMESTEP -timesteps <- 100 -current_timestep <- 50 - -##' RENDERER -renderer <- individual::Render$new(timesteps) -renderer$to_dataframe() - -#----- 4) Individual Steps (Original) -------------------------------------------------------------- - -# Gather the treatment coverage(s) in the current timestep: -treatment_coverages <- get_treatment_coverages(simparams, current_timestep) - -# Sum to get the total treatment coverage in the current time step: -ft <- sum(treatment_coverages) - -# If treatment = 0, return an empty Bitset for the treated individuals: -if (ft == 0) { - return(individual::Bitset$new(simparams$human_population)) -} else { - print("OK") -} - -# Add the total treatment coverage to the renderer: -renderer$render('ft', ft, current_timestep) -renderer$to_dataframe()[current_timestep,] - -# Sample individuals from clinically infected to seek treatment using treatment coverage: -seek_treatment <- sample_bitset(clinical_infections, ft) -seek_treatment$to_vector(); seek_treatment$size() - -# Store the number of people that seek treatment this time step: -n_treat <- seek_treatment$size(); n_treat - -# Add the number of people seeking treatment in the current time step to the renderer: -renderer$render('n_treated', n_treat, current_timestep) -renderer$to_dataframe()[current_timestep,] - -# Assign each individual seeking treatment a drug based on their coverage(s): -drugs <- as.numeric(simparams$clinical_treatment_drugs[ - sample.int( - length(simparams$clinical_treatment_drugs), - n_treat, - prob = treatment_coverages, - replace = TRUE - ) -]) -drugs; length(drugs) == n_treat - -# Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: -successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs]) -successful; length(successful); (length(successful)/length(drugs))*100 - -# Subset the successfully treated people: -treated_index <- bitset_at(seek_treatment, successful) -treated_index$to_vector(); treated_index$size() - - -# # For those people who have been successfully treated: -# if (treated_index$size() > 0) { -# -# # Queue update to the infectious state to Tr: -# variables$state$queue_update('Tr', treated_index) -# -# # Queue update to the infectivity to reflect their new state (Tr): -# variables$infectivity$queue_update( -# parameters$cd * parameters$drug_rel_c[drugs[successful]], -# treated_index -# ) -# # Queue update to the last drug each successfully treated person received: -# variables$drug$queue_update( -# drugs[successful], -# treated_index -# ) -# # Queue update to the time step on which each successfully treated person last -# # received a drug: -# variables$drug_time$queue_update( -# timestep, -# treated_index -# ) -# } - -# Return the Bitset of treated individuals: -treated_index - -#----- 5a) Individual Steps (Updated) Resistance First --------------------------------------------- - -# Gather the treatment coverage(s) in the current timestep: -treatment_coverages <- get_treatment_coverages(simparams, current_timestep); treatment_coverages - -# Sum to get the total treatment coverage in the current time step: -ft <- sum(treatment_coverages); ft - -# If treatment = 0, return an empty Bitset for the treated individuals: -if (ft == 0) { - return(individual::Bitset$new(simparams$human_population)) -} else { - print("OK") -} - -# Add the total treatment coverage to the renderer: -renderer$render('ft', ft, current_timestep) -renderer$to_dataframe()[current_timestep,] - -# Sample individuals from clinically infected to seek treatment using treatment coverage: -seek_treatment <- sample_bitset(clinical_infections, ft) -seek_treatment$to_vector(); seek_treatment$size() -paste0(((seek_treatment$size()/clinical_infections$size())*100), - "% of clinically infected individuals sought treatment") - -# Store the number of people that seek treatment this time step: -n_treat <- seek_treatment$size(); n_treat - -# Add the number of people seeking treatment in the current time step to the renderer: -renderer$render('n_treated', n_treat, current_timestep) -renderer$to_dataframe()[current_timestep,] - -# Assign each individual seeking treatment a drug based on their coverage(s): -drugs <- as.numeric(simparams$clinical_treatment_drugs[ - sample.int( - length(simparams$clinical_treatment_drugs), - n_treat, - prob = treatment_coverages, - replace = TRUE - ) -]); drugs; length(drugs) == n_treat; table(drugs) - -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# -#+++++ RESISTANCE - -# Set the resistance drug index (each individuals drug): -AM_drug_index <- as.numeric(simparams$antimalarial_resistance_drug[drugs]) -drugs; AM_drug_index - -# Generate a vector containing the proportion of artemisinin resistance to the drug taken by each -# individual and it's probability of manifesting as early treatment failure: -art_resistance <- vector(); etf_prob <- vector() -for(i in 1:n_treat) { - - # Identify the correct resistance index: - last_resistance <- match_timestep(ts = simparams$antimalarial_resistance_timesteps[[AM_drug_index[i]]], - t = current_timestep) - - # Retrieve the resistance value corresponding to the drug and time step: - art_resistance[i] <- simparams$prop_artemisinin_resistant[[AM_drug_index[i]]][last_resistance] - - # Retrieve the ETF phenotype probability corresponding to the drug and time step: - etf_prob[i] <- simparams$early_treatment_failure_prob[[AM_drug_index[i]]][last_resistance] - -} -drugs; art_resistance; etf_prob - -# The probability that an individual fails is the product of the proportion of individuals with resistance -# to the drug they've taken and the probability that early treatment failure manifests in cases of resistance -# to that drug. The probability individuals are treated successfully is therefore 1 - this product. - -# Run bernoulli trials to determine which individuals fail treatment due to resistance to the drug -# they have taken: -susceptible <- bernoulli_multi_p(p = 1 - (art_resistance * etf_prob)) -length(susceptible); (length(susceptible)/n_treat)*100 - -##' Drug 1 is AL and Drug 2 is DHA-PQP. Drug 2 is set first in clinical treatment and resistance. -##' The proportion of individuals in the current timestep with artemisinin resistance to drug 1 is -##' 0, while the proportion of the population with artemisinin resistance to drug 2 is 0.42. The prob. -##' of early treatment failure for Drug 1 is 0.5, and is 0.6 for Drug 2. - -# Calculate the number of individuals who failed treatment due to early treatment failure: -n_ETF <- n_treat - length(susceptible) - -# Add the number of Early Treatment Failures to the renderer: -renderer$render('n_ETF', n_ETF, current_timestep) -renderer$to_dataframe()[current_timestep,] - -# Remove the individuals who failed treatment due to resistance from the drugs vector: -drugs[susceptible]; length(drugs[susceptible]); (length(drugs[susceptible])/n_treat)*100 -drugs_2 <- drugs[susceptible] - -# Check which individuals failed and which drug they took (only modelled resistance to drug 2) -res_fail_individuals <- which(!((1:n_treat) %in% susceptible)) -drugs[res_fail_individuals]; table(drugs); table(drugs_2) -drugs; drugs_2 - -# Subset the people who remained susceptible -seek_treatment$to_vector(); seek_treatment$size() -susceptible_index <- bitset_at(seek_treatment, susceptible) -susceptible_index$to_vector(); susceptible_index$size() - -# So, we should now have a slightly shorter vector of drugs taken by each individual to account for -# the individuals who gave failed treatment due to resistance. We can then use this to work out who -# is successfully treated given the drug efficacy. - -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# -#+++++ DRUG EFFICACY -# Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: -successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs_2]) -successful; length(successful); (length(successful)/length(drugs_2))*100 - -# Calculate the number of people who failed treatment due to efficacy: -n_treat_eff_fail <- length(susceptible) - length(successful) - -# Add the number of treatment efficacy failures to the renderer: -renderer$render('n_treat_eff_fail', n_treat_eff_fail, current_timestep) -renderer$to_dataframe()[current_timestep,] - -# Subset the successfully treated people: -treated_index <- bitset_at(susceptible_index, successful) -treated_index$to_vector(); treated_index$size() - -# Compare the three bitsets: -seek_treatment$to_vector(); seek_treatment$size() -susceptible_index$to_vector(); susceptible_index$size() -treated_index$to_vector(); treated_index$size() - -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# - -# # For those people who have been successfully treated: -# if (treated_index$size() > 0) { -# -# # Queue update to the infectious state to Tr: -# variables$state$queue_update('Tr', treated_index) -# -# # Queue update to the infectivity to reflect their new state (Tr): -# variables$infectivity$queue_update( -# parameters$cd * parameters$drug_rel_c[drugs[successful]], -# treated_index -# ) -# # Queue update to the last drug each successfully treated person received: -# variables$drug$queue_update( -# drugs[successful], -# treated_index -# ) -# # Queue update to the time step on which each successfully treated person last -# # received a drug: -# variables$drug_time$queue_update( -# timestep, -# treated_index -# ) -# } - -# Return the Bitset of treated individuals: -treated_index - -#----- 5b) Individual Steps (Updated) Resistance Last ---------------------------------------------- - -# Retrieve the treatment coverages for the current time step: -treatment_coverages <- get_treatment_coverages(simparams, current_timestep); treatment_coverages - -# Calculate the total treatment coverage for the current time step: -ft <- sum(treatment_coverages); ft - -# If there is no treatment coverage, return an empty Bitset: -if (ft == 0) { - return(individual::Bitset$new(simparams$human_population)) -} - -# Store the total coverage in the current time step in the renderer: -renderer$render('ft', ft, current_timestep) -renderer$to_dataframe()[current_timestep,] - -# Use total coverage to sample people from the clinically infected who will seek treatment: -seek_treatment <- sample_bitset(clinical_infections, ft) -seek_treatment$to_vector(); seek_treatment$size() - -# Store the number of people seeking treatment in the current time step: -n_treat <- seek_treatment$size() - -# Add the number of people seeking treatment to the renderer: -renderer$render('n_treated', n_treat, current_timestep) -renderer$to_dataframe()[current_timestep,] - -# Assign each individual seeking treatment a drug based on relative coverages: -drugs <- as.numeric(simparams$clinical_treatment_drugs[ - sample.int( - length(simparams$clinical_treatment_drugs), - n_treat, - prob = treatment_coverages, - replace = TRUE - ) -]) -length(drugs) == n_treat; table(drugs) - -#+++++ DRUG EFFICACY +++++# - -# Determine the people who were successfully treated using bernoulli trials: -successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs]); successful -length(successful) - -# Subset out the successfully treated individuals: -successful_index <- bitset_at(seek_treatment, successful) -successful_index$to_vector(); successful_index$size() - -# Calculate the number of people who failed treatment due to efficacy: -n_treat_eff_fail <- n_treat - successful_index$size() -n_treat; length(successful); n_treat_eff_fail - -# Add the number of treatment efficacy failures to the renderer: -renderer$render('n_treat_eff_fail', n_treat_eff_fail, current_timestep) -renderer$to_dataframe()[current_timestep,] - -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++# -#+++++ RESISTANCE - -# Subset out the drugs received by the people who's treatment didnt fail due to efficacy: -drugs <- drugs[successful] - -# Set the resistance drug index (each individuals drug): -AM_drug_index <- as.numeric(simparams$antimalarial_resistance_drug[drugs]) -drugs; AM_drug_index - -# Generate a vector containing the proportion of artemisinin resistance to the drug taken by each -# individual and it's probability of manifesting as early treatment failure: -art_resistance <- vector(); etf_prob <- vector() -for(i in 1:length(successful)) { - - # Identify the correct resistance index: - last_resistance <- match_timestep(ts = simparams$antimalarial_resistance_timesteps[[AM_drug_index[i]]], - t = current_timestep) - - # Retrieve the resistance value corresponding to the drug and time step: - art_resistance[i] <- simparams$prop_artemisinin_resistant[[AM_drug_index[i]]][last_resistance] - - # Retrieve the ETF phenotype probability corresponding to the drug and time step: - etf_prob[i] <- simparams$early_treatment_failure_prob[[AM_drug_index[i]]][last_resistance] - -} -drugs; art_resistance; etf_prob -length(drugs); length(art_resistance); length(etf_prob) - -# Run bernoulli trials to determine which individuals experience ETF: -treated <- bernoulli_multi_p(p = 1 - (art_resistance * etf_prob)) -length(treated); (length(treated)/length(successful))*100 - -# Calculate the number of individuals who failed treatment due to early treatment failure: -n_ETF <- length(successful) - length(treated) - -# Add the number of Early Treatment Failures to the renderer: -renderer$render('n_ETF', n_ETF, current_timestep) -renderer$to_dataframe()[current_timestep,] - -# Subset the people who remained susceptible -successful_index$to_vector(); successful_index$size() -treated_index <- bitset_at(successful_index, treated) -treated_index$to_vector(); treated_index$size() - -# Can visually check which individual failed treatment due to ETF -seek_treatment$to_vector(); successful_index$to_vector(); treated_index$to_vector() - -# Update the variables for those who have been successfully treated: -if (treated_index$size() > 0) { - variables$state$queue_update('Tr', treated_index) - variables$infectivity$queue_update( - simparams$cd * simparams$drug_rel_c[drugs[treated]], - treated_index - ) - variables$drug$queue_update( - drugs[treated], - treated_index - ) - variables$drug_time$queue_update( - timestep, - treated_index - ) -} - -treated_index - -#----- 6a) Updated calculate_treated() function (V1): Resistance -> Efficacy ----------------------- - -calculate_treated_AM <- function( - variables, - clinical_infections, - parameters, - timestep, - renderer -) { - - # Gather the treatment coverage(s) in the current timestep: - treatment_coverages <- get_treatment_coverages(simparams, timestep) - - # Sum to get the total treatment coverage in the current time step: - ft <- sum(treatment_coverages) - - # If treatment = 0, return an empty Bitset for the treated individuals: - if (ft == 0) { - return(individual::Bitset$new(simparams$human_population)) - } - - # Add the total treatment coverage to the renderer: - renderer$render('ft', ft, timestep) - - # Sample individuals from clinically infected to seek treatment using treatment coverage: - seek_treatment <- sample_bitset(clinical_infections, ft) - - # Store the number of people that seek treatment this time step: - n_treat <- seek_treatment$size() - - # Add the number of people seeking treatment in the current time step to the renderer: - renderer$render('n_treated', n_treat, timestep) - - # Assign each individual seeking treatment a drug based on their coverage(s): - drugs <- as.numeric(simparams$clinical_treatment_drugs[ - sample.int( - length(simparams$clinical_treatment_drugs), - n_treat, - prob = treatment_coverages, - replace = TRUE - ) - ]) - - #+++ ANTIMALARIAL RESISTANCE +++# - - # Set the resistance drug index (each individuals drug): - AM_drug_index <- as.numeric(simparams$antimalarial_resistance_drug[drugs]) - - # Open vectors to store the proportion of artemisinin resistance to the drug taken by each - # individual and it's probability of manifesting as early treatment failure: - art_resistance <- vector(); etf_prob <- vector() - - # For reach individual seeking treatment, retrieve the resistance and ETF probabilities corresponding - # to the drug they have been administered: - for(i in 1:n_treat) { - - # Identify the correct resistance index: - last_resistance <- match_timestep(ts = simparams$antimalarial_resistance_timesteps[[AM_drug_index[i]]], - t = timestep) - - # Retrieve the resistance value corresponding to the drug and time step: - art_resistance[i] <- simparams$prop_artemisinin_resistant[[AM_drug_index[i]]][last_resistance] - - # Retrieve the ETF phenotype probability corresponding to the drug and time step: - etf_prob[i] <- simparams$early_treatment_failure_prob[[AM_drug_index[i]]][last_resistance] - - } - - # Run bernoulli trials to determine which individuals experience early treatment failure given the - # drug they have been administered: - susceptible <- bernoulli_multi_p(p = 1 - (art_resistance * etf_prob)) - - # Calculate the number of individuals who failed treatment due to early treatment failure: - n_ETF <- n_treat - length(susceptible) - - # Add the number of Early Treatment Failures to the renderer: - renderer$render('n_ETF', n_ETF, timestep) - - # Remove the individuals who failed treatment due to resistance from the drugs vector: - drugs <- drugs[susceptible] - - # Subset the people who remained susceptible - susceptible_index <- bitset_at(seek_treatment, susceptible) - - #+++ DRUG EFFICACY +++# - # Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: - successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs]) - - # Calculate the number of people who failed treatment due to efficacy: - n_treat_eff_fail <- length(susceptible) - length(successful) - - # Add the number of treatment efficacy failures to the renderer: - renderer$render('n_treat_eff_fail', n_treat_eff_fail, timestep) - - # Subset the successfully treated people: - treated_index <- bitset_at(susceptible_index, successful) - - # Add number of successfully treated individuals to the renderer - renderer$render('n_treat_success', treated_index$size(), timestep) - - # For those people who have been successfully treated: - if (treated_index$size() > 0) { - - # Queue update to the infectious state to Tr: - variables$state$queue_update('Tr', treated_index) - - # Queue update to the infectivity to reflect their new state (Tr): - variables$infectivity$queue_update( - parameters$cd * parameters$drug_rel_c[drugs[successful]], - treated_index - ) - # Queue update to the last drug each successfully treated person received: - variables$drug$queue_update( - drugs[successful], - treated_index - ) - # Queue update to the time step on which each successfully treated person last - # received a drug: - variables$drug_time$queue_update( - timestep, - treated_index - ) - } - - # Return the Bitset of treated individuals: - treated_index -} - -#----- 6b) Updated calculate_treated_AM() function (V1): Testing -------------------------------------- - -##' RENDERER -test_render <- individual::Render$new(timesteps) - -# Make a copy of the renderer: -renderer_original <- test_render$clone() -renderer_updated <- test_render$clone() - -# Check the normal calculate_treated() function works -test_original_version <- calculate_treated(variables = variables, - clinical_infections = clinical_infections, - parameters = simparams, - timestep = current_timestep, - renderer = renderer_original) -# View the rendered dataframe (original) -renderer_original$to_dataframe()[current_timestep,] - -# Test the updated calculate_treated_AM() function: -test_updated_version <- calculate_treated_AM(variables = variables, - clinical_infections = clinical_infections, - parameters = simparams, - timestep = current_timestep, - renderer = renderer_updated) - -# View the rendered dataframe (original) -renderer_updated$to_dataframe()[current_timestep,] - -# Compare the output Bitsets: -test_original_version$to_vector(); test_original_version$size() -test_updated_version$to_vector(); test_updated_version$size() - -#----- 6c) Updated calculate_treated_AM() function (V1): Simulation Testing ------------------------ - -# Reset the environment -rm(list = ls()) - -# Set an base parameter list -simparams <- get_parameters() - -# Add AL and DHA_PQP drug parameters to parameter list -simparams <- set_drugs(simparams, list(AL_params, DHA_PQP_params)) - -# Add clinical treatment events using set_clinical_treatment(): -simparams <- set_clinical_treatment(parameters = simparams, drug = 2, - timesteps = c(15, 60, 75), coverages = c(0, 0.2, 0.17)) -simparams <- set_clinical_treatment(parameters = simparams, drug = 1, - timesteps = c(35, 55, 100), coverages = c(0, 0.4, 0.35)) - -# Add resistance using set_antimalarial_resistance() using same order as clinical treatment -simparams <- set_antimalarial_resistance(parameters = simparams, - drug = 2, - timesteps = c(0, 25), - artemisinin_resistance = c(0.3, 0.42), - partner_drug_resistance = c(0, 0), - slow_parasite_clearance_prob = rep(0.1, 2), - early_treatment_failure_prob = rep(0.6, 2), - late_clinical_failure_prob = rep(0.1, 2), - late_parasitological_prob = rep(0.1, 2), - reinfection_prob = rep(0.1, 2)) -simparams <- set_antimalarial_resistance(parameters = simparams, - drug = 1, - timesteps = c(0, 50), - artemisinin_resistance = c(0, 0), - partner_drug_resistance = c(0, 0.5), - slow_parasite_clearance_prob = rep(0.05, 2), - early_treatment_failure_prob = rep(0.5, 2), - late_clinical_failure_prob = rep(0.5, 2), - late_parasitological_prob = rep(0.5, 2), - reinfection_prob = rep(0.5, 2)) - -# Run the simulation: -updated_calctreated_test_sim <- run_simulation(timesteps = 10, parameters = simparams) -updated_calctreated_test_sim <- run_simulation(timesteps = 15, parameters = simparams) -updated_calctreated_test_sim <- run_simulation(timesteps = 35, parameters = simparams) -updated_calctreated_test_sim <- run_simulation(timesteps = 56, parameters = simparams) - - -# View the output -updated_calctreated_test_sim - -#----- 7a) Updated calculate_treated() function (V1): Efficacy -> Resistance ----------------------- - -# Version of updated calculate_treated() function with drug efficacy and then resistance: -calculate_treated_AM_2 <- function( - variables, - clinical_infections, - parameters, - timestep, - renderer -) { - - # Retrieve the treatment coverages for the current time step: - treatment_coverages <- get_treatment_coverages(parameters, timestep) - - # Calculate the total treatment coverage for the current time step: - ft <- sum(treatment_coverages) - - # If there is no treatment coverage, return an empty Bitset: - if (ft == 0) { - return(individual::Bitset$new(parameters$human_population)) - } - - # Store the total coverage in the current time step in the renderer: - renderer$render('ft', ft, timestep) - - # Use total coverage to sample people from the clinically infected who will seek treatment: - seek_treatment <- sample_bitset(clinical_infections, ft) - - # Store the number of people seeking treatment in the current time step: - n_treat <- seek_treatment$size() - - # Add the number of people seeking treatment to the renderer: - renderer$render('n_treated', n_treat, timestep) - - # Assign each individual seeking treatment a drug based on relative coverages: - drugs <- as.numeric(parameters$clinical_treatment_drugs[ - sample.int( - length(parameters$clinical_treatment_drugs), - n_treat, - prob = treatment_coverages, - replace = TRUE - ) - ]) - - #+++++ DRUG EFFICACY +++++# - - # Determine the people who were successfully treated using bernoulli trials: - successful <- bernoulli_multi_p(parameters$drug_efficacy[drugs]) - - # Subset out the successfully treated individuals: - successful_index <- bitset_at(seek_treatment, successful) - - # Calculate the number of people who failed treatment due to efficacy: - n_treat_eff_fail <- n_treat - successful_index$size() - - # Add the number of treatment efficacy failures to the renderer: - renderer$render('n_treat_eff_fail', n_treat_eff_fail, timestep) - - #+++++ RESISTANCE +++++# - - # Subset out the drugs received by the people who's treatment didnt fail due to efficacy: - drugs <- drugs[successful] - - # Set the resistance drug index (each individuals drug): - AM_drug_index <- as.numeric(parameters$antimalarial_resistance_drug[drugs]) - - # Generate a vector containing the prop. artemisinin resistance to each drug for each - # individual and the prob. of experiencing as early treatment failure: - art_resistance <- vector(); etf_prob <- vector() - for(i in 1:length(successful)) { - - # Identify the correct resistance index: - last_resistance <- match_timestep(ts = parameters$antimalarial_resistance_timesteps[[AM_drug_index[i]]], - t = timestep) - - # Retrieve the resistance value corresponding to the drug and time step: - art_resistance[i] <- parameters$prop_artemisinin_resistant[[AM_drug_index[i]]][last_resistance] - - # Retrieve the ETF phenotype probability corresponding to the drug and time step: - etf_prob[i] <- parameters$early_treatment_failure_prob[[AM_drug_index[i]]][last_resistance] - - } - - # Run bernoulli trials to determine which individuals experience ETF: - treated <- bernoulli_multi_p(p = 1 - (art_resistance * etf_prob)) - - # Calculate the number of individuals who failed treatment due to early treatment failure: - n_ETF <- length(successful) - length(treated) - - # Add the number of Early Treatment Failures to the renderer: - renderer$render('n_ETF', n_ETF, timestep) - - # Subset the people who remained susceptible - treated_index <- bitset_at(successful_index, treated) - - # Add the number of successfully treated to the renderer: - renderer$render('successfully_treated', treated_index$size(), timestep) - - # Update the variables for those who have been successfully treated: - if (treated_index$size() > 0) { - variables$state$queue_update('Tr', treated_index) - variables$infectivity$queue_update( - parameters$cd * parameters$drug_rel_c[drugs[treated]], - treated_index - ) - variables$drug$queue_update( - drugs[treated], - treated_index - ) - variables$drug_time$queue_update( - timestep, - treated_index - ) - } - - treated_index -} - -#----- 7b) Updated calculate_treated_AM() function (V1): Testing -------------------------------------- - -##' RENDERER -test_render <- individual::Render$new(timesteps) - -# Make a copy of the renderer: -renderer_original <- test_render$clone() -renderer_updated <- test_render$clone() - -# Check the normal calculate_treated() function works -test_original_version <- calculate_treated(variables = variables, - clinical_infections = clinical_infections, - parameters = simparams, - timestep = current_timestep, - renderer = renderer_original) -# View the rendered dataframe (original) -renderer_original$to_dataframe()[current_timestep,] - -# Test the updated calculate_treated_AM() function: -test_updated_version <- calculate_treated_AM_2(variables = variables, - clinical_infections = clinical_infections, - parameters = simparams, - timestep = current_timestep, - renderer = renderer_updated) - -# View the rendered dataframe (original) -renderer_updated$to_dataframe()[current_timestep,] - -# Compare the output Bitsets: -test_original_version$to_vector(); test_original_version$size() -test_updated_version$to_vector(); test_updated_version$size() - -#----- 7c) Updated calculate_treated_AM() function (V1): Simulation Testing ------------------------ - -# Reset the environment -rm(list = ls()) - -# Set an base parameter list -simparams <- get_parameters() - -# Add AL and DHA_PQP drug parameters to parameter list -simparams <- set_drugs(simparams, list(AL_params, DHA_PQP_params)) - -# Add clinical treatment events using set_clinical_treatment(): -simparams <- set_clinical_treatment(parameters = simparams, drug = 2, - timesteps = c(15, 60, 75), coverages = c(0, 0.2, 0.17)) -simparams <- set_clinical_treatment(parameters = simparams, drug = 1, - timesteps = c(35, 55, 100), coverages = c(0, 0.4, 0.35)) - -# Add resistance using set_antimalarial_resistance() using same order as clinical treatment -simparams <- set_antimalarial_resistance(parameters = simparams, - drug = 2, - timesteps = c(0, 25), - artemisinin_resistance = c(0.3, 0.42), - partner_drug_resistance = c(0, 0), - slow_parasite_clearance_prob = rep(0.1, 2), - early_treatment_failure_prob = rep(0.6, 2), - late_clinical_failure_prob = rep(0.1, 2), - late_parasitological_prob = rep(0.1, 2), - reinfection_prob = rep(0.1, 2)) -simparams <- set_antimalarial_resistance(parameters = simparams, - drug = 1, - timesteps = c(0, 50), - artemisinin_resistance = c(0, 0), - partner_drug_resistance = c(0, 0.5), - slow_parasite_clearance_prob = rep(0.05, 2), - early_treatment_failure_prob = rep(0.5, 2), - late_clinical_failure_prob = rep(0.5, 2), - late_parasitological_prob = rep(0.5, 2), - reinfection_prob = rep(0.5, 2)) - -# Run the simulation: -updated_calctreated_test_sim <- run_simulation(timesteps = 150, parameters = simparams) - - -#----- X) Notes ------------------------------------------------------------------------------------ - -##' If we are using a time-series of resistance proportions, we need a method for retrieving the up- -##' to-date proportions given the current time step and dates on which resistance values are updated. -##' For the time-varying deathrate, in create_mortality_process() (mortality_processes.R), the following -##' is used: -##' last_deathrate <- match_timestep(parameters$deathrate_timesteps, timestep) -##' -##' We can use the same method in the following way: -##' -##' latest_resistance <- match_timestep(unlist(parameters$antimalarial_resistance_timesteps), -##' current_timestep) -##' - - - - - - - From 02e49162a883af96ca1b6d62ee18939fcf5efe1b Mon Sep 17 00:00:00 2001 From: tbreweric Date: Mon, 17 Jul 2023 15:52:38 +0100 Subject: [PATCH 138/164] Amended the calculate_treated() function to remove the loop when assigning the resistance parameters and use a vectorised method. Fixed a typo in the set_antimalarial_resistance() function documentation --- R/antimalarial_resistance.R | 2 +- R/human_infection.R | 149 ++++++++++++++++++------------------ 2 files changed, 77 insertions(+), 74 deletions(-) diff --git a/R/antimalarial_resistance.R b/R/antimalarial_resistance.R index 64728fda..b13ab0de 100644 --- a/R/antimalarial_resistance.R +++ b/R/antimalarial_resistance.R @@ -2,7 +2,7 @@ #' #' @param parameters the model parameters #' @param drug the index of the drug which resistance is being set for in the parameter list -#' @param timesteps vector of timesteps for each update to resistance proportion and/or phenotype probability +#' @param timesteps vector of time steps for each update to resistance proportion and/or phenotype probability #' @param artemisinin_resistance vector of updates to the proportions of infections that are artemisinin resistant at time t #' @param partner_drug_resistance vector of updates to the proportions of infections that are partner-drug resistant at time t #' @param slow_parasite_clearance_prob vector of updates to the proportion of artemisinin-resistant infections that result in early treatment failure diff --git a/R/human_infection.R b/R/human_infection.R index f3f4d7fd..5967ec08 100644 --- a/R/human_infection.R +++ b/R/human_infection.R @@ -253,7 +253,7 @@ update_severe_disease <- function( ) } -#===== Resistance -> Efficacy =====# +#===== Resistance -> Efficacy =====================================================================# #' @title Calculate treated humans #' @description @@ -271,125 +271,128 @@ calculate_treated <- function( timestep, renderer ) { - - # Gather the treatment coverage(s) in the current timestep: - treatment_coverages <- get_treatment_coverages(simparams, timestep) - + + # Gather the treatment coverage(s) in the current time step: + treatment_coverages <- get_treatment_coverages(parameters, timestep) + # Sum to get the total treatment coverage in the current time step: ft <- sum(treatment_coverages) - + # If total coverage = 0, return an empty Bitset for the treated individuals: if (ft == 0) { - return(individual::Bitset$new(simparams$human_population)) + return(individual::Bitset$new(parameters$human_population)) } - + # Add the total treatment coverage to the renderer: renderer$render('ft', ft, timestep) - + # Sample individuals from clinically infected to seek treatment using treatment coverage: seek_treatment <- sample_bitset(clinical_infections, ft) - + # Store the number of people that seek treatment this time step: n_treat <- seek_treatment$size() - + # Add the number of people seeking treatment in the current time step to the renderer: renderer$render('n_treated', n_treat, timestep) - + # Assign each individual seeking treatment a drug based on their coverage(s): - drugs <- as.numeric(simparams$clinical_treatment_drugs[ + drugs <- as.numeric(parameters$clinical_treatment_drugs[ sample.int( - length(simparams$clinical_treatment_drugs), + length(parameters$clinical_treatment_drugs), n_treat, prob = treatment_coverages, replace = TRUE ) ]) - + #+++++ RESISTANCE +++++# - - # Set the resistance drug index (each individuals drug): - AM_drug_index <- as.numeric(simparams$antimalarial_resistance_drug)[drugs] - - # Open vectors to store the proportion of artemisinin resistance to the drug taken by each - # individual and it's probability of manifesting as early treatment failure: - art_resistance <- vector(); etf_prob <- vector() - - # For reach individual seeking treatment, retrieve the resistance and ETF probabilities corresponding - # to the drug they have been administered: - for(i in 1:n_treat) { - - # Identify the correct resistance index: - last_resistance <- match_timestep(ts = simparams$antimalarial_resistance_timesteps[[AM_drug_index[i]]], - t = timestep) - - # Retrieve the resistance value corresponding to the drug and time step: - art_resistance[i] <- simparams$prop_artemisinin_resistant[[AM_drug_index[i]]][last_resistance] - - # Retrieve the ETF phenotype probability corresponding to the drug and time step: - etf_prob[i] <- simparams$early_treatment_failure_prob[[AM_drug_index[i]]][last_resistance] - - } - - # Run bernoulli trials to determine which individuals experience early treatment failure given the - # drug they have been administered: - susceptible <- bernoulli_multi_p(p = 1 - (art_resistance * etf_prob)) - + + # Retrieve the index of the drug administered for each individual in the resistance parameters: + antimalarial_resistance_drug_index <- as.numeric(parameters$antimalarial_resistance_drug)[drugs] + + # Open vectors to store artemisinin resistance and early treatment probability parameters for each + # individual: + artemisinin_resistance_proportion <- vector() + early_treatment_failure_probability <- vector() + + # Work out which drug indices belong to each drug + drug_1_indices <- which(antimalarial_resistance_drug_index == which(parameters$antimalarial_resistance_drug == 1)) + drug_2_indices <- which(antimalarial_resistance_drug_index == which(parameters$antimalarial_resistance_drug == 2)) + + # Artemisinin proportion resistance assignment + artemisinin_resistance_proportion[drug_1_indices] <- parameters$prop_artemisinin_resistant[[2]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[2]], t = 30)] + artemisinin_resistance_proportion[drug_2_indices] <- parameters$prop_artemisinin_resistant[[1]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[1]], t = 30)] + + ##' Early treatment failure probability assignment: + early_treatment_failure_probability[drug_1_indices] <- parameters$early_treatment_failure_prob[[2]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[2]], t = 30)] + early_treatment_failure_probability[drug_2_indices] <- parameters$early_treatment_failure_prob[[1]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[1]], t = 30)] + + + # Determine individuals that remain susceptible to the drug they've been administered: + susceptible_to_treatment_index <- bernoulli_multi_p(p = 1 - (artemisinin_resistance_proportion * early_treatment_failure_probability)) + + # Remove the individuals who failed treatment due to resistance from the drugs vector: + drugs <- drugs[susceptible_to_treatment_index] + + # Subset the people who remained susceptible into new Bitset: + susceptible_to_treatment <- bitset_at(seek_treatment, susceptible_to_treatment_index) + # Calculate the number of individuals who failed treatment due to early treatment failure: - n_ETF <- n_treat - length(susceptible) - + n_ETF <- n_treat - length(susceptible_to_treatment_index) + # Add the number of Early Treatment Failures to the renderer: renderer$render('n_ETF', n_ETF, timestep) - - # Remove the individuals who failed treatment due to resistance from the drugs vector: - drugs <- drugs[susceptible] - - # Subset the people who remained susceptible - susceptible_index <- bitset_at(seek_treatment, susceptible) - + #+++ DRUG EFFICACY +++# + # Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: - successful <- bernoulli_multi_p(simparams$drug_efficacy[drugs]) - + successfully_treated_index <- bernoulli_multi_p(parameters$drug_efficacy[drugs]) + + # Subset the successfully treated people into new Bitset: + successfully_treated <- bitset_at(susceptible_to_treatment, successfully_treated_index) + # Calculate the number of people who failed treatment due to efficacy: - n_treat_eff_fail <- length(susceptible) - length(successful) - + n_treat_eff_fail <- length(susceptible_to_treatment_index) - length(successfully_treated_index) + # Add the number of treatment efficacy failures to the renderer: renderer$render('n_treat_eff_fail', n_treat_eff_fail, timestep) - - # Subset the successfully treated people: - treated_index <- bitset_at(susceptible_index, successful) - + # Add number of successfully treated individuals to the renderer - renderer$render('n_treat_success', treated_index$size(), timestep) - + renderer$render('n_treat_success', successfully_treated$size(), timestep) + + #+++ UPDATE VARIABLES +++# + # Update the variables for those who have been successfully treated: - if (treated_index$size() > 0) { - + if (successfully_treated$size() > 0) { + # Queue update to the infectious state to Tr: - variables$state$queue_update('Tr', treated_index) - + variables$state$queue_update('Tr', successfully_treated) + # Queue update to the infectivity to reflect their new state (Tr): variables$infectivity$queue_update( - parameters$cd * parameters$drug_rel_c[drugs[successful]], - treated_index + parameters$cd * parameters$drug_rel_c[drugs[successfully_treated_index]], + successfully_treated ) # Queue update to the last drug each successfully treated person received: variables$drug$queue_update( - drugs[successful], - treated_index + drugs[successfully_treated_index], + successfully_treated ) # Queue update to the time step on which each successfully treated person last # received a drug: variables$drug_time$queue_update( timestep, - treated_index + successfully_treated ) } - + # Return the Bitset of treated individuals: - treated_index + successfully_treated + } +#==================================================================================================# + #' @title Schedule infections #' @description #' Schedule infections in humans after the incubation period From 7be84ee9bddd5d1fa1bd98ac48549f645721b230 Mon Sep 17 00:00:00 2001 From: tbreweric Date: Sat, 22 Jul 2023 21:24:28 +0100 Subject: [PATCH 139/164] Added check to number of clinical_infections in calculate_treated() and a step to render this number for testing --- R/human_infection.R | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/R/human_infection.R b/R/human_infection.R index 5967ec08..44be789f 100644 --- a/R/human_infection.R +++ b/R/human_infection.R @@ -272,6 +272,18 @@ calculate_treated <- function( renderer ) { + #===================================================================# + + # Render the number of clinical infections in the current timestep: + renderer$render('n_clin_infected', clinical_infections$size(), timestep) + + # If there are no clinical infections, return an empty Bitset: + if(clinical_infections$size() == 0) { + return(individual::Bitset$new(parameters$human_population)) + } + + #===================================================================# + # Gather the treatment coverage(s) in the current time step: treatment_coverages <- get_treatment_coverages(parameters, timestep) From fea9da255ab3bb6e12360fa3c4ac45c3fd0138e7 Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Tue, 1 Aug 2023 12:03:53 +0100 Subject: [PATCH 140/164] Removed typos/spaces from antimalarial_resistance.R. Added check for calculate_treated() to separate resistance and non-resistance simulation paths --- R/antimalarial_resistance.R | 14 +++--- R/human_infection.R | 98 +++++++++++++++++++++---------------- 2 files changed, 64 insertions(+), 48 deletions(-) diff --git a/R/antimalarial_resistance.R b/R/antimalarial_resistance.R index b13ab0de..be279f1e 100644 --- a/R/antimalarial_resistance.R +++ b/R/antimalarial_resistance.R @@ -48,7 +48,7 @@ set_antimalarial_resistance <- function(parameters, stop("Resistance phenotype probabilities must fall between 0 and 1") } - # Set antimalarial_resistance to TRUE + # Set antimalarial_resistance to TRUE: parameters$antimalarial_resistance <- TRUE # Store the number of drugs for which parameters are available in the parameter list: @@ -59,26 +59,26 @@ set_antimalarial_resistance <- function(parameters, stop('Drug index is invalid, please set drugs using set_drugs') } - # Check the drug_index for the drug setting parameters for + # Check the drug_index for the we're drug setting parameters for: drug_index <- which(parameters$antimalarial_resistance_drug == drug) - # If drug_index is currently unpopulated + # If drug_index not already assigned, assign the drug the next available index: if (length(drug_index) == 0) { drug_index <- length(parameters$antimalarial_resistance_drug) + 1 } - # Append the drug for which resistance is being assigned + # Append the drug for which resistance is being assigned to the generated index: parameters$antimalarial_resistance_drug[[drug_index]] <- drug - # Append the timesteps on which the resistance proportions are to be updated + # Append the timesteps on which the resistance proportions are to be updated: parameters$antimalarial_resistance_timesteps[[drug_index]] <- timesteps # Append the proportions of all malarial infections that are artemisinin or partner-drug - # resistant + # resistant: parameters$prop_artemisinin_resistant[[drug_index]] <- artemisinin_resistance parameters$prop_partner_drug_resistant[[drug_index]] <- partner_drug_resistance - # Append the probabilities that + # Append the probabilities that individuals will experience the resistance phenotypes: parameters$slow_parasite_clearance_prob[[drug_index]] <- slow_parasite_clearance_prob parameters$early_treatment_failure_prob[[drug_index]] <- early_treatment_failure_prob parameters$late_clinical_failure_prob[[drug_index]] <- late_clinical_failure_prob diff --git a/R/human_infection.R b/R/human_infection.R index 44be789f..49586420 100644 --- a/R/human_infection.R +++ b/R/human_infection.R @@ -272,8 +272,6 @@ calculate_treated <- function( renderer ) { - #===================================================================# - # Render the number of clinical infections in the current timestep: renderer$render('n_clin_infected', clinical_infections$size(), timestep) @@ -282,8 +280,6 @@ calculate_treated <- function( return(individual::Bitset$new(parameters$human_population)) } - #===================================================================# - # Gather the treatment coverage(s) in the current time step: treatment_coverages <- get_treatment_coverages(parameters, timestep) @@ -319,41 +315,61 @@ calculate_treated <- function( #+++++ RESISTANCE +++++# - # Retrieve the index of the drug administered for each individual in the resistance parameters: - antimalarial_resistance_drug_index <- as.numeric(parameters$antimalarial_resistance_drug)[drugs] - - # Open vectors to store artemisinin resistance and early treatment probability parameters for each - # individual: - artemisinin_resistance_proportion <- vector() - early_treatment_failure_probability <- vector() - - # Work out which drug indices belong to each drug - drug_1_indices <- which(antimalarial_resistance_drug_index == which(parameters$antimalarial_resistance_drug == 1)) - drug_2_indices <- which(antimalarial_resistance_drug_index == which(parameters$antimalarial_resistance_drug == 2)) - - # Artemisinin proportion resistance assignment - artemisinin_resistance_proportion[drug_1_indices] <- parameters$prop_artemisinin_resistant[[2]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[2]], t = 30)] - artemisinin_resistance_proportion[drug_2_indices] <- parameters$prop_artemisinin_resistant[[1]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[1]], t = 30)] - - ##' Early treatment failure probability assignment: - early_treatment_failure_probability[drug_1_indices] <- parameters$early_treatment_failure_prob[[2]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[2]], t = 30)] - early_treatment_failure_probability[drug_2_indices] <- parameters$early_treatment_failure_prob[[1]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[1]], t = 30)] - - - # Determine individuals that remain susceptible to the drug they've been administered: - susceptible_to_treatment_index <- bernoulli_multi_p(p = 1 - (artemisinin_resistance_proportion * early_treatment_failure_probability)) - - # Remove the individuals who failed treatment due to resistance from the drugs vector: - drugs <- drugs[susceptible_to_treatment_index] - - # Subset the people who remained susceptible into new Bitset: - susceptible_to_treatment <- bitset_at(seek_treatment, susceptible_to_treatment_index) - - # Calculate the number of individuals who failed treatment due to early treatment failure: - n_ETF <- n_treat - length(susceptible_to_treatment_index) - - # Add the number of Early Treatment Failures to the renderer: - renderer$render('n_ETF', n_ETF, timestep) + if(!is.null(parameters$antimalarial_resistance)) { + + # Retrieve the index of the drug administered for each individual in the resistance parameters: + antimalarial_resistance_drug_index <- as.numeric(parameters$antimalarial_resistance_drug)[drugs] + + # Open vectors to store artemisinin resistance and early treatment probability parameters for each + # individual: + artemisinin_resistance_proportion <- vector() + early_treatment_failure_probability <- vector() + drug_indices <- list(); drug_index <- vector() + + for(i in seq_along(parameters$antimalarial_resistance_drug)) { + + # Retrieve the indices of individuals treated with drug i + drug_indices[[i]] <- which(drugs == i) + + # Retrieve the index of the drug in the resistance parameters + drug_index[i] <- which(parameters$antimalarial_resistance_drug == i) + + # Assign these individuals the resistance proportion corresponding to drug i in the current time step + artemisinin_resistance_proportion[drug_indices[[i]]] <- parameters$prop_artemisinin_resistant[[drug_index[i]]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[drug_index[i]]], + t = timestep)] + # Assign these individuals the ETF probability corresponding to drug i in the current time step + early_treatment_failure_probability[drug_indices[[i]]] <- parameters$early_treatment_failure_prob[[drug_index[i]]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[drug_index[i]]], + t = timestep)] + } + + # Determine individuals that remain susceptible to the drug they've been administered: + susceptible_to_treatment_index <- bernoulli_multi_p(p = 1 - (artemisinin_resistance_proportion * early_treatment_failure_probability)) + + # Remove the individuals who failed treatment due to resistance from the drugs vector: + drugs <- drugs[susceptible_to_treatment_index] + + # Subset the people who remained susceptible into new Bitset: + susceptible_to_treatment <- bitset_at(seek_treatment, susceptible_to_treatment_index) + + # Calculate the number of individuals who failed treatment due to early treatment failure: + n_ETF <- n_treat - susceptible_to_treatment$size() + + # Add the number of Early Treatment Failures to the renderer: + renderer$render('n_ETF', n_ETF, timestep) + + } else { + + # In the absence of resistance, all individuals who have sought treatment have susceptible + # infections + susceptible_to_treatment <- seek_treatment + + # Calculate the number of individuals who failed treatment due to early treatment failure: + n_ETF <- n_treat - susceptible_to_treatment$size() + + # Add the number of Early Treatment Failures to the renderer: + renderer$render('n_ETF', n_ETF, timestep) + + } #+++ DRUG EFFICACY +++# @@ -364,7 +380,7 @@ calculate_treated <- function( successfully_treated <- bitset_at(susceptible_to_treatment, successfully_treated_index) # Calculate the number of people who failed treatment due to efficacy: - n_treat_eff_fail <- length(susceptible_to_treatment_index) - length(successfully_treated_index) + n_treat_eff_fail <- susceptible_to_treatment$size() - length(successfully_treated_index) # Add the number of treatment efficacy failures to the renderer: renderer$render('n_treat_eff_fail', n_treat_eff_fail, timestep) @@ -378,7 +394,7 @@ calculate_treated <- function( if (successfully_treated$size() > 0) { # Queue update to the infectious state to Tr: - variables$state$queue_update('Tr', successfully_treated) + variables$state$queue_update("Tr", successfully_treated) # Queue update to the infectivity to reflect their new state (Tr): variables$infectivity$queue_update( From 0b1adb6bd85e18b6a42d962219c8d68372bd12ef Mon Sep 17 00:00:00 2001 From: tbreweric Date: Fri, 4 Aug 2023 12:46:22 +0100 Subject: [PATCH 141/164] removed comments from calculate_treated() function --- R/human_infection.R | 80 ++++----------------------------------------- 1 file changed, 6 insertions(+), 74 deletions(-) diff --git a/R/human_infection.R b/R/human_infection.R index 49586420..4c7713ab 100644 --- a/R/human_infection.R +++ b/R/human_infection.R @@ -253,8 +253,6 @@ update_severe_disease <- function( ) } -#===== Resistance -> Efficacy =====================================================================# - #' @title Calculate treated humans #' @description #' Sample treated humans from the clinically infected @@ -272,38 +270,24 @@ calculate_treated <- function( renderer ) { - # Render the number of clinical infections in the current timestep: renderer$render('n_clin_infected', clinical_infections$size(), timestep) - # If there are no clinical infections, return an empty Bitset: if(clinical_infections$size() == 0) { return(individual::Bitset$new(parameters$human_population)) } - # Gather the treatment coverage(s) in the current time step: treatment_coverages <- get_treatment_coverages(parameters, timestep) - - # Sum to get the total treatment coverage in the current time step: ft <- sum(treatment_coverages) - # If total coverage = 0, return an empty Bitset for the treated individuals: if (ft == 0) { return(individual::Bitset$new(parameters$human_population)) } - # Add the total treatment coverage to the renderer: renderer$render('ft', ft, timestep) - - # Sample individuals from clinically infected to seek treatment using treatment coverage: seek_treatment <- sample_bitset(clinical_infections, ft) - - # Store the number of people that seek treatment this time step: n_treat <- seek_treatment$size() - - # Add the number of people seeking treatment in the current time step to the renderer: renderer$render('n_treated', n_treat, timestep) - # Assign each individual seeking treatment a drug based on their coverage(s): drugs <- as.numeric(parameters$clinical_treatment_drugs[ sample.int( length(parameters$clinical_treatment_drugs), @@ -313,114 +297,62 @@ calculate_treated <- function( ) ]) - #+++++ RESISTANCE +++++# - if(!is.null(parameters$antimalarial_resistance)) { - # Retrieve the index of the drug administered for each individual in the resistance parameters: antimalarial_resistance_drug_index <- as.numeric(parameters$antimalarial_resistance_drug)[drugs] - - # Open vectors to store artemisinin resistance and early treatment probability parameters for each - # individual: artemisinin_resistance_proportion <- vector() early_treatment_failure_probability <- vector() drug_indices <- list(); drug_index <- vector() - - for(i in seq_along(parameters$antimalarial_resistance_drug)) { - - # Retrieve the indices of individuals treated with drug i - drug_indices[[i]] <- which(drugs == i) - - # Retrieve the index of the drug in the resistance parameters - drug_index[i] <- which(parameters$antimalarial_resistance_drug == i) - - # Assign these individuals the resistance proportion corresponding to drug i in the current time step - artemisinin_resistance_proportion[drug_indices[[i]]] <- parameters$prop_artemisinin_resistant[[drug_index[i]]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[drug_index[i]]], + + for(i in seq_along(parameters$antimalarial_resistance_drug)) { + drug_indices[[i]] <- which(drugs == i) + drug_index[i] <- which(parameters$antimalarial_resistance_drug == i) + artemisinin_resistance_proportion[drug_indices[[i]]] <- parameters$prop_artemisinin_resistant[[drug_index[i]]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[drug_index[i]]], t = timestep)] - # Assign these individuals the ETF probability corresponding to drug i in the current time step - early_treatment_failure_probability[drug_indices[[i]]] <- parameters$early_treatment_failure_prob[[drug_index[i]]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[drug_index[i]]], + early_treatment_failure_probability[drug_indices[[i]]] <- parameters$early_treatment_failure_prob[[drug_index[i]]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[drug_index[i]]], t = timestep)] } - # Determine individuals that remain susceptible to the drug they've been administered: susceptible_to_treatment_index <- bernoulli_multi_p(p = 1 - (artemisinin_resistance_proportion * early_treatment_failure_probability)) - - # Remove the individuals who failed treatment due to resistance from the drugs vector: drugs <- drugs[susceptible_to_treatment_index] - - # Subset the people who remained susceptible into new Bitset: susceptible_to_treatment <- bitset_at(seek_treatment, susceptible_to_treatment_index) - - # Calculate the number of individuals who failed treatment due to early treatment failure: n_ETF <- n_treat - susceptible_to_treatment$size() - - # Add the number of Early Treatment Failures to the renderer: renderer$render('n_ETF', n_ETF, timestep) } else { - # In the absence of resistance, all individuals who have sought treatment have susceptible - # infections susceptible_to_treatment <- seek_treatment - - # Calculate the number of individuals who failed treatment due to early treatment failure: n_ETF <- n_treat - susceptible_to_treatment$size() - - # Add the number of Early Treatment Failures to the renderer: renderer$render('n_ETF', n_ETF, timestep) } - #+++ DRUG EFFICACY +++# - - # Determine, using drug efficacies, use bernoulli trials to see who's treatment worked: successfully_treated_index <- bernoulli_multi_p(parameters$drug_efficacy[drugs]) - - # Subset the successfully treated people into new Bitset: successfully_treated <- bitset_at(susceptible_to_treatment, successfully_treated_index) - - # Calculate the number of people who failed treatment due to efficacy: n_treat_eff_fail <- susceptible_to_treatment$size() - length(successfully_treated_index) - - # Add the number of treatment efficacy failures to the renderer: renderer$render('n_treat_eff_fail', n_treat_eff_fail, timestep) - - # Add number of successfully treated individuals to the renderer renderer$render('n_treat_success', successfully_treated$size(), timestep) - #+++ UPDATE VARIABLES +++# - - # Update the variables for those who have been successfully treated: if (successfully_treated$size() > 0) { - # Queue update to the infectious state to Tr: variables$state$queue_update("Tr", successfully_treated) - # Queue update to the infectivity to reflect their new state (Tr): variables$infectivity$queue_update( parameters$cd * parameters$drug_rel_c[drugs[successfully_treated_index]], successfully_treated ) - # Queue update to the last drug each successfully treated person received: variables$drug$queue_update( drugs[successfully_treated_index], successfully_treated ) - # Queue update to the time step on which each successfully treated person last - # received a drug: variables$drug_time$queue_update( timestep, successfully_treated ) } - - # Return the Bitset of treated individuals: successfully_treated - } -#==================================================================================================# - #' @title Schedule infections #' @description #' Schedule infections in humans after the incubation period From 731899eccb2c63f706fb673465e3eb044d955ab9 Mon Sep 17 00:00:00 2001 From: tbreweric Date: Thu, 17 Aug 2023 10:56:08 +0100 Subject: [PATCH 142/164] removed unnecessary spacing and comments from the calculate_treated() function --- R/human_infection.R | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/R/human_infection.R b/R/human_infection.R index 4c7713ab..f763d2c8 100644 --- a/R/human_infection.R +++ b/R/human_infection.R @@ -298,33 +298,27 @@ calculate_treated <- function( ]) if(!is.null(parameters$antimalarial_resistance)) { - antimalarial_resistance_drug_index <- as.numeric(parameters$antimalarial_resistance_drug)[drugs] artemisinin_resistance_proportion <- vector() early_treatment_failure_probability <- vector() drug_indices <- list(); drug_index <- vector() - - for(i in seq_along(parameters$antimalarial_resistance_drug)) { - drug_indices[[i]] <- which(drugs == i) - drug_index[i] <- which(parameters$antimalarial_resistance_drug == i) - artemisinin_resistance_proportion[drug_indices[[i]]] <- parameters$prop_artemisinin_resistant[[drug_index[i]]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[drug_index[i]]], + for(i in seq_along(parameters$antimalarial_resistance_drug)) { + drug_indices[[i]] <- which(drugs == i) + drug_index[i] <- which(parameters$antimalarial_resistance_drug == i) + artemisinin_resistance_proportion[drug_indices[[i]]] <- parameters$prop_artemisinin_resistant[[drug_index[i]]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[drug_index[i]]], t = timestep)] - early_treatment_failure_probability[drug_indices[[i]]] <- parameters$early_treatment_failure_prob[[drug_index[i]]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[drug_index[i]]], + early_treatment_failure_probability[drug_indices[[i]]] <- parameters$early_treatment_failure_prob[[drug_index[i]]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[drug_index[i]]], t = timestep)] } - susceptible_to_treatment_index <- bernoulli_multi_p(p = 1 - (artemisinin_resistance_proportion * early_treatment_failure_probability)) drugs <- drugs[susceptible_to_treatment_index] susceptible_to_treatment <- bitset_at(seek_treatment, susceptible_to_treatment_index) n_ETF <- n_treat - susceptible_to_treatment$size() renderer$render('n_ETF', n_ETF, timestep) - } else { - susceptible_to_treatment <- seek_treatment n_ETF <- n_treat - susceptible_to_treatment$size() renderer$render('n_ETF', n_ETF, timestep) - } successfully_treated_index <- bernoulli_multi_p(parameters$drug_efficacy[drugs]) @@ -333,10 +327,9 @@ calculate_treated <- function( renderer$render('n_treat_eff_fail', n_treat_eff_fail, timestep) renderer$render('n_treat_success', successfully_treated$size(), timestep) + # Update variables of those who have been successfully treated: if (successfully_treated$size() > 0) { - variables$state$queue_update("Tr", successfully_treated) - variables$infectivity$queue_update( parameters$cd * parameters$drug_rel_c[drugs[successfully_treated_index]], successfully_treated From 578c9e5046317aa8c832782a5cba19623a271ce3 Mon Sep 17 00:00:00 2001 From: tbreweric Date: Thu, 17 Aug 2023 15:46:57 +0100 Subject: [PATCH 143/164] Create test-antimalarial-resistance.R and added six tests for the set_antimalarial_resistance() function in antimalarial_resistance.R file. Also amended the existing test for calculate_treated() in test-infection-integration.R and added five additional calculate_treated() tests. --- R/antimalarial_resistance.R | 2 +- tests/testthat/test-antimalarial-resistance.R | 1 + tests/testthat/test-infection-integration.R | 130 +++++++++++++----- 3 files changed, 100 insertions(+), 33 deletions(-) create mode 100644 tests/testthat/test-antimalarial-resistance.R diff --git a/R/antimalarial_resistance.R b/R/antimalarial_resistance.R index be279f1e..d0d7ba0e 100644 --- a/R/antimalarial_resistance.R +++ b/R/antimalarial_resistance.R @@ -1,7 +1,7 @@ #' @title Parameterise antimalarial resistance #' #' @param parameters the model parameters -#' @param drug the index of the drug which resistance is being set for in the parameter list +#' @param drug the index of the drug which resistance is being set as set by set_drugs() in the parameter list #' @param timesteps vector of time steps for each update to resistance proportion and/or phenotype probability #' @param artemisinin_resistance vector of updates to the proportions of infections that are artemisinin resistant at time t #' @param partner_drug_resistance vector of updates to the proportions of infections that are partner-drug resistant at time t diff --git a/tests/testthat/test-antimalarial-resistance.R b/tests/testthat/test-antimalarial-resistance.R new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/tests/testthat/test-antimalarial-resistance.R @@ -0,0 +1 @@ + diff --git a/tests/testthat/test-infection-integration.R b/tests/testthat/test-infection-integration.R index 0400a361..cbcc4ff7 100644 --- a/tests/testthat/test-infection-integration.R +++ b/tests/testthat/test-infection-integration.R @@ -206,7 +206,6 @@ test_that('calculate_infections works various combinations of drug and vaccinati }) - test_that('calculate_clinical_infections correctly samples clinically infected', { timestep <- 5 parameters <- get_parameters() @@ -253,10 +252,33 @@ test_that('calculate_clinical_infections correctly samples clinically infected', }) test_that('calculate_treated correctly samples treated and updates the drug state', { + parameters <- get_parameters() - parameters <- set_drugs(parameters, list(AL_params, DHA_PQP_params)) - parameters <- set_clinical_treatment(parameters, 1, 1, .25) - parameters <- set_clinical_treatment(parameters, 2, 1, .25) + parameters <- set_drugs(parameters = parameters, drugs = list(AL_params, SP_AQ_params)) + parameters <- set_clinical_treatment(parameters = parameters, drug = 1, timesteps = 1, coverages = 0.25) + parameters <- set_clinical_treatment(parameters = parameters, drug = 2, timesteps = 1, coverages = 0.25) + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 1, + timesteps = 1, + artemisinin_resistance = 0.5, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0, + early_treatment_failure_prob = 0.2, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0) + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 2, + timesteps = 1, + artemisinin_resistance = 0, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0, + early_treatment_failure_prob = 0.9, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0) + + clinical_infections <- individual::Bitset$new(20)$insert(1:20) timestep <- 5 events <- create_events(parameters) variables <- list( @@ -265,24 +287,17 @@ test_that('calculate_treated correctly samples treated and updates the drug stat drug = list(queue_update = mockery::mock()), drug_time = list(queue_update = mockery::mock()) ) - - recovery_mock <- mockery::mock() - mockery::stub(calculate_treated, 'recovery$schedule', recovery_mock) - - seek_treatment <- individual::Bitset$new(4)$insert(c(1, 2, 4)) - mockery::stub( - calculate_treated, - 'sample_bitset', - mockery::mock(seek_treatment) - ) - sample_mock <- mockery::mock(c(2, 1, 1, 1)) - mockery::stub(calculate_treated, 'sample.int', sample_mock) - bernoulli_mock <- mockery::mock(c(1, 3)) + + seek_treatment <- individual::Bitset$new(20)$insert(c(1:10)) + seek_treatment_mock <- mockery::mock(seek_treatment) + mockery::stub(where = calculate_treated, what = 'sample_bitset', how = seek_treatment_mock) + + mock_drugs <- mockery::mock(c(2, 1, 1, 1, 2, 2, 2, 1, 2, 1)) + mockery::stub(calculate_treated, 'sample.int', mock_drugs) + + bernoulli_mock <- mockery::mock(c(1, 2, 3, 4, 5, 6, 7, 8, 9), c(1, 2, 3, 4, 5, 6, 7)) mockery::stub(calculate_treated, 'bernoulli_multi_p', bernoulli_mock) - mockery::stub(calculate_treated, 'log_uniform', mockery::mock(c(3, 4))) - - clinical_infections <- individual::Bitset$new(4) - clinical_infections$insert(c(1, 2, 3, 4)) + calculate_treated( variables, clinical_infections, @@ -290,30 +305,44 @@ test_that('calculate_treated correctly samples treated and updates the drug stat timestep, mock_render(timestep) ) - + mockery::expect_args( - sample_mock, + mock_drugs, 1, 2, - 3, + 10, c(.25, .25), TRUE ) - + + mockery::expect_args( + seek_treatment_mock, + 1, + clinical_infections, + 0.5 + ) + mockery::expect_args( bernoulli_mock, 1, - parameters$drug_efficacy[c(2, 1, 1, 1)] + c(1.0, 0.9, 0.9, 0.9, 1.0, 1.0, 1.0, 0.9, 1, 0.9) ) - - expect_bitset_update(variables$state$queue_update, 'Tr', c(1, 4)) + + mockery::expect_args( + bernoulli_mock, + 2, + parameters$drug_efficacy[c(2, 1, 1, 1, 2, 2, 2, 1, 2)] + ) + + expect_bitset_update(variables$state$queue_update, 'Tr', c(1, 2, 3, 4, 5, 6, 7)) expect_bitset_update( variables$infectivity$queue_update, - parameters$cd * parameters$drug_rel_c[c(2, 1)], - c(1, 4) + parameters$cd * parameters$drug_rel_c[c(2, 1, 1, 1, 2, 2, 2)], + c(1, 2, 3, 4, 5, 6, 7) ) - expect_bitset_update(variables$drug$queue_update, c(2, 1), c(1, 4)) - expect_bitset_update(variables$drug_time$queue_update, 5, c(1, 4)) + expect_bitset_update(variables$drug$queue_update, c(2, 1, 1, 1, 2, 2, 2), c(1, 2, 3, 4, 5, 6, 7)) + expect_bitset_update(variables$drug_time$queue_update, 5, c(1, 2, 3, 4, 5, 6, 7)) + }) test_that('schedule_infections correctly schedules new infections', { @@ -531,3 +560,40 @@ test_that('update_severe_disease renders with no infections', { timestep ) }) + +test_that(desc = "calculate_treated returns empty Bitset when there is no clinical treatment coverage", { + parameters <- get_parameters() + parameters <- set_drugs(parameters = parameters, drugs = list(AL_params)) + parameters <- set_clinical_treatment(parameters = parameters, drug = 1, timesteps = 1, coverages = 0) + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 1, + timesteps = 1, + artemisinin_resistance = 0.5, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0, + early_treatment_failure_prob = 0.2, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0) + clinical_infections <- individual::Bitset$new(20)$insert(1:20) + timestep <- 5 + events <- create_events(parameters) + variables <- list( + state = list(queue_update = mockery::mock()), + infectivity = list(queue_update = mockery::mock()), + drug = list(queue_update = mockery::mock()), + drug_time = list(queue_update = mockery::mock()) + ) + renderer <- individual::Render$new(timesteps = 10) + + treated <- calculate_treated(variables = variables, + clinical_infections = clinical_infections, + parameters = parameters, + timestep = timestep, + renderer = renderer) + + expect_identical(object = treated$size(), expected = 0, info = "Error: calculate_treated() returning non-zero number of treated individuals + in the absence of clinical treatment") + expect_identical(object = treated$to_vector(), expected = numeric(0), info = "Error: calculate_treated() returning non-zero number of treated individuals + in the absence of clinical treatment") +}) From ded0251208e8369538af67fd9abd7383cb4464b5 Mon Sep 17 00:00:00 2001 From: tbreweric Date: Thu, 17 Aug 2023 15:49:35 +0100 Subject: [PATCH 144/164] Added test file for new antimalarial resistance functions and added new calculate_treated() tests to test-infection-integration.R. Note - I thought these changes had been included in the previous commit/push --- tests/testthat/test-antimalarial-resistance.R | 160 ++++++++++++++++++ tests/testthat/test-infection-integration.R | 157 ++++++++++++++++- 2 files changed, 316 insertions(+), 1 deletion(-) diff --git a/tests/testthat/test-antimalarial-resistance.R b/tests/testthat/test-antimalarial-resistance.R index 8b137891..9250bc4e 100644 --- a/tests/testthat/test-antimalarial-resistance.R +++ b/tests/testthat/test-antimalarial-resistance.R @@ -1 +1,161 @@ +test_that('set_antimalarial_resistance() toggles resistance on', { + simparams <- get_parameters() + simparams <- set_drugs(parameters = simparams, drugs = list(SP_AQ_params)) + simparams <- set_clinical_treatment(parameters = simparams, + drug = 1, + timesteps = 1, + coverages = 1) + set_antimalarial_resistance(parameters = simparams, + drug = 1, + timesteps = 1, + artemisinin_resistance = 0.5, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0.5, + early_treatment_failure_prob = 0.6, + late_clinical_failure_prob = 0.2, + late_parasitological_prob = 0.3, + reinfection_prob = 0.4) -> simparams + expect_identical(object = simparams$antimalarial_resistance, expected = TRUE) +}) +test_that('set_antimalarial_resistance() errors if parameter inputs of different length to timesteps', { + simparams <- get_parameters() + simparams <- set_drugs(parameters = simparams, drugs = list(SP_AQ_params)) + simparams <- set_clinical_treatment(parameters = simparams, + drug = 1, + timesteps = 1, + coverages = 1) + expect_error(object = set_antimalarial_resistance(parameters = simparams, + drug = 1, + timesteps = c(1, 10), + artemisinin_resistance = 0.5, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0.5, + early_treatment_failure_prob = 0.6, + late_clinical_failure_prob = 0.2, + late_parasitological_prob = 0.3, + reinfection_prob = 0.4)) +}) + +test_that('set_antimalarial_resistance() errors if resistance proportions outside bound of 0-1', { + simparams <- get_parameters() + simparams <- set_drugs(parameters = simparams, drugs = list(SP_AQ_params)) + simparams <- set_clinical_treatment(parameters = simparams, + drug = 1, + timesteps = 1, + coverages = 1) + expect_error(object = set_antimalarial_resistance(parameters = simparams, + drug = 1, + timesteps = 1, + artemisinin_resistance = 1.01, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0.5, + early_treatment_failure_prob = 0.6, + late_clinical_failure_prob = 0.2, + late_parasitological_prob = 0.3, + reinfection_prob = 0.4)) +}) + +test_that('set_antimalarial_resistance() errors if resistance phenotype probabilities outside bound of 0-1', { + simparams <- get_parameters() + simparams <- set_drugs(parameters = simparams, drugs = list(SP_AQ_params)) + simparams <- set_clinical_treatment(parameters = simparams, + drug = 1, + timesteps = 1, + coverages = 1) + expect_error(object = set_antimalarial_resistance(parameters = simparams, + drug = 1, + timesteps = 1, + artemisinin_resistance = 0.4, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = -0.5, + early_treatment_failure_prob = 0.6, + late_clinical_failure_prob = 0.2, + late_parasitological_prob = 0.3, + reinfection_prob = 0.4)) +}) + +test_that('set_antimalarial_resistance() errors if drug index > than number of drugs assigned using set_drugs()', { + simparams <- get_parameters() + simparams <- set_drugs(parameters = simparams, drugs = list(SP_AQ_params)) + simparams <- set_clinical_treatment(parameters = simparams, + drug = 1, + timesteps = 1, + coverages = 1) + expect_error(object = set_antimalarial_resistance(parameters = simparams, + drug = 2, + timesteps = 1, + artemisinin_resistance = 0.4, + partner_drug_resistance = 0.3, + slow_parasite_clearance_prob = 0.5, + early_treatment_failure_prob = 0.6, + late_clinical_failure_prob = 0.2, + late_parasitological_prob = 0.3, + reinfection_prob = 0.4)) +}) + +test_that('set_antimalarial_resistance() assigns parameters correctly despite drug order', { + + # Randomly assign the order of the drug assignment in clinical treatment and resistance: + clinical_treatment_drugs <- sample.int(n = 3, size = 3, replace = FALSE) + antimalarial_resistance_drugs <- sample.int(n = 3, size = 3, replace = FALSE) + + # Randomly assign drug coverages for clinical treatment: + clinical_treatment_coverages <- sample(c(0.1, 0.2, 0.4)) + + # Randomly assign timesteps for clinical treatment and resistance: + clinical_treatment_timesteps <- sample.int(n = 100, size = 3, replace = FALSE) + antimalarial_resistance_timesteps <- sample.int(n = 100, size = 3, replace = FALSE) + + # Randomly assign values to antimalarial resistance proportions + antimalarial_resistance_artemisinin_proportion <- sample(x = seq(0, 0.33, by = 0.01), size = 3, replace = FALSE) + antimalarial_resistance_partner_drug_proportion <- sample(x = seq(0, 0.33, by = 0.01), size = 3, replace = FALSE) + + # Randomly assign values to antimalarial resistance probabilities: + antimalarial_resistance_ETF_probability <- sample(x = seq(0, 0.33, by = 0.01), size = 3, replace = FALSE) + antimalarial_resistance_SPC_probability <- sample(x = seq(0, 0.33, by = 0.01), size = 3, replace = FALSE) + antimalarial_resistance_LCF_probability <- sample(x = seq(0, 0.33, by = 0.01), size = 3, replace = FALSE) + antimalarial_resistance_LPF_probability <- sample(x = seq(0, 0.33, by = 0.01), size = 3, replace = FALSE) + antimalarial_resistance_RDP_probability <- sample(x = seq(0, 0.33, by = 0.01), size = 3, replace = FALSE) + + # Establish some parameters + simparams <- get_parameters() + + # Add the three drug parameter vectors to the parameter list: + simparams <- set_drugs(parameters = simparams, drugs = list(AL_params, SP_AQ_params, DHA_PQP_params)) + + # Loop through and assign the parameters for each drug + for(i in seq(clinical_treatment_drugs)) { + simparams <- set_clinical_treatment(parameters = simparams, + drug = clinical_treatment_drugs[i], + timesteps = clinical_treatment_timesteps[i], + coverages = clinical_treatment_coverages[i]) + } + + # Loop through and assign the antimalarial resistance parameters for each drug: + for(i in seq(antimalarial_resistance_drugs)) { + simparams <- set_antimalarial_resistance(parameters = simparams, + drug = antimalarial_resistance_drugs[i], + timesteps = antimalarial_resistance_timesteps[i], + artemisinin_resistance = antimalarial_resistance_artemisinin_proportion[i], + partner_drug_resistance = antimalarial_resistance_partner_drug_proportion[i], + slow_parasite_clearance_prob = antimalarial_resistance_SPC_probability[i], + early_treatment_failure_prob = antimalarial_resistance_ETF_probability[i], + late_clinical_failure_prob = antimalarial_resistance_LCF_probability[i], + late_parasitological_prob = antimalarial_resistance_LPF_probability[i], + reinfection_prob = antimalarial_resistance_RDP_probability[i]) + } + + # Check the antimalarial resistance parameters after assignment using set_antimalarial_resistance(): + expect_identical(simparams$antimalarial_resistance, TRUE) + expect_identical(unlist(simparams$antimalarial_resistance_drug), antimalarial_resistance_drugs) + expect_identical(unlist(simparams$antimalarial_resistance_timesteps), antimalarial_resistance_timesteps) + expect_identical(unlist(simparams$prop_artemisinin_resistant), antimalarial_resistance_artemisinin_proportion) + expect_identical(unlist(simparams$prop_partner_drug_resistant), antimalarial_resistance_partner_drug_proportion) + expect_identical(unlist(simparams$slow_parasite_clearance_prob), antimalarial_resistance_SPC_probability) + expect_identical(unlist(simparams$early_treatment_failure_prob), antimalarial_resistance_ETF_probability) + expect_identical(unlist(simparams$late_clinical_failure_prob), antimalarial_resistance_LCF_probability) + expect_identical(unlist(simparams$late_parasitological_failure_prob), antimalarial_resistance_LPF_probability) + expect_identical(unlist(simparams$reinfection_during_prophylaxis), antimalarial_resistance_RDP_probability) + +}) diff --git a/tests/testthat/test-infection-integration.R b/tests/testthat/test-infection-integration.R index cbcc4ff7..00f29f0d 100644 --- a/tests/testthat/test-infection-integration.R +++ b/tests/testthat/test-infection-integration.R @@ -561,7 +561,7 @@ test_that('update_severe_disease renders with no infections', { ) }) -test_that(desc = "calculate_treated returns empty Bitset when there is no clinical treatment coverage", { +test_that('calculate_treated returns empty Bitset when there is no clinical treatment coverage', { parameters <- get_parameters() parameters <- set_drugs(parameters = parameters, drugs = list(AL_params)) parameters <- set_clinical_treatment(parameters = parameters, drug = 1, timesteps = 1, coverages = 0) @@ -597,3 +597,158 @@ test_that(desc = "calculate_treated returns empty Bitset when there is no clinic expect_identical(object = treated$to_vector(), expected = numeric(0), info = "Error: calculate_treated() returning non-zero number of treated individuals in the absence of clinical treatment") }) + +test_that(desc = 'calculate_treated returns empty Bitset when the clinically_infected input is an empty Bitset', { + parameters <- get_parameters() + parameters <- set_drugs(parameters = parameters, drugs = list(AL_params)) + parameters <- set_clinical_treatment(parameters = parameters, drug = 1, timesteps = 1, coverages = 1) + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 1, + timesteps = 1, + artemisinin_resistance = 0.5, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0, + early_treatment_failure_prob = 0.2, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0) + clinical_infections <- individual::Bitset$new(20) + timestep <- 5 + events <- create_events(parameters) + variables <- list( + state = list(queue_update = mockery::mock()), + infectivity = list(queue_update = mockery::mock()), + drug = list(queue_update = mockery::mock()), + drug_time = list(queue_update = mockery::mock()) + ) + renderer <- individual::Render$new(timesteps = 10) + + treated <- calculate_treated(variables = variables, + clinical_infections = clinical_infections, + parameters = parameters, + timestep = timestep, + renderer = renderer) + + expect_identical(object = treated$size(), expected = 0, info = "Error: calculate_treated() returning non-zero number of treated individuals + in the absence of clinically infected individuals") + expect_identical(object = treated$to_vector(), expected = numeric(0), info = "Error: calculate_treated() returning non-zero number of treated individuals + in the absence of clinically infected individuals") +}) + +test_that('calculate_treated() returns an empty Bitset when the parameter list contains no clinical + treatment or resistance parameters', { + parameters <- get_parameters() + clinical_infections <- individual::Bitset$new(20)$insert(1:20) + timestep <- 5 + events <- create_events(parameters) + variables <- list( + state = list(queue_update = mockery::mock()), + infectivity = list(queue_update = mockery::mock()), + drug = list(queue_update = mockery::mock()), + drug_time = list(queue_update = mockery::mock()) + ) + renderer <- individual::Render$new(timesteps = 10) + + treated <- calculate_treated(variables = variables, + clinical_infections = clinical_infections, + parameters = parameters, + timestep = timestep, + renderer = renderer) + + expect_identical(object = treated$size(), expected = 0, info = "Error: calculate_treated() returning non-zero number of treated individuals + in the absence of clinical treatment or resistance parameters") + expect_identical(object = treated$to_vector(), expected = numeric(0), info = "Error: calculate_treated() returning non-zero number of treated individuals + in the absence of clinical treatment or resistance parameters") + }) + +test_that('calculate_treated() returns an empty Bitset when all treatment fails due to early treatment failure', { + parameters <- get_parameters() + parameters <- set_drugs(parameters = parameters, drugs = list(AL_params, SP_AQ_params)) + parameters <- set_clinical_treatment(parameters = parameters, + drug = 1, + timesteps = 1, + coverages = round(runif(1, 0, 1/2), + digits = 2)) + parameters <- set_clinical_treatment(parameters = parameters, + drug = 2, + timesteps = 1, + coverages = round(runif(1, 0, 1/2), + digits = 2)) + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 1, + timesteps = 1, + artemisinin_resistance = 1, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0, + early_treatment_failure_prob = 1, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0) + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 2, + timesteps = 1, + artemisinin_resistance = 1, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0, + early_treatment_failure_prob = 1, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0) + + clinical_infections <- individual::Bitset$new(100) + clinical_infections$insert(sample.int(n = 100, size = round(runif(n = 1, min = 10, max = 100)), replace = FALSE)) + timestep <- 5 + events <- create_events(parameters) + variables <- create_variables(parameters = parameters) + renderer <- individual::Render$new(timesteps = 10) + + treated <- calculate_treated(variables = variables, + clinical_infections = clinical_infections, + parameters = parameters, + timestep = timestep, + renderer = renderer) + + expect_identical(object = treated$size(), expected = 0, info = "Error: non-zero length treated Bitset when clinical treatment coverage = 1, + artemisinin resistance = 1, and early treatment probability = 1") + expect_identical(renderer$to_dataframe()[timestep,'n_ETF'], renderer$to_dataframe()[timestep,'n_treated'], info = "Error: Number of + early treatment failures does not match number of treated individuals when artemisinin resistance proportion and + and early treatment failure probability both equal 1") +}) + +test_that('calculate_treated() successfully adds additional resistance columns to the renderer', { + parameters <- get_parameters() + parameters <- set_drugs(parameters = parameters, drugs = list(AL_params)) + parameters <- set_clinical_treatment(parameters = parameters, drug = 1, timesteps = 1, coverages = 1) + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 1, + timesteps = 1, + artemisinin_resistance = 0.5, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0, + early_treatment_failure_prob = 0.5, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0) + + clinical_infections <- individual::Bitset$new(20)$insert(1:20) + timestep <- 5 + events <- create_events(parameters) + variables <- list( + state = list(queue_update = mockery::mock()), + infectivity = list(queue_update = mockery::mock()), + drug = list(queue_update = mockery::mock()), + drug_time = list(queue_update = mockery::mock()) + ) + renderer <- individual::Render$new(timesteps = 10) + + treated <- calculate_treated(variables = variables, + clinical_infections = clinical_infections, + parameters = parameters, + timestep = timestep, + renderer = renderer) + + calculate_treated_column_names <- c("n_clin_infected", "ft", "n_treated", "n_ETF", "n_treat_eff_fail", "n_treat_success") + expect_identical(sum(calculate_treated_column_names %in% colnames(renderer$to_dataframe())), length(calculate_treated_column_names), + "calculate_treated() not renderering all resistance columns when resistance is present, clinical treatment coverage + is non-zero, and the Bitset of clinically_infected individuals input is of non-zero length.") +}) \ No newline at end of file From d4db8f99ec705f2f3bf9b1194fed1f0c52ff2382 Mon Sep 17 00:00:00 2001 From: tbreweric Date: Wed, 20 Sep 2023 14:53:57 +0100 Subject: [PATCH 145/164] Commiting all changes recommended by Pete/Giovanni except those that involve the function testing (to follow in a subsequent commit). --- R/antimalarial_resistance.R | 10 +- R/human_infection.R | 24 +-- R/model.R | 4 + R/parameters.R | 26 +++ man/get_parameters.Rd | 16 ++ man/run_simulation.Rd | 4 + man/set_antimalarial_resistance.Rd | 6 +- vignettes/Antimalarial_Resistance.Rmd | 240 +++++++++++++++++++++++++- 8 files changed, 311 insertions(+), 19 deletions(-) diff --git a/R/antimalarial_resistance.R b/R/antimalarial_resistance.R index d0d7ba0e..d84d9641 100644 --- a/R/antimalarial_resistance.R +++ b/R/antimalarial_resistance.R @@ -1,8 +1,8 @@ #' @title Parameterise antimalarial resistance #' #' @param parameters the model parameters -#' @param drug the index of the drug which resistance is being set as set by set_drugs() in the parameter list -#' @param timesteps vector of time steps for each update to resistance proportion and/or phenotype probability +#' @param drug the index of the drug which resistance is being set, as set by the set_drugs() function, in the parameter list +#' @param timesteps vector of time steps for each update to resistance proportion and resistance outcome probability #' @param artemisinin_resistance vector of updates to the proportions of infections that are artemisinin resistant at time t #' @param partner_drug_resistance vector of updates to the proportions of infections that are partner-drug resistant at time t #' @param slow_parasite_clearance_prob vector of updates to the proportion of artemisinin-resistant infections that result in early treatment failure @@ -39,13 +39,13 @@ set_antimalarial_resistance <- function(parameters, stop("Artemisinin and partner-drug resistance proportions must fall between 0 and 1") } - # Ensure resistance phenotype probabilities bounded between 0 and 1: + # Ensure resistance outcome probabilities bounded between 0 and 1: if(any(slow_parasite_clearance_prob < 0 | slow_parasite_clearance_prob > 1 | early_treatment_failure_prob < 0 | early_treatment_failure_prob > 1 | late_clinical_failure_prob < 0 | late_clinical_failure_prob > 1 | late_parasitological_prob < 0 | late_parasitological_prob > 1 | reinfection_prob < 0 | reinfection_prob > 1)) { - stop("Resistance phenotype probabilities must fall between 0 and 1") + stop("Resistance outcome probabilities must fall between 0 and 1") } # Set antimalarial_resistance to TRUE: @@ -78,7 +78,7 @@ set_antimalarial_resistance <- function(parameters, parameters$prop_artemisinin_resistant[[drug_index]] <- artemisinin_resistance parameters$prop_partner_drug_resistant[[drug_index]] <- partner_drug_resistance - # Append the probabilities that individuals will experience the resistance phenotypes: + # Append the probabilities that individuals will experience the resistance outcomes: parameters$slow_parasite_clearance_prob[[drug_index]] <- slow_parasite_clearance_prob parameters$early_treatment_failure_prob[[drug_index]] <- early_treatment_failure_prob parameters$late_clinical_failure_prob[[drug_index]] <- late_clinical_failure_prob diff --git a/R/human_infection.R b/R/human_infection.R index f763d2c8..9bb8e565 100644 --- a/R/human_infection.R +++ b/R/human_infection.R @@ -297,28 +297,31 @@ calculate_treated <- function( ) ]) - if(!is.null(parameters$antimalarial_resistance)) { + if(parameters$antimalarial_resistance == TRUE) { antimalarial_resistance_drug_index <- as.numeric(parameters$antimalarial_resistance_drug)[drugs] artemisinin_resistance_proportion <- vector() early_treatment_failure_probability <- vector() drug_indices <- list(); drug_index <- vector() + for(i in seq_along(parameters$antimalarial_resistance_drug)) { drug_indices[[i]] <- which(drugs == i) drug_index[i] <- which(parameters$antimalarial_resistance_drug == i) - artemisinin_resistance_proportion[drug_indices[[i]]] <- parameters$prop_artemisinin_resistant[[drug_index[i]]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[drug_index[i]]], - t = timestep)] - early_treatment_failure_probability[drug_indices[[i]]] <- parameters$early_treatment_failure_prob[[drug_index[i]]][match_timestep(ts = parameters$antimalarial_resistance_timesteps[[drug_index[i]]], - t = timestep)] + matched_t <- match_timestep(ts = parameters$antimalarial_resistance_timesteps[[drug_index[i]]], t = timestep) + artemisinin_resistance_proportion[drug_indices[[i]]] <- parameters$prop_artemisinin_resistant[[drug_index[i]]][matched_t] + early_treatment_failure_probability[drug_indices[[i]]] <- parameters$early_treatment_failure_prob[[drug_index[i]]][matched_t] } - susceptible_to_treatment_index <- bernoulli_multi_p(p = 1 - (artemisinin_resistance_proportion * early_treatment_failure_probability)) + + unsuccessful_treatment_probability <- artemisinin_resistance_proportion * early_treatment_failure_probability + susceptible_to_treatment_index <- bernoulli_multi_p(p = 1 - unsuccessful_treatment_probability) drugs <- drugs[susceptible_to_treatment_index] susceptible_to_treatment <- bitset_at(seek_treatment, susceptible_to_treatment_index) - n_ETF <- n_treat - susceptible_to_treatment$size() - renderer$render('n_ETF', n_ETF, timestep) + n_early_treatment_failure <- n_treat - susceptible_to_treatment$size() + renderer$render('n_early_treatment_failure', n_early_treatment_failure, timestep) + } else { susceptible_to_treatment <- seek_treatment - n_ETF <- n_treat - susceptible_to_treatment$size() - renderer$render('n_ETF', n_ETF, timestep) + n_early_treatment_failure <- n_treat - susceptible_to_treatment$size() + renderer$render('n_early_treatment_failure', n_early_treatment_failure, timestep) } successfully_treated_index <- bernoulli_multi_p(parameters$drug_efficacy[drugs]) @@ -346,6 +349,7 @@ calculate_treated <- function( successfully_treated } + #' @title Schedule infections #' @description #' Schedule infections in humans after the incubation period diff --git a/R/model.R b/R/model.R index fb6ffef9..b665861b 100644 --- a/R/model.R +++ b/R/model.R @@ -74,6 +74,10 @@ #' susceptible #' * net_usage: the number people protected by a bed net #' * mosquito_deaths: number of adult female mosquitoes who die this timestep +#' * n_clin_infected: number of new clinically infected individuals in this timestep +#' * n_early_treatment_failure: number of clinically treated individuals who experienced early treatment failure in this timestep +#' * n_treat_eff_fail: number of clinically treated individuals who's treatment failed due to drug efficacy +#' * n_treat_success: number of newly successfully treated individuals in this timestep #' #' @param timesteps the number of timesteps to run the simulation for (in days) #' @param parameters a named list of parameters to use diff --git a/R/parameters.R b/R/parameters.R index 8a96989a..7cc4a39c 100644 --- a/R/parameters.R +++ b/R/parameters.R @@ -192,6 +192,21 @@ #' * tbv_tra_mu - transmission reduction parameter; default = 12.63 #' * tbv_gamma1 - transmission reduction parameter; default = 2.5 #' * tbv_gamma2 - transmission reduction parameter; default = 0.06 +#' +#' Antimalarial resistance parameters: +#' please set antimalarial resistance parameters with the convenience functions in +#' `antimalarial_resistance.R:set_antimalarial_resistance` +#' +#' * antimalarial_resistance - boolean for if antimalarial resistance is enabled; default = FALSE +#' * antimalarial_resistance_drug - vector of drugs for which resistance can be parameterised; default = NULL +#' * antimalarial_resistance_timesteps - vector of time steps on which resistance updates occur; default = NULL +#' * prop_artemisinin_resistant - vector of proportions of infections resistant to the artemisinin component of a given drug; default = NULL +#' * prop_partner_drug_resistant - vector of proportions of infections resistant to the parter drug component of a given drug; default = NULL +#' * slow_parasite_clearance_prob - vector of probabilities of slow parasite clearance for a given drug; default = NULL +#' * early_treatment_failure_prob - vector of probabilities of early treatment failure for a given drug; default = NULL +#' * late_clinical_failure_prob - vector of probabilities of late clinical failure for a given drug; default = NULL +#' * late_parasitological_failure_prob - vector of probabilities of late parasitological failure for a given drug; default = NULL +#' * reinfection_during_prophylaxis - vector of probabilities of reinfection during prophylaxis for a given drug; default = NULL #' #' rendering: #' All values are in timesteps and all ranges are inclusive @@ -377,6 +392,17 @@ get_parameters <- function(overrides = list()) { tbv_timesteps = NULL, tbv_coverages = NULL, tbv_ages = NULL, + # antimalarial resistance + antimalarial_resistance = FALSE, + antimalarial_resistance_drug = NULL, + antimalarial_resistance_timesteps = NULL, + prop_artemisinin_resistant = NULL, + prop_partner_drug_resistant = NULL, + slow_parasite_clearance_prob = NULL, + early_treatment_failure_prob = NULL, + late_clinical_failure_prob = NULL, + late_parasitological_failure_prob = NULL, + reinfection_during_prophylaxis = NULL, # flexible carrying capacity carrying_capacity = FALSE, carrying_capacity_timesteps = NULL, diff --git a/man/get_parameters.Rd b/man/get_parameters.Rd index 54188c01..20459538 100644 --- a/man/get_parameters.Rd +++ b/man/get_parameters.Rd @@ -214,6 +214,22 @@ please set TBV parameters with the convenience functions in \item tbv_gamma2 - transmission reduction parameter; default = 0.06 } +Antimalarial resistance parameters: +please set antimalarial resistance parameters with the convenience functions in +\code{antimalarial_resistance.R:set_antimalarial_resistance} +\itemize{ +\item antimalarial_resistance - boolean for if antimalarial resistance is enabled; default = FALSE +\item antimalarial_resistance_drug - vector of drugs for which resistance can be parameterised; default = NULL +\item antimalarial_resistance_timesteps - vector of time steps on which resistance updates occur; default = NULL +\item prop_artemisinin_resistant - vector of proportions of infections resistant to the artemisinin component of a given drug; default = NULL +\item prop_partner_drug_resistant - vector of proportions of infections resistant to the parter drug component of a given drug; default = NULL +\item slow_parasite_clearance_prob - vector of probabilities of slow parasite clearance for a given drug; default = NULL +\item early_treatment_failure_prob - vector of probabilities of early treatment failure for a given drug; default = NULL +\item late_clinical_failure_prob - vector of probabilities of late clinical failure for a given drug; default = NULL +\item late_parasitological_failure_prob - vector of probabilities of late parasitological failure for a given drug; default = NULL +\item reinfection_during_prophylaxis - vector of probabilities of reinfection during prophylaxis for a given drug; default = NULL +} + rendering: All values are in timesteps and all ranges are inclusive \itemize{ diff --git a/man/run_simulation.Rd b/man/run_simulation.Rd index 64cac9c4..548fbd7e 100644 --- a/man/run_simulation.Rd +++ b/man/run_simulation.Rd @@ -90,5 +90,9 @@ subpatent susceptible \item net_usage: the number people protected by a bed net \item mosquito_deaths: number of adult female mosquitoes who die this timestep +\item n_clin_infected: number of new clinically infected individuals in this timestep +\item n_early_treatment_failure: number of clinically treated individuals who experienced early treatment failure in this timestep +\item n_treat_eff_fail: number of clinically treated individuals who's treatment failed due to drug efficacy +\item n_treat_success: number of newly successfully treated individuals in this timestep } } diff --git a/man/set_antimalarial_resistance.Rd b/man/set_antimalarial_resistance.Rd index ac80d772..0965d7cb 100644 --- a/man/set_antimalarial_resistance.Rd +++ b/man/set_antimalarial_resistance.Rd @@ -20,9 +20,9 @@ set_antimalarial_resistance( \arguments{ \item{parameters}{the model parameters} -\item{drug}{the index of the drug which resistance is being set for in the parameter list} +\item{drug}{the index of the drug which resistance is being set, as set by the set_drugs() function, in the parameter list} -\item{timesteps}{vector of timesteps for each update to resistance proportion and/or phenotype probability} +\item{timesteps}{vector of time steps for each update to resistance proportion and/or phenotype probability} \item{artemisinin_resistance}{vector of updates to the proportions of infections that are artemisinin resistant at time t} @@ -34,7 +34,7 @@ set_antimalarial_resistance( \item{late_clinical_failure_prob}{vector of updates to the proportion of partner-drug-resistant infections that result in late clinical failure} -\item{late_parasitological_prob}{vector of updates to the proportion of partner-drug-resistant infections that result in late parasitologica; failure} +\item{late_parasitological_prob}{vector of updates to the proportion of partner-drug-resistant infections that result in late parasitological failure} \item{reinfection_prob}{vector of updates to the proportion of partner-drug-resistant infections that result in reinfection during prophylaxis} } diff --git a/vignettes/Antimalarial_Resistance.Rmd b/vignettes/Antimalarial_Resistance.Rmd index 94c90fc5..50a34b91 100644 --- a/vignettes/Antimalarial_Resistance.Rmd +++ b/vignettes/Antimalarial_Resistance.Rmd @@ -14,8 +14,246 @@ knitr::opts_chunk$set( ) ``` + ```{r setup} # Load the requisite packages -library(malariasimulation) +#library(malariasimulation) + +# Use devtools to load the updated malariasimulation: +devtools::load_all("C:/Users/trb216/OneDrive - Imperial College London/Desktop/malariasimulation/malariasimulation.Rproj") + +# Set colour palette: +cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") + ``` + +## Introduction +One of the major threats to the continued success of efforts to reduce the burden of malaria is the evolution and spread of resistance to the antimalarial drugs used to treat uncomplicated cases of malaria. The most effective frontline antimalarials are a class of drugs called artemisinin combination therapies. + +## Using set_antimalarial_resistance() to parameterise resistance +Simulations capturing the effects of resistance to clinical treatment using antimalarial drugs are parameterised using the `set_antimalarial_resistance()` function. This function appends user-defined resistance parameters to a `malariasimulation` parameter list and accepts ten inputs. The first is a list of `malariasimulation` parameters to append the resistance parameters to, and the second the index of the `drug` for which resistance is being parameterised as set using the `set_drugs()` function. The `set_antimalarial_resistance()` function requires the `timesteps`, `artemisinin_resistance`, `partner_drug_resistance`, `slow_parasite_clearance_prob`, `early_treatment_failure_prob`, `late_clinical_failure_prob`, `late_parasitological_failure_prob`, and `reinfection_prob` inputs to be of equal length so that, for each timestep in which an update occurs, a value is available for each parameter. + +## Simulating static resistance +To illustrate how to parameterise resistance to a deployed antimalarial using the `set_antimalarial_resistance()` function, we'll set-up and run three simulations. The first simulates malaria transmission in the absence of interventions or resistance. The second simulates a simple regime of clinical treatment in which 80% of clinical cases are treated with artemether lumefantrine (AL), beginning after one year, in the absence of antimalarial resistance. The third simulates the same clinical treatment programme but with resistance to the artemisinin component of AL emerging after two years. For illustrative purposes, we assume that the proportion of infections resistant to the artemisinin component of AL increases from 0% to 80%, and that these infections have a 90% chance of resulting in early treatment failure. + +### Parameterisation +First, we load the default `malariasimulation` model parameters, using the `overrides` argument to increase the human population. The human and mosquito population parameters are then calibrated to a user-specified initial EIR using the `set_equilibrium()` function. Next, we load the in-built parameters for the antimalarial drug AL and append them to the parameter list using `set_drugs()`. We can then use `set_clinical_treatment()` to specify a clinical treatment regime, beginning after one year, that treats, on average, 80% of the clinical cases of malaria with AL. The `set_antimalarial_resistance()` function is then used to specify a scenario in which resistance is initially absent from the population, but after two years the proportion of malaria infections that are resistant to the artemisinin component of AL rises to 80%. We also set the probability that artemisinin-resistant infections result in early treatment failure to 0.9. In the current instance, we've set the proportion of infections resistant to the AL partner drug to 0% and the probabilities of other resistant infection outcomes to zero for simplicity. + +```{r, eval = TRUE} + +# Specify the time steps over which to simulate: +timesteps <- 365 * 3 + +# Specify an initial EIR to calibrate to: +init_EIR <- 8 + +# Specify a time step for treatment to begin +treatment_start <- (1 * 365) + 1 + +# Specify a time step for resistance to emerge: +resistance_start <- (2 * 365) + 1 + +# Load the base malariasimulation parameter set: +simparams <- get_parameters(overrides = list( + human_population = 10000) +) + +# Calibrate to the initial EIR: +simparams <- set_equilibrium(parameters = simparams, init_EIR = init_EIR) + +# Append the parameters for artemether lumefantrine (AL) to the parameter list: +simparams_clin_treatment <- set_drugs(parameters = simparams, drugs = list(AL_params)) + +# Use the set_clinical_treatment() function to specify a treatment regime for AL: +simparams_clin_treatment <- set_clinical_treatment(parameters = simparams_clin_treatment, + drug = 1, + timesteps = treatment_start, + coverages = 0.8) + +# Use the set_antimalarial_resistance() function to specify resistance to SP-AQ: +simparams_resistance <- set_antimalarial_resistance(parameters = simparams_clin_treatment, + drug = 1, + timesteps = c(0, resistance_start), + artemisinin_resistance = c(0, 0.8), + partner_drug_resistance = rep(0, 2), + slow_parasite_clearance_prob = rep(0, 2), + early_treatment_failure_prob = c(0, 0.9), + late_clinical_failure_prob = rep(0, 2), + late_parasitological_prob = rep(0, 2), + reinfection_prob = rep(0, 2)) + +``` + +### Simulation +We can now use the `run_simulation()` to simulate the three scenarios for which we have generated parameter lists above. + +```{r, eval = TRUE} + +# Baseline: No-intervention, no resistance simulation: +sim_out_baseline <- run_simulation(timesteps = timesteps, parameters = simparams) + +# Clinical treatment with no antimalarial drug resistance: +sim_out_clin_treatment <- run_simulation(timesteps = timesteps, parameters = simparams_clin_treatment) + +# Clinical treatment with antimalarial drug resistance: +sim_out_resistance <- run_simulation(timesteps = timesteps, parameters = simparams_resistance) + +``` + +### Visualisation +With the outputs from the `run_simulation()` function, we can visualise the effect of resistance on malaria transmission by plotting the prevalence of malaria in children aged 2-10 years old (*Pf*PR~2-10~) over time. + +```{r, fig.align = 'center', eval = TRUE} + +# In each timestep, calculate PfPR_2-10 and add it to as a new column for each simulation output: +sim_out_baseline$pfpr210 = sim_out_baseline$n_detect_730_3650/sim_out_baseline$n_730_3650 +sim_out_clin_treatment$pfpr210 = sim_out_clin_treatment$n_detect_730_3650/sim_out_clin_treatment$n_730_3650 +sim_out_resistance$pfpr210 = sim_out_resistance$n_detect_730_3650/sim_out_resistance$n_730_3650 + +# Plot the prevalence through time in each of the three simulated scenarios: +plot.new(); par(mar = c(4, 4, 1, 1), new = TRUE) +plot(x = sim_out_baseline$timestep, y = sim_out_baseline$pfpr210, + xlab = "Time (days)", + ylab = expression(paste(italic(Pf),"PR"[2-10])), cex = 0.7, + ylim = c(0, 1), type = "l", lwd = 2, xaxs = "i", yaxs = "i", + col = cols[3]) + +# Add a line for the clinical treatment scenario: +lines(x = sim_out_clin_treatment$timestep, + y = sim_out_clin_treatment$pfpr210, + col = cols[4]) + +# Add a line for the clinical treatment with resistance scenario: +lines(x = sim_out_resistance$timestep, + y = sim_out_resistance$pfpr210, + col = cols[7]) + +# Add lines to indicate the initiation of treatment and resistance +abline(v = treatment_start, lty = "dashed") +abline(v = resistance_start, lty = "dashed") + +# Annotate the added vlines: +text(x = treatment_start + 10, y = 0.9, labels = "Start of\nTreatment", adj = 0, cex = 0.7) +text(x = resistance_start + 10, y = 0.9, labels = "Start of\nResistance", adj = 0, cex = 0.7) + +# Add gridlines: +grid(lty = 2, col = "grey80", nx = NULL, ny = NULL, lwd = 0.5); box() + +# Add a legend: +legend(x = 20, y = 0.99, legend = c("Baseline", "Treatment", "Resistance"), + col= c(cols[3:4], cols[7]), box.col = "white", + lwd = 1, lty = c(1, 1), cex = 0.7) + +``` + +In our example, prevalence is comparable between all three scenarios for the first year in the absence of clinical treatment or resistance. Following the initiation of clinical treatment at the beginning of the second year, *Pf*PR~2-10~ approximately halves relative to the no-intervention baseline. However, following the introduction of artemisinin resistance at the beginning of the third year, prevalence increases to an intermediate level in the resistance scenario. + +## Simulating dynamic resistance +We can also capture scenarios in which resistance to a drug changes through time. To illustrate, we'll establish and simulate a scenario in which resistance to artemether lumefantrine (AL) is absent from the population in the first year, but emerges in the second year and doubles in proportion each year thereafter until 100% of infections are artemisinin resistant. For simplicity, we'll assume only artemisinin resistance is present in the population, and resistance to artemisinin results only, and always, in early treatment failure. + +### Parameterisation +First, we store in vectors the artemisinin resistance proportions and the time steps on which they will be updated in the simulation. We also create a vector of early treatment failure probabilities which, for simplicity, we assume remain at 1 for each update. Next, we load the default `malariasimulation` parameter set, specifying a larger population size and seasonal transmission, and append the parameters for AL using the `set_drugs()` function. We'll specify a simple treatment regimen using `set_clinical_treatment()` where 80% of clinical cases are treated with AL, beginning after one year. We can then specify a resistance schedule in which artemisinin is introduced at a proportion of 0.2 after 3 years, and doubles each year thereafter until all infections are artemisinin resistant. Finally, we calibrate the human and mosquito population parameters to a defined entomological inoculation rate (EIR) and are ready to run the simulation. + +```{r, eval = TRUE} + +# Specify the time steps over which to simulate: +timesteps <- 365 * 8 + +# Set an initial EIR value: +initial_eir <- 8 + +# Specify the proportion of infections that are artemisinin resistant: +resistance_updates <- c(0, 0.2, 0.4, 0.8, 1) + +# Specify the time steps in which to update the resistance parameters: +resistance_update_timesteps <- c(0, seq(3*365, 6*365, by = 365)) + +# Specify the probability artemisinin resistance infections result in early treatment failure: +early_treatment_failure_updates <- rep(1, length(resistance_update_timesteps)) + +# Load the base malariasimulation parameter set, with seasonal transmission: +simparams <- get_parameters(overrides = list( + human_population = 1000, + model_seasonality = TRUE, + g0 = 0.284596, + g = c(-0.317878,-0.0017527,0.116455), + h = c(-0.331361,0.293128,-0.0617547) +)) + +# Append the parameters for artemether lumefantrine (AL) and sulfadomamine pyrimethaine (SP-AQ) to +# the parameter list: +simparams <- set_drugs(parameters = simparams, drugs = list(AL_params)) + +#REMOVE: Set clinical treatment to begin after 1 year +# Use the set_clinical_treatment() function to specify a treatment regime for AL: +simparams <- set_clinical_treatment(parameters = simparams, + drug = 1, + timesteps = 365 * 1, + coverages = 0.8) + +# Use the set_antimalarial_resistance() function to specify resistance to SP-AQ: +simparams <- set_antimalarial_resistance(parameters = simparams, + drug = 1, + timesteps = resistance_update_timesteps, + artemisinin_resistance = resistance_updates, + partner_drug_resistance = rep(0, length(resistance_update_timesteps)), + slow_parasite_clearance_prob = rep(0, length(resistance_update_timesteps)), + early_treatment_failure_prob = early_treatment_failure_updates, + late_clinical_failure_prob = rep(0, length(resistance_update_timesteps)), + late_parasitological_prob = rep(0, length(resistance_update_timesteps)), + reinfection_prob = rep(0, length(resistance_update_timesteps))) + +# Calibrate the parameters to an initial EIR: +simparams <- set_equilibrium(parameters = simparams, init_EIR = initial_eir) + +``` + +### Simulation +We can now use our parameter list to run our simulations using the the `run_simulation()` function. + +```{r, eval = TRUE} + +# Run the simulation: +dynamic_resistance_output <- run_simulation(timesteps = timesteps, parameters = simparams) + +``` + +### Visualisation +We can visualise the effect of increasing resistance by plotting the *Pf*PR~2-10~ through time. We've also added vertical lines to indicate when clinical treatment begins, and when the proportion of infections resistant to artemisinin is updated. + +```{r, fig.align = 'center', eval = TRUE} + +# Calculate the prevalence (PfPR210) through time: +dynamic_resistance_output$pfpr210 <- dynamic_resistance_output$n_detect_730_3650/dynamic_resistance_output$n_730_3650 + +# Open a new plotting window and add a grid: +plot.new(); par(mar = c(4, 4, 1, 1), new = TRUE) +plot(x = dynamic_resistance_output$timestep, + y = dynamic_resistance_output$pfpr210, + xaxt = "n", + xlab = "Time (years)", + ylab = expression(paste(italic(Pf),"PR"[2-10])), cex = 0.8, + ylim = c(0, 1), type = "l", lwd = 2, xaxs = "i", yaxs = "i", + col = cols[3]) + +# Specify x-axis ticks and labels +axis(1, at = seq(0, 8 * 365, by = 365), labels = seq(0, 8 * 365, by = 365)/365) + +# Add a line indicating the start of the clinical treatment +abline(v = 365, lty = "dotted") + +# Add lines indicating when resistance is updated +abline(v = resistance_update_timesteps, lty = "dashed") + +# Add a line highlighting the maximum PfPR_2-10 value prior to treatment or resistance +abline(h = max(dynamic_resistance_output$pfpr210[1:365]), col = "red") + +# Add annotations for the vlines: +text(x = 365 + 30, y = 0.6, labels = "Clin. treat. begins", adj = 0, cex = 0.8, srt = 90) +text(x = resistance_update_timesteps[2:5] + 30, y = 0.6, labels = paste0("Art. Res. = ", resistance_updates[2:5]), + adj = 0, cex = 0.8, srt = 90) + +``` + +Looking at the figure, we can see that the *Pf*PR~2-10~ decreases over the two years following the onset of clinical treatment in the absence of artemisinin resistance. However, as resistance is introduced and increases through time, the *Pf*PR~2-10~ increases towards the pre-intervention seasonal peak as AL becomes increasingly ineffective in treating clinical cases of malaria. From 11e61e15e386fde957a821923a9390cf2c0f744d Mon Sep 17 00:00:00 2001 From: tbreweric Date: Tue, 10 Oct 2023 12:07:29 +0100 Subject: [PATCH 146/164] Commiting the final set of changes and corrections in response to comments on the first PR request --- R/antimalarial_resistance.R | 4 +- R/human_infection.R | 5 +- man/set_antimalarial_resistance.Rd | 2 +- tests/testthat/test-antimalarial-resistance.R | 112 ++++++++---------- tests/testthat/test-infection-integration.R | 85 ++++++++++--- vignettes/Antimalarial_Resistance.Rmd | 69 ++++++----- 6 files changed, 163 insertions(+), 114 deletions(-) diff --git a/R/antimalarial_resistance.R b/R/antimalarial_resistance.R index d84d9641..9d6e7dfe 100644 --- a/R/antimalarial_resistance.R +++ b/R/antimalarial_resistance.R @@ -30,7 +30,7 @@ set_antimalarial_resistance <- function(parameters, length(late_clinical_failure_prob), length(late_parasitological_prob), length(reinfection_prob)) != length(timesteps))) { - stop("Number of resistance parameter vectors do not match time steps specified for update") + stop("Length of one or more resistance parameter vectors does not match time steps specified for update") } # Ensure resistance proportions bounded between 0 and 1: @@ -59,7 +59,7 @@ set_antimalarial_resistance <- function(parameters, stop('Drug index is invalid, please set drugs using set_drugs') } - # Check the drug_index for the we're drug setting parameters for: + # Check the drug_index for the drug we're setting parameters for: drug_index <- which(parameters$antimalarial_resistance_drug == drug) # If drug_index not already assigned, assign the drug the next available index: diff --git a/R/human_infection.R b/R/human_infection.R index 9bb8e565..a17dad8f 100644 --- a/R/human_infection.R +++ b/R/human_infection.R @@ -326,6 +326,7 @@ calculate_treated <- function( successfully_treated_index <- bernoulli_multi_p(parameters$drug_efficacy[drugs]) successfully_treated <- bitset_at(susceptible_to_treatment, successfully_treated_index) + successfully_treated_drugs <- drugs[successfully_treated_index] n_treat_eff_fail <- susceptible_to_treatment$size() - length(successfully_treated_index) renderer$render('n_treat_eff_fail', n_treat_eff_fail, timestep) renderer$render('n_treat_success', successfully_treated$size(), timestep) @@ -334,11 +335,11 @@ calculate_treated <- function( if (successfully_treated$size() > 0) { variables$state$queue_update("Tr", successfully_treated) variables$infectivity$queue_update( - parameters$cd * parameters$drug_rel_c[drugs[successfully_treated_index]], + parameters$cd * parameters$drug_rel_c[successfully_treated_drugs], successfully_treated ) variables$drug$queue_update( - drugs[successfully_treated_index], + successfully_treated_drugs, successfully_treated ) variables$drug_time$queue_update( diff --git a/man/set_antimalarial_resistance.Rd b/man/set_antimalarial_resistance.Rd index 0965d7cb..30b31433 100644 --- a/man/set_antimalarial_resistance.Rd +++ b/man/set_antimalarial_resistance.Rd @@ -22,7 +22,7 @@ set_antimalarial_resistance( \item{drug}{the index of the drug which resistance is being set, as set by the set_drugs() function, in the parameter list} -\item{timesteps}{vector of time steps for each update to resistance proportion and/or phenotype probability} +\item{timesteps}{vector of time steps for each update to resistance proportion and resistance outcome probability} \item{artemisinin_resistance}{vector of updates to the proportions of infections that are artemisinin resistant at time t} diff --git a/tests/testthat/test-antimalarial-resistance.R b/tests/testthat/test-antimalarial-resistance.R index 9250bc4e..c0e47edb 100644 --- a/tests/testthat/test-antimalarial-resistance.R +++ b/tests/testthat/test-antimalarial-resistance.R @@ -37,7 +37,7 @@ test_that('set_antimalarial_resistance() errors if parameter inputs of different reinfection_prob = 0.4)) }) -test_that('set_antimalarial_resistance() errors if resistance proportions outside bound of 0-1', { +test_that('set_antimalarial_resistance() errors if resistance proportions outside of range 0-1', { simparams <- get_parameters() simparams <- set_drugs(parameters = simparams, drugs = list(SP_AQ_params)) simparams <- set_clinical_treatment(parameters = simparams, @@ -53,7 +53,8 @@ test_that('set_antimalarial_resistance() errors if resistance proportions outsid early_treatment_failure_prob = 0.6, late_clinical_failure_prob = 0.2, late_parasitological_prob = 0.3, - reinfection_prob = 0.4)) + reinfection_prob = 0.4), + regexp = "Artemisinin and partner-drug resistance proportions must fall between 0 and 1") }) test_that('set_antimalarial_resistance() errors if resistance phenotype probabilities outside bound of 0-1', { @@ -94,68 +95,53 @@ test_that('set_antimalarial_resistance() errors if drug index > than number of d reinfection_prob = 0.4)) }) -test_that('set_antimalarial_resistance() assigns parameters correctly despite drug order', { - - # Randomly assign the order of the drug assignment in clinical treatment and resistance: - clinical_treatment_drugs <- sample.int(n = 3, size = 3, replace = FALSE) - antimalarial_resistance_drugs <- sample.int(n = 3, size = 3, replace = FALSE) - - # Randomly assign drug coverages for clinical treatment: - clinical_treatment_coverages <- sample(c(0.1, 0.2, 0.4)) - - # Randomly assign timesteps for clinical treatment and resistance: - clinical_treatment_timesteps <- sample.int(n = 100, size = 3, replace = FALSE) - antimalarial_resistance_timesteps <- sample.int(n = 100, size = 3, replace = FALSE) - - # Randomly assign values to antimalarial resistance proportions - antimalarial_resistance_artemisinin_proportion <- sample(x = seq(0, 0.33, by = 0.01), size = 3, replace = FALSE) - antimalarial_resistance_partner_drug_proportion <- sample(x = seq(0, 0.33, by = 0.01), size = 3, replace = FALSE) - - # Randomly assign values to antimalarial resistance probabilities: - antimalarial_resistance_ETF_probability <- sample(x = seq(0, 0.33, by = 0.01), size = 3, replace = FALSE) - antimalarial_resistance_SPC_probability <- sample(x = seq(0, 0.33, by = 0.01), size = 3, replace = FALSE) - antimalarial_resistance_LCF_probability <- sample(x = seq(0, 0.33, by = 0.01), size = 3, replace = FALSE) - antimalarial_resistance_LPF_probability <- sample(x = seq(0, 0.33, by = 0.01), size = 3, replace = FALSE) - antimalarial_resistance_RDP_probability <- sample(x = seq(0, 0.33, by = 0.01), size = 3, replace = FALSE) - - # Establish some parameters - simparams <- get_parameters() - - # Add the three drug parameter vectors to the parameter list: - simparams <- set_drugs(parameters = simparams, drugs = list(AL_params, SP_AQ_params, DHA_PQP_params)) - - # Loop through and assign the parameters for each drug - for(i in seq(clinical_treatment_drugs)) { - simparams <- set_clinical_treatment(parameters = simparams, - drug = clinical_treatment_drugs[i], - timesteps = clinical_treatment_timesteps[i], - coverages = clinical_treatment_coverages[i]) - } +test_that('set_antimalarial_resistance() assigns parameters correctly despite order in which resistance parameters are specified', { - # Loop through and assign the antimalarial resistance parameters for each drug: - for(i in seq(antimalarial_resistance_drugs)) { - simparams <- set_antimalarial_resistance(parameters = simparams, - drug = antimalarial_resistance_drugs[i], - timesteps = antimalarial_resistance_timesteps[i], - artemisinin_resistance = antimalarial_resistance_artemisinin_proportion[i], - partner_drug_resistance = antimalarial_resistance_partner_drug_proportion[i], - slow_parasite_clearance_prob = antimalarial_resistance_SPC_probability[i], - early_treatment_failure_prob = antimalarial_resistance_ETF_probability[i], - late_clinical_failure_prob = antimalarial_resistance_LCF_probability[i], - late_parasitological_prob = antimalarial_resistance_LPF_probability[i], - reinfection_prob = antimalarial_resistance_RDP_probability[i]) - } + parameters <- get_parameters() + parameters <- set_drugs(parameters = parameters, drugs = list(AL_params, SP_AQ_params, DHA_PQP_params)) + parameters <- set_clinical_treatment(parameters = parameters, drug = 2, timesteps = 1, coverages = 0.2) + parameters <- set_clinical_treatment(parameters = parameters, drug = 1, timesteps = 1, coverages = 0.1) + parameters <- set_clinical_treatment(parameters = parameters, drug = 3, timesteps = 1, coverages = 0.4) + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 2, + timesteps = 1, + artemisinin_resistance = 0.5, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0.41, + early_treatment_failure_prob = 0.2, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0) + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 3, + timesteps = 1, + artemisinin_resistance = 0, + partner_drug_resistance = 0.43, + slow_parasite_clearance_prob = 0, + early_treatment_failure_prob = 0, + late_clinical_failure_prob = 0.01, + late_parasitological_prob = 0.42, + reinfection_prob = 0.89) + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 1, + timesteps = 1, + artemisinin_resistance = 0.27, + partner_drug_resistance = 0.61, + slow_parasite_clearance_prob = 0.23, + early_treatment_failure_prob = 0.9, + late_clinical_failure_prob = 0.49, + late_parasitological_prob = 0.81, + reinfection_prob = 0.009) - # Check the antimalarial resistance parameters after assignment using set_antimalarial_resistance(): - expect_identical(simparams$antimalarial_resistance, TRUE) - expect_identical(unlist(simparams$antimalarial_resistance_drug), antimalarial_resistance_drugs) - expect_identical(unlist(simparams$antimalarial_resistance_timesteps), antimalarial_resistance_timesteps) - expect_identical(unlist(simparams$prop_artemisinin_resistant), antimalarial_resistance_artemisinin_proportion) - expect_identical(unlist(simparams$prop_partner_drug_resistant), antimalarial_resistance_partner_drug_proportion) - expect_identical(unlist(simparams$slow_parasite_clearance_prob), antimalarial_resistance_SPC_probability) - expect_identical(unlist(simparams$early_treatment_failure_prob), antimalarial_resistance_ETF_probability) - expect_identical(unlist(simparams$late_clinical_failure_prob), antimalarial_resistance_LCF_probability) - expect_identical(unlist(simparams$late_parasitological_failure_prob), antimalarial_resistance_LPF_probability) - expect_identical(unlist(simparams$reinfection_during_prophylaxis), antimalarial_resistance_RDP_probability) + expect_identical(parameters$antimalarial_resistance, TRUE) + expect_identical(unlist(parameters$antimalarial_resistance_drug), c(2, 3, 1)) + expect_identical(unlist(parameters$antimalarial_resistance_timesteps), rep(1, 3)) + expect_identical(unlist(parameters$prop_artemisinin_resistant), c(0.5, 0, 0.27)) + expect_identical(unlist(parameters$prop_partner_drug_resistant), c(0, 0.43, 0.61)) + expect_identical(unlist(parameters$slow_parasite_clearance_prob), c(0.41, 0, 0.23)) + expect_identical(unlist(parameters$early_treatment_failure_prob), c(0.2, 0, 0.9)) + expect_identical(unlist(parameters$late_clinical_failure_prob), c(0, 0.01, 0.49)) + expect_identical(unlist(parameters$late_parasitological_failure_prob), c(0, 0.42, 0.81)) + expect_identical(unlist(parameters$reinfection_during_prophylaxis), c(0, 0.89, 0.009)) }) diff --git a/tests/testthat/test-infection-integration.R b/tests/testthat/test-infection-integration.R index 00f29f0d..e169b1af 100644 --- a/tests/testthat/test-infection-integration.R +++ b/tests/testthat/test-infection-integration.R @@ -252,6 +252,70 @@ test_that('calculate_clinical_infections correctly samples clinically infected', }) test_that('calculate_treated correctly samples treated and updates the drug state', { + parameters <- get_parameters() + parameters <- set_drugs(parameters, list(AL_params, DHA_PQP_params)) + parameters <- set_clinical_treatment(parameters, 1, 1, .25) + parameters <- set_clinical_treatment(parameters, 2, 1, .25) + timestep <- 5 + events <- create_events(parameters) + variables <- list( + state = list(queue_update = mockery::mock()), + infectivity = list(queue_update = mockery::mock()), + drug = list(queue_update = mockery::mock()), + drug_time = list(queue_update = mockery::mock()) + ) + + recovery_mock <- mockery::mock() + mockery::stub(calculate_treated, 'recovery$schedule', recovery_mock) + + seek_treatment <- individual::Bitset$new(4)$insert(c(1, 2, 4)) + mockery::stub( + calculate_treated, + 'sample_bitset', + mockery::mock(seek_treatment) + ) + sample_mock <- mockery::mock(c(2, 1, 1, 1)) + mockery::stub(calculate_treated, 'sample.int', sample_mock) + bernoulli_mock <- mockery::mock(c(1, 3)) + mockery::stub(calculate_treated, 'bernoulli_multi_p', bernoulli_mock) + mockery::stub(calculate_treated, 'log_uniform', mockery::mock(c(3, 4))) + + clinical_infections <- individual::Bitset$new(4) + clinical_infections$insert(c(1, 2, 3, 4)) + calculate_treated( + variables, + clinical_infections, + parameters, + timestep, + mock_render(timestep) + ) + + mockery::expect_args( + sample_mock, + 1, + 2, + 3, + c(.25, .25), + TRUE + ) + + mockery::expect_args( + bernoulli_mock, + 1, + parameters$drug_efficacy[c(2, 1, 1, 1)] + ) + + expect_bitset_update(variables$state$queue_update, 'Tr', c(1, 4)) + expect_bitset_update( + variables$infectivity$queue_update, + parameters$cd * parameters$drug_rel_c[c(2, 1)], + c(1, 4) + ) + expect_bitset_update(variables$drug$queue_update, c(2, 1), c(1, 4)) + expect_bitset_update(variables$drug_time$queue_update, 5, c(1, 4)) +}) + +test_that('calculate_treated correctly samples treated and updates the drug state when resistance set', { parameters <- get_parameters() parameters <- set_drugs(parameters = parameters, drugs = list(AL_params, SP_AQ_params)) @@ -594,11 +658,9 @@ test_that('calculate_treated returns empty Bitset when there is no clinical trea expect_identical(object = treated$size(), expected = 0, info = "Error: calculate_treated() returning non-zero number of treated individuals in the absence of clinical treatment") - expect_identical(object = treated$to_vector(), expected = numeric(0), info = "Error: calculate_treated() returning non-zero number of treated individuals - in the absence of clinical treatment") }) -test_that(desc = 'calculate_treated returns empty Bitset when the clinically_infected input is an empty Bitset', { +test_that('calculate_treated returns empty Bitset when the clinically_infected input is an empty Bitset', { parameters <- get_parameters() parameters <- set_drugs(parameters = parameters, drugs = list(AL_params)) parameters <- set_clinical_treatment(parameters = parameters, drug = 1, timesteps = 1, coverages = 1) @@ -631,8 +693,6 @@ test_that(desc = 'calculate_treated returns empty Bitset when the clinically_inf expect_identical(object = treated$size(), expected = 0, info = "Error: calculate_treated() returning non-zero number of treated individuals in the absence of clinically infected individuals") - expect_identical(object = treated$to_vector(), expected = numeric(0), info = "Error: calculate_treated() returning non-zero number of treated individuals - in the absence of clinically infected individuals") }) test_that('calculate_treated() returns an empty Bitset when the parameter list contains no clinical @@ -657,11 +717,10 @@ test_that('calculate_treated() returns an empty Bitset when the parameter list c expect_identical(object = treated$size(), expected = 0, info = "Error: calculate_treated() returning non-zero number of treated individuals in the absence of clinical treatment or resistance parameters") - expect_identical(object = treated$to_vector(), expected = numeric(0), info = "Error: calculate_treated() returning non-zero number of treated individuals - in the absence of clinical treatment or resistance parameters") - }) +}) -test_that('calculate_treated() returns an empty Bitset when all treatment fails due to early treatment failure', { +test_that('Number of treatment failures matches number of individuals treated when artemisinin resistance proportion and + early treatment failure probability both set to 1', { parameters <- get_parameters() parameters <- set_drugs(parameters = parameters, drugs = list(AL_params, SP_AQ_params)) parameters <- set_clinical_treatment(parameters = parameters, @@ -708,9 +767,7 @@ test_that('calculate_treated() returns an empty Bitset when all treatment fails timestep = timestep, renderer = renderer) - expect_identical(object = treated$size(), expected = 0, info = "Error: non-zero length treated Bitset when clinical treatment coverage = 1, - artemisinin resistance = 1, and early treatment probability = 1") - expect_identical(renderer$to_dataframe()[timestep,'n_ETF'], renderer$to_dataframe()[timestep,'n_treated'], info = "Error: Number of + expect_identical(renderer$to_dataframe()[timestep,'n_early_treatment_failure'], renderer$to_dataframe()[timestep,'n_treated'], info = "Error: Number of early treatment failures does not match number of treated individuals when artemisinin resistance proportion and and early treatment failure probability both equal 1") }) @@ -747,8 +804,8 @@ test_that('calculate_treated() successfully adds additional resistance columns t timestep = timestep, renderer = renderer) - calculate_treated_column_names <- c("n_clin_infected", "ft", "n_treated", "n_ETF", "n_treat_eff_fail", "n_treat_success") + calculate_treated_column_names <- c("n_clin_infected", "ft", "n_treated", "n_early_treatment_failure", "n_treat_eff_fail", "n_treat_success") expect_identical(sum(calculate_treated_column_names %in% colnames(renderer$to_dataframe())), length(calculate_treated_column_names), "calculate_treated() not renderering all resistance columns when resistance is present, clinical treatment coverage is non-zero, and the Bitset of clinically_infected individuals input is of non-zero length.") -}) \ No newline at end of file +}) diff --git a/vignettes/Antimalarial_Resistance.Rmd b/vignettes/Antimalarial_Resistance.Rmd index 50a34b91..5730ae99 100644 --- a/vignettes/Antimalarial_Resistance.Rmd +++ b/vignettes/Antimalarial_Resistance.Rmd @@ -17,7 +17,7 @@ knitr::opts_chunk$set( ```{r setup} -# Load the requisite packages +# Load the requisite packages: #library(malariasimulation) # Use devtools to load the updated malariasimulation: @@ -29,16 +29,18 @@ cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55 ``` ## Introduction -One of the major threats to the continued success of efforts to reduce the burden of malaria is the evolution and spread of resistance to the antimalarial drugs used to treat uncomplicated cases of malaria. The most effective frontline antimalarials are a class of drugs called artemisinin combination therapies. +One of the major threats to the continued success of efforts to reduce the burden of malaria is the evolution and spread of resistance to the antimalarial drugs used to treat uncomplicated cases of malaria. The most effective frontline antimalarials are a class of drugs called artemisinin combination therapies (ACTs). ACTs combine a fast-acting, short-lived artemisinin derivative (e.g. artemether), with a slower-acting, longer-lasting partner drug (e.g. lumefantrine) that clears the remaining parasites from the patient's system. Efforts to understand the effect of resistance to ACTs on malaria morbidity and mortality, and to develop strategies to control or mitigate the spread of resistance, would benefit from insights derived from mathematical modelling. Building on the model developed by Slater et al. (2016), `malariasimulation` provides the functionality to simulate the effects of resistance to the artemisinin and/or partner drug components to multiple, independent ACTs, on malaria transmission dynamics. + +Resistance to the artemisinin component of an ACT can result either in slow parasite clearance (SPC), in which treatment with an ACT takes longer than 3 days to fully clear patients with resistant parasites, or early treatment failure (ETF), in which the ACT fails to clear the infection and the individual develops a clinical infection. Resistance to the partner drug, where the partner drug fails to clear the parasite after the artemisinin derivative is depleted, results in infections recrudescing to either clinical (D) or asymptomatic infections (A). Resistance to the partner drug can also result in individuals developing a novel, resistant infection following treatment, as the prophylaxis provided by the ACT fails to protect the individual against reinfection by a resistant strain. In the following vignette, we illustrate how to parameterise and run `malariasimulation` simulations with resistance to ACTs deployed as a clinical treatment ## Using set_antimalarial_resistance() to parameterise resistance -Simulations capturing the effects of resistance to clinical treatment using antimalarial drugs are parameterised using the `set_antimalarial_resistance()` function. This function appends user-defined resistance parameters to a `malariasimulation` parameter list and accepts ten inputs. The first is a list of `malariasimulation` parameters to append the resistance parameters to, and the second the index of the `drug` for which resistance is being parameterised as set using the `set_drugs()` function. The `set_antimalarial_resistance()` function requires the `timesteps`, `artemisinin_resistance`, `partner_drug_resistance`, `slow_parasite_clearance_prob`, `early_treatment_failure_prob`, `late_clinical_failure_prob`, `late_parasitological_failure_prob`, and `reinfection_prob` inputs to be of equal length so that, for each timestep in which an update occurs, a value is available for each parameter. +Simulations capturing the effects of resistance to clinical treatment using antimalarial drugs are parameterised using the `set_antimalarial_resistance()` function. This function appends user-defined resistance parameters to a `malariasimulation` parameter list and accepts ten inputs. The first is a list of `malariasimulation` parameters to append the resistance parameters to, and the second the index of the `drug` for which resistance is being parameterised, as set using the `set_drugs()` function. The `set_antimalarial_resistance()` function requires the `timesteps`, `artemisinin_resistance`, `partner_drug_resistance`, `slow_parasite_clearance_prob`, `early_treatment_failure_prob`, `late_clinical_failure_prob`, `late_parasitological_failure_prob`, and `reinfection_prob` inputs to be of equal length so that, for each time step in which an update occurs, a value is available for each parameter. ## Simulating static resistance -To illustrate how to parameterise resistance to a deployed antimalarial using the `set_antimalarial_resistance()` function, we'll set-up and run three simulations. The first simulates malaria transmission in the absence of interventions or resistance. The second simulates a simple regime of clinical treatment in which 80% of clinical cases are treated with artemether lumefantrine (AL), beginning after one year, in the absence of antimalarial resistance. The third simulates the same clinical treatment programme but with resistance to the artemisinin component of AL emerging after two years. For illustrative purposes, we assume that the proportion of infections resistant to the artemisinin component of AL increases from 0% to 80%, and that these infections have a 90% chance of resulting in early treatment failure. +To illustrate how to parameterise resistance to an ACT using the `set_antimalarial_resistance()` function, we'll set-up and run three simulations. The first simulates malaria transmission in the absence of interventions or resistance. The second simulates a simple regime of clinical treatment in which 80% of clinical cases are treated with artemether lumefantrine (AL), beginning after one year, in the absence of antimalarial resistance. The third simulates the same clinical treatment programme but with resistance to the artemisinin component of AL emerging after two years. For illustrative purposes, we assume that the proportion of infections resistant to the artemisinin component of AL increases from 0% to 80%, and that these infections have a 90% chance of resulting in early treatment failure. ### Parameterisation -First, we load the default `malariasimulation` model parameters, using the `overrides` argument to increase the human population. The human and mosquito population parameters are then calibrated to a user-specified initial EIR using the `set_equilibrium()` function. Next, we load the in-built parameters for the antimalarial drug AL and append them to the parameter list using `set_drugs()`. We can then use `set_clinical_treatment()` to specify a clinical treatment regime, beginning after one year, that treats, on average, 80% of the clinical cases of malaria with AL. The `set_antimalarial_resistance()` function is then used to specify a scenario in which resistance is initially absent from the population, but after two years the proportion of malaria infections that are resistant to the artemisinin component of AL rises to 80%. We also set the probability that artemisinin-resistant infections result in early treatment failure to 0.9. In the current instance, we've set the proportion of infections resistant to the AL partner drug to 0% and the probabilities of other resistant infection outcomes to zero for simplicity. +First, we load the default `malariasimulation` model parameters, using the `overrides` argument to increase the human population. The human and mosquito population parameters are then calibrated to a user-specified initial EIR using the `set_equilibrium()` function. Next, we load the in-built parameters for the antimalarial drug AL and append them to the parameter list using `set_drugs()`. We can then use `set_clinical_treatment()` to specify a clinical treatment regime, beginning after one year, that treats, on average, 80% of the clinical cases of malaria with AL (`AL_params`). The `set_antimalarial_resistance()` function is then used to specify a scenario in which resistance is initially absent from the population, but after two years the proportion of malaria infections that are resistant to the artemisinin component of AL rises to 80%. We also set the probability that artemisinin-resistant infections result in early treatment failure to 0.9. In the current instance, we've set the proportion of infections resistant to the AL partner drug to 0% and the probabilities of other resistant infection outcomes to zero for simplicity. ```{r, eval = TRUE} @@ -48,15 +50,16 @@ timesteps <- 365 * 3 # Specify an initial EIR to calibrate to: init_EIR <- 8 -# Specify a time step for treatment to begin +# Specify a time step for treatment to begin: treatment_start <- (1 * 365) + 1 # Specify a time step for resistance to emerge: resistance_start <- (2 * 365) + 1 # Load the base malariasimulation parameter set: -simparams <- get_parameters(overrides = list( - human_population = 10000) +simparams <- get_parameters( + overrides = list( + human_population = 10000) ) # Calibrate to the initial EIR: @@ -71,7 +74,7 @@ simparams_clin_treatment <- set_clinical_treatment(parameters = simparams_clin_t timesteps = treatment_start, coverages = 0.8) -# Use the set_antimalarial_resistance() function to specify resistance to SP-AQ: +# Use the set_antimalarial_resistance() function to specify resistance to AL: simparams_resistance <- set_antimalarial_resistance(parameters = simparams_clin_treatment, drug = 1, timesteps = c(0, resistance_start), @@ -86,7 +89,7 @@ simparams_resistance <- set_antimalarial_resistance(parameters = simparams_clin_ ``` ### Simulation -We can now use the `run_simulation()` to simulate the three scenarios for which we have generated parameter lists above. +We can now use the `run_simulation()` to simulate the three scenarios for which we have established parameter lists above. ```{r, eval = TRUE} @@ -129,7 +132,7 @@ lines(x = sim_out_resistance$timestep, y = sim_out_resistance$pfpr210, col = cols[7]) -# Add lines to indicate the initiation of treatment and resistance +# Add lines to indicate the initiation of treatment and resistance: abline(v = treatment_start, lty = "dashed") abline(v = resistance_start, lty = "dashed") @@ -147,13 +150,13 @@ legend(x = 20, y = 0.99, legend = c("Baseline", "Treatment", "Resistance"), ``` -In our example, prevalence is comparable between all three scenarios for the first year in the absence of clinical treatment or resistance. Following the initiation of clinical treatment at the beginning of the second year, *Pf*PR~2-10~ approximately halves relative to the no-intervention baseline. However, following the introduction of artemisinin resistance at the beginning of the third year, prevalence increases to an intermediate level in the resistance scenario. +In the absence of clinical treatment or resistance, prevalence is comparable between all three scenarios for the first year. Following the initiation of clinical treatment at the beginning of the second year, *Pf*PR~2-10~ approximately halves relative to the no-intervention baseline. However, following the introduction of artemisinin resistance at the beginning of the third year, early treatment failure causes the *Pf*PR~2-10~ to increase to an intermediate level in the resistance scenario. ## Simulating dynamic resistance -We can also capture scenarios in which resistance to a drug changes through time. To illustrate, we'll establish and simulate a scenario in which resistance to artemether lumefantrine (AL) is absent from the population in the first year, but emerges in the second year and doubles in proportion each year thereafter until 100% of infections are artemisinin resistant. For simplicity, we'll assume only artemisinin resistance is present in the population, and resistance to artemisinin results only, and always, in early treatment failure. +We can also capture scenarios in which resistance to a drug changes through time. To illustrate, we'll establish and simulate a scenario in which resistance to sulfadoxine-pyrimethamine amodiaquine (SP-AQ) is absent from the population in the first year, but emerges in the third year and doubles in proportion each year thereafter until 100% of infections are artemisinin resistant. For simplicity, we'll assume only artemisinin resistance is present in the population, and resistance to artemisinin results only, and always, in early treatment failure. ### Parameterisation -First, we store in vectors the artemisinin resistance proportions and the time steps on which they will be updated in the simulation. We also create a vector of early treatment failure probabilities which, for simplicity, we assume remain at 1 for each update. Next, we load the default `malariasimulation` parameter set, specifying a larger population size and seasonal transmission, and append the parameters for AL using the `set_drugs()` function. We'll specify a simple treatment regimen using `set_clinical_treatment()` where 80% of clinical cases are treated with AL, beginning after one year. We can then specify a resistance schedule in which artemisinin is introduced at a proportion of 0.2 after 3 years, and doubles each year thereafter until all infections are artemisinin resistant. Finally, we calibrate the human and mosquito population parameters to a defined entomological inoculation rate (EIR) and are ready to run the simulation. +First, we store in vectors the artemisinin resistance proportions and the time steps on which they will be updated in the simulation. We also create a vector of early treatment failure probabilities which, for simplicity, we assume remain at 1 for each update. Next, we load the default `malariasimulation` parameter set, specifying a larger population size and seasonal transmission, and append the parameters for SP-AQ (`SP_AQ_params`) using the `set_drugs()` function. We'll specify a simple treatment regimen using `set_clinical_treatment()` where, on average, 80% of clinical cases are treated with SP-AQ, beginning after one year. We then specify a resistance schedule in which artemisinin resistance is introduced at a proportion of 0.2 after 3 years, and doubles each year thereafter until all infections are artemisinin resistant. Finally, we calibrate the human and mosquito population parameters to a defined entomological inoculation rate (EIR) and are ready to run the simulation. ```{r, eval = TRUE} @@ -173,20 +176,19 @@ resistance_update_timesteps <- c(0, seq(3*365, 6*365, by = 365)) early_treatment_failure_updates <- rep(1, length(resistance_update_timesteps)) # Load the base malariasimulation parameter set, with seasonal transmission: -simparams <- get_parameters(overrides = list( - human_population = 1000, - model_seasonality = TRUE, - g0 = 0.284596, - g = c(-0.317878,-0.0017527,0.116455), - h = c(-0.331361,0.293128,-0.0617547) +simparams <- get_parameters( + overrides = list( + human_population = 1000, + model_seasonality = TRUE, + g0 = 0.284596, + g = c(-0.317878,-0.0017527,0.116455), + h = c(-0.331361,0.293128,-0.0617547) )) -# Append the parameters for artemether lumefantrine (AL) and sulfadomamine pyrimethaine (SP-AQ) to -# the parameter list: -simparams <- set_drugs(parameters = simparams, drugs = list(AL_params)) +# Append the parameters for sulfadomamine pyrimethaine (SP-AQ) to the parameter list: +simparams <- set_drugs(parameters = simparams, drugs = list(SP_AQ_params)) -#REMOVE: Set clinical treatment to begin after 1 year -# Use the set_clinical_treatment() function to specify a treatment regime for AL: +# Use the set_clinical_treatment() function to specify a treatment regime for SP-AQ: simparams <- set_clinical_treatment(parameters = simparams, drug = 1, timesteps = 365 * 1, @@ -210,7 +212,7 @@ simparams <- set_equilibrium(parameters = simparams, init_EIR = initial_eir) ``` ### Simulation -We can now use our parameter list to run our simulations using the the `run_simulation()` function. +We can now use our parameter list to run the simulation using the the `run_simulation()` function. ```{r, eval = TRUE} @@ -220,7 +222,7 @@ dynamic_resistance_output <- run_simulation(timesteps = timesteps, parameters = ``` ### Visualisation -We can visualise the effect of increasing resistance by plotting the *Pf*PR~2-10~ through time. We've also added vertical lines to indicate when clinical treatment begins, and when the proportion of infections resistant to artemisinin is updated. +We can visualise the effect of increasing resistance through time by plotting the *Pf*PR~2-10~. We've added vertical lines to indicate when clinical treatment begins, and when the proportion of infections resistant to artemisinin is updated. ```{r, fig.align = 'center', eval = TRUE} @@ -237,16 +239,16 @@ plot(x = dynamic_resistance_output$timestep, ylim = c(0, 1), type = "l", lwd = 2, xaxs = "i", yaxs = "i", col = cols[3]) -# Specify x-axis ticks and labels +# Specify x-axis ticks and labels: axis(1, at = seq(0, 8 * 365, by = 365), labels = seq(0, 8 * 365, by = 365)/365) -# Add a line indicating the start of the clinical treatment +# Add a line indicating the start of the clinical treatment: abline(v = 365, lty = "dotted") -# Add lines indicating when resistance is updated +# Add lines indicating when resistance is updated: abline(v = resistance_update_timesteps, lty = "dashed") -# Add a line highlighting the maximum PfPR_2-10 value prior to treatment or resistance +# Add a line highlighting the maximum PfPR_2-10 value prior to treatment or resistance: abline(h = max(dynamic_resistance_output$pfpr210[1:365]), col = "red") # Add annotations for the vlines: @@ -256,4 +258,7 @@ text(x = resistance_update_timesteps[2:5] + 30, y = 0.6, labels = paste0("Art. R ``` -Looking at the figure, we can see that the *Pf*PR~2-10~ decreases over the two years following the onset of clinical treatment in the absence of artemisinin resistance. However, as resistance is introduced and increases through time, the *Pf*PR~2-10~ increases towards the pre-intervention seasonal peak as AL becomes increasingly ineffective in treating clinical cases of malaria. +Looking at the figure, we can see that the *Pf*PR~2-10~ decreases over the two years following the onset of clinical treatment in the absence of artemisinin resistance. However, as resistance is introduced and increases through time, the *Pf*PR~2-10~ increases towards the pre-intervention seasonal peak as SP-AQ becomes increasingly ineffective in the treatment of clinical cases of malaria. + +## References +Slater, H.C., Griffin, J.T., Ghani, A.C. and Okell, L.C., 2016. Assessing the potential impact of artemisinin and partner drug resistance in sub-Saharan Africa. Malaria journal, 15(1), pp.1-11. \ No newline at end of file From de29495ea93aa7186882a1d6738a4084d56e1470 Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Thu, 8 Feb 2024 18:04:54 +0000 Subject: [PATCH 147/164] Implemented the second round of changes requested in the pull request --- tests/testthat/test-antimalarial-resistance.R | 189 +++++++++++++++++- tests/testthat/test-infection-integration.R | 157 ++++++++++++++- 2 files changed, 331 insertions(+), 15 deletions(-) diff --git a/tests/testthat/test-antimalarial-resistance.R b/tests/testthat/test-antimalarial-resistance.R index c0e47edb..400d93a3 100644 --- a/tests/testthat/test-antimalarial-resistance.R +++ b/tests/testthat/test-antimalarial-resistance.R @@ -14,7 +14,8 @@ test_that('set_antimalarial_resistance() toggles resistance on', { early_treatment_failure_prob = 0.6, late_clinical_failure_prob = 0.2, late_parasitological_prob = 0.3, - reinfection_prob = 0.4) -> simparams + reinfection_prob = 0.4, + slow_parasite_clearance_time = 10) -> simparams expect_identical(object = simparams$antimalarial_resistance, expected = TRUE) }) @@ -34,7 +35,8 @@ test_that('set_antimalarial_resistance() errors if parameter inputs of different early_treatment_failure_prob = 0.6, late_clinical_failure_prob = 0.2, late_parasitological_prob = 0.3, - reinfection_prob = 0.4)) + reinfection_prob = 0.4, + slow_parasite_clearance_time = 10)) }) test_that('set_antimalarial_resistance() errors if resistance proportions outside of range 0-1', { @@ -53,7 +55,8 @@ test_that('set_antimalarial_resistance() errors if resistance proportions outsid early_treatment_failure_prob = 0.6, late_clinical_failure_prob = 0.2, late_parasitological_prob = 0.3, - reinfection_prob = 0.4), + reinfection_prob = 0.4, + slow_parasite_clearance_time = 10), regexp = "Artemisinin and partner-drug resistance proportions must fall between 0 and 1") }) @@ -73,7 +76,8 @@ test_that('set_antimalarial_resistance() errors if resistance phenotype probabil early_treatment_failure_prob = 0.6, late_clinical_failure_prob = 0.2, late_parasitological_prob = 0.3, - reinfection_prob = 0.4)) + reinfection_prob = 0.4, + slow_parasite_clearance_time = 5)) }) test_that('set_antimalarial_resistance() errors if drug index > than number of drugs assigned using set_drugs()', { @@ -111,7 +115,8 @@ test_that('set_antimalarial_resistance() assigns parameters correctly despite or early_treatment_failure_prob = 0.2, late_clinical_failure_prob = 0, late_parasitological_prob = 0, - reinfection_prob = 0) + reinfection_prob = 0, + slow_parasite_clearance_time = 5) parameters <- set_antimalarial_resistance(parameters = parameters, drug = 3, timesteps = 1, @@ -121,7 +126,8 @@ test_that('set_antimalarial_resistance() assigns parameters correctly despite or early_treatment_failure_prob = 0, late_clinical_failure_prob = 0.01, late_parasitological_prob = 0.42, - reinfection_prob = 0.89) + reinfection_prob = 0.89, + slow_parasite_clearance_time = 10) parameters <- set_antimalarial_resistance(parameters = parameters, drug = 1, timesteps = 1, @@ -131,7 +137,8 @@ test_that('set_antimalarial_resistance() assigns parameters correctly despite or early_treatment_failure_prob = 0.9, late_clinical_failure_prob = 0.49, late_parasitological_prob = 0.81, - reinfection_prob = 0.009) + reinfection_prob = 0.009, + slow_parasite_clearance_time = 20) expect_identical(parameters$antimalarial_resistance, TRUE) expect_identical(unlist(parameters$antimalarial_resistance_drug), c(2, 3, 1)) @@ -143,5 +150,173 @@ test_that('set_antimalarial_resistance() assigns parameters correctly despite or expect_identical(unlist(parameters$late_clinical_failure_prob), c(0, 0.01, 0.49)) expect_identical(unlist(parameters$late_parasitological_failure_prob), c(0, 0.42, 0.81)) expect_identical(unlist(parameters$reinfection_during_prophylaxis), c(0, 0.89, 0.009)) + expect_identical(unlist(parameters$dt_slow_parasite_clearance), c(5, 10, 20)) + +}) + +test_that(desc = "set_antimalarial_resistance errors if length slow_parasite_clearance_time > 1", code = { + + parameters <- get_parameters() + parameters <- set_drugs(parameters = parameters, drugs = list(SP_AQ_params)) + parameters <- set_clinical_treatment(parameters = parameters, + drug = 1, + timesteps = c(0, 10), + coverages = c(0.1, 0.2)) + + expect_error( + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 1, + timesteps = c(0, 10), + artemisinin_resistance = c(0.4, 0.8), + partner_drug_resistance = c(0.23, 0.43), + slow_parasite_clearance_prob = c(0.2, 0.4), + early_treatment_failure_prob = c(0, 0.45), + late_clinical_failure_prob = c(0.01, 0.01), + late_parasitological_prob = c(0.05, 0.06), + reinfection_prob = c(0.86, 0.86), + slow_parasite_clearance_time = c(10 ,11)), + "Error: length of slow_parasite_clearance_time not equal to 1") +}) + +test_that(desc = "set_antimalarial_resistance errors if slow_parasite_clearance_time not positive", code = { + + parameters <- get_parameters() + parameters <- set_drugs(parameters = parameters, drugs = list(SP_AQ_params)) + parameters <- set_clinical_treatment(parameters = parameters, + drug = 1, + timesteps = c(0, 10), + coverages = c(0.1, 0.2)) + expect_error( + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 1, + timesteps = c(0, 10), + artemisinin_resistance = c(0.4, 0.8), + partner_drug_resistance = c(0.23, 0.43), + slow_parasite_clearance_prob = c(0.2, 0.4), + early_treatment_failure_prob = c(0, 0.45), + late_clinical_failure_prob = c(0.01, 0.01), + late_parasitological_prob = c(0.05, 0.06), + reinfection_prob = c(0.86, 0.86), + slow_parasite_clearance_time = c(0)), + "Error: slow_parasite_clearance_time is non-positive") }) + +test_that('get_antimalarial_resistance_parameters() correctly retrieves parameters when multiple drugs assigned', { + + get_parameters(overrides = list(human_population = 10000)) %>% + set_drugs(drugs = list(AL_params, SP_AQ_params, DHA_PQP_params)) %>% + set_clinical_treatment(drug = 1, timesteps = 1, coverages = 0.4) %>% + set_clinical_treatment(drug = 2, timesteps = 1, coverages = 0.3) %>% + set_clinical_treatment(drug = 3, timesteps = 1, coverages = 0.2) %>% + set_equilibrium(init_EIR = 20) %>% + set_antimalarial_resistance(drug = 2, + timesteps = c(0, 20), + artemisinin_resistance = c(0.02, 0.2), + partner_drug_resistance = c(0.02, 0.2), + slow_parasite_clearance_prob = c(0.02, 0.2), + early_treatment_failure_prob = c(0.02, 0.2), + late_clinical_failure_prob = c(0.02, 0.2), + late_parasitological_prob = c(0.02, 0.2), + reinfection_prob = c(0.02, 0.2), + slow_parasite_clearance_time = 20) %>% + set_antimalarial_resistance(drug = 1, + timesteps = c(0, 10), + artemisinin_resistance = c(0.01, 0.1), + partner_drug_resistance = c(0.01, 0.1), + slow_parasite_clearance_prob = c(0.01, 0.1), + early_treatment_failure_prob = c(0.01, 0.1), + late_clinical_failure_prob = c(0.01, 0.1), + late_parasitological_prob = c(0.01, 0.1), + reinfection_prob = c(0.01, 0.1), + slow_parasite_clearance_time = 10) %>% + set_antimalarial_resistance(drug = 3, + timesteps = c(0, 30), + artemisinin_resistance = c(0.03, 0.3), + partner_drug_resistance = c(0.03, 0.3), + slow_parasite_clearance_prob = c(0.03, 0.3), + early_treatment_failure_prob = c(0.03, 0.3), + late_clinical_failure_prob = c(0.03, 0.3), + late_parasitological_prob = c(0.03, 0.3), + reinfection_prob = c(0.03, 0.3), + slow_parasite_clearance_time = 30) -> parameters + + drugs <- c(1, 3, 2, 1, 2, 3, 3, 3, 2, 1, 3, 1, 2, 3, 2) + timestep <- 25 + + resistance_parameters <- get_antimalarial_resistance_parameters(parameters = parameters, + drugs = drugs, + timestep = timestep) + + expected_resistance_parameters <- list() + expected_resistance_parameters$artemisinin_resistance_proportion <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) + expected_resistance_parameters$partner_drug_resistance_proportion <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) + expected_resistance_parameters$slow_parasite_clearance_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) + expected_resistance_parameters$early_treatment_failure_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) + expected_resistance_parameters$late_clinical_failure_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) + expected_resistance_parameters$late_parasitological_failure_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) + expected_resistance_parameters$reinfection_during_prophylaxis_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) + expected_resistance_parameters$dt_slow_parasite_clearance <- c(10, 30, 20, 10, 20, 30, 30, 30, 20, 10, 30, 10, 20, 30, 20) + + expect_identical(resistance_parameters, expected = expected_resistance_parameters) + + }) + +test_that('get_antimalarial_resistance_parameters() correctly retrieves parameters when not all drugs assigned resistance', { + + get_parameters(overrides = list(human_population = 10000)) %>% + set_drugs(drugs = list(AL_params, SP_AQ_params, DHA_PQP_params)) %>% + set_clinical_treatment(drug = 1, timesteps = 1, coverages = 0.4) %>% + set_clinical_treatment(drug = 2, timesteps = 1, coverages = 0.3) %>% + set_clinical_treatment(drug = 3, timesteps = 1, coverages = 0.2) %>% + set_equilibrium(init_EIR = 20) %>% + set_antimalarial_resistance(drug = 2, + timesteps = c(0, 20), + artemisinin_resistance = c(0.02, 0.2), + partner_drug_resistance = c(0.02, 0.2), + slow_parasite_clearance_prob = c(0.02, 0.2), + early_treatment_failure_prob = c(0.02, 0.2), + late_clinical_failure_prob = c(0.02, 0.2), + late_parasitological_prob = c(0.02, 0.2), + reinfection_prob = c(0.02, 0.2), + slow_parasite_clearance_time = 20) -> parameters + + drugs <- c(1, 3, 2, 1, 2, 3, 3, 3, 2, 1, 3, 1, 2, 3, 2) + timestep <- 25 + + resistance_parameters <- get_antimalarial_resistance_parameters(parameters = parameters, + drugs = drugs, + timestep = timestep) + + expected_resistance_parameters <- list() + expected_resistance_parameters$artemisinin_resistance_proportion <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) + expected_resistance_parameters$partner_drug_resistance_proportion <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) + expected_resistance_parameters$slow_parasite_clearance_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) + expected_resistance_parameters$early_treatment_failure_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) + expected_resistance_parameters$late_clinical_failure_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) + expected_resistance_parameters$late_parasitological_failure_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) + expected_resistance_parameters$reinfection_during_prophylaxis_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) + expected_resistance_parameters$dt_slow_parasite_clearance <- c(5, 5, 20, 5, 20, 5, 5, 5, 20, 5, 5, 5, 20, 5, 20) + + expect_identical(resistance_parameters, expected = expected_resistance_parameters) + + }) + +test_that('get_antimalarial_resistance_parameters() returns an error when antimalarial resistance has not been parameterised', { + + get_parameters(overrides = list(human_population = 10000)) %>% + set_drugs(drugs = list(AL_params, SP_AQ_params, DHA_PQP_params)) %>% + set_clinical_treatment(drug = 1, timesteps = 1, coverages = 0.4) %>% + set_clinical_treatment(drug = 2, timesteps = 1, coverages = 0.3) %>% + set_clinical_treatment(drug = 3, timesteps = 1, coverages = 0.2) %>% + set_equilibrium(init_EIR = 20) -> parameters + + drugs <- c(1, 3, 2, 1, 2, 3, 3, 3, 2, 1, 3, 1, 2, 3, 2) + timestep <- 25 + + + expect_error(get_antimalarial_resistance_parameters(parameters = parameters, + drugs = drugs, + timestep = timestep), + "Error: Antimalarial resistance has not been parameterised; antimalarial_resistance = FALSE") +}) \ No newline at end of file diff --git a/tests/testthat/test-infection-integration.R b/tests/testthat/test-infection-integration.R index e169b1af..70a0ec6f 100644 --- a/tests/testthat/test-infection-integration.R +++ b/tests/testthat/test-infection-integration.R @@ -330,7 +330,8 @@ test_that('calculate_treated correctly samples treated and updates the drug stat early_treatment_failure_prob = 0.2, late_clinical_failure_prob = 0, late_parasitological_prob = 0, - reinfection_prob = 0) + reinfection_prob = 0, + slow_parasite_clearance_time = 10) parameters <- set_antimalarial_resistance(parameters = parameters, drug = 2, timesteps = 1, @@ -340,7 +341,8 @@ test_that('calculate_treated correctly samples treated and updates the drug stat early_treatment_failure_prob = 0.9, late_clinical_failure_prob = 0, late_parasitological_prob = 0, - reinfection_prob = 0) + reinfection_prob = 0, + slow_parasite_clearance_time = 15) clinical_infections <- individual::Bitset$new(20)$insert(1:20) timestep <- 5 @@ -409,6 +411,140 @@ test_that('calculate_treated correctly samples treated and updates the drug stat }) +test_that('calculate_treated correctly samples treated and updates the drug state when resistance not set for all drugs', { + + # Establish the parameters + parameters <- get_parameters() + parameters <- set_drugs(parameters = parameters, drugs = list(AL_params, SP_AQ_params)) + parameters <- set_clinical_treatment(parameters = parameters, drug = 1, timesteps = 1, coverages = 0.25) + parameters <- set_clinical_treatment(parameters = parameters, drug = 2, timesteps = 1, coverages = 0.25) + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 2, + timesteps = 1, + artemisinin_resistance = 0.8, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0, + early_treatment_failure_prob = 0.9, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0, + slow_parasite_clearance_time = 20) + + # Establish Bitset of clinically infected individuals + clinical_infections <- individual::Bitset$new(20)$insert(1:20) + + # Set the timestep to 5: + timestep <- 5 + + # Establish the events: + events <- create_events(parameters) + + # Establish list of variables used in calculate_treated() using mocks: + variables <- list( + state = list(queue_update = mockery::mock()), + infectivity = list(queue_update = mockery::mock()), + drug = list(queue_update = mockery::mock()), + drug_time = list(queue_update = mockery::mock()) + ) + + # Create a Bitset of individuals seeking treatment individuals: + seek_treatment <- individual::Bitset$new(20)$insert(c(1:10)) + + # Create a mock of seek_treatment: + seek_treatment_mock <- mockery::mock(seek_treatment) + + # Specify that, when calculate_treated() calls sample_bitset(), return the seek_treatment_mock: + mockery::stub(where = calculate_treated, what = 'sample_bitset', how = seek_treatment_mock) + + # Create a mock_drugs object (5 of each drug): + mock_drugs <- mockery::mock(c(2, 1, 1, 1, 2, 2, 2, 1, 2, 1)) + + # Specify that when calculate_treated() calls sample.int(), it returns mock_drugs: + mockery::stub(calculate_treated, 'sample.int', mock_drugs) + + # Create a bernoulli_mock of i) individuals susceptible, and ii) individuals successfully treated: + bernoulli_mock <- mockery::mock(c(1, 2, 3, 4, 5, 6, 7, 8, 9), c(1, 2, 3, 4, 5, 6, 7)) + + # Specify that when calculate_treated() calls bernoulli_multi_p() it returns the bernoulli_mock: + mockery::stub(calculate_treated, 'bernoulli_multi_p', bernoulli_mock) + + # Run the calculate_treated() function now the mocks and stubs are established: + calculate_treated( + variables, + clinical_infections, + parameters, + timestep, + mock_render(timestep) + ) + + # Check that mock_drugs was called only once, and that the arguments used in the function call + # mock_drugs() was used in (sample.int()) match those expected: + mockery::expect_args( + mock_drugs, + 1, + 2, + 10, + c(.25, .25), + TRUE + ) + + # Check that seek_treatment_mock was called only once, and that the arguments used in the function + # call mock_drugs() was used in (sample_bitset()) match those expected: + mockery::expect_args( + seek_treatment_mock, + 1, + clinical_infections, + 0.5 + ) + + # Check that the first time bernoulli_mock was called the arguments used in the function + # call bernoulli_mock was involved in (bernoulli_multi_p()) match those expected: + mockery::expect_args( + bernoulli_mock, + 1, + c(0.28, 1, 1, 1, 0.28, 0.28, 0.28, 1, 0.28, 1) # (1 - (art_prop * etf_prob)) + ) + + # Check that the secnd time bernoulli_mock was called (bernoulli_multi_p()) the arguments used in + # the function it was called in are as expected: + mockery::expect_args( + bernoulli_mock, + 2, + parameters$drug_efficacy[c(2, 1, 1, 1, 2, 2, 2, 1, 2)] + ) + + # Check that update queued that updates the state of successfully treated individuals to "Tr" + expect_bitset_update( + variables$state$queue_update, + 'Tr', + c(1, 2, 3, 4, 5, 6, 7) + ) + + # Check that update queued that updates the infectivity of successfully treated individuals to "Tr" + # to their new infectivity (drug concentration x infectivity of "D" compartment) + expect_bitset_update( + variables$infectivity$queue_update, + parameters$cd * parameters$drug_rel_c[c(2, 1, 1, 1, 2, 2, 2)], + c(1, 2, 3, 4, 5, 6, 7) + ) + + # Check that update queued that updates the drug of successfully treated individuals to the drug + # they took: + expect_bitset_update( + variables$drug$queue_update, + c(2, 1, 1, 1, 2, 2, 2), + c(1, 2, 3, 4, 5, 6, 7) + ) + + # Check that update queued that updates the drug time of successfully treated individuals to the + # simulated/mocked time step (5) + expect_bitset_update( + variables$drug_time$queue_update, + 5, + c(1, 2, 3, 4, 5, 6, 7) + ) +}) + test_that('schedule_infections correctly schedules new infections', { parameters <- get_parameters(list(human_population = 20)) variables <- create_variables(parameters) @@ -638,7 +774,8 @@ test_that('calculate_treated returns empty Bitset when there is no clinical trea early_treatment_failure_prob = 0.2, late_clinical_failure_prob = 0, late_parasitological_prob = 0, - reinfection_prob = 0) + reinfection_prob = 0, + slow_parasite_clearance_time = 10) clinical_infections <- individual::Bitset$new(20)$insert(1:20) timestep <- 5 events <- create_events(parameters) @@ -673,7 +810,8 @@ test_that('calculate_treated returns empty Bitset when the clinically_infected i early_treatment_failure_prob = 0.2, late_clinical_failure_prob = 0, late_parasitological_prob = 0, - reinfection_prob = 0) + reinfection_prob = 0, + slow_parasite_clearance_time = 10) clinical_infections <- individual::Bitset$new(20) timestep <- 5 events <- create_events(parameters) @@ -742,7 +880,8 @@ test_that('Number of treatment failures matches number of individuals treated wh early_treatment_failure_prob = 1, late_clinical_failure_prob = 0, late_parasitological_prob = 0, - reinfection_prob = 0) + reinfection_prob = 0, + slow_parasite_clearance_time = 10) parameters <- set_antimalarial_resistance(parameters = parameters, drug = 2, timesteps = 1, @@ -752,7 +891,8 @@ test_that('Number of treatment failures matches number of individuals treated wh early_treatment_failure_prob = 1, late_clinical_failure_prob = 0, late_parasitological_prob = 0, - reinfection_prob = 0) + reinfection_prob = 0, + slow_parasite_clearance_time = 20) clinical_infections <- individual::Bitset$new(100) clinical_infections$insert(sample.int(n = 100, size = round(runif(n = 1, min = 10, max = 100)), replace = FALSE)) @@ -785,7 +925,8 @@ test_that('calculate_treated() successfully adds additional resistance columns t early_treatment_failure_prob = 0.5, late_clinical_failure_prob = 0, late_parasitological_prob = 0, - reinfection_prob = 0) + reinfection_prob = 0, + slow_parasite_clearance_time = 10) clinical_infections <- individual::Bitset$new(20)$insert(1:20) timestep <- 5 @@ -804,7 +945,7 @@ test_that('calculate_treated() successfully adds additional resistance columns t timestep = timestep, renderer = renderer) - calculate_treated_column_names <- c("n_clin_infected", "ft", "n_treated", "n_early_treatment_failure", "n_treat_eff_fail", "n_treat_success") + calculate_treated_column_names <- c("ft", "n_treated", "n_early_treatment_failure", "n_treat_eff_fail", "n_treat_success") expect_identical(sum(calculate_treated_column_names %in% colnames(renderer$to_dataframe())), length(calculate_treated_column_names), "calculate_treated() not renderering all resistance columns when resistance is present, clinical treatment coverage is non-zero, and the Bitset of clinically_infected individuals input is of non-zero length.") From 4d75b2eb152ccb7a56e74322e6d733e21a32ee7f Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Thu, 8 Feb 2024 18:12:31 +0000 Subject: [PATCH 148/164] Implented the second round of changes requested in the pull request --- R/antimalarial_resistance.R | 100 ++++++++++++++---- R/human_infection.R | 27 ++--- R/model.R | 3 +- R/parameters.R | 1 + man/get_antimalarial_resistance_parameters.Rd | 19 ++++ man/get_parameters.Rd | 1 + man/run_simulation.Rd | 3 +- man/set_antimalarial_resistance.Rd | 5 +- vignettes/Antimalarial_Resistance.Rmd | 8 +- 9 files changed, 119 insertions(+), 48 deletions(-) create mode 100644 man/get_antimalarial_resistance_parameters.Rd diff --git a/R/antimalarial_resistance.R b/R/antimalarial_resistance.R index 9d6e7dfe..0aad5315 100644 --- a/R/antimalarial_resistance.R +++ b/R/antimalarial_resistance.R @@ -1,5 +1,7 @@ #' @title Parameterise antimalarial resistance -#' +#' @description +#' Parameterise antimalarial resistance +#' #' @param parameters the model parameters #' @param drug the index of the drug which resistance is being set, as set by the set_drugs() function, in the parameter list #' @param timesteps vector of time steps for each update to resistance proportion and resistance outcome probability @@ -10,6 +12,7 @@ #' @param late_clinical_failure_prob vector of updates to the proportion of partner-drug-resistant infections that result in late clinical failure #' @param late_parasitological_prob vector of updates to the proportion of partner-drug-resistant infections that result in late parasitological failure #' @param reinfection_prob vector of updates to the proportion of partner-drug-resistant infections that result in reinfection during prophylaxis +#' @param slow_parasite_clearance_time single value representing the mean time individual's experiencing slow parasite clearance reside in the treated state #' @export set_antimalarial_resistance <- function(parameters, drug, @@ -20,9 +23,9 @@ set_antimalarial_resistance <- function(parameters, early_treatment_failure_prob, late_clinical_failure_prob, late_parasitological_prob, - reinfection_prob) { + reinfection_prob, + slow_parasite_clearance_time) { - # Check that the number of values input is equal for each resistance parameter if(any(c(length(artemisinin_resistance), length(partner_drug_resistance), length(slow_parasite_clearance_prob), @@ -33,13 +36,11 @@ set_antimalarial_resistance <- function(parameters, stop("Length of one or more resistance parameter vectors does not match time steps specified for update") } - # Ensure resistance proportions bounded between 0 and 1: - if(any(artemisinin_resistance < 0 | artemisinin_resistance > 1 | + if(any(artemisinin_resistance < 0 | artemisinin_resistance > 1 | partner_drug_resistance < 0 | partner_drug_resistance > 1)) { stop("Artemisinin and partner-drug resistance proportions must fall between 0 and 1") } - # Ensure resistance outcome probabilities bounded between 0 and 1: if(any(slow_parasite_clearance_prob < 0 | slow_parasite_clearance_prob > 1 | early_treatment_failure_prob < 0 | early_treatment_failure_prob > 1 | late_clinical_failure_prob < 0 | late_clinical_failure_prob > 1 | @@ -47,45 +48,102 @@ set_antimalarial_resistance <- function(parameters, reinfection_prob < 0 | reinfection_prob > 1)) { stop("Resistance outcome probabilities must fall between 0 and 1") } + + if(length(slow_parasite_clearance_time) != 1) { + stop("Error: length of slow_parasite_clearance_time not equal to 1") + } + + if(slow_parasite_clearance_time <= 0) { + stop("Error: slow_parasite_clearance_time is non-positive") + } - # Set antimalarial_resistance to TRUE: parameters$antimalarial_resistance <- TRUE - # Store the number of drugs for which parameters are available in the parameter list: n_drugs <- length(parameters$drug_efficacy) - # If the drug index falls outside range 1:n_drugs, terminate the operation: if (drug < 1 | drug > n_drugs) { stop('Drug index is invalid, please set drugs using set_drugs') } - # Check the drug_index for the drug we're setting parameters for: drug_index <- which(parameters$antimalarial_resistance_drug == drug) - # If drug_index not already assigned, assign the drug the next available index: if (length(drug_index) == 0) { drug_index <- length(parameters$antimalarial_resistance_drug) + 1 } - # Append the drug for which resistance is being assigned to the generated index: parameters$antimalarial_resistance_drug[[drug_index]] <- drug - - # Append the timesteps on which the resistance proportions are to be updated: parameters$antimalarial_resistance_timesteps[[drug_index]] <- timesteps - - # Append the proportions of all malarial infections that are artemisinin or partner-drug - # resistant: parameters$prop_artemisinin_resistant[[drug_index]] <- artemisinin_resistance parameters$prop_partner_drug_resistant[[drug_index]] <- partner_drug_resistance - - # Append the probabilities that individuals will experience the resistance outcomes: parameters$slow_parasite_clearance_prob[[drug_index]] <- slow_parasite_clearance_prob parameters$early_treatment_failure_prob[[drug_index]] <- early_treatment_failure_prob parameters$late_clinical_failure_prob[[drug_index]] <- late_clinical_failure_prob parameters$late_parasitological_failure_prob[[drug_index]] <- late_parasitological_prob parameters$reinfection_during_prophylaxis[[drug_index]] <- reinfection_prob + parameters$dt_slow_parasite_clearance[[drug_index]] <- slow_parasite_clearance_time + + return(parameters) + +} + +#' @title Retrieve resistance parameters +#' @description +#' Retrieve the resistance parameters associated with the drug each individual receiving clinical +#' treatment has been administered in the current time step. +#' +#' @param parameters the model parameters +#' @param drug vector of integers representing the drugs administered to each individual receiving treatment +#' @param timestep the current time step +get_antimalarial_resistance_parameters <- function(parameters, drugs, timestep) { + + if(!parameters$antimalarial_resistance) { + stop("Error: Antimalarial resistance has not been parameterised; antimalarial_resistance = FALSE") + } + + artemisinin_resistance_proportion <- numeric(length = length(drugs)) + partner_drug_resistance_proportion <- numeric(length = length(drugs)) + slow_parasite_clearance_probability <- numeric(length = length(drugs)) + early_treatment_failure_probability <- numeric(length = length(drugs)) + late_clinical_failure_probability <- numeric(length = length(drugs)) + late_parasitological_failure_probability <- numeric(length = length(drugs)) + reinfection_during_prophylaxis_probability <- numeric(length = length(drugs)) + dt_slow_parasite_clearance <- rep(parameters$dt, length = length(drugs)) + + for(i in seq_along(parameters$antimalarial_resistance_drug)) { + drug <- parameters$antimalarial_resistance_drug[[i]] + treated_with_drug <- which(drugs == drug) + resistance_timestep <- match_timestep(ts = parameters$antimalarial_resistance_timesteps[[i]], t = timestep) + artemisinin_resistance_proportion[treated_with_drug] <- parameters$prop_artemisinin_resistant[[i]][resistance_timestep] + partner_drug_resistance_proportion[treated_with_drug] <- parameters$prop_partner_drug_resistant[[i]][resistance_timestep] + slow_parasite_clearance_probability[treated_with_drug] <- parameters$slow_parasite_clearance_prob[[i]][resistance_timestep] + early_treatment_failure_probability[treated_with_drug] <- parameters$early_treatment_failure_prob[[i]][resistance_timestep] + late_clinical_failure_probability[treated_with_drug] <- parameters$late_clinical_failure_prob[[i]][resistance_timestep] + late_parasitological_failure_probability[treated_with_drug] <- parameters$late_parasitological_failure_prob[[i]][resistance_timestep] + reinfection_during_prophylaxis_probability[treated_with_drug] <- parameters$reinfection_during_prophylaxis[[i]][resistance_timestep] + dt_slow_parasite_clearance[treated_with_drug] <- parameters$dt_slow_parasite_clearance[[i]] + } + + resistance_parameters <- list() + resistance_parameters$artemisinin_resistance_proportion <- artemisinin_resistance_proportion + resistance_parameters$partner_drug_resistance_proportion <- partner_drug_resistance_proportion + resistance_parameters$slow_parasite_clearance_probability <- slow_parasite_clearance_probability + resistance_parameters$early_treatment_failure_probability <- early_treatment_failure_probability + resistance_parameters$late_clinical_failure_probability <- late_clinical_failure_probability + resistance_parameters$late_parasitological_failure_probability <- late_parasitological_failure_probability + resistance_parameters$reinfection_during_prophylaxis_probability <- reinfection_during_prophylaxis_probability + resistance_parameters$dt_slow_parasite_clearance <- dt_slow_parasite_clearance + + if(any(c(length(resistance_parameters$artemisinin_resistance_proportion), + length(resistance_parameters$partner_drug_resistance_proportion), + length(resistance_parameters$slow_parasite_clearance_probability), + length(resistance_parameters$early_treatment_failure_probability), + length(resistance_parameters$late_clinical_failure_probability), + length(resistance_parameters$late_parasitological_failure_probability), + length(resistance_parameters$reinfection_during_prophylaxis_probability), + length(resistance_parameters$dt_slow_parasite_clearance)) != length(drugs))) { + stop("Length of one or more resistance parameter vectors does not match length of drugs vector") + } - # Return the parameter list: - parameters + return(resistance_parameters) } \ No newline at end of file diff --git a/R/human_infection.R b/R/human_infection.R index a17dad8f..68013e58 100644 --- a/R/human_infection.R +++ b/R/human_infection.R @@ -270,8 +270,6 @@ calculate_treated <- function( renderer ) { - renderer$render('n_clin_infected', clinical_infections$size(), timestep) - if(clinical_infections$size() == 0) { return(individual::Bitset$new(parameters$human_population)) } @@ -297,27 +295,18 @@ calculate_treated <- function( ) ]) - if(parameters$antimalarial_resistance == TRUE) { - antimalarial_resistance_drug_index <- as.numeric(parameters$antimalarial_resistance_drug)[drugs] - artemisinin_resistance_proportion <- vector() - early_treatment_failure_probability <- vector() - drug_indices <- list(); drug_index <- vector() - - for(i in seq_along(parameters$antimalarial_resistance_drug)) { - drug_indices[[i]] <- which(drugs == i) - drug_index[i] <- which(parameters$antimalarial_resistance_drug == i) - matched_t <- match_timestep(ts = parameters$antimalarial_resistance_timesteps[[drug_index[i]]], t = timestep) - artemisinin_resistance_proportion[drug_indices[[i]]] <- parameters$prop_artemisinin_resistant[[drug_index[i]]][matched_t] - early_treatment_failure_probability[drug_indices[[i]]] <- parameters$early_treatment_failure_prob[[drug_index[i]]][matched_t] - } - - unsuccessful_treatment_probability <- artemisinin_resistance_proportion * early_treatment_failure_probability + if(parameters$antimalarial_resistance) { + resistance_parameters <- get_antimalarial_resistance_parameters( + parameters = parameters, + drugs = drugs, + timestep = timestep + ) + unsuccessful_treatment_probability <- resistance_parameters$artemisinin_resistance_proportion * resistance_parameters$early_treatment_failure_probability susceptible_to_treatment_index <- bernoulli_multi_p(p = 1 - unsuccessful_treatment_probability) - drugs <- drugs[susceptible_to_treatment_index] susceptible_to_treatment <- bitset_at(seek_treatment, susceptible_to_treatment_index) + drugs <- drugs[susceptible_to_treatment_index] n_early_treatment_failure <- n_treat - susceptible_to_treatment$size() renderer$render('n_early_treatment_failure', n_early_treatment_failure, timestep) - } else { susceptible_to_treatment <- seek_treatment n_early_treatment_failure <- n_treat - susceptible_to_treatment$size() diff --git a/R/model.R b/R/model.R index b665861b..4c4f7c2b 100644 --- a/R/model.R +++ b/R/model.R @@ -74,10 +74,9 @@ #' susceptible #' * net_usage: the number people protected by a bed net #' * mosquito_deaths: number of adult female mosquitoes who die this timestep -#' * n_clin_infected: number of new clinically infected individuals in this timestep #' * n_early_treatment_failure: number of clinically treated individuals who experienced early treatment failure in this timestep #' * n_treat_eff_fail: number of clinically treated individuals who's treatment failed due to drug efficacy -#' * n_treat_success: number of newly successfully treated individuals in this timestep +#' * n_treat_success: number of successfully treated individuals in this timestep #' #' @param timesteps the number of timesteps to run the simulation for (in days) #' @param parameters a named list of parameters to use diff --git a/R/parameters.R b/R/parameters.R index 7cc4a39c..9abbeb60 100644 --- a/R/parameters.R +++ b/R/parameters.R @@ -207,6 +207,7 @@ #' * late_clinical_failure_prob - vector of probabilities of late clinical failure for a given drug; default = NULL #' * late_parasitological_failure_prob - vector of probabilities of late parasitological failure for a given drug; default = NULL #' * reinfection_during_prophylaxis - vector of probabilities of reinfection during prophylaxis for a given drug; default = NULL +#' * dt_slow_parasite_clearance - the delay for humans experiencing slow parasite clearance to move from state Tr to S; default = NULL #' #' rendering: #' All values are in timesteps and all ranges are inclusive diff --git a/man/get_antimalarial_resistance_parameters.Rd b/man/get_antimalarial_resistance_parameters.Rd new file mode 100644 index 00000000..34c0a9c6 --- /dev/null +++ b/man/get_antimalarial_resistance_parameters.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/antimalarial_resistance.R +\name{get_antimalarial_resistance_parameters} +\alias{get_antimalarial_resistance_parameters} +\title{Retrieve resistance parameters} +\usage{ +get_antimalarial_resistance_parameters(parameters, drugs, timestep) +} +\arguments{ +\item{parameters}{the model parameters} + +\item{timestep}{the current time step} + +\item{drug}{vector of integers representing the drugs administered to each individual receiving treatment} +} +\description{ +Retrieve the resistance parameters associated with the drug each individual receiving clinical +treatment has been administered in the current time step. +} diff --git a/man/get_parameters.Rd b/man/get_parameters.Rd index 20459538..fc6ba000 100644 --- a/man/get_parameters.Rd +++ b/man/get_parameters.Rd @@ -228,6 +228,7 @@ please set antimalarial resistance parameters with the convenience functions in \item late_clinical_failure_prob - vector of probabilities of late clinical failure for a given drug; default = NULL \item late_parasitological_failure_prob - vector of probabilities of late parasitological failure for a given drug; default = NULL \item reinfection_during_prophylaxis - vector of probabilities of reinfection during prophylaxis for a given drug; default = NULL +\item dt_slow_parasite_clearance - the delay for humans experiencing slow parasite clearance to move from state Tr to S; default = NULL } rendering: diff --git a/man/run_simulation.Rd b/man/run_simulation.Rd index 548fbd7e..07871b13 100644 --- a/man/run_simulation.Rd +++ b/man/run_simulation.Rd @@ -90,9 +90,8 @@ subpatent susceptible \item net_usage: the number people protected by a bed net \item mosquito_deaths: number of adult female mosquitoes who die this timestep -\item n_clin_infected: number of new clinically infected individuals in this timestep \item n_early_treatment_failure: number of clinically treated individuals who experienced early treatment failure in this timestep \item n_treat_eff_fail: number of clinically treated individuals who's treatment failed due to drug efficacy -\item n_treat_success: number of newly successfully treated individuals in this timestep +\item n_treat_success: number of successfully treated individuals in this timestep } } diff --git a/man/set_antimalarial_resistance.Rd b/man/set_antimalarial_resistance.Rd index 30b31433..82c65405 100644 --- a/man/set_antimalarial_resistance.Rd +++ b/man/set_antimalarial_resistance.Rd @@ -14,7 +14,8 @@ set_antimalarial_resistance( early_treatment_failure_prob, late_clinical_failure_prob, late_parasitological_prob, - reinfection_prob + reinfection_prob, + slow_parasite_clearance_time ) } \arguments{ @@ -37,6 +38,8 @@ set_antimalarial_resistance( \item{late_parasitological_prob}{vector of updates to the proportion of partner-drug-resistant infections that result in late parasitological failure} \item{reinfection_prob}{vector of updates to the proportion of partner-drug-resistant infections that result in reinfection during prophylaxis} + +\item{slow_parasite_clearance_time}{single value representing the mean time individual's experiencing slow parasite clearance reside in the treated state} } \description{ Parameterise antimalarial resistance diff --git a/vignettes/Antimalarial_Resistance.Rmd b/vignettes/Antimalarial_Resistance.Rmd index 5730ae99..eaeb7e89 100644 --- a/vignettes/Antimalarial_Resistance.Rmd +++ b/vignettes/Antimalarial_Resistance.Rmd @@ -34,7 +34,7 @@ One of the major threats to the continued success of efforts to reduce the burde Resistance to the artemisinin component of an ACT can result either in slow parasite clearance (SPC), in which treatment with an ACT takes longer than 3 days to fully clear patients with resistant parasites, or early treatment failure (ETF), in which the ACT fails to clear the infection and the individual develops a clinical infection. Resistance to the partner drug, where the partner drug fails to clear the parasite after the artemisinin derivative is depleted, results in infections recrudescing to either clinical (D) or asymptomatic infections (A). Resistance to the partner drug can also result in individuals developing a novel, resistant infection following treatment, as the prophylaxis provided by the ACT fails to protect the individual against reinfection by a resistant strain. In the following vignette, we illustrate how to parameterise and run `malariasimulation` simulations with resistance to ACTs deployed as a clinical treatment ## Using set_antimalarial_resistance() to parameterise resistance -Simulations capturing the effects of resistance to clinical treatment using antimalarial drugs are parameterised using the `set_antimalarial_resistance()` function. This function appends user-defined resistance parameters to a `malariasimulation` parameter list and accepts ten inputs. The first is a list of `malariasimulation` parameters to append the resistance parameters to, and the second the index of the `drug` for which resistance is being parameterised, as set using the `set_drugs()` function. The `set_antimalarial_resistance()` function requires the `timesteps`, `artemisinin_resistance`, `partner_drug_resistance`, `slow_parasite_clearance_prob`, `early_treatment_failure_prob`, `late_clinical_failure_prob`, `late_parasitological_failure_prob`, and `reinfection_prob` inputs to be of equal length so that, for each time step in which an update occurs, a value is available for each parameter. +Simulations capturing the effects of resistance to clinical treatment using antimalarial drugs are parameterised using the `set_antimalarial_resistance()` function. This function appends user-defined resistance parameters to a `malariasimulation` parameter list and accepts ten inputs. The first is a list of `malariasimulation` parameters to append the resistance parameters to, and the second the index of the `drug` for which resistance is being parameterised, as set using the `set_drugs()` function. The `set_antimalarial_resistance()` function requires the `timesteps`, `artemisinin_resistance`, `partner_drug_resistance`, `slow_parasite_clearance_prob`, `early_treatment_failure_prob`, `late_clinical_failure_prob`, `late_parasitological_failure_prob`, and `reinfection_prob` inputs to be of equal length so that, for each time step in which an update occurs, a value is available for each parameter. Finally, the `slow_parasite_clearance_time` parameter represents the mean residence time, in days, for artemisinin-resistant individuals experiencing slow parasite clearance (SPC) in the Treated compartment, and must be input as a single, positive value. ## Simulating static resistance To illustrate how to parameterise resistance to an ACT using the `set_antimalarial_resistance()` function, we'll set-up and run three simulations. The first simulates malaria transmission in the absence of interventions or resistance. The second simulates a simple regime of clinical treatment in which 80% of clinical cases are treated with artemether lumefantrine (AL), beginning after one year, in the absence of antimalarial resistance. The third simulates the same clinical treatment programme but with resistance to the artemisinin component of AL emerging after two years. For illustrative purposes, we assume that the proportion of infections resistant to the artemisinin component of AL increases from 0% to 80%, and that these infections have a 90% chance of resulting in early treatment failure. @@ -84,7 +84,8 @@ simparams_resistance <- set_antimalarial_resistance(parameters = simparams_clin_ early_treatment_failure_prob = c(0, 0.9), late_clinical_failure_prob = rep(0, 2), late_parasitological_prob = rep(0, 2), - reinfection_prob = rep(0, 2)) + reinfection_prob = rep(0, 2), + slow_parasite_clearance_time = 10) ``` @@ -204,7 +205,8 @@ simparams <- set_antimalarial_resistance(parameters = simparams, early_treatment_failure_prob = early_treatment_failure_updates, late_clinical_failure_prob = rep(0, length(resistance_update_timesteps)), late_parasitological_prob = rep(0, length(resistance_update_timesteps)), - reinfection_prob = rep(0, length(resistance_update_timesteps))) + reinfection_prob = rep(0, length(resistance_update_timesteps)), + slow_parasite_clearance_time = 10) # Calibrate the parameters to an initial EIR: simparams <- set_equilibrium(parameters = simparams, init_EIR = initial_eir) From d51bbf71f558f9cd1bb3385283b53d4a62eeee95 Mon Sep 17 00:00:00 2001 From: tbreweric Date: Mon, 12 Feb 2024 14:16:04 +0000 Subject: [PATCH 149/164] Re-adding the changes recommended by Pete following a reversion to 4d75b2eb after a merge error --- R/antimalarial_resistance.R | 26 ++++++++------------------ R/human_infection.R | 7 +++---- vignettes/Antimalarial_Resistance.Rmd | 5 +---- 3 files changed, 12 insertions(+), 26 deletions(-) diff --git a/R/antimalarial_resistance.R b/R/antimalarial_resistance.R index 0aad5315..d4712a25 100644 --- a/R/antimalarial_resistance.R +++ b/R/antimalarial_resistance.R @@ -100,13 +100,14 @@ get_antimalarial_resistance_parameters <- function(parameters, drugs, timestep) stop("Error: Antimalarial resistance has not been parameterised; antimalarial_resistance = FALSE") } - artemisinin_resistance_proportion <- numeric(length = length(drugs)) - partner_drug_resistance_proportion <- numeric(length = length(drugs)) - slow_parasite_clearance_probability <- numeric(length = length(drugs)) - early_treatment_failure_probability <- numeric(length = length(drugs)) - late_clinical_failure_probability <- numeric(length = length(drugs)) - late_parasitological_failure_probability <- numeric(length = length(drugs)) - reinfection_during_prophylaxis_probability <- numeric(length = length(drugs)) + blank_vector <- numeric(length = length(drugs)) + artemisinin_resistance_proportion <- blank_vector + partner_drug_resistance_proportion <- blank_vector + slow_parasite_clearance_probability <- blank_vector + early_treatment_failure_probability <- blank_vector + late_clinical_failure_probability <- blank_vector + late_parasitological_failure_probability <- blank_vector + reinfection_during_prophylaxis_probability <- blank_vector dt_slow_parasite_clearance <- rep(parameters$dt, length = length(drugs)) for(i in seq_along(parameters$antimalarial_resistance_drug)) { @@ -133,17 +134,6 @@ get_antimalarial_resistance_parameters <- function(parameters, drugs, timestep) resistance_parameters$reinfection_during_prophylaxis_probability <- reinfection_during_prophylaxis_probability resistance_parameters$dt_slow_parasite_clearance <- dt_slow_parasite_clearance - if(any(c(length(resistance_parameters$artemisinin_resistance_proportion), - length(resistance_parameters$partner_drug_resistance_proportion), - length(resistance_parameters$slow_parasite_clearance_probability), - length(resistance_parameters$early_treatment_failure_probability), - length(resistance_parameters$late_clinical_failure_probability), - length(resistance_parameters$late_parasitological_failure_probability), - length(resistance_parameters$reinfection_during_prophylaxis_probability), - length(resistance_parameters$dt_slow_parasite_clearance)) != length(drugs))) { - stop("Length of one or more resistance parameter vectors does not match length of drugs vector") - } - return(resistance_parameters) } \ No newline at end of file diff --git a/R/human_infection.R b/R/human_infection.R index 68013e58..6b2ac3cf 100644 --- a/R/human_infection.R +++ b/R/human_infection.R @@ -305,18 +305,17 @@ calculate_treated <- function( susceptible_to_treatment_index <- bernoulli_multi_p(p = 1 - unsuccessful_treatment_probability) susceptible_to_treatment <- bitset_at(seek_treatment, susceptible_to_treatment_index) drugs <- drugs[susceptible_to_treatment_index] - n_early_treatment_failure <- n_treat - susceptible_to_treatment$size() - renderer$render('n_early_treatment_failure', n_early_treatment_failure, timestep) } else { susceptible_to_treatment <- seek_treatment - n_early_treatment_failure <- n_treat - susceptible_to_treatment$size() - renderer$render('n_early_treatment_failure', n_early_treatment_failure, timestep) + } + n_early_treatment_failure <- n_treat - susceptible_to_treatment$size() successfully_treated_index <- bernoulli_multi_p(parameters$drug_efficacy[drugs]) successfully_treated <- bitset_at(susceptible_to_treatment, successfully_treated_index) successfully_treated_drugs <- drugs[successfully_treated_index] n_treat_eff_fail <- susceptible_to_treatment$size() - length(successfully_treated_index) + renderer$render('n_early_treatment_failure', n_early_treatment_failure, timestep) renderer$render('n_treat_eff_fail', n_treat_eff_fail, timestep) renderer$render('n_treat_success', successfully_treated$size(), timestep) diff --git a/vignettes/Antimalarial_Resistance.Rmd b/vignettes/Antimalarial_Resistance.Rmd index eaeb7e89..7bf197b7 100644 --- a/vignettes/Antimalarial_Resistance.Rmd +++ b/vignettes/Antimalarial_Resistance.Rmd @@ -18,10 +18,7 @@ knitr::opts_chunk$set( ```{r setup} # Load the requisite packages: -#library(malariasimulation) - -# Use devtools to load the updated malariasimulation: -devtools::load_all("C:/Users/trb216/OneDrive - Imperial College London/Desktop/malariasimulation/malariasimulation.Rproj") +library(malariasimulation) # Set colour palette: cols <- c("#E69F00", "#56B4E9", "#009E73", "#CC79A7","#F0E442", "#0072B2", "#D55E00") From 2adf82349c2ac86d0802d4322a19e950226df5fa Mon Sep 17 00:00:00 2001 From: tbreweric Date: Tue, 13 Feb 2024 17:27:31 +0000 Subject: [PATCH 150/164] Corrected drugs documentation for get_antimalarial_resistance_parameters() function (antimalarial_resistance.R) --- R/antimalarial_resistance.R | 2 +- man/CorrelationParameters.Rd | 36 +++++++++---------- man/get_antimalarial_resistance_parameters.Rd | 4 +-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/R/antimalarial_resistance.R b/R/antimalarial_resistance.R index d4712a25..532c042b 100644 --- a/R/antimalarial_resistance.R +++ b/R/antimalarial_resistance.R @@ -92,7 +92,7 @@ set_antimalarial_resistance <- function(parameters, #' treatment has been administered in the current time step. #' #' @param parameters the model parameters -#' @param drug vector of integers representing the drugs administered to each individual receiving treatment +#' @param drugs vector of integers representing the drugs administered to each individual receiving treatment #' @param timestep the current time step get_antimalarial_resistance_parameters <- function(parameters, drugs, timestep) { diff --git a/man/CorrelationParameters.Rd b/man/CorrelationParameters.Rd index b1d22578..c2e6ada7 100644 --- a/man/CorrelationParameters.Rd +++ b/man/CorrelationParameters.Rd @@ -14,17 +14,17 @@ Describes an event in the simulation \section{Methods}{ \subsection{Public methods}{ \itemize{ -\item \href{#method-new}{\code{CorrelationParameters$new()}} -\item \href{#method-inter_round_rho}{\code{CorrelationParameters$inter_round_rho()}} -\item \href{#method-inter_intervention_rho}{\code{CorrelationParameters$inter_intervention_rho()}} -\item \href{#method-sigma}{\code{CorrelationParameters$sigma()}} -\item \href{#method-mvnorm}{\code{CorrelationParameters$mvnorm()}} -\item \href{#method-clone}{\code{CorrelationParameters$clone()}} +\item \href{#method-CorrelationParameters-new}{\code{CorrelationParameters$new()}} +\item \href{#method-CorrelationParameters-inter_round_rho}{\code{CorrelationParameters$inter_round_rho()}} +\item \href{#method-CorrelationParameters-inter_intervention_rho}{\code{CorrelationParameters$inter_intervention_rho()}} +\item \href{#method-CorrelationParameters-sigma}{\code{CorrelationParameters$sigma()}} +\item \href{#method-CorrelationParameters-mvnorm}{\code{CorrelationParameters$mvnorm()}} +\item \href{#method-CorrelationParameters-clone}{\code{CorrelationParameters$clone()}} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-new}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-CorrelationParameters-new}{}}} \subsection{Method \code{new()}}{ initialise correlation parameters \subsection{Usage}{ @@ -40,8 +40,8 @@ initialise correlation parameters } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-inter_round_rho}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-CorrelationParameters-inter_round_rho}{}}} \subsection{Method \code{inter_round_rho()}}{ Add rho between rounds \subsection{Usage}{ @@ -60,8 +60,8 @@ the intervention} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-inter_intervention_rho}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-CorrelationParameters-inter_intervention_rho}{}}} \subsection{Method \code{inter_intervention_rho()}}{ Add rho between interventions \subsection{Usage}{ @@ -83,8 +83,8 @@ the intervention} } } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-sigma}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-CorrelationParameters-sigma}{}}} \subsection{Method \code{sigma()}}{ Standard deviation of each intervention between rounds \subsection{Usage}{ @@ -93,8 +93,8 @@ Standard deviation of each intervention between rounds } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-mvnorm}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-CorrelationParameters-mvnorm}{}}} \subsection{Method \code{mvnorm()}}{ multivariate norm draws for these parameters \subsection{Usage}{ @@ -103,8 +103,8 @@ multivariate norm draws for these parameters } \if{html}{\out{
}} -\if{html}{\out{}} -\if{latex}{\out{\hypertarget{method-clone}{}}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-CorrelationParameters-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ diff --git a/man/get_antimalarial_resistance_parameters.Rd b/man/get_antimalarial_resistance_parameters.Rd index 34c0a9c6..71de6961 100644 --- a/man/get_antimalarial_resistance_parameters.Rd +++ b/man/get_antimalarial_resistance_parameters.Rd @@ -9,9 +9,9 @@ get_antimalarial_resistance_parameters(parameters, drugs, timestep) \arguments{ \item{parameters}{the model parameters} -\item{timestep}{the current time step} +\item{drugs}{vector of integers representing the drugs administered to each individual receiving treatment} -\item{drug}{vector of integers representing the drugs administered to each individual receiving treatment} +\item{timestep}{the current time step} } \description{ Retrieve the resistance parameters associated with the drug each individual receiving clinical From d16978e59261eca17193c6518101150ad95a1ee6 Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Thu, 15 Feb 2024 11:52:51 +0000 Subject: [PATCH 151/164] Added check for undeveloped antimalarial resistance features (SPC/LPF/LCF/RDP). Included test to ensure check works and amended documentation in get_parameters() to warn users features in development. --- R/antimalarial_resistance.R | 12 +- R/parameters.R | 12 +- man/get_parameters.Rd | 12 +- tests/testthat/test-antimalarial-resistance.R | 243 ++++++++++++------ 4 files changed, 186 insertions(+), 93 deletions(-) diff --git a/R/antimalarial_resistance.R b/R/antimalarial_resistance.R index 532c042b..18d14d9a 100644 --- a/R/antimalarial_resistance.R +++ b/R/antimalarial_resistance.R @@ -26,6 +26,14 @@ set_antimalarial_resistance <- function(parameters, reinfection_prob, slow_parasite_clearance_time) { + if(any(partner_drug_resistance > 0, + slow_parasite_clearance_prob > 0, + late_clinical_failure_prob > 0, + late_parasitological_prob > 0, + reinfection_prob > 0)) { + stop("Parameters set for unimplemented feature - late clinical failure, late parasitological failure, or reinfection during prophylaxis") + } + if(any(c(length(artemisinin_resistance), length(partner_drug_resistance), length(slow_parasite_clearance_prob), @@ -48,8 +56,8 @@ set_antimalarial_resistance <- function(parameters, reinfection_prob < 0 | reinfection_prob > 1)) { stop("Resistance outcome probabilities must fall between 0 and 1") } - - if(length(slow_parasite_clearance_time) != 1) { + + if(length(slow_parasite_clearance_time) != 1) { stop("Error: length of slow_parasite_clearance_time not equal to 1") } diff --git a/R/parameters.R b/R/parameters.R index 9abbeb60..473225fa 100644 --- a/R/parameters.R +++ b/R/parameters.R @@ -201,13 +201,13 @@ #' * antimalarial_resistance_drug - vector of drugs for which resistance can be parameterised; default = NULL #' * antimalarial_resistance_timesteps - vector of time steps on which resistance updates occur; default = NULL #' * prop_artemisinin_resistant - vector of proportions of infections resistant to the artemisinin component of a given drug; default = NULL -#' * prop_partner_drug_resistant - vector of proportions of infections resistant to the parter drug component of a given drug; default = NULL -#' * slow_parasite_clearance_prob - vector of probabilities of slow parasite clearance for a given drug; default = NULL +#' * prop_partner_drug_resistant - vector of proportions of infections resistant to the parter drug component of a given drug; default = NULL (currently unimplemented) +#' * slow_parasite_clearance_prob - vector of probabilities of slow parasite clearance for a given drug; default = NULL (currently unimplemented) #' * early_treatment_failure_prob - vector of probabilities of early treatment failure for a given drug; default = NULL -#' * late_clinical_failure_prob - vector of probabilities of late clinical failure for a given drug; default = NULL -#' * late_parasitological_failure_prob - vector of probabilities of late parasitological failure for a given drug; default = NULL -#' * reinfection_during_prophylaxis - vector of probabilities of reinfection during prophylaxis for a given drug; default = NULL -#' * dt_slow_parasite_clearance - the delay for humans experiencing slow parasite clearance to move from state Tr to S; default = NULL +#' * late_clinical_failure_prob - vector of probabilities of late clinical failure for a given drug; default = NULL (currently unimplemented) +#' * late_parasitological_failure_prob - vector of probabilities of late parasitological failure for a given drug; default = NULL (currently unimplemented) +#' * reinfection_during_prophylaxis - vector of probabilities of reinfection during prophylaxis for a given drug; default = NULL (currently unimplemented) +#' * dt_slow_parasite_clearance - the delay for humans experiencing slow parasite clearance to move from state Tr to S; default = NULL (currently unimplemented) #' #' rendering: #' All values are in timesteps and all ranges are inclusive diff --git a/man/get_parameters.Rd b/man/get_parameters.Rd index fc6ba000..1a0dde29 100644 --- a/man/get_parameters.Rd +++ b/man/get_parameters.Rd @@ -222,13 +222,13 @@ please set antimalarial resistance parameters with the convenience functions in \item antimalarial_resistance_drug - vector of drugs for which resistance can be parameterised; default = NULL \item antimalarial_resistance_timesteps - vector of time steps on which resistance updates occur; default = NULL \item prop_artemisinin_resistant - vector of proportions of infections resistant to the artemisinin component of a given drug; default = NULL -\item prop_partner_drug_resistant - vector of proportions of infections resistant to the parter drug component of a given drug; default = NULL -\item slow_parasite_clearance_prob - vector of probabilities of slow parasite clearance for a given drug; default = NULL +\item prop_partner_drug_resistant - vector of proportions of infections resistant to the parter drug component of a given drug; default = NULL (currently unimplemented) +\item slow_parasite_clearance_prob - vector of probabilities of slow parasite clearance for a given drug; default = NULL (currently unimplemented) \item early_treatment_failure_prob - vector of probabilities of early treatment failure for a given drug; default = NULL -\item late_clinical_failure_prob - vector of probabilities of late clinical failure for a given drug; default = NULL -\item late_parasitological_failure_prob - vector of probabilities of late parasitological failure for a given drug; default = NULL -\item reinfection_during_prophylaxis - vector of probabilities of reinfection during prophylaxis for a given drug; default = NULL -\item dt_slow_parasite_clearance - the delay for humans experiencing slow parasite clearance to move from state Tr to S; default = NULL +\item late_clinical_failure_prob - vector of probabilities of late clinical failure for a given drug; default = NULL (currently unimplemented) +\item late_parasitological_failure_prob - vector of probabilities of late parasitological failure for a given drug; default = NULL (currently unimplemented) +\item reinfection_during_prophylaxis - vector of probabilities of reinfection during prophylaxis for a given drug; default = NULL (currently unimplemented) +\item dt_slow_parasite_clearance - the delay for humans experiencing slow parasite clearance to move from state Tr to S; default = NULL (currently unimplemented) } rendering: diff --git a/tests/testthat/test-antimalarial-resistance.R b/tests/testthat/test-antimalarial-resistance.R index 400d93a3..feb7f67a 100644 --- a/tests/testthat/test-antimalarial-resistance.R +++ b/tests/testthat/test-antimalarial-resistance.R @@ -10,11 +10,11 @@ test_that('set_antimalarial_resistance() toggles resistance on', { timesteps = 1, artemisinin_resistance = 0.5, partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0.5, + slow_parasite_clearance_prob = 0, early_treatment_failure_prob = 0.6, - late_clinical_failure_prob = 0.2, - late_parasitological_prob = 0.3, - reinfection_prob = 0.4, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0, slow_parasite_clearance_time = 10) -> simparams expect_identical(object = simparams$antimalarial_resistance, expected = TRUE) }) @@ -31,11 +31,11 @@ test_that('set_antimalarial_resistance() errors if parameter inputs of different timesteps = c(1, 10), artemisinin_resistance = 0.5, partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0.5, + slow_parasite_clearance_prob = 0, early_treatment_failure_prob = 0.6, - late_clinical_failure_prob = 0.2, - late_parasitological_prob = 0.3, - reinfection_prob = 0.4, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0, slow_parasite_clearance_time = 10)) }) @@ -51,11 +51,11 @@ test_that('set_antimalarial_resistance() errors if resistance proportions outsid timesteps = 1, artemisinin_resistance = 1.01, partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0.5, + slow_parasite_clearance_prob = 0, early_treatment_failure_prob = 0.6, - late_clinical_failure_prob = 0.2, - late_parasitological_prob = 0.3, - reinfection_prob = 0.4, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0, slow_parasite_clearance_time = 10), regexp = "Artemisinin and partner-drug resistance proportions must fall between 0 and 1") }) @@ -72,11 +72,11 @@ test_that('set_antimalarial_resistance() errors if resistance phenotype probabil timesteps = 1, artemisinin_resistance = 0.4, partner_drug_resistance = 0, - slow_parasite_clearance_prob = -0.5, - early_treatment_failure_prob = 0.6, - late_clinical_failure_prob = 0.2, - late_parasitological_prob = 0.3, - reinfection_prob = 0.4, + slow_parasite_clearance_prob = 0, + early_treatment_failure_prob = -0.6, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0, slow_parasite_clearance_time = 5)) }) @@ -91,12 +91,12 @@ test_that('set_antimalarial_resistance() errors if drug index > than number of d drug = 2, timesteps = 1, artemisinin_resistance = 0.4, - partner_drug_resistance = 0.3, - slow_parasite_clearance_prob = 0.5, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0, early_treatment_failure_prob = 0.6, - late_clinical_failure_prob = 0.2, - late_parasitological_prob = 0.3, - reinfection_prob = 0.4)) + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0)) }) test_that('set_antimalarial_resistance() assigns parameters correctly despite order in which resistance parameters are specified', { @@ -111,7 +111,7 @@ test_that('set_antimalarial_resistance() assigns parameters correctly despite or timesteps = 1, artemisinin_resistance = 0.5, partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0.41, + slow_parasite_clearance_prob = 0, early_treatment_failure_prob = 0.2, late_clinical_failure_prob = 0, late_parasitological_prob = 0, @@ -120,36 +120,36 @@ test_that('set_antimalarial_resistance() assigns parameters correctly despite or parameters <- set_antimalarial_resistance(parameters = parameters, drug = 3, timesteps = 1, - artemisinin_resistance = 0, - partner_drug_resistance = 0.43, + artemisinin_resistance = 0.43, + partner_drug_resistance = 0, slow_parasite_clearance_prob = 0, early_treatment_failure_prob = 0, - late_clinical_failure_prob = 0.01, - late_parasitological_prob = 0.42, - reinfection_prob = 0.89, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0, slow_parasite_clearance_time = 10) parameters <- set_antimalarial_resistance(parameters = parameters, drug = 1, timesteps = 1, artemisinin_resistance = 0.27, - partner_drug_resistance = 0.61, - slow_parasite_clearance_prob = 0.23, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0, early_treatment_failure_prob = 0.9, - late_clinical_failure_prob = 0.49, - late_parasitological_prob = 0.81, - reinfection_prob = 0.009, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0, slow_parasite_clearance_time = 20) expect_identical(parameters$antimalarial_resistance, TRUE) expect_identical(unlist(parameters$antimalarial_resistance_drug), c(2, 3, 1)) expect_identical(unlist(parameters$antimalarial_resistance_timesteps), rep(1, 3)) - expect_identical(unlist(parameters$prop_artemisinin_resistant), c(0.5, 0, 0.27)) - expect_identical(unlist(parameters$prop_partner_drug_resistant), c(0, 0.43, 0.61)) - expect_identical(unlist(parameters$slow_parasite_clearance_prob), c(0.41, 0, 0.23)) + expect_identical(unlist(parameters$prop_artemisinin_resistant), c(0.5, 0.43, 0.27)) + expect_identical(unlist(parameters$prop_partner_drug_resistant), c(0, 0, 0)) + expect_identical(unlist(parameters$slow_parasite_clearance_prob), c(0, 0, 0)) expect_identical(unlist(parameters$early_treatment_failure_prob), c(0.2, 0, 0.9)) - expect_identical(unlist(parameters$late_clinical_failure_prob), c(0, 0.01, 0.49)) - expect_identical(unlist(parameters$late_parasitological_failure_prob), c(0, 0.42, 0.81)) - expect_identical(unlist(parameters$reinfection_during_prophylaxis), c(0, 0.89, 0.009)) + expect_identical(unlist(parameters$late_clinical_failure_prob), c(0, 0, 0)) + expect_identical(unlist(parameters$late_parasitological_failure_prob), c(0, 0, 0)) + expect_identical(unlist(parameters$reinfection_during_prophylaxis), c(0, 0, 0)) expect_identical(unlist(parameters$dt_slow_parasite_clearance), c(5, 10, 20)) }) @@ -168,12 +168,12 @@ test_that(desc = "set_antimalarial_resistance errors if length slow_parasite_cle drug = 1, timesteps = c(0, 10), artemisinin_resistance = c(0.4, 0.8), - partner_drug_resistance = c(0.23, 0.43), - slow_parasite_clearance_prob = c(0.2, 0.4), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = c(0, 0), early_treatment_failure_prob = c(0, 0.45), - late_clinical_failure_prob = c(0.01, 0.01), - late_parasitological_prob = c(0.05, 0.06), - reinfection_prob = c(0.86, 0.86), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), slow_parasite_clearance_time = c(10 ,11)), "Error: length of slow_parasite_clearance_time not equal to 1") }) @@ -192,16 +192,101 @@ test_that(desc = "set_antimalarial_resistance errors if slow_parasite_clearance_ drug = 1, timesteps = c(0, 10), artemisinin_resistance = c(0.4, 0.8), - partner_drug_resistance = c(0.23, 0.43), - slow_parasite_clearance_prob = c(0.2, 0.4), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = c(0, 0), early_treatment_failure_prob = c(0, 0.45), - late_clinical_failure_prob = c(0.01, 0.01), - late_parasitological_prob = c(0.05, 0.06), - reinfection_prob = c(0.86, 0.86), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), slow_parasite_clearance_time = c(0)), "Error: slow_parasite_clearance_time is non-positive") }) +test_that("set_antimalarial_resistance() errors when users attempt to use undeveloped model features", { + + # Partner Drug Resistance + expect_error(get_parameters() |> + set_drugs(drugs = list(SP_AQ_params)) |> + set_clinical_treatment(drug = 1, timesteps = 1, coverages = 0.6) |> + set_antimalarial_resistance(drug = 1, + timesteps = c(1, 10), + artemisinin_resistance = c(0.4, 0.5), + partner_drug_resistance = c(0, 0.5), + slow_parasite_clearance_prob = c(0, 0), + early_treatment_failure_prob = c(0.8, 0.8), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), + slow_parasite_clearance_time = 10), + "Parameters set for unimplemented feature - late clinical failure, late parasitological failure, or reinfection during prophylaxis") + + + # Slow Parasite Clearance + expect_error(get_parameters() |> + set_drugs(drugs = list(SP_AQ_params)) |> + set_clinical_treatment(drug = 1, timesteps = 1, coverages = 0.6) |> + set_antimalarial_resistance(drug = 1, + timesteps = c(1, 10), + artemisinin_resistance = c(0.4, 0.5), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = c(0, 0.0001), + early_treatment_failure_prob = c(0.8, 0.8), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), + slow_parasite_clearance_time = 10), + "Parameters set for unimplemented feature - late clinical failure, late parasitological failure, or reinfection during prophylaxis") + + # Late Clinical Failure + expect_error(get_parameters() |> + set_drugs(drugs = list(SP_AQ_params)) |> + set_clinical_treatment(drug = 1, timesteps = 1, coverages = 0.6) |> + set_antimalarial_resistance(drug = 1, + timesteps = c(1, 10), + artemisinin_resistance = c(0.4, 0.5), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = c(0, 0), + early_treatment_failure_prob = c(0.8, 0.8), + late_clinical_failure_prob = c(0.6, 0.43), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), + slow_parasite_clearance_time = 10), + "Parameters set for unimplemented feature - late clinical failure, late parasitological failure, or reinfection during prophylaxis") + + # Late Parasitological Failure + expect_error(get_parameters() |> + set_drugs(drugs = list(SP_AQ_params)) |> + set_clinical_treatment(drug = 1, timesteps = 1, coverages = 0.6) |> + set_antimalarial_resistance(drug = 1, + timesteps = c(1, 10), + artemisinin_resistance = c(0.4, 0.5), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = c(0, 0), + early_treatment_failure_prob = c(0.8, 0.8), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(1, 0), + reinfection_prob = c(0, 0), + slow_parasite_clearance_time = 10), + "Parameters set for unimplemented feature - late clinical failure, late parasitological failure, or reinfection during prophylaxis") + + # Reinfection During Prophylaxis + expect_error(get_parameters() |> + set_drugs(drugs = list(SP_AQ_params)) |> + set_clinical_treatment(drug = 1, timesteps = 1, coverages = 0.6) |> + set_antimalarial_resistance(drug = 1, + timesteps = c(1, 10), + artemisinin_resistance = c(0.4, 0.5), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = c(0, 0), + early_treatment_failure_prob = c(0.8, 0.8), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0.21, 0), + slow_parasite_clearance_time = 10), + "Parameters set for unimplemented feature - late clinical failure, late parasitological failure, or reinfection during prophylaxis") + +}) + test_that('get_antimalarial_resistance_parameters() correctly retrieves parameters when multiple drugs assigned', { get_parameters(overrides = list(human_population = 10000)) %>% @@ -213,32 +298,32 @@ test_that('get_antimalarial_resistance_parameters() correctly retrieves paramete set_antimalarial_resistance(drug = 2, timesteps = c(0, 20), artemisinin_resistance = c(0.02, 0.2), - partner_drug_resistance = c(0.02, 0.2), - slow_parasite_clearance_prob = c(0.02, 0.2), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = c(0, 0), early_treatment_failure_prob = c(0.02, 0.2), - late_clinical_failure_prob = c(0.02, 0.2), - late_parasitological_prob = c(0.02, 0.2), - reinfection_prob = c(0.02, 0.2), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), slow_parasite_clearance_time = 20) %>% set_antimalarial_resistance(drug = 1, timesteps = c(0, 10), artemisinin_resistance = c(0.01, 0.1), - partner_drug_resistance = c(0.01, 0.1), - slow_parasite_clearance_prob = c(0.01, 0.1), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = c(0, 0), early_treatment_failure_prob = c(0.01, 0.1), - late_clinical_failure_prob = c(0.01, 0.1), - late_parasitological_prob = c(0.01, 0.1), - reinfection_prob = c(0.01, 0.1), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), slow_parasite_clearance_time = 10) %>% set_antimalarial_resistance(drug = 3, timesteps = c(0, 30), artemisinin_resistance = c(0.03, 0.3), - partner_drug_resistance = c(0.03, 0.3), - slow_parasite_clearance_prob = c(0.03, 0.3), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = c(0, 0), early_treatment_failure_prob = c(0.03, 0.3), - late_clinical_failure_prob = c(0.03, 0.3), - late_parasitological_prob = c(0.03, 0.3), - reinfection_prob = c(0.03, 0.3), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), slow_parasite_clearance_time = 30) -> parameters drugs <- c(1, 3, 2, 1, 2, 3, 3, 3, 2, 1, 3, 1, 2, 3, 2) @@ -250,12 +335,12 @@ test_that('get_antimalarial_resistance_parameters() correctly retrieves paramete expected_resistance_parameters <- list() expected_resistance_parameters$artemisinin_resistance_proportion <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) - expected_resistance_parameters$partner_drug_resistance_proportion <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) - expected_resistance_parameters$slow_parasite_clearance_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) + expected_resistance_parameters$partner_drug_resistance_proportion <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + expected_resistance_parameters$slow_parasite_clearance_probability <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) expected_resistance_parameters$early_treatment_failure_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) - expected_resistance_parameters$late_clinical_failure_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) - expected_resistance_parameters$late_parasitological_failure_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) - expected_resistance_parameters$reinfection_during_prophylaxis_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) + expected_resistance_parameters$late_clinical_failure_probability <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + expected_resistance_parameters$late_parasitological_failure_probability <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + expected_resistance_parameters$reinfection_during_prophylaxis_probability <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) expected_resistance_parameters$dt_slow_parasite_clearance <- c(10, 30, 20, 10, 20, 30, 30, 30, 20, 10, 30, 10, 20, 30, 20) expect_identical(resistance_parameters, expected = expected_resistance_parameters) @@ -273,12 +358,12 @@ test_that('get_antimalarial_resistance_parameters() correctly retrieves paramete set_antimalarial_resistance(drug = 2, timesteps = c(0, 20), artemisinin_resistance = c(0.02, 0.2), - partner_drug_resistance = c(0.02, 0.2), - slow_parasite_clearance_prob = c(0.02, 0.2), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = c(0, 0), early_treatment_failure_prob = c(0.02, 0.2), - late_clinical_failure_prob = c(0.02, 0.2), - late_parasitological_prob = c(0.02, 0.2), - reinfection_prob = c(0.02, 0.2), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), slow_parasite_clearance_time = 20) -> parameters drugs <- c(1, 3, 2, 1, 2, 3, 3, 3, 2, 1, 3, 1, 2, 3, 2) @@ -290,12 +375,12 @@ test_that('get_antimalarial_resistance_parameters() correctly retrieves paramete expected_resistance_parameters <- list() expected_resistance_parameters$artemisinin_resistance_proportion <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) - expected_resistance_parameters$partner_drug_resistance_proportion <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) - expected_resistance_parameters$slow_parasite_clearance_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) + expected_resistance_parameters$partner_drug_resistance_proportion <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + expected_resistance_parameters$slow_parasite_clearance_probability <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) expected_resistance_parameters$early_treatment_failure_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) - expected_resistance_parameters$late_clinical_failure_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) - expected_resistance_parameters$late_parasitological_failure_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) - expected_resistance_parameters$reinfection_during_prophylaxis_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) + expected_resistance_parameters$late_clinical_failure_probability <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + expected_resistance_parameters$late_parasitological_failure_probability <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + expected_resistance_parameters$reinfection_during_prophylaxis_probability <- c(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) expected_resistance_parameters$dt_slow_parasite_clearance <- c(5, 5, 20, 5, 20, 5, 5, 5, 20, 5, 5, 5, 20, 5, 20) expect_identical(resistance_parameters, expected = expected_resistance_parameters) From c42e2c52cee9f70e6067f8e6474e62f8428bcae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Li=C3=A9tar?= Date: Tue, 27 Feb 2024 20:02:49 +0000 Subject: [PATCH 152/164] Add initial support for saving and restoring simulation state. (#280) The model can now be run for a given number of steps, have its state saved, and then restore it and run for some more time steps. Parameters of the model may be modified when resuming, allowing a simulation to be forked with a single historical run and many futures, modelling different intervention scenarios. There are some limitations as to which parameters may be modified. In general, the structure of the simulation must remain the same, with the same variables and same events. This means interventions cannot be enabled or disabled when resuming, only their parameterization can change. Additionally, the timing of intervention events should not be modified. These limitations may be relaxed in the future, if there is a need for it. To avoid changing the existing API, this feature is available as a new `run_resumable_simulation` function. The function returns a pair of values, the existing dataframe with the simulation data and an object representing the internal simulation state. The function can be called a second time, passing the saved simulation state as an extra argument. See the `test-resume.R` file for usage of the new function. The implementation builds on top of individual's new support for this. Individual already saves the state of its native objects, ie. variables and events. The malaria model keeps quite a bit of state outside of individual, which we need to save and restore explicitly. This is done by creating a set of "stateful objects", ie. R6 objects with a pair `save_state` and `restore_state` methods. This interface is implemented by every bit of the model that has state to capture: - `LaggedValue` objects store the short term EIR and FOIM history. - `Solver` objects represent the current state of ODE solvers. - Adult mosquito ODEs keep a history of incubating values which need to be restored. - `CorrelationParameters` stores a randomly sampled value. This needs to be saved to ensure the simulation is resumed with that same value. - In addition to R's native RNG (whose state is already saved by individual), the model uses the dqrng library, whose state needs saving. --- DESCRIPTION | 6 +- R/RcppExports.R | 28 +++++++ R/biting_process.R | 8 +- R/compartmental.R | 81 +++++++++++++++++--- R/correlation.R | 19 +++++ R/lag.R | 8 ++ R/model.R | 64 ++++++++++++++-- R/mosquito_biology.R | 2 +- R/render.R | 2 +- R/stateful.R | 47 ++++++++++++ man/CorrelationParameters.Rd | 32 ++++++++ man/run_resumable_simulation.Rd | 34 +++++++++ src/Random.cpp | 15 +++- src/Random.h | 3 + src/RcppExports.cpp | 84 ++++++++++++++++++++- src/adult_mosquito_eqs.cpp | 24 +++++- src/adult_mosquito_eqs.h | 2 +- src/solver.cpp | 5 ++ src/timeseries.cpp | 51 +++++++++++-- src/timeseries.h | 5 +- src/utils.cpp | 10 +++ tests/testthat/helper-integration.R | 7 ++ tests/testthat/test-biting-integration.R | 2 +- tests/testthat/test-compartmental.R | 39 +++++++--- tests/testthat/test-emergence-integration.R | 33 ++++---- tests/testthat/test-resume.R | 41 ++++++++++ tests/testthat/test-seasonality.R | 6 +- 27 files changed, 583 insertions(+), 75 deletions(-) create mode 100644 R/stateful.R create mode 100644 man/run_resumable_simulation.Rd create mode 100644 tests/testthat/test-resume.R diff --git a/DESCRIPTION b/DESCRIPTION index 1d971723..ce25ce05 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -69,13 +69,15 @@ LazyData: true Remotes: mrc-ide/malariaEquilibrium, mrc-ide/individual +Additional_repositories: + https://mrc-ide.r-universe.dev Imports: - individual (>= 0.1.7), + individual (>= 0.1.13), malariaEquilibrium (>= 1.0.1), Rcpp, statmod, MASS, - dqrng, + dqrng (>= 0.3.2.2), sitmo, BH, R6, diff --git a/R/RcppExports.R b/R/RcppExports.R index 73a51dd0..01f3dc11 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -9,6 +9,14 @@ adult_mosquito_model_update <- function(model, mu, foim, susceptible, f) { invisible(.Call(`_malariasimulation_adult_mosquito_model_update`, model, mu, foim, susceptible, f)) } +adult_mosquito_model_save_state <- function(model) { + .Call(`_malariasimulation_adult_mosquito_model_save_state`, model) +} + +adult_mosquito_model_restore_state <- function(model, state) { + invisible(.Call(`_malariasimulation_adult_mosquito_model_restore_state`, model, state)) +} + create_adult_solver <- function(model, init, r_tol, a_tol, max_steps) { .Call(`_malariasimulation_create_adult_solver`, model, init, r_tol, a_tol, max_steps) } @@ -41,6 +49,10 @@ solver_get_states <- function(solver) { .Call(`_malariasimulation_solver_get_states`, solver) } +solver_set_states <- function(solver, state) { + invisible(.Call(`_malariasimulation_solver_set_states`, solver, state)) +} + solver_step <- function(solver) { invisible(.Call(`_malariasimulation_solver_step`, solver)) } @@ -57,10 +69,26 @@ timeseries_push <- function(timeseries, value, timestep) { invisible(.Call(`_malariasimulation_timeseries_push`, timeseries, value, timestep)) } +timeseries_save_state <- function(timeseries) { + .Call(`_malariasimulation_timeseries_save_state`, timeseries) +} + +timeseries_restore_state <- function(timeseries, state) { + invisible(.Call(`_malariasimulation_timeseries_restore_state`, timeseries, state)) +} + random_seed <- function(seed) { invisible(.Call(`_malariasimulation_random_seed`, seed)) } +random_save_state <- function() { + .Call(`_malariasimulation_random_save_state`) +} + +random_restore_state <- function(state) { + invisible(.Call(`_malariasimulation_random_restore_state`, state)) +} + bernoulli_multi_p_cpp <- function(p) { .Call(`_malariasimulation_bernoulli_multi_p_cpp`, p) } diff --git a/R/biting_process.R b/R/biting_process.R index ec09620d..801aea20 100644 --- a/R/biting_process.R +++ b/R/biting_process.R @@ -103,7 +103,7 @@ simulate_bites <- function( for (s_i in seq_along(parameters$species)) { species_name <- parameters$species[[s_i]] - solver_states <- solver_get_states(solvers[[s_i]]) + solver_states <- solvers[[s_i]]$get_states() p_bitten <- prob_bitten(timestep, variables, s_i, parameters) Q0 <- parameters$Q0[[s_i]] W <- average_p_successful(p_bitten$prob_bitten_survives, .pi, Q0) @@ -167,7 +167,7 @@ simulate_bites <- function( if (parameters$individual_mosquitoes) { # update the ODE with stats for ovoposition calculations aquatic_mosquito_model_update( - models[[s_i]], + models[[s_i]]$.model, species_index$size(), f, mu @@ -189,7 +189,7 @@ simulate_bites <- function( ) } else { adult_mosquito_model_update( - models[[s_i]], + models[[s_i]]$.model, mu, foim, solver_states[[ADULT_ODE_INDICES['Sm']]], @@ -235,7 +235,7 @@ calculate_infectious <- function(species, solvers, variables, parameters) { ) ) } - calculate_infectious_compartmental(solver_get_states(solvers[[species]])) + calculate_infectious_compartmental(solvers[[species]]$get_states()) } calculate_infectious_individual <- function( diff --git a/R/compartmental.R b/R/compartmental.R index f3405728..7df83a6e 100644 --- a/R/compartmental.R +++ b/R/compartmental.R @@ -50,16 +50,16 @@ parameterise_mosquito_models <- function(parameters, timesteps) { m )[ADULT_ODE_INDICES['Sm']] return( - create_adult_mosquito_model( + AdultMosquitoModel$new(create_adult_mosquito_model( growth_model, parameters$mum[[i]], parameters$dem, susceptible * parameters$init_foim, parameters$init_foim - ) + )) ) } - growth_model + AquaticMosquitoModel$new(growth_model) } ) } @@ -72,22 +72,22 @@ parameterise_solvers <- function(models, parameters) { init <- initial_mosquito_counts(parameters, i, parameters$init_foim, m) if (!parameters$individual_mosquitoes) { return( - create_adult_solver( - models[[i]], + Solver$new(create_adult_solver( + models[[i]]$.model, init, parameters$r_tol, parameters$a_tol, parameters$ode_max_steps - ) + )) ) } - create_aquatic_solver( - models[[i]], + Solver$new(create_aquatic_solver( + models[[i]]$.model, init[ODE_INDICES], parameters$r_tol, parameters$a_tol, parameters$ode_max_steps - ) + )) } ) } @@ -103,7 +103,7 @@ create_compartmental_rendering_process <- function(renderer, solvers, parameters counts <- rep(0, length(indices)) for (s_i in seq_along(solvers)) { if (parameters$species_proportions[[s_i]] > 0) { - row <- solver_get_states(solvers[[s_i]]) + row <- solvers[[s_i]]$get_states() } else { row <- rep(0, length(indices)) } @@ -128,8 +128,67 @@ create_solver_stepping_process <- function(solvers, parameters) { function(timestep) { for (i in seq_along(solvers)) { if (parameters$species_proportions[[i]] > 0) { - solver_step(solvers[[i]]) + solvers[[i]]$step() } } } } + +Solver <- R6::R6Class( + 'Solver', + private = list( + .solver = NULL + ), + public = list( + initialize = function(solver) { + private$.solver <- solver + }, + step = function() { + solver_step(private$.solver) + }, + get_states = function() { + solver_get_states(private$.solver) + }, + + # This is the same as `get_states`, just exposed under the interface that + # is expected of stateful objects. + save_state = function() { + solver_get_states(private$.solver) + }, + restore_state = function(state) { + solver_set_states(private$.solver, state) + } + ) +) + +AquaticMosquitoModel <- R6::R6Class( + 'AquaticMosquitoModel', + public = list( + .model = NULL, + initialize = function(model) { + self$.model <- model + }, + + # The aquatic mosquito model doesn't have any state to save or restore (the + # state of the ODE is stored separately). We still provide these methods to + # conform to the expected interface. + save_state = function() { NULL }, + restore_state = function(state) { } + ) +) + +AdultMosquitoModel <- R6::R6Class( + 'AdultMosquitoModel', + public = list( + .model = NULL, + initialize = function(model) { + self$.model <- model + }, + save_state = function() { + adult_mosquito_model_save_state(self$.model) + }, + restore_state = function(state) { + adult_mosquito_model_restore_state(self$.model, state) + } + ) +) diff --git a/R/correlation.R b/R/correlation.R index 68119369..df5f88f5 100644 --- a/R/correlation.R +++ b/R/correlation.R @@ -115,6 +115,25 @@ CorrelationParameters <- R6::R6Class( dimnames(private$.mvnorm)[[2]] <- private$interventions } private$.mvnorm + }, + + #' @description Save the correlation state. + save_state = function() { + # mvnorm is sampled at random lazily on its first use. We need to save it + # in order to restore the same value when resuming the simulation, + # otherwise we would be drawing a new, probably different, value. + # The rest of the object is derived deterministically from the parameters + # and does not need saving. + list(mvnorm=private$.mvnorm) + }, + + #' @description Restore the correlation state. + #' Only the randomly drawn weights are restored. The object needs to be + #' initialized with the same rhos. + #' @param state a previously saved correlation state, as returned by the + #' save_state method. + restore_state = function(state) { + private$.mvnorm <- state$mvnorm } ) ) diff --git a/R/lag.R b/R/lag.R index 35e47026..ca858ac7 100644 --- a/R/lag.R +++ b/R/lag.R @@ -14,6 +14,14 @@ LaggedValue <- R6::R6Class( get = function(timestep) { timeseries_at(private$history, timestep, TRUE) + }, + + save_state = function() { + timeseries_save_state(private$history) + }, + + restore_state = function(state) { + timeseries_restore_state(private$history, state) } ) ) diff --git a/R/model.R b/R/model.R index 4c4f7c2b..34bbfb46 100644 --- a/R/model.R +++ b/R/model.R @@ -87,6 +87,28 @@ run_simulation <- function( timesteps, parameters = NULL, correlations = NULL +) { + run_resumable_simulation(timesteps, parameters, correlations)$data +} + +#' @title Run the simulation in a resumable way +#' +#' @description this function accepts an initial simulation state as an argument, and returns the +#' final state after running all of its timesteps. This allows one run to be resumed, possibly +#' having changed some of the parameters. +#' @param timesteps the timestep at which to stop the simulation +#' @param parameters a named list of parameters to use +#' @param correlations correlation parameters +#' @param initial_state the state from which the simulation is resumed +#' @param restore_random_state if TRUE, restore the random number generator's state from the checkpoint. +#' @return a list with two entries, one for the dataframe of results and one for the final +#' simulation state. +run_resumable_simulation <- function( + timesteps, + parameters = NULL, + correlations = NULL, + initial_state = NULL, + restore_random_state = FALSE ) { random_seed(ceiling(runif(1) * .Machine$integer.max)) if (is.null(parameters)) { @@ -108,7 +130,23 @@ run_simulation <- function( ) vector_models <- parameterise_mosquito_models(parameters, timesteps) solvers <- parameterise_solvers(vector_models, parameters) - individual::simulation_loop( + + lagged_eir <- create_lagged_eir(variables, solvers, parameters) + lagged_infectivity <- create_lagged_infectivity(variables, parameters) + + stateful_objects <- unlist(list( + RandomState$new(restore_random_state), + correlations, + vector_models, + solvers, + lagged_eir, + lagged_infectivity)) + + if (!is.null(initial_state)) { + restore_state(initial_state$malariasimulation, stateful_objects) + } + + individual_state <- individual::simulation_loop( processes = create_processes( renderer, variables, @@ -117,15 +155,31 @@ run_simulation <- function( vector_models, solvers, correlations, - list(create_lagged_eir(variables, solvers, parameters)), - list(create_lagged_infectivity(variables, parameters)), + list(lagged_eir), + list(lagged_infectivity), timesteps ), variables = variables, events = unlist(events), - timesteps = timesteps + timesteps = timesteps, + state = initial_state$individual, + restore_random_state = restore_random_state ) - renderer$to_dataframe() + + final_state <- list( + timesteps=timesteps, + individual=individual_state, + malariasimulation=save_state(stateful_objects) + ) + + data <- renderer$to_dataframe() + if (!is.null(initial_state)) { + # Drop the timesteps we didn't simulate from the data. + # It would just be full of NA. + data <- data[-(1:initial_state$timesteps),] + } + + list(data=data, state=final_state) } #' @title Run a metapopulation model diff --git a/R/mosquito_biology.R b/R/mosquito_biology.R index 381450d9..4225a46f 100644 --- a/R/mosquito_biology.R +++ b/R/mosquito_biology.R @@ -220,7 +220,7 @@ create_mosquito_emergence_process <- function( p_counts <- vnapply( solvers, function(solver) { - solver_get_states(solver)[[ODE_INDICES[['P']]]] + solver$get_states()[[ODE_INDICES[['P']]]] } ) n <- sum(p_counts) * rate diff --git a/R/render.R b/R/render.R index 3fcf4882..60cb5b73 100644 --- a/R/render.R +++ b/R/render.R @@ -146,7 +146,7 @@ create_total_M_renderer_compartmental <- function(renderer, solvers, parameters) function(timestep) { total_M <- 0 for (i in seq_along(solvers)) { - row <- solver_get_states(solvers[[i]]) + row <- solvers[[i]]$get_states() species_M <- sum(row[ADULT_ODE_INDICES]) total_M <- total_M + species_M renderer$render(paste0('total_M_', parameters$species[[i]]), species_M, timestep) diff --git a/R/stateful.R b/R/stateful.R new file mode 100644 index 00000000..05c614a0 --- /dev/null +++ b/R/stateful.R @@ -0,0 +1,47 @@ +#' @title Save the state of a list of \emph{stateful objects} +#' @description The state of each element is saved and stored into a single +#' object, representing them in a way that can be exported and re-used later. +#' @param objects A list of stateful objects to be saved. Stateful objects are +#' instances of R6 classes with a pair of \code{save_state} and +#' \code{restore_state} methods. +#' @noRd +save_state <- function(objects) { + lapply(objects, function(o) o$save_state()) +} + +#' @title Restore the state of a collection of stateful objects +#' @description This is the counterpart of \code{save_state}. Calling it +#' restores the collection of objects back into their original state. +#' @param state A state object, as returned by the \code{save_state} function. +#' @param objects A collection of stateful objects to be restored. +#' @noRd +restore_state <- function(state, objects) { + stopifnot(length(state) == length(objects)) + for (i in seq_along(state)) { + objects[[i]]$restore_state(state[[i]]) + } +} + +#' @title a placeholder class to save the random number generator class. +#' @description the class integrates with the simulation loop to save and +#' restore the random number generator class when appropriate. +#' @noRd +RandomState <- R6::R6Class( + 'RandomState', + private = list( + restore_random_state = NULL + ), + public = list( + initialize = function(restore_random_state) { + private$restore_random_state <- restore_random_state + }, + save_state = function() { + random_save_state() + }, + restore_state = function(state) { + if (private$restore_random_state) { + random_restore_state(state) + } + } + ) +) diff --git a/man/CorrelationParameters.Rd b/man/CorrelationParameters.Rd index c2e6ada7..480d663d 100644 --- a/man/CorrelationParameters.Rd +++ b/man/CorrelationParameters.Rd @@ -19,6 +19,8 @@ Describes an event in the simulation \item \href{#method-CorrelationParameters-inter_intervention_rho}{\code{CorrelationParameters$inter_intervention_rho()}} \item \href{#method-CorrelationParameters-sigma}{\code{CorrelationParameters$sigma()}} \item \href{#method-CorrelationParameters-mvnorm}{\code{CorrelationParameters$mvnorm()}} +\item \href{#method-CorrelationParameters-save_state}{\code{CorrelationParameters$save_state()}} +\item \href{#method-CorrelationParameters-restore_state}{\code{CorrelationParameters$restore_state()}} \item \href{#method-CorrelationParameters-clone}{\code{CorrelationParameters$clone()}} } } @@ -101,6 +103,36 @@ multivariate norm draws for these parameters \if{html}{\out{
}}\preformatted{CorrelationParameters$mvnorm()}\if{html}{\out{
}} } +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-CorrelationParameters-save_state}{}}} +\subsection{Method \code{save_state()}}{ +Save the correlation state. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{CorrelationParameters$save_state()}\if{html}{\out{
}} +} + +} +\if{html}{\out{
}} +\if{html}{\out{}} +\if{latex}{\out{\hypertarget{method-CorrelationParameters-restore_state}{}}} +\subsection{Method \code{restore_state()}}{ +Restore the correlation state. +Only the randomly drawn weights are restored. The object needs to be +initialized with the same rhos. +\subsection{Usage}{ +\if{html}{\out{
}}\preformatted{CorrelationParameters$restore_state(state)}\if{html}{\out{
}} +} + +\subsection{Arguments}{ +\if{html}{\out{
}} +\describe{ +\item{\code{state}}{a previously saved correlation state, as returned by the +save_state method.} +} +\if{html}{\out{
}} +} } \if{html}{\out{
}} \if{html}{\out{}} diff --git a/man/run_resumable_simulation.Rd b/man/run_resumable_simulation.Rd new file mode 100644 index 00000000..8991fd1c --- /dev/null +++ b/man/run_resumable_simulation.Rd @@ -0,0 +1,34 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/model.R +\name{run_resumable_simulation} +\alias{run_resumable_simulation} +\title{Run the simulation in a resumable way} +\usage{ +run_resumable_simulation( + timesteps, + parameters = NULL, + correlations = NULL, + initial_state = NULL, + restore_random_state = FALSE +) +} +\arguments{ +\item{timesteps}{the timestep at which to stop the simulation} + +\item{parameters}{a named list of parameters to use} + +\item{correlations}{correlation parameters} + +\item{initial_state}{the state from which the simulation is resumed} + +\item{restore_random_state}{if TRUE, restore the random number generator's state from the checkpoint.} +} +\value{ +a list with two entries, one for the dataframe of results and one for the final +simulation state. +} +\description{ +this function accepts an initial simulation state as an argument, and returns the +final state after running all of its timesteps. This allows one run to be resumed, possibly +having changed some of the parameters. +} diff --git a/src/Random.cpp b/src/Random.cpp index fad22963..2906ccc7 100644 --- a/src/Random.cpp +++ b/src/Random.cpp @@ -61,7 +61,7 @@ void Random::prop_sample_bucket( // all probabilities are the same if (heavy == n) { for (auto i = 0; i < size; ++i) { - *result = (*rng)(n); + *result = (*rng)((uint64_t)n); ++result; } return; @@ -122,10 +122,21 @@ void Random::prop_sample_bucket( // sample for (auto i = 0; i < size; ++i) { - size_t bucket = (*rng)(n); + size_t bucket = (*rng)((uint64_t)n); double acceptance = dqrng::uniform01((*rng)()); *result = (acceptance < dividing_probs[bucket]) ? bucket : alternative_index[bucket]; ++result; } } + +std::string Random::save_state() { + std::ostringstream stream; + stream << *rng; + return stream.str(); +} + +void Random::restore_state(std::string state) { + std::istringstream stream(state); + stream >> *rng; +} diff --git a/src/Random.h b/src/Random.h index b6e15039..e796fb9a 100644 --- a/src/Random.h +++ b/src/Random.h @@ -58,6 +58,9 @@ class Random : public RandomInterface { Random(Random &&other) = delete; Random& operator=(const Random &other) = delete; Random& operator=(Random &&other) = delete; + + std::string save_state(); + void restore_state(std::string state); private: Random() : rng(dqrng::generator(42)) {}; }; diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index f5c226fd..7675e8e6 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -40,6 +40,28 @@ BEGIN_RCPP return R_NilValue; END_RCPP } +// adult_mosquito_model_save_state +std::vector adult_mosquito_model_save_state(Rcpp::XPtr model); +RcppExport SEXP _malariasimulation_adult_mosquito_model_save_state(SEXP modelSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< Rcpp::XPtr >::type model(modelSEXP); + rcpp_result_gen = Rcpp::wrap(adult_mosquito_model_save_state(model)); + return rcpp_result_gen; +END_RCPP +} +// adult_mosquito_model_restore_state +void adult_mosquito_model_restore_state(Rcpp::XPtr model, std::vector state); +RcppExport SEXP _malariasimulation_adult_mosquito_model_restore_state(SEXP modelSEXP, SEXP stateSEXP) { +BEGIN_RCPP + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< Rcpp::XPtr >::type model(modelSEXP); + Rcpp::traits::input_parameter< std::vector >::type state(stateSEXP); + adult_mosquito_model_restore_state(model, state); + return R_NilValue; +END_RCPP +} // create_adult_solver Rcpp::XPtr create_adult_solver(Rcpp::XPtr model, std::vector init, double r_tol, double a_tol, size_t max_steps); RcppExport SEXP _malariasimulation_create_adult_solver(SEXP modelSEXP, SEXP initSEXP, SEXP r_tolSEXP, SEXP a_tolSEXP, SEXP max_stepsSEXP) { @@ -168,6 +190,17 @@ BEGIN_RCPP return rcpp_result_gen; END_RCPP } +// solver_set_states +void solver_set_states(Rcpp::XPtr solver, std::vector state); +RcppExport SEXP _malariasimulation_solver_set_states(SEXP solverSEXP, SEXP stateSEXP) { +BEGIN_RCPP + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< Rcpp::XPtr >::type solver(solverSEXP); + Rcpp::traits::input_parameter< std::vector >::type state(stateSEXP); + solver_set_states(solver, state); + return R_NilValue; +END_RCPP +} // solver_step void solver_step(Rcpp::XPtr solver); RcppExport SEXP _malariasimulation_solver_step(SEXP solverSEXP) { @@ -215,6 +248,28 @@ BEGIN_RCPP return R_NilValue; END_RCPP } +// timeseries_save_state +Rcpp::List timeseries_save_state(Rcpp::XPtr timeseries); +RcppExport SEXP _malariasimulation_timeseries_save_state(SEXP timeseriesSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< Rcpp::XPtr >::type timeseries(timeseriesSEXP); + rcpp_result_gen = Rcpp::wrap(timeseries_save_state(timeseries)); + return rcpp_result_gen; +END_RCPP +} +// timeseries_restore_state +void timeseries_restore_state(Rcpp::XPtr timeseries, Rcpp::List state); +RcppExport SEXP _malariasimulation_timeseries_restore_state(SEXP timeseriesSEXP, SEXP stateSEXP) { +BEGIN_RCPP + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< Rcpp::XPtr >::type timeseries(timeseriesSEXP); + Rcpp::traits::input_parameter< Rcpp::List >::type state(stateSEXP); + timeseries_restore_state(timeseries, state); + return R_NilValue; +END_RCPP +} // random_seed void random_seed(size_t seed); RcppExport SEXP _malariasimulation_random_seed(SEXP seedSEXP) { @@ -225,6 +280,26 @@ BEGIN_RCPP return R_NilValue; END_RCPP } +// random_save_state +std::string random_save_state(); +RcppExport SEXP _malariasimulation_random_save_state() { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + rcpp_result_gen = Rcpp::wrap(random_save_state()); + return rcpp_result_gen; +END_RCPP +} +// random_restore_state +void random_restore_state(std::string state); +RcppExport SEXP _malariasimulation_random_restore_state(SEXP stateSEXP) { +BEGIN_RCPP + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< std::string >::type state(stateSEXP); + random_restore_state(state); + return R_NilValue; +END_RCPP +} // bernoulli_multi_p_cpp std::vector bernoulli_multi_p_cpp(const std::vector p); RcppExport SEXP _malariasimulation_bernoulli_multi_p_cpp(SEXP pSEXP) { @@ -260,11 +335,13 @@ BEGIN_RCPP END_RCPP } -RcppExport SEXP run_testthat_tests(); +RcppExport SEXP run_testthat_tests(void); static const R_CallMethodDef CallEntries[] = { {"_malariasimulation_create_adult_mosquito_model", (DL_FUNC) &_malariasimulation_create_adult_mosquito_model, 5}, {"_malariasimulation_adult_mosquito_model_update", (DL_FUNC) &_malariasimulation_adult_mosquito_model_update, 5}, + {"_malariasimulation_adult_mosquito_model_save_state", (DL_FUNC) &_malariasimulation_adult_mosquito_model_save_state, 1}, + {"_malariasimulation_adult_mosquito_model_restore_state", (DL_FUNC) &_malariasimulation_adult_mosquito_model_restore_state, 2}, {"_malariasimulation_create_adult_solver", (DL_FUNC) &_malariasimulation_create_adult_solver, 5}, {"_malariasimulation_create_aquatic_mosquito_model", (DL_FUNC) &_malariasimulation_create_aquatic_mosquito_model, 18}, {"_malariasimulation_aquatic_mosquito_model_update", (DL_FUNC) &_malariasimulation_aquatic_mosquito_model_update, 4}, @@ -273,11 +350,16 @@ static const R_CallMethodDef CallEntries[] = { {"_malariasimulation_eggs_laid", (DL_FUNC) &_malariasimulation_eggs_laid, 3}, {"_malariasimulation_rainfall", (DL_FUNC) &_malariasimulation_rainfall, 5}, {"_malariasimulation_solver_get_states", (DL_FUNC) &_malariasimulation_solver_get_states, 1}, + {"_malariasimulation_solver_set_states", (DL_FUNC) &_malariasimulation_solver_set_states, 2}, {"_malariasimulation_solver_step", (DL_FUNC) &_malariasimulation_solver_step, 1}, {"_malariasimulation_create_timeseries", (DL_FUNC) &_malariasimulation_create_timeseries, 2}, {"_malariasimulation_timeseries_at", (DL_FUNC) &_malariasimulation_timeseries_at, 3}, {"_malariasimulation_timeseries_push", (DL_FUNC) &_malariasimulation_timeseries_push, 3}, + {"_malariasimulation_timeseries_save_state", (DL_FUNC) &_malariasimulation_timeseries_save_state, 1}, + {"_malariasimulation_timeseries_restore_state", (DL_FUNC) &_malariasimulation_timeseries_restore_state, 2}, {"_malariasimulation_random_seed", (DL_FUNC) &_malariasimulation_random_seed, 1}, + {"_malariasimulation_random_save_state", (DL_FUNC) &_malariasimulation_random_save_state, 0}, + {"_malariasimulation_random_restore_state", (DL_FUNC) &_malariasimulation_random_restore_state, 1}, {"_malariasimulation_bernoulli_multi_p_cpp", (DL_FUNC) &_malariasimulation_bernoulli_multi_p_cpp, 1}, {"_malariasimulation_bitset_index_cpp", (DL_FUNC) &_malariasimulation_bitset_index_cpp, 2}, {"_malariasimulation_fast_weighted_sample", (DL_FUNC) &_malariasimulation_fast_weighted_sample, 2}, diff --git a/src/adult_mosquito_eqs.cpp b/src/adult_mosquito_eqs.cpp index ad5553eb..8126c7d7 100644 --- a/src/adult_mosquito_eqs.cpp +++ b/src/adult_mosquito_eqs.cpp @@ -17,7 +17,7 @@ AdultMosquitoModel::AdultMosquitoModel( ) : growth_model(growth_model), mu(mu), tau(tau), foim(foim) { for (auto i = 0u; i < tau; ++i) { - lagged_incubating.push(incubating); + lagged_incubating.push_back(incubating); } } @@ -82,12 +82,30 @@ void adult_mosquito_model_update( model->foim = foim; model->growth_model.f = f; model->growth_model.mum = mu; - model->lagged_incubating.push(susceptible * foim); + model->lagged_incubating.push_back(susceptible * foim); if (model->lagged_incubating.size() > 0) { - model->lagged_incubating.pop(); + model->lagged_incubating.pop_front(); } } +//[[Rcpp::export]] +std::vector adult_mosquito_model_save_state( + Rcpp::XPtr model + ) { + // Only the lagged_incubating needs to be saved. The rest of the model + // state is reset at each time step by a call to update before it gets + // used. + return {model->lagged_incubating.begin(), model->lagged_incubating.end()}; +} + +//[[Rcpp::export]] +void adult_mosquito_model_restore_state( + Rcpp::XPtr model, + std::vector state + ) { + model->lagged_incubating.assign(state.begin(), state.end()); +} + //[[Rcpp::export]] Rcpp::XPtr create_adult_solver( Rcpp::XPtr model, diff --git a/src/adult_mosquito_eqs.h b/src/adult_mosquito_eqs.h index 6fc30501..c3e0ac8b 100644 --- a/src/adult_mosquito_eqs.h +++ b/src/adult_mosquito_eqs.h @@ -28,7 +28,7 @@ enum class AdultState : size_t {S = 3, E = 4, I = 5}; */ struct AdultMosquitoModel { AquaticMosquitoModel growth_model; - std::queue lagged_incubating; //last tau values for incubating mosquitos + std::deque lagged_incubating; //last tau values for incubating mosquitos double mu; //death rate for adult female mosquitoes const double tau; //extrinsic incubation period double foim; //force of infection towards mosquitoes diff --git a/src/solver.cpp b/src/solver.cpp index 7cb8b9f4..0a5f7401 100644 --- a/src/solver.cpp +++ b/src/solver.cpp @@ -47,6 +47,11 @@ std::vector solver_get_states(Rcpp::XPtr solver) { return solver->state; } +//[[Rcpp::export]] +void solver_set_states(Rcpp::XPtr solver, std::vector state) { + solver->state = state; +} + //[[Rcpp::export]] void solver_step(Rcpp::XPtr solver) { solver->step(); diff --git a/src/timeseries.cpp b/src/timeseries.cpp index 2383ac73..51a494de 100644 --- a/src/timeseries.cpp +++ b/src/timeseries.cpp @@ -15,18 +15,18 @@ Timeseries::Timeseries(size_t max_size, double default_value) : max_size(max_size), has_default(true), default_value(default_value) {} void Timeseries::push(double value, double time) { - values.insert({time, value}); + _values.insert({time, value}); if (max_size != -1) { - while(values.size() > max_size) { - values.erase(values.begin()); + while(_values.size() > max_size) { + _values.erase(_values.begin()); } } } double Timeseries::at(double time, bool linear) const { - auto it = values.lower_bound(time); - if (it == values.end()) { - if (values.size() > 0 && !linear) { + auto it = _values.lower_bound(time); + if (it == _values.end()) { + if (_values.size() > 0 && !linear) { it--; return it->second; } @@ -45,7 +45,7 @@ double Timeseries::at(double time, bool linear) const { auto after_element = *it; while(it->first > time) { // Check if we're at the start of the timeseries - if (it == values.begin()) { + if (it == _values.begin()) { if (has_default) { return default_value; } @@ -64,6 +64,14 @@ double Timeseries::at(double time, bool linear) const { return it->second; } +const std::map& Timeseries::values() { + return _values; +} + +void Timeseries::set_values(std::map values) { + _values = std::move(values); +} + //[[Rcpp::export]] Rcpp::XPtr create_timeseries(size_t size, double default_value) { return Rcpp::XPtr(new Timeseries(size, default_value), true); @@ -78,3 +86,32 @@ double timeseries_at(Rcpp::XPtr timeseries, double timestep, bool li void timeseries_push(Rcpp::XPtr timeseries, double value, double timestep) { return timeseries->push(value, timestep); } + +//[[Rcpp::export]] +Rcpp::List timeseries_save_state(Rcpp::XPtr timeseries) { + std::vector timesteps; + std::vector values; + for (const auto& entry: timeseries->values()) { + timesteps.push_back(entry.first); + values.push_back(entry.second); + } + return Rcpp::DataFrame::create( + Rcpp::Named("timestep") = timesteps, + Rcpp::Named("value") = values + ); +} + +//[[Rcpp::export]] +void timeseries_restore_state(Rcpp::XPtr timeseries, Rcpp::List state) { + std::vector timesteps = state["timestep"]; + std::vector values = state["value"]; + if (timesteps.size() != values.size()) { + Rcpp::stop("Bad size"); + } + + std::map values_map; + for (size_t i = 0; i < timesteps.size(); i++) { + values_map.insert({timesteps[i], values[i]}); + } + timeseries->set_values(std::move(values_map)); +} diff --git a/src/timeseries.h b/src/timeseries.h index c9e7c32f..78f3780b 100644 --- a/src/timeseries.h +++ b/src/timeseries.h @@ -12,7 +12,7 @@ class Timeseries { private: - std::map values; + std::map _values; size_t max_size; void clean(); bool has_default; @@ -23,6 +23,9 @@ class Timeseries { Timeseries(size_t, double); void push(double, double); double at(double, bool = true) const; + + const std::map& values(); + void set_values(std::map state); }; #endif /* SRC_TIMESERIES_ */ diff --git a/src/utils.cpp b/src/utils.cpp index 838a9530..d2b36043 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -8,6 +8,16 @@ void random_seed(size_t seed) { Random::get_instance().seed(seed); } +//[[Rcpp::export]] +std::string random_save_state() { + return Random::get_instance().save_state(); +} + +//[[Rcpp::export]] +void random_restore_state(std::string state) { + return Random::get_instance().restore_state(state); +} + //[[Rcpp::export]] std::vector bernoulli_multi_p_cpp(const std::vector p) { auto values = Random::get_instance().bernoulli_multi_p(p); diff --git a/tests/testthat/helper-integration.R b/tests/testthat/helper-integration.R index b69b7dcb..22c7dd63 100644 --- a/tests/testthat/helper-integration.R +++ b/tests/testthat/helper-integration.R @@ -88,6 +88,13 @@ mock_event <- function(event) { ) } +mock_solver <- function(states) { + list( + get_states = mockery::mock(states), + step = mockery::mock() + ) +} + expect_bitset_update <- function(mock, value, index, call = 1) { expect_equal(mockery::mock_args(mock)[[call]][[1]], value) expect_equal(mockery::mock_args(mock)[[call]][[2]]$to_vector(), index) diff --git a/tests/testthat/test-biting-integration.R b/tests/testthat/test-biting-integration.R index 66bf5b72..7da79b66 100644 --- a/tests/testthat/test-biting-integration.R +++ b/tests/testthat/test-biting-integration.R @@ -131,7 +131,7 @@ test_that('simulate_bites integrates eir calculation and mosquito side effects', expect_equal(effects_args[[1]][[8]], parameters) expect_equal(effects_args[[1]][[9]], timestep) - mockery::expect_args(eqs_update, 1, models[[1]], 25, f, parameters$mum) + mockery::expect_args(eqs_update, 1, models[[1]]$.model, 25, f, parameters$mum) mockery::expect_args( pois_mock, 1, diff --git a/tests/testthat/test-compartmental.R b/tests/testthat/test-compartmental.R index a4fb3b6a..9958c7a5 100644 --- a/tests/testthat/test-compartmental.R +++ b/tests/testthat/test-compartmental.R @@ -11,9 +11,14 @@ test_that('ODE stays at equilibrium with a constant total_M', { counts <- c() for (t in seq(timesteps)) { - counts <- rbind(counts, c(t, solver_get_states(solvers[[1]]))) - aquatic_mosquito_model_update(models[[1]], total_M, f, parameters$mum) - solver_step(solvers[[1]]) + counts <- rbind(counts, c(t, solvers[[1]]$get_states())) + aquatic_mosquito_model_update( + models[[1]]$.model, + total_M, + f, + parameters$mum + ) + solvers[[1]]$step() } expected <- c() @@ -41,16 +46,16 @@ test_that('Adult ODE stays at equilibrium with a constant foim and mu', { counts <- c() for (t in seq(timesteps)) { - states <- solver_get_states(solvers[[1]]) + states <- solvers[[1]]$get_states() counts <- rbind(counts, c(t, states)) adult_mosquito_model_update( - models[[1]], + models[[1]]$.model, parameters$mum, parameters$init_foim, states[ADULT_ODE_INDICES['Sm']], f ) - solver_step(solvers[[1]]) + solvers[[1]]$step() } expected <- c() @@ -82,9 +87,14 @@ test_that('ODE stays at equilibrium with low total_M', { counts <- c() for (t in seq(timesteps)) { - counts <- rbind(counts, c(t, solver_get_states(solvers[[1]]))) - aquatic_mosquito_model_update(models[[1]], total_M, f, parameters$mum) - solver_step(solvers[[1]]) + counts <- rbind(counts, c(t, solvers[[1]]$get_states())) + aquatic_mosquito_model_update( + models[[1]]$.model, + total_M, + f, + parameters$mum + ) + solvers[[1]]$step() } expected <- c() @@ -121,14 +131,19 @@ test_that('Changing total_M stabilises', { counts <- c() for (t in seq(timesteps)) { - counts <- rbind(counts, c(t, solver_get_states(solvers[[1]]))) + counts <- rbind(counts, c(t, solvers[[1]]$get_states())) if (t < change) { total_M <- total_M_0 } else { total_M <- total_M_1 } - aquatic_mosquito_model_update(models[[1]], total_M, f, parameters$mum) - solver_step(solvers[[1]]) + aquatic_mosquito_model_update( + models[[1]]$.model, + total_M, + f, + parameters$mum + ) + solvers[[1]]$step() } initial_eq <- initial_mosquito_counts( diff --git a/tests/testthat/test-emergence-integration.R b/tests/testthat/test-emergence-integration.R index fa7464be..bf452d2f 100644 --- a/tests/testthat/test-emergence-integration.R +++ b/tests/testthat/test-emergence-integration.R @@ -8,22 +8,19 @@ test_that('emergence process fails when there are not enough individuals', { c('gamb'), rep('gamb', 2000) ) + solvers <- list( + mock_solver(c(1000, 500, 100)), + mock_solver(c(1000, 500, 100)) + ) + emergence_process <- create_mosquito_emergence_process( - list(), + solvers, state, species, c('gamb'), parameters$dpl ) - mockery::stub( - emergence_process, - 'solver_get_states', - mockery::mock( - c(1000, 500, 100), - c(1000, 500, 100) - ) - ) - expect_error(emergence_process(0), '*') + expect_error(emergence_process(0), 'Not enough mosquitoes') }) test_that('emergence_process creates the correct number of susceptables', { @@ -36,23 +33,19 @@ test_that('emergence_process creates the correct number of susceptables', { c('a', 'b'), c('a', 'b') ) + solvers <- list( + mock_solver(c(100000, 50000, 10000)), + mock_solver(c(1000, 5000, 1000)) + ) + emergence_process <- create_mosquito_emergence_process( - list(mockery::mock(), mockery::mock()), + solvers, state, species, c('a', 'b'), parameters$dpl ) - mockery::stub( - emergence_process, - 'solver_get_states', - mockery::mock( - c(100000, 50000, 10000), - c(10000, 5000, 1000) - ) - ) - emergence_process(0) expect_bitset_update( diff --git a/tests/testthat/test-resume.R b/tests/testthat/test-resume.R new file mode 100644 index 00000000..83bada35 --- /dev/null +++ b/tests/testthat/test-resume.R @@ -0,0 +1,41 @@ +test_that('Simulation can be resumed', { + initial_timesteps <- 50 + total_timesteps <- 100 + + parameters <- get_parameters() + + set.seed(1) + first_phase <- run_resumable_simulation(initial_timesteps, parameters) + second_phase <- run_resumable_simulation( + total_timesteps, + parameters, + initial_state=first_phase$state, + restore_random_state=TRUE) + + set.seed(1) + uninterrupted_run <- run_simulation(total_timesteps, parameters=parameters) + + expect_equal(nrow(first_phase$data), initial_timesteps) + expect_equal(nrow(second_phase$data), total_timesteps - initial_timesteps) + expect_equal(rbind(first_phase$data, second_phase$data), uninterrupted_run) +}) + +test_that('Intervention parameters can be changed when resuming', { + initial_timesteps <- 50 + total_timesteps <- 100 + tbv_timesteps <- 70 + + # Because of how event scheduling works, we must enable TBV even in the inital phase. + # We set a coverage of 0 to act as-if it was disabled. + initial_parameters <- get_parameters() |> set_tbv(timesteps=tbv_timesteps, coverage=0, ages=5:60) + + tbv_parameters <- initial_parameters |> + set_tbv(timesteps=tbv_timesteps, coverage=1, ages=5:60) + + initial_run <- run_resumable_simulation(initial_timesteps, initial_parameters) + control_run <- run_resumable_simulation(total_timesteps, initial_parameters, initial_state = initial_run$state) + tbv_run <- run_resumable_simulation(total_timesteps, tbv_parameters, initial_state = initial_run$state) + + expect_equal(control_run$data$n_vaccinated_tbv[tbv_timesteps - initial_timesteps], 0) + expect_gt(tbv_run$data$n_vaccinated_tbv[tbv_timesteps - initial_timesteps], 0) +}) diff --git a/tests/testthat/test-seasonality.R b/tests/testthat/test-seasonality.R index 01302d8d..f600ebf4 100644 --- a/tests/testthat/test-seasonality.R +++ b/tests/testthat/test-seasonality.R @@ -15,14 +15,14 @@ test_that('Seasonality correctly affects P', { counts <- c() for (t in seq(timesteps)) { - counts <- rbind(counts, c(t, solver_get_states(solvers[[1]]))) + counts <- rbind(counts, c(t, solvers[[1]]$get_states())) aquatic_mosquito_model_update( - models[[1]], + models[[1]]$.model, total_M, parameters$blood_meal_rates, parameters$mum ) - solver_step(solvers[[1]]) + solvers[[1]]$step() } burn_in <- 20 From b3376d33cda29cc5e4d7217fefad4b367f9f9167 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Li=C3=A9tar?= Date: Thu, 21 Mar 2024 13:21:06 +0000 Subject: [PATCH 153/164] Rewrite the exponential decay process in C++. (#285) The existing process written in R needs to copy the contents of each variable from C++ using `v$get_values()`, then after scaling the vector it would copy the result back into C++ using `v$queue_update`. The amount of data copied and the time it took was pretty significant. 6 double variables, one for each kind of immunity, need to be updated in full at each time step, each as big as the population size. Moving this into C++ removes the need for any copy at all, besides the multication loop. Values are read out of a reference to the vector held by the DoubleVariable, the result of the multication is moved to the queue, and finally individual moves the vector in the queue into the DoubleVariable. The speedup from this change for a 1M population size is around 10%. An alternative optimization I considered was to compute the exponential decay lazily, recording only the timestep and value at which the immunity was last updated and using the closed form expression of the exponential decay. This would avoid the need to have mass updates of the immunity variables at every time step. Unfortunately in my testing this ends up being slower than even the current implementation, with all the time being spent in calculating the current value. This would also be a much more intrusive change, since every use of the immunity variables needs to be modified to take the last update timestep, the current timestep and the decay rate into consideration. --- DESCRIPTION | 2 +- R/RcppExports.R | 4 ++ R/processes.R | 3 +- src/RcppExports.cpp | 13 ++++ src/processes.cpp | 117 ++++++++++++++++++++++++++++++++ tests/testthat/test-processes.R | 23 +++++++ 6 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 src/processes.cpp create mode 100644 tests/testthat/test-processes.R diff --git a/DESCRIPTION b/DESCRIPTION index ce25ce05..d92fa304 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -72,7 +72,7 @@ Remotes: Additional_repositories: https://mrc-ide.r-universe.dev Imports: - individual (>= 0.1.13), + individual (>= 0.1.15), malariaEquilibrium (>= 1.0.1), Rcpp, statmod, diff --git a/R/RcppExports.R b/R/RcppExports.R index 01f3dc11..678a50bf 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -45,6 +45,10 @@ rainfall <- function(t, g0, g, h, floor) { .Call(`_malariasimulation_rainfall`, t, g0, g, h, floor) } +exponential_process_cpp <- function(variable, rate) { + .Call(`_malariasimulation_exponential_process_cpp`, variable, rate) +} + solver_get_states <- function(solver) { .Call(`_malariasimulation_solver_get_states`, solver) } diff --git a/R/processes.R b/R/processes.R index d3b11fda..28810263 100644 --- a/R/processes.R +++ b/R/processes.R @@ -261,8 +261,9 @@ create_processes <- function( #' @param rate the exponential rate #' @noRd create_exponential_decay_process <- function(variable, rate) { + stopifnot(inherits(variable, "DoubleVariable")) decay_rate <- exp(-1/rate) - function(timestep) variable$queue_update(variable$get_values() * decay_rate) + exponential_process_cpp(variable$.variable, decay_rate) } #' @title Create and initialise lagged_infectivity object diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 7675e8e6..439cb12b 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -179,6 +179,18 @@ BEGIN_RCPP return rcpp_result_gen; END_RCPP } +// exponential_process_cpp +Rcpp::XPtr exponential_process_cpp(Rcpp::XPtr variable, const double rate); +RcppExport SEXP _malariasimulation_exponential_process_cpp(SEXP variableSEXP, SEXP rateSEXP) { +BEGIN_RCPP + Rcpp::RObject rcpp_result_gen; + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< Rcpp::XPtr >::type variable(variableSEXP); + Rcpp::traits::input_parameter< const double >::type rate(rateSEXP); + rcpp_result_gen = Rcpp::wrap(exponential_process_cpp(variable, rate)); + return rcpp_result_gen; +END_RCPP +} // solver_get_states std::vector solver_get_states(Rcpp::XPtr solver); RcppExport SEXP _malariasimulation_solver_get_states(SEXP solverSEXP) { @@ -349,6 +361,7 @@ static const R_CallMethodDef CallEntries[] = { {"_malariasimulation_carrying_capacity", (DL_FUNC) &_malariasimulation_carrying_capacity, 8}, {"_malariasimulation_eggs_laid", (DL_FUNC) &_malariasimulation_eggs_laid, 3}, {"_malariasimulation_rainfall", (DL_FUNC) &_malariasimulation_rainfall, 5}, + {"_malariasimulation_exponential_process_cpp", (DL_FUNC) &_malariasimulation_exponential_process_cpp, 2}, {"_malariasimulation_solver_get_states", (DL_FUNC) &_malariasimulation_solver_get_states, 1}, {"_malariasimulation_solver_set_states", (DL_FUNC) &_malariasimulation_solver_set_states, 2}, {"_malariasimulation_solver_step", (DL_FUNC) &_malariasimulation_solver_step, 1}, diff --git a/src/processes.cpp b/src/processes.cpp new file mode 100644 index 00000000..b5db4bad --- /dev/null +++ b/src/processes.cpp @@ -0,0 +1,117 @@ +#include +#include + +/** + * An iterator adaptor which yields the same values as the underlying iterator, + * but scaled by a pre-determined factor. + * + * This is used by the exponential_process below to scale an std::vector by a + * constant. + * + * There are two straightforward ways of performing the operation. The first is + * to create an empty vector, use `reserve(N)` to pre-allocate the vector and + * then call `push_back` with each new value. The second way would be to create + * a zero-initialised vector of size N and then use `operator[]` to fill in the + * values. + * + * Unfortunately both approaches have significant overhead. In the former, the + * use of `push_back` requires repeated checks as to whether the vector needs + * growing, despite the prior reserve call. These calls inhibits optimizations + * such as unrolling and auto-vectorization of the loop. The latter approach + * requires an initial memset when zero-initializing the vector, even though the + * vector then gets overwritten entirely. Sadly gcc fails to optimize out either + * of those. Ideally we want a way to create a pre-sized but uninitialised + * std::vector we can write to ourselves, but there is no API in the standard + * library to do this. All existing workarounds end up with an std::vector with + * non-default item type or allocators. + * + * There is however a way out! std::vector has a constructor which accepts a + * pair of iterators and fills the vector with values from the iterators. Using + * `std::distance` on the iterator pair it can even pre-allocate the vector to + * the right size. No zero-initialisation or no capacity checks, just one + * allocation and a straightforward easily optimizable loop. All we need is an + * iterator yielding the right values, hence `scale_iterator`. In C++20 we would + * probably be able to use the new ranges library as our iterators. + * + * How much does this matter? On microbenchmarks, for small and medium sized + * vector (<= 1M doubles), this version is about 30% faster than the + * zero-initialising implementation and 60% faster than the one which uses + * push_back. For larger vector sizes the difference is less pronounced, + * possibly because caches become saturated. At the time of writing, on a + * real-word run of malariasimulation with a population size of 1M the overall + * speedup is about 2-3%. + * + * https://wolchok.org/posts/cxx-trap-1-constant-size-vector/ + * https://codingnest.com/the-little-things-the-missing-performance-in-std-vector/ + * https://lemire.me/blog/2012/06/20/do-not-waste-time-with-stl-vectors/ + */ +template +struct scale_iterator { + using iterator_category = std::forward_iterator_tag; + using difference_type = typename std::iterator_traits::difference_type; + using value_type = typename std::iterator_traits::value_type; + using pointer = typename std::iterator_traits::pointer; + + // We skirt the rules a bit by returning a prvalue from `operator*`, even + // though the C++17 (and prior) standard says forward iterators are supposed + // to return a reference type (ie. a glvalue). Because the scaling is + // applied on the fly, there is no glvalue we could return a reference to. + // + // An input iterator would be allowed to return a prvalue, but the + // std::vector constructor wouldn't be able to figure out the length ahead + // of time if we were an input iterator. + // + // C++20 actually introduces parallel definitions of input and forward + // iterators, which relax this requirement, so under that classification our + // implementation in correct. + // + // In practice though, this does not really matter. We only use this + // iterator in one specific context, and the vector constructor doesn't do + // anything elaborate that we would be upsetting. + using reference = value_type; + + scale_iterator(underlying_iterator it, value_type factor) : it(it), factor(factor) {} + reference operator*() { + return factor * (*it); + } + bool operator==(const scale_iterator& other) { + return it == other.it; + } + bool operator!=(const scale_iterator& other) { + return it != other.it; + } + scale_iterator& operator++() { + it++; + return *this; + } + scale_iterator operator++(int) { + return scale_iterator(it++, factor); + } + + private: + underlying_iterator it; + value_type factor; +}; + +template +scale_iterator make_scale_iterator(T&& it, typename std::iterator_traits::value_type scale) { + return scale_iterator(std::forward(it), scale); +} + +//[[Rcpp::export]] +Rcpp::XPtr exponential_process_cpp( + Rcpp::XPtr variable, + const double rate +){ + return Rcpp::XPtr( + new process_t([=](size_t t){ + const std::vector& values = variable->get_values(); + std::vector new_values( + make_scale_iterator(values.cbegin(), rate), + make_scale_iterator(values.cend(), rate)); + + variable->queue_update(std::move(new_values), std::vector()); + }), + true + ); +} diff --git a/tests/testthat/test-processes.R b/tests/testthat/test-processes.R new file mode 100644 index 00000000..29f0d6b0 --- /dev/null +++ b/tests/testthat/test-processes.R @@ -0,0 +1,23 @@ +test_that("exponential_decay_process works as expected", { + # This rate gives a halving at every timestep + rate <- -1 / log(0.5) + + v <- individual::DoubleVariable$new(c(0,0.5,1,2,4,10)) + p <- create_exponential_decay_process(v, rate) + + individual:::execute_any_process(p, 1) + v$.update() + + expect_equal(v$get_values(), c(0, 0.25, 0.5, 1, 2, 5)) + + individual:::execute_any_process(p, 2) + v$.update() + + expect_equal(v$get_values(), c(0, 0.125, 0.25, 0.5, 1, 2.5)) +}) + +test_that("exponential_decay_process fails on IntegerVariable", { + rate <- -1 / log(0.5) + v <- individual::IntegerVariable$new(c(0,1,2,3)) + expect_error(create_exponential_decay_process(v, rate)) +}) From 2c9932bb87d5415a13cea5314544fd5ada116645 Mon Sep 17 00:00:00 2001 From: tbreweric Date: Tue, 26 Mar 2024 14:42:47 +0000 Subject: [PATCH 154/164] Combined ETF and SPC. Need to fix testthat files before PR --- DESCRIPTION | 2 +- R/antimalarial_resistance.R | 7 +++ R/disease_progression.R | 28 ++++++--- R/human_infection.R | 68 +++++++++++++++------ R/model.R | 7 ++- R/mortality_processes.R | 7 ++- R/parameters.R | 1 + R/processes.R | 24 +++++++- R/variables.R | 12 ++++ man/run_simulation.Rd | 7 ++- src/RcppExports.cpp | 2 +- tests/testthat/test-infection-integration.R | 4 ++ 12 files changed, 132 insertions(+), 37 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 1d971723..7ebbd7a0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -91,7 +91,7 @@ Suggests: ggplot2, covr, mgcv -RoxygenNote: 7.2.3 +RoxygenNote: 7.3.1 Roxygen: list(markdown = TRUE) LinkingTo: Rcpp, diff --git a/R/antimalarial_resistance.R b/R/antimalarial_resistance.R index 532c042b..7da3ad83 100644 --- a/R/antimalarial_resistance.R +++ b/R/antimalarial_resistance.R @@ -26,6 +26,13 @@ set_antimalarial_resistance <- function(parameters, reinfection_prob, slow_parasite_clearance_time) { + if(any(partner_drug_resistance > 0, + late_clinical_failure_prob > 0, + late_parasitological_prob > 0, + reinfection_prob > 0)) { + stop("Parameters set for unimplemented feature - late clinical failure, late parasitological failure, or reinfection during prophylaxis") + } + if(any(c(length(artemisinin_resistance), length(partner_drug_resistance), length(slow_parasite_clearance_prob), diff --git a/R/disease_progression.R b/R/disease_progression.R index 05367252..e8b35874 100644 --- a/R/disease_progression.R +++ b/R/disease_progression.R @@ -19,15 +19,27 @@ update_infection <- function( } create_progression_process <- function( - state, - from_state, - to_state, - rate, - infectivity, - new_infectivity - ) { + state, + from_state, + to_state, + rate, + infectivity, + new_infectivity +) { function(timestep) { - to_move <- state$get_index_of(from_state)$sample(1/rate) + + # Retrieve the indices of all individuals in the to_move state: + index <- state$get_index_of(from_state) + + # If the length of rate is greater than 1 (when it's a variable): + if (length(rate) > 1) { + rate <- rate$get_values(index$to_vector()) + } + + # Sample the individuals to be moved into a new Bitset using the transition rate(s): + to_move <- index$sample(1/rate) + + # Update the infection status of those individuals who are moving: update_infection( state, to_state, diff --git a/R/human_infection.R b/R/human_infection.R index 6b2ac3cf..4890e8a0 100644 --- a/R/human_infection.R +++ b/R/human_infection.R @@ -295,50 +295,82 @@ calculate_treated <- function( ) ]) + #+++ DRUG EFFICACY +++# + #+++++++++++++++++++++# + effectively_treated_index <- bernoulli_multi_p(parameters$drug_efficacy[drugs]) + effectively_treated <- bitset_at(seek_treatment, effectively_treated_index) + drugs <- drugs[effectively_treated_index] + n_drug_efficacy_failures <- n_treat - effectively_treated$size() + renderer$render('n_drug_efficacy_failures', n_drug_efficacy_failures, timestep) + + #+++ ANTIMALARIAL RESISTANCE +++# + #+++++++++++++++++++++++++++++++# if(parameters$antimalarial_resistance) { + resistance_parameters <- get_antimalarial_resistance_parameters( parameters = parameters, drugs = drugs, timestep = timestep ) - unsuccessful_treatment_probability <- resistance_parameters$artemisinin_resistance_proportion * resistance_parameters$early_treatment_failure_probability - susceptible_to_treatment_index <- bernoulli_multi_p(p = 1 - unsuccessful_treatment_probability) - susceptible_to_treatment <- bitset_at(seek_treatment, susceptible_to_treatment_index) - drugs <- drugs[susceptible_to_treatment_index] + + #+++ EARLY TREATMENT FAILURE +++# + #+++++++++++++++++++++++++++++++# + early_treatment_failure_probability <- resistance_parameters$artemisinin_resistance_proportion * resistance_parameters$early_treatment_failure_probability + successfully_treated_indices <- bernoulli_multi_p(p = 1 - early_treatment_failure_probability) + successfully_treated <- bitset_at(effectively_treated, successfully_treated_indices) + n_early_treatment_failure <- effectively_treated$size() - successfully_treated$size() + renderer$render('n_early_treatment_failure', n_early_treatment_failure, timestep) + drugs <- drugs[successfully_treated_indices] + resistance_parameters$dt_slow_parasite_clearance <- resistance_parameters$dt_slow_parasite_clearance[successfully_treated_indices] + + #+++ SLOW PARASITE CLEARANCE +++# + #+++++++++++++++++++++++++++++++# + slow_parasite_clearance_probability <- resistance_parameters$artemisinin_resistance_proportion[successfully_treated_indices] * + resistance_parameters$slow_parasite_clearance_probability[successfully_treated_indices] + slow_parasite_clearance_indices <- bernoulli_multi_p(p = slow_parasite_clearance_probability) + slow_parasite_clearance_individuals <- bitset_at(successfully_treated, slow_parasite_clearance_indices) + renderer$render('n_slow_parasite_clearance', slow_parasite_clearance_individuals$size(), timestep) + non_slow_parasite_clearance_individuals <- successfully_treated$copy()$set_difference(slow_parasite_clearance_individuals) + renderer$render('n_successfully_treated', successfully_treated$size(), timestep) + resistance_parameters$dt_slow_parasite_clearance <- resistance_parameters$dt_slow_parasite_clearance[slow_parasite_clearance_indices] + } else { - susceptible_to_treatment <- seek_treatment + + successfully_treated <- effectively_treated + renderer$render('n_successfully_treated', successfully_treated$size(), timestep) } - n_early_treatment_failure <- n_treat - susceptible_to_treatment$size() - successfully_treated_index <- bernoulli_multi_p(parameters$drug_efficacy[drugs]) - successfully_treated <- bitset_at(susceptible_to_treatment, successfully_treated_index) - successfully_treated_drugs <- drugs[successfully_treated_index] - n_treat_eff_fail <- susceptible_to_treatment$size() - length(successfully_treated_index) - renderer$render('n_early_treatment_failure', n_early_treatment_failure, timestep) - renderer$render('n_treat_eff_fail', n_treat_eff_fail, timestep) - renderer$render('n_treat_success', successfully_treated$size(), timestep) - - # Update variables of those who have been successfully treated: if (successfully_treated$size() > 0) { variables$state$queue_update("Tr", successfully_treated) variables$infectivity$queue_update( - parameters$cd * parameters$drug_rel_c[successfully_treated_drugs], + parameters$cd * parameters$drug_rel_c[drugs], successfully_treated ) variables$drug$queue_update( - successfully_treated_drugs, + drugs, successfully_treated ) variables$drug_time$queue_update( timestep, successfully_treated ) + if(parameters$antimalarial_resistance) { + variables$dt$queue_update( + parameters$dt, + non_slow_parasite_clearance_individuals + ) + variables$dt$queue_update( + resistance_parameters$dt_slow_parasite_clearance, + slow_parasite_clearance_individuals + ) + } } + successfully_treated + } - #' @title Schedule infections #' @description #' Schedule infections in humans after the incubation period diff --git a/R/model.R b/R/model.R index 4c4f7c2b..b4401855 100644 --- a/R/model.R +++ b/R/model.R @@ -74,9 +74,10 @@ #' susceptible #' * net_usage: the number people protected by a bed net #' * mosquito_deaths: number of adult female mosquitoes who die this timestep -#' * n_early_treatment_failure: number of clinically treated individuals who experienced early treatment failure in this timestep -#' * n_treat_eff_fail: number of clinically treated individuals who's treatment failed due to drug efficacy -#' * n_treat_success: number of successfully treated individuals in this timestep +#' * n_drug_efficacy_failures: number of clinically treated individuals whose treatment failed due to drug efficacy +#' * n_early_treatment_failure: number of clinically treated individuals who experienced early treatment failure +#' * n_successfully_treated: number of clinically treated individuals who are treated successfully (includes individuals who experience slow parasite clearance) +#' * n_slow_parasite_clearance: number of clinically treated individuals who experienced slow parasite clearance #' #' @param timesteps the number of timesteps to run the simulation for (in days) #' @param parameters a named list of parameters to use diff --git a/R/mortality_processes.R b/R/mortality_processes.R index f0f1b1f9..e9ea6ac9 100644 --- a/R/mortality_processes.R +++ b/R/mortality_processes.R @@ -74,7 +74,7 @@ sample_maternal_immunity <- function(variables, target, timestep, parameters) { } } -reset_target <- function(variables, events, target, state, timestep) { +reset_target <- function(variables, events, target, state, parameters, timestep) { if (target$size() > 0) { # clear events to_clear <- c( @@ -113,6 +113,11 @@ reset_target <- function(variables, events, target, state, timestep) { # onwards infectiousness variables$infectivity$queue_update(0, target) + + # treated compartment residence time: + if(!is.null(variables$dt)) { + variables$dt$queue_update(parameters$dt, target) + } # zeta and zeta group and vector controls survive rebirth } diff --git a/R/parameters.R b/R/parameters.R index 9abbeb60..c87e69bf 100644 --- a/R/parameters.R +++ b/R/parameters.R @@ -404,6 +404,7 @@ get_parameters <- function(overrides = list()) { late_clinical_failure_prob = NULL, late_parasitological_failure_prob = NULL, reinfection_during_prophylaxis = NULL, + dt_slow_parasite_clearance = NULL, # flexible carrying capacity carrying_capacity = FALSE, carrying_capacity_timesteps = NULL, diff --git a/R/processes.R b/R/processes.R index d3b11fda..bbd7a754 100644 --- a/R/processes.R +++ b/R/processes.R @@ -104,12 +104,32 @@ create_processes <- function( parameters$du, variables$infectivity, 0 - ), + ) + ) + + # ======================= + # Antimalarial Resistance + # ======================= + # Add an a new process which governs the transition from Tr to S when + # antimalarial resistance is simulated. The rate of transition switches + # from a parameter to a variable when antimalarial resistance == TRUE. + + # Assign the dt input to a separate object with the default single parameter value: + dt_input <- parameters$dt + + # If antimalarial resistance is switched on, assign dt variable values to the + if(parameters$antimalarial_resistance == TRUE) { + dt_input <- variables$dt + } + + # Create the progression process for Tr --> S specifying dt_input as the rate: + processes <- c( + processes, create_progression_process( variables$state, 'Tr', 'S', - parameters$dt, + dt_input, variables$infectivity, 0 ) diff --git a/R/variables.R b/R/variables.R index f9c75e6e..077a4f29 100644 --- a/R/variables.R +++ b/R/variables.R @@ -33,6 +33,9 @@ #' * drug - The last prescribed drug #' * drug_time - The timestep of the last drug #' +#' Antimalarial resistance variables are: +#' * dt - the delay for humans to move from state Tr to state S +#' #' Mosquito variables are: #' * mosquito_state - the state of the mosquito, a category Sm|Pm|Im|NonExistent #' * species - the species of mosquito, this is a category gamb|fun|arab @@ -226,6 +229,15 @@ create_variables <- function(parameters) { net_time = net_time, spray_time = spray_time ) + + # Add variables for antimalarial resistance state residency times (dt) + if(parameters$antimalarial_resistance == TRUE) { + dt <- individual::DoubleVariable$new(rep(parameters$dt, size)) + variables <- c( + variables, + dt = dt + ) + } # Add variables for individual mosquitoes if (parameters$individual_mosquitoes) { diff --git a/man/run_simulation.Rd b/man/run_simulation.Rd index 07871b13..b9e95e0a 100644 --- a/man/run_simulation.Rd +++ b/man/run_simulation.Rd @@ -90,8 +90,9 @@ subpatent susceptible \item net_usage: the number people protected by a bed net \item mosquito_deaths: number of adult female mosquitoes who die this timestep -\item n_early_treatment_failure: number of clinically treated individuals who experienced early treatment failure in this timestep -\item n_treat_eff_fail: number of clinically treated individuals who's treatment failed due to drug efficacy -\item n_treat_success: number of successfully treated individuals in this timestep +\item n_drug_efficacy_failures: number of clinically treated individuals whose treatment failed due to drug efficacy +\item n_early_treatment_failure: number of clinically treated individuals who experienced early treatment failure +\item n_successfully_treated: number of clinically treated individuals who are treated successfully +\item n_slow_parasite_clearance: number of clinically treated individuals who experienced slow parasite clearance } } diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index f5c226fd..affb233d 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -260,7 +260,7 @@ BEGIN_RCPP END_RCPP } -RcppExport SEXP run_testthat_tests(); +RcppExport SEXP run_testthat_tests(void); static const R_CallMethodDef CallEntries[] = { {"_malariasimulation_create_adult_mosquito_model", (DL_FUNC) &_malariasimulation_create_adult_mosquito_model, 5}, diff --git a/tests/testthat/test-infection-integration.R b/tests/testthat/test-infection-integration.R index 70a0ec6f..b2e2b3bc 100644 --- a/tests/testthat/test-infection-integration.R +++ b/tests/testthat/test-infection-integration.R @@ -315,6 +315,7 @@ test_that('calculate_treated correctly samples treated and updates the drug stat expect_bitset_update(variables$drug_time$queue_update, 5, c(1, 4)) }) +##' FIXING test_that('calculate_treated correctly samples treated and updates the drug state when resistance set', { parameters <- get_parameters() @@ -411,6 +412,7 @@ test_that('calculate_treated correctly samples treated and updates the drug stat }) +##' FIX test_that('calculate_treated correctly samples treated and updates the drug state when resistance not set for all drugs', { # Establish the parameters @@ -857,6 +859,7 @@ test_that('calculate_treated() returns an empty Bitset when the parameter list c in the absence of clinical treatment or resistance parameters") }) +##' FIX test_that('Number of treatment failures matches number of individuals treated when artemisinin resistance proportion and early treatment failure probability both set to 1', { parameters <- get_parameters() @@ -912,6 +915,7 @@ test_that('Number of treatment failures matches number of individuals treated wh and early treatment failure probability both equal 1") }) +##' FIX test_that('calculate_treated() successfully adds additional resistance columns to the renderer', { parameters <- get_parameters() parameters <- set_drugs(parameters = parameters, drugs = list(AL_params)) From 2a3d4cc3a77a0ff0a953d8a3727ef90501b860b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Li=C3=A9tar?= Date: Wed, 3 Apr 2024 10:56:05 +0100 Subject: [PATCH 155/164] Improve correlation tests. (#287) The tests for the correlation parameters were using a tolerance of 1e2 everywhere. Since the tolerance is relative, assertions would effectively succeed for any value within a few orders of magnitude. Setting obviously wrong expected results in the assertions did not produce any errors. This switches the tolerance to 0.1. This was chosen through experimenting, as something that didn't cause false negative even after many runs, while also being reasonably close. When using 0.01 I did get 1 failure in 100 runs of the test suite. Some of the assertions were using incorrected expected values, which flew under the radar because of the huge tolerance. I've also cleared up the tests and bit and made them more consitent with one another. Finally I changed the `CorrelationParameters` constructor to accept only the values it needs (population size and intervention booleans), rather than the full simulation parameters. This makes the test a bit more concise, and will also help with upcoming tests that work at restoring correlation state while adding interventions. The existing public wrapper `get_correlation_parameters` still has the same interface as before. --- R/correlation.R | 18 ++-- tests/testthat/test-correlation.R | 159 ++++++++++++++++++------------ 2 files changed, 104 insertions(+), 73 deletions(-) diff --git a/R/correlation.R b/R/correlation.R index df5f88f5..458a3015 100644 --- a/R/correlation.R +++ b/R/correlation.R @@ -24,11 +24,11 @@ CorrelationParameters <- R6::R6Class( public = list( #' @description initialise correlation parameters - #' @param parameters model parameters - initialize = function(parameters) { - # Find a list of enabled interventions - enabled <- vlapply(INTS, function(name) parameters[[name]]) - private$interventions <- INTS[enabled] + #' @param population popularion size + #' @param interventions character vector with the name of enabled interventions + initialize = function(population, interventions) { + private$population <- population + private$interventions <- interventions # Initialise a rho matrix for our interventions n_ints <- private$n_ints() @@ -38,9 +38,6 @@ CorrelationParameters <- R6::R6Class( ncol = n_ints, dimnames = list(private$interventions, private$interventions) ) - - # Store population for mvnorm draws - private$population <- parameters$human_population }, #' @description Add rho between rounds @@ -183,7 +180,10 @@ CorrelationParameters <- R6::R6Class( #' #' # You can now pass the correlation parameters to the run_simulation function get_correlation_parameters <- function(parameters) { - CorrelationParameters$new(parameters) + # Find a list of enabled interventions + enabled <- vlapply(INTS, function(name) parameters[[name]]) + + CorrelationParameters$new(parameters$human_population, INTS[enabled]) } #' @title Sample a population to intervene in given the correlation parameters diff --git a/tests/testthat/test-correlation.R b/tests/testthat/test-correlation.R index 880221ba..882831f8 100644 --- a/tests/testthat/test-correlation.R +++ b/tests/testthat/test-correlation.R @@ -1,105 +1,136 @@ test_that('1 correlation between rounds gives sensible samples', { pop <- 1e6 target <- seq(pop) - vaccine_coverage <- .2 - parameters <- get_parameters(list( - human_population = pop, - pev = TRUE - )) - correlations <- get_correlation_parameters(parameters) + + coverage_1 <- .2 + coverage_2 <- .4 + + correlations <- CorrelationParameters$new(pop, c('pev')) correlations$inter_round_rho('pev', 1) - round_1 <- sample_intervention(target, 'pev', vaccine_coverage, correlations) - round_2 <- sample_intervention(target, 'pev', vaccine_coverage, correlations) - expect_equal(sum(round_1), pop * .2, tolerance=1e2) - expect_equal(sum(round_2), pop * .2, tolerance=1e2) - expect_equal(sum(round_1 & round_2), pop * .2, tolerance=1e2) + + round_1 <- sample_intervention(target, 'pev', coverage_1, correlations) + round_2 <- sample_intervention(target, 'pev', coverage_2, correlations) + + expect_equal(sum(round_1), pop * coverage_1, tolerance=.1) + expect_equal(sum(round_2), pop * coverage_2, tolerance=.1) + + expect_equal( + sum(round_1 & round_2), + pop * min(coverage_1, coverage_2), + tolerance=.1) + + expect_equal( + sum(round_1 | round_2), + pop * max(coverage_1, coverage_2), + tolerance=.1) }) test_that('0 correlation between rounds gives sensible samples', { pop <- 1e6 target <- seq(pop) - vaccine_coverage <- .5 - parameters <- get_parameters(list( - human_population = pop, - pev = TRUE - )) - correlations <- get_correlation_parameters(parameters) + + coverage_1 <- .2 + coverage_2 <- .4 + + correlations <- CorrelationParameters$new(pop, c('pev')) correlations$inter_round_rho('pev', 0) - round_1 <- sample_intervention(target, 'pev', vaccine_coverage, correlations) - round_2 <- sample_intervention(target, 'pev', vaccine_coverage, correlations) + + round_1 <- sample_intervention(target, 'pev', coverage_1, correlations) + round_2 <- sample_intervention(target, 'pev', coverage_2, correlations) + + expect_equal(sum(round_1), pop * coverage_1, tolerance=.1) + expect_equal(sum(round_2), pop * coverage_2, tolerance=.1) + expect_equal( - length(intersect(which(round_1), which(round_2))), - pop * .5, - tolerance=1e2 - ) - expect_equal(sum(round_1), sum(round_2), tolerance=1e2) - expect_equal(sum(round_1), pop * .5, tolerance=1e2) + sum(round_1 & round_2), + pop * coverage_1 * coverage_2, + tolerance=.1) + + expect_equal( + sum(round_1 | round_2), + pop * (coverage_1 + coverage_2 - (coverage_1 * coverage_2)), + tolerance=.1) }) test_that('1 correlation between interventions gives sensible samples', { pop <- 1e6 target <- seq(pop) - vaccine_coverage <- .2 - mda_coverage <- .2 - parameters <- get_parameters(list( - human_population = pop, - pev = TRUE, - mda = TRUE - )) - correlations <- get_correlation_parameters(parameters) + + pev_coverage <- .2 + mda_coverage <- .4 + + correlations <- CorrelationParameters$new(pop, c('pev', 'mda')) correlations$inter_round_rho('pev', 1) correlations$inter_round_rho('mda', 1) correlations$inter_intervention_rho('pev', 'mda', 1) - vaccine_sample <- sample_intervention(target, 'pev', vaccine_coverage, correlations) + + pev_sample <- sample_intervention(target, 'pev', pev_coverage, correlations) mda_sample <- sample_intervention(target, 'mda', mda_coverage, correlations) - expect_equal(sum(vaccine_sample), pop * .2, tolerance=1e2) - expect_equal(sum(mda_sample), pop * .2, tolerance=1e2) - expect_equal(sum(vaccine_sample & mda_sample), pop * .2, tolerance=1e2) + expect_equal(sum(pev_sample), pop * pev_coverage, tolerance=.1) + expect_equal(sum(mda_sample), pop * mda_coverage, tolerance=.1) + + expect_equal( + sum(pev_sample & mda_sample), + pop * min(pev_coverage, mda_coverage), + tolerance=.1) + + expect_equal( + sum(pev_sample | mda_sample), + pop * max(pev_coverage, mda_coverage), + tolerance=.1) }) test_that('0 correlation between interventions gives sensible samples', { pop <- 1e6 target <- seq(pop) - vaccine_coverage <- .2 - mda_coverage <- .2 - parameters <- get_parameters(list( - human_population = pop, - pev = TRUE, - mda = TRUE - )) - correlations <- get_correlation_parameters(parameters) + + pev_coverage <- .2 + mda_coverage <- .4 + + correlations <- CorrelationParameters$new(pop, c('pev', 'mda')) correlations$inter_round_rho('pev', 1) correlations$inter_round_rho('mda', 1) correlations$inter_intervention_rho('pev', 'mda', 0) - vaccine_sample <- sample_intervention(target, 'pev', vaccine_coverage, correlations) + + pev_sample <- sample_intervention(target, 'pev', pev_coverage, correlations) mda_sample <- sample_intervention(target, 'mda', mda_coverage, correlations) + + expect_equal(sum(pev_sample), pop * pev_coverage, tolerance=.1) + expect_equal(sum(mda_sample), pop * mda_coverage, tolerance=.1) + expect_equal( - length(intersect(which(vaccine_sample), which(mda_sample))), - pop * .5, - tolerance=1e2 - ) - expect_equal(sum(vaccine_sample), sum(mda_sample), tolerance=1e2) - expect_equal(sum(vaccine_sample), pop * .5, tolerance=1e2) + sum(pev_sample & mda_sample), + pop * pev_coverage * mda_coverage, + tolerance=.1) + + expect_equal( + sum(pev_sample | mda_sample), + pop * (pev_coverage + mda_coverage - (pev_coverage * mda_coverage)), + tolerance=.1) }) test_that('-1 correlation between interventions gives sensible samples', { pop <- 1e6 target <- seq(pop) - vaccine_coverage <- .2 - mda_coverage <- .2 - parameters <- get_parameters(list( - human_population = pop, - pev = TRUE, - mda = TRUE - )) - correlations <- get_correlation_parameters(parameters) + + pev_coverage <- .2 + mda_coverage <- .4 + + correlations <- CorrelationParameters$new(pop, c('pev', 'mda')) correlations$inter_round_rho('pev', 1) correlations$inter_round_rho('mda', 1) correlations$inter_intervention_rho('pev', 'mda', -1) - vaccine_sample <- sample_intervention(target, 'pev', vaccine_coverage, correlations) + + pev_sample <- sample_intervention(target, 'pev', pev_coverage, correlations) mda_sample <- sample_intervention(target, 'mda', mda_coverage, correlations) - expect_equal(length(intersect(which(vaccine_sample), which(mda_sample))), 0) - expect_equal(sum(vaccine_sample), .2 * pop, tolerance=1e2) - expect_equal(sum(mda_sample), .2 * pop, tolerance=1e2) + + expect_equal(sum(pev_sample), pop * pev_coverage, tolerance=.1) + expect_equal(sum(mda_sample), pop * mda_coverage, tolerance=.1) + + expect_equal(sum(pev_sample & mda_sample), 0, tolerance=.1) + expect_equal( + sum(pev_sample | mda_sample), + pop * (pev_coverage + mda_coverage), + tolerance=.1) }) From 952108c3314fc767d0d6d5a60c925fced364897c Mon Sep 17 00:00:00 2001 From: Thomas Brewer Date: Wed, 3 Apr 2024 15:40:24 +0100 Subject: [PATCH 156/164] Fixed errors in unit tests which included amending the create_mortality_process function to include parameters as an input --- R/human_infection.R | 1 - R/mortality_processes.R | 2 +- tests/testthat/test-antimalarial-resistance.R | 100 +++++----- tests/testthat/test-infection-integration.R | 180 +++++++++++------- 4 files changed, 161 insertions(+), 122 deletions(-) diff --git a/R/human_infection.R b/R/human_infection.R index 4890e8a0..569757ef 100644 --- a/R/human_infection.R +++ b/R/human_infection.R @@ -306,7 +306,6 @@ calculate_treated <- function( #+++ ANTIMALARIAL RESISTANCE +++# #+++++++++++++++++++++++++++++++# if(parameters$antimalarial_resistance) { - resistance_parameters <- get_antimalarial_resistance_parameters( parameters = parameters, drugs = drugs, diff --git a/R/mortality_processes.R b/R/mortality_processes.R index e9ea6ac9..37792f6c 100644 --- a/R/mortality_processes.R +++ b/R/mortality_processes.R @@ -27,7 +27,7 @@ create_mortality_process <- function(variables, events, renderer, parameters) { died <- individual::Bitset$new(pop)$insert(bernoulli_multi_p(deathrates)) renderer$render('natural_deaths', died$size(), timestep) } - reset_target(variables, events, died, 'S', timestep) + reset_target(variables, events, died, 'S', parameters, timestep) sample_maternal_immunity(variables, died, timestep, parameters) } } diff --git a/tests/testthat/test-antimalarial-resistance.R b/tests/testthat/test-antimalarial-resistance.R index 400d93a3..193e09cf 100644 --- a/tests/testthat/test-antimalarial-resistance.R +++ b/tests/testthat/test-antimalarial-resistance.R @@ -12,9 +12,9 @@ test_that('set_antimalarial_resistance() toggles resistance on', { partner_drug_resistance = 0, slow_parasite_clearance_prob = 0.5, early_treatment_failure_prob = 0.6, - late_clinical_failure_prob = 0.2, - late_parasitological_prob = 0.3, - reinfection_prob = 0.4, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0, slow_parasite_clearance_time = 10) -> simparams expect_identical(object = simparams$antimalarial_resistance, expected = TRUE) }) @@ -53,9 +53,9 @@ test_that('set_antimalarial_resistance() errors if resistance proportions outsid partner_drug_resistance = 0, slow_parasite_clearance_prob = 0.5, early_treatment_failure_prob = 0.6, - late_clinical_failure_prob = 0.2, - late_parasitological_prob = 0.3, - reinfection_prob = 0.4, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0, slow_parasite_clearance_time = 10), regexp = "Artemisinin and partner-drug resistance proportions must fall between 0 and 1") }) @@ -121,35 +121,35 @@ test_that('set_antimalarial_resistance() assigns parameters correctly despite or drug = 3, timesteps = 1, artemisinin_resistance = 0, - partner_drug_resistance = 0.43, + partner_drug_resistance = 0, slow_parasite_clearance_prob = 0, early_treatment_failure_prob = 0, - late_clinical_failure_prob = 0.01, - late_parasitological_prob = 0.42, - reinfection_prob = 0.89, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0, slow_parasite_clearance_time = 10) parameters <- set_antimalarial_resistance(parameters = parameters, drug = 1, timesteps = 1, artemisinin_resistance = 0.27, - partner_drug_resistance = 0.61, + partner_drug_resistance = 0, slow_parasite_clearance_prob = 0.23, early_treatment_failure_prob = 0.9, - late_clinical_failure_prob = 0.49, - late_parasitological_prob = 0.81, - reinfection_prob = 0.009, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0, slow_parasite_clearance_time = 20) expect_identical(parameters$antimalarial_resistance, TRUE) expect_identical(unlist(parameters$antimalarial_resistance_drug), c(2, 3, 1)) expect_identical(unlist(parameters$antimalarial_resistance_timesteps), rep(1, 3)) expect_identical(unlist(parameters$prop_artemisinin_resistant), c(0.5, 0, 0.27)) - expect_identical(unlist(parameters$prop_partner_drug_resistant), c(0, 0.43, 0.61)) + expect_identical(unlist(parameters$prop_partner_drug_resistant), c(0, 0, 0)) expect_identical(unlist(parameters$slow_parasite_clearance_prob), c(0.41, 0, 0.23)) expect_identical(unlist(parameters$early_treatment_failure_prob), c(0.2, 0, 0.9)) - expect_identical(unlist(parameters$late_clinical_failure_prob), c(0, 0.01, 0.49)) - expect_identical(unlist(parameters$late_parasitological_failure_prob), c(0, 0.42, 0.81)) - expect_identical(unlist(parameters$reinfection_during_prophylaxis), c(0, 0.89, 0.009)) + expect_identical(unlist(parameters$late_clinical_failure_prob), c(0, 0, 0)) + expect_identical(unlist(parameters$late_parasitological_failure_prob), c(0, 0, 0)) + expect_identical(unlist(parameters$reinfection_during_prophylaxis), c(0, 0, 0)) expect_identical(unlist(parameters$dt_slow_parasite_clearance), c(5, 10, 20)) }) @@ -168,12 +168,12 @@ test_that(desc = "set_antimalarial_resistance errors if length slow_parasite_cle drug = 1, timesteps = c(0, 10), artemisinin_resistance = c(0.4, 0.8), - partner_drug_resistance = c(0.23, 0.43), + partner_drug_resistance = c(0, 0), slow_parasite_clearance_prob = c(0.2, 0.4), early_treatment_failure_prob = c(0, 0.45), - late_clinical_failure_prob = c(0.01, 0.01), - late_parasitological_prob = c(0.05, 0.06), - reinfection_prob = c(0.86, 0.86), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), slow_parasite_clearance_time = c(10 ,11)), "Error: length of slow_parasite_clearance_time not equal to 1") }) @@ -192,12 +192,12 @@ test_that(desc = "set_antimalarial_resistance errors if slow_parasite_clearance_ drug = 1, timesteps = c(0, 10), artemisinin_resistance = c(0.4, 0.8), - partner_drug_resistance = c(0.23, 0.43), + partner_drug_resistance = c(0, 0), slow_parasite_clearance_prob = c(0.2, 0.4), early_treatment_failure_prob = c(0, 0.45), - late_clinical_failure_prob = c(0.01, 0.01), - late_parasitological_prob = c(0.05, 0.06), - reinfection_prob = c(0.86, 0.86), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), slow_parasite_clearance_time = c(0)), "Error: slow_parasite_clearance_time is non-positive") }) @@ -213,32 +213,32 @@ test_that('get_antimalarial_resistance_parameters() correctly retrieves paramete set_antimalarial_resistance(drug = 2, timesteps = c(0, 20), artemisinin_resistance = c(0.02, 0.2), - partner_drug_resistance = c(0.02, 0.2), + partner_drug_resistance = c(0, 0), slow_parasite_clearance_prob = c(0.02, 0.2), early_treatment_failure_prob = c(0.02, 0.2), - late_clinical_failure_prob = c(0.02, 0.2), - late_parasitological_prob = c(0.02, 0.2), - reinfection_prob = c(0.02, 0.2), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), slow_parasite_clearance_time = 20) %>% set_antimalarial_resistance(drug = 1, timesteps = c(0, 10), artemisinin_resistance = c(0.01, 0.1), - partner_drug_resistance = c(0.01, 0.1), + partner_drug_resistance = c(0, 0), slow_parasite_clearance_prob = c(0.01, 0.1), early_treatment_failure_prob = c(0.01, 0.1), - late_clinical_failure_prob = c(0.01, 0.1), - late_parasitological_prob = c(0.01, 0.1), - reinfection_prob = c(0.01, 0.1), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), slow_parasite_clearance_time = 10) %>% set_antimalarial_resistance(drug = 3, timesteps = c(0, 30), artemisinin_resistance = c(0.03, 0.3), - partner_drug_resistance = c(0.03, 0.3), + partner_drug_resistance = c(0, 0), slow_parasite_clearance_prob = c(0.03, 0.3), early_treatment_failure_prob = c(0.03, 0.3), - late_clinical_failure_prob = c(0.03, 0.3), - late_parasitological_prob = c(0.03, 0.3), - reinfection_prob = c(0.03, 0.3), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), slow_parasite_clearance_time = 30) -> parameters drugs <- c(1, 3, 2, 1, 2, 3, 3, 3, 2, 1, 3, 1, 2, 3, 2) @@ -250,12 +250,12 @@ test_that('get_antimalarial_resistance_parameters() correctly retrieves paramete expected_resistance_parameters <- list() expected_resistance_parameters$artemisinin_resistance_proportion <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) - expected_resistance_parameters$partner_drug_resistance_proportion <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) + expected_resistance_parameters$partner_drug_resistance_proportion <- rep(0, 15) expected_resistance_parameters$slow_parasite_clearance_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) expected_resistance_parameters$early_treatment_failure_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) - expected_resistance_parameters$late_clinical_failure_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) - expected_resistance_parameters$late_parasitological_failure_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) - expected_resistance_parameters$reinfection_during_prophylaxis_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) + expected_resistance_parameters$late_clinical_failure_probability <- rep(0, 15) + expected_resistance_parameters$late_parasitological_failure_probability <- rep(0, 15) + expected_resistance_parameters$reinfection_during_prophylaxis_probability <- rep(0, 15) expected_resistance_parameters$dt_slow_parasite_clearance <- c(10, 30, 20, 10, 20, 30, 30, 30, 20, 10, 30, 10, 20, 30, 20) expect_identical(resistance_parameters, expected = expected_resistance_parameters) @@ -273,12 +273,12 @@ test_that('get_antimalarial_resistance_parameters() correctly retrieves paramete set_antimalarial_resistance(drug = 2, timesteps = c(0, 20), artemisinin_resistance = c(0.02, 0.2), - partner_drug_resistance = c(0.02, 0.2), + partner_drug_resistance = c(0, 0), slow_parasite_clearance_prob = c(0.02, 0.2), early_treatment_failure_prob = c(0.02, 0.2), - late_clinical_failure_prob = c(0.02, 0.2), - late_parasitological_prob = c(0.02, 0.2), - reinfection_prob = c(0.02, 0.2), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), slow_parasite_clearance_time = 20) -> parameters drugs <- c(1, 3, 2, 1, 2, 3, 3, 3, 2, 1, 3, 1, 2, 3, 2) @@ -290,12 +290,12 @@ test_that('get_antimalarial_resistance_parameters() correctly retrieves paramete expected_resistance_parameters <- list() expected_resistance_parameters$artemisinin_resistance_proportion <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) - expected_resistance_parameters$partner_drug_resistance_proportion <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) + expected_resistance_parameters$partner_drug_resistance_proportion <- rep(0, 15) expected_resistance_parameters$slow_parasite_clearance_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) expected_resistance_parameters$early_treatment_failure_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) - expected_resistance_parameters$late_clinical_failure_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) - expected_resistance_parameters$late_parasitological_failure_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) - expected_resistance_parameters$reinfection_during_prophylaxis_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) + expected_resistance_parameters$late_clinical_failure_probability <- rep(0, 15) + expected_resistance_parameters$late_parasitological_failure_probability <- rep(0, 15) + expected_resistance_parameters$reinfection_during_prophylaxis_probability <- rep(0, 15) expected_resistance_parameters$dt_slow_parasite_clearance <- c(5, 5, 20, 5, 20, 5, 5, 5, 20, 5, 5, 5, 20, 5, 20) expect_identical(resistance_parameters, expected = expected_resistance_parameters) diff --git a/tests/testthat/test-infection-integration.R b/tests/testthat/test-infection-integration.R index b2e2b3bc..409cc466 100644 --- a/tests/testthat/test-infection-integration.R +++ b/tests/testthat/test-infection-integration.R @@ -315,7 +315,6 @@ test_that('calculate_treated correctly samples treated and updates the drug stat expect_bitset_update(variables$drug_time$queue_update, 5, c(1, 4)) }) -##' FIXING test_that('calculate_treated correctly samples treated and updates the drug state when resistance set', { parameters <- get_parameters() @@ -336,7 +335,7 @@ test_that('calculate_treated correctly samples treated and updates the drug stat parameters <- set_antimalarial_resistance(parameters = parameters, drug = 2, timesteps = 1, - artemisinin_resistance = 0, + artemisinin_resistance = 0.3, partner_drug_resistance = 0, slow_parasite_clearance_prob = 0, early_treatment_failure_prob = 0.9, @@ -352,17 +351,24 @@ test_that('calculate_treated correctly samples treated and updates the drug stat state = list(queue_update = mockery::mock()), infectivity = list(queue_update = mockery::mock()), drug = list(queue_update = mockery::mock()), - drug_time = list(queue_update = mockery::mock()) + drug_time = list(queue_update = mockery::mock()), + dt = list(queue_update = mockery::mock()) ) + renderer <- individual::Render$new(timesteps = timestep) + # Set up seek_treatment mock and instruct calculate_treated() to return it when sample_bitset() called: seek_treatment <- individual::Bitset$new(20)$insert(c(1:10)) seek_treatment_mock <- mockery::mock(seek_treatment) mockery::stub(where = calculate_treated, what = 'sample_bitset', how = seek_treatment_mock) + # Set up drugs mock and instruct it to return it when sample.int() called: mock_drugs <- mockery::mock(c(2, 1, 1, 1, 2, 2, 2, 1, 2, 1)) mockery::stub(calculate_treated, 'sample.int', mock_drugs) - bernoulli_mock <- mockery::mock(c(1, 2, 3, 4, 5, 6, 7, 8, 9), c(1, 2, 3, 4, 5, 6, 7)) + # Set up bernoulli mock and instruct calculate_treated to return it when bernoulli_multi_p() called: + bernoulli_mock <- mockery::mock(c(1, 2, 3, 4, 5, 6, 7, 8, 9), + c(1, 2, 3, 4, 5, 6, 7), + c(1)) mockery::stub(calculate_treated, 'bernoulli_multi_p', bernoulli_mock) calculate_treated( @@ -370,7 +376,7 @@ test_that('calculate_treated correctly samples treated and updates the drug stat clinical_infections, parameters, timestep, - mock_render(timestep) + renderer ) mockery::expect_args( @@ -392,13 +398,25 @@ test_that('calculate_treated correctly samples treated and updates the drug stat mockery::expect_args( bernoulli_mock, 1, - c(1.0, 0.9, 0.9, 0.9, 1.0, 1.0, 1.0, 0.9, 1, 0.9) + c(0.9, 0.95, 0.95, 0.95, 0.9, 0.9, 0.9, 0.95, 0.9, 0.95) ) mockery::expect_args( bernoulli_mock, 2, - parameters$drug_efficacy[c(2, 1, 1, 1, 2, 2, 2, 1, 2)] + c(0.73, 0.9, 0.9, 0.9, 0.73, 0.73, 0.73, 0.9, 0.73) + ) + + mockery::expect_args( + bernoulli_mock, + 2, + 1 - (unlist(parameters$prop_artemisinin_resistant[c(2, 1, 1, 1, 2, 2, 2, 1, 2)]) * unlist(parameters$early_treatment_failure_prob[c(2, 1, 1, 1, 2, 2, 2, 1, 2)])) + ) + + mockery::expect_args( + bernoulli_mock, + 3, + unlist(parameters$prop_artemisinin_resistant[c(2, 1, 1, 1, 2, 2, 2)]) * unlist(parameters$slow_parasite_clearance_prob[c(2, 1, 1, 1, 2, 2, 2)]) ) expect_bitset_update(variables$state$queue_update, 'Tr', c(1, 2, 3, 4, 5, 6, 7)) @@ -409,10 +427,10 @@ test_that('calculate_treated correctly samples treated and updates the drug stat ) expect_bitset_update(variables$drug$queue_update, c(2, 1, 1, 1, 2, 2, 2), c(1, 2, 3, 4, 5, 6, 7)) expect_bitset_update(variables$drug_time$queue_update, 5, c(1, 2, 3, 4, 5, 6, 7)) - + expect_bitset_update(variables$dt$queue_update, 5, c(2, 3, 4, 5, 6, 7), 1) + expect_bitset_update(variables$dt$queue_update, 15, c(1), 2) }) -##' FIX test_that('calculate_treated correctly samples treated and updates the drug state when resistance not set for all drugs', { # Establish the parameters @@ -425,8 +443,8 @@ test_that('calculate_treated correctly samples treated and updates the drug stat timesteps = 1, artemisinin_resistance = 0.8, partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0, - early_treatment_failure_prob = 0.9, + slow_parasite_clearance_prob = 0.2, + early_treatment_failure_prob = 0.3, late_clinical_failure_prob = 0, late_parasitological_prob = 0, reinfection_prob = 0, @@ -446,7 +464,8 @@ test_that('calculate_treated correctly samples treated and updates the drug stat state = list(queue_update = mockery::mock()), infectivity = list(queue_update = mockery::mock()), drug = list(queue_update = mockery::mock()), - drug_time = list(queue_update = mockery::mock()) + drug_time = list(queue_update = mockery::mock()), + dt = list(queue_update = mockery::mock()) ) # Create a Bitset of individuals seeking treatment individuals: @@ -465,7 +484,9 @@ test_that('calculate_treated correctly samples treated and updates the drug stat mockery::stub(calculate_treated, 'sample.int', mock_drugs) # Create a bernoulli_mock of i) individuals susceptible, and ii) individuals successfully treated: - bernoulli_mock <- mockery::mock(c(1, 2, 3, 4, 5, 6, 7, 8, 9), c(1, 2, 3, 4, 5, 6, 7)) + bernoulli_mock <- mockery::mock(c(1, 2, 3, 4, 5, 6, 7, 8, 9), + c(1, 2, 3, 4, 5, 6, 7), + c(1)) # Specify that when calculate_treated() calls bernoulli_multi_p() it returns the bernoulli_mock: mockery::stub(calculate_treated, 'bernoulli_multi_p', bernoulli_mock) @@ -504,7 +525,7 @@ test_that('calculate_treated correctly samples treated and updates the drug stat mockery::expect_args( bernoulli_mock, 1, - c(0.28, 1, 1, 1, 0.28, 0.28, 0.28, 1, 0.28, 1) # (1 - (art_prop * etf_prob)) + parameters$drug_efficacy[c(2, 1, 1, 1, 2, 2, 2, 1, 2, 1)] ) # Check that the secnd time bernoulli_mock was called (bernoulli_multi_p()) the arguments used in @@ -512,7 +533,7 @@ test_that('calculate_treated correctly samples treated and updates the drug stat mockery::expect_args( bernoulli_mock, 2, - parameters$drug_efficacy[c(2, 1, 1, 1, 2, 2, 2, 1, 2)] + c(0.76, 1, 1, 1, 0.76, 0.76, 0.76, 1, 0.76) ) # Check that update queued that updates the state of successfully treated individuals to "Tr" @@ -545,6 +566,21 @@ test_that('calculate_treated correctly samples treated and updates the drug stat 5, c(1, 2, 3, 4, 5, 6, 7) ) + + # Check that update queued for dt for the non-slow parasite clearance individuals is correct: + expect_bitset_update( + variables$dt$queue_update, + parameters$dt, + c(2, 3, 4, 5, 6, 7), + 1) + + # Check that update queued for dt for the slow parasite clearance individuals is correct: + expect_bitset_update( + variables$dt$queue_update, + unlist(parameters$dt_slow_parasite_clearance), + c(1), + 2) + }) test_that('schedule_infections correctly schedules new infections', { @@ -859,63 +895,61 @@ test_that('calculate_treated() returns an empty Bitset when the parameter list c in the absence of clinical treatment or resistance parameters") }) -##' FIX test_that('Number of treatment failures matches number of individuals treated when artemisinin resistance proportion and early treatment failure probability both set to 1', { - parameters <- get_parameters() - parameters <- set_drugs(parameters = parameters, drugs = list(AL_params, SP_AQ_params)) - parameters <- set_clinical_treatment(parameters = parameters, - drug = 1, - timesteps = 1, - coverages = round(runif(1, 0, 1/2), - digits = 2)) - parameters <- set_clinical_treatment(parameters = parameters, - drug = 2, - timesteps = 1, - coverages = round(runif(1, 0, 1/2), - digits = 2)) - parameters <- set_antimalarial_resistance(parameters = parameters, - drug = 1, - timesteps = 1, - artemisinin_resistance = 1, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0, - early_treatment_failure_prob = 1, - late_clinical_failure_prob = 0, - late_parasitological_prob = 0, - reinfection_prob = 0, - slow_parasite_clearance_time = 10) - parameters <- set_antimalarial_resistance(parameters = parameters, - drug = 2, - timesteps = 1, - artemisinin_resistance = 1, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0, - early_treatment_failure_prob = 1, - late_clinical_failure_prob = 0, - late_parasitological_prob = 0, - reinfection_prob = 0, - slow_parasite_clearance_time = 20) - - clinical_infections <- individual::Bitset$new(100) - clinical_infections$insert(sample.int(n = 100, size = round(runif(n = 1, min = 10, max = 100)), replace = FALSE)) - timestep <- 5 - events <- create_events(parameters) - variables <- create_variables(parameters = parameters) - renderer <- individual::Render$new(timesteps = 10) - - treated <- calculate_treated(variables = variables, - clinical_infections = clinical_infections, - parameters = parameters, - timestep = timestep, - renderer = renderer) - - expect_identical(renderer$to_dataframe()[timestep,'n_early_treatment_failure'], renderer$to_dataframe()[timestep,'n_treated'], info = "Error: Number of - early treatment failures does not match number of treated individuals when artemisinin resistance proportion and + parameters <- get_parameters() + parameters <- set_drugs(parameters = parameters, drugs = list(AL_params, SP_AQ_params)) + parameters <- set_clinical_treatment(parameters = parameters, + drug = 1, + timesteps = 1, + coverages = round(runif(1, 0, 1/2), + digits = 2)) + parameters <- set_clinical_treatment(parameters = parameters, + drug = 2, + timesteps = 1, + coverages = round(runif(1, 0, 1/2), + digits = 2)) + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 1, + timesteps = 1, + artemisinin_resistance = 1, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0, + early_treatment_failure_prob = 1, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0, + slow_parasite_clearance_time = 10) + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 2, + timesteps = 1, + artemisinin_resistance = 1, + partner_drug_resistance = 0, + slow_parasite_clearance_prob = 0, + early_treatment_failure_prob = 1, + late_clinical_failure_prob = 0, + late_parasitological_prob = 0, + reinfection_prob = 0, + slow_parasite_clearance_time = 20) + + clinical_infections <- individual::Bitset$new(100) + clinical_infections$insert(sample.int(n = 100, size = round(runif(n = 1, min = 10, max = 100)), replace = FALSE)) + timestep <- 5 + events <- create_events(parameters) + variables <- create_variables(parameters = parameters) + renderer <- individual::Render$new(timesteps = 10) + + treated <- calculate_treated(variables = variables, + clinical_infections = clinical_infections, + parameters = parameters, + timestep = timestep, + renderer = renderer) + + expect_identical(renderer$to_dataframe()[timestep,'n_early_treatment_failure'], renderer$to_dataframe()[timestep,'n_treated'] - renderer$to_dataframe()[timestep,'n_drug_efficacy_failures'], info = "Error: Number of + early treatment failures does not match number of treated individuals (minus drug efficacy failures) when artemisinin resistance proportion and and early treatment failure probability both equal 1") -}) + }) -##' FIX test_that('calculate_treated() successfully adds additional resistance columns to the renderer', { parameters <- get_parameters() parameters <- set_drugs(parameters = parameters, drugs = list(AL_params)) @@ -939,7 +973,8 @@ test_that('calculate_treated() successfully adds additional resistance columns t state = list(queue_update = mockery::mock()), infectivity = list(queue_update = mockery::mock()), drug = list(queue_update = mockery::mock()), - drug_time = list(queue_update = mockery::mock()) + drug_time = list(queue_update = mockery::mock()), + dt = list(queue_update = mockery::mock()) ) renderer <- individual::Render$new(timesteps = 10) @@ -949,7 +984,12 @@ test_that('calculate_treated() successfully adds additional resistance columns t timestep = timestep, renderer = renderer) - calculate_treated_column_names <- c("ft", "n_treated", "n_early_treatment_failure", "n_treat_eff_fail", "n_treat_success") + calculate_treated_column_names <- c("ft", + "n_treated", + "n_drug_efficacy_failures", + "n_early_treatment_failure", + "n_slow_parasite_clearance", + "n_successfully_treated") expect_identical(sum(calculate_treated_column_names %in% colnames(renderer$to_dataframe())), length(calculate_treated_column_names), "calculate_treated() not renderering all resistance columns when resistance is present, clinical treatment coverage is non-zero, and the Bitset of clinically_infected individuals input is of non-zero length.") From 0cef2733583300c8ad3cb47f2937b09571c69f36 Mon Sep 17 00:00:00 2001 From: tbreweric Date: Thu, 4 Apr 2024 17:59:57 +0100 Subject: [PATCH 157/164] Added section modelling early treatment failure and slow parasite clearance to the vignette --- vignettes/Antimalarial_Resistance.Rmd | 153 +++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 1 deletion(-) diff --git a/vignettes/Antimalarial_Resistance.Rmd b/vignettes/Antimalarial_Resistance.Rmd index 7bf197b7..9c873202 100644 --- a/vignettes/Antimalarial_Resistance.Rmd +++ b/vignettes/Antimalarial_Resistance.Rmd @@ -14,7 +14,6 @@ knitr::opts_chunk$set( ) ``` - ```{r setup} # Load the requisite packages: @@ -259,5 +258,157 @@ text(x = resistance_update_timesteps[2:5] + 30, y = 0.6, labels = paste0("Art. R Looking at the figure, we can see that the *Pf*PR~2-10~ decreases over the two years following the onset of clinical treatment in the absence of artemisinin resistance. However, as resistance is introduced and increases through time, the *Pf*PR~2-10~ increases towards the pre-intervention seasonal peak as SP-AQ becomes increasingly ineffective in the treatment of clinical cases of malaria. +## Simulating antimalarial resistance with multiple resistance outcomes + +As we've discussed, resistance to an ACT can manifest in multiple ways. For instance, resistance to the artemisinin component of an ACT can result in either early treatment failure or slow parasite clearance. + +Using `malariasimulation`, we can simulate the effects of multiple potential outcomes of resistance on malaria transmission dynamics. To illustrate, we'll parameterise and run a series of simulations in is i) no clinical treatment, ii) no resistance, iii) resistance with early treatment failure, iv) resistance with slow parasite clearance, and v) resistance with early treatment failure and slow parasite clearance. + +### Parameterisation +```{r} + +# Determine the number of timesteps to run for: +timesteps <- 365 * 6 + +# Set up a list to store the simulation parameter lists in: +simulation_parameters <- list() + +# Establish a list of the base parameters with no clinical treatment or antimalarial resistance: +get_parameters(overrides = list(human_population = 1000)) -> simulation_parameters$base + +# Establish a parameter list with clinical treatment starting after one year: +simulation_parameters$base |> + set_drugs(drugs = list(AL_params)) |> + set_clinical_treatment(drug = 1, timesteps = (365 * 1) + 1, coverages = c(0.8)) |> + set_equilibrium(init_EIR = 16) -> simulation_parameters$treatment + +# Set the equilibrium for the base parameters: +simulation_parameters$base |> + set_equilibrium(init_EIR = 16) -> simulation_parameters$base + +# Establish a parameter list with clinical treatment and early treatment failure +simulation_parameters$treatment |> + set_antimalarial_resistance(drug = 1, + timesteps = c(0, (365 * 3) + 1), + artemisinin_resistance = c(0, 0.8), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = c(0, 0), + early_treatment_failure_prob = c(0, 0.8), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), + slow_parasite_clearance_time = 10) -> simulation_parameters$etf + +# Establish a parameter list with clinical treatment and slow parasite clearance +simulation_parameters$treatment |> + set_antimalarial_resistance(drug = 1, + timesteps = c(0, (365 * 3) + 1), + artemisinin_resistance = c(0, 0.8), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = c(0, 0.8), + early_treatment_failure_prob = c(0, 0), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), + slow_parasite_clearance_time = 10) -> simulation_parameters$spc + +# Establish a parameter list with clinical treatment, early treatment failure and slow parasite clearance: +simulation_parameters$treatment |> + set_antimalarial_resistance(drug = 1, + timesteps = c(0, (365 * 3) + 1), + artemisinin_resistance = c(0, 0.8), + partner_drug_resistance = c(0, 0), + slow_parasite_clearance_prob = c(0, 0.8), + early_treatment_failure_prob = c(0, 0.8), + late_clinical_failure_prob = c(0, 0), + late_parasitological_prob = c(0, 0), + reinfection_prob = c(0, 0), + slow_parasite_clearance_time = 10) -> simulation_parameters$etf_spc + +``` + +### Simulation +We can now use our lists of `malariasimulation` parameters to run the simulations. + +```{r} + +# Open a list to store the simulation outputs in: +simulation_outputs <- list() + +# Run the simulations +for(i in seq(length(simulation_parameters))) { + + # Run the i-th simulation + simulation_temp <- run_simulation(timesteps = timesteps, + parameters = simulation_parameters[[i]]) + + # Append the simulation identifier: + simulation_temp$identifier <- names(simulation_parameters)[i] + + # Append the ith simulation outputs to the combined simulation dataframe: + simulation_outputs[[names(simulation_parameters)[i]]] <- simulation_temp + + # Print the number of columns in the i-th simulation outputs dataframe: + print(ncol(simulation_temp)) +} + +``` + +### Data Wranging + + + +### Visualisation + +We can compare the effects of independent resistance outcomes with combined resistance outcomes visually. + +```{R} + +# Open a new plotting window and add a grid: +plot.new(); par(mar = c(4, 4, 1, 1), new = TRUE) + +# Plot malaria prevalence in 2-10 years through time: +plot(x = simulation_outputs$base$timestep, + y = simulation_outputs$base$n_detect_730_3650/simulation_outputs$base$n_730_3650, + xlab = "Time (days)", + ylab = expression(paste(italic(Pf),"PR"[2-10])), cex = 0.8, + ylim = c(0, 1), type = "l", lwd = 2, xaxs = "i", yaxs = "i", + col = cols[3]) + +# Add the dynamics for no-intervention simulation +lines(x = simulation_outputs$treatment$timestep, + y = simulation_outputs$treatment$n_detect_730_3650/simulation_outputs$treatment$n_730_3650, + col = cols[4]) + +lines(x = simulation_outputs$etf$timestep, + y = simulation_outputs$etf$n_detect_730_3650/simulation_outputs$etf$n_730_3650, + col = cols[5]) + +lines(x = simulation_outputs$spc$timestep, + y = simulation_outputs$spc$n_detect_730_3650/simulation_outputs$spc$n_730_3650, + col = cols[6]) + +lines(x = simulation_outputs$etf_spc$timestep, + y = simulation_outputs$etf_spc$n_detect_730_3650/simulation_outputs$etf_spc$n_730_3650, + col = cols[7]) + +# Add vlines to indicate when SP-AQ were administered: +abline(v = 365 + 1, lty = "dashed", lwd = 1) +text(x = (365 * 1) - 40, y = 0.6, labels = "Treatment Introduced", adj = 0, cex = 0.8, srt = 90) + +abline(v = (365 * 3) + 1, lty = "dashed", lwd = 1) +text(x = (365 * 3) - 40, y = 0.6, labels = "Resistance Introduced", adj = 0, cex = 0.8, srt = 90) + +# Add gridlines: +grid(lty = 2, col = "grey80", nx = NULL, ny = NULL, lwd = 0.5); box() + +# Add a legend: +legend(x = 3000, y = 0.99, legend = c("Baseline", "Treatment", "ETF-only", "SPC-only", "ETF and SPC"), + col= c(cols[3:7]), box.col = "white", + lwd = 1, lty = c(1, 1), cex = 0.8) + + +``` + ## References Slater, H.C., Griffin, J.T., Ghani, A.C. and Okell, L.C., 2016. Assessing the potential impact of artemisinin and partner drug resistance in sub-Saharan Africa. Malaria journal, 15(1), pp.1-11. \ No newline at end of file From 5123d6e28c49c4e6de33de337ea06c383f35068f Mon Sep 17 00:00:00 2001 From: tbreweric Date: Thu, 4 Apr 2024 22:15:22 +0100 Subject: [PATCH 158/164] Made clearer the antimalarial resistance parameter names in set_antimalarial_resistance and get_antimalarial_resistance_parameters, then made additional changes to documentation where necessary to reflect changes. Fixed the effects of the changes on unit tests --- R/antimalarial_resistance.R | 94 ++-- R/parameters.R | 28 +- man/get_parameters.Rd | 14 +- man/run_simulation.Rd | 2 +- man/set_antimalarial_resistance.Rd | 28 +- tests/testthat/test-antimalarial-resistance.R | 459 +++++++++--------- tests/testthat/test-infection-integration.R | 230 ++++----- vignettes/Antimalarial_Resistance.Rmd | 74 +-- 8 files changed, 465 insertions(+), 464 deletions(-) diff --git a/R/antimalarial_resistance.R b/R/antimalarial_resistance.R index 7da3ad83..ce5d94f6 100644 --- a/R/antimalarial_resistance.R +++ b/R/antimalarial_resistance.R @@ -5,54 +5,54 @@ #' @param parameters the model parameters #' @param drug the index of the drug which resistance is being set, as set by the set_drugs() function, in the parameter list #' @param timesteps vector of time steps for each update to resistance proportion and resistance outcome probability -#' @param artemisinin_resistance vector of updates to the proportions of infections that are artemisinin resistant at time t -#' @param partner_drug_resistance vector of updates to the proportions of infections that are partner-drug resistant at time t -#' @param slow_parasite_clearance_prob vector of updates to the proportion of artemisinin-resistant infections that result in early treatment failure -#' @param early_treatment_failure_prob vector of updates to the proportion of artemisinin-resistant infections that result in slow parasite clearance -#' @param late_clinical_failure_prob vector of updates to the proportion of partner-drug-resistant infections that result in late clinical failure -#' @param late_parasitological_prob vector of updates to the proportion of partner-drug-resistant infections that result in late parasitological failure -#' @param reinfection_prob vector of updates to the proportion of partner-drug-resistant infections that result in reinfection during prophylaxis +#' @param artemisinin_resistance_proportion vector of updates to the proportions of infections that are artemisinin resistant at time t +#' @param partner_drug_resistance_proportion vector of updates to the proportions of infections that are partner-drug resistant at time t +#' @param slow_parasite_clearance_probability vector of updates to the proportion of artemisinin-resistant infections that result in early treatment failure +#' @param early_treatment_failure_probability vector of updates to the proportion of artemisinin-resistant infections that result in slow parasite clearance +#' @param late_clinical_failure_probability vector of updates to the proportion of partner-drug-resistant infections that result in late clinical failure +#' @param late_parasitological_failure_probability vector of updates to the proportion of partner-drug-resistant infections that result in late parasitological failure +#' @param reinfection_during_prophylaxis_probability vector of updates to the proportion of partner-drug-resistant infections that result in reinfection during prophylaxis #' @param slow_parasite_clearance_time single value representing the mean time individual's experiencing slow parasite clearance reside in the treated state #' @export set_antimalarial_resistance <- function(parameters, drug, timesteps, - artemisinin_resistance, - partner_drug_resistance, - slow_parasite_clearance_prob, - early_treatment_failure_prob, - late_clinical_failure_prob, - late_parasitological_prob, - reinfection_prob, + artemisinin_resistance_proportion, + partner_drug_resistance_proportion, + slow_parasite_clearance_probability, + early_treatment_failure_probability, + late_clinical_failure_probability, + late_parasitological_failure_probability, + reinfection_during_prophylaxis_probability, slow_parasite_clearance_time) { - if(any(partner_drug_resistance > 0, - late_clinical_failure_prob > 0, - late_parasitological_prob > 0, - reinfection_prob > 0)) { + if(any(partner_drug_resistance_proportion > 0, + late_clinical_failure_probability > 0, + late_parasitological_failure_probability > 0, + reinfection_during_prophylaxis_probability > 0)) { stop("Parameters set for unimplemented feature - late clinical failure, late parasitological failure, or reinfection during prophylaxis") } - if(any(c(length(artemisinin_resistance), - length(partner_drug_resistance), - length(slow_parasite_clearance_prob), - length(early_treatment_failure_prob), - length(late_clinical_failure_prob), - length(late_parasitological_prob), - length(reinfection_prob)) != length(timesteps))) { + if(any(c(length(artemisinin_resistance_proportion), + length(partner_drug_resistance_proportion), + length(slow_parasite_clearance_probability), + length(early_treatment_failure_probability), + length(late_clinical_failure_probability), + length(late_parasitological_failure_probability), + length(reinfection_during_prophylaxis_probability)) != length(timesteps))) { stop("Length of one or more resistance parameter vectors does not match time steps specified for update") } - if(any(artemisinin_resistance < 0 | artemisinin_resistance > 1 | - partner_drug_resistance < 0 | partner_drug_resistance > 1)) { + if(any(artemisinin_resistance_proportion < 0 | artemisinin_resistance_proportion > 1 | + partner_drug_resistance_proportion < 0 | partner_drug_resistance_proportion > 1)) { stop("Artemisinin and partner-drug resistance proportions must fall between 0 and 1") } - if(any(slow_parasite_clearance_prob < 0 | slow_parasite_clearance_prob > 1 | - early_treatment_failure_prob < 0 | early_treatment_failure_prob > 1 | - late_clinical_failure_prob < 0 | late_clinical_failure_prob > 1 | - late_parasitological_prob < 0 | late_parasitological_prob > 1 | - reinfection_prob < 0 | reinfection_prob > 1)) { + if(any(slow_parasite_clearance_probability < 0 | slow_parasite_clearance_probability > 1 | + early_treatment_failure_probability < 0 | early_treatment_failure_probability > 1 | + late_clinical_failure_probability < 0 | late_clinical_failure_probability > 1 | + late_parasitological_failure_probability < 0 | late_parasitological_failure_probability > 1 | + reinfection_during_prophylaxis_probability < 0 | reinfection_during_prophylaxis_probability > 1)) { stop("Resistance outcome probabilities must fall between 0 and 1") } @@ -80,13 +80,13 @@ set_antimalarial_resistance <- function(parameters, parameters$antimalarial_resistance_drug[[drug_index]] <- drug parameters$antimalarial_resistance_timesteps[[drug_index]] <- timesteps - parameters$prop_artemisinin_resistant[[drug_index]] <- artemisinin_resistance - parameters$prop_partner_drug_resistant[[drug_index]] <- partner_drug_resistance - parameters$slow_parasite_clearance_prob[[drug_index]] <- slow_parasite_clearance_prob - parameters$early_treatment_failure_prob[[drug_index]] <- early_treatment_failure_prob - parameters$late_clinical_failure_prob[[drug_index]] <- late_clinical_failure_prob - parameters$late_parasitological_failure_prob[[drug_index]] <- late_parasitological_prob - parameters$reinfection_during_prophylaxis[[drug_index]] <- reinfection_prob + parameters$artemisinin_resistance_proportion[[drug_index]] <- artemisinin_resistance_proportion + parameters$partner_drug_resistance_proportion[[drug_index]] <- partner_drug_resistance_proportion + parameters$slow_parasite_clearance_probability[[drug_index]] <- slow_parasite_clearance_probability + parameters$early_treatment_failure_probability[[drug_index]] <- early_treatment_failure_probability + parameters$late_clinical_failure_probability[[drug_index]] <- late_clinical_failure_probability + parameters$late_parasitological_failure_probability[[drug_index]] <- late_parasitological_failure_probability + parameters$reinfection_during_prophylaxis_probability[[drug_index]] <- reinfection_during_prophylaxis_probability parameters$dt_slow_parasite_clearance[[drug_index]] <- slow_parasite_clearance_time return(parameters) @@ -121,13 +121,13 @@ get_antimalarial_resistance_parameters <- function(parameters, drugs, timestep) drug <- parameters$antimalarial_resistance_drug[[i]] treated_with_drug <- which(drugs == drug) resistance_timestep <- match_timestep(ts = parameters$antimalarial_resistance_timesteps[[i]], t = timestep) - artemisinin_resistance_proportion[treated_with_drug] <- parameters$prop_artemisinin_resistant[[i]][resistance_timestep] - partner_drug_resistance_proportion[treated_with_drug] <- parameters$prop_partner_drug_resistant[[i]][resistance_timestep] - slow_parasite_clearance_probability[treated_with_drug] <- parameters$slow_parasite_clearance_prob[[i]][resistance_timestep] - early_treatment_failure_probability[treated_with_drug] <- parameters$early_treatment_failure_prob[[i]][resistance_timestep] - late_clinical_failure_probability[treated_with_drug] <- parameters$late_clinical_failure_prob[[i]][resistance_timestep] - late_parasitological_failure_probability[treated_with_drug] <- parameters$late_parasitological_failure_prob[[i]][resistance_timestep] - reinfection_during_prophylaxis_probability[treated_with_drug] <- parameters$reinfection_during_prophylaxis[[i]][resistance_timestep] + artemisinin_resistance_proportion[treated_with_drug] <- parameters$artemisinin_resistance_proportion[[i]][resistance_timestep] + partner_drug_resistance_proportion[treated_with_drug] <- parameters$partner_drug_resistance_proportion[[i]][resistance_timestep] + slow_parasite_clearance_probability[treated_with_drug] <- parameters$slow_parasite_clearance_probability[[i]][resistance_timestep] + early_treatment_failure_probability[treated_with_drug] <- parameters$early_treatment_failure_probability[[i]][resistance_timestep] + late_clinical_failure_probability[treated_with_drug] <- parameters$late_clinical_failure_probability[[i]][resistance_timestep] + late_parasitological_failure_probability[treated_with_drug] <- parameters$late_parasitological_failure_probability[[i]][resistance_timestep] + reinfection_during_prophylaxis_probability[treated_with_drug] <- parameters$reinfection_during_prophylaxis_probability[[i]][resistance_timestep] dt_slow_parasite_clearance[treated_with_drug] <- parameters$dt_slow_parasite_clearance[[i]] } @@ -143,4 +143,4 @@ get_antimalarial_resistance_parameters <- function(parameters, drugs, timestep) return(resistance_parameters) -} \ No newline at end of file +} diff --git a/R/parameters.R b/R/parameters.R index c87e69bf..b5b145ed 100644 --- a/R/parameters.R +++ b/R/parameters.R @@ -200,13 +200,13 @@ #' * antimalarial_resistance - boolean for if antimalarial resistance is enabled; default = FALSE #' * antimalarial_resistance_drug - vector of drugs for which resistance can be parameterised; default = NULL #' * antimalarial_resistance_timesteps - vector of time steps on which resistance updates occur; default = NULL -#' * prop_artemisinin_resistant - vector of proportions of infections resistant to the artemisinin component of a given drug; default = NULL -#' * prop_partner_drug_resistant - vector of proportions of infections resistant to the parter drug component of a given drug; default = NULL -#' * slow_parasite_clearance_prob - vector of probabilities of slow parasite clearance for a given drug; default = NULL -#' * early_treatment_failure_prob - vector of probabilities of early treatment failure for a given drug; default = NULL -#' * late_clinical_failure_prob - vector of probabilities of late clinical failure for a given drug; default = NULL -#' * late_parasitological_failure_prob - vector of probabilities of late parasitological failure for a given drug; default = NULL -#' * reinfection_during_prophylaxis - vector of probabilities of reinfection during prophylaxis for a given drug; default = NULL +#' * artemisinin_resistant_proportion - vector of proportions of infections resistant to the artemisinin component of a given drug; default = NULL +#' * partner_drug_resistance_proportion - vector of proportions of infections resistant to the parter drug component of a given drug; default = NULL +#' * slow_parasite_clearance_probability - vector of probabilities of slow parasite clearance for a given drug; default = NULL +#' * early_treatment_failure_probability - vector of probabilities of early treatment failure for a given drug; default = NULL +#' * late_clinical_failure_probability - vector of probabilities of late clinical failure for a given drug; default = NULL +#' * late_parasitological_failure_probability - vector of probabilities of late parasitological failure for a given drug; default = NULL +#' * reinfection_during_prophylaxis_probability - vector of probabilities of reinfection during prophylaxis for a given drug; default = NULL #' * dt_slow_parasite_clearance - the delay for humans experiencing slow parasite clearance to move from state Tr to S; default = NULL #' #' rendering: @@ -397,13 +397,13 @@ get_parameters <- function(overrides = list()) { antimalarial_resistance = FALSE, antimalarial_resistance_drug = NULL, antimalarial_resistance_timesteps = NULL, - prop_artemisinin_resistant = NULL, - prop_partner_drug_resistant = NULL, - slow_parasite_clearance_prob = NULL, - early_treatment_failure_prob = NULL, - late_clinical_failure_prob = NULL, - late_parasitological_failure_prob = NULL, - reinfection_during_prophylaxis = NULL, + artemisinin_resistance_proportion = NULL, + partner_drug_resistance_proportion = NULL, + slow_parasite_clearance_probability = NULL, + early_treatment_failure_probability = NULL, + late_clinical_failure_probability = NULL, + late_parasitological_failure_probability = NULL, + reinfection_during_prophylaxis_probability = NULL, dt_slow_parasite_clearance = NULL, # flexible carrying capacity carrying_capacity = FALSE, diff --git a/man/get_parameters.Rd b/man/get_parameters.Rd index fc6ba000..f1f7ddee 100644 --- a/man/get_parameters.Rd +++ b/man/get_parameters.Rd @@ -221,13 +221,13 @@ please set antimalarial resistance parameters with the convenience functions in \item antimalarial_resistance - boolean for if antimalarial resistance is enabled; default = FALSE \item antimalarial_resistance_drug - vector of drugs for which resistance can be parameterised; default = NULL \item antimalarial_resistance_timesteps - vector of time steps on which resistance updates occur; default = NULL -\item prop_artemisinin_resistant - vector of proportions of infections resistant to the artemisinin component of a given drug; default = NULL -\item prop_partner_drug_resistant - vector of proportions of infections resistant to the parter drug component of a given drug; default = NULL -\item slow_parasite_clearance_prob - vector of probabilities of slow parasite clearance for a given drug; default = NULL -\item early_treatment_failure_prob - vector of probabilities of early treatment failure for a given drug; default = NULL -\item late_clinical_failure_prob - vector of probabilities of late clinical failure for a given drug; default = NULL -\item late_parasitological_failure_prob - vector of probabilities of late parasitological failure for a given drug; default = NULL -\item reinfection_during_prophylaxis - vector of probabilities of reinfection during prophylaxis for a given drug; default = NULL +\item artemisinin_resistant_proportion - vector of proportions of infections resistant to the artemisinin component of a given drug; default = NULL +\item partner_drug_resistance_proportion - vector of proportions of infections resistant to the parter drug component of a given drug; default = NULL +\item slow_parasite_clearance_probability - vector of probabilities of slow parasite clearance for a given drug; default = NULL +\item early_treatment_failure_probability - vector of probabilities of early treatment failure for a given drug; default = NULL +\item late_clinical_failure_probability - vector of probabilities of late clinical failure for a given drug; default = NULL +\item late_parasitological_failure_probability - vector of probabilities of late parasitological failure for a given drug; default = NULL +\item reinfection_during_prophylaxis_probability - vector of probabilities of reinfection during prophylaxis for a given drug; default = NULL \item dt_slow_parasite_clearance - the delay for humans experiencing slow parasite clearance to move from state Tr to S; default = NULL } diff --git a/man/run_simulation.Rd b/man/run_simulation.Rd index b9e95e0a..383b38f6 100644 --- a/man/run_simulation.Rd +++ b/man/run_simulation.Rd @@ -92,7 +92,7 @@ susceptible \item mosquito_deaths: number of adult female mosquitoes who die this timestep \item n_drug_efficacy_failures: number of clinically treated individuals whose treatment failed due to drug efficacy \item n_early_treatment_failure: number of clinically treated individuals who experienced early treatment failure -\item n_successfully_treated: number of clinically treated individuals who are treated successfully +\item n_successfully_treated: number of clinically treated individuals who are treated successfully (includes individuals who experience slow parasite clearance) \item n_slow_parasite_clearance: number of clinically treated individuals who experienced slow parasite clearance } } diff --git a/man/set_antimalarial_resistance.Rd b/man/set_antimalarial_resistance.Rd index 82c65405..56627125 100644 --- a/man/set_antimalarial_resistance.Rd +++ b/man/set_antimalarial_resistance.Rd @@ -8,13 +8,13 @@ set_antimalarial_resistance( parameters, drug, timesteps, - artemisinin_resistance, - partner_drug_resistance, - slow_parasite_clearance_prob, - early_treatment_failure_prob, - late_clinical_failure_prob, - late_parasitological_prob, - reinfection_prob, + artemisinin_resistance_proportion, + partner_drug_resistance_proportion, + slow_parasite_clearance_probability, + early_treatment_failure_probability, + late_clinical_failure_probability, + late_parasitological_failure_probability, + reinfection_during_prophylaxis_probability, slow_parasite_clearance_time ) } @@ -25,19 +25,19 @@ set_antimalarial_resistance( \item{timesteps}{vector of time steps for each update to resistance proportion and resistance outcome probability} -\item{artemisinin_resistance}{vector of updates to the proportions of infections that are artemisinin resistant at time t} +\item{artemisinin_resistance_proportion}{vector of updates to the proportions of infections that are artemisinin resistant at time t} -\item{partner_drug_resistance}{vector of updates to the proportions of infections that are partner-drug resistant at time t} +\item{partner_drug_resistance_proportion}{vector of updates to the proportions of infections that are partner-drug resistant at time t} -\item{slow_parasite_clearance_prob}{vector of updates to the proportion of artemisinin-resistant infections that result in early treatment failure} +\item{slow_parasite_clearance_probability}{vector of updates to the proportion of artemisinin-resistant infections that result in early treatment failure} -\item{early_treatment_failure_prob}{vector of updates to the proportion of artemisinin-resistant infections that result in slow parasite clearance} +\item{early_treatment_failure_probability}{vector of updates to the proportion of artemisinin-resistant infections that result in slow parasite clearance} -\item{late_clinical_failure_prob}{vector of updates to the proportion of partner-drug-resistant infections that result in late clinical failure} +\item{late_clinical_failure_probability}{vector of updates to the proportion of partner-drug-resistant infections that result in late clinical failure} -\item{late_parasitological_prob}{vector of updates to the proportion of partner-drug-resistant infections that result in late parasitological failure} +\item{late_parasitological_failure_probability}{vector of updates to the proportion of partner-drug-resistant infections that result in late parasitological failure} -\item{reinfection_prob}{vector of updates to the proportion of partner-drug-resistant infections that result in reinfection during prophylaxis} +\item{reinfection_during_prophylaxis_probability}{vector of updates to the proportion of partner-drug-resistant infections that result in reinfection during prophylaxis} \item{slow_parasite_clearance_time}{single value representing the mean time individual's experiencing slow parasite clearance reside in the treated state} } diff --git a/tests/testthat/test-antimalarial-resistance.R b/tests/testthat/test-antimalarial-resistance.R index 193e09cf..ae45a20e 100644 --- a/tests/testthat/test-antimalarial-resistance.R +++ b/tests/testthat/test-antimalarial-resistance.R @@ -1,102 +1,103 @@ test_that('set_antimalarial_resistance() toggles resistance on', { - simparams <- get_parameters() - simparams <- set_drugs(parameters = simparams, drugs = list(SP_AQ_params)) - simparams <- set_clinical_treatment(parameters = simparams, - drug = 1, - timesteps = 1, - coverages = 1) - set_antimalarial_resistance(parameters = simparams, + parameters <- get_parameters() + parameters <- set_drugs(parameters = parameters, drugs = list(SP_AQ_params)) + parameters <- set_clinical_treatment(parameters = parameters, + drug = 1, + timesteps = 1, + coverages = 1) + set_antimalarial_resistance(parameters = parameters, drug = 1, timesteps = 1, - artemisinin_resistance = 0.5, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0.5, - early_treatment_failure_prob = 0.6, - late_clinical_failure_prob = 0, - late_parasitological_prob = 0, - reinfection_prob = 0, - slow_parasite_clearance_time = 10) -> simparams - expect_identical(object = simparams$antimalarial_resistance, expected = TRUE) + artemisinin_resistance_proportion = 0.5, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0.5, + early_treatment_failure_probability = 0.6, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, + slow_parasite_clearance_time = 10) -> parameters + expect_identical(object = parameters$antimalarial_resistance, expected = TRUE) }) test_that('set_antimalarial_resistance() errors if parameter inputs of different length to timesteps', { - simparams <- get_parameters() - simparams <- set_drugs(parameters = simparams, drugs = list(SP_AQ_params)) - simparams <- set_clinical_treatment(parameters = simparams, - drug = 1, - timesteps = 1, - coverages = 1) - expect_error(object = set_antimalarial_resistance(parameters = simparams, + parameters <- get_parameters() + parameters <- set_drugs(parameters = parameters, drugs = list(SP_AQ_params)) + parameters <- set_clinical_treatment(parameters = parameters, + drug = 1, + timesteps = 1, + coverages = 1) + expect_error(object = set_antimalarial_resistance(parameters = parameters, drug = 1, timesteps = c(1, 10), - artemisinin_resistance = 0.5, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0.5, - early_treatment_failure_prob = 0.6, - late_clinical_failure_prob = 0.2, - late_parasitological_prob = 0.3, - reinfection_prob = 0.4, + artemisinin_resistance_proportion = 0.5, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0.5, + early_treatment_failure_probability = 0.6, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, slow_parasite_clearance_time = 10)) }) test_that('set_antimalarial_resistance() errors if resistance proportions outside of range 0-1', { - simparams <- get_parameters() - simparams <- set_drugs(parameters = simparams, drugs = list(SP_AQ_params)) - simparams <- set_clinical_treatment(parameters = simparams, - drug = 1, - timesteps = 1, - coverages = 1) - expect_error(object = set_antimalarial_resistance(parameters = simparams, + parameters <- get_parameters() + parameters <- set_drugs(parameters = parameters, drugs = list(SP_AQ_params)) + parameters <- set_clinical_treatment(parameters = parameters, + drug = 1, + timesteps = 1, + coverages = 1) + expect_error(object = set_antimalarial_resistance(parameters = parameters, drug = 1, timesteps = 1, - artemisinin_resistance = 1.01, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0.5, - early_treatment_failure_prob = 0.6, - late_clinical_failure_prob = 0, - late_parasitological_prob = 0, - reinfection_prob = 0, + artemisinin_resistance_proportion = 1.01, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0.5, + early_treatment_failure_probability = 0.6, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, slow_parasite_clearance_time = 10), regexp = "Artemisinin and partner-drug resistance proportions must fall between 0 and 1") }) test_that('set_antimalarial_resistance() errors if resistance phenotype probabilities outside bound of 0-1', { - simparams <- get_parameters() - simparams <- set_drugs(parameters = simparams, drugs = list(SP_AQ_params)) - simparams <- set_clinical_treatment(parameters = simparams, - drug = 1, - timesteps = 1, - coverages = 1) - expect_error(object = set_antimalarial_resistance(parameters = simparams, + parameters <- get_parameters() + parameters <- set_drugs(parameters = parameters, drugs = list(SP_AQ_params)) + parameters <- set_clinical_treatment(parameters = parameters, + drug = 1, + timesteps = 1, + coverages = 1) + expect_error(object = set_antimalarial_resistance(parameters = parameters, drug = 1, timesteps = 1, - artemisinin_resistance = 0.4, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = -0.5, - early_treatment_failure_prob = 0.6, - late_clinical_failure_prob = 0.2, - late_parasitological_prob = 0.3, - reinfection_prob = 0.4, + artemisinin_resistance_proportion = 0.4, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = -0.5, + early_treatment_failure_probability = 0.6, + late_clinical_failure_probability = 0.2, + late_parasitological_failure_probability = 0.3, + reinfection_during_prophylaxis_probability = 0.4, slow_parasite_clearance_time = 5)) }) test_that('set_antimalarial_resistance() errors if drug index > than number of drugs assigned using set_drugs()', { - simparams <- get_parameters() - simparams <- set_drugs(parameters = simparams, drugs = list(SP_AQ_params)) - simparams <- set_clinical_treatment(parameters = simparams, - drug = 1, - timesteps = 1, - coverages = 1) - expect_error(object = set_antimalarial_resistance(parameters = simparams, + parameters <- get_parameters() + parameters <- set_drugs(parameters = parameters, drugs = list(SP_AQ_params)) + parameters <- set_clinical_treatment(parameters = parameters, + drug = 1, + timesteps = 1, + coverages = 1) + expect_error(object = set_antimalarial_resistance(parameters = parameters, drug = 2, timesteps = 1, - artemisinin_resistance = 0.4, - partner_drug_resistance = 0.3, - slow_parasite_clearance_prob = 0.5, - early_treatment_failure_prob = 0.6, - late_clinical_failure_prob = 0.2, - late_parasitological_prob = 0.3, - reinfection_prob = 0.4)) + artemisinin_resistance_proportion = 0.4, + partner_drug_resistance_proportion = 0.3, + slow_parasite_clearance_probability = 0.5, + early_treatment_failure_probability = 0.6, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0.4, + slow_parasite_clearance_time = 10)) }) test_that('set_antimalarial_resistance() assigns parameters correctly despite order in which resistance parameters are specified', { @@ -109,52 +110,52 @@ test_that('set_antimalarial_resistance() assigns parameters correctly despite or parameters <- set_antimalarial_resistance(parameters = parameters, drug = 2, timesteps = 1, - artemisinin_resistance = 0.5, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0.41, - early_treatment_failure_prob = 0.2, - late_clinical_failure_prob = 0, - late_parasitological_prob = 0, - reinfection_prob = 0, + artemisinin_resistance_proportion = 0.5, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0.41, + early_treatment_failure_probability = 0.2, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, slow_parasite_clearance_time = 5) parameters <- set_antimalarial_resistance(parameters = parameters, drug = 3, timesteps = 1, - artemisinin_resistance = 0, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0, - early_treatment_failure_prob = 0, - late_clinical_failure_prob = 0, - late_parasitological_prob = 0, - reinfection_prob = 0, + artemisinin_resistance_proportion = 0, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0, + early_treatment_failure_probability = 0, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, slow_parasite_clearance_time = 10) parameters <- set_antimalarial_resistance(parameters = parameters, drug = 1, timesteps = 1, - artemisinin_resistance = 0.27, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0.23, - early_treatment_failure_prob = 0.9, - late_clinical_failure_prob = 0, - late_parasitological_prob = 0, - reinfection_prob = 0, + artemisinin_resistance_proportion = 0.27, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0.23, + early_treatment_failure_probability = 0.9, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, slow_parasite_clearance_time = 20) expect_identical(parameters$antimalarial_resistance, TRUE) expect_identical(unlist(parameters$antimalarial_resistance_drug), c(2, 3, 1)) expect_identical(unlist(parameters$antimalarial_resistance_timesteps), rep(1, 3)) - expect_identical(unlist(parameters$prop_artemisinin_resistant), c(0.5, 0, 0.27)) - expect_identical(unlist(parameters$prop_partner_drug_resistant), c(0, 0, 0)) - expect_identical(unlist(parameters$slow_parasite_clearance_prob), c(0.41, 0, 0.23)) - expect_identical(unlist(parameters$early_treatment_failure_prob), c(0.2, 0, 0.9)) - expect_identical(unlist(parameters$late_clinical_failure_prob), c(0, 0, 0)) - expect_identical(unlist(parameters$late_parasitological_failure_prob), c(0, 0, 0)) - expect_identical(unlist(parameters$reinfection_during_prophylaxis), c(0, 0, 0)) + expect_identical(unlist(parameters$artemisinin_resistance_proportion), c(0.5, 0, 0.27)) + expect_identical(unlist(parameters$partner_drug_resistance_proportion), c(0, 0, 0)) + expect_identical(unlist(parameters$slow_parasite_clearance_probability), c(0.41, 0, 0.23)) + expect_identical(unlist(parameters$early_treatment_failure_probability), c(0.2, 0, 0.9)) + expect_identical(unlist(parameters$late_clinical_failure_probability), c(0, 0, 0)) + expect_identical(unlist(parameters$late_parasitological_failure_probability), c(0, 0, 0)) + expect_identical(unlist(parameters$reinfection_during_prophylaxis_probability), c(0, 0, 0)) expect_identical(unlist(parameters$dt_slow_parasite_clearance), c(5, 10, 20)) }) -test_that(desc = "set_antimalarial_resistance errors if length slow_parasite_clearance_time > 1", code = { +test_that("set_antimalarial_resistance errors if length slow_parasite_clearance_time > 1", { parameters <- get_parameters() parameters <- set_drugs(parameters = parameters, drugs = list(SP_AQ_params)) @@ -167,18 +168,18 @@ test_that(desc = "set_antimalarial_resistance errors if length slow_parasite_cle parameters <- set_antimalarial_resistance(parameters = parameters, drug = 1, timesteps = c(0, 10), - artemisinin_resistance = c(0.4, 0.8), - partner_drug_resistance = c(0, 0), - slow_parasite_clearance_prob = c(0.2, 0.4), - early_treatment_failure_prob = c(0, 0.45), - late_clinical_failure_prob = c(0, 0), - late_parasitological_prob = c(0, 0), - reinfection_prob = c(0, 0), + artemisinin_resistance_proportion = c(0.4, 0.8), + partner_drug_resistance_proportion = c(0, 0), + slow_parasite_clearance_probability = c(0.2, 0.4), + early_treatment_failure_probability = c(0, 0.45), + late_clinical_failure_probability = c(0, 0), + late_parasitological_failure_probability = c(0, 0), + reinfection_during_prophylaxis_probability = c(0, 0), slow_parasite_clearance_time = c(10 ,11)), "Error: length of slow_parasite_clearance_time not equal to 1") }) -test_that(desc = "set_antimalarial_resistance errors if slow_parasite_clearance_time not positive", code = { +test_that("set_antimalarial_resistance errors if slow_parasite_clearance_time not positive", { parameters <- get_parameters() parameters <- set_drugs(parameters = parameters, drugs = list(SP_AQ_params)) @@ -191,132 +192,132 @@ test_that(desc = "set_antimalarial_resistance errors if slow_parasite_clearance_ parameters <- set_antimalarial_resistance(parameters = parameters, drug = 1, timesteps = c(0, 10), - artemisinin_resistance = c(0.4, 0.8), - partner_drug_resistance = c(0, 0), - slow_parasite_clearance_prob = c(0.2, 0.4), - early_treatment_failure_prob = c(0, 0.45), - late_clinical_failure_prob = c(0, 0), - late_parasitological_prob = c(0, 0), - reinfection_prob = c(0, 0), + artemisinin_resistance_proportion = c(0.4, 0.8), + partner_drug_resistance_proportion = c(0, 0), + slow_parasite_clearance_probability = c(0.2, 0.4), + early_treatment_failure_probability = c(0, 0.45), + late_clinical_failure_probability = c(0, 0), + late_parasitological_failure_probability = c(0, 0), + reinfection_during_prophylaxis_probability = c(0, 0), slow_parasite_clearance_time = c(0)), "Error: slow_parasite_clearance_time is non-positive") }) test_that('get_antimalarial_resistance_parameters() correctly retrieves parameters when multiple drugs assigned', { - - get_parameters(overrides = list(human_population = 10000)) %>% - set_drugs(drugs = list(AL_params, SP_AQ_params, DHA_PQP_params)) %>% - set_clinical_treatment(drug = 1, timesteps = 1, coverages = 0.4) %>% - set_clinical_treatment(drug = 2, timesteps = 1, coverages = 0.3) %>% - set_clinical_treatment(drug = 3, timesteps = 1, coverages = 0.2) %>% - set_equilibrium(init_EIR = 20) %>% - set_antimalarial_resistance(drug = 2, - timesteps = c(0, 20), - artemisinin_resistance = c(0.02, 0.2), - partner_drug_resistance = c(0, 0), - slow_parasite_clearance_prob = c(0.02, 0.2), - early_treatment_failure_prob = c(0.02, 0.2), - late_clinical_failure_prob = c(0, 0), - late_parasitological_prob = c(0, 0), - reinfection_prob = c(0, 0), - slow_parasite_clearance_time = 20) %>% - set_antimalarial_resistance(drug = 1, - timesteps = c(0, 10), - artemisinin_resistance = c(0.01, 0.1), - partner_drug_resistance = c(0, 0), - slow_parasite_clearance_prob = c(0.01, 0.1), - early_treatment_failure_prob = c(0.01, 0.1), - late_clinical_failure_prob = c(0, 0), - late_parasitological_prob = c(0, 0), - reinfection_prob = c(0, 0), - slow_parasite_clearance_time = 10) %>% - set_antimalarial_resistance(drug = 3, - timesteps = c(0, 30), - artemisinin_resistance = c(0.03, 0.3), - partner_drug_resistance = c(0, 0), - slow_parasite_clearance_prob = c(0.03, 0.3), - early_treatment_failure_prob = c(0.03, 0.3), - late_clinical_failure_prob = c(0, 0), - late_parasitological_prob = c(0, 0), - reinfection_prob = c(0, 0), - slow_parasite_clearance_time = 30) -> parameters - - drugs <- c(1, 3, 2, 1, 2, 3, 3, 3, 2, 1, 3, 1, 2, 3, 2) - timestep <- 25 - - resistance_parameters <- get_antimalarial_resistance_parameters(parameters = parameters, - drugs = drugs, - timestep = timestep) - - expected_resistance_parameters <- list() - expected_resistance_parameters$artemisinin_resistance_proportion <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) - expected_resistance_parameters$partner_drug_resistance_proportion <- rep(0, 15) - expected_resistance_parameters$slow_parasite_clearance_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) - expected_resistance_parameters$early_treatment_failure_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) - expected_resistance_parameters$late_clinical_failure_probability <- rep(0, 15) - expected_resistance_parameters$late_parasitological_failure_probability <- rep(0, 15) - expected_resistance_parameters$reinfection_during_prophylaxis_probability <- rep(0, 15) - expected_resistance_parameters$dt_slow_parasite_clearance <- c(10, 30, 20, 10, 20, 30, 30, 30, 20, 10, 30, 10, 20, 30, 20) - - expect_identical(resistance_parameters, expected = expected_resistance_parameters) - - }) + + get_parameters(overrides = list(human_population = 10000)) |> + set_drugs(drugs = list(AL_params, SP_AQ_params, DHA_PQP_params)) |> + set_clinical_treatment(drug = 1, timesteps = 1, coverages = 0.4) |> + set_clinical_treatment(drug = 2, timesteps = 1, coverages = 0.3) |> + set_clinical_treatment(drug = 3, timesteps = 1, coverages = 0.2) |> + set_equilibrium(init_EIR = 20) |> + set_antimalarial_resistance(drug = 2, + timesteps = c(0, 20), + artemisinin_resistance_proportion = c(0.02, 0.2), + partner_drug_resistance_proportion = c(0, 0), + slow_parasite_clearance_probability = c(0.02, 0.2), + early_treatment_failure_probability = c(0.02, 0.2), + late_clinical_failure_probability = c(0, 0), + late_parasitological_failure_probability = c(0, 0), + reinfection_during_prophylaxis_probability = c(0, 0), + slow_parasite_clearance_time = 20) |> + set_antimalarial_resistance(drug = 1, + timesteps = c(0, 10), + artemisinin_resistance_proportion = c(0.01, 0.1), + partner_drug_resistance_proportion = c(0, 0), + slow_parasite_clearance_probability = c(0.01, 0.1), + early_treatment_failure_probability = c(0.01, 0.1), + late_clinical_failure_probability = c(0, 0), + late_parasitological_failure_probability = c(0, 0), + reinfection_during_prophylaxis_probability = c(0, 0), + slow_parasite_clearance_time = 10) |> + set_antimalarial_resistance(drug = 3, + timesteps = c(0, 30), + artemisinin_resistance_proportion = c(0.03, 0.3), + partner_drug_resistance_proportion = c(0, 0), + slow_parasite_clearance_probability = c(0.03, 0.3), + early_treatment_failure_probability = c(0.03, 0.3), + late_clinical_failure_probability = c(0, 0), + late_parasitological_failure_probability = c(0, 0), + reinfection_during_prophylaxis_probability = c(0, 0), + slow_parasite_clearance_time = 30) -> parameters + + drugs <- c(1, 3, 2, 1, 2, 3, 3, 3, 2, 1, 3, 1, 2, 3, 2) + timestep <- 25 + + resistance_parameters <- get_antimalarial_resistance_parameters(parameters = parameters, + drugs = drugs, + timestep = timestep) + + expected_resistance_parameters <- list() + expected_resistance_parameters$artemisinin_resistance_proportion <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) + expected_resistance_parameters$partner_drug_resistance_proportion <- rep(0, 15) + expected_resistance_parameters$slow_parasite_clearance_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) + expected_resistance_parameters$early_treatment_failure_probability <- c(0.1, 0.03, 0.2, 0.1, 0.2, 0.03, 0.03, 0.03, 0.2, 0.1, 0.03, 0.1, 0.2, 0.03, 0.2) + expected_resistance_parameters$late_clinical_failure_probability <- rep(0, 15) + expected_resistance_parameters$late_parasitological_failure_probability <- rep(0, 15) + expected_resistance_parameters$reinfection_during_prophylaxis_probability <- rep(0, 15) + expected_resistance_parameters$dt_slow_parasite_clearance <- c(10, 30, 20, 10, 20, 30, 30, 30, 20, 10, 30, 10, 20, 30, 20) + + expect_identical(resistance_parameters, expected = expected_resistance_parameters) + +}) test_that('get_antimalarial_resistance_parameters() correctly retrieves parameters when not all drugs assigned resistance', { - - get_parameters(overrides = list(human_population = 10000)) %>% - set_drugs(drugs = list(AL_params, SP_AQ_params, DHA_PQP_params)) %>% - set_clinical_treatment(drug = 1, timesteps = 1, coverages = 0.4) %>% - set_clinical_treatment(drug = 2, timesteps = 1, coverages = 0.3) %>% - set_clinical_treatment(drug = 3, timesteps = 1, coverages = 0.2) %>% - set_equilibrium(init_EIR = 20) %>% - set_antimalarial_resistance(drug = 2, - timesteps = c(0, 20), - artemisinin_resistance = c(0.02, 0.2), - partner_drug_resistance = c(0, 0), - slow_parasite_clearance_prob = c(0.02, 0.2), - early_treatment_failure_prob = c(0.02, 0.2), - late_clinical_failure_prob = c(0, 0), - late_parasitological_prob = c(0, 0), - reinfection_prob = c(0, 0), - slow_parasite_clearance_time = 20) -> parameters - - drugs <- c(1, 3, 2, 1, 2, 3, 3, 3, 2, 1, 3, 1, 2, 3, 2) - timestep <- 25 - - resistance_parameters <- get_antimalarial_resistance_parameters(parameters = parameters, - drugs = drugs, - timestep = timestep) - - expected_resistance_parameters <- list() - expected_resistance_parameters$artemisinin_resistance_proportion <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) - expected_resistance_parameters$partner_drug_resistance_proportion <- rep(0, 15) - expected_resistance_parameters$slow_parasite_clearance_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) - expected_resistance_parameters$early_treatment_failure_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) - expected_resistance_parameters$late_clinical_failure_probability <- rep(0, 15) - expected_resistance_parameters$late_parasitological_failure_probability <- rep(0, 15) - expected_resistance_parameters$reinfection_during_prophylaxis_probability <- rep(0, 15) - expected_resistance_parameters$dt_slow_parasite_clearance <- c(5, 5, 20, 5, 20, 5, 5, 5, 20, 5, 5, 5, 20, 5, 20) - - expect_identical(resistance_parameters, expected = expected_resistance_parameters) - - }) + + get_parameters(overrides = list(human_population = 10000)) %>% + set_drugs(drugs = list(AL_params, SP_AQ_params, DHA_PQP_params)) %>% + set_clinical_treatment(drug = 1, timesteps = 1, coverages = 0.4) %>% + set_clinical_treatment(drug = 2, timesteps = 1, coverages = 0.3) %>% + set_clinical_treatment(drug = 3, timesteps = 1, coverages = 0.2) %>% + set_equilibrium(init_EIR = 20) %>% + set_antimalarial_resistance(drug = 2, + timesteps = c(0, 20), + artemisinin_resistance_proportion = c(0.02, 0.2), + partner_drug_resistance_proportion = c(0, 0), + slow_parasite_clearance_probability = c(0.02, 0.2), + early_treatment_failure_probability = c(0.02, 0.2), + late_clinical_failure_probability = c(0, 0), + late_parasitological_failure_probability = c(0, 0), + reinfection_during_prophylaxis_probability = c(0, 0), + slow_parasite_clearance_time = 20) -> parameters + + drugs <- c(1, 3, 2, 1, 2, 3, 3, 3, 2, 1, 3, 1, 2, 3, 2) + timestep <- 25 + + resistance_parameters <- get_antimalarial_resistance_parameters(parameters = parameters, + drugs = drugs, + timestep = timestep) + + expected_resistance_parameters <- list() + expected_resistance_parameters$artemisinin_resistance_proportion <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) + expected_resistance_parameters$partner_drug_resistance_proportion <- rep(0, 15) + expected_resistance_parameters$slow_parasite_clearance_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) + expected_resistance_parameters$early_treatment_failure_probability <- c(0, 0, 0.2, 0, 0.2, 0, 0, 0, 0.2, 0, 0, 0, 0.2, 0, 0.2) + expected_resistance_parameters$late_clinical_failure_probability <- rep(0, 15) + expected_resistance_parameters$late_parasitological_failure_probability <- rep(0, 15) + expected_resistance_parameters$reinfection_during_prophylaxis_probability <- rep(0, 15) + expected_resistance_parameters$dt_slow_parasite_clearance <- c(5, 5, 20, 5, 20, 5, 5, 5, 20, 5, 5, 5, 20, 5, 20) + + expect_identical(resistance_parameters, expected = expected_resistance_parameters) + +}) test_that('get_antimalarial_resistance_parameters() returns an error when antimalarial resistance has not been parameterised', { - - get_parameters(overrides = list(human_population = 10000)) %>% - set_drugs(drugs = list(AL_params, SP_AQ_params, DHA_PQP_params)) %>% - set_clinical_treatment(drug = 1, timesteps = 1, coverages = 0.4) %>% - set_clinical_treatment(drug = 2, timesteps = 1, coverages = 0.3) %>% - set_clinical_treatment(drug = 3, timesteps = 1, coverages = 0.2) %>% - set_equilibrium(init_EIR = 20) -> parameters - - drugs <- c(1, 3, 2, 1, 2, 3, 3, 3, 2, 1, 3, 1, 2, 3, 2) - timestep <- 25 - - - expect_error(get_antimalarial_resistance_parameters(parameters = parameters, - drugs = drugs, - timestep = timestep), - "Error: Antimalarial resistance has not been parameterised; antimalarial_resistance = FALSE") -}) \ No newline at end of file + + get_parameters(overrides = list(human_population = 10000)) %>% + set_drugs(drugs = list(AL_params, SP_AQ_params, DHA_PQP_params)) %>% + set_clinical_treatment(drug = 1, timesteps = 1, coverages = 0.4) %>% + set_clinical_treatment(drug = 2, timesteps = 1, coverages = 0.3) %>% + set_clinical_treatment(drug = 3, timesteps = 1, coverages = 0.2) %>% + set_equilibrium(init_EIR = 20) -> parameters + + drugs <- c(1, 3, 2, 1, 2, 3, 3, 3, 2, 1, 3, 1, 2, 3, 2) + timestep <- 25 + + + expect_error(get_antimalarial_resistance_parameters(parameters = parameters, + drugs = drugs, + timestep = timestep), + "Error: Antimalarial resistance has not been parameterised; antimalarial_resistance = FALSE") +}) diff --git a/tests/testthat/test-infection-integration.R b/tests/testthat/test-infection-integration.R index 409cc466..2f05c463 100644 --- a/tests/testthat/test-infection-integration.R +++ b/tests/testthat/test-infection-integration.R @@ -6,7 +6,7 @@ test_that('simulate_infection integrates different types of infection and schedu )) events <- create_events(parameters) renderer <- mock_render(timestep) - + age <- c(20, 24, 5, 39, 20, 24, 5, 39) * 365 immunity <- c(.2, .3, .5, .9, .2, .3, .5, .9) asymptomatics <- mockery::mock() @@ -15,7 +15,7 @@ test_that('simulate_infection integrates different types of infection and schedu id = individual::DoubleVariable$new(immunity), state = list(get_index_of = mockery::mock(asymptomatics)) ) - + bitten <- individual::Bitset$new(population)$insert(c(1, 3, 5, 7)) boost_immunity_mock <- mockery::mock() infected <- individual::Bitset$new(population)$insert(c(1, 3, 5)) @@ -27,7 +27,7 @@ test_that('simulate_infection integrates different types of infection and schedu treated <- individual::Bitset$new(population)$insert(3) treated_mock <- mockery::mock(treated) schedule_mock <- mockery::mock() - + mockery::stub(simulate_infection, 'boost_immunity', boost_immunity_mock) mockery::stub(simulate_infection, 'calculate_infections', infection_mock) mockery::stub(simulate_infection, 'calculate_clinical_infections', clinical_infection_mock) @@ -45,7 +45,7 @@ test_that('simulate_infection integrates different types of infection and schedu timestep, renderer ) - + mockery::expect_args( boost_immunity_mock, 1, @@ -55,7 +55,7 @@ test_that('simulate_infection integrates different types of infection and schedu 5, parameters$ub ) - + mockery::expect_args( infection_mock, 1, @@ -65,7 +65,7 @@ test_that('simulate_infection integrates different types of infection and schedu renderer, timestep ) - + mockery::expect_args( clinical_infection_mock, 1, @@ -75,7 +75,7 @@ test_that('simulate_infection integrates different types of infection and schedu renderer, timestep ) - + mockery::expect_args( severe_infection_mock, 1, @@ -85,7 +85,7 @@ test_that('simulate_infection integrates different types of infection and schedu parameters, renderer ) - + mockery::expect_args( treated_mock, 1, @@ -95,7 +95,7 @@ test_that('simulate_infection integrates different types of infection and schedu timestep, renderer ) - + mockery::expect_args( schedule_mock, 1, @@ -125,7 +125,7 @@ test_that('calculate_infections works various combinations of drug and vaccinati booster_coverage = matrix(1), booster_profile = list(rtss_booster_profile) ) - + variables <- list( state = individual::CategoricalVariable$new( c('D', 'S', 'A', 'U', 'Tr'), @@ -137,7 +137,7 @@ test_that('calculate_infections works various combinations of drug and vaccinati pev_profile = individual::IntegerVariable$new(c(-1, 1, 2, -1)), ib = individual::DoubleVariable$new(c(.2, .3, .5, .9)) ) - + immunity_mock <- mockery::mock(c(.2, .3, .4)) weibull_mock <- mockery::mock(.2) vaccine_antibodies_mock <- mockery::mock(c(2, 3)) @@ -148,7 +148,7 @@ test_that('calculate_infections works various combinations of drug and vaccinati mockery::stub(calculate_infections, 'calculate_pev_antibodies', vaccine_antibodies_mock) mockery::stub(calculate_infections, 'calculate_pev_efficacy', vaccine_efficacy_mock) mockery::stub(calculate_infections, 'bernoulli_multi_p', bernoulli_mock) - + # remove randomness from vaccine parameters mockery::stub( calculate_infections, @@ -158,9 +158,9 @@ test_that('calculate_infections works various combinations of drug and vaccinati }, depth = 4 ) - + bitten_humans <- individual::Bitset$new(4)$insert(c(1, 2, 3, 4)) - + infections <- calculate_infections( variables, bitten_humans, @@ -168,9 +168,9 @@ test_that('calculate_infections works various combinations of drug and vaccinati mock_render(timestep), timestep ) - + expect_equal(infections$to_vector(), 3) - + mockery::expect_args(immunity_mock, 1, c(.3, .5, .9), parameters) mockery::expect_args( weibull_mock, @@ -179,7 +179,7 @@ test_that('calculate_infections works various combinations of drug and vaccinati parameters$drug_prophylaxis_shape[[2]], parameters$drug_prophylaxis_scale[[2]] ) - + mockery::expect_args( vaccine_antibodies_mock, 1, @@ -203,13 +203,13 @@ test_that('calculate_infections works various combinations of drug and vaccinati 1, c(.2 * .8 * .8, .3 * .7, .4) ) - + }) test_that('calculate_clinical_infections correctly samples clinically infected', { timestep <- 5 parameters <- get_parameters() - + variables <- list( ica = individual::DoubleVariable$new(c(.2, .3, .5, .9)), icm = individual::DoubleVariable$new(c(.2, .3, .5, .9)), @@ -217,25 +217,25 @@ test_that('calculate_clinical_infections correctly samples clinically infected', last_boosted_ica = individual::DoubleVariable$new(c(-1, -1, 1, -1)), last_boosted_id = individual::DoubleVariable$new(c(-1, -1, 1, -1)) ) - + immunity_mock <- mockery::mock(c(.2, .3, .4)) boost_mock <- mockery::mock() mockery::stub(calculate_clinical_infections, 'boost_immunity', boost_mock) - + mockery::stub(calculate_clinical_infections, 'clinical_immunity', immunity_mock) bernoulli_mock <- mockery::mock(c(1, 3)) mockery::stub(calculate_clinical_infections, 'bernoulli_multi_p', bernoulli_mock) - + infections <- individual::Bitset$new(4)$insert(c(2, 3, 4)) - + clinical_infections <- calculate_clinical_infections( variables, infections, parameters ) - + expect_equal(clinical_infections$to_vector(), c(2, 4)) - + mockery::expect_args( immunity_mock, 1, @@ -243,7 +243,7 @@ test_that('calculate_clinical_infections correctly samples clinically infected', c(.3, .5, .9), parameters ) - + mockery::expect_args( bernoulli_mock, 1, @@ -324,24 +324,24 @@ test_that('calculate_treated correctly samples treated and updates the drug stat parameters <- set_antimalarial_resistance(parameters = parameters, drug = 1, timesteps = 1, - artemisinin_resistance = 0.5, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0, - early_treatment_failure_prob = 0.2, - late_clinical_failure_prob = 0, - late_parasitological_prob = 0, - reinfection_prob = 0, + artemisinin_resistance_proportion = 0.5, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0, + early_treatment_failure_probability = 0.2, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, slow_parasite_clearance_time = 10) parameters <- set_antimalarial_resistance(parameters = parameters, drug = 2, timesteps = 1, - artemisinin_resistance = 0.3, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0, - early_treatment_failure_prob = 0.9, - late_clinical_failure_prob = 0, - late_parasitological_prob = 0, - reinfection_prob = 0, + artemisinin_resistance_proportion = 0.3, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0, + early_treatment_failure_probability = 0.9, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, slow_parasite_clearance_time = 15) clinical_infections <- individual::Bitset$new(20)$insert(1:20) @@ -410,13 +410,13 @@ test_that('calculate_treated correctly samples treated and updates the drug stat mockery::expect_args( bernoulli_mock, 2, - 1 - (unlist(parameters$prop_artemisinin_resistant[c(2, 1, 1, 1, 2, 2, 2, 1, 2)]) * unlist(parameters$early_treatment_failure_prob[c(2, 1, 1, 1, 2, 2, 2, 1, 2)])) + 1 - (unlist(parameters$artemisinin_resistance_proportion[c(2, 1, 1, 1, 2, 2, 2, 1, 2)]) * unlist(parameters$early_treatment_failure_probability[c(2, 1, 1, 1, 2, 2, 2, 1, 2)])) ) mockery::expect_args( bernoulli_mock, 3, - unlist(parameters$prop_artemisinin_resistant[c(2, 1, 1, 1, 2, 2, 2)]) * unlist(parameters$slow_parasite_clearance_prob[c(2, 1, 1, 1, 2, 2, 2)]) + unlist(parameters$artemisinin_resistance_proportion[c(2, 1, 1, 1, 2, 2, 2)]) * unlist(parameters$slow_parasite_clearance_probability[c(2, 1, 1, 1, 2, 2, 2)]) ) expect_bitset_update(variables$state$queue_update, 'Tr', c(1, 2, 3, 4, 5, 6, 7)) @@ -441,13 +441,13 @@ test_that('calculate_treated correctly samples treated and updates the drug stat parameters <- set_antimalarial_resistance(parameters = parameters, drug = 2, timesteps = 1, - artemisinin_resistance = 0.8, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0.2, - early_treatment_failure_prob = 0.3, - late_clinical_failure_prob = 0, - late_parasitological_prob = 0, - reinfection_prob = 0, + artemisinin_resistance_proportion = 0.8, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0.2, + early_treatment_failure_probability = 0.3, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, slow_parasite_clearance_time = 20) # Establish Bitset of clinically infected individuals @@ -586,17 +586,17 @@ test_that('calculate_treated correctly samples treated and updates the drug stat test_that('schedule_infections correctly schedules new infections', { parameters <- get_parameters(list(human_population = 20)) variables <- create_variables(parameters) - + infections <- individual::Bitset$new(20)$insert(1:20) clinical_infections <- individual::Bitset$new(20)$insert(5:15) treated <- individual::Bitset$new(20)$insert(7:12) - + infection_mock <- mockery::mock() asymp_mock <- mockery::mock() - + mockery::stub(schedule_infections, 'update_infection', infection_mock) mockery::stub(schedule_infections, 'update_to_asymptomatic_infection', asymp_mock) - + schedule_infections( variables, clinical_infections, @@ -605,15 +605,15 @@ test_that('schedule_infections correctly schedules new infections', { parameters, 42 ) - + actual_infected <- mockery::mock_args(infection_mock)[[1]][[5]]$to_vector() actual_asymp_infected <- mockery::mock_args(asymp_mock)[[1]][[4]]$to_vector() - + expect_equal( actual_infected, c(5, 6, 13, 14, 15) ) - + expect_equal( actual_asymp_infected, c(1, 2, 3, 4, 16, 17, 18, 19, 20) @@ -625,7 +625,7 @@ test_that('prophylaxis is considered for medicated humans', { parameters <- set_drugs(parameters, list(AL_params, DHA_PQP_params)) events <- create_events(parameters) timestep <- 50 - + variables = list( state = individual::CategoricalVariable$new( c('D', 'S', 'A', 'U', 'Tr'), @@ -637,11 +637,11 @@ test_that('prophylaxis is considered for medicated humans', { pev_profile = individual::IntegerVariable$new(c(-1, -1, -1, -1)), ib = individual::DoubleVariable$new(c(.2, .3, .5, .9)) ) - + bitten <- individual::Bitset$new(4)$insert(seq(4)) m <- mockery::mock(seq(3)) mockery::stub(calculate_infections, 'bernoulli_multi_p', m) - + calculate_infections( variables, bitten, @@ -649,7 +649,7 @@ test_that('prophylaxis is considered for medicated humans', { mock_render(timestep), timestep ) - + expect_equal( mockery::mock_args(m)[[1]][[1]], c(2.491951e-07, 2.384032e-01, 5.899334e-01), @@ -661,17 +661,17 @@ test_that('boost_immunity respects the delay period', { level <- c(2.4, 1.2, 0., 4.) immunity <- individual::DoubleVariable$new(level) last_boosted <- individual::DoubleVariable$new(c(11, 5, 1, 13)) - + level_mock <- mockery::mock() mockery::stub(boost_immunity, 'immunity_variable$queue_update', level_mock) - + last_mock <- mockery::mock() mockery::stub(boost_immunity, 'last_boosted_variable$queue_update', last_mock) - + index <- individual::Bitset$new(4)$insert(seq(4)) timestep <- 15 delay <- 4 - + boost_immunity( immunity, index, @@ -679,14 +679,14 @@ test_that('boost_immunity respects the delay period', { timestep, delay ) - + mockery::expect_args( level_mock, 1, c(3.4, 2.2, 1), seq(3) ) - + mockery::expect_args( last_mock, 1, @@ -699,18 +699,18 @@ test_that('boost_immunity respects the delay period', { level <- c(2.4, 1.2, 0., 4., 0.) immunity <- individual::DoubleVariable$new(level) last_boosted <- individual::DoubleVariable$new(c(11, 5, 1, 13, -1)) - + index <- individual::Bitset$new(5) index$insert(seq(5)) timestep <- 15 delay <- 4 - + level_mock <- mockery::mock() mockery::stub(boost_immunity, 'immunity_variable$queue_update', level_mock) - + last_mock <- mockery::mock() mockery::stub(boost_immunity, 'last_boosted_variable$queue_update', last_mock) - + boost_immunity( immunity, index, @@ -718,14 +718,14 @@ test_that('boost_immunity respects the delay period', { timestep, delay ) - + mockery::expect_args( level_mock, 1, c(3.4, 2.2, 1, 1), c(seq(3), 5) ) - + mockery::expect_args( last_mock, 1, @@ -738,18 +738,18 @@ test_that('boost_immunity does not update when there is no-one to update', { level <- c(2.4, 1.2, 0., 4., 0.) immunity <- individual::DoubleVariable$new(level) last_boosted <- individual::DoubleVariable$new(c(11, 5, 1, 13, -1)) - + index <- individual::Bitset$new(5) index$insert(seq(5)) timestep <- 15 delay <- 4 - + level_mock <- mockery::mock() mockery::stub(boost_immunity, 'immunity$queue_update', level_mock) - + last_mock <- mockery::mock() mockery::stub(boost_immunity, 'last_boosted$queue_update', last_mock) - + boost_immunity( immunity, index, @@ -771,11 +771,11 @@ test_that('update_severe_disease renders with no infections', { severe_incidence_rendering_max_ages = 5 * 365 )) variables <- create_variables(parameters) - + render_function <- mockery::mock() mockery::stub(update_severe_disease, 'incidence_renderer', render_function) empty <- individual::Bitset$new(population) - + update_severe_disease( timestep, empty, @@ -783,7 +783,7 @@ test_that('update_severe_disease renders with no infections', { parameters, renderer ) - + mockery::expect_args( render_function, 1, @@ -806,13 +806,13 @@ test_that('calculate_treated returns empty Bitset when there is no clinical trea parameters <- set_antimalarial_resistance(parameters = parameters, drug = 1, timesteps = 1, - artemisinin_resistance = 0.5, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0, - early_treatment_failure_prob = 0.2, - late_clinical_failure_prob = 0, - late_parasitological_prob = 0, - reinfection_prob = 0, + artemisinin_resistance_proportion = 0.5, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0, + early_treatment_failure_probability = 0.2, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, slow_parasite_clearance_time = 10) clinical_infections <- individual::Bitset$new(20)$insert(1:20) timestep <- 5 @@ -842,13 +842,13 @@ test_that('calculate_treated returns empty Bitset when the clinically_infected i parameters <- set_antimalarial_resistance(parameters = parameters, drug = 1, timesteps = 1, - artemisinin_resistance = 0.5, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0, - early_treatment_failure_prob = 0.2, - late_clinical_failure_prob = 0, - late_parasitological_prob = 0, - reinfection_prob = 0, + artemisinin_resistance_proportion = 0.5, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0, + early_treatment_failure_probability = 0.2, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, slow_parasite_clearance_time = 10) clinical_infections <- individual::Bitset$new(20) timestep <- 5 @@ -893,7 +893,7 @@ test_that('calculate_treated() returns an empty Bitset when the parameter list c expect_identical(object = treated$size(), expected = 0, info = "Error: calculate_treated() returning non-zero number of treated individuals in the absence of clinical treatment or resistance parameters") -}) + }) test_that('Number of treatment failures matches number of individuals treated when artemisinin resistance proportion and early treatment failure probability both set to 1', { @@ -912,24 +912,24 @@ test_that('Number of treatment failures matches number of individuals treated wh parameters <- set_antimalarial_resistance(parameters = parameters, drug = 1, timesteps = 1, - artemisinin_resistance = 1, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0, - early_treatment_failure_prob = 1, - late_clinical_failure_prob = 0, - late_parasitological_prob = 0, - reinfection_prob = 0, + artemisinin_resistance_proportion = 1, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0, + early_treatment_failure_probability = 1, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, slow_parasite_clearance_time = 10) parameters <- set_antimalarial_resistance(parameters = parameters, drug = 2, timesteps = 1, - artemisinin_resistance = 1, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0, - early_treatment_failure_prob = 1, - late_clinical_failure_prob = 0, - late_parasitological_prob = 0, - reinfection_prob = 0, + artemisinin_resistance_proportion = 1, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0, + early_treatment_failure_probability = 1, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, slow_parasite_clearance_time = 20) clinical_infections <- individual::Bitset$new(100) @@ -957,13 +957,13 @@ test_that('calculate_treated() successfully adds additional resistance columns t parameters <- set_antimalarial_resistance(parameters = parameters, drug = 1, timesteps = 1, - artemisinin_resistance = 0.5, - partner_drug_resistance = 0, - slow_parasite_clearance_prob = 0, - early_treatment_failure_prob = 0.5, - late_clinical_failure_prob = 0, - late_parasitological_prob = 0, - reinfection_prob = 0, + artemisinin_resistance_proportion = 0.5, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0, + early_treatment_failure_probability = 0.5, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, slow_parasite_clearance_time = 10) clinical_infections <- individual::Bitset$new(20)$insert(1:20) diff --git a/vignettes/Antimalarial_Resistance.Rmd b/vignettes/Antimalarial_Resistance.Rmd index 9c873202..9c529950 100644 --- a/vignettes/Antimalarial_Resistance.Rmd +++ b/vignettes/Antimalarial_Resistance.Rmd @@ -30,7 +30,7 @@ One of the major threats to the continued success of efforts to reduce the burde Resistance to the artemisinin component of an ACT can result either in slow parasite clearance (SPC), in which treatment with an ACT takes longer than 3 days to fully clear patients with resistant parasites, or early treatment failure (ETF), in which the ACT fails to clear the infection and the individual develops a clinical infection. Resistance to the partner drug, where the partner drug fails to clear the parasite after the artemisinin derivative is depleted, results in infections recrudescing to either clinical (D) or asymptomatic infections (A). Resistance to the partner drug can also result in individuals developing a novel, resistant infection following treatment, as the prophylaxis provided by the ACT fails to protect the individual against reinfection by a resistant strain. In the following vignette, we illustrate how to parameterise and run `malariasimulation` simulations with resistance to ACTs deployed as a clinical treatment ## Using set_antimalarial_resistance() to parameterise resistance -Simulations capturing the effects of resistance to clinical treatment using antimalarial drugs are parameterised using the `set_antimalarial_resistance()` function. This function appends user-defined resistance parameters to a `malariasimulation` parameter list and accepts ten inputs. The first is a list of `malariasimulation` parameters to append the resistance parameters to, and the second the index of the `drug` for which resistance is being parameterised, as set using the `set_drugs()` function. The `set_antimalarial_resistance()` function requires the `timesteps`, `artemisinin_resistance`, `partner_drug_resistance`, `slow_parasite_clearance_prob`, `early_treatment_failure_prob`, `late_clinical_failure_prob`, `late_parasitological_failure_prob`, and `reinfection_prob` inputs to be of equal length so that, for each time step in which an update occurs, a value is available for each parameter. Finally, the `slow_parasite_clearance_time` parameter represents the mean residence time, in days, for artemisinin-resistant individuals experiencing slow parasite clearance (SPC) in the Treated compartment, and must be input as a single, positive value. +Simulations capturing the effects of resistance to clinical treatment using antimalarial drugs are parameterised using the `set_antimalarial_resistance()` function. This function appends user-defined resistance parameters to a `malariasimulation` parameter list and accepts ten inputs. The first is a list of `malariasimulation` parameters to append the resistance parameters to, and the second the index of the `drug` for which resistance is being parameterised, as set using the `set_drugs()` function. The `set_antimalarial_resistance()` function requires the `timesteps`, `artemisinin_resistance_proportion`, `partner_drug_resistance_proportion_proportion`, `slow_parasite_clearance_probability`, `early_treatment_failure_probability`, `late_clinical_failure_probability`, `late_parasitological_failure_prob`, and `reinfection_during_prophylaxis_probability` inputs to be of equal length so that, for each time step in which an update occurs, a value is available for each parameter. Finally, the `slow_parasite_clearance_time` parameter represents the mean residence time, in days, for artemisinin-resistant individuals experiencing slow parasite clearance (SPC) in the Treated compartment, and must be input as a single, positive value. ## Simulating static resistance To illustrate how to parameterise resistance to an ACT using the `set_antimalarial_resistance()` function, we'll set-up and run three simulations. The first simulates malaria transmission in the absence of interventions or resistance. The second simulates a simple regime of clinical treatment in which 80% of clinical cases are treated with artemether lumefantrine (AL), beginning after one year, in the absence of antimalarial resistance. The third simulates the same clinical treatment programme but with resistance to the artemisinin component of AL emerging after two years. For illustrative purposes, we assume that the proportion of infections resistant to the artemisinin component of AL increases from 0% to 80%, and that these infections have a 90% chance of resulting in early treatment failure. @@ -74,13 +74,13 @@ simparams_clin_treatment <- set_clinical_treatment(parameters = simparams_clin_t simparams_resistance <- set_antimalarial_resistance(parameters = simparams_clin_treatment, drug = 1, timesteps = c(0, resistance_start), - artemisinin_resistance = c(0, 0.8), - partner_drug_resistance = rep(0, 2), - slow_parasite_clearance_prob = rep(0, 2), - early_treatment_failure_prob = c(0, 0.9), - late_clinical_failure_prob = rep(0, 2), - late_parasitological_prob = rep(0, 2), - reinfection_prob = rep(0, 2), + artemisinin_resistance_proportion = c(0, 0.8), + partner_drug_resistance_proportion = rep(0, 2), + slow_parasite_clearance_probability = rep(0, 2), + early_treatment_failure_probability = c(0, 0.9), + late_clinical_failure_probability = rep(0, 2), + late_parasitological_failure_probability = rep(0, 2), + reinfection_during_prophylaxis_probability = rep(0, 2), slow_parasite_clearance_time = 10) ``` @@ -195,13 +195,13 @@ simparams <- set_clinical_treatment(parameters = simparams, simparams <- set_antimalarial_resistance(parameters = simparams, drug = 1, timesteps = resistance_update_timesteps, - artemisinin_resistance = resistance_updates, - partner_drug_resistance = rep(0, length(resistance_update_timesteps)), - slow_parasite_clearance_prob = rep(0, length(resistance_update_timesteps)), - early_treatment_failure_prob = early_treatment_failure_updates, - late_clinical_failure_prob = rep(0, length(resistance_update_timesteps)), - late_parasitological_prob = rep(0, length(resistance_update_timesteps)), - reinfection_prob = rep(0, length(resistance_update_timesteps)), + artemisinin_resistance_proportion = resistance_updates, + partner_drug_resistance_proportion = rep(0, length(resistance_update_timesteps)), + slow_parasite_clearance_probability = rep(0, length(resistance_update_timesteps)), + early_treatment_failure_probability = early_treatment_failure_updates, + late_clinical_failure_probability = rep(0, length(resistance_update_timesteps)), + late_parasitological_failure_probability = rep(0, length(resistance_update_timesteps)), + reinfection_during_prophylaxis_probability = rep(0, length(resistance_update_timesteps)), slow_parasite_clearance_time = 10) # Calibrate the parameters to an initial EIR: @@ -290,39 +290,39 @@ simulation_parameters$base |> simulation_parameters$treatment |> set_antimalarial_resistance(drug = 1, timesteps = c(0, (365 * 3) + 1), - artemisinin_resistance = c(0, 0.8), - partner_drug_resistance = c(0, 0), - slow_parasite_clearance_prob = c(0, 0), - early_treatment_failure_prob = c(0, 0.8), - late_clinical_failure_prob = c(0, 0), - late_parasitological_prob = c(0, 0), - reinfection_prob = c(0, 0), + artemisinin_resistance_proportion = c(0, 0.8), + partner_drug_resistance_proportion = c(0, 0), + slow_parasite_clearance_probability = c(0, 0), + early_treatment_failure_probability = c(0, 0.8), + late_clinical_failure_probability = c(0, 0), + late_parasitological_failure_probability = c(0, 0), + reinfection_during_prophylaxis_probability = c(0, 0), slow_parasite_clearance_time = 10) -> simulation_parameters$etf # Establish a parameter list with clinical treatment and slow parasite clearance simulation_parameters$treatment |> set_antimalarial_resistance(drug = 1, timesteps = c(0, (365 * 3) + 1), - artemisinin_resistance = c(0, 0.8), - partner_drug_resistance = c(0, 0), - slow_parasite_clearance_prob = c(0, 0.8), - early_treatment_failure_prob = c(0, 0), - late_clinical_failure_prob = c(0, 0), - late_parasitological_prob = c(0, 0), - reinfection_prob = c(0, 0), + artemisinin_resistance_proportion = c(0, 0.8), + partner_drug_resistance_proportion = c(0, 0), + slow_parasite_clearance_probability = c(0, 0.8), + early_treatment_failure_probability = c(0, 0), + late_clinical_failure_probability = c(0, 0), + late_parasitological_failure_probability = c(0, 0), + reinfection_during_prophylaxis_probability = c(0, 0), slow_parasite_clearance_time = 10) -> simulation_parameters$spc # Establish a parameter list with clinical treatment, early treatment failure and slow parasite clearance: simulation_parameters$treatment |> set_antimalarial_resistance(drug = 1, timesteps = c(0, (365 * 3) + 1), - artemisinin_resistance = c(0, 0.8), - partner_drug_resistance = c(0, 0), - slow_parasite_clearance_prob = c(0, 0.8), - early_treatment_failure_prob = c(0, 0.8), - late_clinical_failure_prob = c(0, 0), - late_parasitological_prob = c(0, 0), - reinfection_prob = c(0, 0), + artemisinin_resistance_proportion = c(0, 0.8), + partner_drug_resistance_proportion = c(0, 0), + slow_parasite_clearance_probability = c(0, 0.8), + early_treatment_failure_probability = c(0, 0.8), + late_clinical_failure_probability = c(0, 0), + late_parasitological_failure_probability = c(0, 0), + reinfection_during_prophylaxis_probability = c(0, 0), slow_parasite_clearance_time = 10) -> simulation_parameters$etf_spc ``` @@ -360,7 +360,7 @@ for(i in seq(length(simulation_parameters))) { ### Visualisation -We can compare the effects of independent resistance outcomes with combined resistance outcomes visually. +We can compare the effects of independent resistance outcomes with combined resistance outcomes visually. In the following plot, we compare the *Pf*PR~2-10~ between a baseline without any clinical treatment or antimalarial resistance, a clinical-treatment only run, a clinical treatment with early treatment failure run, a clinical treatment with slow parasite clearance run, and a clinical treatment with both early treatment failure and slow parasite clearance run. ```{R} From d9ce4a68d1c88163ba487c9150199a856edb28e7 Mon Sep 17 00:00:00 2001 From: tbreweric Date: Thu, 11 Apr 2024 15:36:24 +0100 Subject: [PATCH 159/164] Implemented the changes recommended by in first round of PR comments --- R/disease_progression.R | 2 +- R/human_infection.R | 6 +- R/processes.R | 2 +- R/variables.R | 2 +- tests/testthat/test-infection-integration.R | 144 ++++++++++---------- vignettes/Antimalarial_Resistance.Rmd | 4 - 6 files changed, 78 insertions(+), 82 deletions(-) diff --git a/R/disease_progression.R b/R/disease_progression.R index e8b35874..455f79e0 100644 --- a/R/disease_progression.R +++ b/R/disease_progression.R @@ -33,7 +33,7 @@ create_progression_process <- function( # If the length of rate is greater than 1 (when it's a variable): if (length(rate) > 1) { - rate <- rate$get_values(index$to_vector()) + rate <- rate$get_values(index) } # Sample the individuals to be moved into a new Bitset using the transition rate(s): diff --git a/R/human_infection.R b/R/human_infection.R index 569757ef..d62b16f0 100644 --- a/R/human_infection.R +++ b/R/human_infection.R @@ -320,7 +320,7 @@ calculate_treated <- function( n_early_treatment_failure <- effectively_treated$size() - successfully_treated$size() renderer$render('n_early_treatment_failure', n_early_treatment_failure, timestep) drugs <- drugs[successfully_treated_indices] - resistance_parameters$dt_slow_parasite_clearance <- resistance_parameters$dt_slow_parasite_clearance[successfully_treated_indices] + dt_slow_parasite_clearance <- resistance_parameters$dt_slow_parasite_clearance[successfully_treated_indices] #+++ SLOW PARASITE CLEARANCE +++# #+++++++++++++++++++++++++++++++# @@ -331,7 +331,7 @@ calculate_treated <- function( renderer$render('n_slow_parasite_clearance', slow_parasite_clearance_individuals$size(), timestep) non_slow_parasite_clearance_individuals <- successfully_treated$copy()$set_difference(slow_parasite_clearance_individuals) renderer$render('n_successfully_treated', successfully_treated$size(), timestep) - resistance_parameters$dt_slow_parasite_clearance <- resistance_parameters$dt_slow_parasite_clearance[slow_parasite_clearance_indices] + dt_slow_parasite_clearance <- dt_slow_parasite_clearance[slow_parasite_clearance_indices] } else { @@ -360,7 +360,7 @@ calculate_treated <- function( non_slow_parasite_clearance_individuals ) variables$dt$queue_update( - resistance_parameters$dt_slow_parasite_clearance, + dt_slow_parasite_clearance, slow_parasite_clearance_individuals ) } diff --git a/R/processes.R b/R/processes.R index bbd7a754..5593a74d 100644 --- a/R/processes.R +++ b/R/processes.R @@ -118,7 +118,7 @@ create_processes <- function( dt_input <- parameters$dt # If antimalarial resistance is switched on, assign dt variable values to the - if(parameters$antimalarial_resistance == TRUE) { + if(parameters$antimalarial_resistance) { dt_input <- variables$dt } diff --git a/R/variables.R b/R/variables.R index 077a4f29..092a6431 100644 --- a/R/variables.R +++ b/R/variables.R @@ -231,7 +231,7 @@ create_variables <- function(parameters) { ) # Add variables for antimalarial resistance state residency times (dt) - if(parameters$antimalarial_resistance == TRUE) { + if(parameters$antimalarial_resistance) { dt <- individual::DoubleVariable$new(rep(parameters$dt, size)) variables <- c( variables, diff --git a/tests/testthat/test-infection-integration.R b/tests/testthat/test-infection-integration.R index 2f05c463..83d7def9 100644 --- a/tests/testthat/test-infection-integration.R +++ b/tests/testthat/test-infection-integration.R @@ -873,82 +873,82 @@ test_that('calculate_treated returns empty Bitset when the clinically_infected i test_that('calculate_treated() returns an empty Bitset when the parameter list contains no clinical treatment or resistance parameters', { - parameters <- get_parameters() - clinical_infections <- individual::Bitset$new(20)$insert(1:20) - timestep <- 5 - events <- create_events(parameters) - variables <- list( - state = list(queue_update = mockery::mock()), - infectivity = list(queue_update = mockery::mock()), - drug = list(queue_update = mockery::mock()), - drug_time = list(queue_update = mockery::mock()) - ) - renderer <- individual::Render$new(timesteps = 10) - - treated <- calculate_treated(variables = variables, - clinical_infections = clinical_infections, - parameters = parameters, - timestep = timestep, - renderer = renderer) - - expect_identical(object = treated$size(), expected = 0, info = "Error: calculate_treated() returning non-zero number of treated individuals + parameters <- get_parameters() + clinical_infections <- individual::Bitset$new(20)$insert(1:20) + timestep <- 5 + events <- create_events(parameters) + variables <- list( + state = list(queue_update = mockery::mock()), + infectivity = list(queue_update = mockery::mock()), + drug = list(queue_update = mockery::mock()), + drug_time = list(queue_update = mockery::mock()) + ) + renderer <- individual::Render$new(timesteps = 10) + + treated <- calculate_treated(variables = variables, + clinical_infections = clinical_infections, + parameters = parameters, + timestep = timestep, + renderer = renderer) + + expect_identical(object = treated$size(), expected = 0, info = "Error: calculate_treated() returning non-zero number of treated individuals in the absence of clinical treatment or resistance parameters") - }) +}) -test_that('Number of treatment failures matches number of individuals treated when artemisinin resistance proportion and - early treatment failure probability both set to 1', { - parameters <- get_parameters() - parameters <- set_drugs(parameters = parameters, drugs = list(AL_params, SP_AQ_params)) - parameters <- set_clinical_treatment(parameters = parameters, - drug = 1, - timesteps = 1, - coverages = round(runif(1, 0, 1/2), - digits = 2)) - parameters <- set_clinical_treatment(parameters = parameters, - drug = 2, - timesteps = 1, - coverages = round(runif(1, 0, 1/2), - digits = 2)) - parameters <- set_antimalarial_resistance(parameters = parameters, - drug = 1, - timesteps = 1, - artemisinin_resistance_proportion = 1, - partner_drug_resistance_proportion = 0, - slow_parasite_clearance_probability = 0, - early_treatment_failure_probability = 1, - late_clinical_failure_probability = 0, - late_parasitological_failure_probability = 0, - reinfection_during_prophylaxis_probability = 0, - slow_parasite_clearance_time = 10) - parameters <- set_antimalarial_resistance(parameters = parameters, - drug = 2, - timesteps = 1, - artemisinin_resistance_proportion = 1, - partner_drug_resistance_proportion = 0, - slow_parasite_clearance_probability = 0, - early_treatment_failure_probability = 1, - late_clinical_failure_probability = 0, - late_parasitological_failure_probability = 0, - reinfection_during_prophylaxis_probability = 0, - slow_parasite_clearance_time = 20) - - clinical_infections <- individual::Bitset$new(100) - clinical_infections$insert(sample.int(n = 100, size = round(runif(n = 1, min = 10, max = 100)), replace = FALSE)) - timestep <- 5 - events <- create_events(parameters) - variables <- create_variables(parameters = parameters) - renderer <- individual::Render$new(timesteps = 10) - - treated <- calculate_treated(variables = variables, - clinical_infections = clinical_infections, - parameters = parameters, - timestep = timestep, - renderer = renderer) - - expect_identical(renderer$to_dataframe()[timestep,'n_early_treatment_failure'], renderer$to_dataframe()[timestep,'n_treated'] - renderer$to_dataframe()[timestep,'n_drug_efficacy_failures'], info = "Error: Number of +test_that('Number of treatment failures matches number of individuals treated when artemisinin resistance + proportion and early treatment failure probability both set to 1', { + parameters <- get_parameters() + parameters <- set_drugs(parameters = parameters, drugs = list(AL_params, SP_AQ_params)) + parameters <- set_clinical_treatment(parameters = parameters, + drug = 1, + timesteps = 1, + coverages = round(runif(1, 0, 1/2), + digits = 2)) + parameters <- set_clinical_treatment(parameters = parameters, + drug = 2, + timesteps = 1, + coverages = round(runif(1, 0, 1/2), + digits = 2)) + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 1, + timesteps = 1, + artemisinin_resistance_proportion = 1, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0, + early_treatment_failure_probability = 1, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, + slow_parasite_clearance_time = 10) + parameters <- set_antimalarial_resistance(parameters = parameters, + drug = 2, + timesteps = 1, + artemisinin_resistance_proportion = 1, + partner_drug_resistance_proportion = 0, + slow_parasite_clearance_probability = 0, + early_treatment_failure_probability = 1, + late_clinical_failure_probability = 0, + late_parasitological_failure_probability = 0, + reinfection_during_prophylaxis_probability = 0, + slow_parasite_clearance_time = 20) + + clinical_infections <- individual::Bitset$new(100) + clinical_infections$insert(sample.int(n = 100, size = round(runif(n = 1, min = 10, max = 100)), replace = FALSE)) + timestep <- 5 + events <- create_events(parameters) + variables <- create_variables(parameters = parameters) + renderer <- individual::Render$new(timesteps = 10) + + treated <- calculate_treated(variables = variables, + clinical_infections = clinical_infections, + parameters = parameters, + timestep = timestep, + renderer = renderer) + + expect_identical(renderer$to_dataframe()[timestep,'n_early_treatment_failure'], renderer$to_dataframe()[timestep,'n_treated'] - renderer$to_dataframe()[timestep,'n_drug_efficacy_failures'], info = "Error: Number of early treatment failures does not match number of treated individuals (minus drug efficacy failures) when artemisinin resistance proportion and and early treatment failure probability both equal 1") - }) +}) test_that('calculate_treated() successfully adds additional resistance columns to the renderer', { parameters <- get_parameters() diff --git a/vignettes/Antimalarial_Resistance.Rmd b/vignettes/Antimalarial_Resistance.Rmd index 9c529950..5b6acd40 100644 --- a/vignettes/Antimalarial_Resistance.Rmd +++ b/vignettes/Antimalarial_Resistance.Rmd @@ -354,10 +354,6 @@ for(i in seq(length(simulation_parameters))) { ``` -### Data Wranging - - - ### Visualisation We can compare the effects of independent resistance outcomes with combined resistance outcomes visually. In the following plot, we compare the *Pf*PR~2-10~ between a baseline without any clinical treatment or antimalarial resistance, a clinical-treatment only run, a clinical treatment with early treatment failure run, a clinical treatment with slow parasite clearance run, and a clinical treatment with both early treatment failure and slow parasite clearance run. From f58d48f7283a25616440e788583ebfadc5ef52b2 Mon Sep 17 00:00:00 2001 From: tbreweric Date: Thu, 18 Apr 2024 22:10:46 +0100 Subject: [PATCH 160/164] Altered check for rate data type in create_disease_progression() function --- R/disease_progression.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/disease_progression.R b/R/disease_progression.R index 455f79e0..d9ac11e4 100644 --- a/R/disease_progression.R +++ b/R/disease_progression.R @@ -32,7 +32,7 @@ create_progression_process <- function( index <- state$get_index_of(from_state) # If the length of rate is greater than 1 (when it's a variable): - if (length(rate) > 1) { + if (inherits(rate, "DoubleVariable")) { rate <- rate$get_values(index) } From e9d46e7ade47dd9b25e1d68d20c656d14294689e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Li=C3=A9tar?= Date: Thu, 25 Apr 2024 16:13:30 +0100 Subject: [PATCH 161/164] Update description of the dt parameter. (#288) The dt parameter was described as "the delay to move from state Tr to Ph", but the Ph (prophylaxis) state does not exist in the model. Instead the dt parameter is used to transition from Tr to S, in `R/processes.R`. Looking at the commit history, there seems to have been a bit of back and forth around adding and removing the Tr and Ph states. The comment in question was introduced in mrc-ide/malariasimulation#30, after the prophylaxis state had already been removed and even at the time the parameter was already used as the transition rate from Tr to S. --- R/parameters.R | 2 +- man/get_parameters.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/parameters.R b/R/parameters.R index 473225fa..12f4c4be 100644 --- a/R/parameters.R +++ b/R/parameters.R @@ -11,7 +11,7 @@ #' fixed state transitions: #' #' * dd - the delay for humans to move from state D to A; default = 5 -#' * dt - the delay for humans to move from state Tr to Ph; default = 5 +#' * dt - the delay for humans to move from state Tr to S; default = 5 #' * da - the delay for humans to move from state A to U; default = 195 #' * du - the delay for humans to move from state U to S; default = 110 #' * del - the delay for mosquitoes to move from state E to L; default = 6.64 diff --git a/man/get_parameters.Rd b/man/get_parameters.Rd index 1a0dde29..8afae241 100644 --- a/man/get_parameters.Rd +++ b/man/get_parameters.Rd @@ -13,7 +13,7 @@ The parameters are defined below. fixed state transitions: \itemize{ \item dd - the delay for humans to move from state D to A; default = 5 -\item dt - the delay for humans to move from state Tr to Ph; default = 5 +\item dt - the delay for humans to move from state Tr to S; default = 5 \item da - the delay for humans to move from state A to U; default = 195 \item du - the delay for humans to move from state U to S; default = 110 \item del - the delay for mosquitoes to move from state E to L; default = 6.64 From 9debd7f2b95f109adcb0163803bccb742ecec117 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Li=C3=A9tar?= Date: Fri, 26 Apr 2024 14:05:32 +0100 Subject: [PATCH 162/164] Clarify some intervention parametrization documentation. (#291) The `set_tbv` function was located at the bottom of `pev_parameters.R`, which was confusing and unintuitive. I believe this was a remnant of a time when that file was named `vaccine_parameters.R`. It is now moved to its own file, named `tbv_parameters.R`. This matches the general naming convention used by all other interventions. The ages parameter of `set_tbv` was previously described as being "per-round", which might hint at it being, eg. a list of age ranges with one entry per round. This did not match the implementation, which uses the same whole `tbv_ages` parameter for every round. I don't how useful being able to pass in a non-contiguous set of ages is. In the future it might be clearer to change the TBV intervention to use `min_ages` and `max_ages`, the same way other mass-event interventions (MDA, SMC and mass-PEV) are implementated. This will make it easy to actually have varying age ranges for each round, if desired. This also adds a check in `set_tbv` for the length of coverages to ensure it matches the timesteps, the same way it is done in other interventions. The documentation for the `timesteps` and `coverages` parameters of the `set_pmc` method made mentions of rounds, implying that the intervention only takes place at the given timesteps, when it is in fact a perennial age-based intervention that may happen at any timestep. The timesteps parameter is only used to vary the coverage over time. Finally, there were a pair of lost words in the documentation of `set_tbv` and `set_mda` from successive code refactors, which have now been removed. --- R/mda_parameters.R | 7 +++---- R/pev_parameters.R | 23 +---------------------- R/tbv_parameters.R | 23 +++++++++++++++++++++++ man/CorrelationParameters.Rd | 6 ++++-- man/set_mda.Rd | 3 +-- man/set_pev_epi.Rd | 2 +- man/set_pmc.Rd | 6 +++--- man/set_tbv.Rd | 5 ++--- tests/testthat/test-tbv.R | 11 +++++++++++ 9 files changed, 49 insertions(+), 37 deletions(-) create mode 100644 R/tbv_parameters.R diff --git a/R/mda_parameters.R b/R/mda_parameters.R index a07d7e70..f84b86e1 100644 --- a/R/mda_parameters.R +++ b/R/mda_parameters.R @@ -6,7 +6,6 @@ #' round #' @param min_ages a vector of minimum ages of the target population for each round exclusive (in timesteps) #' @param max_ages a vector of maximum ages of the target population for each round exclusive (in timesteps) -#' drug #' @export set_mda <- function( parameters, @@ -77,9 +76,9 @@ set_smc <- function( #' @title Parameterise a perennial malaria chemoprevention (PMC, formerly IPIi) #' @param parameters a list of parameters to modify #' @param drug the index of the drug to administer -#' @param timesteps a vector of timesteps for each round of PMC -#' @param coverages a vector of the proportion of the target population who receive each -#' round +#' @param timesteps a vector of timesteps for each change in coverage +#' @param coverages a vector of proportions of the target population to receive +#' the intervention #' @param ages a vector of ages at which PMC is administered (in timesteps) #' @export set_pmc <- function( diff --git a/R/pev_parameters.R b/R/pev_parameters.R index 7edcb39c..a9509f96 100644 --- a/R/pev_parameters.R +++ b/R/pev_parameters.R @@ -64,7 +64,7 @@ rtss_booster_profile <- create_pev_profile( #' @param parameters a list of parameters to modify #' @param profile a list of details for the vaccine profile, create with `create_pev_profile` #' @param coverages a vector of coverages for the primary doses -#' @param timesteps a vector of timesteps associated with coverages +#' @param timesteps a vector of timesteps for each change in coverage #' @param age the age when an individual will receive the first dose of the #' vaccine (in timesteps) #' @param min_wait the minimum acceptable time since the last vaccination (in @@ -221,24 +221,3 @@ set_mass_pev <- function( parameters$mass_pev_profile_indices <- profile_indices parameters } - -#' @title Parameterise an TBV strategy -#' @param parameters a list of parameters to modify -#' @param timesteps a vector of timesteps for each round of vaccinations -#' @param coverages the coverage for each round of vaccinations -#' @param ages for each round (in years) -#' vaccine -#' @export -set_tbv <- function( - parameters, - timesteps, - coverages, - ages - ) { - stopifnot(all(coverages >= 0) && all(coverages <= 1)) - parameters$tbv <- TRUE - parameters$tbv_timesteps <- timesteps - parameters$tbv_coverages <- coverages - parameters$tbv_ages <- ages - parameters -} diff --git a/R/tbv_parameters.R b/R/tbv_parameters.R new file mode 100644 index 00000000..089455a2 --- /dev/null +++ b/R/tbv_parameters.R @@ -0,0 +1,23 @@ +#' @title Parameterise an TBV strategy +#' @param parameters a list of parameters to modify +#' @param timesteps a vector of timesteps for each round of vaccinations +#' @param coverages the coverage for each round of vaccinations +#' @param ages a vector of ages of the target population (in years) +#' @export +set_tbv <- function( + parameters, + timesteps, + coverages, + ages + ) { + stopifnot(all(coverages >= 0) && all(coverages <= 1)) + if(length(coverages) != length(timesteps)){ + stop("coverages and timesteps do no align") + } + + parameters$tbv <- TRUE + parameters$tbv_timesteps <- timesteps + parameters$tbv_coverages <- coverages + parameters$tbv_ages <- ages + parameters +} diff --git a/man/CorrelationParameters.Rd b/man/CorrelationParameters.Rd index 480d663d..2898aee5 100644 --- a/man/CorrelationParameters.Rd +++ b/man/CorrelationParameters.Rd @@ -30,13 +30,15 @@ Describes an event in the simulation \subsection{Method \code{new()}}{ initialise correlation parameters \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{CorrelationParameters$new(parameters)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{CorrelationParameters$new(population, interventions)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ -\item{\code{parameters}}{model parameters} +\item{\code{population}}{popularion size} + +\item{\code{interventions}}{character vector with the name of enabled interventions} } \if{html}{\out{
}} } diff --git a/man/set_mda.Rd b/man/set_mda.Rd index 0b6f81c0..5437faeb 100644 --- a/man/set_mda.Rd +++ b/man/set_mda.Rd @@ -18,8 +18,7 @@ round} \item{min_ages}{a vector of minimum ages of the target population for each round exclusive (in timesteps)} -\item{max_ages}{a vector of maximum ages of the target population for each round exclusive (in timesteps) -drug} +\item{max_ages}{a vector of maximum ages of the target population for each round exclusive (in timesteps)} } \description{ Parameterise a Mass Drug Administration diff --git a/man/set_pev_epi.Rd b/man/set_pev_epi.Rd index a3a4d195..077811c3 100644 --- a/man/set_pev_epi.Rd +++ b/man/set_pev_epi.Rd @@ -24,7 +24,7 @@ set_pev_epi( \item{coverages}{a vector of coverages for the primary doses} -\item{timesteps}{a vector of timesteps associated with coverages} +\item{timesteps}{a vector of timesteps for each change in coverage} \item{age}{the age when an individual will receive the first dose of the vaccine (in timesteps)} diff --git a/man/set_pmc.Rd b/man/set_pmc.Rd index 62625c04..2985e29a 100644 --- a/man/set_pmc.Rd +++ b/man/set_pmc.Rd @@ -11,10 +11,10 @@ set_pmc(parameters, drug, timesteps, coverages, ages) \item{drug}{the index of the drug to administer} -\item{timesteps}{a vector of timesteps for each round of PMC} +\item{timesteps}{a vector of timesteps for each change in coverage} -\item{coverages}{a vector of the proportion of the target population who receive each -round} +\item{coverages}{a vector of proportions of the target population to receive +the intervention} \item{ages}{a vector of ages at which PMC is administered (in timesteps)} } diff --git a/man/set_tbv.Rd b/man/set_tbv.Rd index 34a641aa..23149e6d 100644 --- a/man/set_tbv.Rd +++ b/man/set_tbv.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/pev_parameters.R +% Please edit documentation in R/tbv_parameters.R \name{set_tbv} \alias{set_tbv} \title{Parameterise an TBV strategy} @@ -13,8 +13,7 @@ set_tbv(parameters, timesteps, coverages, ages) \item{coverages}{the coverage for each round of vaccinations} -\item{ages}{for each round (in years) -vaccine} +\item{ages}{a vector of ages of the target population (in years)} } \description{ Parameterise an TBV strategy diff --git a/tests/testthat/test-tbv.R b/tests/testthat/test-tbv.R index 0e4451a1..e8af946e 100644 --- a/tests/testthat/test-tbv.R +++ b/tests/testthat/test-tbv.R @@ -1,3 +1,14 @@ +test_that('TBV checks arguments', { + parameters <- get_parameters() + expect_error( + parameters <- set_tbv( + parameters, + timesteps = c(50, 150), + coverages = 1, + ages = 5:60 + ), "coverages and timesteps do no align") +}) + test_that('TBV strategy parameterisation works', { parameters <- get_parameters() parameters <- set_tbv( From e534db7e9903b5b64d07d6a77d956def875c509d Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Tue, 13 Feb 2024 17:26:26 +0000 Subject: [PATCH 163/164] Allow simulation to be restored with new interventions. (#286) This uses a few of individual's new features that make restoring more flexible. It also fixes a bug when restoring the mosquitto solvers, by correctly restoring the timestep, which is needed to model seasonality. The intervention events use the new `restore = FALSE` flag to make sure their schedule can be modified when resuming. Instead of having the events re-schedule themselves everytime they fire, we setup the entire schedule upfront when initialising the simulation. It adds end-to-end testing of this feature, across a range of scenarios. For each scenario, the outcomes of the simulation with and without restoring are compared and we make sure they are equivalent. --- DESCRIPTION | 2 +- R/RcppExports.R | 4 +- R/compartmental.R | 8 +- R/correlation.R | 9 +- R/events.R | 18 ++-- R/lag.R | 2 +- R/mda_processes.R | 7 -- R/model.R | 17 ++-- R/pev.R | 5 - R/stateful.R | 47 ---------- R/tbv.R | 5 - R/utils.R | 24 +++++ man/CorrelationParameters.Rd | 7 +- src/RcppExports.cpp | 9 +- src/solver.cpp | 3 +- tests/testthat/test-mda.R | 15 --- tests/testthat/test-pev.R | 7 -- tests/testthat/test-resume.R | 174 +++++++++++++++++++++++++++++------ 18 files changed, 217 insertions(+), 146 deletions(-) delete mode 100644 R/stateful.R diff --git a/DESCRIPTION b/DESCRIPTION index 76eb8165..74445497 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -72,7 +72,7 @@ Remotes: Additional_repositories: https://mrc-ide.r-universe.dev Imports: - individual (>= 0.1.15), + individual (>= 0.1.16), malariaEquilibrium (>= 1.0.1), Rcpp, statmod, diff --git a/R/RcppExports.R b/R/RcppExports.R index 678a50bf..ad658f2c 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -53,8 +53,8 @@ solver_get_states <- function(solver) { .Call(`_malariasimulation_solver_get_states`, solver) } -solver_set_states <- function(solver, state) { - invisible(.Call(`_malariasimulation_solver_set_states`, solver, state)) +solver_set_states <- function(solver, t, state) { + invisible(.Call(`_malariasimulation_solver_set_states`, solver, t, state)) } solver_step <- function(solver) { diff --git a/R/compartmental.R b/R/compartmental.R index 7df83a6e..4e16c7c1 100644 --- a/R/compartmental.R +++ b/R/compartmental.R @@ -155,8 +155,8 @@ Solver <- R6::R6Class( save_state = function() { solver_get_states(private$.solver) }, - restore_state = function(state) { - solver_set_states(private$.solver, state) + restore_state = function(t, state) { + solver_set_states(private$.solver, t, state) } ) ) @@ -173,7 +173,7 @@ AquaticMosquitoModel <- R6::R6Class( # state of the ODE is stored separately). We still provide these methods to # conform to the expected interface. save_state = function() { NULL }, - restore_state = function(state) { } + restore_state = function(t, state) { } ) ) @@ -187,7 +187,7 @@ AdultMosquitoModel <- R6::R6Class( save_state = function() { adult_mosquito_model_save_state(self$.model) }, - restore_state = function(state) { + restore_state = function(t, state) { adult_mosquito_model_restore_state(self$.model, state) } ) diff --git a/R/correlation.R b/R/correlation.R index 458a3015..2a59fdbc 100644 --- a/R/correlation.R +++ b/R/correlation.R @@ -125,11 +125,16 @@ CorrelationParameters <- R6::R6Class( }, #' @description Restore the correlation state. + #' #' Only the randomly drawn weights are restored. The object needs to be #' initialized with the same rhos. + #' + #' @param timestep the timestep at which simulation is resumed. This + #' parameter's value is ignored, it only exists to conform to a uniform + #' interface. #' @param state a previously saved correlation state, as returned by the - #' save_state method. - restore_state = function(state) { + #' save_state method. + restore_state = function(timestep, state) { private$.mvnorm <- state$mvnorm } ) diff --git a/R/events.R b/R/events.R index d7ad3416..de0c7c1f 100644 --- a/R/events.R +++ b/R/events.R @@ -1,11 +1,11 @@ create_events <- function(parameters) { events <- list( # MDA events - mda_administer = individual::Event$new(), - smc_administer = individual::Event$new(), + mda_administer = individual::Event$new(restore=FALSE), + smc_administer = individual::Event$new(restore=FALSE), # TBV event - tbv_vaccination = individual::Event$new(), + tbv_vaccination = individual::Event$new(restore=FALSE), # Bednet events throw_away_net = individual::TargetedEvent$new(parameters$human_population) @@ -21,7 +21,7 @@ create_events <- function(parameters) { seq_along(parameters$mass_pev_booster_spacing), function(.) individual::TargetedEvent$new(parameters$human_population) ) - events$mass_pev <- individual::Event$new() + events$mass_pev <- individual::Event$new(restore=FALSE) events$mass_pev_doses <- mass_pev_doses events$mass_pev_boosters <- mass_pev_boosters } @@ -63,16 +63,16 @@ initialise_events <- function(events, variables, parameters) { # Initialise scheduled interventions if (!is.null(parameters$mass_pev_timesteps)) { - events$mass_pev$schedule(parameters$mass_pev_timesteps[[1]] - 1) + events$mass_pev$schedule(parameters$mass_pev_timesteps - 1) } if (parameters$mda) { - events$mda_administer$schedule(parameters$mda_timesteps[[1]] - 1) + events$mda_administer$schedule(parameters$mda_timesteps - 1) } if (parameters$smc) { - events$smc_administer$schedule(parameters$smc_timesteps[[1]] - 1) + events$smc_administer$schedule(parameters$smc_timesteps - 1) } if (parameters$tbv) { - events$tbv_vaccination$schedule(parameters$tbv_timesteps[[1]] - 1) + events$tbv_vaccination$schedule(parameters$tbv_timesteps - 1) } } @@ -158,7 +158,6 @@ attach_event_listeners <- function( if (parameters$mda == 1) { events$mda_administer$add_listener(create_mda_listeners( variables, - events$mda_administer, parameters$mda_drug, parameters$mda_timesteps, parameters$mda_coverages, @@ -174,7 +173,6 @@ attach_event_listeners <- function( if (parameters$smc == 1) { events$smc_administer$add_listener(create_mda_listeners( variables, - events$smc_administer, parameters$smc_drug, parameters$smc_timesteps, parameters$smc_coverages, diff --git a/R/lag.R b/R/lag.R index ca858ac7..de8d1653 100644 --- a/R/lag.R +++ b/R/lag.R @@ -20,7 +20,7 @@ LaggedValue <- R6::R6Class( timeseries_save_state(private$history) }, - restore_state = function(state) { + restore_state = function(t, state) { timeseries_restore_state(private$history, state) } ) diff --git a/R/mda_processes.R b/R/mda_processes.R index 42960be4..72cbe779 100644 --- a/R/mda_processes.R +++ b/R/mda_processes.R @@ -1,6 +1,5 @@ #' @title Create listeners for MDA events #' @param variables the variables available in the model -#' @param administer_event the event schedule for drug administration #' @param drug the drug to administer #' @param timesteps timesteps for each round #' @param coverages the coverage for each round @@ -14,7 +13,6 @@ #' @noRd create_mda_listeners <- function( variables, - administer_event, drug, timesteps, coverages, @@ -78,11 +76,6 @@ create_mda_listeners <- function( variables$drug$queue_update(drug, to_move) variables$drug_time$queue_update(timestep, to_move) } - - # Schedule next round - if (time_index < length(timesteps)) { - administer_event$schedule(timesteps[[time_index + 1]] - timestep) - } } } diff --git a/R/model.R b/R/model.R index def6db23..67f79758 100644 --- a/R/model.R +++ b/R/model.R @@ -135,16 +135,19 @@ run_resumable_simulation <- function( lagged_eir <- create_lagged_eir(variables, solvers, parameters) lagged_infectivity <- create_lagged_infectivity(variables, parameters) - stateful_objects <- unlist(list( + stateful_objects <- list( RandomState$new(restore_random_state), correlations, vector_models, solvers, lagged_eir, - lagged_infectivity)) + lagged_infectivity) if (!is.null(initial_state)) { - restore_state(initial_state$malariasimulation, stateful_objects) + individual::restore_object_state( + initial_state$timesteps, + stateful_objects, + initial_state$malariasimulation) } individual_state <- individual::simulation_loop( @@ -161,16 +164,16 @@ run_resumable_simulation <- function( timesteps ), variables = variables, - events = unlist(events), + events = events, timesteps = timesteps, state = initial_state$individual, restore_random_state = restore_random_state ) final_state <- list( - timesteps=timesteps, - individual=individual_state, - malariasimulation=save_state(stateful_objects) + timesteps = timesteps, + individual = individual_state, + malariasimulation = individual::save_object_state(stateful_objects) ) data <- renderer$to_dataframe() diff --git a/R/pev.R b/R/pev.R index bc27fc9f..e460e5c3 100644 --- a/R/pev.R +++ b/R/pev.R @@ -130,11 +130,6 @@ create_mass_pev_listener <- function( parameters, events$mass_pev_doses ) - if (time_index < length(parameters$mass_pev_timesteps)) { - events$mass_pev$schedule( - parameters$mass_pev_timesteps[[time_index + 1]] - timestep - ) - } } } diff --git a/R/stateful.R b/R/stateful.R deleted file mode 100644 index 05c614a0..00000000 --- a/R/stateful.R +++ /dev/null @@ -1,47 +0,0 @@ -#' @title Save the state of a list of \emph{stateful objects} -#' @description The state of each element is saved and stored into a single -#' object, representing them in a way that can be exported and re-used later. -#' @param objects A list of stateful objects to be saved. Stateful objects are -#' instances of R6 classes with a pair of \code{save_state} and -#' \code{restore_state} methods. -#' @noRd -save_state <- function(objects) { - lapply(objects, function(o) o$save_state()) -} - -#' @title Restore the state of a collection of stateful objects -#' @description This is the counterpart of \code{save_state}. Calling it -#' restores the collection of objects back into their original state. -#' @param state A state object, as returned by the \code{save_state} function. -#' @param objects A collection of stateful objects to be restored. -#' @noRd -restore_state <- function(state, objects) { - stopifnot(length(state) == length(objects)) - for (i in seq_along(state)) { - objects[[i]]$restore_state(state[[i]]) - } -} - -#' @title a placeholder class to save the random number generator class. -#' @description the class integrates with the simulation loop to save and -#' restore the random number generator class when appropriate. -#' @noRd -RandomState <- R6::R6Class( - 'RandomState', - private = list( - restore_random_state = NULL - ), - public = list( - initialize = function(restore_random_state) { - private$restore_random_state <- restore_random_state - }, - save_state = function() { - random_save_state() - }, - restore_state = function(state) { - if (private$restore_random_state) { - random_restore_state(state) - } - } - ) -) diff --git a/R/tbv.R b/R/tbv.R index 27c29dfb..d0f75de1 100644 --- a/R/tbv.R +++ b/R/tbv.R @@ -75,11 +75,6 @@ create_tbv_listener <- function(variables, events, parameters, correlations, ren to_vaccinate ) } - if (time_index < length(parameters$tbv_timesteps)) { - events$tbv_vaccination$schedule( - parameters$tbv_timesteps[[time_index + 1]] - timestep - ) - } } } diff --git a/R/utils.R b/R/utils.R index f25244bd..2262c939 100644 --- a/R/utils.R +++ b/R/utils.R @@ -64,3 +64,27 @@ rtexp <- function(n, m, t) { itexp(runif(n), m, t) } match_timestep <- function(ts, t) { min(sum(ts <= t), length(ts)) } + +#' @title a placeholder class to save the random number generator class. +#' @description the class integrates with the simulation loop to save and +#' restore the random number generator class when appropriate. +#' @noRd +RandomState <- R6::R6Class( + 'RandomState', + private = list( + restore_random_state = NULL + ), + public = list( + initialize = function(restore_random_state) { + private$restore_random_state <- restore_random_state + }, + save_state = function() { + random_save_state() + }, + restore_state = function(t, state) { + if (private$restore_random_state) { + random_restore_state(state) + } + } + ) +) diff --git a/man/CorrelationParameters.Rd b/man/CorrelationParameters.Rd index 2898aee5..8bb43d70 100644 --- a/man/CorrelationParameters.Rd +++ b/man/CorrelationParameters.Rd @@ -121,15 +121,20 @@ Save the correlation state. \if{latex}{\out{\hypertarget{method-CorrelationParameters-restore_state}{}}} \subsection{Method \code{restore_state()}}{ Restore the correlation state. + Only the randomly drawn weights are restored. The object needs to be initialized with the same rhos. \subsection{Usage}{ -\if{html}{\out{
}}\preformatted{CorrelationParameters$restore_state(state)}\if{html}{\out{
}} +\if{html}{\out{
}}\preformatted{CorrelationParameters$restore_state(timestep, state)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ +\item{\code{timestep}}{the timestep at which simulation is resumed. This +parameter's value is ignored, it only exists to conform to a uniform +interface.} + \item{\code{state}}{a previously saved correlation state, as returned by the save_state method.} } diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 439cb12b..e2a6b9d6 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -203,13 +203,14 @@ BEGIN_RCPP END_RCPP } // solver_set_states -void solver_set_states(Rcpp::XPtr solver, std::vector state); -RcppExport SEXP _malariasimulation_solver_set_states(SEXP solverSEXP, SEXP stateSEXP) { +void solver_set_states(Rcpp::XPtr solver, double t, std::vector state); +RcppExport SEXP _malariasimulation_solver_set_states(SEXP solverSEXP, SEXP tSEXP, SEXP stateSEXP) { BEGIN_RCPP Rcpp::RNGScope rcpp_rngScope_gen; Rcpp::traits::input_parameter< Rcpp::XPtr >::type solver(solverSEXP); + Rcpp::traits::input_parameter< double >::type t(tSEXP); Rcpp::traits::input_parameter< std::vector >::type state(stateSEXP); - solver_set_states(solver, state); + solver_set_states(solver, t, state); return R_NilValue; END_RCPP } @@ -363,7 +364,7 @@ static const R_CallMethodDef CallEntries[] = { {"_malariasimulation_rainfall", (DL_FUNC) &_malariasimulation_rainfall, 5}, {"_malariasimulation_exponential_process_cpp", (DL_FUNC) &_malariasimulation_exponential_process_cpp, 2}, {"_malariasimulation_solver_get_states", (DL_FUNC) &_malariasimulation_solver_get_states, 1}, - {"_malariasimulation_solver_set_states", (DL_FUNC) &_malariasimulation_solver_set_states, 2}, + {"_malariasimulation_solver_set_states", (DL_FUNC) &_malariasimulation_solver_set_states, 3}, {"_malariasimulation_solver_step", (DL_FUNC) &_malariasimulation_solver_step, 1}, {"_malariasimulation_create_timeseries", (DL_FUNC) &_malariasimulation_create_timeseries, 2}, {"_malariasimulation_timeseries_at", (DL_FUNC) &_malariasimulation_timeseries_at, 3}, diff --git a/src/solver.cpp b/src/solver.cpp index 0a5f7401..4c3f182f 100644 --- a/src/solver.cpp +++ b/src/solver.cpp @@ -48,7 +48,8 @@ std::vector solver_get_states(Rcpp::XPtr solver) { } //[[Rcpp::export]] -void solver_set_states(Rcpp::XPtr solver, std::vector state) { +void solver_set_states(Rcpp::XPtr solver, double t, std::vector state) { + solver->t = t; solver->state = state; } diff --git a/tests/testthat/test-mda.R b/tests/testthat/test-mda.R index bf92ae3a..1ee440f6 100644 --- a/tests/testthat/test-mda.R +++ b/tests/testthat/test-mda.R @@ -81,11 +81,8 @@ test_that('MDA moves the diseased and non-diseased population correctly', { drug = mock_double(c(1, 2, 1, 2)) ) - events$mda_administer <- mock_event(events$mda_administer) - listener <- create_mda_listeners( variables, - events$mda_administer, parameters$mda_drug, parameters$mda_timesteps, parameters$mda_coverages, @@ -141,12 +138,6 @@ test_that('MDA moves the diseased and non-diseased population correctly', { 50, c(3, 4) ) - - mockery::expect_args( - events$mda_administer$schedule, - 1, - 100 - ) }) test_that('MDA moves the diseased and non-diseased population correctly - second round, varying age range', { @@ -176,11 +167,8 @@ test_that('MDA moves the diseased and non-diseased population correctly - second drug = mock_double(c(1, 2, 1, 2)) ) - events$mda_administer <- mock_event(events$mda_administer) - listener <- create_mda_listeners( variables, - events$mda_administer, parameters$mda_drug, parameters$mda_timesteps, parameters$mda_coverages, @@ -265,11 +253,8 @@ test_that('MDA ignores non-detectable asymptomatics', { drug = mock_double(c(1, 2, 1, 2)) ) - events$mda_administer <- mock_event(events$mda_administer) - listener <- create_mda_listeners( variables, - events$mda_administer, parameters$mda_drug, parameters$mda_timesteps, parameters$mda_coverages, diff --git a/tests/testthat/test-pev.R b/tests/testthat/test-pev.R index 88b95b35..09c4cf7d 100644 --- a/tests/testthat/test-pev.R +++ b/tests/testthat/test-pev.R @@ -203,7 +203,6 @@ test_that('Mass vaccinations update vaccination time', { c(-1, -1, -1, 50, 50) ) - events$mass_pev <- mock_event(events$mass_pev) events$mass_pev_doses <- lapply(events$mass_pev_doses, mock_event) listener <- create_mass_pev_listener( @@ -241,12 +240,6 @@ test_that('Mass vaccinations update vaccination time', { c(1, 3), parameters$pev_doses[[3]] ) - - mockery::expect_args( - events$mass_pev$schedule, - 1, - 365 - ) }) test_that('Mass vaccinations ignore EPI individuals', { diff --git a/tests/testthat/test-resume.R b/tests/testthat/test-resume.R index 83bada35..4d4a572d 100644 --- a/tests/testthat/test-resume.R +++ b/tests/testthat/test-resume.R @@ -1,41 +1,161 @@ -test_that('Simulation can be resumed', { - initial_timesteps <- 50 - total_timesteps <- 100 - - parameters <- get_parameters() +#' Test simulation saving and restoring for a given parameter set. +#' +#' This function runs the simulation twice. A first, continuous and uninterrupted +#' run of the simulation is used as a reference. The second run is split into +#' two phases. Between the two phases, the simulation state is saved and +#' restored. Optionally, the initial warmup phase can use a different set of +#' parameters, by specifying a value for warmup_parameters. +test_resume <- function( + parameters, + timesteps = 200, + warmup_parameters = parameters, + warmup_timesteps = 50 + ) { + set.seed(123) + uninterrupted_run <- run_simulation(timesteps, parameters=parameters) - set.seed(1) - first_phase <- run_resumable_simulation(initial_timesteps, parameters) + set.seed(123) + first_phase <- run_resumable_simulation(warmup_timesteps, warmup_parameters) second_phase <- run_resumable_simulation( - total_timesteps, + timesteps, parameters, initial_state=first_phase$state, restore_random_state=TRUE) - set.seed(1) - uninterrupted_run <- run_simulation(total_timesteps, parameters=parameters) + expect_equal(nrow(first_phase$data), warmup_timesteps) + expect_equal(nrow(second_phase$data), timesteps - warmup_timesteps) + + expect_mapequal( + second_phase$data, + uninterrupted_run[-(1:warmup_timesteps),]) + + invisible(second_phase$data) +} + +test_that('Simulation can be resumed', { + test_resume(get_parameters(overrides=list( + individual_mosquitoes = FALSE, + model_seasonality = TRUE + ))) + test_resume(get_parameters(overrides=list( + individual_mosquitoes = TRUE, + model_seasonality = TRUE + ))) + test_resume(get_parameters(overrides=list( + individual_mosquitoes = FALSE, + model_seasonality = TRUE + ))) + test_resume(get_parameters(overrides=list( + individual_mosquitoes = TRUE, + model_seasonality = TRUE + ))) +}) + +test_that('PEV intervention can be added when resuming', { + set_default_mass_pev <- function(parameters, timesteps) { + n <- length(timesteps) + set_mass_pev( + parameters, + profile = rtss_profile, + timesteps = timesteps, + coverages = rep(0.5, n), + min_wait = 5, + min_ages = 365*10, + max_ages = 365*60, + booster_spacing = NULL, + booster_coverage = NULL, + booster_profile = NULL) + } + base <- get_parameters(overrides=list(pev_doses=c(0, 45, 90))) + + data <- test_resume( + warmup_parameters = base, + parameters = base %>% set_default_mass_pev(100)) + expect_equal(data[data$n_pev_mass_dose_1 > 0, "timestep"], 100) + expect_equal(data[data$n_pev_mass_dose_2 > 0, "timestep"], 145) + expect_equal(data[data$n_pev_mass_dose_3 > 0, "timestep"], 190) + + # Add a second mass PEV intervention when resuming the simulation. + data <- test_resume( + warmup_parameters = base %>% set_default_mass_pev(25), + parameters = base %>% set_default_mass_pev(c(25, 100))) - expect_equal(nrow(first_phase$data), initial_timesteps) - expect_equal(nrow(second_phase$data), total_timesteps - initial_timesteps) - expect_equal(rbind(first_phase$data, second_phase$data), uninterrupted_run) + # The first dose, at time step 25, happens during the warmup and is not + # returned by test_resume, hence why we don't see it in the data. Follow-up + # doses do show up, even though they we scheduled during warmup. + expect_equal(data[data$n_pev_mass_dose_1 > 0, "timestep"], c(100)) + expect_equal(data[data$n_pev_mass_dose_2 > 0, "timestep"], c(70, 145)) + expect_equal(data[data$n_pev_mass_dose_3 > 0, "timestep"], c(115, 190)) }) -test_that('Intervention parameters can be changed when resuming', { - initial_timesteps <- 50 - total_timesteps <- 100 - tbv_timesteps <- 70 +test_that("TBV intervention can be added when resuming", { + set_default_tbv <- function(parameters, timesteps) { + set_tbv( + parameters, + timesteps=timesteps, + coverage=rep(1, length(timesteps)), + ages=5:60) + } + + base <- get_parameters() + + data <- test_resume( + warmup_parameters = base, + parameters = base %>% set_default_tbv(100)) + expect_equal(data[!is.na(data$n_vaccinated_tbv), "timestep"], 100) + + data <- test_resume( + warmup_parameters = base %>% set_default_tbv(25), + parameters = base %>% set_default_tbv(c(25, 100))) + expect_equal(data[!is.na(data$n_vaccinated_tbv), "timestep"], 100) +}) + +test_that("MDA intervention can be added when resuming", { + set_default_mda <- function(parameters, timesteps) { + parameters %>% set_drugs(list(SP_AQ_params)) %>% set_mda( + drug = 1, + timesteps = timesteps, + coverages = rep(0.8, length(timesteps)), + min_ages = rep(0, length(timesteps)), + max_ages = rep(60*365, length(timesteps))) + } + + base <- get_parameters() + + data <- test_resume( + warmup_parameters = base, + parameters = base %>% set_default_mda(100)) + expect_equal(data[data$n_mda_treated > 0, "timestep"], 100) + + data <- test_resume( + warmup_parameters = base %>% set_default_mda(25), + parameters = base %>% set_default_mda(c(25, 100))) + expect_equal(data[data$n_mda_treated > 0, "timestep"], 100) +}) - # Because of how event scheduling works, we must enable TBV even in the inital phase. - # We set a coverage of 0 to act as-if it was disabled. - initial_parameters <- get_parameters() |> set_tbv(timesteps=tbv_timesteps, coverage=0, ages=5:60) +test_that("Bednets intervention can be added when resuming", { + set_default_bednets <- function(parameters, timesteps) { + n <- length(timesteps) + set_bednets( + parameters, + timesteps = timesteps, + coverages = rep(0.5, n), + retention = 25, + dn0 = matrix(rep(0.533, n), ncol=1), + rn = matrix(rep(0.56, n), ncol=1), + rnm = matrix(rep(0.24, n), ncol=1), + gamman = rep(2.64 * 365, n)) + } - tbv_parameters <- initial_parameters |> - set_tbv(timesteps=tbv_timesteps, coverage=1, ages=5:60) + base <- get_parameters() - initial_run <- run_resumable_simulation(initial_timesteps, initial_parameters) - control_run <- run_resumable_simulation(total_timesteps, initial_parameters, initial_state = initial_run$state) - tbv_run <- run_resumable_simulation(total_timesteps, tbv_parameters, initial_state = initial_run$state) + data <- test_resume( + warmup_parameters = base, + parameters = base %>% set_default_bednets(100)) + expect_equal(data[diff(data$n_use_net) > 0, "timestep"], 100) - expect_equal(control_run$data$n_vaccinated_tbv[tbv_timesteps - initial_timesteps], 0) - expect_gt(tbv_run$data$n_vaccinated_tbv[tbv_timesteps - initial_timesteps], 0) + data <- test_resume( + warmup_parameters = base %>% set_default_bednets(25), + parameters = base %>% set_default_bednets(c(25, 100))) + expect_equal(data[diff(data$n_use_net) > 0, "timestep"], 100) }) From 1111500493e3df5d6216d8dffdf75dba306e8292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Li=C3=A9tar?= Date: Tue, 30 Apr 2024 15:20:12 +0100 Subject: [PATCH 164/164] Allow correlations to be extended when resuming. (#293) When resuming a simulation, it is possible to add new intervention. The correlation of the new intervention may need configuring, both relative to itself and to existing interventions. The correlation parameters work by sampling, at the start of the simulation, relative weights for each individual and intervention. The weight are later used to select which individuals are targeted by the a given intervention. There weights are drawn from a multivariate normal distribution, whose variance-covariance matrix depends on the configured correlation. When adding interventions, new corresponding columns need to be added to the weights matrix. A fresh mvnorm distribution cannot be used, since it would override the already drawn weigths for the existing interventions. The solution instead is to use a conditional mvnorm distribution on the new columns, using the existing values as the conditions. This yields new weigths which follow the determined variance-covariance matrix while preserving the existing values. --- R/correlation.R | 162 +++++++++++++++++++--- man/CorrelationParameters.Rd | 31 ++++- tests/testthat/test-correlation.R | 218 ++++++++++++++++++++++++++++++ tests/testthat/test-resume.R | 150 +++++++++++++++++++- 4 files changed, 535 insertions(+), 26 deletions(-) diff --git a/R/correlation.R b/R/correlation.R index 2a59fdbc..bb98fb3b 100644 --- a/R/correlation.R +++ b/R/correlation.R @@ -9,7 +9,26 @@ INTS <- c( ) #' Class: Correlation parameters -#' Describes an event in the simulation +#' +#' This class implements functionality that allows interventions to be +#' correlated, positively or negatively. By default, interventions are applied +#' independently and an individual's probability of receiving two interventions +#' (either two separate interventions or two rounds of the same one) is the +#' product of the probability of receiving each one. +#' +#' By setting a positive correlation between two interventions, we can make it +#' so that the individuals that receive intervention A are more likely to +#' receive intervention B. Conversely, a negative correlation will make it such +#' that individuals that receive intervention A are less likely to also receive +#' intervention B. +#' +#' Broadly speaking, the implementation works by assigning at startup a weight +#' to each individual and intervention pair, reflecting how likely an individual +#' is to receive that intervention. Those weights are derived stochastically +#' from the configured correlation parameters. +#' +#' For a detailed breakdown of the calculations, see Protocol S2 of +#' Griffin et al. (2010). CorrelationParameters <- R6::R6Class( 'CorrelationParameters', private = list( @@ -19,7 +38,40 @@ CorrelationParameters <- R6::R6Class( rho_matrix = NULL, rho = function() diag(private$rho_matrix), .sigma = NULL, - .mvnorm = NULL + .mvnorm = NULL, + + #' Derive the mvnorm from the configured correlations. + #' + #' If a \code{restored_mvnorm} is specified, its columns (corresponding to + #' restored interventions) will be re-used as is. Missing columns (for new + #' interventions) are derived in accordance with the restored data. + calculate_mvnorm = function(restored_mvnorm = matrix(ncol=0, nrow=private$population)) { + sigma <- self$sigma() + V <- outer(sigma, sigma) * private$rho_matrix + diag(V) <- sigma ^ 2 + + restored_interventions <- match(colnames(restored_mvnorm), private$interventions) + new_interventions <- setdiff(seq_along(private$interventions), restored_interventions) + + mvnorm <- matrix( + nrow = private$population, + ncol = length(private$interventions), + dimnames = list(NULL, private$interventions) + ) + mvnorm[,restored_interventions] <- restored_mvnorm + if (length(new_interventions) > 0) { + mvnorm[,new_interventions] <- rcondmvnorm( + private$population, + mean = rep(0, length(private$interventions)), + sigma = V, + given = restored_mvnorm, + dependent.ind = new_interventions, + given.ind = restored_interventions + ) + } + + mvnorm + } ), public = list( @@ -45,6 +97,8 @@ CorrelationParameters <- R6::R6Class( #' @param rho value between 0 and 1 representing the correlation between rounds of #' the intervention inter_round_rho = function(int, rho) { + stopifnot(is.null(private$.sigma) && is.null(private$.mvnorm)) + if (!(int %in% private$interventions)) { stop(paste0('invalid intervention name: ', int)) } @@ -55,8 +109,6 @@ CorrelationParameters <- R6::R6Class( rho <- 1 - .Machine$double.eps } private$rho_matrix[[int, int]] <- rho - private$.sigma <- NULL - private$.mvnorm <- NULL }, #' @description Add rho between interventions @@ -66,6 +118,8 @@ CorrelationParameters <- R6::R6Class( #' @param rho value between -1 and 1 representing the correlation between rounds of #' the intervention inter_intervention_rho = function(int_1, int_2, rho) { + stopifnot(is.null(private$.sigma) && is.null(private$.mvnorm)) + if (!(int_1 %in% private$interventions)) { stop(paste0('invalid intervention name: ', int_1)) } @@ -83,8 +137,6 @@ CorrelationParameters <- R6::R6Class( } private$rho_matrix[[int_1, int_2]] <- rho private$rho_matrix[[int_2, int_1]] <- rho - private$.sigma <- NULL - private$.mvnorm <- NULL }, #' @description Standard deviation of each intervention between rounds @@ -98,18 +150,9 @@ CorrelationParameters <- R6::R6Class( }, #' @description multivariate norm draws for these parameters - #' @importFrom MASS mvrnorm mvnorm = function() { if (is.null(private$.mvnorm)) { - sigma <- self$sigma() - V <- outer(sigma, sigma) * private$rho_matrix - diag(V) <- sigma ^ 2 - private$.mvnorm <- mvrnorm( - private$population, - rep(0, length(private$interventions)), - V - ) - dimnames(private$.mvnorm)[[2]] <- private$interventions + private$.mvnorm <- private$calculate_mvnorm() } private$.mvnorm }, @@ -121,7 +164,7 @@ CorrelationParameters <- R6::R6Class( # otherwise we would be drawing a new, probably different, value. # The rest of the object is derived deterministically from the parameters # and does not need saving. - list(mvnorm=private$.mvnorm) + list(mvnorm=self$mvnorm()) }, #' @description Restore the correlation state. @@ -135,7 +178,8 @@ CorrelationParameters <- R6::R6Class( #' @param state a previously saved correlation state, as returned by the #' save_state method. restore_state = function(timestep, state) { - private$.mvnorm <- state$mvnorm + stopifnot(is.null(private$.sigma) && is.null(private$.mvnorm)) + private$.mvnorm <- private$calculate_mvnorm(state$mvnorm) } ) ) @@ -205,3 +249,85 @@ sample_intervention <- function(target, intervention, p, correlations) { z <- rnorm(length(target)) u0 + correlations$mvnorm()[target, intervention] + z < 0 } + +#' Simulate from a conditional multivariate normal distribution. +#' +#' Given a multidimensional variable Z which follows a multivariate normal +#' distribution, this function allows one to draw samples for a subset of Z, +#' while putting conditions on the values of the rest of Z. +#' +#' This effectively allows one to grow a MVN distributed matrix (with columns as +#' the dimensions and a row per sampled vector), adding new dimensions after the +#' fact. The existing columns are used as the condition set on the distribution, +#' and the values returned by this function are used as the new dimensions. +#' +#' The maths behind the implementation are described in various online sources: +#' - https://statproofbook.github.io/P/mvn-cond.html +#' - https://www.stats.ox.ac.uk/~doucet/doucet_simulationconditionalgaussian.pdf +#' - https://en.wikipedia.org/wiki/Multivariate_normal_distribution#Conditional_distributions +#' +#' @param n the number of samples to simulate +#' @param mean the mean vector of the distribution, including both given and +#' dependent variables +#' @param sigma the variance-covariance matrix of the distribution, including +#' both given and dependent variables +#' @param given a matrix of given values used as conditions when simulating the +#' distribution. The matrix should have \code{n} rows, each one specifying a +#' different set of values for the given variables. +#' @param dependent.ind the indices within \code{mean} and \code{sigma} of the +#' variables to simulate. +#' @param given.ind the indices within \code{mean} and \code{sigma} of the +#' variables for which conditions are given. The length of this vector must be +#' equal to the number of columns of the \code{given} matrix. If empty or NULL, +#' this function is equivalent to simulating from an unconditional multivariate +#' normal distribution. +#' @return a matrix with \code{n} rows and \code{length(dependent.ind)} columns, +#' containing the simulated value. +#' @importFrom MASS mvrnorm +#' @noRd +rcondmvnorm <- function(n, mean, sigma, given, dependent.ind, given.ind) { + stopifnot(length(mean) == nrow(sigma)) + stopifnot(length(mean) == ncol(sigma)) + stopifnot(nrow(given) == n) + stopifnot(ncol(given) == length(given.ind)) + + sigma11 <- sigma[dependent.ind, dependent.ind, drop=FALSE] + sigma12 <- sigma[dependent.ind, given.ind, drop=FALSE] + sigma21 <- sigma[given.ind, dependent.ind, drop=FALSE] + sigma22 <- sigma[given.ind, given.ind, drop=FALSE] + + if (all(sigma22 == 0)) { + # This covers two cases: there were no given variables and therefore their + # variance-covariance matrix is empty, or there were given variables but + # they had a variance of zero. The general formula can't support the latter + # case since it tries to invert the matrix, but we can safely ignore the + # values since they are all equal to their mean and don't influence the + # dependent variables. + # + # In both cases we revert to a standard MVN with no condition. + mvrnorm(n, mean[dependent.ind], sigma11) + } else { + # Available implementations of the conditional multivariate normal assume + # every sample is drawn using the same condition on the given variables. + # This is not true in our usecase, where every individual has already had an + # independent vector of values drawn for the given variable. We are + # effectively drawing from as many different distributions as there are + # individuals. Thankfully the same conditional covariance matrix can be + # used for all the distributions, only the mean vector needs to be + # different. We draw the underlying samples from the MVN at mean 0, and + # offset that later on a per-individual basis. + # + # To work over all the vectors directly they need to be as columns, which + # is why we start by transposing `given`. R will recycle the `m` matrix and + # `mean` vectors across all the columns. The last step is to transpose the + # result back into the expected configuration. + + m <- sigma12 %*% solve(sigma22) + residual <- t(given) - mean[given.ind] + cond_mu <- t(m %*% residual + mean[dependent.ind]) + cond_sigma <- sigma11 - m %*% sigma21 + + samples <- mvrnorm(n, rep(0, length(dependent.ind)), cond_sigma) + samples + cond_mu + } +} diff --git a/man/CorrelationParameters.Rd b/man/CorrelationParameters.Rd index 8bb43d70..0aebf688 100644 --- a/man/CorrelationParameters.Rd +++ b/man/CorrelationParameters.Rd @@ -2,14 +2,37 @@ % Please edit documentation in R/correlation.R \name{CorrelationParameters} \alias{CorrelationParameters} -\title{Class: Correlation parameters -Describes an event in the simulation} +\title{Class: Correlation parameters} \description{ Class: Correlation parameters -Describes an event in the simulation Class: Correlation parameters -Describes an event in the simulation +} +\details{ +This class implements functionality that allows interventions to be +correlated, positively or negatively. By default, interventions are applied +independently and an individual's probability of receiving two interventions +(either two separate interventions or two rounds of the same one) is the +product of the probability of receiving each one. + +By setting a positive correlation between two interventions, we can make it +so that the individuals that receive intervention A are more likely to +receive intervention B. Conversely, a negative correlation will make it such +that individuals that receive intervention A are less likely to also receive +intervention B. + +Broadly speaking, the implementation works by assigning at startup a weight +to each individual and intervention pair, reflecting how likely an individual +is to receive that intervention. Those weights are derived stochastically +from the configured correlation parameters. + +For a detailed breakdown of the calculations, see Protocol S2 of +Griffin et al. (2010). +Derive the mvnorm from the configured correlations. + +If a \code{restored_mvnorm} is specified, its columns (corresponding to +restored interventions) will be re-used as is. Missing columns (for new +interventions) are derived in accordance with the restored data. } \section{Methods}{ \subsection{Public methods}{ diff --git a/tests/testthat/test-correlation.R b/tests/testthat/test-correlation.R index 882831f8..5653daaa 100644 --- a/tests/testthat/test-correlation.R +++ b/tests/testthat/test-correlation.R @@ -134,3 +134,221 @@ test_that('-1 correlation between interventions gives sensible samples', { pop * (pev_coverage + mda_coverage), tolerance=.1) }) + +test_that('correlation between rounds is preserved when adding interventions', { + pop <- 1e6 + target <- seq(pop) + + pev_coverage_1 <- .2 + pev_coverage_2 <- .4 + + initial <- CorrelationParameters$new(pop, c('pev')) + initial$inter_round_rho('pev', 1) + + restored <- CorrelationParameters$new(pop, c('pev', 'mda')) + restored$inter_round_rho('pev', 1) + restored$inter_round_rho('mda', 1) + restored$inter_intervention_rho('pev', 'mda', 1) + restored$restore_state(0, initial$save_state()) + + round_1 <- sample_intervention(target, 'pev', pev_coverage_1, initial) + round_2 <- sample_intervention(target, 'pev', pev_coverage_2, restored) + + expect_equal(sum(round_1), pop * pev_coverage_1, tolerance=.1) + expect_equal(sum(round_2), pop * pev_coverage_2, tolerance=.1) + + expect_equal( + sum(round_1 & round_2), + pop * min(pev_coverage_1, pev_coverage_2), + tolerance=.1) + + expect_equal( + sum(round_1 | round_2), + pop * max(pev_coverage_1, pev_coverage_2), + tolerance=.1) +}) + +test_that('1 correlation between interventions gives sensible samples when restored', { + pop <- 1e6 + target <- seq(pop) + + pev_coverage <- .2 + mda_coverage <- .2 + + initial <- CorrelationParameters$new(pop, c('pev')) + initial$inter_round_rho('pev', 1) + + restored <- CorrelationParameters$new(pop, c('pev', 'mda')) + restored$inter_round_rho('pev', 1) + restored$inter_round_rho('mda', 1) + restored$inter_intervention_rho('pev', 'mda', 1) + restored$restore_state(0, initial$save_state()) + + pev_sample <- sample_intervention(target, 'pev', pev_coverage, initial) + mda_sample <- sample_intervention(target, 'mda', mda_coverage, restored) + + expect_equal(sum(pev_sample), pop * pev_coverage, tolerance=.1) + expect_equal(sum(mda_sample), pop * mda_coverage, tolerance=.1) + + expect_equal( + sum(pev_sample & mda_sample), + pop * min(pev_coverage, mda_coverage), + tolerance=.1) + + expect_equal( + sum(pev_sample | mda_sample), + pop * max(pev_coverage, mda_coverage), + tolerance=.1) +}) + +test_that('0 correlation between interventions gives sensible samples when restored', { + pop <- 1e6 + target <- seq(pop) + + pev_coverage <- .2 + mda_coverage <- .2 + + initial <- CorrelationParameters$new(pop, c('pev')) + initial$inter_round_rho('pev', 1) + + restored <- CorrelationParameters$new(pop, c('pev', 'mda')) + restored$inter_round_rho('pev', 1) + restored$inter_round_rho('mda', 1) + restored$inter_intervention_rho('pev', 'mda', 0) + restored$restore_state(0, initial$save_state()) + + pev_sample <- sample_intervention(target, 'pev', pev_coverage, initial) + mda_sample <- sample_intervention(target, 'mda', mda_coverage, restored) + + expect_equal(sum(pev_sample), pop * pev_coverage, tolerance=.1) + expect_equal(sum(mda_sample), pop * mda_coverage, tolerance=.1) + + expect_equal( + sum(pev_sample & mda_sample), + pop * pev_coverage * mda_coverage, + tolerance=.1) + + expect_equal( + sum(pev_sample | mda_sample), + pop * (pev_coverage + mda_coverage - (pev_coverage * mda_coverage)), + tolerance=.1) +}) + +test_that('-1 correlation between interventions gives sensible samples when restored', { + pop <- 1e6 + target <- seq(pop) + pev_coverage <- .2 + mda_coverage <- .2 + + initial <- CorrelationParameters$new(pop, c('pev')) + initial$inter_round_rho('pev', 1) + + restored <- CorrelationParameters$new(pop, c('pev', 'mda')) + restored$inter_round_rho('pev', 1) + restored$inter_round_rho('mda', 1) + restored$inter_intervention_rho('pev', 'mda', -1) + restored$restore_state(0, initial$save_state()) + + pev_sample <- sample_intervention(target, 'pev', pev_coverage, initial) + mda_sample <- sample_intervention(target, 'mda', mda_coverage, restored) + + expect_equal(sum(pev_sample), pop * pev_coverage, tolerance=.1) + expect_equal(sum(mda_sample), pop * mda_coverage, tolerance=.1) + + expect_equal(sum(pev_sample & mda_sample), 0, tolerance=.1) + expect_equal( + sum(pev_sample | mda_sample), + pop * (pev_coverage + mda_coverage), + tolerance=.1) +}) + +test_that("rcondmvnorm has correct distribution", { + set.seed(123) + + pop <- 1e6 + + # These are completely arbitrary values. The statistics from the simulated + # sample will get compared back to this. + means <- c(-5, 7, 0, 0.3) + variance <- c(0.3, 0.6, 0.9, 0.2) + correlation <- matrix(0, ncol=4, nrow=4) + correlation[1,2] <- correlation[2,1] <- -0.6 + correlation[1,3] <- correlation[3,1] <- 0.4 + correlation[1,4] <- correlation[4,1] <- 1 + correlation[2,3] <- correlation[3,2] <- 0 + correlation[2,4] <- correlation[4,2] <- 0.1 + correlation[3,4] <- correlation[4,3] <- 0.5 + + covariance <- outer(variance, variance) * correlation + diag(covariance) <- variance + + # These are indices of variables that get simulated together. + wy.ind <- c(1, 3) + xz.ind <- c(2, 4) + + # Simulate from the MVN for a subset of the dimensions. We intentionally pass + # in a subset of the mean and covariance matrices, as the rest of the + # parameters are not needed and may not be known. `dependent.ind` is relative + # to the subsetted mean and covariance, and therefore is set the first two + # indices as opposed to `wy.ind`. + wy <- rcondmvnorm(pop, means[wy.ind], covariance[wy.ind, wy.ind], given=NULL, + dependent.ind=c(1,2), given.ind=NULL) + expect_equal(dim(wy), c(pop, 2)) + expect_equal(apply(wy, 2, mean), means[wy.ind], tolerance=0.001) + expect_equal(cov(wy), covariance[wy.ind, wy.ind], tolerance=0.001) + + # Now simulate some more, but conditional on the existing values. + # The call to rcondmvnorm needs all the mean and covariance parameters, + # including the ones that have already been simulated. + xz <- rcondmvnorm(pop, means, covariance, given=wy, + dependent.ind=xz.ind, given.ind=wy.ind) + expect_equal(dim(xz), c(pop, 2)) + expect_equal(apply(xz, 2, mean), means[xz.ind], tolerance=0.001) + expect_equal(cov(xz), covariance[xz.ind, xz.ind], tolerance=0.001) + + # Stitch the variables back together and make sure the covariance across the + # separately simulated values match the expected one. + values <- cbind(wy[,1], xz[,1], wy[,2], xz[,2]) + expect_equal(apply(values, 2, mean), means, tolerance=0.001) + expect_equal(cov(values), covariance, tolerance=0.001) +}) + +# This would usually be considered an uninteresting edge case, since null +# variance just yields a constant vector. The way we use the function in the +# simulation though, a null variance is actually the default and most common +# case, as it is used where the different rounds of an intervention have no +# correlation. +# +# We need to make sure the other variables are still correctly simulated. +test_that("rcondmvnorm allows null variance of given variables", { + set.seed(123) + + pop <- 1e6 + + means <- c(-5, 7, 0) + variance <- c(0.3, 0, 0.9) + correlation <- matrix(0, ncol=3, nrow=3) + correlation[1,3] <- 0.4 + correlation[3,1] <- 0.4 + + covariance <- outer(variance, variance) * correlation + diag(covariance) <- variance + + # These are indices of variables that get simulated together. + y.ind <- 2 + xz.ind <- c(1,3) + + # Simulate one dimension. Because its variance was null, the result is a + # constant vector. + y <- rcondmvnorm(pop, means, covariance, given=NULL, + dependent.ind=y.ind, given.ind=NULL) + expect_equal(as.vector(y), rep(means[y.ind], pop)) + + # Simulate the rest. The original dimension has no influence on the result. + xz <- rcondmvnorm(pop, means, covariance, given=y, + dependent.ind=xz.ind, given.ind=y.ind) + + xyz <- cbind(xz[,1], y, xz[,2]) + expect_equal(apply(xyz, 2, mean), means, tolerance=0.001) + expect_equal(cov(xyz), covariance, tolerance=0.001) +}) diff --git a/tests/testthat/test-resume.R b/tests/testthat/test-resume.R index 4d4a572d..1fb7ff87 100644 --- a/tests/testthat/test-resume.R +++ b/tests/testthat/test-resume.R @@ -11,20 +11,39 @@ test_resume <- function( warmup_parameters = parameters, warmup_timesteps = 50 ) { + + # This function is only used with null correlations. However a null + # correlation involves sampling random numbers during initialization, which + # disrupts the global RNG and affects the reproducibility if the size of the + # matrix is not always the same. + # + # We use a single correlation object, that we initialize eagerly, such that + # the simulation can run undisturbed. + correlations <- get_correlation_parameters(parameters) + correlations$mvnorm() + set.seed(123) - uninterrupted_run <- run_simulation(timesteps, parameters=parameters) + uninterrupted_run <- run_simulation( + timesteps, + parameters = parameters, + correlations = correlations) set.seed(123) - first_phase <- run_resumable_simulation(warmup_timesteps, warmup_parameters) + first_phase <- run_resumable_simulation( + warmup_timesteps, + warmup_parameters, + correlations = correlations) second_phase <- run_resumable_simulation( timesteps, parameters, - initial_state=first_phase$state, - restore_random_state=TRUE) + initial_state = first_phase$state, + restore_random_state = TRUE) expect_equal(nrow(first_phase$data), warmup_timesteps) expect_equal(nrow(second_phase$data), timesteps - warmup_timesteps) + # The order of columns isn't always identical, hence why mapequal needs to be + # used. expect_mapequal( second_phase$data, uninterrupted_run[-(1:warmup_timesteps),]) @@ -159,3 +178,126 @@ test_that("Bednets intervention can be added when resuming", { parameters = base %>% set_default_bednets(c(25, 100))) expect_equal(data[diff(data$n_use_net) > 0, "timestep"], 100) }) + +test_that("Correlations can be set when resuming with new interventions", { + set.seed(123) + + # When adding a new intervention with a non-zero correlation, we cannot + # ensure that an uninterrupted run matches the stopped-and-resumed simulation + # exactly, as the correlation matrix ends up being randomly sampled in a + # different order. This stops us from using the `test_resume` used throughout + # the rest of this file. Instead we'll only do stopped-and-resumed simulations + #' and check its behaviour. + # + # We first do a warmup phase with only TBV enabled. We then resume that + # simulation three times, each time with MDA enabled. Each time we resume the + # simulation, we set a different correlation parameter between the TBV and + # MDA interventions, with values -1, 0 and 1. + # + # We look at the output data and confirm that the correlation worked as + # expected. For this we need not only how many people got each intervention, + # but also how many received both and how many received at least one. This is + # not normally exposed, so we add an extra process to render these values. + # + # For simplicity, for each intervention, we remove any selection process other + # than overall coverage, such as age range (set to 0-200years) and drug + # efficacy (set to 100%). + # + # We need a large population to make the statistical assertions succeed. We'll + # only simulate 3 timesteps to keep execution time down: one timestep for + # warmup during which TBV takes place, one in which MDA takes place and one + # final timestep to collect the updated variables. + population <- 10000 + tbv_coverage <- 0.2 + mda_coverage <- 0.4 + + warmup_parameters <- get_parameters(overrides=list(human_population=population)) %>% + set_tbv( + timesteps=1, + coverage=tbv_coverage, + ages=0:200) + + drug <- SP_AQ_params + drug[1] <- 1. # Override the drug efficacy to 100% + parameters <- warmup_parameters %>% + set_drugs(list(drug)) %>% + set_mda( + drug = 1, + timesteps = 2, + coverages = mda_coverage, + min_ages = 0, + max_ages = 200*365) + + create_processes_stub <- function(renderer, variables, events, parameters, ...) { + p <- function(t) { + pop <- parameters$human_population + tbv <- variables$tbv_vaccinated$get_index_of(a=-1, b=0)$not() + mda <- variables$drug_time$get_index_of(-1)$not() + + renderer$render("total_tbv", tbv$size(), t) + renderer$render("total_mda", mda$size(), t) + renderer$render("total_tbv_and_mda", tbv$copy()$and(mda)$size(), t) + renderer$render("total_tbv_or_mda", tbv$copy()$or(mda)$size(), t) + } + c(create_processes(renderer, variables, events, parameters, ...), p) + } + + mockery::stub(run_resumable_simulation, 'create_processes', create_processes_stub) + + warmup_correlations <- get_correlation_parameters(warmup_parameters) + warmup_correlations$inter_round_rho('tbv', 1) + + warmup <- run_resumable_simulation(1, + parameters=warmup_parameters, + correlations=warmup_correlations) + + zero_correlation <- get_correlation_parameters(parameters) + zero_correlation$inter_round_rho('tbv', 1) + zero_correlation$inter_round_rho('mda', 1) + + positive_correlation <- get_correlation_parameters(parameters) + positive_correlation$inter_round_rho('tbv', 1) + positive_correlation$inter_round_rho('mda', 1) + positive_correlation$inter_intervention_rho('tbv', 'mda', 1) + + negative_correlation <- get_correlation_parameters(parameters) + negative_correlation$inter_round_rho('tbv', 1) + negative_correlation$inter_round_rho('mda', 1) + negative_correlation$inter_intervention_rho('tbv', 'mda', -1) + + data <- run_resumable_simulation( + 3, + initial_state=warmup$state, + parameters=parameters, + correlations=zero_correlation)$data %>% tail(1) + expect_equal(data$total_tbv, population * tbv_coverage, tolerance = 0.1) + expect_equal(data$total_mda, population * mda_coverage, tolerance = 0.1) + expect_equal( + data$total_tbv_and_mda, + population * (tbv_coverage * mda_coverage), + tolerance = 0.1) + expect_equal( + data$total_tbv_or_mda, + population * (tbv_coverage + mda_coverage - tbv_coverage * mda_coverage), + tolerance = 0.1) + + data <- run_resumable_simulation( + 3, + initial_state=warmup$state, + parameters=parameters, + correlations=positive_correlation)$data %>% tail(1) + expect_equal(data$total_tbv, population * tbv_coverage, tolerance = 0.1) + expect_equal(data$total_mda, population * mda_coverage, tolerance = 0.1) + expect_equal(data$total_tbv_and_mda, min(data$total_tbv, data$total_mda)) + expect_equal(data$total_tbv_or_mda, max(data$total_tbv, data$total_mda)) + + data <- run_resumable_simulation( + 3, + initial_state=warmup$state, + parameters=parameters, + correlations=negative_correlation)$data %>% tail(1) + expect_equal(data$total_tbv, population * tbv_coverage, tolerance = 0.1) + expect_equal(data$total_mda, population * mda_coverage, tolerance = 0.1) + expect_equal(data$total_tbv_and_mda, 0) + expect_equal(data$total_tbv_or_mda, data$total_tbv + data$total_mda) +})