Package 'yersinia'

Title: Plague Transmission Models for Epidemiological Research
Description: A toolkit for plague transmission modeling using stochastic compartmental models. Implements carcass-based transmission dynamics (Didelot et al. 2017) with spatial structure and multi-host dynamics for epidemiological research.
Authors: Nick Gauthier [aut, cre] (ORCID: <https://orcid.org/0000-0002-2225-5827>), Nich Martin [aut] (ORCID: <https://orcid.org/0000-0001-9539-250X>)
Maintainer: Nick Gauthier <[email protected]>
License: MIT + file LICENSE
Version: 0.1.0
Built: 2026-06-03 22:13:24 UTC
Source: https://github.com/flmnh-ai/yersinia

Help Index


Names of bundled scenario YAML files.

Description

Mirrors the canonical list in load_named_scenario(). v1 hardcodes the five built-in scenarios; future versions will scan system.file("scenarios", package = "yersinia") so user-bundled YAMLs show up automatically.

Usage

available_scenarios()

Value

Character vector of scenario names.


Advance the CA one tick

Description

Vectorized one-step update of a 3-state CA (0 = susceptible, 1 = epidemic, 2 = endemic) following K&G (2000) Table 3 semantics:

Usage

ca_step(
  state,
  sus,
  A,
  lookups,
  d_per_tick,
  P_recovery_sus = 20,
  grow_per_tick = 12
)

Arguments

state

Integer vector of length npop, values 0/1/2.

sus

Numeric vector of length npop, values in ⁠[0, 100]⁠.

A

Sparse adjacency matrix from ⁠make_*_grid()⁠.

lookups

List of three functions (T_E, T_P, Q) of ⁠S_frac ∈ [0, 1]⁠. Use make_lookups().

d_per_tick

Probability per tick that an isolated P cell decays back to S. Estimate from your metapop using a long-run P-state survival simulation.

P_recovery_sus

Susceptibility (0-100) that recovered P cells land at. Default 20 is just below the band where transmission becomes reliable in the vignette's parameter regime.

grow_per_tick

Increment in sus per tick for S cells.

Details

  • ⁠S → E⁠ or ⁠S → P⁠ if any neighbour is in E or P, with per-target probability ⁠1 - (1 - T_E)^n_E × (1 - T_P)^n_P⁠ and outcome P with conditional probability Q (else E).

  • ⁠E → S_0⁠ (deterministic — epidemics resolve in one tick).

  • ⁠P → S_w⁠ with probability d_per_tick, sus reset to P_recovery_sus.

  • Susceptibility regrows in S cells by grow_per_tick (capped at 100).

All transitions are computed from the start-of-tick state; no within-tick asynchronous updates.

Value

A list with the updated state and sus vectors.


Calculate equilibrium values for deterministic models

Description

Calculate equilibrium values for deterministic models

Usage

calculate_equilibrium(params, model_type = "rats_only")

Arguments

params

plague_parameters object or list

model_type

Type of model

Value

List of equilibrium values

Note

This function is for reference/educational purposes. For operational models, use the stochastic simulations in run_plague_model().


Calculate force of infection over time

Description

Calculate force of infection over time

Usage

calculate_force_of_infection(results)

Arguments

results

plague_results object

Value

Tibble with force of infection by time


Calculate outbreak summary statistics

Description

Calculate outbreak summary statistics

Usage

calculate_outbreak_metrics(results, compartment = "I", threshold = 1)

Arguments

results

plague_results object

compartment

Compartment to analyze (default "I")

threshold

Minimum value to consider as "outbreak" (default 1)

Value

Data frame with outbreak statistics


Calculate basic reproduction number (R0) for different model types

Description

Calculate basic reproduction number (R0) for different model types

Usage

calculate_R0(params, model_type = "rats_only", K_r = 2500, K_h = 5000)

Arguments

params

plague_parameters object or list

model_type

Type of model ("rats_only", "with_humans", etc.)

K_r

Rat carrying capacity (defaults to 2500 if not in params)

K_h

Human carrying capacity (defaults to 5000 if not in params, only used for "with_humans")

Value

Numeric R0 value or list of R0 values


Long-format cohort data with NA-padded synchronized time grid.

Description

For multi-outbreak fits, dust2's grouped likelihood requires every group to share the same time grid; shorter outbreaks are NA-padded out to the longest. The returned tibble has columns group (character — dust2 rejects factor group), time, deaths.

Usage

cohort_data(cohort_ids, data = NULL)

Arguments

cohort_ids

Character vector of outbreak_ids.

data

Long outbreaks tibble (defaults to bundled outbreaks).

Value

Tibble with group, time, deaths.


Per-outbreak observation period (must be consistent across the cohort).

Description

dust2's grouped likelihood evaluates a single obs_period; mixing daily and weekly outbreaks in one fit isn't supported here (London 1563 is weekly; everything else is daily). Errors when the cohort mixes cadences.

Usage

cohort_obs_period(cohort_ids, data = NULL)

Arguments

cohort_ids

Character vector of outbreak_ids.

data

Long outbreaks tibble (defaults to bundled outbreaks).

Value

Single integer.


Per-outbreak population values (K_h / K_r when fixed).

Description

Per-outbreak population values (K_h / K_r when fixed).

Usage

cohort_population(cohort_ids, data = NULL)

Arguments

cohort_ids

Character vector of outbreak_ids.

data

Long outbreaks tibble.

Value

Named numeric, one entry per outbreak.


Cohort module — server.

Description

Selection state is lab_session$cohort_ids (character vector of outbreak_ids). The UI is rebuilt whenever that vector changes.

Usage

cohort_server(id, lab_session, data = NULL)

Arguments

id

Module namespace id.

lab_session

A LabSession instance.

data

Long outbreaks tibble. Defaults to the bundled outbreaks.

Value

Invisibly, the moduleServer result.


Cohort module — UI.

Description

Cohort module — UI.

Usage

cohort_ui(id)

Arguments

id

Module namespace id.

Value

A bslib::card() with the cohort chips + picker grid.


Names of model parameters configurable from the Virtual Lab UI.

Description

Excludes parameters that aren't user-fittable in practice:

Usage

configurable_param_names()

Details

  • tau (timestep — system, not biological)

  • seasonal (vector — handled separately as climate input)

  • obs_period (integer flag — derived from the cohort data)

  • iota (resistance fecundity multiplier — always-fixed per CLAUDE.md)

The returned set is ~23 scalar parameters: rates, capacities, initial counts, and the likelihood dispersion kappa.

Value

Character vector of parameter names.


Temperature-dependent multiplier for delta_R (rate of loss of carcass infectiousness in a Didelot-style plague model)

Description

Returns a Brière-shaped multiplier capturing the combined temperature effects on flea survival and Y. pestis biofilm blockage formation. Multiply your fitted baseline delta_R rate by this output to obtain delta_R(T) for use in the model:

Usage

delta_R_multiplier(
  temperature,
  T_min = 5,
  T_max = 37,
  q = 1.5,
  T_ref = 17.8,
  cap = 1000
)

Arguments

temperature

Numeric vector of temperatures (degrees Celsius)

T_min

Lower thermal bound (default 5 C)

T_max

Upper thermal bound (default 37 C)

q

Warm-side asymmetry exponent (default 1.5)

T_ref

Reference temperature where multiplier = 1 (default 17.8 C)

cap

Maximum multiplier value, applied beyond thermal bounds (default 1000) to keep the likelihood numerically well-behaved

Details

delta_R(T) = delta * delta_R_multiplier(T)

Functional form: L(T) = (T - T_min) * (T_max - T)^q for T_min < T < T_max multiplier(T) = L(T_ref) / L(T)

Defaults place the optimum (longest infectious period) at 17.8 C with hard bounds at 5 C (cold cliff: Y. pestis blockage formation fails) and 37 C (warm cliff: flea thermal death + biofilm dissolution). These are anchored to: Krauer et al. 2021 (epidemic peak ~17 C), Hinnebusch lab biofilm work (cold cliff), and Mellanby 1932 (thermal death point of X. cheopis).

Default T_ref = 17.8 means the fitted delta represents delta_R at the thermal optimum, i.e. the minimum loss rate (longest carcass infectiousness). All multipliers are then >= 1. To match Didelot et al. 2017's calibration anchor instead, set T_ref = 14 — delta then represents delta_R at Cairo winter mean temperature, comparable to their posterior median of 0.267/day.

Value

Numeric vector of multipliers, one per input temperature


Diagnostics strip module — server.

Description

Diagnostics strip module — server.

Usage

diag_strip_server(id, lab_session)

Arguments

id

Module namespace id.

lab_session

A LabSession instance.

Value

Invisibly, the moduleServer result.


Diagnostics strip module — UI.

Description

Diagnostics strip module — UI.

Usage

diag_strip_ui(id)

Arguments

id

Module namespace id.

Value

A shiny::div() for the strip (initially empty).


Detect posterior mass piling against prior bounds.

Description

For each parameter with finite ⁠[low, high]⁠ bounds in bounds, computes the fraction of draws within edge (a fraction of the bound width) of either bound. Flags any parameter where that fraction exceeds threshold. Bound-piling indicates the prior is constraining the posterior — either the prior is too tight, or the model wants a parameter the prior forbids.

Usage

diagnose_bound_piling(samples, bounds, threshold = 0.2, edge = 0.05)

Arguments

samples

A monty_samples object or a posterior::draws_array.

bounds

Named list keyed by parameter name; each entry is a length-2 numeric c(low, high). Parameters not in bounds are skipped.

threshold

Fraction of draws within edge of a bound that triggers the flag. Default 0.20 (20%).

edge

Fraction of bound width counted as "near the edge". Default 0.05 (5%).

Details

Parameters with non-finite bounds (e.g. Exponential(rate=0.1) with high = Inf) are silently skipped — there's no upper edge to pile against.

Value

A diagnostic record or NULL.


Detect non-mixing chains via R-hat.

Description

Uses posterior::rhat() on each parameter; flags the fit if any parameter's R-hat exceeds threshold. The MVP threshold of 1.5 is intentionally loose (the conventional convergence cutoff is 1.05–1.1) — we want to flag pilots that are obviously broken, not over-warn on borderline cases.

Usage

diagnose_chain_stuck(samples, threshold = 1.5)

Arguments

samples

A monty_samples object or a posterior::draws_array.

threshold

R-hat above which the fit is flagged. Default 1.5.

Value

A diagnostic record (see file header) or NULL if all R-hats are below threshold.


Detect low NegBinomial dispersion (kappa).

Description

The plague-fit likelihood is deaths ~ NegBinomial(size = kappa, mu = ...). Small kappa means highly overdispersed observations — the data is so noisy that almost any trajectory is plausible, so the posterior over transmission parameters becomes uninformative. The MVP threshold of 5 is a rule of thumb from the Cairo / Barcelona pilots in this conversation: kappa < 5 typically corresponded to broken or under-specified fits.

Usage

diagnose_low_kappa(samples, par = "kappa", threshold = 5)

Arguments

samples

A monty_samples object or a posterior::draws_array.

par

Name of the dispersion parameter. Default "kappa".

threshold

Median kappa below which the fit is flagged. Default 5.

Details

Uses the posterior median of kappa across all chains and iterations.

Value

A diagnostic record or NULL (also NULL if par isn't in the sampled parameters — kappa may be pinned in some configurations).


Hero plot module — server.

Description

Renders cohort death curves and (when a fit exists) the posterior predictive trajectory fan. Recomputes the fan lazily on fit_state changes.

Usage

hero_server(id, lab_session, n_draws = 80L)

Arguments

id

Module namespace id (must match hero_ui()).

lab_session

A LabSession instance.

n_draws

Number of posterior draws to render. Default 80.

Value

Invisibly, the moduleServer result.


Hero plot module — UI.

Description

Hero plot module — UI.

Usage

hero_ui(id)

Arguments

id

Module namespace id.

Value

A bslib::card() with the hero plot.


Posterior predictive forward simulation from a Lab fit.

Description

Subsamples n_draws posterior draws (evenly spaced by posterior::thin_draws), runs the deterministic plague humans model forward for each, and returns a long-format tibble of per-draw predicted observation series. Used by the hero plot to render the posterior fan over cohort data.

Usage

lab_fit_forward_sim(setup, samples, n_draws = 100, t_grid = NULL)

Arguments

setup

Output of lab_fit_assemble().

samples

A monty_samples object from lab_fit_run().

n_draws

Target number of posterior draws to simulate. Default 100.

t_grid

Optional integer vector of simulation times. Defaults to seq(0, max(setup$data$time)).

Details

Handles both the single-outbreak (flat packer) and multi-outbreak (grouped packer) cases.

Value

Tibble with columns draw, group, time, mu (predicted observation expectation per posterior draw).


Run a deterministic-pilot fit assembled by lab_fit_assemble().

Description

Synchronous: blocks until all chains complete. v1 uses monty::monty_runner_serial() (sequential chains in the calling process) to keep the runtime model simple; switch to monty_runner_callr in v2 for parallel chains.

Usage

lab_fit_run(
  setup,
  n_chains = 4L,
  n_iter = 30000L,
  burnin_frac = 0.5,
  initial = NULL
)

Arguments

setup

Output of lab_fit_assemble().

n_chains

Number of chains. Default 4.

n_iter

Iterations per chain. Default 30000. Single-outbreak fits converge by ~10k; multi-outbreak hierarchical fits (4+ outbreaks) typically need 30–50k for the adaptive sampler to settle the per-group ⁠(beta_h, I_ini)⁠ ridges.

burnin_frac

Fraction of iterations to discard from each chain as warmup. Default 0.5 (drop first half). Set to 0 to keep everything.

initial

Optional matrix of initial parameter vectors (⁠n_parameters × n_chains⁠). When NULL (default), monty draws from the prior.

Details

Discards the first burnin_frac of iterations from each chain post-hoc. The adaptive sampler tunes its proposal VCV continuously during sampling, so early iterations are biased relative to the converged regime — discarding the first half is the convention for adaptive RWM (see e.g. Stan / NUTS warmup defaults). Returns the trimmed samples.

Value

A monty_samples object with the warmup iterations removed.


Run a stochastic production fit on top of a deterministic pilot.

Description

After a pilot completes, use the adaptive sampler's tuned proposal VCV to warm-start a shorter stochastic chain that respects the actual particle-filter likelihood (the pilot's deterministic unfilter is an expected-value approximation). Returns the production samples; the caller is responsible for keeping the pilot around for diagnostics.

Usage

lab_fit_run_production(
  pilot_setup,
  pilot_samples,
  n_chains = 4L,
  n_iter = 5000L,
  burnin_frac = 0.2,
  n_particles = 500L,
  n_threads = 2L,
  vcv_inflation = NULL
)

Arguments

pilot_setup

The setup list returned by lab_fit_assemble().

pilot_samples

The samples returned by lab_fit_run().

n_chains

Number of chains. Default 4.

n_iter

Iterations per chain. Default 5000 (much shorter than pilot since the proposal is already tuned).

burnin_frac

Fraction to discard. Default 0.2 (chains start from a converged pilot region, so minimal warmup needed).

n_particles

Particle filter size. Default 500.

n_threads

OpenMP threads. Default 2.

vcv_inflation

Factor to scale the tuned pilot VCV by. Default ⁠0.7 · (2.38² / n_pars)⁠ (Roberts–Rosenthal optimal-scaling, slightly shrunk to give the stochastic chain cushion against filter noise).

Details

Mirrors the two-stage workflow in vignettes/monty-barcelona-hierarchical.qmd and friends.

Value

A monty_samples object with the warmup iterations removed.


Reconstruct a LabSession from a saved state list.

Description

Inverse of LabSession$to_list(). Unknown keys in state are ignored so older snapshots remain loadable as the schema grows; missing keys fall back to the same defaults LabSession's constructor uses.

Usage

lab_session_from_list(state)

Arguments

state

Named list as returned by LabSession$to_list().

Value

A new LabSession instance.


LabSession R6 class — Virtual Lab session state.

Description

LabSession R6 class — Virtual Lab session state.

LabSession R6 class — Virtual Lab session state.

Details

Holds the reactive state of an interactive plague-fitting session. Used by lab_app() and the Shiny modules. State is exposed as active bindings backed by shiny::reactiveVal() so reads from inside reactive contexts subscribe automatically; outside Shiny, reads return the current value.

Current fields: cohort_ids (character vector of selected outbreak_ids from the outbreaks dataset), model_config (list with scenario, shared, local — see model_config_default()). Future versions will add priors, fit_state, sandbox_draw as the corresponding modules come online.

Use lab_session_from_list() to reconstruct from a saved state list.

Active bindings

cohort_ids

Character vector of selected outbreak_ids. Reading from inside a reactive context subscribes; assigning triggers downstream observers.

model_config

Model-config list (scenario, shared, local) — see model_config_default() for the schema.

priors

Named list of priors keyed by parameter name; each entry is list(family, params). See priors_default().

fit_state

Named list summarising the most recent fit: status ("idle" | "running" | "complete" | "error"), samples (a monty_samples object or NULL), n_chains, n_iter, duration (seconds), error (message), started_at, completed_at.

Methods

Public methods


Method new()

Construct a new LabSession.

Usage
LabSession$new(
  cohort_ids = character(0),
  model_config = NULL,
  priors = NULL,
  fit_state = NULL
)
Arguments
cohort_ids

Initial cohort (character vector of outbreak_ids). Default empty.

model_config

Initial model config; defaults to model_config_default().

priors

Named list of priors. Defaults to priors_default() over the fitted parameters implied by model_config.

fit_state

Initial fit-state struct; defaults to an idle state.


Method to_list()

Snapshot the session state as a plain list (no reactive infrastructure), suitable for saveRDS().

Usage
LabSession$to_list()

Method apply_list()

Mutate this LabSession in place from a saved-state list (e.g. one produced by to_list()). All reactiveVals fire, so any subscribed Shiny observers update. Unknown keys are ignored so older snapshots remain loadable.

Usage
LabSession$apply_list(state)
Arguments
state

Named list as returned by to_list().


Method clone()

The objects of this class are cloneable with this method.

Usage
LabSession$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.


Load named scenario parameters

Description

Load named scenario parameters

Usage

load_named_scenario(name)

Arguments

name

Name of scenario

Value

List of model parameters


Load plague model scenario parameters

Description

Load plague model scenario parameters

Usage

load_scenario(scenario = "defaults", ...)

Arguments

scenario

Name of scenario or path to YAML file or list of parameters

...

Additional model parameters to override

Value

List of model parameters


Build a hexagonal CA lattice

Description

Constructs a hex-tessellated grid covering a ⁠side × side⁠ bounding box (one hex cell per unit area, pointy-top by default), with 6-neighbour adjacency. Requires the sf package. Returns the same lattice interface as make_square_grid() plus an sf field that lets you visualize results with ggplot2::geom_sf().

Usage

make_hex_lattice(side)

Arguments

side

Numeric. Side length of the square bounding box. The number of cells produced is approximately side^2.

Value

A list with neighbors, A, npop, and sf (an sf data frame with cell_id and geometry columns).

See Also

make_square_grid() for the square variant.


Build CA transition-probability lookups

Description

From a tidy data frame of empirical T_i / Q_i estimates (as produced by the metapop-cellular-automaton vignette), build linear interpolation functions for T_E(S_frac), T_P(S_frac), and Q(S_frac) at a chosen coupling level mu_r. The returned lookup list is the form ca_step() expects.

Usage

make_lookups(TQ, mu_r_use)

Arguments

TQ

Data frame with columns source ("E" or "P"), mu_r, S_frac, T_i, Q_i. The vignette produces this as tq or ca_TQ.

mu_r_use

Coupling level at which to extract lookups (must match a value in TQ$mu_r).

Details

Pads T_i only with ⁠(S_frac = 0, T_i = 0)⁠ (biologically required — fully-resistant cells cannot trigger) and uses approxfun(rule = 2) to extrapolate T_i past the empirical S_frac range as the boundary value. For Q_i no synthetic boundary points are added, since the empirical Q curve often drops at high S_frac (fully-susceptible patches burn out fast) and a Q(1) = 1 pad would inflate the lookup exactly where the data says it should fall. Rare-trigger NAs in Q_i (n_trig < 5) are dropped before interpolation.

Value

A list of ⁠function(S_frac)⁠ interpolators: T_E, T_P, Q.


Build a square-lattice CA grid

Description

Constructs a ⁠n_row × n_col⁠ regular grid with rook (4-neighbour) adjacency, returning a list with the neighbour list, sparse adjacency matrix, and per-cell ⁠(row, col)⁠ coordinates. Boundary cells have 2-3 neighbours; interior cells have 4. The neighbour ordering is row-major (cell index = (row - 1) * n_col + col).

Usage

make_square_grid(n_row, n_col)

Arguments

n_row, n_col

Integer dimensions of the lattice.

Value

A list with elements:

  • neighbors — list of integer vectors, one per cell

  • A — sparse Matrix::sparseMatrix adjacency, dims ⁠(npop, npop)⁠

  • n_row, n_col, npop

  • cell_xy — data frame with row and col columns

See Also

make_hex_lattice() for the hex variant; run_ca() consumes the returned list directly.


Model accordion module — server.

Description

Model accordion module — server.

Usage

model_accordion_server(id, lab_session)

Arguments

id

Module namespace id.

lab_session

A LabSession instance.

Value

Invisibly, the moduleServer result.


Model accordion module — UI.

Description

Model accordion module — UI.

Usage

model_accordion_ui(id)

Arguments

id

Module namespace id.

Value

A bslib::accordion() containing the model config controls.


Default model configuration for a fresh Virtual Lab session.

Description

Mirrors the Barcelona / Cairo vignette fitting workflows: biology + likelihood-overdispersion are shared across the cohort; transmission to humans and ignition + record-quality knobs are local (per outbreak). Populations (K_h, K_r) are not in the fitted set — when omitted, lab_fit_assemble() pins them per-group at each outbreak's known population from the outbreaks dataset. Same applies to g_h — the vignettes pin it at the scenario value because it's only weakly identifiable from death counts alone.

Usage

model_config_default(scenario = "defaults")

Arguments

scenario

Base scenario name. Default "defaults" — the curated baseline scenario designed for out-of-the-box outbreak fitting. Era- specific scenarios ("historical", "modern-estimates", "didelot") are available for paper reproduction.

Details

rho (flea redistribution exponent) is also intentionally not fitted by default: it's confounded with beta_r via the rat-side R₀ formula ⁠R₀ ∝ beta_r · (1 − e^(−rho)) / delta_R⁠, so jointly fitting both creates a ridge in the posterior that wrecks rhat. Pin rho at the scenario value and let beta_r carry the rat-side identification.

To fit K_h/K_r, g_h, or rho, add them via the Model tab.

Value

A model-config list.


Resolve a model config to per-parameter scope and value.

Description

Loads the named scenario, then for every configurable parameter reports the scenario value, the chosen scope (fixed | shared | local), and the value the model would actually see (scenario_value for fixed, NA for shared/local since the sampler will set those).

Usage

model_config_resolve(config)

Arguments

config

A model-config list (see file header).

Details

Parameters that appear in both shared and local are reported as local — the multi-cohort case usually wants per-outbreak resolution when the user has flagged conflict.

Value

A tibble with columns parameter, scope, scenario_value, resolved_value, sorted alphabetically.


Create a plague_results object

Description

Create a plague_results object

Usage

new_plague_results(data, model_type, params, run_info = list())

Arguments

data

Tibble with simulation results

model_type

Type of model used

params

Parameters used in simulation

run_info

Runtime information

Value

plague_results object


Per-outbreak summary table for the cohort picker.

Description

Aggregates the long-format outbreaks dataset to one row per outbreak, with the metadata + summary stats the cohort picker displays (location, year, population, duration, total deaths, peak day, observation period).

Usage

outbreak_summary(data = NULL)

Arguments

data

Long-format outbreaks tibble. Defaults to the package's bundled outbreaks dataset.

Value

A tibble with one row per outbreak_id, sorted by year.

Examples

outbreak_summary()

Historical plague outbreak data

Description

Historical plague mortality data from multiple European and Middle Eastern cities spanning from 1348 to 1835, compiled by Dean et al. (2018).

Usage

outbreaks

Format

A tibble with 1,451 rows and 7 variables:

outbreak_id

Unique identifier for each outbreak (location_year)

location

City name

year

Year of the outbreak

population

Total population of the city

day

Calendar day of the observation, 1-indexed from outbreak start. For weekly outbreaks (London 1563) this is the day at the end of the reporting week (7, 14, ...).

deaths

Death count for the reporting window ending at day; daily for most outbreaks, weekly for London 1563 – see caveats below re: plague-specific vs all-cause across sources

obs_period

Length in days of the reporting window each deaths value covers (1 for daily, 7 for London 1563). Pass this to plague_fit_setup via the obs_period argument so the model's D_h accumulator aggregates over a matching window.

Details

The dataset includes plague outbreaks from:

  • Barcelona 1490 (daily data, 182 days)

  • Malta 1813 (daily data, 209 days)

  • Florence 1400 (daily data, 180 days)

  • Cairo 1835 (daily data, 366 days)

  • Eyam 1665 (daily data, 145 days)

  • Prague 1713 (daily data, 198 days)

  • London 1563 (weekly data, 33 weeks; obs_period = 7)

  • Givry 1348 (daily data with some missing values, 138 days)

Some datasets contain missing values (NA) where historical records were incomplete. London 1563 carries weekly Bills of Mortality counts – the obs_period = 7 flag signals that to fitting code, and day steps in increments of 7.

Cause-of-death provenance. The source documents differ in whether they record plague-specific deaths or all burials during the outbreak. This matters when fitting to the model's D_h (plague deaths only). Summary:

  • Plague-specific (cause distinguished in source): Barcelona 1490 (cerca de morts), London 1563 (Bills of Mortality), Malta 1813, Prague 1713, Cairo 1835

  • All-cause burial records, but with negligible baseline vs. epidemic peak: Givry 1348 (parish register, ~1,200 pop), Eyam 1665 (parish register, ~700 pop). Fittable as plague-specific in practice.

  • Ambiguous: Florence 1400 (Libri dei Morti, inconsistent cause-of-death annotation)

See data-raw/outbreaks.R for per-outbreak primary-source citations.

Users can filter to specific outbreaks using the outbreak_id or location/year: # Get Barcelona data barcelona <- plague_outbreaks |> filter(outbreak_id == "Barcelona_1490") # Get all 15th century outbreaks fifteenth_century <- plague_outbreaks |> filter(year >= 1400 & year < 1500)

Source

Dean, K.R., Krauer, F., Walløe, L., Lingjærde, O.C., Bramanti, B., Stenseth, N.C. and Schmid, B.V., 2018. Human ectoparasites and the spread of plague in Europe during the Second Pandemic. Proceedings of the National Academy of Sciences, 115(6), pp.1304-1309.

Examples

# View structure of the data
str(outbreaks)

# Summary statistics by outbreak
outbreaks |>
  group_by(outbreak_id, location, year) |>
  summarise(
    duration_days = max(day),
    total_deaths = sum(deaths, na.rm = TRUE),
    peak_deaths = max(deaths, na.rm = TRUE),
    population = first(population)
  )

Build a particle filter for the humans plague model.

Description

Build a particle filter for the humans plague model.

Usage

plague_fit_filter(data, n_particles = 2000, n_threads = 2)

Arguments

data

Data frame with columns time and deaths (see outbreaks).

n_particles

Number of particles in the filter.

n_threads

Number of OpenMP threads for the filter (default 2).

Value

A dust2 particle filter ready for dust2::dust_likelihood_run() or dust2::dust_likelihood_monty().


Default fitted parameter names for plague humans fits.

Description

These are the parameters swept by the monty sampler in plague_fit_setup(). If you change this set, you also need to provide a matching prior and vcv — the defaults returned by plague_fit_prior() and plague_fit_vcv() are built for exactly this ordering.

Usage

plague_fit_fitted_names()

Details

The model also supports p_obs (observation/ascertainment probability, defaults to 1 = perfect reporting) which is deliberately NOT fitted by default. To opt in, pass e.g. fitted_names = c(plague_fit_fitted_names(), "p_obs") to plague_fit_setup() with a matching prior (p_obs ~ Uniform(0, 1) follows the 2009-flu example in the odin-monty book) and an extended VCV.

Value

Character vector of parameter names.


Build the fixed (non-fitted) parameter list for a plague humans fit.

Description

Loads a scenario via load_scenario(), drops any parameter that the sampler will vary, and filters to just the keys the odin2 humans model accepts. The returned list is suitable for the fixed argument of monty::monty_packer() or as pars for dust2::dust_system_create().

Usage

plague_fit_fixed_pars(
  scenario = "historical",
  fitted_names = plague_fit_fitted_names()
)

Arguments

scenario

Scenario name, path to YAML, or parameter list. Defaults to "historical" — the scenario the monty fit pipeline was calibrated against.

fitted_names

Names of parameters that the sampler will set; these are stripped from the fixed set. Defaults to plague_fit_fitted_names().

Value

Plain named list of fixed parameters.


Default prior over the fitted plague humans parameters (monty DSL).

Description

Paired with plague_fit_fitted_names() — order and variables must match.

Usage

plague_fit_prior()

Value

A monty model returned by monty::monty_dsl().


Assemble everything needed to call monty::monty_sample() on a plague fit.

Description

Wires the filter, packer (with fixed parameters), likelihood, prior, and sampler together. Runs the filter once at the fixed defaults as a smoke test — if that throws, the parameters and data don't agree and you want the error now rather than inside monty_sample().

Usage

plague_fit_setup(
  data,
  scenario = "historical",
  fitted_names = plague_fit_fitted_names(),
  n_particles = 2000,
  n_threads = 2,
  prior = NULL,
  vcv = NULL,
  obs_period = 1L,
  smoke_test = TRUE
)

Arguments

data

Data frame with columns time and deaths.

scenario

Fixed-parameter scenario (name, path, or list). Default "historical".

fitted_names

Parameters for the sampler to vary. Default plague_fit_fitted_names().

n_particles

Particle filter size. Default 2000.

n_threads

OpenMP threads for the filter. Default 2.

prior

monty model; default plague_fit_prior().

vcv

Sampler VCV; default plague_fit_vcv().

obs_period

Integer length (in days) of the observation window over which D_h accumulates between data points. Default 1L for daily data. Set to e.g. 7L when fitting weekly counts (London 1563); the model's D_h accumulator then resets every 7 days so each comparison is between a weekly count and a 7-day sum of simulated plague deaths. All data$time values must be multiples of obs_period.

smoke_test

If TRUE (default), call dust_likelihood_run() once to validate filter + fixed params + data before returning.

Value

Named list: posterior, sampler, filter, packer, fixed_pars, fitted_names. The caller chooses runner, n_steps, n_chains, burnin when invoking monty_sample().


Default diagonal VCV for the random-walk sampler.

Description

Diagonal entries are ordered to match plague_fit_fitted_names(). Replace with an empirical covariance after a pilot run for better mixing (the monty vignette walks through that tuning step).

Usage

plague_fit_vcv()

Value

Numeric matrix.


Stochastic humans plague model (carcass formulation)

Description

An odin2/dust2 system generator compiled at package build time from inst/odin/plague_stochastic_humans.R. Pass it directly to dust2::dust_system_create() or dust2::dust_filter_create().


Stochastic metapopulation plague model (rat dispersal between patches)

Description

An odin2/dust2 system generator compiled at package build time from inst/odin/plague_stochastic_metapop.R. Same Didelot carcass-based transmission core as plague_stochastic_humans, with rat S/I/R compartments arrayed over npop patches and a row-stochastic contact_r[npop, npop] matrix routing migrants. Carcasses Q are sessile; humans live per-patch and do not migrate (v1). Pass directly to dust2::dust_system_create().


Create multi-panel comparison plot

Description

Create multi-panel comparison plot

Usage

plot_comparison(results_list, compartment = "I", population = 1)

Arguments

results_list

Named list of plague_results objects

compartment

Compartment to compare (default "I")

population

Which population to plot (default 1)

Value

ggplot2 object


Plot compartment dynamics with uncertainty bands

Description

Plot compartment dynamics with uncertainty bands

Usage

plot_dynamics(
  results,
  compartments = NULL,
  population = 1,
  show_uncertainty = TRUE,
  log_scale = FALSE
)

Arguments

results

plague_results object

compartments

Vector of compartments to plot (NULL for all)

population

Which population to plot (for spatial models, default 1)

show_uncertainty

Show uncertainty bands for stochastic models (default TRUE)

log_scale

Use log scale for y-axis (default FALSE)

Value

ggplot2 object


Plot phase portrait (S vs I)

Description

Plot phase portrait (S vs I)

Usage

plot_phase_portrait(
  results,
  compartments = c("S", "I"),
  population = 1,
  replicate = 1,
  ...
)

Arguments

results

plague_results object

compartments

Vector of two compartments to plot (default c("S", "I"))

population

Which population to plot (for spatial models, default 1)

replicate

Which replicate to plot (for stochastic models, default 1)

...

Additional ggplot2 arguments

Value

ggplot2 object


Plot parameter sensitivity results

Description

Plot parameter sensitivity results

Usage

plot_sensitivity(sensitivity_results, compartment = "I", metric = "peak")

Arguments

sensitivity_results

Output from run_sensitivity_analysis

compartment

Compartment to plot (default "I")

metric

Summary metric to plot ("peak", "final", "auc")

Value

ggplot2 object


Plot method for plague_results

Description

Plot method for plague_results

Usage

## S3 method for class 'plague_results'
plot(x, compartments = NULL)

Arguments

x

plague_results object

compartments

Vector of compartments to plot (NULL for all)


Print method for outbreak metrics

Description

Print method for outbreak metrics

Usage

## S3 method for class 'plague_outbreak_metrics'
print(x, ...)

Arguments

x

plague_outbreak_metrics object

...

Additional arguments (ignored)


Print method for plague_results

Description

Print method for plague_results

Usage

## S3 method for class 'plague_results'
print(x, ...)

Arguments

x

plague_results object

...

Additional arguments passed to tibble print


Print method for plague_parameters

Description

Print method for plague_parameters

Usage

## S3 method for class 'scenario_parameters'
print(x, ...)

Arguments

x

plague_parameters object

...

Additional arguments (ignored)


Hard-bound interval implied by a prior, for piling detection.

Description

Returns a length-2 numeric c(low, high). Only families with a finite interval support produce both ends finite — Uniform and Beta. For families with infinite or one-sided support (Normal, LogNormal, Gamma, Exponential), the unbounded side is Inf/-Inf. The diagnose_bound_piling() detector skips parameters with non-finite bounds, so this function safely "no-ops" the diagnostic for unbounded priors.

Usage

prior_bounds(prior)

Arguments

prior

A prior list (family, params).

Value

Length-2 numeric c(low, high).


Default prior for a single fittable parameter.

Description

Hand-picked defaults seeded from the literature and from the pilots in the existing monty vignettes. Returns NULL when there is no canonical default for parameter — the caller should fall back to Uniform(0, 1) or prompt the user.

Usage

prior_default(parameter)

Arguments

parameter

Name of a model parameter.

Value

A prior list (family, params) or NULL.


Evaluate a prior's density on a grid for plotting.

Description

Returns a tibble with columns x and density, suitable for ggplot. The grid spans the family's prior_families() range(params) with n points; densities outside the support of compactly-supported families (Uniform, Beta) are zero by definition of the underlying R function.

Usage

prior_density(prior, n = 200)

Arguments

prior

A prior list (family, params).

n

Number of grid points. Default 200.

Value

A tibble with columns x and density.


Registry of supported prior distribution families.

Description

Each entry is a list with:

  • params: named list of parameter specs ⁠(default, min, max, label)⁠, in the order the family expects them when called via the monty DSL

  • density: function ⁠(x, p)⁠ returning the PDF at x, where p is a named list of parameter values

  • range: function (p) returning a length-2 numeric c(low, high) — sensible plot range for the family at parameter values p

Usage

prior_families()

Details

v1 supports six families: Uniform, Normal, LogNormal, Gamma, Exponential, Beta. Names match the monty DSL exactly.

Value

Named list of family definitions.


Convert one prior to a monty-DSL expression.

Description

Produces an unevaluated expression of the form name ~ Family(args), where the args are taken from prior$params in the order the family declares them. Suitable for splicing into monty::monty_dsl().

Usage

prior_to_dsl(name, prior)

Arguments

name

Parameter name (will become the LHS of ~).

prior

A prior list (family, params).

Value

A length-1 unevaluated expression.


Priors accordion module — server.

Description

Priors accordion module — server.

Usage

priors_accordion_server(id, lab_session)

Arguments

id

Module namespace id.

lab_session

A LabSession instance.

Value

Invisibly, the moduleServer result.


Priors accordion module — UI.

Description

Priors accordion module — UI.

Usage

priors_accordion_ui(id)

Arguments

id

Module namespace id.

Value

A bslib::card() whose body is the dynamic priors accordion.


Build a default priors list for a set of fitted parameters.

Description

For each parameter in fitted_params, returns its prior_default() or falls back to Uniform(0, 1) if no canonical default exists.

Usage

priors_default(fitted_params)

Arguments

fitted_params

Character vector of parameter names.

Value

Named list of priors keyed by parameter name.


Bounds for every parameter in a packer, including per-group decorations.

Description

Maps each packer_names entry back to its base parameter (stripping any ⁠<group>⁠ decoration), looks up that parameter's prior, and returns the bounds via prior_bounds(). Suitable for passing to diagnose_bound_piling().

Usage

priors_to_bounds(priors, packer_names)

Arguments

priors

Named list of priors.

packer_names

Character vector of (possibly decorated) parameter names from packer$names().

Value

Named list of c(low, high) keyed by packer_names.


Convert a full priors list to a list of monty-DSL expressions.

Description

Convert a full priors list to a list of monty-DSL expressions.

Usage

priors_to_dsl(priors)

Arguments

priors

Named list of priors (see file header).

Value

List of unevaluated expressions in the same order as priors.


Run a CA from n_seeds seed cells for n_ticks

Description

Initializes a fresh lattice (all S with full susceptibility), seeds n_seeds cells in state E, and advances ca_step() for n_ticks. Returns the per-tick state matrix; the sus history is not retained (regenerable from state and the recovery rules if needed).

Usage

run_ca(lattice, lookups, d_per_tick, n_ticks, n_seeds = 5, seed = NULL, ...)

Arguments

lattice

Lattice list from make_square_grid() or make_hex_lattice().

lookups

Lookup list from make_lookups().

d_per_tick

⁠P → S⁠ decay probability per tick.

n_ticks

Integer number of ticks to advance.

n_seeds

Integer number of cells to seed in state E at tick 0.

seed

Optional integer for set.seed() to make the run reproducible.

...

Additional arguments forwarded to ca_step() (e.g. P_recovery_sus, grow_per_tick).

Value

Integer matrix of shape ⁠(n_ticks + 1, npop)⁠ with row t + 1 the state at tick t.


Run all v1 diagnostics on a fit.

Description

Bundles diagnose_chain_stuck(), diagnose_bound_piling(), and diagnose_low_kappa(). Returns a list of records (length 0 to 3); pass bounds = NULL to skip bound-piling.

Usage

run_diagnostics(
  samples,
  bounds = NULL,
  rhat_threshold = 1.5,
  bound_threshold = 0.2,
  bound_edge = 0.05,
  kappa_par = "kappa",
  kappa_threshold = 5
)

Arguments

samples

A monty_samples object or a posterior::draws_array.

bounds

Optional named list of c(low, high) bounds for each fitted parameter. Pass NULL to skip bound-piling detection.

rhat_threshold

Passed to diagnose_chain_stuck().

bound_threshold

Passed to diagnose_bound_piling() as threshold.

bound_edge

Passed to diagnose_bound_piling() as edge.

kappa_par

Passed to diagnose_low_kappa() as par.

kappa_threshold

Passed to diagnose_low_kappa() as threshold.

Value

List of diagnostic records (possibly empty).


Run human stochastic model (dust2/odin2 backend)

Description

Run human stochastic model (dust2/odin2 backend)

Usage

run_human_stochastic_model(params, timesteps, n_particles, n_threads)

Arguments

params

List of parameters

timesteps

Vector of timesteps

n_particles

Number of particles

n_threads

Number of threads

Value

Tidy tibble with results


Run plague metapopulation model

Description

Forward-simulates the metapopulation plague model (inst/odin/plague_stochastic_metapop.R). Same Didelot carcass-based transmission core as run_plague_model(), with rats dispersing between patches at rate mu_r (via contact_r) and humans dispersing at rate mu_h (via contact_h). For each species, susceptible, infected, and recovered individuals migrate at the same rate; carcasses Q are sessile. Human-side: I_h represents both incubating and symptomatic infections (the model has no E_h compartment), and small mu_h is the parsimonious way to express that humans are sedentary on outbreak timescales.

Usage

run_plague_metapop_model(
  scenario = "defaults",
  npop,
  contact_r,
  mu_r,
  contact_h = NULL,
  mu_h = 0,
  K_r,
  K_h,
  I_ini,
  R_ini = NULL,
  I_h_ini = NULL,
  R_h_ini = NULL,
  years = 1,
  timestep = c("daily", "weekly"),
  n_particles = 100,
  n_threads = 1,
  obs_period = 1L,
  seasonal = NULL,
  ...
)

Arguments

scenario

Parameter set name, file path, or list of parameters.

npop

Integer number of patches.

contact_r

Row-stochastic ⁠npop x npop⁠ destination matrix (contact_r[i, j] = probability that a rat leaving patch i arrives in patch j). Must have zero diagonal.

mu_r

Rat migration rate per day. Same value applies to S, I, R rats.

contact_h

Row-stochastic ⁠npop x npop⁠ destination matrix for humans. Defaults to contact_r (assumes humans share the rat-transport network) when NULL. Same validation rules as contact_r.

mu_h

Human migration rate per day (default 0 – sessile humans). Same value applies to S_h, I_h, R_h.

K_r

Length-npop vector of rat carrying capacities per patch.

K_h

Length-npop vector of human carrying capacities per patch.

I_ini

Length-npop vector of initial infected rats per patch.

R_ini

Length-npop vector of initial heritably-resistant rats per patch (default all zero).

I_h_ini

Length-npop vector of initial infected humans per patch (default all zero).

R_h_ini

Length-npop vector of initial recovered humans per patch (default all zero).

years

Number of years to simulate (default 1).

timestep

"weekly" or "daily" (default "daily" – migration is typically a daily-cadence process).

n_particles

Number of particles for the stochastic run.

n_threads

Number of threads for parallel processing.

obs_period

Integer length (in days) of the observation window for D_h / D_r (default 1L; requires timestep = "daily" if > 1).

seasonal

Optional length-n_days per-day multiplier on carcass decay (defaults to no seasonality).

...

Additional scalar parameter overrides (beta_r, rho, ...).

Details

Per-patch parameters (K_r, K_h, I_ini, R_ini, I_h_ini, R_h_ini) must be length-npop numeric vectors. All transmission and demographic rates are scalars shared across patches (treat them as biological constants, not place-specific). For per-patch beta_r[i] etc., edit inst/odin/plague_stochastic_metapop.R directly.

Value

plague_results tibble with population column running 1..npop.


Run plague model simulation

Description

Runs the stochastic rats + humans plague model (inst/odin/plague_stochastic_humans.R) via dust2. The spatial rats-only model was retired in April 2026 along with the dust v1 backend (see archive/plague_stochastic.R). Re-adding spatial support means writing a spatial+humans odin2 model first; this function will then grow a npop argument again.

Usage

run_plague_model(
  scenario = "defaults",
  years = 10,
  timestep = c("weekly", "daily"),
  n_particles = 100,
  n_threads = 1,
  K_r = 2500,
  K_h = 5000,
  I_ini = 1,
  obs_period = 1L,
  ...
)

Arguments

scenario

Parameter set name, file path, or list of parameters.

years

Number of years to simulate (default 10).

timestep

Time step resolution: "weekly" or "daily" (default "weekly").

n_particles

Number of particles for the stochastic run.

n_threads

Number of threads for parallel processing.

K_r

Rat carrying capacity (used only when scenario does not set it).

K_h

Human carrying capacity (used only when scenario does not set it).

I_ini

Initial infected rats.

obs_period

Integer length (in days) of the observation window over which D_h and D_r accumulate before resetting. Default 1L keeps the per-day count used by daily-data fits. Set to 7L to make the simulated death series weekly (matching e.g. London 1563). Requires timestep = "daily".

...

Additional parameters to override on top of the scenario.

Value

plague_results object.


Status bar module — server.

Description

Status bar module — server.

Usage

status_bar_server(id, lab_session)

Arguments

id

Module namespace id.

lab_session

A LabSession instance.

Value

Invisibly, the moduleServer result.


Status bar module — UI.

Description

Status bar module — UI.

Usage

status_bar_ui(id)

Arguments

id

Module namespace id.

Value

A shiny::div() styled as a sticky bottom bar.


Summarize outbreak metrics across replicates

Description

Summarize outbreak metrics across replicates

Usage

summarize_outbreak_metrics(outbreak_metrics)

Arguments

outbreak_metrics

Output from calculate_outbreak_metrics

Value

Summary statistics


Summary method for plague_results

Description

Summary method for plague_results

Usage

## S3 method for class 'plague_results'
summary(object, ...)

Arguments

object

plague_results object

...

Additional arguments (ignored)


Modulate per-group seasonal forcing by a fitted alpha exponent.

Description

Replaces each group's seasonal vector with group_seasonal[[g]] ^ alpha. Lets the data inform the strength of seasonality — alpha = 0 collapses seasonal to flat 1, alpha = 1 is the raw climate signal, intermediate values dampen, larger values amplify. Removes alpha from unpacked pars.

Usage

with_alpha_seasonal(packer, group_seasonal)

Arguments

packer

A grouped packer or wrapper around one. Must have alpha as a shared scalar parameter.

group_seasonal

Named list keyed by group; each entry is a numeric vector of per-day seasonal multipliers (length = number of simulation days for that outbreak).

Value

A packer with wrapped ⁠$unpack⁠.


Compute per-group seasonal forcing from temperature via Brière.

Description

For each group, transforms the temperature time series into a per-day multiplier on delta_R (carcass decay) using the Brière function parameterised by fitted T_min, T_max, q_briere. The multiplier is normalised so delta_R equals its scenario value at T_ref (default 17.8°C, the typical mid-range plague-permissive temperature) — i.e. calibrating outside the Brière transformation reaches the unmodulated scenario delta_R at the reference temperature.

Usage

with_briere_seasonal(packer, group_temp, T_ref = 17.8, cap = 1000)

Arguments

packer

A grouped packer or wrapper around one. Must have T_min, T_max, q_briere as shared scalar parameters.

group_temp

Named list keyed by group; each entry is a numeric per-day temperature vector (°C, length = number of simulation days).

T_ref

Reference temperature at which the Brière multiplier equals 1 (i.e. the scenario delta_R is unchanged). Default 17.8°C.

cap

Maximum allowed multiplier — clamps the transmission-off signal when params are out of range. Default 1000.

Details

If T_ref falls outside ⁠[T_min, T_max]⁠ (sampler exploring biologically implausible cliffs), returns cap for all temperatures, which collapses transmission and signals the proposal is bad. Per-temperature points outside ⁠[T_min, T_max]⁠ are also capped. Removes T_min, T_max, q_briere from unpacked pars.

Value

A packer with wrapped ⁠$unpack⁠.


Splice per-group fixed parameters into a grouped packer.

Description

For values that are fixed but vary per group (e.g. each outbreak's K_h, K_r pinned to its Krauer-listed population), monty::monty_packer_grouped()'s fixed argument doesn't help — it's global. This wrapper merges group_fixed[[g]] into each group's pars during unpack.

Usage

with_per_group_fixed(packer, group_fixed)

Arguments

packer

A grouped packer (from monty::monty_packer_grouped()) or a wrapper around one.

group_fixed

Named list keyed by group; each entry is a named list of parameters to splice into that group's unpacked pars. Groups not in group_fixed are passed through unchanged.

Value

A packer with wrapped ⁠$unpack⁠. Class preserved so dust2's grouped filter accepts it.


Convert R0 to beta_r per group during unpack.

Description

Sampling R0 directly (rather than beta_r) gives a more interpretable prior and a flatter posterior geometry. The conversion uses the disease-free equilibrium derivation in the carcass model (see CLAUDE.md "R0 formula"): beta_r = R0 * delta_R / ((1 - g_r) * (1 - exp(-rho))).

Usage

with_R0_to_beta_r(packer)

Arguments

packer

A grouped packer or wrapper around one. Must have R0 as a shared scalar parameter.

Details

Requires g_r, rho, delta_R to already be present in each group's pars (typically via the packer's global fixed argument). Removes R0 from the unpacked pars after conversion.

Value

A packer with wrapped ⁠$unpack⁠.