# Spatially-aware virus transmission

### 1 collaborator

Ian Heath (Author)

### Tags

covid-19, epidemiology

Tagged by Ian Heath over 3 years ago

spatial

Tagged by Ian Heath over 3 years ago

Tagged by Ian Heath over 3 years ago

Visible to everyone | Changeable by the author
Model was written in NetLogo 6.1.1 • Viewed 234 times • Downloaded 18 times • Run 0 times

## WHAT IS IT?

This model simulates the spread of an infectious disease in a closed population.

It diverges from the classical Kermack-McKendrick model, which we henceforth call the Standard model, in that it takes account of spatial proximity on transmission. It is novel in that it doesn't model the movement of persons but instead assumes that transmission is between static households, and that households can transmit at a distance. Of course in reality, the way this remote transmission takes place is by the movement of persons from the households. However, we don't need to model this movement. We simply assume that transmission is between static households and that it is more likely to be between nearer households. For simplicity, every patch is a household.

This proximity effect is determined by a Reach parameter which is the average distance of transmission to other households. For example, a Reach of 1% means that transmissions are to households that are at a 1% radius of the transmitter, on average. The households at 1% radius are those on the boundary of the 1% of all households that are closest to the transmitter. Note that this 1% radius is only an average. The actual transmission radius is a random-Poisson of the 1% radius.

This is a simple model that is designed only to show the Reach-effect on the spread of infection. It is for experimental purposes only, so that users can see how the Reach% compresses and depresses the spread of the infection and how it differs significantly from the non-spatial Standard model.

I have avoided using the standard term R_0 as it is often misused and could be confused with some of my terms relating to the Removeds measure. Instead I use the term Transmission# (also abbreviated to T#) as I think this is much more self-descriptive.

There are 3 main parameters that can be experimented with using the sliders:

• generation-perHousehold
• meanReach%, and
• Transmission#

The first, generation-perHousehold, requires a little explanation. It means the average number of days from first infection in a household till the day it reinfects other households. This is complicated as there will sometimes be a delay from the first infection in a household and any reinfection of other members in the household who will in turn elongate the total reinfection interval of the household. I have assumed a default which is my guess for Covid-19 and have assumed that secondary infections within the household have little effect on the household reinfection interval. In terms of the Standard Model it equals 1/gamma.

## HOW IT WORKS

Initially, the household at the centre of the World is infected. This household transmits an average T# times at the end of its reinfection interval to other nearby households and then becomes Removed (i.e. recovered or deceased). Infected households, in turn do the same. Thus all households transmit at the end of their reinfection interval, making the model temporally-aware as well as spatially-aware. Temporal awareness only makes a difference because the model is spatially-aware. Restricting transmission to the end of the reinfection interval ensures that the oldest (and hence the less-distributed) households transmit each day. This transmission by the oldest infected is implemented using a queueing system for infected households.

The state of each household is shown by its colour:

• red for the Infectious
• green for the Removed
• black for the still Susceptible

The %Infectious and the %Removed is plotted by day. Examination of the %Infectious plot shows it is approximately the shape of a Normal-distribution curve. It is therefore overlaid with a fitted Normal-distribution curve and the %Removed curve is overlaid with the corresponding fitted curve that is gamma * (the daily accumulated fitted %Infectious). You can see that they are a very good fit.

The reason why the Normal-distribution curve is a better fit than the Standard-model curves is because infection is suppressed by the Reach-effect and the Standard-model does not take this into account. Also, the Standard-model %Infectious curves show a positive-skew (increasing markedly with T# above 4). Whereas, the Reach-model shows very little skew in the Reach% range of 0.6% to 1.4%, a slight negative-skew when Reach% < 0.6% and a slight positive-skew when Reach% > 1.4%. I suspect that this could be corrected by introducing a skew coefficient into the Random-distribution formula.

## HOW TO USE IT

First, run it with the "view updates" on and observe how the red and green household dots spread through the World, eventually leaving just completely-randomised green households. However, this slows down the model and you will soon want to speed up the runs and plotting by unclicking "view updates" in the Interface ribbon.

As per usual, you can adjust the input-parameter sliders then click the Setup button and then click the Go-forever button (or you can click the Go botton to run single daily steps).

However, you can just click the "run current Transmission#" button to do both. Alternatively, you can click the "run the next Transmission#" button to step-up to the next Transmission# and automatically run that. This latter button is a great-way of observing dynamically how the increasing Transmission# affects the plots.

You can observe how good the Normal-curve fit is. This fit will vary on repeated runs due to stochastic noise and occasionally you will observe an almost perfect fit.

The other item that you may want to vary is the number of households. The default is 250,000 for a World that is 500 by 500. The only way to change this is to resize the World which you can do by clicking Settings on the Interface ribbon.For example, you can set a World that is 1000 by 1000 to produce a number of households (N) of 1 million. I have tested this up to 20 million households, which equates to an approximate population of 50 million persons. Beware though that changing to a bigger World size can be slow and it slows down the run time considerably.

## HOW TO CITE

If you mention this model or the NetLogo software in a publication, we ask that you include the citations below.

For the model itself:

• Ian J Heath, the author, an independent researcher in Canterbury, UK

For the NetLogo software:

I would love to see any comments.

## Posted over 3 years ago

Click to Run Model

```globals [
#I           ;; # of Infectious     - red
#R           ;; # of Removeds       - green   (note: not exactly the integral of #I)
nI           ;; fractional I for the fitted Normal curve
nR           ;; fractional R for the fitted Normal curve
rR0          ;; to align Normal-R with Reach-R at liftoff
RedsQ        ;; list of red patches - to remove the oldest first
T#           ;; # of transmissible (i.e. always infects susceptibles) contacts per household
meanReach    ;; mean infection distance  = radius that spans meanReach% of HHs
gamma        ;; the removal rate per day for infectious households
N            ;; # households  (that fill the whole World)
#Imax        ;; peak #I
ImaxDay      ;; peak #I day
Istdev       ;; standard deviation (width of the "bell") for a Normal curve that best fits the Proximity model I-curve
Ilist        ;; list of daily #Is - used to calc VAR of the fitted I curve
plottingReach;; a switch to turn this off when plotting over it
liftoff      ;; switch = (#I / N > .001)
day          ;; for plotting Normal curves
stopGos
]

to runCurrentT#  ;; avoid having to setup first
setup
while [not stopGos] [go]  ;; run for current T#
end

to runNextT#     ;; to dynamically show the effect of stepping up through each T#
set Transmission#  precision (Transmission# + 0.1) 5   ;; Increment the T#  (note: precision is to correct an anomylous addition error)
runCurrentT#
end

to setup
clear-all
set stopGos   false       ;; enable resumption of go's for this Transmission# - used in runCurrentTransmission#

;; setup the Reach model
set N          count patches
set T#         Transmission#                ;; the T# abbreviation will be used throughout this model
set gamma      1 / generation-perHousehold  ;; removeds per day per infectious HH
set meanReach  sqrt(meanReach% / 100 * N / pi)
set RedsQ      []
ask patch      (world-width / 2) (world-width / 2) [turn-infectious]            ;; infect the origin
set #I         1
set #R         0
set #Imax      #I
set Ilist      []

;; LIFTOFF - startup until liftoff (when #I >= N * .001).  During liftoff "infect&remove" avoids accidentally exhausting all infections.
set liftoff  false                                                              ;; start liftoff
while [#I < N * .001] [goReachModel]                                            ;; run till liftoff
set liftoff  true                                                               ;; achieved liftoff
set rR0  #R / N                                                                 ;; to align Normal-R with Reach-R at liftoff in plotNORMdistFit
set plottingReach true                                                          ;; enable plot of Reach curves until we plot Normal curves over the top of them

reset-ticks
end

to go
goReachModel
;; tally Imax and ImaxDay
if #I > #Imax  [
set #Imax    #I
set ImaxDay  ticks + 1
]

;; stop when I is passed its peak and nearly exhausted
if (ticks > ImaxDay) and (#I <= N * .0001) [
print (word "N=" N  ", genDays=" generation-perHousehold ", Reach=" meanReach%  "%, T#=" PadRight T# 3  ", ImaxDay=" PadRight ImaxDay 4 ", %Imax=" precision (#Imax / N * 100) 2 ", %R=" precision (#R / N * 100) 1)
plotNORMdistFit
set stopGos true                                                              ;; tell runNextTransmission# to stop go's
stop
]

tick                                                                            ;; advance to next day
end

to goReachModel
;; step the proximity model today. Transmit then remove the oldest reds, according to the removal rate, gamma
set Ilist  lput #I  Ilist                                                       ;; append #I to Ilist
if #I = 0 [stop]
let #newR  max list 1 round(gamma * #I)                                         ;; the number of oldest reds - to transmit and then remove
foreach   (sublist RedsQ 0     #newR         ) [HH -> ask HH [infect&remove]]  ;; transmit these oldest reds (those at the front of the queue), which adds new reds to the back of the queue
set RedsQ (sublist RedsQ #newR (length RedsQ))                                  ;; drop these oldest reds from the front of the list, now that they have been processed
end

to infect&remove  ;; infect and then remove
let #Contacts  ifelse-value liftoff [random-poisson     T#       ] [1 + random-poisson     (T# - 1)       ]
let Reach      ifelse-value liftoff [random-exponential meanReach] [1 + random-exponential (meanReach - 1)]

repeat #Contacts [ ;; make a transmissible contact at distance random-exponential of meanReach
]
turn-removed                                                                    ;; remove this HH, now that it has transmitted
end

to turn-infectious    ;; turn into an "infectious"
set RedsQ  lput self RedsQ                                                      ;; put new red at the back of the queue
set pcolor red      ;; set infectious
set #I  #I + 1
end

to turn-removed       ;; turn into a "removed"
set pcolor green    ;; set removed
set #I  #I - 1
set #R  #R + 1
end

to-report PadRight [number to-length]  ;; to align decimal columns in output
report substring (word number "             ") 0 to-length
end

to plotNORMdistFit
;; plot nI (the Normal curve that fits the Reach I curve) and nR (the R curve that is the accumulation of nI * gamma), alongside the Reach I and R curves

set plottingReach false   ;; to cease plotting the Reach curves while plotting the Normal curves over the Reach curves

;; plot the nI and nR plots
let Imax    #Imax / N
let cumI    #R / gamma                                                          ;; cumI = the integral of the Reach #I-curve
set Istdev  cumI / (#Imax * sqrt(2 * pi))

set nR   rR0                                                                    ;; to align nR with rR at liftoff

set day  (- 1)
set day  0
repeat ticks + 1 [
set day  day + 1
set nI   Imax * exp(-(((day - ImaxDay)/ Istdev)^ 2)/ 2)                       ;; the Normal distribution with this ImaxDay and Istdev
set nR   nR + nI * gamma
update-plots
]
end
```

There are 2 versions of this model.