- Overview
- Basic Structure
- Calculating R0 with the Next Generation Matrix
- Single-Population SEIR Model Example
- Getting Simulation Output
- Metapopulation SEIR Model Example
ModularEpi is a Python framework to create compartmental epidemiological models and run simulations on them. The framework includes support for both single-population and metapopulation models, and implements the Next Generation Matrix method to compute R0 for models.
The framework uses 5 basic object types to create CompartmentalModel
objects:
-
DiseaseCompartment
A
DiseaseCompartment
is compartment in a model that contains individuals. For example, our model may include Infectious, Exposed, and RemovedDiseaseCompartment
s.To add a
DiseaseCompartment
to theCompartmentalModel
model
, we callmodel.add_disease_compartment(name, initial_value, self_param=self_parameter)
where
name
is a string that is the (unique) name of the compartment,intial_value
is the initial occupancy of the compartment, andself_parameter
is a tuple of the formself_parameter = (self_param_name, self_param_value)
where the occupancy of the compartment changes by the self parameter's value on each day, for example, as a birth or death rate. By default, a
DiseaseCompartment
's self parameter has no name and has a value of 0. -
SusceptibleCompartment
A
SusceptibleCompartment
is aDiseaseCompartment
that contains susceptible individuals.To add a
SusceptibleCompartment
tomodel
, we callmodel.add_susceptible_comaprtment(name, initial_value, N, self_param=self_parameter)
where
N
is the total size of thisSusceptibleCompartment
's associated population. -
Transition
A
Transition
connects two compartments and has an associatedParameter
. It indicates that individuals should transition from one of these compartments to the other based on the given parameter value.To add a transition to our model between, for example, the
DiseaseCompartments
with names'E'
and'I'
, we call:model.add_transition('E', 'I', rate_parameter)
where
rate_parameter
is a tuple of the formrate_parameter = (parameter_name, parameter_value)
indicating the rate of transition between the compartments.
We can additionally add multiple transitions out of one compartment, or multiple into another compartment.
-
Transmission
A
Transmission
connects aSusceptibleCompartment
and aDiseaseCompartment
with an associatedParameter
and indicates that individuals in the givenSusceptibleCompartment
are infected by individuals in the givenDiseaseCompartment
at the rate given by the parameter value.To add a
Transmission
tomodel
, say where theSusceptibleCompartment
with name'S'
is infected by theDiseaseCompartment
with name'I'
and then transitions to a compartment with name'E'
, we have to add both aTransmission
and a special type ofTransition
called atransition_at_infection
:model.add_transmission('S', 'I', N, transmission_parameter) model.add_transition_at_infection('S', 'E', proportion_parameter)
The
transmission_parameter
is a tuple (in the form of the other parameter tuples) where the rate value indicates the baseline transmission rate of'I'
onto'S'
. Theproportion_parameter
's value indicates the proportion of infected individuals at each timesetp that should transition to'E'
. By default, this proportion is 1, but if we would like to implement multiple types of exposed compartments such that infected individuals transition into each of them with chosen probabilities, we can add multiple exposed compartments and multiple transitions at infection.
To calculate R0 for a CompartmentalModel
model
, we create a new NGM
object from the model:
from modularepi.ngm import NGM
model_ngm = NGM(model)
R0 = model_ngm.R0()
Below is an example implementation for a simple closed-system SEIR model with no births or deaths. In this case, beta_val
is the transmission rate, sigma_val
the rate of transition from the exposed compartment 'E'
to the infectious compartment 'I'
, and gamma_val
the recovery/removal rate from 'I'
to the removed compartment 'R'
.
from modularepi.model import CompartmentalModel
from modularepi.ngm import NGM
# Simulation parameters.
POP_SIZE = 1000
SIMULATION_DAYS = 365
ITERATIONS_PER_DAY = 24 # Simulation iterations per day.
INIT_INFECTIOUS_POP = 1
# Model parameters.
BETA_VAL = 0.3
SIGMA_VAL = 0.5
GAMMA_VAL = 0.1
seir_model = CompartmentalModel(SIMULATION_DAYS, ITERATIONS_PER_DAY)
# Add the compartments.
seir_model.add_susceptible_compartment('S', init_val=POP_SIZE-INIT_INFECTIOUS_POP, N=POP_SIZE)
seir_model.add_disease_compartment('E')
seir_model.add_disease_compartment('I', init_val=INIT_INFECTIOUS_POP)
seir_model.add_disease_compartment('R')
# Add the transitions and transmissions.
seir_model.add_transmission('S', 'I', POP_SIZE, ('beta', BETA_VAL))
seir_model.add_transition_at_infection('S', 'E')
seir_model.add_transition('E', 'I', ('sigma', SIGMA_VAL))
seir_model.add_transition('I', 'R', ('gamma', GAMMA_VAL))
# Run the model.
seir_model.run()
# Calculate and print the model's R0 with the Next Generation Matrix (NGM).
seir_ngm = NGM(seir_model)
print(seir_ngm.R0())
The code for this example is provided in seir_example.py
.
We can receive three types of simulation results from a model:
- Current compartment values on each day via
model.get_current_metrics()
- Incident compartment values on each day (i.e., the change in a compartment's value on each day) via
model.get_incidence()
- Cumulative compartment values on each day via
model.get_cumulative()
All three methods return a dictionary with keys as compartment names and values as arrays with the type of metric's value at each day (given by the array index).
In a metapopulation model, we consider c different metapopulations that follow the same disease progression but with different parameters. These metapopulations can infect each other (and themselves) at rates specified in the model. The below example is an SEIR model with two metapopulations (children and adults); each metapopulation infects itself and the other as specified by the mixing matrix, which gives the relative contact rates among and between groups, and each metapopulation progresses through the disease at different rates.
The example code can be found in seir_metapopulation_example.py
.
from modularepi.metapopulationmodel import MetapopulationModel
from modularepi.ngm import NGM
# For all arrays, index 0 is children, index 1 is adults.
NUM_POPS = 2
POP_SIZES = [200, 1000]
SIMULATION_DAYS = 365
ITERATIONS_PER_DAY = 24 # Simulation iterations per day.
INIT_INFECTIOUS = [5, 20]
INIT_SUSCEPTIBLE = [POP_SIZES[0]-INIT_INFECTIOUS[0],
POP_SIZES[1]-INIT_INFECTIOUS[1]]
# Model parameters.
BETA_VAL = 0.3 # Baseline transmission rate is one parameter. Individual
# group-to-group contact rates are controleld by the mixing matrix.
SIGMA_VALS = [0.1, 0.3]
GAMMA_VALS = [0.2, 0.1]
# The mixing matrix gives the relative contact rates between each pair of
# groups.
MIXING_MATRIX = [
[1.5, 1.2],
[0.6, 1.0]]
seir_metapopulation_model = MetapopulationModel(NUM_POPS, SIMULATION_DAYS,
ITERATIONS_PER_DAY)
# Add the compartments.
seir_metapopulation_model.add_susceptible_compartment('S', INIT_SUSCEPTIBLE,
POP_SIZES)
seir_metapopulation_model.add_disease_compartment('E')
seir_metapopulation_model.add_disease_compartment('I',
init_vals=INIT_INFECTIOUS)
seir_metapopulation_model.add_disease_compartment('R')
# Add the transitions and transmissions.
seir_metapopulation_model.add_transmission('S', 'I', POP_SIZES,
('beta', BETA_VAL),
MIXING_MATRIX)
seir_metapopulation_model.add_transition_at_infection('S', 'E')
seir_metapopulation_model.add_transition('E', 'I', ('sigma', SIGMA_VALS))
seir_metapopulation_model.add_transition('I', 'R', ('gamma', GAMMA_VALS))
# Run the model.
seir_metapopulation_model.run()