Composable tools for infectious disease modelling in Julia.
Small, interchangeable parts — delays, latent processes, infection and observation models — that combine into a full joint model. Swap a part to test a different assumption.
Uncertainty propagated correctly from the latent process through infection dynamics and observation. Full Bayesian inference via Turing.jl’s NUTS sampler.
Designed for real-time outbreak analysis: nowcasting, forecasting, and scenario modelling from the same model definition, with reporting delays and ascertainment built in.
Fast, autodiff-ready, and tightly integrated with Turing.jl, SciML, and the Julia scientific ecosystem.
using ComposedDistributions, ModifiedDistributions, Distributions
# A delay tree: incubation → competing outcomes
tree = Sequential([
Gamma(2.0, 1.5), # incubation period
# compete/recover branches
resolve(:death => (Gamma(2.0, 3.0), 0.3), # 30% fatal
:recover => (LogNormal(2.0, 0.8), 0.5), # 50% recover
:hosp => LogNormal(1.5, 0.6)), # 20% hospitalised
])
# Inspect the tree, parameter inventory, and default priors
event_tree(tree)
params_table(tree)
priors = build_priors(params_table(tree))
# Simulate a record and score it
rand(tree)
logpdf(tree, ans)The EpiAware ecosystem is built on a foundation of powerful, composable packages.
Assemble infectious disease models from interchangeable parts as a single Turing model.
Handle the censoring and truncation biases common in epidemiological delay data.
A grammar for composing distributions into event trees.
Rescale, weight, or modify distributions, keeping the full distribution interface.
Assemble a latent process, an infection model, and observation layers into one Turing model. The structure is clear — every part is named and stays inline.
using ComposableTuringIDModels, Distributions, Turing
# Renewal infections with inline latent process
data = IDData(gen_distribution = Gamma(1.4, 1 / 0.38))
model = IDModel(
Renewal(data;
rt = AR(; ϵ_t = HierarchicalNormal(
std_prior = HalfNormal(0.1))),
initialisation_prior = Normal(log(1.0), 1.0)),
# Multiple observation layers:
# delay → ascertainment → negative-binomial noise
LatentDelay(
Ascertainment(
NegativeBinomialError(),
ascertainment_prior = Beta(10, 2)),
truncated(Normal(5.0, 2.0), 0.0, Inf)))
# Fit to case data with Turing's NUTS
chain = sample(as_turing_model(model, cases, length(cases)),
NUTS(), MCMCThreads(), 1_000, 2)Read the latest from the EpiAware team.
We build in Julia for its type system, multiple dispatch, and automatic differentiation, on top of the scientific infrastructure.
Differential equations, sensitivity analysis, and scientific machine learning.
Probabilistic programming and Bayesian inference.
The shared vocabulary of probability distributions our packages extend.
New to Julia? Start with the Using Julia guide.
From R to Julia — the story behind EpiAware.
In R we built the epinowcast ecosystem and packages such as EpiNow2 and scoringutils, now used by academics and public health teams internationally. EpiAware is the Julia equivalent: a domain-focused ecosystem in the mould of SciML or Turing.jl, with community infrastructure like rOpenSci and the domain focus of SpeedyWeather.jl.
We are at an early stage and looking for collaborators — here is how to get involved.