# Load packages
library(epidemics)
library(socialmixr)
library(odin)
library(data.table)
library(ggplot2)
# Prepare population initial conditions
# get social contacts data
<- socialmixr::polymod
polymod <- socialmixr::contact_matrix(
contact_data
polymod,countries = "United Kingdom",
age.limits = c(0, 20, 40),
symmetric = TRUE
)
# assume arbitrary populations for each demo group
<- contact_data$demography$population
demography_vector
# prepare contact matrix, divide by leading eigenvalue and rowwise by popsize
<- t(contact_data[["matrix"]])
contact_matrix <- (contact_matrix / max(Re(eigen(contact_matrix)$values))) /
contact_matrix
demography_vector
# an intervention to close schools
<- epidemics::intervention(
close_schools type = "contacts",
time_begin = 200,
time_end = 260,
reduction = base::matrix(c(0.5, 0.01, 0.01))
)
# view the intervention
close_schools#>
#> Intervention name:
#>
#> Begins at:
#> [1] 200
#>
#> Ends at:
#> [1] 260
#>
#> Reduction:
#> Interv. 1
#> Demo. grp. 1 0.50
#> Demo. grp. 2 0.01
#> Demo. grp. 3 0.01
# initial conditions defined as proportions and converted to absolute values
<- base::matrix(
initial_conditions c(S = 1 - 1e-6, E = 0, I = 1e-6, R = 0),
nrow = length(demography_vector),
ncol = 4L, byrow = TRUE
* demography_vector
)
# an intervention to close schools
<- epidemics::intervention(
close_schools type = "contacts",
time_begin = 200,
time_end = 260,
reduction = base::matrix(c(0.15,0.15,0.15))
)
# view the intervention
close_schools#>
#> Intervention name:
#>
#> Begins at:
#> [1] 200
#>
#> Ends at:
#> [1] 260
#>
#> Reduction:
#> Interv. 1
#> Demo. grp. 1 0.15
#> Demo. grp. 2 0.15
#> Demo. grp. 3 0.15
# Define an epidemic SEIR model in {odin}
<- odin::odin({
seir # NOTE: crude time-dependence of transmission rate
# similar to a `<rate_intervention>`
<- if (t > intervention_interval[1] && t < intervention_interval[2]) (1.0 - reduction[i]) else 1
beta_reduce[]
# number of age groups taken from contact matrix passed by user
<- user()
n
# FOI is contacts * infectious * transmission rate
# returns a matrix, must be converted to a vector/1D array
<- C[i, j] * I[j] * beta * beta_reduce[j]* beta_reduce[i]
lambda_prod[, ] #lambda_prod2[, ] <- if (i != j) lambda_prod[i, j] * beta_reduce[i] else lambda_prod[i, j] # if want to keep diagonal the same
<- sum(lambda_prod[i, ])
lambda[]
## Derivatives
deriv(S[]) <- -S[i] * lambda[i]
deriv(E[]) <- (S[i] * lambda[i]) - (nu * E[i])
deriv(I[]) <- (nu * E[i]) - (gamma * I[i])
deriv(R[]) <- gamma * I[i]
## Initial conditions: passed by user
initial(S[]) <- init_S[i]
initial(E[]) <- init_E[i]
initial(I[]) <- init_I[i]
initial(R[]) <- init_R[i]
## parameters
<- user()
beta <- 1 / 3
nu <- 1 / 7
gamma <- user() # user defined contact matrix
C[, ] <- user()
init_S[] <- user()
init_E[] <- user()
init_I[] <- user()
init_R[] <- user()
reduction[] <- user()
intervention_interval[]
# dimensions - all rely on contact matrix
dim(lambda_prod) <- c(n, n)
#dim(lambda_prod2) <- c(n, n)
dim(lambda) <- n
dim(S) <- n
dim(E) <- n
dim(I) <- n
dim(R) <- n
dim(init_S) <- n
dim(init_E) <- n
dim(init_I) <- n
dim(init_R) <- n
dim(reduction) <- n
dim(beta_reduce) <- n
dim(C) <- c(n, n)
dim(intervention_interval) <- 2
})
# Initialise model and run over time 0 - 600
<- seir$new(
mod beta = 1.5 / 7,
reduction = close_schools$reduction[,],
intervention_interval = c(close_schools$time_begin, close_schools$time_end),
C = contact_matrix, n = nrow(contact_matrix),
init_S = initial_conditions[, 1],
init_E = initial_conditions[, 2],
init_I = initial_conditions[, 3],
init_R = initial_conditions[, 4]
)<- seq(0, 600)
t <- mod$run(t)
y
# convert to data.table and plot infectious in each age class
<- as.data.table(y)
y <- melt(y, id.vars = c("t"))
y
ggplot(y[variable %like% "I"]) +
geom_vline(
xintercept = c(close_schools[["time_begin"]], close_schools[["time_end"]]),
colour = "red",
linetype = "dashed",
linewidth = 0.2
+
) annotate(
geom = "text",
label = "Schools closed",
colour = "red",
x = 230, y = 400e3,
angle = 90,
vjust = "outward"
+
) geom_line(
aes(t, value, col = variable)
+
) scale_colour_brewer(
palette = "Dark2",
labels = rownames(contact_matrix),
name = "Age group"
+
) scale_y_continuous(
labels = scales::comma,
name = "Individuals infected"
+
) labs(
x = "Model time (days)"
+
) theme_bw() +
theme(
legend.position = "top"
)
How to use epidemics classes with odin-generated models?
Ingredients
This guide shows how to use some of the convenient features of epidemics, especially the classes that describe populations, interventions, and vaccination regimes, with models that are generated by odin.
This guide shows this interoperability by implementing the default model from epidemics in odin.