SEIR
Overview
The SEIR function numerically solves the SEIR system of ordinary differential equations for infectious disease modeling, describing the dynamics of susceptible, exposed, infected, and recovered populations. The SEIR model is a classic compartmental model in epidemiology, governed by the following equations:
where is the number of susceptible individuals, is exposed (infected but not yet infectious), is infectious, is recovered, is the total population, is the infection rate, is the rate at which exposed individuals become infectious, and is the recovery rate. The function uses SciPy’s ODE solver (scipy.integrate.solve_ivp ) to integrate the system over a specified time interval. Only the most commonly used parameters are exposed; features such as stochasticity, age structure, or spatial effects are not supported. The integration method can be selected from several common solvers, but only the most used options are exposed. This example function is provided as-is without any representation of accuracy.
Usage
To use the function in Excel:
=SEIR(s_initial, e_initial, i_initial, r_initial, beta, gamma, sigma, t_start, t_end, [timesteps], [solve_ivp_method])s_initial(float, required): Initial number of susceptible individuals.e_initial(float, required): Initial number of exposed individuals.i_initial(float, required): Initial number of infected individuals.r_initial(float, required): Initial number of recovered individuals.beta(float, required): Infection rate parameter.gamma(float, required): Recovery rate parameter.sigma(float, required): Rate at which exposed individuals become infectious.t_start(float, required): Start time of integration.t_end(float, required): End time of integration.timesteps(int, optional, default=10): Number of timesteps to solve for.solve_ivp_method(string (enum), optional, default=‘RK45’): Integration method. Valid options:RK45,RK23,DOP853,Radau,BDF,LSODA.
The function returns a 2D array (table) with columns: t, S, E, I, R, representing time and compartment values at each step. If the input is invalid or integration fails, a string error message is returned.
Examples
Example 1: Basic Case (Default Method)
Inputs:
| s_initial | e_initial | i_initial | r_initial | beta | gamma | sigma | t_start | t_end | timesteps |
|---|---|---|---|---|---|---|---|---|---|
| 990.0 | 0.0 | 10.0 | 0.0 | 0.3 | 0.1 | 0.2 | 0.0 | 10.0 | 10 |
Excel formula:
=SEIR(990.0, 0.0, 10.0, 0.0, 0.3, 0.1, 0.2, 0.0, 10.0, 10)Output:
| t | S | E | I | R |
|---|---|---|---|---|
| 0.000 | 990.000 | 0.000 | 10.000 | 0.000 |
| 1.111 | 986.846 | 2.824 | 9.266 | 1.064 |
| 2.222 | 983.839 | 4.957 | 9.123 | 2.081 |
| 3.333 | 980.816 | 6.681 | 9.396 | 3.107 |
| 4.444 | 977.662 | 8.181 | 9.977 | 4.180 |
| 5.556 | 974.288 | 9.580 | 10.799 | 5.333 |
| 6.667 | 970.627 | 10.960 | 11.826 | 6.588 |
| 7.778 | 966.617 | 12.377 | 13.038 | 7.967 |
| 8.889 | 962.207 | 13.872 | 14.429 | 9.492 |
| 10.000 | 957.345 | 15.476 | 15.999 | 11.180 |
Example 2: With Optional Method (RK23)
Inputs:
| s_initial | e_initial | i_initial | r_initial | beta | gamma | sigma | t_start | t_end | timesteps | method |
|---|---|---|---|---|---|---|---|---|---|---|
| 990.0 | 0.0 | 10.0 | 0.0 | 0.3 | 0.1 | 0.2 | 0.0 | 10.0 | 10 | RK23 |
Excel formula:
=SEIR(990.0, 0.0, 10.0, 0.0, 0.3, 0.1, 0.2, 0.0, 10.0, 10, "RK23")Output:
| t | S | E | I | R |
|---|---|---|---|---|
| 0.000 | 990.000 | 0.000 | 10.000 | 0.000 |
| 1.111 | 986.846 | 2.824 | 9.266 | 1.064 |
| 2.222 | 983.839 | 4.957 | 9.123 | 2.081 |
| 3.333 | 980.816 | 6.681 | 9.396 | 3.107 |
| 4.444 | 977.662 | 8.181 | 9.977 | 4.180 |
| 5.556 | 974.288 | 9.580 | 10.799 | 5.333 |
| 6.667 | 970.627 | 10.960 | 11.826 | 6.588 |
| 7.778 | 966.617 | 12.377 | 13.038 | 7.967 |
| 8.889 | 962.207 | 13.872 | 14.429 | 9.492 |
| 10.000 | 957.345 | 15.476 | 15.999 | 11.180 |
Example 3: Longer Time Span
Inputs:
| s_initial | e_initial | i_initial | r_initial | beta | gamma | sigma | t_start | t_end | timesteps |
|---|---|---|---|---|---|---|---|---|---|
| 990.0 | 0.0 | 10.0 | 0.0 | 0.3 | 0.1 | 0.2 | 0.0 | 50.0 | 10 |
Excel formula:
=SEIR(990.0, 0.0, 10.0, 0.0, 0.3, 0.1, 0.2, 0.0, 50.0, 10)Output:
| t | S | E | I | R |
|---|---|---|---|---|
| 0.000 | 990.000 | 0.000 | 10.000 | 0.000 |
| 5.556 | 974.288 | 9.580 | 10.799 | 5.333 |
| 11.111 | 951.980 | 17.212 | 17.755 | 13.054 |
| 16.667 | 915.756 | 28.488 | 29.771 | 25.985 |
| 22.222 | 858.735 | 45.141 | 48.709 | 47.415 |
| 27.778 | 774.719 | 67.175 | 76.371 | 81.735 |
| 33.333 | 662.602 | 91.200 | 112.355 | 133.844 |
| 38.889 | 531.721 | 109.582 | 151.502 | 207.195 |
| 44.444 | 401.445 | 114.072 | 183.605 | 300.878 |
| 50.000 | 291.178 | 102.642 | 198.257 | 407.923 |
Example 4: Different Parameters
Inputs:
| s_initial | e_initial | i_initial | r_initial | beta | gamma | sigma | t_start | t_end | timesteps |
|---|---|---|---|---|---|---|---|---|---|
| 950.0 | 20.0 | 30.0 | 0.0 | 0.5 | 0.2 | 0.3 | 0.0 | 10.0 | 10 |
Excel formula:
=SEIR(950.0, 20.0, 30.0, 0.0, 0.5, 0.2, 0.3, 0.0, 10.0, 10)Output:
| t | S | E | I | R |
|---|---|---|---|---|
| 0.000 | 950.000 | 20.000 | 30.000 | 0.000 |
| 1.111 | 934.067 | 27.890 | 31.278 | 6.765 |
| 2.222 | 917.242 | 34.323 | 34.399 | 14.036 |
| 3.333 | 898.840 | 40.286 | 38.732 | 22.143 |
| 4.444 | 878.459 | 46.248 | 43.976 | 31.317 |
| 5.556 | 855.856 | 52.415 | 49.986 | 41.744 |
| 6.667 | 830.894 | 58.841 | 56.681 | 53.584 |
| 7.778 | 803.524 | 65.494 | 64.000 | 66.982 |
| 8.889 | 773.780 | 72.277 | 71.873 | 82.070 |
| 10.000 | 741.787 | 79.047 | 80.206 | 98.960 |
Python Code
from scipy.integrate import solve_ivp
import numpy as np
def seir(s_initial, e_initial, i_initial, r_initial, beta, gamma, sigma, t_start, t_end, timesteps=10, solve_ivp_method='RK45'):
"""
Numerically solves the SEIR system of ordinary differential equations for infectious disease modeling.
Args:
s_initial: Initial number of susceptible individuals.
e_initial: Initial number of exposed individuals.
i_initial: Initial number of infected individuals.
r_initial: Initial number of recovered individuals.
beta: Infection rate parameter.
gamma: Recovery rate parameter.
sigma: Rate at which exposed individuals become infectious.
t_start: Start time of integration.
t_end: End time of integration.
timesteps: Number of timesteps to solve for. Default is 10.
solve_ivp_method: Integration method ('RK45', 'RK23', 'DOP853', 'Radau', 'BDF', 'LSODA'). Default is 'RK45'.
Returns:
2D list with header row: t, S, E, I, R. Each row contains time and compartment values, or an error message (str) if input is invalid.
This example function is provided as-is without any representation of accuracy.
"""
# Validate inputs
try:
s0 = float(s_initial)
e0 = float(e_initial)
i0 = float(i_initial)
r0 = float(r_initial)
beta_ = float(beta)
gamma_ = float(gamma)
sigma_ = float(sigma)
t0 = float(t_start)
t1 = float(t_end)
ntp = int(timesteps)
except Exception:
return "Invalid input: all initial values, parameters, and timesteps must be numbers."
if t1 <= t0:
return "Invalid input: t_end must be greater than t_start."
if ntp <= 0:
return "Invalid input: timesteps must be a positive integer."
if any(x < 0 for x in [s0, e0, i0, r0, beta_, gamma_, sigma_]):
return "Invalid input: all initial values and parameters must be non-negative."
allowed_methods = ['RK45', 'RK23', 'DOP853', 'Radau', 'BDF', 'LSODA']
if solve_ivp_method not in allowed_methods:
return f"Invalid input: solve_ivp_method must be one of {allowed_methods}."
# Create time array for evaluation
t_eval = np.linspace(t0, t1, ntp)
N = s0 + e0 + i0 + r0
def seir_ode(t, y):
S, E, I, R = y
dSdt = -beta_ * S * I / N
dEdt = beta_ * S * I / N - sigma_ * E
dIdt = sigma_ * E - gamma_ * I
dRdt = gamma_ * I
return [dSdt, dEdt, dIdt, dRdt]
try:
sol = solve_ivp(
seir_ode,
[t0, t1],
[s0, e0, i0, r0],
method=solve_ivp_method,
dense_output=False,
rtol=1e-6,
atol=1e-8,
t_eval=t_eval
)
except Exception as e:
return f"ODE integration error: {e}"
if not sol.success:
return f"ODE integration failed: {sol.message}"
result = [["t", "S", "E", "I", "R"]]
for i in range(len(sol.t)):
t_val = float(sol.t[i])
s_val = float(sol.y[0][i])
e_val = float(sol.y[1][i])
i_val = float(sol.y[2][i])
r_val = float(sol.y[3][i])
# Disallow nan/inf
if any([
not isinstance(t_val, float) or not isinstance(s_val, float) or not isinstance(e_val, float) or not isinstance(i_val, float) or not isinstance(r_val, float),
t_val != t_val or s_val != s_val or e_val != e_val or i_val != i_val or r_val != r_val,
abs(t_val) == float('inf') or abs(s_val) == float('inf') or abs(e_val) == float('inf') or abs(i_val) == float('inf') or abs(r_val) == float('inf')
]):
return "Invalid output: nan or inf detected."
result.append([t_val, s_val, e_val, i_val, r_val])
return result