# Construct a multistrata RUME
import matplotlib.pyplot as plt
import numpy as np
from sympy import Max
from epymorph.kit import *
from epymorph.adrio import acs5, us_tiger
class MyRume(MultiStrataRUMEBuilder):
= [
strata
GPM(="age_00-19",
name=ipm.SIRS(),
ipm=mm.No(),
mm=init.NoInfection(),
init
),
GPM(="age_20-59",
name=ipm.SIRS(),
ipm=mm.No(),
mm=init.SingleLocation(location=0, seed_size=100),
init
),
GPM(="age_60-79",
name=ipm.SIRS(),
ipm=mm.No(),
mm=init.NoInfection(),
init
),
]
= [
meta_requirements "beta_12", float, Shapes.TxN),
AttributeDef("beta_13", float, Shapes.TxN),
AttributeDef("beta_21", float, Shapes.TxN),
AttributeDef("beta_23", float, Shapes.TxN),
AttributeDef("beta_31", float, Shapes.TxN),
AttributeDef("beta_32", float, Shapes.TxN),
AttributeDef(
]
def meta_edges(self, symbols: MultiStrataModelSymbols) -> list[TransitionDef]:
# extract compartment symbols by strata
= symbols.strata_compartments("age_00-19")
S_1, I_1, R_1 = symbols.strata_compartments("age_20-59")
S_2, I_2, R_2 = symbols.strata_compartments("age_60-79")
S_3, I_3, R_3
# extract compartment totals by strata
= Max(1, S_1 + I_1 + R_1)
N_1 = Max(1, S_2 + I_2 + R_2)
N_2 = Max(1, S_3 + I_3 + R_3)
N_3
# extract meta attributes
= (
beta_12, beta_13, beta_21, beta_23, beta_31, beta_32
symbols.all_meta_requirements
)
return [
=S_1 * beta_12 * I_2 / N_2), # 2 infects 1
edge(S_1, I_1, rate=S_1 * beta_13 * I_3 / N_3), # 3 infects 1
edge(S_1, I_1, rate=S_2 * beta_21 * I_1 / N_1), # 1 infects 2
edge(S_2, I_2, rate=S_2 * beta_23 * I_3 / N_3), # 3 infects 2
edge(S_2, I_2, rate=S_3 * beta_31 * I_1 / N_1), # 1 infects 3
edge(S_3, I_3, rate=S_3 * beta_32 * I_2 / N_2), # 2 infects 3
edge(S_3, I_3, rate ]
Multi-strata Models with Multiple Movement Models
SCENARIO:
Exercise 1
= StateScope.in_states(["AZ"], year=2020)
single_scope
= MyRume().build(
rume =single_scope,
scope=TimeFrame.of("2020-01-01", 180),
time_frame={
params# IPM params
"gpm:age_00-19::ipm::beta": 0.05,
"gpm:age_20-59::ipm::beta": 0.20,
"gpm:age_60-79::ipm::beta": 0.35,
"*::ipm::gamma": 1 / 10,
"*::ipm::xi": 1 / 90,
"meta::ipm::beta_12": 0.05,
"meta::ipm::beta_13": 0.05,
"meta::ipm::beta_21": 0.20,
"meta::ipm::beta_23": 0.20,
"meta::ipm::beta_31": 0.35,
"meta::ipm::beta_32": 0.35,
# ADRIOs for population by age
"*::*::population_by_age_table": acs5.PopulationByAgeTable(),
"gpm:age_00-19::*::population": acs5.PopulationByAge(0, 19),
"gpm:age_20-59::*::population": acs5.PopulationByAge(20, 59),
"gpm:age_60-79::*::population": acs5.PopulationByAge(60, 79),
}, )
rume.ipm.diagram()
= BasicSimulator(rume)
sim with sim_messaging(live=False):
= sim.run(
out =default_rng(2)
rng_factory )
Loading gpm:age_00-19::init::population_by_age_table (epymorph.adrio.acs5.PopulationByAgeTable):
|####################| 100% (11.126s)
Loading gpm:age_00-19::init::population (epymorph.adrio.acs5.PopulationByAge):
|####################| 100% (0.000s)
Loading gpm:age_20-59::init::population (epymorph.adrio.acs5.PopulationByAge):
|####################| 100% (0.000s)
Loading gpm:age_60-79::init::population (epymorph.adrio.acs5.PopulationByAge):
|####################| 100% (0.000s)
Running simulation (BasicSimulator):
• 2020-01-01 to 2020-06-28 (180 days)
• 1 geo nodes
|####################| 100%
Runtime: 0.100s
out.plot.line(=out.rume.scope.select.all(),
geo=out.rume.time_frame.select.all(),
time=out.rume.ipm.select.compartments("I*"),
quantity="Compartment values per strata",
title )
out.plot.line(=out.rume.scope.select.all(),
geo=out.rume.time_frame.select.all(),
time=out.rume.ipm.select.compartments("*_age_00-19"),
quantity="Compartment values for youngest strata",
title )
Exercise 2
class MyRume(MultiStrataRUMEBuilder):
= [
strata
GPM(="age_00-19",
name=ipm.SIRS(),
ipm=mm.No(),
mm=init.NoInfection(),
init
),
GPM(="age_20-59",
name=ipm.SIRS(),
ipm=mm.No(),
mm=init.SingleLocation(location=0, seed_size=100),
init
),
GPM(="age_60-79",
name=ipm.SIRH(),
ipm=mm.No(),
mm=init.NoInfection(),
init
),
]
= [
meta_requirements "beta_12", float, Shapes.TxN),
AttributeDef("beta_13", float, Shapes.TxN),
AttributeDef("beta_21", float, Shapes.TxN),
AttributeDef("beta_23", float, Shapes.TxN),
AttributeDef("beta_31", float, Shapes.TxN),
AttributeDef("beta_32", float, Shapes.TxN),
AttributeDef(
]
def meta_edges(self, symbols: MultiStrataModelSymbols) -> list[TransitionDef]:
# extract compartment symbols by strata
= symbols.strata_compartments("age_00-19")
S_1, I_1, R_1 = symbols.strata_compartments("age_20-59")
S_2, I_2, R_2 = symbols.strata_compartments("age_60-79")
S_3, I_3, R_3, H_3
# extract compartment totals by strata
= Max(1, S_1 + I_1 + R_1)
N_1 = Max(1, S_2 + I_2 + R_2)
N_2 = Max(1, S_3 + I_3 + R_3 + H_3)
N_3
# extract meta attributes
= (
beta_12, beta_13, beta_21, beta_23, beta_31, beta_32
symbols.all_meta_requirements
)
return [
=S_1 * beta_12 * I_2 / N_2), # 2 infects 1
edge(S_1, I_1, rate=S_1 * beta_13 * I_3 / N_3), # 3 infects 1
edge(S_1, I_1, rate=S_2 * beta_21 * I_1 / N_1), # 1 infects 2
edge(S_2, I_2, rate=S_2 * beta_23 * I_3 / N_3), # 3 infects 2
edge(S_2, I_2, rate=S_3 * beta_31 * I_1 / N_1), # 1 infects 3
edge(S_3, I_3, rate=S_3 * beta_32 * I_2 / N_2), # 2 infects 3
edge(S_3, I_3, rate ]
= MyRume().build(
rume =single_scope,
scope=TimeFrame.of("2020-01-01", 180),
time_frame={
params# IPM params
"gpm:age_00-19::ipm::beta": 0.05,
"gpm:age_20-59::ipm::beta": 0.20,
"gpm:age_60-79::ipm::beta": 0.35,
"*::ipm::gamma": 1 / 10,
"*::ipm::xi": 1 / 90,
"meta::ipm::beta_12": 0.05,
"meta::ipm::beta_13": 0.05,
"meta::ipm::beta_21": 0.20,
"meta::ipm::beta_23": 0.20,
"meta::ipm::beta_31": 0.35,
"meta::ipm::beta_32": 0.35,
# SIRH IPM
"gpm:age_60-79::ipm::hospitalization_prob": 0.1,
"gpm:age_60-79::ipm::hospitalization_duration": 7.0,
# ADRIO
"*::*::population_by_age_table": acs5.PopulationByAgeTable(),
"gpm:age_00-19::*::population": acs5.PopulationByAge(0, 19),
"gpm:age_20-59::*::population": acs5.PopulationByAge(20, 59),
"gpm:age_60-79::*::population": acs5.PopulationByAge(60, 79),
}, )
rume.ipm.diagram()
= BasicSimulator(rume)
sim with sim_messaging(live=False):
= sim.run(
out =default_rng(2)
rng_factory )
Loading gpm:age_00-19::init::population_by_age_table (epymorph.adrio.acs5.PopulationByAgeTable):
|####################| 100% (0.551s)
Loading gpm:age_00-19::init::population (epymorph.adrio.acs5.PopulationByAge):
|####################| 100% (0.000s)
Loading gpm:age_20-59::init::population (epymorph.adrio.acs5.PopulationByAge):
|####################| 100% (0.000s)
Loading gpm:age_60-79::init::population (epymorph.adrio.acs5.PopulationByAge):
|####################| 100% (0.000s)
Running simulation (BasicSimulator):
• 2020-01-01 to 2020-06-28 (180 days)
• 1 geo nodes
|####################| 100%
Runtime: 0.107s
out.plot.line(=out.rume.scope.select.all(),
geo=out.rume.time_frame.select.all(),
time=out.rume.ipm.select.compartments("*_age_60-79"),
quantity="Compartment values for elder strata",
title )
Exercise 3
In this most complicated example, we’re going to create a multi-strata simulation across multiple nodes, with multiple IPM, and with multiple movement models.
from epymorph.data.mm.pei import Pei as CommuterMM
class MyRume(MultiStrataRUMEBuilder):
= [
strata
GPM(="age_00-19",
name=ipm.SIRS(),
ipm=mm.Centroids(),
mm=init.NoInfection(),
init
),
GPM(="age_20-59",
name=ipm.SIRS(),
ipm=mm.Centroids(),
mm=init.SingleLocation(location=0, seed_size=100),
init
),
GPM(="age_60-79",
name=ipm.SIRH(),
ipm=CommuterMM(),
mm=init.NoInfection(),
init
),
]
= [
meta_requirements "beta_12", float, Shapes.TxN),
AttributeDef("beta_13", float, Shapes.TxN),
AttributeDef("beta_21", float, Shapes.TxN),
AttributeDef("beta_23", float, Shapes.TxN),
AttributeDef("beta_31", float, Shapes.TxN),
AttributeDef("beta_32", float, Shapes.TxN),
AttributeDef(
]
def meta_edges(self, symbols: MultiStrataModelSymbols) -> list[TransitionDef]:
# extract compartment symbols by strata
= symbols.strata_compartments("age_00-19")
S_1, I_1, R_1 = symbols.strata_compartments("age_20-59")
S_2, I_2, R_2 = symbols.strata_compartments("age_60-79")
S_3, I_3, R_3, H_3
# extract compartment totals by strata
= Max(1, S_1 + I_1 + R_1)
N_1 = Max(1, S_2 + I_2 + R_2)
N_2 = Max(1, S_3 + I_3 + R_3 + H_3)
N_3
# extract meta attributes
= (
beta_12, beta_13, beta_21, beta_23, beta_31, beta_32
symbols.all_meta_requirements
)
return [
=S_1 * beta_12 * I_2 / N_2), # 2 infects 1
edge(S_1, I_1, rate=S_1 * beta_13 * I_3 / N_3), # 3 infects 1
edge(S_1, I_1, rate=S_2 * beta_21 * I_1 / N_1), # 1 infects 2
edge(S_2, I_2, rate=S_2 * beta_23 * I_3 / N_3), # 3 infects 2
edge(S_2, I_2, rate=S_3 * beta_31 * I_1 / N_1), # 1 infects 3
edge(S_3, I_3, rate=S_3 * beta_32 * I_2 / N_2), # 2 infects 3
edge(S_3, I_3, rate ]
from epymorph.adrio import lodes
= StateScope.in_states(["AZ", "NM", "CO", "UT"], year=2020)
multi_scope
= MyRume().build(
rume =multi_scope,
scope=TimeFrame.of("2020-01-01", 180),
time_frame={
params# IPM params
"gpm:age_00-19::ipm::beta": 0.05,
"gpm:age_20-59::ipm::beta": 0.20,
"gpm:age_60-79::ipm::beta": 0.35,
"*::ipm::gamma": 1 / 10,
"*::ipm::xi": 1 / 90,
"meta::ipm::beta_12": 0.05,
"meta::ipm::beta_13": 0.05,
"meta::ipm::beta_21": 0.20,
"meta::ipm::beta_23": 0.20,
"meta::ipm::beta_31": 0.35,
"meta::ipm::beta_32": 0.35,
# SIRH IPM
"gpm:age_60-79::ipm::hospitalization_prob": 0.1,
"gpm:age_60-79::ipm::hospitalization_duration": 7.0,
# MM params
"gpm:age_00-19::mm::phi": 20.0,
"gpm:age_20-59::mm::phi": 40.0,
"gpm:age_60-79::mm::move_control": 0.9,
"gpm:age_60-79::mm::theta": 0.1,
"gpm:age_60-79::mm::commuters": lodes.CommutersByAge("55 and Over"),
# ADRIO
"*::*::centroid": us_tiger.InternalPoint(),
"*::*::population_by_age_table": acs5.PopulationByAgeTable(),
"gpm:age_00-19::*::population": acs5.PopulationByAge(0, 19),
"gpm:age_20-59::*::population": acs5.PopulationByAge(20, 59),
"gpm:age_60-79::*::population": acs5.PopulationByAge(60, 79),
}, )
print(rume.params_description())
gpm:age_00-19::ipm::beta (type: float, shape: TxN)
infectivity
gpm:age_00-19::ipm::gamma (type: float, shape: TxN)
progression from infected to recovered
gpm:age_00-19::ipm::xi (type: float, shape: TxN)
progression from recovered to susceptible
gpm:age_20-59::ipm::beta (type: float, shape: TxN)
infectivity
gpm:age_20-59::ipm::gamma (type: float, shape: TxN)
progression from infected to recovered
gpm:age_20-59::ipm::xi (type: float, shape: TxN)
progression from recovered to susceptible
gpm:age_60-79::ipm::beta (type: float, shape: TxN)
infectivity
gpm:age_60-79::ipm::gamma (type: float, shape: TxN)
recovery rate
gpm:age_60-79::ipm::xi (type: float, shape: TxN)
immune waning rate
gpm:age_60-79::ipm::hospitalization_prob (type: float, shape: TxN)
a ratio of cases which are expected to require hospitalization
gpm:age_60-79::ipm::hospitalization_duration (type: float, shape: TxN)
the mean duration of hospitalization, in days
meta::ipm::beta_12 (type: float, shape: TxN)
meta::ipm::beta_13 (type: float, shape: TxN)
meta::ipm::beta_21 (type: float, shape: TxN)
meta::ipm::beta_23 (type: float, shape: TxN)
meta::ipm::beta_31 (type: float, shape: TxN)
meta::ipm::beta_32 (type: float, shape: TxN)
gpm:age_00-19::mm::population (type: int, shape: N)
The total population at each node.
gpm:age_00-19::mm::centroid (type: [(longitude, float), (latitude, float)], shape: N)
The centroids for each node as (longitude, latitude) tuples.
gpm:age_00-19::mm::phi (type: float, shape: S, default: 40.0)
Influences the distance that movers tend to travel.
gpm:age_00-19::mm::commuter_proportion (type: float, shape: S, default: 0.1)
The proportion of the total population which commutes.
gpm:age_00-19::init::population (type: int, shape: N)
The population at each geo node.
gpm:age_20-59::mm::population (type: int, shape: N)
The total population at each node.
gpm:age_20-59::mm::centroid (type: [(longitude, float), (latitude, float)], shape: N)
The centroids for each node as (longitude, latitude) tuples.
gpm:age_20-59::mm::phi (type: float, shape: S, default: 40.0)
Influences the distance that movers tend to travel.
gpm:age_20-59::mm::commuter_proportion (type: float, shape: S, default: 0.1)
The proportion of the total population which commutes.
gpm:age_20-59::init::population (type: int, shape: N)
The population at each geo node.
gpm:age_60-79::mm::commuters (type: int, shape: NxN)
A node-to-node commuters marix.
gpm:age_60-79::mm::move_control (type: float, shape: S, default: 0.9)
A factor which modulates the number of commuters by conducting a
binomial draw with this probability and the expected commuters
from the commuters matrix.
gpm:age_60-79::mm::theta (type: float, shape: S, default: 0.1)
A factor which allows for randomized movement by conducting a
poisson draw with this factor times the average number of
commuters between two nodes from the commuters matrix.
gpm:age_60-79::init::population (type: int, shape: N)
The population at each geo node.
= BasicSimulator(rume)
sim with sim_messaging(live=False):
= sim.run() out
Loading gpm:age_00-19::mm::population_by_age_table (epymorph.adrio.acs5.PopulationByAgeTable):
|####################| 100% (0.571s)
Loading gpm:age_00-19::mm::population (epymorph.adrio.acs5.PopulationByAge):
|####################| 100% (0.000s)
Loading gpm:age_00-19::mm::centroid (epymorph.adrio.us_tiger.InternalPoint):
|####################| 100% (1.641s)
Loading gpm:age_20-59::mm::population (epymorph.adrio.acs5.PopulationByAge):
|####################| 100% (0.000s)
Loading gpm:age_60-79::mm::commuters (epymorph.adrio.lodes.CommutersByAge):
|####################| 100% (40.104s)
Loading gpm:age_60-79::init::population (epymorph.adrio.acs5.PopulationByAge):
|####################| 100% (0.000s)
Running simulation (BasicSimulator):
• 2020-01-01 to 2020-06-28 (180 days)
• 4 geo nodes
|####################| 100%
Runtime: 0.771s
out.plot.line(=out.rume.scope.select.all(),
geo=out.rume.time_frame.select.all().group("day").agg(),
time=out.rume.ipm.select.compartments(),
quantity="",
title="outside",
legend )
out.table.quantiles(=[0.025, 0.5, 0.975],
quantiles=out.rume.scope.select.all(),
geo=out.rume.time_frame.select.all(),
time=out.rume.ipm.select.all(),
quantity )
geo | quantity | other strata | 0.025 | 0.5 | 0.975 | |
---|---|---|---|---|---|---|
0 | AZ | S_age_00-19 | 619660.125 | 849743.0 | 1836807.325 | |
1 | AZ | I_age_00-19 | 41.825 | 94596.5 | 503575.450 | |
2 | AZ | R_age_00-19 | 7.850 | 889452.5 | 1058452.825 | |
3 | AZ | S_age_20-59 | 175365.450 | 669430.5 | 3646494.525 | |
4 | AZ | I_age_20-59 | 405.400 | 298161.5 | 1761381.350 | |
... | ... | ... | ... | ... | ... | ... |
103 | UT | S_age_00-19 → I_age_00-19 | age_60-79 | 0.000 | 869.5 | 9021.100 |
104 | UT | S_age_20-59 → I_age_20-59 | age_00-19 | 0.000 | 1124.0 | 7054.350 |
105 | UT | S_age_20-59 → I_age_20-59 | age_60-79 | 0.000 | 1934.0 | 28810.725 |
106 | UT | S_age_60-79 → I_age_60-79 | age_00-19 | 0.000 | 314.5 | 1849.100 |
107 | UT | S_age_60-79 → I_age_60-79 | age_20-59 | 0.000 | 493.5 | 5714.625 |
108 rows × 6 columns
map.choropleth(
out.=out.rume.scope.select.all(),
geo=out.rume.time_frame.select.all().agg(events="sum"),
time=out.rume.ipm.select.events("I*->H*"),
quantity )