Epidemics#
Background#
In this project you will develop a simulation which models the spread of a viral infection through a population. Individuals in the population are assumed to be distributed in a grid of cells which might represent a geographical area such as a city or country, and are assigned various states which describe their exposure to the virus. As the simulation progresses, individuals transition between states according to probabilistic rules (see Fig. 1).
Simplified Model#
Fig. 2 shows the results of a simple SIR model of infection on a 6 by 6 grid. Each cell represents an individual in one of three states: Susceptible (S), Infected (I) or Recovered (R). Initially all cells are in the susceptible state except one infected individual. At each timestep, each cell changes state according to the following rules:
A cell in state S which has at least one neighbouring cell in state I changes to state I with probability \(p=0.25\), otherwise remains in state S;
A cell in state I changes to state R with probability \(q=0.25\), otherwise remains in state I;
A cell in state R remains in state R.
In this simulation, we use the definition of a Moore neighbourhood consisting of a cell and each of its eight immediate surrounding neighbours.
SEIQR Model#
A more sophisticated model of infection might include more states and more complicated update rules such as the SEIQR model which extends the SIR model to include Exposed (E) and Quarantined (Q) states and time-dependent update rules [Ghosh and Bhattacharya, 2021].
State |
Description |
---|---|
S |
Susceptible |
E |
Exposed and asymptomatically infected |
I |
Infected, but not yet quarantined |
Q |
Quarantined |
R |
Recovered |
Starter Code#
The following code performs a simulation of susceptible and infected individuals (i.e. excluding recovery).
import numpy as np
import matplotlib.pyplot as plt
# This function takes an n x n array and returns
# a new array after applying the state transition rules
def advance(grid, n, p):
result = np.zeros((n, n))
# loop over all cells in grid (except border cells)
for i in range(1, n-1):
for j in range(1, n-1):
# determine the number of infected neighbours of cell i,j
num_infected_neighbours = np.sum(grid[i-1:i+2,j-1:j+2] == 1)
# if cell i,j is susceptible and has at least one infected neighbour,
# it becomes infected with probability p
if grid[i,j] == 0:
if num_infected_neighbours > 0 and np.random.rand() < p:
result[i,j] = 1
else:
result[i,j] = 0
# if cell i,j is infected it remains infected
elif grid[i,j] == 1:
result[i,j] = 1
return result
# run simulation
grid = np.zeros((5,5))
grid[2,2] = 1
print("Initial state\n", grid)
for i in range(5):
grid = advance(grid, 5, 0.2)
print("Iteration", i + 1 , "\n", grid)