configuration - CDCgov/DynODE GitHub Wiki
DynODE Configuration Module
The DynODE configuration module defines the structure and validation logic for compartmental ODE models. It provides a flexible, type-safe way to specify model compartments, their dimensions, and the bins (states) within each dimension. This documentation covers the core classes: SimulationConfig
, Compartment
, Dimension
, and Bin
.
Lets start with a visual representation of the configuration structure, then go into each class in detail.
Visual Representation
classDiagram
class SimulationConfig {
+list~Compartment~ compartments
+Params parameters
+Initializer initializer
+NameSpace idx
+get_compartment(name)
+flatten_bins() list~Bin~
+flatten_dims() list~Dimension~
}
class Compartment {
+str name
+list~Dimension~ dimensions
+tuple~int~ shape
+NameSpace idx
}
class Dimension {
+str name
+list~Bin~ bins
+__len__()
+idx
}
class Bin {
+str name
}
class Params {
+SolverParams solver_params
+TransmissionParams transmission_params
}
class SolverParams {
+Object solver_method
+float ode_solver_rel_tolerance
+float ode_solver_abs_tolerance
+int max_steps
+float constant_step_size
+list~float~ discontinuity_points
}
class TransmissionParams {
+list~Strain~ strains
+dict strain_interactions
+contact_matrix
}
class Strain {
+str strain_name
+r0
+infectious_period
}
class Initializer {
+str description
+float population_size
+date initialize_date
+get_initial_state() CompartmentState
}
SimulationConfig --> Compartment
SimulationConfig --> Params
SimulationConfig --> Initializer
Compartment --> Dimension
Dimension --> Bin
Params --> SolverParams
Params --> TransmissionParams
TransmissionParams --> Strain
Bin
A Bin
represents a single discrete state within a dimension. This could be an age group, vaccination status, or any other stratifying factor.
Key Fields:
name
: Unique name for the bin within its dimension.
Specialized Bins:
DiscretizedPositiveIntBin
: Bin with inclusive integer min/max values (e.g., for age or dose count).AgeBin
: SpecializedDiscretizedPositiveIntBin
for age groups, with auto-generated names.WaneBin
: Bin for waning immunity, with fields for waiting time and base protection.
Validation:
- For discretized bins, ensures
min_value <= max_value
.
Dimension
A Dimension
defines an axis of stratification within a compartment (e.g., age, vaccination, immune history).
Key Fields:
name
: Unique name for the dimension within a compartment.bins
: List ofBin
objects representing the discrete states along this dimension.
Key Methods:
__len__
: Number of bins in the dimension..idx
: Property returning a namespace mapping bin names to their indices within thebins
list.
Validation:
- All bins must be of the same type and have unique names.
- For
DiscretizedPositiveIntBin
-based dimensions, bins must be sorted in increasing order, non-overlapping, and gapless.
Specialized Dimensions:
VaccinationDimension
: For ordinal and seasonal vaccination tracking.ImmuneHistoryDimension
,FullStratifiedImmuneHistoryDimension
,LastStrainImmuneHistoryDimension
: For tracking infection history.WaneDimension
: For tracking waning immunity with custom waiting times and protection levels.
Compartment
A Compartment
represents a single population group or state in the model, defined by a set of stratifying dimensions (e.g., age, vaccination status).
Key Fields:
name
: Unique name for the compartment.dimensions
: List ofDimension
objects defining the axes of the compartment.
Key Methods:
.shape
: Returns the shape of the compartment (tuple of bin counts per dimension)..idx
: Cached property for enum-like access to dimension and bin indices.
Validation:
- Ensures all dimension names are unique within the compartment.
Initializer
An Initializer
defines how the initial state of the model is set up. It can be a simple constant value, or more complex initialization logic. The logic itself is defined mostly in the get_initial_state()
method, which must be implemented by subclasses.
Key Fields:
description
: A human-readable description of the initializer, its data sources, and intended initialization date range.initialize_date
: The date at which the model should be initialized.population_size
: The total population size to distribute across compartments at initialization.
Key Methods:
get_initial_state(**kwargs)
: Abstract method to generate the initial compartment state, ensuring values sum topopulation_size
. Must be implemented by subclasses.
Validation:
- Ensures
population_size
is a positive integer. - Enforces implementation of
get_initial_state()
in subclasses.
Params: SolverParams
SolverParams
specifies the configuration for the ODE solver used in simulations.
Key Fields:
solver_method
: The ODE solver algorithm (e.g.,Tsit5
). Defaults to a general-purpose, non-stiff solver.ode_solver_rel_tolerance
/ode_solver_abs_tolerance
: Relative and absolute tolerances for adaptive step size control.max_steps
: Maximum number of steps the solver will take before raising an error.constant_step_size
: If nonzero, uses a fixed step size; otherwise, adaptive stepping is used.discontinuity_points
: List of time points where the system has known discontinuities (e.g., intervention changes).
Validation:
- Ensures all solver parameters are positive and consistent with solver requirements.
Params: TransmissionParams
TransmissionParams
defines the structure for transmission-related parameters, especially for models with multiple pathogen strains.
Key Fields:
strain_interactions
: Nested dictionary specifying interaction parameters between strains (e.g., cross-immunity, competition). Keys are strain names; values are dictionaries mapping other strain names to interaction values or distributions.strains
: List ofStrain
objects, each representing a pathogen variant or lineage.
Validation:
- Ensures the
strains
list is not empty. - Validates that
strain_interactions
covers all strains and is symmetric (all strains interact with all others, including themselves). - Checks that certain optional fields (e.g.,
exposed_to_infectious
,vaccine_efficacy
) are either set for all strains or none, and that introduction ages are consistent across strains.
Params
The Params
class is a container for all model parameters, grouping together SolverParams
and TransmissionParams
.
SimulationConfig
SimulationConfig
is the top-level configuration object for a DynODE model. It encapsulates the entire model structure, including compartments, parameters, and initialization logic.
Key Fields:
initializer
: AnInitializer
object specifying how the initial state is created.compartments
: A list ofCompartment
objects, each representing a population or state group. Think of these objects as a wireframe for the compartments in the model, but are not the values themselves.parameters
: AParams
object containing model parameters.
Key Methods:
get_compartment(name)
: Retrieve a compartment by name.flatten_bins()
: Returns a flat list of all bins in all compartments.flatten_dims()
: Returns a flat list of all dimensions in all compartments.
Validation:
- Ensures unique compartment names.
- Ensures dimensions with the same name across compartments are structurally identical.
- Validates immune history dimensions and strain introduction logic.
Indexing:
.idx
property provides a cached, enum-like namespace for programmatic access to compartments and their dimensions/bins. This enum is recursive, meaningconfig.idx.s
will return the index of thes
compartment withinconfig.compartments
, but you can also accessconfig.idx.s.age
to get the index of theage
dimension within thes
compartment, and furthermoreconfig.idx.s.age.under_5
to get the index of theunder_5
bin within theage
dimension of thes
compartment.
Example
lets define a simple SIR model with a single strain and a simple initializer. This example is repeated in the examples/sir.py
file, but is included here for completeness.
from dynode.config import (
SimulationConfig,
Compartment,
Dimension,
AgeBin,
Params,
SolverParams,
TransmissionParams,
Strain,
Initializer,
)
import jax.numpy as jnp
from datetime import date
# --- SIR Initializer with age stratification ---
class SIRInitializer(Initializer):
"""Initializer for SIR model, setting initial conditions for compartments."""
def __init__(self):
"""Create an SIR Initializer."""
super().__init__(
description="An SIR initalizer",
initialize_date=date(2022, 2, 11), # random date
population_size=1000,
)
def get_initial_state(
self, s0_prop=0.99, i0_prop=0.01, **kwargs
) -> CompartmentState:
"""Get initial compartment values for an SIR model stratified by age."""
assert s0_prop + i0_prop == 1.0, (
"s0_prop and i0_prop must sum to 1.0, "
f"got {s0_prop} and {i0_prop}."
)
# proportion of young to old in the population
age_demographics = jnp.array([0.75, 0.25])
num_susceptibles = self.population_size * jnp.array([s0_prop])
s_0 = num_susceptibles * age_demographics
num_infectious = self.population_size * jnp.array([i0_prop])
i_0 = num_infectious * age_demographics
r_0 = jnp.array([0.0, 0.0])
# SimulationConfig has no impact on initial state in this example
return (s_0, i_0, r_0)
# --- SIRConfig for bin definitions and strain specification---
dimension = Dimension(
name="age", bins=[Bin(name="young"), Bin(name="old")]
)
s = Compartment(name="s", dimensions=[dimension])
i = Compartment(name="i", dimensions=[dimension])
r = Compartment(name="r", dimensions=[dimension])
strain = [
Strain(strain_name="swo9", r0=r_0, infectious_period=infectious_period)
]
contact_matrix = jnp.array([0.7, 0.3], [0.3, 0.7](/CDCgov/DynODE/wiki/0.7,-0.3],-[0.3,-0.7))
parameters = Params(
solver_params=SolverParams(),
transmission_params=TransmissionParams(
strains=strain,
strain_interactions={"swo9": {"swo9": 1.0}},
contact_matrix=contact_matrix,
),
)
config = SimulationConfig(
compartments=[s, i, r],
initializer=SIRInitializer(),
parameters=parameters,
)
For further details, see the docstrings in each class and the validation logic in the source files.