05
Time grids, lists and NumPy arrays
A numerical epidemic model needs a sequence of time points and a place to store the compartment values at those times. This lesson prepares those structures without yet solving the SIR equations.
Biological scenario
We want to prepare an SIR simulation covering 5 days, with values recorded every 0.5 day. The initial state is \(S(0)=4985\), \(I(0)=12\) and \(R(0)=3\).
How can Python represent the observation times and reserve matching storage for the three compartment histories?
From continuous time to a time grid
The mathematical model describes continuous time, but a numerical program stores results at selected time points:
If \(t_0=0\) and \(\Delta t=0.5\), then
\[t_n=t_0+n\Delta t.\]
There are 10 intervals but 11 stored time points because both the starting and ending times are included.
Python lists
A list stores an ordered collection of values. Square brackets create a list:
observation_days = [0, 1, 2, 3]
infected_counts = [12, 14, 17, 21]
- Python indexing begins at 0, so infected_counts[0] is 12.
- len(infected_counts) returns the number of stored values.
- infected_counts.append(26) adds 26 to the end.
- The time list and infected-count list must have equal lengths if their entries correspond.
Why use NumPy arrays?
Python list
infected = [12, 14, 17, 21]
Flexible general-purpose container. Useful for collecting values gradually.
NumPy array
infected = np.array([12, 14, 17, 21])
Numerical container designed for efficient scientific calculations on many values.
For example, an array can divide every entry in one operation:
infected_proportion = infected / N
A Python list does not perform this numerical operation in the same way.
Important NumPy tools
| Code | Purpose | Important condition |
|---|---|---|
import numpy as np | Loads NumPy and gives it the short name np. | NumPy must be available in the Python environment. |
np.array(values) | Converts supplied values into a NumPy array. | Numerical model arrays should normally contain compatible number types. |
np.linspace(start, end, points) | Creates equally spaced values including both endpoints. | points is the number of stored values, not the number of intervals. |
np.full(length, np.nan) | Creates storage filled with missing-value markers. | np.nan means “not yet assigned a numerical value.” |
array.shape | Reports the dimensions of an array. | A one-dimensional array with 11 values has shape (11,). |
array.dtype | Reports the stored numerical data type. | Arrays containing np.nan use a floating-point type. |
Construct a reliable time grid
Step 1: Calculate intervals and points
number_of_steps = int(round((end_time - start_time) / dt))
number_of_points = number_of_steps + 1
Ten half-day intervals cover 5 days. Adding one includes the initial time point.
Step 2: Create the time array
time = np.linspace(start_time, end_time, number_of_points)
linspace is short for linearly spaced values.
Step 3: Create matching compartment arrays
S = np.full(number_of_points, np.nan)
I = np.full(number_of_points, np.nan)
R = np.full(number_of_points, np.nan)
Each compartment array has exactly one storage position for every time point.
Step 4: Store the initial conditions at index 0
S[0] = 4985
I[0] = 12
R[0] = 3
Index 0 corresponds to \(t=0\). Later, a numerical method will calculate and store the remaining values.
Run the complete preparation program
Output
Run the code to see the result.
Expected outcome
| Index | Time | S | I | R |
|---|---|---|---|---|
| 0 | 0.0 | 4985.0 | 12.0 | 3.0 |
| 1 | 0.5 | nan | nan | nan |
| 2 | 1.0 | nan | nan | nan |
| 3 | 1.5 | nan | nan | nan |
| 4 | 2.0 | nan | nan | nan |
The arrays are prepared but the epidemic has not yet been solved. Only index 0 contains the initial conditions. The nan entries deliberately mark future values that a numerical method still needs to calculate.
Lists and arrays in a modelling workflow
- Use a list when values are being collected flexibly or may contain different kinds of information.
- Use a NumPy array for organised numerical calculations with a fixed shape.
- Corresponding time and compartment arrays must have equal lengths.
- Index \(n\) connects time[n], S[n], I[n] and R[n].
- The time-step size and the spacing of the time array must agree.
Try it yourself
Change end_time = 5 to end_time = 10 while keeping dt = 0.5.
- Predict the new number of intervals.
- Predict the new number of stored points.
- Run the program.
- Check the array shape and explain why it contains one more value than the number of intervals.