Skip to main content

V-SEIHR

Vaccinated SEIHR: a Susceptible-Exposed-Infected-Hospitalized-Recovered model with a parallel vaccinated branch. Every compartment has a _vax twin, and vaccine efficacy reduces both susceptibility (VE_S) and severity (VE_H). Pair it with the vaccination block to set vaccination rollout schedule, which adds a flow from Susceptible into Susceptible_vax compartments over a campaign window.

Compartments

The preset declares ten compartments: five clinical states, each with an unvaccinated and a vaccinated version.

  • Susceptible / Susceptible_vax: can be infected; the _vax branch is exposed at a reduced rate.
  • Exposed / Exposed_vax: infected but not yet infectious.
  • Infected / Infected_vax: currently infectious. Vaccinated infectious individuals transmit at the same per-contact rate as unvaccinated; the reduction sits on susceptibility, not transmissibility.
  • Hospitalized / Hospitalized_vax: severe cases under hospital care.
  • Recovered / Recovered_vax: recovered and (transiently) immune; waning, if enabled, returns them to the matching susceptible compartment.

Transitions

The unvaccinated and vaccinated branches mirror each other. Vaccinated susceptibles are exposed by both Infected and Infected_vax (same per-contact rate transmission_rate, attenuated by (1 - VE_S)); the hospitalization split is attenuated by (1 - VE_H) for vaccinated infected.

FromToKindRate
SusceptibleExposedmediated by Infected and Infected_vaxtransmission_rate
ExposedInfectedspontaneousincubation_rate
InfectedRecoveredspontaneous(1 - hosp_proportion) * recovery_rate
InfectedHospitalizedspontaneoushosp_proportion * recovery_rate
HospitalizedRecoveredspontaneoushosp_recovery_rate
RecoveredSusceptiblespontaneouswaning_rate (0 by default)
Susceptible_vaxExposed_vaxmediated by Infected and Infected_vaxtransmission_rate_vax = (1 - VE_S) * transmission_rate
Exposed_vaxInfected_vaxspontaneousincubation_rate
Infected_vaxRecovered_vaxspontaneous(1 - hosp_proportion_vax) * recovery_rate
Infected_vaxHospitalized_vaxspontaneoushosp_proportion_vax * recovery_rate where hosp_proportion_vax = (1 - VE_H) * hosp_proportion
Hospitalized_vaxRecovered_vaxspontaneoushosp_recovery_rate
Recovered_vaxSusceptible_vaxspontaneouswaning_rate

The Susceptible → Susceptible_vax flow is not part of the preset itself; it is added when the request supplies a vaccination block. Without that block the vaccinated branch stays at zero and the model behaves like plain SEIHR.

Equivalent ODE form

For each age group ii, the deterministic mean-field counterpart of the transitions above is:

Unvaccinated branch

dSidt=λiSiνiSi+ωRidEidt=λiSiσEidIidt=σEi(1ph,i)γIiph,iαIidHidt=ph,iαIiδHidRidt=(1ph,i)γIi+δHiωRi\begin{aligned} \frac{dS_i}{dt} &= -\lambda_i S_i - \nu_i S_i + \omega R_i \\[4pt] \frac{dE_i}{dt} &= \lambda_i S_i - \sigma E_i \\[4pt] \frac{dI_i}{dt} &= \sigma E_i - (1 - p_{h,i})\gamma I_i - p_{h,i} \, \alpha I_i \\[4pt] \frac{dH_i}{dt} &= p_{h,i} \, \alpha I_i - \delta H_i \\[4pt] \frac{dR_i}{dt} &= (1 - p_{h,i})\gamma I_i + \delta H_i - \omega R_i \end{aligned}

Vaccinated branch

dSivdt=νiSi(1VES)λiSiv+ωRivdEivdt=(1VES)λiSivσEivdIivdt=σEiv(1(1VEH)ph,i)γIiv(1VEH)ph,iαIivdHivdt=(1VEH)ph,iαIivδHivdRivdt=(1(1VEH)ph,i)γIiv+δHivωRiv\begin{aligned} \frac{dS^v_i}{dt} &= \nu_i S_i - (1 - \text{VE}_S) \, \lambda_i S^v_i + \omega R^v_i \\[4pt] \frac{dE^v_i}{dt} &= (1 - \text{VE}_S) \, \lambda_i S^v_i - \sigma E^v_i \\[4pt] \frac{dI^v_i}{dt} &= \sigma E^v_i - \bigl(1 - (1 - \text{VE}_H) p_{h,i}\bigr)\gamma I^v_i - (1 - \text{VE}_H) p_{h,i} \, \alpha I^v_i \\[4pt] \frac{dH^v_i}{dt} &= (1 - \text{VE}_H) p_{h,i} \, \alpha I^v_i - \delta H^v_i \\[4pt] \frac{dR^v_i}{dt} &= \bigl(1 - (1 - \text{VE}_H) p_{h,i}\bigr)\gamma I^v_i + \delta H^v_i - \omega R^v_i \end{aligned}

Age groups couple through the contact matrix in the force of infection:

λi(t)=βjCijIj(t)+Ijv(t)Nj\lambda_i(t) = \beta \sum_j C_{ij} \, \frac{I_j(t) + I^v_j(t)}{N_j}
SymbolShapeParameter
λi\lambda_iper-ageforce of infection (depends on β\beta = transmission_rate and contact matrix CijC_{ij}; see Vaccine efficacy)
σ\sigmascalarincubation_rate
γ\gamma, α\alphascalarrecovery_rate (in this preset the two I-exit branches share the same total rate; γ\gamma and α\alpha are kept distinct above only to make the I → R vs I → H split explicit)
δ\deltascalarhosp_recovery_rate
ω\omegascalarwaning_rate (zero unless immunity_duration is passed)
ph,ip_{h,i}per-agehosp_proportion
νi\nu_iper-ageper-day vaccination rate from the vaccination block; zero outside any campaign window and outside that campaign's target_age_groups
VES\text{VE}_S, VEH\text{VE}_HscalarVE_S, VE_H

The simulator is fully stochastic: at each step every source compartment is updated by a competing-risks multinomial draw over its out-edges, with leave probability 1eHidt1 - e^{-H_i\,dt} and destination weights proportional to the per-edge rates. The expected dynamics match the mean-field equations above.

Vaccine efficacy

The preset exposes two efficacy parameters, both unitless and in [0,1][0, 1].

VE_S (efficacy against susceptibility) lowers the force of infection on vaccinated susceptibles, reducing their per-exposure probability of getting infected. A separate efficacy against infectiousness (VE_I) would instead reduce transmission from vaccinated infected; that is not modeled here (see the note below).

λivax(t)=(1VES)λi(t),\lambda^{\text{vax}}_i(t) = (1 - \mathrm{VE_S}) \cdot \lambda_i(t),

where

λi(t)=βjCijIj(t)+Ijvax(t)Nj\lambda_i(t) = \beta \sum_j C_{ij}\,\frac{I_j(t) + I_j^{\text{vax}}(t)}{N_j}

is the standard age-structured force of infection, β\beta is transmission_rate, and CijC_{ij} is the contact matrix from the resolved population. Vaccinated infectious individuals transmit at the same per-contact rate as unvaccinated; the reduction sits entirely on the susceptibility side. Internally, the preset stores this as the calculated parameter transmission_rate_vax = (1 - VE_S) * transmission_rate.

VE_H (efficacy against hospitalization, given infection) lowers the hospitalization split for vaccinated infected:

pHvax=(1VEH)pH,p_H^{\text{vax}} = (1 - \mathrm{VE_H}) \cdot p_H,

stored as hosp_proportion_vax = (1 - VE_H) * hosp_proportion.

Limit cases worth remembering:

  • VES=1\mathrm{VE_S} = 1: sterilizing immunity. The vaccinated branch has zero force of infection and never sees breakthrough infections.
  • VES=0\mathrm{VE_S} = 0: no protection against susceptibility. The vaccinated branch's transmission dynamics collapse onto the unvaccinated branch's.
  • VEH=1\mathrm{VE_H} = 1: vaccinated infected never hospitalize (pHvax=0p_H^{\text{vax}} = 0); all flow through Infected_vax → Recovered_vax.
  • VEH=0\mathrm{VE_H} = 0: vaccinated infected hospitalize at the same rate as unvaccinated.

Parameters

Some parameters can be provided in multiple forms. For example, you can provide infectious_period instead of recovery_rate and it gets automatically converted. If both are sent, the rate form wins and the source is dropped silently. See calculated parameters for the conversion machinery.

ParameterStatusDefaultDescription
R0Default2.5Basic reproduction number.
transmission_rateAlternative to R0derivedβ\beta. Default: R0 * recovery_rate / CONTACT_MATRIX_EIGENVALUE_ALL.
incubation_periodDefault3.0 (days)Days from exposure to infectiousness.
incubation_rateAlternative to incubation_periodderivedE → I rate. Default: 1 / incubation_period.
infectious_periodDefault2.5 (days)Days infectious.
recovery_rateAlternative to infectious_periodderivedI exit rate (split into R vs H by hosp_proportion). Default: 1 / infectious_period.
hosp_durationDefault5.0 (days)Days hospitalized before recovery.
hosp_recovery_rateAlternative to hosp_durationderivedH → R rate. Default: 1 / hosp_duration.
waning_rateDefault0.0 (off)R → S rate. Waning is off by default.
immunity_durationAlternative to waning_rateunsetDays from R → S. Pass to enable waning via waning_rate = 1 / immunity_duration.
hosp_proportionDefault[0.002, 0.005, 0.015, 0.05, 0.18]Fraction of unvaccinated Infected who progress to Hospitalized (rest go to Recovered). Age-stratified; the five-bin default aligns with the built-in population. Pass a scalar (e.g. 0.05) for homogeneous behavior, or a length-N list to match a population with a different number of age groups.
VE_SDefault0.7Vaccine efficacy against susceptibility, in [0,1][0, 1]. Lowers the force of infection on vaccinated susceptibles. 0 = no protection, 1 = sterilizing.
VE_HDefault0.85Vaccine efficacy against hospitalization given infection, in [0,1][0, 1].

The derived parameters (transmission_rate_vax, hosp_proportion_vax, I_to_R_rate, I_to_H_rate, Ivax_to_R_rate, Ivax_to_H_rate) are computed automatically from the inputs above and surface in results.parameters when output.include_parameters is set. You can override any of them by passing a matching name in parameters (user-supplied calc-params win on collision).

Examples

All examples below seed 0.1% of the population as Infected at t=0 via an explicit initial_conditions block; the rest of the population starts in Susceptible, and the _vax branch starts at zero. See Initial Conditions for other seeding options.

With a vaccination campaign

V-SEIHR with a flat-count vaccination campaign over a three-month window. VE_S and VE_H drive the protection on the vaccinated branch. See the Campaigns page for the full set of rollout options.

curl -X POST https://epyscenario-api.isi.it/api/v1/simulations \
-H "Content-Type: application/json" \
-d '{
"model": {
"preset": "V-SEIHR",
"parameters": {
"R0": 2.5,
"incubation_period": 3.0,
"infectious_period": 2.5,
"hosp_duration": 5.0,
"hosp_proportion": [0.002, 0.005, 0.015, 0.05, 0.18],
"VE_S": 0.7,
"VE_H": 0.85
}
},
"population": {"name": "United_States"},
"simulation": {"start_date": "2025-01-01", "end_date": "2025-06-30", "Nsim": 10},
"initial_conditions": {
"method": "percentage",
"initial_percentages": {"Infected": 0.1}
},
"vaccination": {
"campaigns": [
{
"start_date": "2025-02-01",
"end_date": "2025-04-30",
"rollout": {"type": "flat_count", "daily_doses": 100000}
}
]
}
}'

Without vaccination

Drop the vaccination block to get the no-intervention baseline (no vaccination rollout). The vaccinated branch stays at zero for the whole run and the model collapses to plain SEIHR (compartments and rates on the unvaccinated branch only). Useful to compare against the vaccinated case above.

curl -X POST https://epyscenario-api.isi.it/api/v1/simulations \
-H "Content-Type: application/json" \
-d '{
"model": {
"preset": "V-SEIHR",
"parameters": {
"R0": 2.5,
"incubation_period": 3.0,
"infectious_period": 2.5,
"hosp_duration": 5.0,
"hosp_proportion": [0.002, 0.005, 0.015, 0.05, 0.18]
}
},
"population": {"name": "United_States"},
"simulation": {"start_date": "2025-01-01", "end_date": "2025-06-30", "Nsim": 10},
"initial_conditions": {
"method": "percentage",
"initial_percentages": {"Infected": 0.1}
}
}'

VE_S and VE_H are omitted here because they only matter once any of the population is in the vaccinated branch; with no campaign and no seeded Susceptible_vax, their values do not affect the trajectory.

With seasonality and a vaccination campaign

Apply seasonality to transmission_rate (peak January 15, trough July 15, per the Northern Hemisphere defaults in Balcan et al., 2010) and run a pre-peak vaccination campaign in autumn so the rollout finishes just before the winter wave hits. Because transmission_rate is itself derived from R0, the seasonal multiplier is applied on top of the evaluated β\beta at each step. See parameter transforms for the full transform reference.

curl -X POST https://epyscenario-api.isi.it/api/v1/simulations \
-H "Content-Type: application/json" \
-d '{
"model": {
"preset": "V-SEIHR",
"parameters": {
"R0": 2.5,
"incubation_period": 3.0,
"infectious_period": 2.5,
"hosp_duration": 5.0,
"hosp_proportion": [0.002, 0.005, 0.015, 0.05, 0.18],
"VE_S": 0.7,
"VE_H": 0.85
}
},
"population": {"name": "United_States"},
"simulation": {"start_date": "2025-08-01", "end_date": "2026-07-31", "Nsim": 10},
"initial_conditions": {
"method": "percentage",
"initial_percentages": {"Infected": 0.1}
},
"parameter_transforms": [
{
"target_parameter": "transmission_rate",
"method": "balcan",
"max_date": "2026-01-15",
"min_date": "2026-07-15",
"min_value": 0.85
}
],
"vaccination": {
"campaigns": [
{
"start_date": "2025-10-15",
"end_date": "2025-12-31",
"rollout": {"type": "flat_count", "daily_doses": 100000}
}
]
},
"output": {"include_parameters": true}
}'