Source code for episia.models.sir
"""
models/sir.py - SIR compartmental epidemic model.
dS/dt = -β * S * I / N
dI/dt = β * S * I / N - γ * I
dR/dt = γ * I
References
----------
Kermack & McKendrick (1927). Proc. Royal Society A, 115, 700-721.
"""
from __future__ import annotations
from typing import Any, Dict, List
import numpy as np
from .base import CompartmentalModel
from .parameters import SIRParameters
[docs]
class SIRModel(CompartmentalModel):
"""
SIR epidemic model.
Args:
parameters: SIRParameters instance.
Example::
from episia.models import SIRModel
from episia.models.parameters import SIRParameters
params = SIRParameters(
N=1_000_000,
I0=10,
beta=0.3,
gamma=0.1,
t_span=(0, 200),
)
model = SIRModel(params)
result = model.run()
print(model.summary())
result.plot().show()
"""
[docs]
def __init__(self, parameters: SIRParameters):
if not isinstance(parameters, SIRParameters):
raise TypeError(
f"Expected SIRParameters, got {type(parameters).__name__}."
)
super().__init__(parameters)
@property
def compartment_names(self) -> List[str]:
return ["S", "I", "R"]
def _initial_state(self) -> np.ndarray:
p = self.parameters
return np.array([p.S0, p.I0, p.R0_init])
def _derivatives(self, t: float, y: np.ndarray) -> np.ndarray:
S, I, R = y
N = float(self.parameters.N)
beta = self.parameters.beta
gamma = self.parameters.gamma
force_of_infection = beta * S * I / N
dS = -force_of_infection
dI = force_of_infection - gamma * I
dR = gamma * I
return np.array([dS, dI, dR])
def _compute_metrics(
self,
t: np.ndarray,
solution: np.ndarray,
) -> Dict[str, Any]:
S, I, R = solution
N = float(self.parameters.N)
p = self.parameters
# Peak
peak_idx = int(np.argmax(I))
peak_infected = float(I[peak_idx])
peak_time = float(t[peak_idx])
# Final size (fraction of population ever infected)
final_size = float(R[-1]) / N
# Herd immunity threshold
from .solver import estimate_herd_immunity
hit = estimate_herd_immunity(p.r0)
return {
"r0": p.r0,
"peak_infected": peak_infected,
"peak_time": peak_time,
"final_size": final_size,
"herd_immunity_threshold": hit,
}
__all__ = ["SIRModel"]