SIR
Overview
The SIR function numerically solves the SIR (Susceptible-Infected-Recovered) system of ordinary differential equations, a classic model for infectious disease spread in a population. The SIR model describes the time evolution of three compartments:
- Susceptible (): individuals who can contract the disease
- Infected (): individuals who are currently infected and can transmit the disease
- Recovered (): individuals who have recovered and are immune
The system is governed by:
where is the total population, is the infection rate, and is the recovery rate. The function uses scipy.integrate.solve_ivp to perform the integration, exposing only the most commonly used parameters for Excel users. The output includes a header row and a time column for clarity. This example function is provided as-is without any representation of accuracy.
Usage
To use the function in Excel:
=SIR(s_initial, i_initial, r_initial, beta, gamma, t_start, t_end, [timesteps], [solve_ivp_method])s_initial(float, required): Initial number of susceptible 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.t_start(float, required): Start time of integration.t_end(float, required): End time of integration.timesteps(integer, optional, default=10): Number of timesteps to solve for.solve_ivp_method(string (enum), optional, default=RK45): Integration method (RK45,RK23,DOP853,Radau,BDF,LSODA).
The function returns a 2D table with a header row: t, S, I, R. Each subsequent row contains the time and corresponding values for susceptible, infected, and recovered individuals. If the input is invalid, an error message (string) is returned.
Examples
Example 1: Basic SIR Simulation
Inputs:
| s_initial | i_initial | r_initial | beta | gamma | t_start | t_end | timesteps |
|---|---|---|---|---|---|---|---|
| 990 | 10 | 0 | 0.3 | 0.1 | 0 | 10 | 10 |
Excel formula:
=SIR(990, 10, 0, 0.3, 0.1, 0, 10, 10)Expected output:
| t | S | I | R |
|---|---|---|---|
| 0.000 | 990.000 | 10.000 | 0.000 |
| 1.111 | 986.318 | 12.440 | 1.242 |
| 2.222 | 981.761 | 15.453 | 2.786 |
| 3.333 | 976.135 | 19.164 | 4.702 |
| 4.444 | 969.208 | 23.717 | 7.075 |
| 5.556 | 960.713 | 29.276 | 10.010 |
| 6.667 | 950.348 | 36.027 | 13.625 |
| 7.778 | 937.769 | 44.164 | 18.067 |
| 8.889 | 922.609 | 53.892 | 23.499 |
| 10.000 | 904.494 | 65.397 | 30.109 |
Example 2: RK23 Integration Method
Inputs:
| s_initial | i_initial | r_initial | beta | gamma | t_start | t_end | timesteps | method |
|---|---|---|---|---|---|---|---|---|
| 990 | 10 | 0 | 0.3 | 0.1 | 0 | 10 | 10 | RK23 |
Excel formula:
=SIR(990, 10, 0, 0.3, 0.1, 0, 10, 10, "RK23")Expected output:
| t | S | I | R |
|---|---|---|---|
| 0.000 | 990.000 | 10.000 | 0.000 |
| 1.111 | 986.319 | 12.439 | 1.242 |
| 2.222 | 981.764 | 15.452 | 2.785 |
| 3.333 | 976.140 | 19.160 | 4.699 |
| 4.444 | 969.223 | 23.707 | 7.070 |
| 5.556 | 960.740 | 29.260 | 10.000 |
| 6.667 | 950.388 | 36.001 | 13.611 |
| 7.778 | 937.836 | 44.122 | 18.042 |
| 8.889 | 922.700 | 53.835 | 23.466 |
| 10.000 | 904.614 | 65.322 | 30.064 |
Example 3: Longer Simulation Time
Inputs:
| s_initial | i_initial | r_initial | beta | gamma | t_start | t_end | timesteps |
|---|---|---|---|---|---|---|---|
| 990 | 10 | 0 | 0.3 | 0.1 | 0 | 50 | 10 |
Excel formula:
=SIR(990, 10, 0, 0.3, 0.1, 0, 50, 10)Expected output:
| t | S | I | R |
|---|---|---|---|
| 0.000 | 990.000 | 10.000 | 0.000 |
| 5.556 | 960.713 | 29.276 | 10.010 |
| 11.111 | 883.036 | 78.862 | 38.102 |
| 16.667 | 719.319 | 174.251 | 106.430 |
| 22.222 | 491.286 | 275.392 | 233.323 |
| 27.778 | 299.172 | 302.787 | 398.041 |
| 33.333 | 186.119 | 258.033 | 555.848 |
| 38.889 | 127.446 | 191.642 | 680.912 |
| 44.444 | 97.391 | 132.333 | 770.276 |
| 50.000 | 81.208 | 87.996 | 830.795 |
Example 4: BDF Integration Method
Inputs:
| s_initial | i_initial | r_initial | beta | gamma | t_start | t_end | timesteps | method |
|---|---|---|---|---|---|---|---|---|
| 990 | 10 | 0 | 0.3 | 0.1 | 0 | 10 | 10 | BDF |
Excel formula:
=SIR(990, 10, 0, 0.3, 0.1, 0, 10, 10, "BDF")Expected output:
| t | S | I | R |
|---|---|---|---|
| 0.000 | 990.000 | 10.000 | 0.000 |
| 1.111 | 986.318 | 12.440 | 1.242 |
| 2.222 | 981.761 | 15.453 | 2.786 |
| 3.333 | 976.133 | 19.165 | 4.702 |
| 4.444 | 969.205 | 23.718 | 7.077 |
| 5.556 | 960.710 | 29.278 | 10.012 |
| 6.667 | 950.344 | 36.026 | 13.630 |
| 7.778 | 937.770 | 44.159 | 18.071 |
| 8.889 | 922.619 | 53.879 | 23.502 |
| 10.000 | 904.515 | 65.375 | 30.110 |
All outputs are rounded to 3 decimal places for display.
Python Code
from scipy.integrate import solve_ivp as scipy_solve_ivp
import numpy as np
def sir(s_initial, i_initial, r_initial, beta, gamma, t_start, t_end, timesteps=10, solve_ivp_method='RK45'):
"""
Solves the SIR system of ordinary differential equations for infection dynamics.
Args:
s_initial: Initial number of susceptible individuals (float).
i_initial: Initial number of infected individuals (float).
r_initial: Initial number of recovered individuals (float).
beta: Infection rate parameter (float).
gamma: Recovery rate parameter (float).
t_start: Start time of integration (float).
t_end: End time of integration (float).
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, I, R. Each row contains time and variable 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)
i0 = float(i_initial)
r0 = float(r_initial)
b = float(beta)
g = float(gamma)
t0 = float(t_start)
tf = float(t_end)
ntp = int(timesteps)
except Exception:
return "Invalid input: All initial values, parameters, and timesteps must be numbers."
if any(x < 0 for x in [s0, i0, r0, b, g]):
return "Invalid input: Initial values and parameters must be non-negative."
if tf <= 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 solve_ivp_method not in ['RK45', 'RK23', 'DOP853', 'Radau', 'BDF', 'LSODA']:
return "Invalid input: solve_ivp_method must be one of 'RK45', 'RK23', 'DOP853', 'Radau', 'BDF', 'LSODA'."
# Create time array for evaluation
t_eval = np.linspace(t0, tf, ntp)
# SIR ODE system
def sir_ode(t, y):
S, I, R = y
N = S + I + R
dSdt = -b * S * I / N
dIdt = b * S * I / N - g * I
dRdt = g * I
return [dSdt, dIdt, dRdt]
# Integrate
try:
sol = scipy_solve_ivp(
sir_ode,
[t0, tf],
[s0, i0, r0],
method=solve_ivp_method,
t_eval=t_eval
)
except Exception as e:
return f"scipy.integrate.solve_ivp error: {e}"
if not sol.success:
return f"Integration failed: {sol.message}"
# Return 2D list: header row, then each row is [t, S, I, R] at each time point
header = ["t", "S", "I", "R"]
result = [header] + [[float(sol.t[i]), float(sol.y[0][i]), float(sol.y[1][i]), float(sol.y[2][i])] for i in range(len(sol.t))]
return result