The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

Flexible Extended State-Space Epidemiological Models with Modern Inference
eSIR (Song Lab, 2020) was a pioneering R package for
COVID-19 modelling that introduced time-varying quarantine protocols
into a Bayesian SIR framework. After studying its architecture, we
identified 15+ structural limitations and designed
EpiNova as a ground-up redesign.
# Install from GitHub
devtools::install_github("causalfragility-lab/EpiNova")
# Core dependencies (installed automatically)
# deSolve, ggplot2, dplyr, tidyr, splines, scales
# Optional — unlock extra capabilities
install.packages("DEoptim") # faster global optimisation in fit_mle()
install.packages("EpiEstim") # full Bayesian Rt estimation
install.packages("MASS") # parametric bootstrap uncertainty
install.packages("numDeriv") # Hessian-based confidence intervals
install.packages("cmdstanr") # HMC backend (Stan)No JAGS binary required. Core functionality is pure R.
library(EpiNova)
# --- Built-in Hubei COVID-19 data ---
props <- prep_proportions(hubei_covid) # Y = active infected, R = removed
# --- Smooth spline intervention ---
pi_fn <- build_pi_spline(
knot_times = c(0, 10, 22, 60),
knot_values = c(1, 0.9, 0.4, 0.25)
)
# --- Solve SEIRD ODE ---
traj <- solve_model(
params = list(beta = 0.35, gamma = 0.07, sigma = 0.2, delta = 0.005),
init = c(S = 0.9999, E = 0.00005, I = 0.00005, R = 0, D = 0),
times = 0:200,
model = "SEIRD",
pi_fn = pi_fn
)
plot_trajectory(traj, obs_Y = props$Y, obs_R = props$R, T_obs_end = 29)
# --- Scenario comparison ---
sc <- do.call(rbind, lapply(
list("No NPI" = function(t) 1,
"Lockdown" = build_pi_step(c(10), c(1, 0.4)),
"Spline" = pi_fn),
function(pi) {
tr <- solve_model(
list(beta=0.35, gamma=0.07, sigma=0.2, delta=0.005),
c(S=0.9999, E=5e-5, I=5e-5, R=0, D=0), 0:200, "SEIRD", pi_fn=pi)
data.frame(time=tr$time, I_median=tr$I,
I_lower=tr$I*0.8, I_upper=tr$I*1.2, scenario=deparse(substitute(pi)))
}
))
plot_scenarios(sc)
# --- Real-time Rt estimation (no extra packages) ---
new_cases <- pmax(0L, diff(hubei_covid$NI))
Rt_df <- estimate_Rt_simple(new_cases, mean_si = 5.2, window = 7L)
plot_Rt(Rt_df, change_times = c(10, 22))eSIR: S → I → R (only)
EpiNova: S → I → R (SIR)
S → E → I → R (SEIR)
S → E → I → R / D (SEIRD)
S ⇄ V → E → I → R (SVEIR)
S ⇄ V → E → I → R / D ← waning immunity (SVEIRD)
[S,E,I,R] × n_age groups + contact matrix (age-SEIR)
All models share the same solve_model(model = "SVEIRD")
interface.
| Builder | Shape | Advantage over eSIR |
|---|---|---|
build_pi_step() |
Step function | Same as eSIR (baseline) |
build_pi_exp() |
Exponential decay | Same as eSIR (baseline) |
build_pi_spline() |
Natural cubic spline | Smooth, realistic policy ramp |
gp_cov_sqexp() |
Gaussian Process prior | Data-driven, non-parametric |
compose_pi() |
Multiplicative composite | Multiple simultaneous NPIs |
build_phi_pulse() |
Gaussian pulse (vs Dirac) | Differentiable for HMC |
# Fast MLE — no external binary needed
fit <- fit_mle(Y, R, N, model = "SEIRD",
par_init = list(beta=0.3, gamma=0.1, sigma=0.2,
delta=0.003, I0=1e-4, E0=2e-4))
# Real-time Sequential Monte Carlo
fit <- fit_smc(Y, R, N, model = "SEIR",
prior_fn = my_prior, n_particles = 2000)
# Dependency-free Rt estimation
Rt <- estimate_Rt_simple(new_cases, mean_si = 5.2, window = 7L)
# Full Bayesian Rt via EpiEstim (when installed)
Rt <- estimate_Rt(new_cases, mean_si = 5.2, sd_si = 2.8)Why it matters: - MLE via DEoptim +
nlminb: 10–100× faster than JAGS MCMC -
SMC enables real-time daily updating — impossible with
JAGS - No JAGS, no rjags, no external binary for core paths
# Build mobility matrix from geography
M <- gravity_mobility(N_vec, dist_mat, kappa = 1e-7)
# Couple n patches with per-patch parameters and interventions
ode <- build_multipatch_SEIR(
n_patches = 3,
M = M,
beta_vec = c(0.35, 0.28, 0.22),
pi_fn_list = list(strict_lockdown, mild_lockdown, function(t) 1)
)
mp_df <- solve_multipatch(ode, init_mat, times = 0:150, n_patches = 3)
plot_multipatch_snapshot(mp_df, t_snapshot = 30,
patch_names = c("Hubei", "Guangdong", "Beijing"))eSIR had zero spatial structure.
# BMA across model types
ens <- ensemble_forecast(Y, R, N,
models = c("SEIR", "SEIRD", "SVEIRD"),
par_inits = list(...), par_bounds = list(...))
# "What-if" scenario projection
sc <- project_scenarios(fit, scenarios = list(
"No intervention" = function(t) 1,
"Light lockdown" = build_pi_step(c(10), c(1, 0.6)),
"Strict lockdown" = build_pi_spline(c(0,10,20,60), c(1,0.8,0.2,0.2))
))
# Score your forecasts with proper scoring rules
score_forecast(ens$ensemble_forecast, actual_Y = Y_holdout)
# Returns: CRPS, 95% coverage, MAEplot_trajectory(traj, obs_Y = Y, obs_R = R, T_obs_end = 29)
plot_forecast(forecast_df, obs_Y = Y)
plot_scenarios(sc_df)
plot_Rt(Rt_df, change_times = c(10, 22))
plot_multipatch_snapshot(mp_df, t_snapshot = 30)EpiNova/
├── R/
│ ├── 01_ode_models.R # solve_model() dispatcher + all ODE systems
│ ├── 02_intervention_functions.R # build_pi_*(), compose_pi(), build_phi_pulse()
│ ├── 03_inference.R # fit_mle(), fit_smc(), estimate_Rt*()
│ ├── 04_multipatch.R # build_multipatch_SEIR(), gravity_mobility()
│ ├── 05_ensemble.R # ensemble_forecast(), project_scenarios(), score_forecast()
│ ├── 06_plotting.R # all plot_*() functions
│ └── 07_data.R # hubei_covid dataset + prep_proportions()
├── tests/testthat/ # 76 unit tests (6 files)
├── vignettes/
│ └── getting_started.Rmd
├── data-raw/
│ └── hubei_covid.R
└── DESCRIPTION
@Manual{EpiNova2025,
title = {EpiNova: Flexible Extended State-Space Epidemiological Models
with Modern Inference},
author = {Hait, Subir},
year = {2026},
note = {R package version 0.1.0},
url = {https://github.com/causalfragility-lab/EpiNova}
}These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.