Skip to content

API reference

BdbvLinelist.analyse Method
julia
analyse(
;
    data,
    output,
    family,
    samples,
    chains,
    seed,
    target_accept,
    progress
) -> Tuple{Any, NamedTuple, NamedTuple{(:rhat, :ess, :ndiv), <:Tuple{Float64, Float64, Any}}}

Load the line list, fit the BDBV delay + CFR model under one distribution family, print the summary, and save the posterior to output/posterior_<family>.csv. Returns (chain, post, diag).

source
BdbvLinelist.bdbv_model Method
julia
bdbv_model(d; fam, prior_scale) -> Any

Turing model for the BDBV Isiro 2012 line list, parametrised by the choice of delay-distribution family (:lognormal, :gamma, or :weibull). Estimates four delay components and a stratified CFR logistic regression.

Per-case latent event times (T_onset, T_admit, T_death, T_disch, T_notif, sampled where observed) are shared across that case's atomic delays, so the natural-history identity (D_oa + D_ad = D_od per case) is enforced in the model rather than recovered in post-processing. Within-day positions are sampled with Sam Abbott's bounded-primary reparametrisation —

julia
T_death/T_disch ~ Uniform(day, day + 1)                       # leaf
T_admit         ~ Uniform(day, min(day + 1, T_death, T_disch))
T_notif         ~ Uniform(day, day + 1)
T_onset         ~ Uniform(day, min(day + 1, T_admit, T_notif))

— which absorbs the ordering constraint into the support and avoids the wedge-shaped boundary geometry NUTS handles poorly at same-day cases. A log(upper − L) Jacobian on each bounded prior restores the implicit independent-uniform-over-day-window prior of the equivalent marginalised model.

Reference: Park et al. 2024 (medRxiv 2024.01.12.24301247) §2.3.3 for the latent-variable formulation; the bounded-primary trick is from Sam Abbott.

source
BdbvLinelist.bdbv_model_stratified Method
julia
bdbv_model_stratified(d; fam) -> Any

Stratified-by-HCW model. Adds an β_*_hcw log-mean shift to each of the four atomic delay components, so HCW vs non-HCW cases share the shape parameter but can differ on the central tendency.

Reports per-delay HCW odds-ratio-like shifts (exp(β_*_hcw)) = multiplicative effect on the delay mean for HCWs vs non-HCWs.

source
BdbvLinelist.build_data Method
julia
build_data(
    ll
) -> NamedTuple{(:onset_to_admit, :admit_to_death, :admit_to_discharge, :onset_to_notif, :hcw_oa, :hcw_ad, :hcw_ac, :hcw_on, :oa_h, :oa_n, :ad_h, :ad_n, :ac_h, :ac_n, :on_h, :on_n, :onset_to_comm_death, :n_admit_died, :n_comm_died, :onset_to_death_all, :case_events, :unique_counts, :outcome, :hcw, :probable, :age_z, :N), <:Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Bool}, Vector{Bool}, Vector{Bool}, Vector{Bool}, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}, Vector{Float64}, Any, Int64, Vector{Float64}, Any, @NamedTuple{oa_h::Tuple{Vector{Float64}, Vector{Int64}}, oa_n::Tuple{Vector{Float64}, Vector{Int64}}, ad_h::Tuple{Vector{Float64}, Vector{Int64}}, ad_n::Tuple{Vector{Float64}, Vector{Int64}}, ac_h::Tuple{Vector{Float64}, Vector{Int64}}, ac_n::Tuple{Vector{Float64}, Vector{Int64}}, on_h::Tuple{Vector{Float64}, Vector{Int64}}, on_n::Tuple{Vector{Float64}, Vector{Int64}}, comm::Tuple{Vector{Float64}, Vector{Int64}}, death_all::Tuple{Vector{Float64}, Vector{Int64}}}, Vararg{Any, 5}}}

Build the model input from a cleaned line-list DataFrame.

Returns a named tuple with:

  • four vectors of integer day-delays (one per atomic component): onset_to_admit, admit_to_death, admit_to_discharge, onset_to_notif. Each vector contains only cases for which both endpoint dates are observed and the delay is non-negative.

  • the HCW indicator (hcw_oa, …) and HCW-stratified subsets (oa_h/oa_n, …) of each component, for the stratified model.

  • community-pathway death delays: onset_to_comm_death (died with no recorded admission) plus the counts n_admit_died, n_comm_died; and onset_to_death_all, the marginal onset → death over all cases (admit-pathway + community) for the single-distribution fit.

  • case_events: per-case event-day offsets from onset, for the per-case shared-latent model.

  • unique_counts: precomputed (uniques, counts) pairs (via _unique_counts) for each stratified component subset and the community pathways (comm from onset_to_comm_death, death_all from onset_to_death_all), so the deduplication for the weighted likelihoods runs once here rather than inside the models.

  • CFR covariates over all N = 52 cases: outcome (Bool died), hcw, probable, age_z.

  • N: total number of cases.

The marginal onset → discharge is NOT in the data tuple — it is derived in post-processing from the fitted component distributions.

source
BdbvLinelist.community_death_model Method
julia
community_death_model(
    uc;
    fam,
    n_admit_died,
    n_comm_died
) -> Any

Small standalone model: fits a single doubly-censored delay distribution for the community-died onset → death pathway, plus a Beta-Binomial posterior for p_admit (the population share of fatal cases that pass through the admit-and-died pathway). Used by fit_death_mixture together with the main bdbv_model to build the death-pathway mixture marginal.

source
BdbvLinelist.compare_families Method
julia
compare_families(
;
    data,
    output,
    samples,
    chains,
    seed,
    target_accept,
    progress
) -> Dict{Symbol, Any}

Fit all three families and print a side-by-side comparison of the headline atomic delay means alongside model-comparison via WAIC (per compute_waic).

Returns a Dict keyed by family symbol with (; chain, post, diag, waic) for each.

source
BdbvLinelist.compute_waic Method
julia
compute_waic(
    chn,
    d,
    family::Symbol
) -> @NamedTuple{waic::Float64, lppd::Float64, p_waic::Float64, n_obs::Int64}

Compute WAIC directly from the per-draw delay parameters and the CFR coefficients in the fitted chain. Independent of any pointwise_loglikelihoods machinery so it works uniformly across FlexiChains and family choices.

Returns (; waic, lppd, p_waic, n_obs). Lower WAIC is better. WAIC = −2 (lppd − p_waic) by the standard scaling.

source
BdbvLinelist.diagnostics Method
julia
diagnostics(
    chn
) -> NamedTuple{(:rhat, :ess, :ndiv), <:Tuple{Float64, Float64, Any}}

Convergence diagnostics for chn: (; rhat, ess, ndiv) — max R̂ across scalar parameter entries, min bulk ESS, and divergent transition count.

source
BdbvLinelist.fit_death_mixture Method
julia
fit_death_mixture(
;
    data,
    family,
    samples,
    chains,
    seed,
    target_accept,
    progress,
    n_per_draw
) -> NamedTuple{(:chn_main, :chn_comm, :chn_all, :p_admit, :means_admit, :means_comm, :means_mix, :medians_mix), <:NTuple{8, Any}}

Death-pathway mixture analysis. Fits

  1. the main bdbv_model (for oa, ad and the admit-pathway convolution od_admit = oa ⊛ ad),

  2. a separate doubly-censored Gamma for the community-died onset → death distribution od_comm,

  3. a Beta-Binomial posterior on p_admit = N_admit_died / (N_admit_died + N_comm_died).

The population-mixture marginal is then

od_mix = p_admit · od_admit + (1 − p_admit) · od_comm

sampled per-draw and summarised. Reports all three (community-only, admit-pathway, mixture) side-by-side along with their interpretation ranges in operational terms (early outbreak vs after ETC).

source
BdbvLinelist.fit_growth_rate Method
julia
fit_growth_rate(
    ll;
    n_samples,
    n_chains,
    seed
) -> NamedTuple{(:r_week, :r_day, :doubling_time, :rising, :chain), <:NTuple{5, Any}}

Fit log(λ_t) = α + r·t (Poisson, weekly bins of onset counts) to the rising phase of the Isiro outbreak — week 1 through the modal-count week, inclusive. Intended as an upstream prior source for downstream re-applications (e.g. outbreak-size work in epiforecasts/BVDOutbreakSize).

Returns a named tuple with:

  • r_week, r_day: posterior draws of the growth rate per week and per day.

  • doubling_time: posterior draws of log(2) / r_day (days).

  • rising: the DataFrame slice of weekly counts that was fitted.

  • chain: the underlying Turing chain (for diagnostics).

The fit uses weakly-informative Normal(0, 5) on the intercept and Normal(0, 1) on r_week; 1000 post-warmup samples, 2 chains. The posterior on r_day is the recommended Normal-prior source for downstream models — see LIMITATIONS.md.

source
BdbvLinelist.load_linelist Function
julia
load_linelist() -> DataFrames.DataFrame
load_linelist(path) -> DataFrames.DataFrame

Load the 2012 Isiro BDBV line list cleaned from the Rosello 2015 eLife supplement. See top of data.jl for the outlier scrub.

source
BdbvLinelist.plot_epi_curve Method
julia
plot_epi_curve(ll) -> Figure

Epidemic curve: weekly onset counts with HCW subcounts stacked.

source
BdbvLinelist.plot_family_comparison Method
julia
plot_family_comparison(chns_by_family, d; seed) -> Figure

Side-by-side posterior predictive comparison across families. One column per family, four rows (one per delay). Used to make the WAIC comparison visually concrete.

source
BdbvLinelist.plot_ppc Method
julia
plot_ppc(chn, d, family::Symbol; seed) -> Figure

Posterior predictive check figure: four panels (one per atomic delay), each showing the observed histogram, the simulated day-binned posterior predictive (median + 95% band), and the fitted continuous latent density (median + 95% band, on a secondary y-axis).

source
BdbvLinelist.sample_fit Method
julia
sample_fit(
    model;
    samples,
    chains,
    target_accept,
    seed,
    progress,
    adtype
) -> Any

Run NUTS on model using the given AD backend and per-chain prior init.

adtype defaults to AutoForwardDiff(). On this model it is the fastest-to-compile backend and at least as fast to sample as a reverse-mode backend once the chains run in parallel, so it is the simplest sensible default. Pass another ADTypes backend to override.

A parent MersenneTwister(seed) is used to draw chains child seeds, which are passed as an explicit RNG vector to sample. This avoids mutating the global RNG and keeps results reproducible regardless of unrelated Random calls between runs.

source
BdbvLinelist.save_figure Method
julia
save_figure(fig, path) -> Any

Save a Makie figure to path (PNG by default).

source
BdbvLinelist.save_posterior Method
julia
save_posterior(post, path) -> Any

Save the posterior summary to a CSV.

source
BdbvLinelist.sensitivity Method
julia
sensitivity(
;
    data,
    family,
    samples,
    chains,
    seed,
    target_accept,
    progress,
    scales
) -> Dict{Float64, Any}

Prior sensitivity sweep: fit the canonical (gamma) model under three prior-scale settings (tight 0.5 / default 1.0 / wide 2.0) and tabulate the atomic delay means with their 95% CrIs.

source
BdbvLinelist.summarise Method
julia
summarise(
    chn,
    family::Symbol;
    d,
    seed,
    n_per_draw
) -> NamedTuple{(:family, :mean_oa, :median_oa, :mean_ad, :median_ad, :mean_ac, :median_ac, :mean_on, :median_on, :sd_oa, :sd_ad, :sd_ac, :sd_on, :shape_oa, :shape_ad, :shape_ac, :shape_on, :scale_oa, :scale_ad, :scale_ac, :scale_on, :od_mean, :od_median, :od_sd, :od_p95, :oc_mean, :oc_median, :oc_sd, :oc_p95, :β_0, :β_hcw, :β_def, :β_age, :cfr_baseline, :cfr_hcw_conf, :cfr_nonhcw_prob, :cfr_hcw_prob), <:Tuple{Symbol, Vararg{Any, 36}}}

Build the named tuple of posterior draws and print a headline summary table. Onset → death and onset → discharge are derived in post-processing as convolutions of the fitted onset→admit with admit→death and admit→discharge respectively.

When the model input d is supplied, the in-hospital length-of-stay marginal (admission → departure) is also derived: a per-draw mixture of admit→death and admit→discharge, weighted by the in-hospital fatality among admitted cases (Beta(1 + n_died, 1 + n_discharged)).

source
BdbvLinelist.weekly_onset_counts Method
julia
weekly_onset_counts(ll) -> DataFrames.DataFrame

Tabulate onset-date counts per ISO week for the loaded line list. Returns a DataFrame with columns (week_start, count, hcw_count).

source