← Deterministic Models

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:

1 EQUATIONSThe derivative function
2 TIME INTERVALStarting and ending times
3 INITIAL STATECompartment values at the start
4 PARAMETERSBiological rate values
5 OUTPUT TIMESTimes at which results are requested

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

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
    ]
PartMeaning
tThe current time supplied by the solver. The basic SIR equations do not use it explicitly, but the required function signature includes it.
yThe current state array. For SIR, it contains \([S,I,R]\).
S, I, R = yUnpacks the state array into meaningful compartment names.
beta, gammaAdditional 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
)
ArgumentDefinition and use
sir_rhsThe 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_timesThe 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.
rtolRelative error tolerance, scaled in relation to solution size.
atolAbsolute 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 times
solution.ytwo-dimensional array of compartment results
solution.successBoolean indicating whether integration finished successfully

For 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

Interactive PythonSIR and SEIR with solve_ivp

Output

Run the code to see the result.

Additional returned information

AttributeMeaning
solution.successTrue when the solver reaches the end successfully.
solution.messageA textual explanation of termination or failure.
solution.nfevNumber of derivative-function evaluations performed.
solution.tReturned time values.
solution.yReturned 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.

  1. Compare nfev for each run.
  2. Compare the reported peak values and times.
  3. Compare the population-conservation errors.
  4. Explain the trade-off between requested accuracy and computation.