COVID 19 Model
Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)
WHAT IS IT?
This COVID-19 Model is an Agent-Based-Model looking at how different demographic factors and policy interventions impact COVID-19 transmission and health outcomes.
HOW IT WORKS
An initial population of agents (blue-colored humanoids) are randomly placed in the model space with an initial population of infected individuals (red). As time moves forward, agents move randomly through the model space according to specified parameters such as number of stationary individuals and mobility. Infected individuals transmit the virus to susceptible individuals by coming within a certain distance of each other. Whether the susceptible individual becomes infected is determined by a random probability, the likelihood of which increases as transmission rate increases. The model can be run with and without immune individuals; when ran with immunity, infected individuals will become immune (color changes to gray) according to a random probability, the liklihood of which increases with increasing recovery rate. Mortality rate can be adjusted. The ability of hospitals to cope with the proportion of infected individuals can be adjusted as well. Once the proportion of infected individuals is greater than health care capacity mortality increases an order of magnitude, as predicted by other current models.
HOW TO USE IT
After adjusting the parameters, described below, simply click the setup button and click go. The model will continue to run until there are either no more infected individuals or no more susceptible individuals.
THINGS TO NOTICE
THINGS TO TRY
EXTENDING THE MODEL
If you have any suggestions for things to add or change in the model feel free to contact me at jonathan.huang@richmond.edu.
RELATED MODELS
This model was inspired from these models:
SIR Model with random movement by Paul Smaldino http://smaldino.com/wp/
COVID-19 epidemics with Non-Pharmaceutical Interventions and zonal restraints by Sergio Rojas-Galeano and Lindsay Alvarez http://modelingcommons.org/browse/onemodel/6374#modeltabsbrowseinfo
Many Regions Example by Nicolas Payette http://www.netlogoweb.org/launch#http://ccl.northwestern.edu/netlogo/models/models/Code%20Examples/Many%20Regions%20Example.nlogo
CREDITS AND REFERENCES
CREATIVE COMMONS LICENSE This code is distributed by Nich Martin under a Creative Commons License: Attribution-ShareAlike 4.0 International (CC 4.0) https://creativecommons.org/licenses/by/4.0/
Comments and Questions
globals [ rich-population middle-population poor-population region-boundaries hospital-beds-occupied population-density dead-total-age dead-total-gdp number-vaccinated-once number-vaccinated-twice n-cases n-confirmed day hour vaccine-interval test-interval leave-time return-time one-dose-success ] breed[ rich-houses rich-house ] breed[ middle-houses middle-house ] breed[ poor-houses poor-house ] breed[ people person] breed[ houses house ] patches-own [ region ] turtles-own[ homebase commute susceptible? infected? immune? stationary? hospitalized? vaccinated? one-dose? two-dose? sick-time age mobility infected-mortality chance-of-recovery income antivaxxer? household-size tested? tested-positive? quarantined? masked? dose-counter infection-rate area ] to go if (count people with [infected?] = 0) [stop] move random-testing quarantine-positive-tested infect-susceptibles vaccinate illness end -quarantine clock tick end to setup clear-all setup-globals setup-regions 3 setup-people setup-houses setup-segregate setup-infected reset-ticks end to setup-globals set population-density initial-population set number-vaccinated-once 0 set number-vaccinated-twice 0 set dead-total-age 0 set dead-total-gdp 0 set n-cases 0 set n-confirmed 0 set hospital-beds-occupied 0 (ifelse distribution-interval = "Every Hour" [set vaccine-interval 24] distribution-interval = "Once a Day" [set vaccine-interval 1] distribution-interval = "Once a Week" [set vaccine-interval 1 / 7]) (ifelse testing-interval = "Every Hour" [set test-interval 24] testing-interval = "Once a Day" [set test-interval 1] testing-interval = "Once a Week" [set test-interval 1 / 7]) (ifelse lockdown-end = "1:00 AM" [set leave-time 1] lockdown-end = "2:00 AM" [set leave-time 2] lockdown-end = "3:00 AM" [set leave-time 3] lockdown-end = "4:00 AM" [set leave-time 4] lockdown-end = "5:00 AM" [set leave-time 5] lockdown-end = "6:00 AM" [set leave-time 6] lockdown-end = "7:00 AM" [set leave-time 7] lockdown-end = "8:00 AM" [set leave-time 8] lockdown-end = "9:00 AM" [set leave-time 9] lockdown-end = "10:00 AM" [set leave-time 10] lockdown-end = "11:00 AM" [set leave-time 11] lockdown-end = "12:00 PM" [set leave-time 12]) (ifelse lockdown-start = "1:00 PM" [set return-time 1] lockdown-start = "2:00 PM" [set return-time 2] lockdown-start = "3:00 PM" [set return-time 3] lockdown-start = "4:00 PM" [set return-time 4] lockdown-start = "5:00 PM" [set return-time 5] lockdown-start = "6:00 PM" [set return-time 6] lockdown-start = "7:00 PM" [set return-time 7] lockdown-start = "8:00 PM" [set return-time 8] lockdown-start = "9:00 PM" [set return-time 9] lockdown-start = "10:00 PM" [set return-time 10] lockdown-start = "11:00 PM" [set return-time 11] lockdown-start = "12:00 AM" [set return-time 12]) end to setup-regions [ num-regions ] ;num-regions = 3 if income-separation? [ foreach region-divisions num-regions draw-region-division set region-boundaries calculate-region-boundaries num-regions let region-numbers (range 1 (num-regions + 1)) (foreach region-boundaries region-numbers [ [boundaries region-number] -> ask patches with [ pxcor >= first boundaries and pxcor <= last boundaries ] [ set region region-number ] ]) ] ask patches with [ region != 0 ] [ set pcolor 2 + region * 10 set plabel-color pcolor + 1 ] end to-report region-divisions [ num-regions ] ;num-regions = 3 ; This procedure reports a list of pxcor that should be outside every region. ; Patches with these pxcor will act as "dividers" between regions. report n-values (num-regions + 1) [ n -> [ pxcor ] of patch (min-pxcor + (n * ((max-pxcor - min-pxcor) / num-regions))) 0 ] end to draw-region-division [ x ] ask patches with [ pxcor = x ] [ set pcolor grey ] create-turtles 1 [ ; use a temporary turtle to draw a line in the middle of our division setxy x max-pycor set heading 0 set color grey - 3 pen-down forward world-height set xcor xcor + 1 / patch-size right 180 set color grey + 3 forward world-height die] end to-report calculate-region-boundaries [ num-regions ] ;num-regions = 3 ; The region definitions are built from the region divisions: let divisions region-divisions num-regions ; Each region definition lists the min-pxcor and max-pxcor of the region. ; To get those, we use `map` on two "shifted" copies of the division list, ; which allow us to scan through all pairs of dividers ; and built our list of definitions from those pairs: report (map [ [d1 d2] -> list (d1 + 1) (d2 - 1) ] (but-last divisions) (but-first divisions)) end to setup-people create-people initial-population [ set color blue set shape "person" set size 2 set commute commute-distance set heading random 360 set susceptible? true set infected? false set immune? false set stationary? false set hospitalized? false set vaccinated? false set tested? false set tested-positive? false set quarantined? false set one-dose? false set two-dose? false set sick-time 0 set dose-counter 0 set antivaxxer? random 100 <= anti-vaccination-proportion set area 0 let coinA random 100 let coinB random 10 ifelse (coinA < percent-age-ten )[ set age coinB set infected-mortality 0.0001][ ifelse (coinA < percent-age-twenty )[ set age (coinB + 10) set infected-mortality 0.05][ ifelse (coinA < percent-age-thirty )[ set age (coinB + 20) set infected-mortality 0.105][ ifelse (coinA < percent-age-forty )[ set age (coinB + 30) set infected-mortality 0.188][ ifelse (coinA < percent-age-fifty )[ set age (coinB + 40) set infected-mortality 0.295][ ifelse (coinA < percent-age-sixty )[ set age (coinB + 50) set infected-mortality 0.8][ ifelse (coinA < percent-age-seventy )[ set age (coinB + 60) set infected-mortality 2.7][ ifelse (coinA < percent-age-eighty )[ set age (coinB + 70) set infected-mortality 7.98] [set age (coinB + 80) set infected-mortality 15.9] ] ] ] ] ] ] ] set income random-normal average-household-income income-spread if (income < 0)[set income 0] set infection-rate (transmission-rate + (population-density * 0.00004 ) - (income * 0.0000001)) if (infection-rate > 1) [set infection-rate 1] set infected-mortality (infected-mortality + (-0.00004 * (income - 50577))) if (infected-mortality < 0) [set infected-mortality 0] set chance-of-recovery (100 - infected-mortality) if (chance-of-recovery < 0)[set chance-of-recovery 0] ifelse masks? [ ifelse (random-float 100 < mask-effort) [set masked? true] [set masked? false] ] [ set masked? false ] ifelse age < 15 [ set mobility (age / 50)][ ifelse age > 65[ set mobility ((age - 50) / 50)] [set mobility ((100 - age) / 50)] ;15-65 year olds ] ] end to setup-infected let rich-count count people with [income > middle-class-income-end] let middle-count count people with [income > middle-class-income-start and income < middle-class-income-end] let poor-count count people with [income < middle-class-income-start] ifelse rich-count > initial-infected-rich [ ask n-of initial-infected-rich people with [income > middle-class-income-end] [ set color red set infected? true ] ] [ ask n-of rich-count people with [income > middle-class-income-end] [ set color red set infected? true ] ] ifelse middle-count > initial-infected-middle [ ask n-of initial-infected-middle people with [income > middle-class-income-start and income < middle-class-income-end] [ set color red set infected? true ] ] [ ask n-of middle-count people with [income > middle-class-income-start and income < middle-class-income-end] [ set color red set infected? true ] ] ifelse poor-count > initial-infected-poor [ ask n-of initial-infected-poor people with [income < middle-class-income-start] [ set color red set infected? true ] ] [ ask n-of poor-count people with [income < middle-class-income-start] [ set color red set infected? true ] ] end to setup-houses (ifelse housing? and income-separation? [ set rich-population count people with [income > middle-class-income-end] set middle-population count people with [income > middle-class-income-start and income < middle-class-income-end] set poor-population count people with [income < middle-class-income-start] let r 0 ifelse (rich-population < rich-household-size) [set r 1] [set r rich-population / rich-household-size] create-rich-houses r [ let rich-patch patches with [ region = 3 ] move-to one-of rich-patch set color white set shape "house" set size 2] let m 0 ifelse (middle-population < middle-class-household-size) [set m 1] [set m middle-population / middle-class-household-size] create-middle-houses m [ let middle-patch patches with [ region = 2 ] move-to one-of middle-patch set color white set shape "house" set size 2 ] let p 0 ifelse (poor-population < poor-household-size) [set p 1] [set p poor-population / poor-household-size] create-poor-houses p [ let poor-patch patches with [ region = 1 ] move-to one-of poor-patch set color white set shape "house" set size 2 ] ] housing? and not income-separation? [ create-houses initial-population / 4 [ setxy random-xcor random-ycor set color white set shape "house" set size 2 ] ] ) end to setup-segregate ask people [ (ifelse housing? and income-separation? [ if (income > middle-class-income-end and count rich-houses > 0 )[set homebase one-of rich-houses move-to homebase] if (income < middle-class-income-end and income > middle-class-income-start and count middle-houses > 0) [set homebase one-of middle-houses move-to homebase] if (income < middle-class-income-start and count poor-houses > 0) [set homebase one-of poor-houses move-to homebase] ] housing? and not income-separation? [ set homebase one-of houses move-to homebase ] not housing? and not income-separation? [ setxy random-xcor random-ycor ] ) ] end to move (ifelse housing? and lockdown? [ ifelse ((hour mod 24) >= leave-time and (hour mod 24) <= (return-time + 12)) [ ask people with [not hospitalized? and not quarantined?] [ forward mobility ; move ahead if distance homebase > commute [ face homebase ] ; if too far from home, head back if (any? patches in-radius 1 with [pxcor = max-pxcor or pxcor = min-pxcor or pycor = min-pycor or pycor = max-pycor]) [face homebase] set heading heading + (random-float 5 - random-float 5) ] ] [ask people with [not hospitalized? and not quarantined?] [ ifelse patch-here = homebase [set heading random-float 360 forward 0] [face homebase forward mobility] ] ] ; once it is not commute time, ask people to return to homes and stay there until next day ] housing? and not lockdown? [ ask people with [not hospitalized? and not quarantined?] [ forward mobility ; move ahead if distance homebase > commute [ face homebase ] ; if too far from home, head back if (any? patches in-radius 1 with [pxcor = max-pxcor or pxcor = min-pxcor or pycor = min-pycor or pycor = max-pycor]) [face homebase] set heading heading + (random-float 5 - random-float 5) ] ] not housing? and lockdown? [ ifelse ((hour mod 24) >= leave-time and (hour mod 24) <= (return-time + 12)) [ ask people with [not hospitalized? and not quarantined?] [forward mobility] ] [ask people with [not hospitalized? and not quarantined?] [forward 0] ] ] not housing? and not lockdown? [ ask people with [not hospitalized? and not quarantined?] [forward mobility] ] ) end to random-testing if testing? [ let target turtle-set people with [not tested-positive?] ask n-of (count target * population-tested-percent) target [ if (ticks mod (round(ticks-day / test-interval)) = 0 and ticks > 0) [ set tested? true if infected? [ ifelse (random-float 1 < false-negative-rate) [set tested-positive? false] [ set tested-positive? true set n-confirmed n-confirmed + 1 ] ] if not infected? [ ifelse (random-float 1 < false-positive-rate) [ set tested-positive? true set n-confirmed n-confirmed + 1 ] [set tested-positive? false] ] ] ] ] end to quarantine-positive-tested if testing? and housing? [ ask people with [tested? and tested-positive? and not hospitalized?] [ if (random 100 < quarantine-effort) [set quarantined? true ifelse patch-here = homebase [forward 0] [face homebase forward mobility] ] ] ] end to vaccinate if vaccination? [ let vaccinate-priority-people turtle-set people (ifelse vaccine-priority = "No Priority" [set vaccinate-priority-people turtle-set people with [not vaccinated? and not infected? and not immune? and not hospitalized? and not antivaxxer?]] vaccine-priority = "Ages 0-20" [set vaccinate-priority-people turtle-set people with [not vaccinated? and not infected? and not immune? and not hospitalized? and not antivaxxer? and age < 20]] vaccine-priority = "Ages 20-50" [set vaccinate-priority-people turtle-set people with [not vaccinated? and not infected? and not immune? and not hospitalized? and not antivaxxer? and age > 20 and age < 50]] vaccine-priority = "Ages 50 and up" [set vaccinate-priority-people turtle-set people with [not vaccinated? and not infected? and not immune? and not hospitalized? and not antivaxxer? and age >= 50]] ) let vaccine-ready-people turtle-set people with [not vaccinated? and not infected? and not immune? and not hospitalized? and not antivaxxer?] let n count vaccine-ready-people let x count vaccinate-priority-people if (x = 0) [ set vaccinate-priority-people turtle-set vaccine-ready-people set x n ] (ifelse dose-amount = 1 [ if (ticks mod (round(ticks-day / vaccine-interval)) = 0 and ticks > 0) [ ;let n count vaccinate-people ifelse ((vaccinated-proportion * .01 * n) <= x) [ ask (n-of (vaccinated-proportion * .01 * n) vaccinate-priority-people) [ set number-vaccinated-once number-vaccinated-once + 1 set vaccinated? true set one-dose? true set color green if (random-float 100 < one-dose-success) [ set susceptible? false set immune? true ] ] ] [ ask (vaccinate-priority-people) [ set number-vaccinated-once number-vaccinated-once + 1 set vaccinated? true set one-dose? true set color green if (random-float 100 < one-dose-success) [ set susceptible? false set immune? true ] ] ] ] ask people with [one-dose?] [ set dose-counter dose-counter + 1 ifelse (dose-counter / ticks-day) > 14 [ set one-dose-success one-dose-success-after-14-days ] [ set one-dose-success one-dose-success-first-14-days ] ] ] dose-amount = 2 [ if (ticks mod (round(ticks-day / vaccine-interval)) = 0 and ticks > 0)[ ;let n count vaccinate-people ifelse ((vaccinated-proportion * .01 * n) <= x) [ ask (n-of (vaccinated-proportion * .01 * n) vaccinate-priority-people) [ set number-vaccinated-once number-vaccinated-once + 1 set vaccinated? true set one-dose? true set color green if (random-float 100 < one-dose-success) [ set susceptible? false set immune? true ] ] ] [ ask (vaccinate-priority-people) [ set number-vaccinated-once number-vaccinated-once + 1 set vaccinated? true set one-dose? true set color green if (random-float 100 < one-dose-success) [ set susceptible? false set immune? true ] ] ] ] let m people with [one-dose? and not two-dose?] let two count m ask n-of two m [ set dose-counter dose-counter + 1 ifelse (dose-counter / ticks-day) > 14 [ set one-dose-success one-dose-success-after-14-days ] [ set one-dose-success one-dose-success-first-14-days ] ] ask (n-of (vaccine-completion * .01 * two) m) [ if (dose-counter / ticks-day) > dose-wait-time [ if (random-float 100 < two-dose-success) [ set number-vaccinated-twice number-vaccinated-twice + 1 set immune? true set vaccinated? true set susceptible? false set color green set two-dose? true ] ] ] ] ) ] end to infect-susceptibles ;S -> I ask people with [susceptible?] [ let infected-neighbors (count other people with [infected?] in-radius (0.12 - (0.06 * social-distancing-effort / 100)) ) let mask-effect 1 if (masked?) [ set mask-effect (1 - (mask-effectiveness * 0.01)) ] if (random-float 1 < (1 - (1 - (infection-rate * mask-effect)) ^ infected-neighbors) and not immune? and not hospitalized? and not quarantined?) [ set susceptible? false set infected? true set color red set n-cases n-cases + 1 ] ] end to illness ask people with [infected? or (tested? and tested-positive?)] [ set sick-time sick-time + 1 ] ask people with [infected?] [ ;I -> H if (not tested? and not hospitalized? and int(sick-time / ticks-day) > 5) or (tested? and tested-positive? and not hospitalized? and not vaccinated?) [ if (hospital-beds-occupied < healthcare-capacity and age >= 50 and income > middle-class-income-start ) [ set hospitalized? true set color yellow set hospital-beds-occupied hospital-beds-occupied + 1 set chance-of-recovery chance-of-recovery * 2 if (chance-of-recovery > 100) [set chance-of-recovery 100] ] ] ;H -> Die during sickness if (int(sick-time / ticks-day) < duration and hospitalized?) [ if (random-float 100 < ((infected-mortality / 2) / (duration * ticks-day))) [ set dead-total-age dead-total-age + age set dead-total-gdp dead-total-gdp + income die set hospital-beds-occupied hospital-beds-occupied - 1 ] ] ;I -> Die during sickness if (int(sick-time / ticks-day) < duration and not hospitalized?) [ if (random-float 100 < ((infected-mortality) / (duration * ticks-day))) [ set dead-total-age dead-total-age + age set dead-total-gdp dead-total-gdp + income die set hospital-beds-occupied hospital-beds-occupied - 1 ] ] ;Sickness duration complete if (int(sick-time / ticks-day) >= duration) [ ;I -> R ifelse (random-float 100 < chance-of-recovery) [ if hospitalized? [ set hospitalized? false set hospital-beds-occupied hospital-beds-occupied - 1 ] set infected? false set immune? true set sick-time 0 set susceptible? false set color gray ] ;I -> Die after sickness duration is complete [ if hospitalized? [ set hospitalized? false set hospital-beds-occupied hospital-beds-occupied - 1 set dead-total-age dead-total-age + age set dead-total-gdp dead-total-gdp + income die ] set dead-total-age dead-total-age + age set dead-total-gdp dead-total-gdp + income die ] ] ] end to end-quarantine ask people with [quarantined?] [ if (int(sick-time / ticks-day) >= duration) [set quarantined? false] ] end to clock ; ticks-day refers to the total number of ticks in one day 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 end to-report prop-infected report ((count people with [infected?]) / initial-population) end to-report prop-uninfected report 1 - ((count people with [infected?]) / initial-population) end to-report num-dead report (initial-population - count people) end to-report prop-dead report (initial-population - count people) / initial-population end to-report population report count people end to-report immune report count people with [immune?] end to-report infected report count people with [infected?] end to-report hospitalized-proportion report count people with [hospitalized?] end to-report cumulative-infected report (n-cases + initial-infected-rich + initial-infected-middle + initial-infected-poor) / initial-population end to-report prop-hospital-beds-occupied report hospital-beds-occupied / healthcare-capacity end to-report dead-avg-age report (dead-total-age / (initial-population - count people)) end to-report dead-avg-gdp report (dead-total-gdp / (initial-population - count people)) end to-report total-cases report n-cases + initial-infected-rich + initial-infected-middle + initial-infected-poor end to-report confirmed-cases report n-confirmed end to-report total-vaccinated report count people with [vaccinated?] end to-report recieved-two-doses report count people with [two-dose?] end to-report recieved-one-dose report count people with [one-dose? and not two-dose?] end
There are 3 versions of this model.
Attached files
File | Type | Description | Last updated | |
---|---|---|---|---|
COVID 19 Model.png | preview | Preview for 'COVID 19 Model' | over 3 years ago, by Jonathan Huang | Download |
This model does not have any ancestors.
This model does not have any descendants.