API reference
BdbvLinelist.analyse Method
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).
BdbvLinelist.bdbv_model Method
bdbv_model(d; fam, prior_scale) -> AnyTuring 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 —
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.
sourceBdbvLinelist.bdbv_model_stratified Method
bdbv_model_stratified(d; fam) -> AnyStratified-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.
BdbvLinelist.build_data Method
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 countsn_admit_died,n_comm_died; andonset_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 (commfromonset_to_comm_death,death_allfromonset_to_death_all), so the deduplication for the weighted likelihoods runs once here rather than inside the models.CFR covariates over all
N = 52cases: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.
sourceBdbvLinelist.community_death_model Method
community_death_model(
uc;
fam,
n_admit_died,
n_comm_died
) -> AnySmall 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.
BdbvLinelist.compare_families Method
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.
BdbvLinelist.compute_waic Method
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.
BdbvLinelist.diagnostics Method
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.
BdbvLinelist.fit_death_mixture Method
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
the main
bdbv_model(foroa,adand the admit-pathway convolutionod_admit = oa ⊛ ad),a separate doubly-censored Gamma for the community-died onset → death distribution
od_comm,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).
sourceBdbvLinelist.fit_growth_rate Method
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 oflog(2) / r_day(days).rising: theDataFrameslice of weekly counts that was fitted.chain: the underlyingTuringchain (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.
BdbvLinelist.load_linelist Function
load_linelist() -> DataFrames.DataFrame
load_linelist(path) -> DataFrames.DataFrameLoad the 2012 Isiro BDBV line list cleaned from the Rosello 2015 eLife supplement. See top of data.jl for the outlier scrub.
BdbvLinelist.plot_epi_curve Method
plot_epi_curve(ll) -> FigureEpidemic curve: weekly onset counts with HCW subcounts stacked.
sourceBdbvLinelist.plot_family_comparison Method
plot_family_comparison(chns_by_family, d; seed) -> FigureSide-by-side posterior predictive comparison across families. One column per family, four rows (one per delay). Used to make the WAIC comparison visually concrete.
sourceBdbvLinelist.plot_ppc Method
plot_ppc(chn, d, family::Symbol; seed) -> FigurePosterior 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).
sourceBdbvLinelist.sample_fit Method
sample_fit(
model;
samples,
chains,
target_accept,
seed,
progress,
adtype
) -> AnyRun 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.
BdbvLinelist.save_figure Method
save_figure(fig, path) -> AnySave a Makie figure to path (PNG by default).
BdbvLinelist.save_posterior Method
save_posterior(post, path) -> AnySave the posterior summary to a CSV.
sourceBdbvLinelist.sensitivity Method
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.
sourceBdbvLinelist.summarise Method
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)).
BdbvLinelist.weekly_onset_counts Method
weekly_onset_counts(ll) -> DataFrames.DataFrameTabulate onset-date counts per ISO week for the loaded line list. Returns a DataFrame with columns (week_start, count, hcw_count).