| Title: | Mobility-Based SEAIR Epidemic Models |
|---|---|
| Description: | Tools for simulating, analysing, and fitting mobility-based SEAIR (Susceptible-Exposed-Asymptomatic-Infectious-Recovered) compartmental epidemic models with heterogeneous individual mobility. Each individual carries a fixed mobility trait that scales susceptibility and infectiousness through a rank-one kernel, extending the mobility-based compartmental framework of Jiang et al. (2025) <doi:10.1137/24M1691557> by adding a latent stage and a behavioural split between asymptomatic and symptomatic infectiousness. Provides a numerical solver for the underlying partial differential equation system, closed-form computation of the basic reproduction number R0 and the final epidemic size, and a parametric least-squares routine for recovering the mobility distribution from an observed aggregate symptomatic time series. |
| Authors: | Weinan Wang [aut, cre] |
| Maintainer: | Weinan Wang <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0 |
| Built: | 2026-06-10 06:56:31 UTC |
| Source: | https://github.com/cran/seairmobility |
The seairmobility package provides tools for simulating and
analysing mobility-based SEAIR compartmental epidemic models.
Each individual in the population carries a fixed mobility trait
that scales both their susceptibility and their
infectiousness through a rank-one transmission kernel. The
infectious period is split into an asymptomatic stage with
relative infectiousness and a symptomatic stage with
mobility-reduction factor .
The main functions are
seair_paramsBuild a parameter list.
seair_initBuild initial conditions.
seair_solveSolve the SEAIR system.
seair_aggregateAggregate solution over mobility.
R0_seairBasic reproduction number.
final_sizeFinal epidemic size under vanishing seed.
fit_mobilityParametric least-squares fit of the mobility distribution from an observed symptomatic time series.
Maintainer: Weinan Wang [email protected]
Jiang, N., Chu, W., and Li, Y. (2025). Modeling, inference, and prediction in mobility-based compartmental models for epidemiology. SIAM Journal on Applied Mathematics, 85(5), 2355–2375. doi:10.1137/24M1691557.
Evaluates a weighted mixture of Beta densities
renormalised on . Weights are coerced to be nonnegative
and to sum to one.
beta_mixture_density(m, weights, shape1, shape2)beta_mixture_density(m, weights, shape1, shape2)
m |
Numeric vector of finite evaluation points in |
weights |
Numeric vector of mixture weights (length |
shape1 |
Numeric vector of Beta |
shape2 |
Numeric vector of Beta |
Numeric vector of densities at m.
m <- seq(0, 1, length.out = 101) beta_mixture_density(m, weights = c(0.5, 0.3, 0.2), shape1 = c(2, 5, 9), shape2 = c(8, 3, 2))m <- seq(0, 1, length.out = 101) beta_mixture_density(m, weights = c(0.5, 0.3, 0.2), shape1 = c(2, 5, 9), shape2 = c(8, 3, 2))
Computes the scalar
the integrated contribution of a unit of newly infected mass to
the force of infection, collapsing the stage
chain into a single number. The latency rate does
not appear in .
c_effective(params)c_effective(params)
params |
A |
A positive scalar.
pars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) c_effective(pars)pars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) c_effective(pars)
Solves the scalar fixed-point equation
for the first mobility moment of the recovered compartment at the
end of the epidemic (with , ,
), and returns the total final epidemic size
When the basic reproduction number is less than or equal to one,
the function returns .
final_size(params, f, m_grid = NULL, tol = 1e-10)final_size(params, f, m_grid = NULL, tol = 1e-10)
params |
A |
f |
A mobility density, either a function on |
m_grid |
Optional mobility grid used when |
tol |
Tolerance for |
A list with R_inf (total final size),
MR_inf (first moment), R0 (basic reproduction
number), and converged (logical).
pars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) f <- function(m) 6 * m * (1 - m) final_size(pars, f)pars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) f <- function(m) 6 * m * (1 - m) final_size(pars, f)
Solves the scalar equation of Theorem 4.3 (final-size relation),
allowing a nonzero initial symptomatic fraction
, with .
final_size_general(params, f, m_grid = NULL, I_seed = 1e-04, tol = 1e-10)final_size_general(params, f, m_grid = NULL, I_seed = 1e-04, tol = 1e-10)
params |
A |
f |
A mobility density, either a function on |
m_grid |
Optional mobility grid used when |
I_seed |
Initial symptomatic fraction. |
tol |
Tolerance for |
A list with R_inf, MR_inf, R0, and
converged.
pars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) f <- function(m) 6 * m * (1 - m) final_size_general(pars, f, I_seed = 0.001)pars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) f <- function(m) 6 * m * (1 - m) final_size_general(pars, f, I_seed = 0.001)
Fits a Beta-mixture mobility distribution by minimising the
sum of squared errors between an observed aggregate symptomatic
time series and the simulated output of
the mobility-based SEAIR model at the same times. All transmission
and stage parameters are held fixed.
fit_mobility( times, I_obs, params, K = 3, m_grid = seq(0, 1, length.out = 51), I_seed = 1e-04, start = NULL, n_restarts = 5, control = list(maxit = 500), verbose = FALSE )fit_mobility( times, I_obs, params, K = 3, m_grid = seq(0, 1, length.out = 51), I_seed = 1e-04, start = NULL, n_restarts = 5, control = list(maxit = 500), verbose = FALSE )
times |
Numeric vector of observation times (starting at 0). |
I_obs |
Observed aggregate symptomatic fraction at each time. |
params |
A |
K |
Number of Beta-mixture components (default 3). |
m_grid |
Mobility grid for the solver. |
I_seed |
Initial symptomatic fraction in |
start |
Optional finite user-supplied starting parameter vector of
length |
n_restarts |
Number of random restarts (default 5). |
control |
List of |
verbose |
Logical; if |
The unconstrained optimisation parameter is, for each component
, a triple
with mixture weights
recovered as . The
first weight's log is fixed to 0 to remove the scale ambiguity,
so the parameter vector has length .
A list with weights, shape1, shape2
(the fitted Beta-mixture parameters), f_hat (density on
m_grid), m_grid, loss (final SSE),
I_fit (simulated aggregate symptomatic time series at
times), and optim_result.
pars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) m <- seq(0, 1, length.out = 21) f_true <- dbeta(m, 3, 3) init <- seair_init(m, f_true, I_seed = 1e-4) times <- seq(0, 20, by = 5) sol <- seair_solve(init, pars, times) I_obs <- seair_aggregate(sol)$I fit <- fit_mobility(times, I_obs, pars, K = 1, m_grid = m, start = log(c(3, 3)), n_restarts = 0, control = list(maxit = 20)) fit$losspars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) m <- seq(0, 1, length.out = 21) f_true <- dbeta(m, 3, 3) init <- seair_init(m, f_true, I_seed = 1e-4) times <- seq(0, 20, by = 5) sol <- seair_solve(init, pars, times) I_obs <- seair_aggregate(sol)$I fit <- fit_mobility(times, I_obs, pars, K = 1, m_grid = m, start = log(c(3, 3)), n_restarts = 0, control = list(maxit = 20)) fit$loss
Convenience plot of the five aggregate compartment trajectories produced by a SEAIR solution.
plot_seair(sol, which = c("S", "E", "A", "I", "R"), ...)plot_seair(sol, which = c("S", "E", "A", "I", "R"), ...)
sol |
A |
which |
Character vector of compartments to plot; any subset
of |
... |
Additional graphical parameters passed to
|
Invisibly returns the aggregate data frame.
m <- seq(0, 1, length.out = 31) f <- dbeta(m, 2, 2) init <- seair_init(m, f, I_seed = 1e-4) pars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) sol <- seair_solve(init, pars, times = seq(0, 30, by = 2)) plot_seair(sol, which = c("S","I","R"))m <- seq(0, 1, length.out = 31) f <- dbeta(m, 2, 2) init <- seair_init(m, f, I_seed = 1e-4) pars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) sol <- seair_solve(init, pars, times = seq(0, 30, by = 2)) plot_seair(sol, which = c("S","I","R"))
For a mobility distribution on , the basic
reproduction number at the disease-free equilibrium is
where is as in c_effective and
.
R0_seair(params, f, m_grid = NULL)R0_seair(params, f, m_grid = NULL)
params |
A |
f |
A function returning the density |
m_grid |
Mobility grid (used only if |
The basic reproduction number .
pars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) ## f given as a function (normalised automatically by the caller). f <- function(m) 6 * m * (1 - m) # Beta(2, 2) density on [0, 1] R0_seair(pars, f) ## f given as values on a grid. m <- seq(0, 1, length.out = 101) R0_seair(pars, f(m), m_grid = m)pars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) ## f given as a function (normalised automatically by the caller). f <- function(m) 6 * m * (1 - m) # Beta(2, 2) density on [0, 1] R0_seair(pars, f) ## f given as values on a grid. m <- seq(0, 1, length.out = 101) R0_seair(pars, f(m), m_grid = m)
Computes the aggregate time series
, , etc., using
the trapezoidal rule on the solver's mobility grid.
seair_aggregate(sol)seair_aggregate(sol)
sol |
A |
A data frame with columns time, S, E,
A, I, R (aggregate ratios).
m <- seq(0, 1, length.out = 31) f <- dbeta(m, 2, 2) init <- seair_init(m, f, I_seed = 1e-4) pars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) sol <- seair_solve(init, pars, times = seq(0, 30, by = 2)) agg <- seair_aggregate(sol) head(agg)m <- seq(0, 1, length.out = 31) f <- dbeta(m, 2, 2) init <- seair_init(m, f, I_seed = 1e-4) pars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) sol <- seair_solve(init, pars, times = seq(0, 30, by = 2)) agg <- seair_aggregate(sol) head(agg)
Constructs initial profiles on the
mobility grid from a user-supplied mobility density and a
seed fraction placed in the symptomatic
compartment. The initial condition is "proportional":
,
,
.
seair_init(m_grid, f_vals, I_seed = 1e-04)seair_init(m_grid, f_vals, I_seed = 1e-04)
m_grid |
Numeric vector of mobility grid points in |
f_vals |
Numeric vector of densities |
I_seed |
Non-negative fraction of the population seeded in the
symptomatic compartment (default |
A list of class "seair_init" with entries
m_grid, f, S, E, A, I,
R, and I_seed.
m <- seq(0, 1, length.out = 101) f <- dbeta(m, 2, 2) seair_init(m, f, I_seed = 1e-4)m <- seq(0, 1, length.out = 101) f <- dbeta(m, 2, 2) seair_init(m, f, I_seed = 1e-4)
Constructs and validates the list of transmission and stage-progression
parameters used by the mobility-based SEAIR model
,
,
,
,
,
where
.
seair_params(beta, sigma, kappa, gamma_A, gamma_I, alpha = 1, delta = 1)seair_params(beta, sigma, kappa, gamma_A, gamma_I, alpha = 1, delta = 1)
beta |
Transmission rate |
sigma |
Rate |
kappa |
Symptom-onset rate |
gamma_A |
Recovery rate |
gamma_I |
Recovery rate |
alpha |
Relative infectiousness |
delta |
Mobility-reduction factor |
A list of class "seair_params" containing the checked
parameters.
seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3)seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3)
Discretises the mobility-based SEAIR system on the user-supplied
mobility grid (using the trapezoidal rule for the non-local
integral ) and integrates the resulting coupled
ODE system over times with deSolve.
seair_solve(init, params, times, method = "lsoda", ...)seair_solve(init, params, times, method = "lsoda", ...)
init |
A |
params |
A |
times |
Numeric vector of times at which the solution is
reported (must be increasing and include |
method |
Integration method passed to |
... |
Additional arguments passed to |
A list of class "seair_solution" with entries
times, m_grid, S, E, A,
I, R (each a matrix of dimension
length(times) by length(m_grid)),
together with the input params and init.
m <- seq(0, 1, length.out = 31) f <- dbeta(m, 2, 2) init <- seair_init(m, f, I_seed = 1e-4) pars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) sol <- seair_solve(init, pars, times = seq(0, 30, by = 2))m <- seq(0, 1, length.out = 31) f <- dbeta(m, 2, 2) init <- seair_init(m, f, I_seed = 1e-4) pars <- seair_params(beta = 1.5, sigma = 0.3, kappa = 0.2, gamma_A = 0.1, gamma_I = 0.13, alpha = 0.5, delta = 0.3) sol <- seair_solve(init, pars, times = seq(0, 30, by = 2))