Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

laser-typhoid

Typhoid SEIRC — a spatial agent-based model with a small chronic-carrier compartment (~3% of survivors) that sustains endemic typhoid alongside acute transmission, plus a spatial sanitation intervention targeted at carrier-mediated transmission (urban patches only). Historical parallel: early 20th-century US water treatment infrastructure was urban-first, leaving rural typhoid endemic for decades longer.

Status: prototype; not calibrated to any real-world dataset. Parameters were chosen from published typhoid literature (Pitzer 2014, Antillón 2017, Ames & Robins 1943), then subjected to a 1D per-parameter sensitivity sweep — see sensitivity/SENSITIVITY.md.

What this model shows

A small chronic-carrier compartment (~3% of survivors) sustains endemic typhoid alongside acute transmission. Water & food sanitation targeted at carrier-mediated transmission produces a substantial but not-complete reduction in incidence.

Compartments and flows:

S -> E -> I -> R      (97% of acute cases; immunity wanes over ~6 yr)
          I -> C      (3% become chronic biliary carriers, shedding for decades)
R -> S               (waning immunity)
C -> R               (rare natural clearance)

Force of infection carries a reduced-weight carrier contribution:

λ(t) = β · (I(t) + α(t) · C(t)) / N(t)

where α is the shedding intensity ratio — carriers shed roughly 5% of what acute cases do. The sanitation intervention drops α from ALPHA_BASELINE to ALPHA_AFTER at year SANITATION_START_YEAR in the urban core + ring only (13 patches out of 25). Rural patches keep α_baseline.

Gallery

Fiji (admin-1, 5 divisions, ~882k population, 50-year run)

Real-geography demonstration on Fiji's 5 admin-1 divisions (Central, Western, Northern, Eastern, Rotuma). Boundaries come from GADM and populations from WorldPop 2020 via the laser-init microservices; the cached responses ship under laser_typhoid/data/fiji/ so the runner works fully offline.

Sanitation intervention is applied at year 30 to Central and Western only — the two urban divisions that together carry ~82% of Fiji's population. Northern, Eastern, and Rotuma keep the baseline shedding intensity, mirroring the urban-first sewage rollout pattern.

typhoid on Fiji — 50y run, 5 divisions, urban sanitation at y30

Six panels:

  • A — Aggregate S / R / C compartments; carrier stock grows through year 30, then rolls over as the urban intervention starves the transmission cycle in Central + Western.
  • B — Urban (Central + Western) vs rural (rest) active-I burden. Urban drops sharply at intervention; rural continues largely on its previous trajectory.
  • C — Per-division daily incidence (14-day smoothed, log scale). All five divisions on one chart makes the urban / rural gap immediate.
  • D — Choropleth of cumulative infections per capita at year 30 (pre-intervention). Central and Western are darker.
  • E — Same choropleth at year 50 (post-intervention). Central and Western fade while Northern / Eastern continue to accumulate.
  • F — Chronic-carrier stock at end, per division. Central still holds the largest reservoir in absolute terms but the rate has flattened; rural divisions keep accumulating.

Animations:

Synthetic 5×5 grid (25-patch, ~300k population, 50-year run)

Same model on a synthetic 5×5 grid. Useful for isolating what the intervention design does without the confound of real-geography population imbalances (Fiji's Central and Western together are 82% of the country; the synthetic grid has more uniform patches).

typhoid on the synthetic grid — 50y run

Install + run

pip install .[geo]      # Fiji runner needs geopandas + shapely + requests
python -c "from laser_typhoid.run_fiji import run_fiji; r = run_fiji({'YEARS': 35}, verbose=True); print(r['scenario'].name.values)"

Or as scripts:

laser-typhoid-fiji --years 50 --out out_fiji.png     # real Fiji geography
laser-typhoid      --years 35 --seed 42               # synthetic 5×5 grid

Public API

Synthetic-grid model (base install; no geo deps needed):

from laser_typhoid import DEFAULTS, run_model, metrics

result = run_model(overrides={"P_CARRIER": 0.05, "YEARS": 40}, verbose=True)
model = result["model"]                    # laser-generic Model instance
urban_nids = result["urban_nids"]          # set of patch ids that see sanitation
print(metrics(result))

Real-geography Fiji runner (requires [geo] extras):

from laser_typhoid.run_fiji import DEFAULTS as FIJI_DEFAULTS, run_fiji
from laser_typhoid.plots_fiji import save_summary_figure

result = run_fiji({"YEARS": 50}, verbose=True)
scenario = result["scenario"]              # GeoDataFrame with 5 divisions
urban_mask = result["urban_mask"]          # boolean array over divisions
save_summary_figure(result, "out_typhoid_fiji.png")

Unknown keys in overrides raise KeyError early. metrics() extracts six outcome scalars used by the sensitivity harness: chronic-carrier fraction at year 30 (pre-sanitation), endemic active-typhoid prevalence at year 30, urban and rural 5-year-pre-vs-5-year-post incidence reductions, chronic-carrier fraction at end of sim, and final total population.

Parameter table

From published typhoid literature; not calibrated to any specific dataset. See sensitivity/SENSITIVITY.md for the per-parameter perturbation study.

symbol value source / justification
R_ACUTE 2.0 Pitzer et al 2014
P_CARRIER 0.03 Ames & Robins 1943 (25-yr Michigan cohort)
EXP_SCALE_DAYS 12 d E period (incubation); Antillón 2017 (8-14 d range)
INF_SCALE_DAYS 18 d I period; untreated acute typhoid
CARRIER_PERSIST_SCALE_DAYS 50 yr C→R natural clearance; near-lifelong biliary carriage
WANING_SCALE_DAYS 6 yr R→S immunity waning; Antillón 2017 (~15%/yr loss)
ALPHA_BASELINE 0.05 carrier shedding intensity ratio; Pitzer et al 2014
ALPHA_AFTER 0.005 urban post-sanitation shedding intensity (10× reduction)
SANITATION_START_YEAR 30 when sanitation kicks in
CBR 30/1000/yr typical low/middle-income
CDR 15/1000/yr net +1.5%/yr population growth
GRID_M × GRID_N 5×5 = 25 patches urban core (60k), ring (20k each), rural periphery (8k each). Urban core+ring = 13 patches get the sanitation intervention.
YEARS 50 to see endemic dynamics + post-intervention response
SEED 20260710

Sensitivity

A 1D per-parameter perturbation study (±30% around each science parameter, three stochastic seeds per cell, 35-year sims — long enough to include the SANITATION_START_YEAR + 5 years post) landed alongside this repo — see sensitivity/SENSITIVITY.md for the tornado charts and per-parameter interpretation. Rerun with:

python -m sensitivity.sensitivity --years 35 --seeds 3 --workers 1
python -m sensitivity.make_tornado

Why this is interesting

  • Standard SIR-with-carrier models often exaggerate the carrier contribution because they omit birth/waning refilling of S. Adding waning immunity puts carriers in the right place: important but not dominant.
  • Historical parallel: in the U.S. between 1900 and 1950, typhoid deaths fell from ~30/100 000/yr to <1, primarily through progressive water-treatment infrastructure and food-safety regulation targeted at carrier-mediated routes. The model's simulated incidence drop from a single urban sanitation step is consistent with the shape of that historical curve (not the magnitude — this isn't calibrated).
  • Spatial urban-first rollout is realistic: real early sewage systems reached cities decades before rural areas. The rural-continues-endemic-while-urban-drops asymmetry is what the model reproduces.
  • The "Typhoid Mary" archetype is quantitative here: P_CARRIER = 0.03 means ~3% of acute cases become chronic; each carrier persists ~50 years on average. That's the individual-level version of the Mary Mallon story.

Extensions

  • Vaccination: modern typhoid conjugate vaccines (TCV) have ~85% efficacy for ~3 yr. Model as periodic routine immunization creating a V compartment.
  • Age structure: young children have higher carrier acquisition rates in some settings (Levine 1982). Add age-dependent P_CARRIER.
  • Antibiotic treatment: acute I → R happens faster with treatment (mean 5 d) but carrier prevalence unchanged. Split I into "treated" and "untreated" branches.
  • Water compartment: an explicit environmental reservoir with its own decay dynamics (cf. Codeço 2001 cholera model).
  • More country runners: the Fiji runner is a template. Adding e.g. Bangladesh (BGD) or Malawi (MWI) at admin-1 is a _laser_init.load_real_scenario("BGD", level=1, year=2020) call plus setting URBAN_DIVISIONS for that country.

References

  • Pitzer VE et al. 2014. Predicting the impact of vaccination on the transmission dynamics of typhoid in South Asia. Am J Epidemiol 179:1188-1197.
  • Antillón M et al. 2017. The burden of typhoid fever in low- and middle-income countries. PLoS Negl Trop Dis 11:e0005376.
  • Levine MM et al. 1982. Precise estimation of the numbers of chronic carriers of Salmonella typhi in Santiago, Chile. J Infect Dis 146:724-726.
  • Ames WR, Robins M. 1943. Age and sex as factors in the development of the typhoid carrier state. AJPH 33:221.
  • Bhan MK et al. 2005. Typhoid and paratyphoid fever. Lancet 366:749-762.

Implementation notes

  • CARRIER = np.int8(5) extends the laser-generic State enum. Model is instantiated with additional_states=["C"] so _initialize_flows propagates C[t] → C[t+1].
  • Carrier fate is drawn at E → I transition time (inside ExposedTyphoid.step) and stored in people.fate. Then InfectiousTyphoid.step uses two fated countdown-transitions to send agents to R or C on itimer expiry.
  • Waning immunity uses people.rtimer (uint32) sampled Exponential(scale) on I → R. WaningImmunity.step() decrements and sends R → S on expiry.
  • ChronicCarrier also decrements ctimer (uint32) for slow C → R clearance.
  • Only agents whose rtimer > 0 are subject to waning — this preserves the invariant that agents in R via carrier clearance stay permanently R.
  • The mortality mappings passed to MortalityByCDR include the CARRIER state so nodes.C is decremented on death.

About

Typhoid SEIRC spatial ABM with chronic carriers + urban-first sanitation intervention.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages