Vaccines

# Load the requisite packages:
library(malariasimulation)
# Set colour palette:
cols <- c("#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")

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.

# Plotting clinical incidence 
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_clinical_0_1825 / output$n_age_0_1825
  output$time_year <- output$timestep / year
  comparison$clinical_incidence <- 1000 * comparison$n_inc_clinical_0_1825 / comparison$n_age_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)",
       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)
  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") 
  lines(comparison$time_year, predict(curve_valuescomp), 
        col = cols[6], lwd = 3)
  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
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
  comparison$time_year <- comparison$timestep / year

  plot(x = output$time_year, y = output$n_detect_lm_730_3650/output$n_age_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")
  grid(lty = 2, col = "grey80", lwd = 0.5)
  lines(x = comparison$time_year, y = comparison$n_detect_lm_730_3650/comparison$n_age_730_3650,
        col = cols[6], lwd = 3)
  abline(v = vaccinetime, col = "black", lty = 2, 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
plot_doses <- function(){
  output$month <- ceiling(output$timestep / month)
  doses <- output[, c(grep("n_pev" , names(output)), grep("month", names(output)))]
  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, 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"),
         fill = cols[1:6], bg="transparent", cex = 0.8, y.intersp = 1.5)
}

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).

year <- 365
month <- 30
sim_length <- 3 * year
human_population <- 10000
starting_EIR <- 20

simparams <- get_parameters(list(
    human_population = human_population,
    clinical_incidence_rendering_min_ages = 0,
    clinical_incidence_rendering_max_ages = 5 * year,
    individual_mosquitoes = FALSE
  )
)

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(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 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.

Simulation

rtssmassparams <- set_mass_pev(
  simparams,
  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.
  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_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.
)

output <- run_simulation(timesteps = sim_length, parameters = rtssmassparams)

Visualisation

# Plot clinical incidence
plot_inci()

# Plot prevalence
plot_prev()