09
Solving SIR and SEIR with solve_ivp
Writing Euler’s method from scratch reveals how numerical approximation works. For practical modelling, SciPy provides tested differential-equation solvers. Here we use solve_ivp while keeping the biological equations visible.
Biological scenario
We want to solve deterministic SIR and SEIR epidemics in populations of 1,000 people using the same transmission and recovery parameters. The SEIR model additionally uses a five-day mean exposed period.
We will compare the infectious peaks and inspect how introducing the exposed stage changes epidemic timing.
What solve_ivp does
The name means “solve an initial-value problem.” An initial-value problem contains:
solve_ivp repeatedly evaluates the derivative function, chooses internal step sizes and returns an approximate solution.
Import the solver
from scipy.integrate import solve_ivp
- scipy is a scientific-computing library.
- integrate is its integration and differential-equation module.
- solve_ivp is the function being imported.
The derivative function has a required form
The solver calls a function using the pattern function(t, y, ...).
def sir_rhs(t, y, beta, gamma):
S, I, R = y
N = S + I + R
infection_flow = beta * S * I / N
recovery_flow = gamma * I
return [
-infection_flow,
infection_flow - recovery_flow,
recovery_flow
]
| Part | Meaning |
|---|---|
t | The current time supplied by the solver. The basic SIR equations do not use it explicitly, but the required function signature includes it. |
y | The current state array. For SIR, it contains \([S,I,R]\). |
S, I, R = y | Unpacks the state array into meaningful compartment names. |
beta, gamma | Additional biological parameters passed through args. |
return [...] | Returns one derivative for every entry in y, in the same order. |
Call solve_ivp
sir_solution = solve_ivp(
sir_rhs,
t_span=(0, 200),
y0=[990, 10, 0],
t_eval=reporting_times,
args=(beta, gamma),
method="RK45",
rtol=1e-8,
atol=1e-10
)
| Argument | Definition and use |
|---|---|
sir_rhs | The derivative function. It is passed without parentheses because the solver must call it repeatedly. |
t_span=(0, 200) | The integration interval: start at day 0 and finish at day 200. |
y0=[990, 10, 0] | The initial state in the same order expected by the derivative function. |
t_eval=reporting_times | The times at which solution values should be returned. |
args=(beta, gamma) | A tuple of extra arguments passed to the derivative function. |
method="RK45" | An adaptive Runge–Kutta method. It is also the default method. |
rtol | Relative error tolerance, scaled in relation to solution size. |
atol | Absolute error tolerance, important when solution values are close to zero. |
Output times are not necessarily solver steps
t_eval specifies where results are reported. It does not force the adaptive solver to use those intervals as its internal steps. The solver may take smaller or larger internal steps while controlling estimated error.
This differs from the manual Euler program, where dt was both the update step and the spacing of stored values.
Understand the returned solution
solution.tone-dimensional array of returned timessolution.ytwo-dimensional array of compartment resultssolution.successBoolean indicating whether integration finished successfullyFor SIR, solution.y has three rows:
S, I, R = sir_solution.y
Each row has one value for every entry of solution.t. For SEIR, the solution has four rows.
Run both models
Output
Run the code to see the result.
Additional returned information
| Attribute | Meaning |
|---|---|
solution.success | True when the solver reaches the end successfully. |
solution.message | A textual explanation of termination or failure. |
solution.nfev | Number of derivative-function evaluations performed. |
solution.t | Returned time values. |
solution.y | Returned state values, organised as variables by times. |
Euler and solve_ivp
Manual Euler method
- One fixed update formula
- Step size selected directly
- Easy to inspect and learn
- Accuracy requires careful step-size testing
solve_ivp
- Established numerical methods
- Adaptive internal step sizes
- Error tolerances supplied directly
- Solver success and diagnostic information returned
Using a library solver does not replace mathematical understanding. The modeller must still define the correct equations, initial conditions, parameters, time interval and biological interpretation.
Biological interpretation
The SIR model moves newly infected people directly into the infectious compartment. The SEIR model delays infectiousness through the exposed compartment. This usually shifts and reshapes the infectious curve.
The displayed comparison is illustrative rather than a controlled scientific comparison because the two models have different compartment structures and initial-state definitions.
Important conditions and common errors
- The order of y0, unpacked variables and returned derivatives must match.
- The derivative function must return the same number of values as the initial-state vector.
- All requested t_eval values must lie inside t_span and be ordered in the integration direction.
- Always inspect solution.success before interpreting results.
- Tighter tolerances usually require more computation; they do not correct an incorrect model.
- Population conservation and non-negativity should still be checked.
Try changing the tolerances
First run the models with rtol=1e-8 and atol=1e-10. Then use rtol=1e-4 and atol=1e-6.
- Compare nfev for each run.
- Compare the reported peak values and times.
- Compare the population-conservation errors.
- Explain the trade-off between requested accuracy and computation.