Viral Spread

This notebook builds a susceptible-infected-recovered (SIR) model as an AutoReduce System and simulates the full ODE model. The example is intentionally lightweight so it can be used as a documentation smoke test.

SIR model

The model is

\[\begin{split}\begin{aligned} \dot{S} &= -\beta\frac{SI}{N}, \\ \dot{I} &= \beta\frac{SI}{N} - \gamma I, \\ \dot{R} &= \gamma I. \end{aligned}\end{split}\]

The total population \(N = S + I + R\) is conserved by the dynamics.

[ ]:
import numpy as np
from sympy import Symbol

from autoreduce import System, solve_ode

S = Symbol("S")
I = Symbol("I")
R = Symbol("R")
beta = Symbol("beta")
gamma = Symbol("gamma")
N = Symbol("N")

x = [S, I, R]
f = [
    -beta * S * I / N,
    beta * S * I / N - gamma * I,
    gamma * I,
]

population = 1000.0
system = System(
    x,
    f,
    params=[beta, gamma, N],
    params_values=[0.3, 0.08, population],
    x_init=[990.0, 10.0, 0.0],
    C=np.eye(3),
)

Simulate the full model

The ODE solver returns one row per time point and one column per state.

[ ]:
timepoints = np.linspace(0.0, 160.0, 41)
solution = solve_ode(system, timepoints)

solution.shape

Check population conservation

The total population should remain constant up to numerical integration error.

[ ]:
total_population = solution.sum(axis=1)
max_conservation_error = np.max(np.abs(total_population - population))

final_state = dict(zip([str(state) for state in system.x], solution[-1]))
max_conservation_error, final_state