The goal of this package is to catalogue, document, and version iterations of the Early Pandemic Age-structured Compartmental model so that they can be pulled easily into project-specific pipelines to produce modelling outputs.
Set up model simulator
To work with a model, we need to set up its simulator. A simulator in
macpan2
is an object that includes model structure (state
names, flow expressions, etc.) along with a set of variable values (such
as components of flow rates, initial states) that ensure it is ready to
produce simulation results.
This package includes several models whose simulators can quickly and
easily be retrieved (see vignette("pkg-models")
). It can
also work with locally defined models (see
vignette("local-models")
).
Package model names can be listed with:
list_models()
#> [1] "five-year-age-groups" "old-and-young"
To get a model’s simulator, we simply call:
model.name <- "old-and-young"
model_simulator <- make_simulator(
model.name = model.name
)
#> Warning in checkMatrixPackageVersion(getOption("TMB.check.Matrix", TRUE)): Package version inconsistency detected.
#> TMB was built with Matrix version 1.6.3
#> Current Matrix version is 1.6.1.1
#> Please re-install 'TMB' from source using install.packages('TMB', type = 'source') or ask CRAN for a binary version of 'TMB' matching CRAN's 'Matrix' package
By default, make_simulator()
will attach a set of
default values for variables in the model (components of flow rates,
initial states, etc.) to the model structure. It will also set a default
number of time steps. You can see all default values easily as
follows:
# load default values (initial state, params, etc.)
default.values = get_default_values(model.name)
The definition of each default value is documented in
vignette("pkg-models")
.
Any of these values can be changed by passing the optional
update.values
argument to make_simulator()
. We
recommend first loading the entire list of default values and extracting
the specific value (list element) that you want to update, editing the
numeric quantity as desired, and then passing the modified list element
to make_simulator()
via the update.values
argument, to ensure that format of value is preserved to remain
compatible with the model definition and macpan2
:
# get default initial state
default.state = default.values$state
print("default state:")
#> [1] "default state:"
print(default.state)
#> S_y R_y E_y I_y H_y D_y S_o R_o
#> 31400000 0 1 1 0 0 6900000 0
#> E_o I_o H_o D_o
#> 1 1 0 0
# move some young susceptibles to the recovered class
new.state = default.state # copy over default value to preserve format
new.state["R_y"] = 1000 # modify specific elements
new.state["S_y"] = new.state["S_y"] - new.state["R_y"] # modify specific elements
print("new state:")
#> [1] "new state:"
print(new.state)
#> S_y R_y E_y I_y H_y D_y S_o R_o
#> 31399000 1000 1 1 0 0 6900000 0
#> E_o I_o H_o D_o
#> 1 1 0 0
# use updated state to make a new simulator
new_model_simulator = make_simulator(
model.name = model.name,
updated.values = list(state = new.state)
)
Simulate a model
To simulate a model, just use the simulate()
function:
sim.output = simulate(model_simulator)
Since the model simulator already has all required values attached, all required calculations can be performed to produce the simulation results.
For all models, simulation outputs are stored in a data frame with columns
time | state_name | value_type | value
The output value_types
are
-
state
: the number of individuals in given state at a given time, -
total_inflow
: the total inflow into a given compartment at a given time.
For instance, here is the number of individuals in each state,
stratified by the two age groups y
(young) and
o
(old), at time 10:
(sim.output
|> dplyr::filter(value_type == 'state', time == 10)
)
#> time state_name value_type value
#> 1 10 S_y state 3.139988e+07
#> 2 10 E_y state 7.888172e+01
#> 3 10 I_y state 2.644023e+01
#> 4 10 H_y state 5.068467e+00
#> 5 10 R_y state 7.329988e+00
#> 6 10 D_y state 7.329988e-01
#> 7 10 S_o state 6.899959e+06
#> 8 10 E_o state 2.621033e+01
#> 9 10 I_o state 9.945527e+00
#> 10 10 H_o state 2.328352e+00
#> 11 10 R_o state 3.674943e+00
#> 12 10 D_o state 3.674943e-01
The total inflow into \(I\) compartments can be used to extract disease incidence by age over time:
(sim.output
|> dplyr::filter(
stringr::str_detect(state_name, "^I"),
value_type == 'total_inflow'
)
|> head()
)
#> time state_name value_type value
#> 1 1 I_y total_inflow 0.1000000
#> 2 1 I_o total_inflow 0.1000000
#> 3 2 I_y total_inflow 0.0990000
#> 4 2 I_o total_inflow 0.0990000
#> 5 3 I_y total_inflow 0.1455143
#> 6 3 I_o total_inflow 0.1195285
We can plot the results using standard data manipulation and plotting
tools, like dplyr
and ggplot2
:
Scenarios
By default, make_simulator()
will initialize a base
model. Some model definitions include optional scenarios on top of the
base model, such as interventions modelled through time-varying model
parameters. For instance, one could simulate a stay-at-home order by
reducing the transmission rate on a given date by some amount.
One can specify the scenario.name
argument in
make_simulator()
to attach the required model structure to
simulate a given scenario type. Scenario options and descriptions are
catalogued in vignette("pkg-models")
.
Here we demonstrate the old-and-young
model with the
transmission-intervention
scenario. By default, this
scenario reduces the transmission rate in each age group to 50% then 10%
of its original value on days 30 and 40, respectively:
values = get_default_values("old-and-young")
values[
c("intervention.day", "trans.factor.young", "trans.factor.old")
]
#> $intervention.day
#> [1] 40 50
#>
#> $trans.factor.young
#> [1] 0.5 0.1
#>
#> $trans.factor.old
#> [1] 0.5 0.1
We specify that we want to use the change-transmission
scenario in the call to make_simulator()
:
model_simulator <- make_simulator(
model.name = "old-and-young",
scenario.name = "change-transmission"
)
sim.output = simulate(model_simulator)