COVID-19 mitigation with personal habits and intermittent short lockdowns

COVID-19 mitigation with personal habits and intermittent short lockdowns preview image

1 collaborator

Tags

Visible to everyone | Changeable by everyone
Model was written in NetLogo 6.1.0 • Viewed 1097 times • Downloaded 70 times • Run 0 times
Download the 'COVID-19 mitigation with personal habits and intermittent short lockdowns' modelDownload this modelEmbed this model

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)


WHAT IS IT?

This is an extension of the "COVID-19 epidemics with Non-Pharmaceutical Interventions and zonal restraints" model (http://modelingcommons.org/browse/one_model/6374), that incorporates some additional interventions including personal hygiene habits (mask-using and hand-washing) as an individual choice, plus an intermittent 3x4 or "accordion lockdown" (the lockdown is periodically enforced 3 days and lifted the following 4 days), along with the possibility of unlocking a particular zone or set of zones. Such new changes implemented in this extended version are documented in the WHAT IS NEW and NEW THINGS TO NOTICE sections at the end of this page. The original model description is given below.

The model is an agent-based system to simulate the evolution of the COVID-19 epidemics and the mitigation impact of Non-Pharmaceutical Interventions (NPI) within a toy city. NPIs are the mechanisms that public health offices around the world are using to attempt to contain the spread of the virus.

We consider a number of NPIs, including social distancing, case isolation, home quarantine, total lockdown, sentinel testing, mask protection and a proposed zonal restriction where these interventions can be applied to separated districts or zones of the city. The effect of these strategies are measured in terms of morbidity, mortality, lethality -infection fatality rate (IFR) and case fatality rate (CFR)-, doubling time, reproduction number and plots of infection, recovery and death during the simulation timeline. The main purpose of the tool is to let modelers assess which NPIs or combination of NPIs can help flattening or crushing the curve of spread of the disease (mitigate or suppress, respectively), and the effects on the corresponding epidemics indicators.

HOW IT WORKS

The model implements the NPIs within the epidemic SIRE+CARDS model (see [1]) as well as the agent behavior rules. We build upon the compartmental SIRE epidemic framework (Susceptible-Infectious-Recovered-Extinct), but we regarded the Infectious compartment as an extended-state consisting of a number of conditions: Confirmed or not (indicating the patient will remain isolated), Risky or not (meaning predisposition to develop severe or critical disease), Asymptomatic or not (meaning patient is unaware of being a virus carrier), Severe or not (meaning it requires to be hospitalized to avoid dead), and Deadly or not (indicating the patient requires Intensive Care Unit -ICU- assistance). The details of event transition rules and condition activation are described in [1].

The simulation tracks an individual disease path for every agent, from susceptible to recovery or death, according to the SIRE+CARDS epidemic model described above. Each agent is assigned a daily routine consisting of going outdoors and returning home with a commuting distance range randomly chosen from {25, 50, 100, 200} unit steps; the actual route the agent follows varies slightly due to random fluctuations in his orientation. In addition the length of each step can be set as a global parameter between 0.1 and 1 units. Similarly, the day length can be defined with a given number of ticks in the range between 600 and 2400.

Individuals interact randomly with other agents around. Virus transmission occurs due to proximity of an infectious agent with other susceptible agent within a spatial radius of 0.5 units; the chance of contagion depends on what mask protection intervention is applied. On recovery from the disease, individuals acquire immunity to the virus so they cannot be re-infected. In this model all deaths are considered to be caused by COVID-19. The flow of events applied to each agent at each timestep are: lifestyle, epidemic, isolation, quarantine, distancing, sentinel, lockdown, illness, clock and indicators (see code and [1] for further details).

In the simulation view area, agents are represented with different shapes according to the zone where they reside. The color of the agent represents its extended state (healthy: same color as zone ground; immune: white; sick: red or yellow if asymptomatic; dead: black X). Special agents intended to implement some of the NPIs such as households for home-quarantine and ambulances for sentinel-testing can also be seen.

HOW TO USE IT

The control panel is organised in sections related to general, city and COVID-19 settings, monitors of epidemic indicators, parameters, action commands to execute the simulation, and a dedicated section for NPI activation with their corresponding parameters.

A typical setup for a simulation run is: POP-SIZE=400 (total number of simulated people or agents), ZONES=9 (number of residential zones), DAYS=60 (period of observation days or simulation length), %-HIGH-RISK=30 (percentage of population with co-morbidities), HOSPITAL-BEDS=12 (total number of hospital beds available), ICU-BEDS=2 (total number of ICU beds available), AMBULANCES-ZONE=1 (number of ambulances or sentinels per zone), HOUSING?=on (show households in the view area), AVG-DURATION=18 (average day period to recover from illness), %-ASYMPTOMATIC=50 (percentage of patients showing mild or no symptoms), TICKS-DAY=1200 (number of ticks after one day elapse), STEP-SIZE=0.1 (distance each agent move every tick), END-DAY=60 (simulation timeline).

Once setup is done, activate or deactivate the NPIs you want to assess (the details of meaning and implementation of each NPI can be found in [1]), then press SETUP, then GO. After a few simulated hours (or ticks) you can seed a patient zero randomly (or many other, if you want) by pressing INFECT. Alternatively, using OUTBREAK you can randomly infect a percentage (%-SPREAD) of the population. Afterwards, you will be able to see the emergence of the epidemic SIRE curves in the plot area, as well as the other epidemic indicators in the monitor area, while the contagion, recover and death of people unfolds as a result of the development of the COVID-19 epidemics with such particular settings.

THINGS TO NOTICE

The NPIs control panel can be used to handle their application even while the epidemic unfolds. For example, you can activate/disactivate a total lockdown at any time, and it will take effect at the 00:00 of the next simulated day. Or you can isolate or release confirmed cases inmmediately, by switching it on or off. Similar thing occurs with the rest of NPIs. In contrast, you should not change any of the other parameters (general, city, or COVID-19 settings), as they are used to setup the model just and only before running the simulation.

There are two distinctive features in this model that allows the application of NPIs with a zonal scope. This means, firstly, you can restrict mobility of agents within their zone of residence; hence, you can try and see if this kind of restriction (ZONE-ENFORCING) is advantageous in flattening the curve when combined with other NPIs compared to the single application of said NPIs. Secondly, when enforcing a TOTAL-LOCKDOWN, you are able to lift this NPI in an arbitrary zone or zones using the PICK-ZONE slider and UNLOCK-ZONE button. Again, you can see how the resulting emergencies compare to maintaining the total lockdown in the entire city. These features may yield interesting insights about alternative implementation of these measures that usually have a hard impact on the economy of the city. Notice that TOTAL-LOCKDOWN has an associated parameter %-PERMITS that determines the amount of agents permitted to go out of their households.

The SENTINEL-TESTING intervention is also useful to assess the impact of mass-test campaigns in the population. Sentinels are shown as ambulances moving around the city while testing any agent they find in their ways; again, you can restrict sentinels mobility with a zonal scope (ZONAL?) and see the difference with respect to allowing city-wide mobility. Notice that since test kits are a finite resource, the model assigns an initial stock of tests equals to the population size. When ambulances run out of tests they stop and stay still. You can of course replenish the stock for each ambulance using the RESUPPLY button to re-activate sentinels' journeys.

THINGS TO TRY

Start-off by defining the general, city, COVID-19 and NPI settings you want to simulate in a single run (a suggested set of settings was given above, see HOW TO USE IT). Execute the simulation to observe how the contagion spreads and how the epidemics evolve by inspecting the monitors, plots and view areas. Then try changing the NPI parameters to assess their mitigation impact by comparing with previous outputs (see also THINGS TO NOTICE). If you like, start running the simulation with only one zone (choose 1 in the ZONES pull down menu); this will be equivalent to have a single district in the entire city, so agents will to move around freely. Then experiment simulations with many districts or multi-zone (choose ZONES in {4, 9, 16}), and try to apply ZONE-ENFORCING to see how agents mobility becomes restricted to their zones of residence.

The HOUSING? switch is used as a decoration and as a behaviour feature. When this switch is on, the model shows households in the simulation view area and assigns agents randomly to each one with a proportion of one house per four agents approximately. When this switch is off, the household of an agent would be the patch were he/she was created randomly at the beginning of the simulation; no houses will be seen. If you try the CASE-ISOLATION or TOTAL-LOCKDOWN interventions with HOUSING? on, agents will be sent home and stay confined in their corresponding households (they will be hidden as they stay inside the house); in contrast, if HOUSING? is off, they will move to their home patch and stay quiet there, being visible and showing their shape, color and state.

Finally, the SEE-SUNSET is a decoration feature. Try it and surprise yourself!

WHAT IS NEW

This extended version includes two personal health interventions implemented as an individual choice, namely using face masks at all times and hand-washing regularly during the day. For this purpose, two sliders, %-MASK-USERS and %-HAND-WASHERS have been enabled. These two parameters will define the tendency of an agent to develop those two hygiene habits. Recent studies have suggested that these two personal interventions can have positive effect in mitigating the contagion of the coronavirus (see [2] and references within). This is reasonable, as they reduce the risk of getting infected when a healthy agent encounters an infectious agent, which may be even more effective when physical distancing to other agents is observed (try and see it!).

Given that these three interventions depend mostly on individual decisions rather than government policy, it would be of great interest in the post-COVID19 scenario, to study strategies where they are combined with other interventions not affecting the mobility of the agents (such as SENTINEL-TESTING) to continue with epidemic mitigation while opening economy and social interaction.

Regarding mobility restrictions, when the TOTAL-LOCKDOWN intervention is on, in this extended model it is possible to lift it independently on the agents residing in a particular zone. For this aim, the user can choose the desired zone number with the PICK-ZONE slider and then should press the UNLOCK button. Then, the agents residing in such zone will start immediately to get out of their households and move freely around, while the rest of the population stays at home, as it can be attested in the simulation view area. When the ZONE-ENFORCING intervention is simultaneously activated, its residents will move around but only within the zone limits.

In addition, this extended version enables the application of the TOTAL-LOCKDOWN intervention with an intermittent 3x4 schedule (the so called "accordion" scheme), where the mobility restriction is applied adhering to a 7-day loop consisting of enforcing stay-at-home order during 3 consecutive days, and lifting the rule the remaining 4 days (hoping in this way to ameliorate the negative impact of shutting down economy due to indefinite lockdowns). To apply the accordion intervention, the user can press the LOCK3x4 button to activate/inactivate this scheme; when activated, a "3x4 ON" sign will be displayed in the bottom-left corner of the simulation view area. We remark that once activated, this intervention, similarly to the TOTAL-LOCKDOWN takes effect starting at zero hours of the next day (you can check it on the CLOCK monitor).

NEW THINGS TO NOTICE

Observe that now the chance of a contagion depends on the individual decisions regarding keeping physical distance, using mask and washing hands, which varies amply depending on the habits of the two agents involved in a contagion encounter. The actual risk on a particular encounter can be seen in the LAST CONTAGION RISK monitor. You can try and see how the risks fluctuate as you change the combination of sliders of %-WILLINGS to keep personal distance, and %-MASK-USERS and %-HAND-WASHERS with values between 0 and 100 (these parameters have effect only at the beginning of the simulation, when the population is created).

Now, when the ZONE-ENFORCING and TOTAL-LOCKDOWN interventions are simultaneously been applied, it would be interesting to verify if releasing a particular single zone or a couple of them having low contagion rates, would be advantageous to facilitate mobility (and encourage economic recovering) of a group of the population without worsening too much the overall epidemic indicators of the city.

Lastly, the impact of the "accordion" LOCK3x4 intervention is evident in the epidemic SIRE+CARDS curves, which adopt a "staircase" or "chainsaw" shape with discrete rising and falling steps, corresponding to the periods of intermittent enforce/lift of the lockdown.

EXTENDING THE MODEL

Given the complex nature of human behavior and virus infection, attempting to model every mechanism of the COVID-19 epidemic may prove difficult; necessary assumptions need to be taken to simplify the representation of the agents and their interactions. We have made a few of them, as described above, so evidently there are interesting aspects that can be addressed to extend the model. We mention just some ideas here (for a more comprehensive discussion we refer the reader to [1]):

  • consider virus incubation periods after infection,
  • model infectiousness, aggressiveness or symptomatic severity levels,
  • include age or gender structures,
  • account for births or deaths due to other causes,
  • expand further risk stratification for co-morbidities and age windows,
  • add hubs or attractor sites (i.e. mass transport, schools, cinemas, etc.),
  • incorporate explicit sites for hospitals were severe or critical patients are moved instead of staying still,
  • set up daily schedules for agent routines (e.g. going forth and back to/from work, or leisure or shopping, etc.),
  • measure the economical impact of NPIs (model food or money supply at a population or individual level),
  • simulate cotagions not only by direct contact, but also indirect by surface contact (virus particles adhered to patches),
  • implement of other epidemic indicators (different estimates of R0) or measuring them within subpopulations corresponding to residents of the different zones,
  • design mechanisms allowing tendencies to develop personal health habits (like wearing masks and routinely washing hands) to emerge as consequence of changes in the psychological biases or beliefs of the agents.

CREDITS AND REFERENCES

Authors:

Sergio Rojas-Galeano and Lindsay Alvarez

Copyright (c) September 2020

email: srojas@udistrital.edu.co, lalvarez@udistrital.edu.co

Version 1.27

Licenses:

References:

[1] Alvarez, L. and Rojas-Galeano, S. "Simulation of Non-Pharmaceutical Interventions on COVID-19 with an Agent-based Model of Zonal Restraint". medRxiv pre-print 2020/06/13; https://www.medrxiv.org/content/10.1101/2020.06.13.20130542v1 doi: 10.1101/2020.06.13.20130542

[2] Alvarez, L. and Rojas-Galeano, S. "Impact of Personal Care Habits on Post-Lockdown COVID-19 Contagion: Insights from Agent-based Simulations". medRxiv pre-print 2020/10/01; https://www.medrxiv.org/content/10.1101/2020.09.23.20200212v2 doi: 10.1101/2020.09.23.20200212

Comments and Questions

Please start the discussion about this model! (You'll first need to log in.)

Click to Run Model

;; --------------------------------------------------------------------------
;; COVID-19 mitigation with personal habits and intermittent short lockdowns
;;
;; A model by Sergio Rojas-Galeano and Lindsay Alvarez
;; v1.27 Copyright (c) September 2020 The authors
;; Correspondance email: srojas@udistrital.edu.co
;; Universidad Distrital Francisco Jose de Caldas, Bogota, Colombia
;;
;; This is an extended version of the of the COVID-19 epidemic simulation
;; with Non-Pharmaceutical Interventions and zonal restraints model
;;
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License (GPLv3)
;; (see license at: https://www.gnu.org/licenses/gpl-3.0.txt)
;;
;; The model is made publicly available in the hope that it will be useful
;; to modelers, but WITHOUT ANY WARRANTY whatsoever (see license for details).
;; --------------------------------------------------------------------------

;; Define globals
globals [
  daytime?      ; is it day or night? ( 1 day + 1 night = ticks-day)
  sort-codes    ; a list of codes to identify each zone of a city
  shapes-list   ; a list of shapes to identify agents of the same zone
  colors-list   ; a list of colors to identify different zones
  day hour      ; the current day and hour since simulation started
  sicks-day     ; list of daily count of sicks
  n-cases       ; number of overall COVID-19 sick people
  n-confirmed   ; number of confirmed COVID-19 sick people
  n-tested      ; number of overall people tested by sentinel
  n-positives   ; number of people that tested COVID-19 positive
  doubling-time ; estimated days to double today's number of sicks
  R0 S0 R0_     ; reproduction number and initial Susceptibles
  p-contagion   ; probability of contagion on a single encounter
  intermittent? ; is it intermittent lockdown on or off (i.e. "accordion strategy")?
]

;; Define breeds for healthy and infected people
breed[ healthies healthy ]
breed[ sicks sick ]
breed[ deaths death ]
breed[ houses house ]
breed[ ambulances ambulance ]

;; Define attributes for patches
patches-own [
  zone                   ; the zone code of this patch
]

;; Define attributes of all the people
turtles-own [
  homebase               ; the home patch of this person
  scope                  ; the reach of distance away from home for this person
  speed                  ; how fast does he/she move? A speed of 0 is still
  unlocked?              ; is the person free from lockdown?
  tested?                ; was the person tested by sentinel test?
  contagions             ; how many people this person infected if he/she ever got sick
  mask-habit?            ; is the person willing to wear protection mask?
  wash-habit?            ; is the person willing to wash his hands regularly?
]

;; Define attributes for sick people only
sicks-own [
  days-to-cure           ; the actual duration of the illness for this person
  recovery               ; counter of days remaining to recovery
  confirmed?             ; is the person isolated at homebase?
  asymptomatic?          ; is the person asymptomatic?
  risky?                 ; is the person high-risk due to existing factor (obese, diabetes, older, etc)
  severe?                ; is the person in severe condition?
  deadly?                ; is the person in deadly (critical) condition?
  hospitalised?          ; has he/she been admitted to hospital?
  ICU-admitted?          ; has he/she been admitted to ICU?
]

;; Define attributes for healthy people only
healthies-own [
  immune?                ; has the person recovered and acquired immunity?
]

;; Define attributes for ambulances
ambulances-own [
  tests-stock            ; how many tests in stock
  tests-supply           ; numbers of tests to top-up (depends on amount of zone residents)
]

;; One iteration of simulation's steps

to go
  if ticks = ticks-day / 2 [ outbreak ] ; Epidemic begins with outbreak at 0d:12h (enable this line only for BehaviourSpace experiments)
  ifelse day < end-day [ tick ] [ stop ] ;screenshot stop ]
  lifestyle
  epidemic
  isolation
  quarantine
  distancing
  sentinel
  lockdown
  illness
  clock
  indicators
end 

;; Simulate everyday routine of people

to lifestyle
    ask (turtle-set healthies sicks with [not confirmed?] ) [
    if zone-enforcing? [
      if zone != [zone] of homebase [ face homebase fd 0.5 ]  ; if away from resident zone, head back
    ]
    forward speed                                             ; move ahead
    if distance homebase > scope [ face homebase ]            ; if too far from home, head back
    set heading heading + (random-float 3 - random-float 3)   ; change direction swiftly
  ]
end 

;; Spread the infection from sicks not yet isolated, to healthies

to epidemic
  ask sicks with [not confirmed?] [
    let counter 0                     ; number of contagions made by this sick
    let sick-masked? mask-habit?      ; is the sick wearing mask?

    ask healthies with [not immune?] in-radius .5 [
      let healthy-masked? mask-habit? ; is the healthy wearing mask?

      ;; Set contagion risk depending on mask-wearing habits
      set p-contagion contagion-risk sick-masked? healthy-masked?

      ;; Contagion risk may decrease further depending on hand-washing habits of healthies
      if wash-habit? [ set p-contagion (p-contagion * 0.3) ]  ; P(Contagion | p-contagion, healthy-washer?)

      if random-float 1 < p-contagion [
        get-sick
        set counter counter + 1
      ]
    ]
    set contagions contagions + counter
  ]
end 

;; Probablity of contagion depending on mask wearing combination

to-report contagion-risk [sick-masked? healthy-masked?]
  let p 0
  if not sick-masked? and not healthy-masked? [ set p 0.9 ]  ; P(Contagion | False, False)
  if not sick-masked? and     healthy-masked? [ set p 0.5 ]  ; P(Contagion | False, True )
  if     sick-masked? and not healthy-masked? [ set p 0.3 ]  ; P(Contagion | True,  False)
  if     sick-masked? and     healthy-masked? [ set p 0.1 ]  ; P(Contagion | True,  True)
  report p
end 


;; Make a single person ill

to get-sick
  ;; S->I (set the initial properties of a sick person)
  set breed sicks
  set shape item ([zone] of homebase) shapes-list
  set confirmed? false
  set tested? false
  set severe? false
  set deadly? false
  set hospitalised? false
  set ICU-admitted? false

  ;; Set stochastic attributes
  set days-to-cure abs int random-normal avg-duration 4         ; duration of illness for this sick
  set recovery 0                                                ; initial count of days until recovery
  set asymptomatic? (random 100) < %-asymptomatics              ; is this an asymptomatic patient?
  set risky? (random 100) < %-high-risk  and not asymptomatic?  ; is it high-risk (co-morbidities) given not asymptomatic?
  set color ifelse-value asymptomatic? [ yellow ] [ red ]

  ;; Update how many cases so far
  set n-cases n-cases + 1
end 

;; Ask confirmed sick people to stay home

to isolation
  ;; If quarantine on, enforce isolation of symptomatic
  ifelse case-isolation? [
    ask sicks with [ not asymptomatic? and not confirmed? ] [
      move-to homebase
      set confirmed? true
      set n-confirmed n-confirmed + 1         ; these sicks are now confirmed cases
    ]
  ]
  ;; Else lift isolation, except if was sent sentinel testing
  [
    ask sicks with [ not tested? and confirmed? ] [
      set confirmed? false
      set n-confirmed n-confirmed - 1         ; these sicks are set back to not confirmed cases
    ]
  ]

  ;; Decorate houses with color of isolated people
  ask houses [
    set color ifelse-value any? sicks-here with [ not asymptomatic? ] [ red ]
            [ ifelse-value any? sicks-here with [ asymptomatic? ] [ yellow ] [ white ] ]
  ]
end 

;; Ask housemates of isolated  people to stay home

to quarantine
  if home-quarantine? [
    ask sicks with [ confirmed? ] [
      let sick-home homebase
      ask other turtles with [ homebase = sick-home ] [ move-to homebase ]
    ]
  ]

  ;; Decorate houses with color of quarantined people
  ask houses [
    set color ifelse-value any? sicks-here with [ not asymptomatic? ] [ red ]
            [ ifelse-value any? sicks-here with [ asymptomatic? ] [ yellow ] [ white ] ]
  ]
end 

;; Avoid contacting nearby people (closer than than min-dist)

to distancing
  if social-distancing?
  [ let people (turtle-set healthies sicks)
    let willings (count people * %-willings / 100)
    ask n-of willings people [
      if any? other people in-radius 0.6 [  ; a radius of 0.6 is slightly higher than the 0.5 threshold to contagion
        let closest min-one-of other people [distance myself]
        face closest rt 180                 ; head in the opposite direction of closest person
      ]
    ]
  ]
end 

;; Ask ambulances to catch sicks by mass testing

to sentinel
  ifelse sentinel-testing? [
    ask ambulances [
      st
      if tests-stock > 0 [
        ;; Move ambulances around
        forward speed
        if zonal? [ if zone != [zone] of homebase [ face homebase fd 0.5 ] ]  ; keep ambulance in-zone
        set heading heading + (random-float 10 - random-float 10)             ; change ambulance's heading randomly

        ;; Pick nearbys and perform tests
        let target-people ((turtle-set healthies sicks) in-radius 5) with [not tested?]
        ask target-people  [
          if is-sick? self and not confirmed? [                               ; if sick and not isolated, target is positive
            move-to homebase set confirmed? true
            set n-positives n-positives + 1                                   ; update count positives tests so far
            set n-confirmed n-confirmed + 1                                   ; update count of confirmed cases so far
          ]
          set tested? true                                                    ; mark this person as tested
        ]
        set n-tested n-tested + (count target-people)                         ; update count of tests made so far
        set tests-stock tests-stock - (count target-people)                   ; update stock of tests available
      ]
    ]
  ]
  ;; Else, stop and hide ambulances
  [ ask ambulances [ ht ] ]
end 

;; Enforce everyone staying home, except for a few permits

to lockdown
  if (hour mod 24) = 0 [                                            ; lockdown starts or ends at 00:00 of next day
    ifelse total-lockdown? [
      let people (turtle-set healthies sicks) with [not unlocked?]  ; for people not in an unlocked zone
      ask people [ move-to homebase set speed 0 ]                   ; sent everyone home, not confirmed
      foreach sort-codes [
        z -> let residents people with [ zone = z ]
        let permits (count residents * %-permits / 100)
        ask n-of permits residents [ set speed step-size ]
      ]
      if intermittent? and (day mod 7) >= 3 [                            ; apply flexible lockdown: 3 days out of 7 days period
        ask people [ set speed step-size ]
      ]
    ]
    ;; Else unlock everyone
    [
      ask (turtle-set healthies sicks) [ set speed step-size set unlocked? false ]
      if intermittent? [ lock3X4 ]
    ]
  ]
end 

;; Allow to lift total lockdown by unlocking zones gradually

to unlock
  ;let pick-zone random zones
  ask (turtle-set healthies sicks) with [ zone = (pick-zone - 1) ] [ set speed step-size set unlocked? true ] ;not unlocked? ]
end 

;; Enable/disable 3x4 flexible lockdown i.e. "accordion rule": 3 days lockdown by 4 days free movement

to lock3X4
  set intermittent? (not intermittent?)                   ; flip to the opposite value
  ask patch (min-pxcor + 20) (min-pycor + 2) [  ; show/hide indicator label at bottom-left corner
    set plabel-color black
    set plabel ifelse-value intermittent? [ "3x4 ON" ] [""]
  ]
end 

;; Simulate illness evolution in each person

to illness
  if (ticks mod ticks-day) = 0 [                        ; illness unfolds in a daily basis

    ;; I->R (sicks recovering after days-to cure)
    ask sicks [
      set recovery recovery + 1                       ; countdown of days left to recover
      if recovery >= days-to-cure [ get-well ]        ; if recovery time over, the person is cured
    ]

    ;; I->E (sicks getting extinct, that is, dead)
    ask sicks with [not asymptomatic?] [
      ;; Define probability of death
      let p 0.005                                     ; P(Extinct | Symptomatic)
      if deadly? and not ICU-admitted? [ set p 1.0  ] ; P(Extinct | Deadly, no ICU)
      if deadly? and     ICU-admitted? [ set p 0.5  ] ; P(Extinct | Deadly, ICU)
      if severe? and not hospitalised? [ set p 0.2  ] ; P(Extinct | Severe, Hospitalised)
      if severe? and     hospitalised? [ set p 0.05 ] ; P(Extinct | Severe, no Hospitalised)

      ;; Death may occur any day within days-to-cure, with triangular probability distribution peaking at half the days-to-cure
      let day-chance cdf-triangle recovery days-to-cure ; CDF of triangle distribution

      ;; Simulate death
      let r random-float 1.0
      if r < (p * day-chance) [ pass-away ]
    ]

    ;; I+Severe
    ask sicks with [not asymptomatic? and not (severe? or deadly?)] [
      let p 0.0
      if not risky? [ set p 0.05 ]                    ; P(Severe | Symptomatic, no Risky)
      if risky?     [ set p 0.25 ]                    ; P(Severe | Symptomatic, Risky)

      ;; Severity may arise any day within days-to-cure, following an uniform distribution
      let day-chance recovery / days-to-cure          ; CDF of uniform distribution

      ;; Simulate severity
      let r random-float 1.0
      if r < (p * day-chance) [ set severe? true ]
    ]

    ;; I+Deadly
    ask sicks with [severe?] [
      let p 0.0
      if not risky? [ set p 0.05 ]                    ; P(Deadly | Severe, no Risky)
      if risky?     [ set p 0.25 ]                    ; P(Deadly | Severe, Risky)

      ;; Deadliness may arise any day within days-to-cure, following an uniform distribution
      let day-chance recovery / days-to-cure          ; CDF of uniform distribution

      ;; Simulate deadliness
      let r random-float 1.0
      if r < (p * day-chance) [ set deadly? true set severe? false ]
    ]

    ;; I+Hospitalised
    let occupied count sicks with [severe? and hospitalised?]
    let required count sicks with [severe? and not hospitalised?]
    let incoming min list (hospital-beds - occupied) required                   ; how many can be hospitalised?
    ask n-of incoming sicks with [severe? and not hospitalised?] [              ; hospitalised as many as possible
      set hospitalised? true
      set tested? true                                                          ; so they can't move even when isolation off
      if not confirmed? [ set confirmed? true set n-confirmed n-confirmed + 1 ] ; if wasn't confirmed yet, confirm and update count
    ]

    ;; I+ICU-admitted
    set occupied count sicks with [deadly? and ICU-admitted?]
    set required count sicks with [deadly? and not ICU-admitted?]
    set incoming min list (ICU-beds - occupied) required                        ; how many can be admitted to ICU?
    ask n-of incoming sicks with [deadly? and not ICU-admitted?] [              ; ICU-admit as many as possible
      set ICU-admitted? true
      set tested? true                                                          ; so they can't move even when isolation off
      if not confirmed? [ set confirmed? true set n-confirmed n-confirmed + 1 ] ; if wasn't confirmed yet, confirm and update count
    ]
  ]
end 

;; Compute Cumulative Distribution Function (CDF) of triangular distribution at a given number of days elapsed (x) within illness period (width)

to-report cdf-triangle [x width]
  ;; Height of the inner triangle to obtain CDF, i.e. the value of the PDF on x
  let height 2 * (width - abs (width - (2 * x))) / (width ^ 2)

  ;; If x is before peak, CDF is the area of the inner triangle with base x
  ifelse x <= (width / 2) [
    let base x
    report height * base / 2
  ]
  ;; Else if x is after peak, CDF is to total area (1) minus area of inner triangle with base (width - x)
  [
    let base (width - x)
    report 1 - (height * base / 2)
  ]
end 

;; Become healthy again

to get-well
  let old-shape shape
  set breed healthies
  set immune? true
  set shape old-shape
  set color white
  set speed step-size
end 

;; Become dead

to pass-away
  if not confirmed? [ set confirmed? true set n-confirmed n-confirmed + 1 ]  ; some cases are confirmed only at death
  set breed deaths
  set shape "x"
  set speed 0
  set color black
end 

;; Update counters of days and hours

to clock
  set day int (ticks / ticks-day)           ; track of number of days elapsed since beginning
  set hour int ((ticks / ticks-day) * 24)   ; track of number of hours elapsed since beginning
  sunset
end 

;; Record epidemic indicators

to indicators
  ;; Daily statistics are sicks per day and doubling-time
  if ticks mod ticks-day = 0 [
    set sicks-day lput (count sicks) sicks-day

    ;; Compute doubling time
    ;; see (Bakir, 2016, "Compound Interest Doubling Time Rule: Extensions and Examples from Antiquities.")
    if any? sicks[
      ifelse (last sicks-day) > (item (day - 1) sicks-day)
      [ set doubling-time ln 2 / ln ((last sicks-day) / (item (day - 1) sicks-day + 1E-10)) ]
      [ set doubling-time "Inf" ]
    ]
  ]

  if ticks mod (ticks-day / 24) = 0 [
    ;; Estimate R0 based on the final size of susceptibles in population
    ;; see (Dietz, 1993, "The estimation of the basic reproduction number for infectious diseases.")
    if S0 != 0 [
      let Sn count healthies with [ not immune? ] / pop-size
      set R0 (ln (S0 + 1E-10) - ln (Sn + 1E-10)) / (S0 - Sn + 1E-10)
    ]
    ;; Estimate R0_ with an individual-based approach, as the average of contagions per sick
    if any? turtles with [contagions > 0] [
      set R0_ mean [contagions] of turtles with [contagions > 0]
    ]
  ]
end 

;; Inoculate infection on one agent

to infect
  if any? healthies with [not immune?][
    ask one-of healthies with [not immune?] [ get-sick ]
  ]

  ;; Record the initial count of susceptibles for R0 computation
  set S0 (count healthies with [not immune?]) / pop-size
end 

;; Contagion by an outbreak

to outbreak
  ;; Infect a percentage of population
  repeat pop-size * (%-spread / 100) [ infect ]

  ;; Record the initial count of susceptibles for R0 computation
  set S0 (count healthies with [not immune?]) / pop-size
end 

;; Light up or down the city depending on daytime

to sunset
  if see-sunset? [
    if (ticks mod (ticks-day / 2)) = 0 [
      ifelse daytime?
      [ ask patches [ set pcolor pcolor + 4 ] ]
      [ ask patches [ set pcolor pcolor - 4 ] ]
      set daytime? not daytime?
    ]
  ]
end 

;; Get ready to go

to setup
  clear-all
  reset-ticks
  setup-globals
  setup-city
  setup-people
  setup-ambulances
  set daytime? false
  set intermittent? false
end 

;; Initialize global variables

to setup-globals
  ;; Codes to identify zones
  set sort-codes n-values zones [ i -> i ]

  ;; Residents of each zone are identified with different shapes and color
  set shapes-list [ "dog" "cat" "cow skull" "fish 2" "chess knight" "ant 2" "wolf 7" "bird"
    "butterfly 2" "rabbit" "bug" "spider" "ghost" "monster" "person" "fish" "sheep" "bee 2"]
  set colors-list [ cyan pink violet green brown turquoise gray sky lime violet blue
    brown gray sky pink turquoise ]

  ;; Initalise daily sicks, positives, total-tested, total and confirmed cases
  set sicks-day [0]
  set n-positives 0 set n-tested  0 set n-cases 0 set n-confirmed 0

  ;; Initial value for doubling time
  set doubling-time 0.0
end 

;; Split the city into zones and setup facilities

to setup-city
  set-patch-size 1.9

  ;; Layout a grid of patch square zones by assingning auxiliary codes
  let step world-width / sqrt zones
  ask patches[
    let units int ((pxcor + max-pxcor) / step)
    let tens  int ((pycor + max-pycor) / step)
    set zone 10 * tens + units
  ]

  ;; Now map those auxiliary codes to consecutive sort-codes and corresponding colors
  let aux-codes sort remove-duplicates [zone] of patches
  (foreach aux-codes sort-codes [ [old new] -> ask patches with [zone = old] [set zone new] ])
  ask patches [ set pcolor (item zone colors-list) + 1 ]
  ;foreach sort-codes [ c -> ask one-of patches with [zone = c] [set plabel zone] ] ; display zone code on view area

  ;; If housing, create houses
  if housing? [
    create-houses pop-size / 4 [
      setxy random-xcor random-ycor
      set color white set shape "house" set size 9
    ]
  ]
end 

;; Create initial population

to setup-people
  create-healthies pop-size [
    ;; Assign as homebase either a house if any, otherwise his initial position
    ifelse housing?
    [  set homebase one-of houses
       move-to homebase
    ][ setxy random-xcor random-ycor
       set homebase patch-here
    ]

    ;; Assign color and shape depending on homebase's zone
    set color item zone colors-list - 2
    set shape item zone shapes-list
    set size 9
    set heading random 360
    set scope one-of (list 25 50 100 200)      ; choose radomly movement range
    set immune? false
    set unlocked? false
    set tested? false
    set contagions 0
    set mask-habit? random 100 < %-mask-users  ; set face mask protection social habit
    set wash-habit? random 100 < %-handwashers ; set hand-washing social habit
    set speed step-size ;0.1 ;0.5
    forward 3                                  ; peek out of house to be seen at the beginning
  ]
end 

;; Create ambulances

to setup-ambulances
  foreach range zones [ z ->
    create-ambulances ambulances-zone [
      move-to one-of patches with [ zone = z ]
      set homebase patch-here
      set shape "ambulance 2" set size 12 set color white
      set speed 4 * step-size        ; ambulances move faster than people
      let residents (turtle-set healthies sicks) with [ zone = z ]

      ;; The amount of tests supply depends on residents population
      set tests-supply round (count residents * (%-tests / 100) / ambulances-zone )
      set tests-stock tests-supply   ; initialise stock of tests
    ]
  ]
end 

;; Replenish the stock of available tests in ambulances

to supply-ambulances
  ask ambulances [ set tests-stock tests-stock + tests-supply ]
end 

;; Replenish an infinite stock of tests in ambulances

to supply-infinity
  ask ambulances [ set tests-stock 1000000 ]
end 

;; Save a screenshot of the interface (view+plots, etc) in a file

to screenshot
  display
  ;export-interface (word "COVID19-NPI-ABM-" random 1000 random 1000 ".png")
end 

There are 5 versions of this model.

Uploaded by When Description Download
Sergio Rojas-Galeano about 3 years ago URL link to medRxive pre-print Download this version
Sergio Rojas-Galeano over 3 years ago Fixed comments in source code Download this version
Sergio Rojas-Galeano over 3 years ago Info tab fixed Download this version
Sergio Rojas-Galeano over 3 years ago Info tab fixed Download this version
Sergio Rojas-Galeano over 3 years ago Extended model Download this version

Attached files

File Type Description Last updated
COVID-19 mitigation with personal habits and intermittent short lockdowns.png preview Preview image over 3 years ago, by Sergio Rojas-Galeano Download
COVID_19_NPI_Zones_UserGuide_v1_27.pdf pdf User guide over 3 years ago, by Sergio Rojas-Galeano Download

Parent: COVID-19 epidemics with Non-Pharmaceutical Interventions and zonal restraints

This model does not have any descendants.

Graph of models related to 'COVID-19 mitigation with personal habits and intermittent short lockdowns'