# Viral Epidemic with Frational Hospitalization and Death Simulation
# (c) 2020 Kevan Hashemi, Brandeis University.
# Set up the graphical user interface.
wm title . "Epidemic Simulation Version 4.1"
set param(run) "Stop"
set g [frame .f1]
pack $g -side top -fill x
label $g.state -textvariable param(run) -fg blue
pack $g.state -side left -expand yes
foreach a {Construct Start Stop Reset Help} {
set b [string tolower $a]
button $g.$b -text $a -command "epidemic_$b"
pack $g.$b -side left -expand yes
}
set g [frame .f2]
pack $g -side top -fill x
foreach a {unexposed infected recovered hospitalized dead} {
label $g.l$a -text "$a"
entry $g.e$a -textvariable param($a) -width 6
pack $g.l$a $g.e$a -side left -expand yes
}
set g [frame .f3]
pack $g -side top -fill x
foreach a {contact_rate recover_days hospitalization_rate death_rate time} {
label $g.l$a -text "$a"
entry $g.e$a -textvariable param($a) -width 4
pack $g.l$a $g.e$a -side left -expand yes
}
set t [text .text -relief sunken -border 2 -setgrid 1 \
-height 20 -width 60 -wrap word]
set param(t) $t
$t configure -yscrollcommand ".vsb set"
set vsb [scrollbar .vsb -orient vertical -command "$t yview"]
pack $vsb -side right -fill y
pack $t -expand yes -fill both
bind $t [list $t delete 1.0 end]
bind $t [list $t delete 1.0 end]
bind $t [list $t delete 1.0 end]
$t tag configure title -foreground purple
$t tag configure help -foreground brown
update
# Print title.
$t insert end "Viral Epidemic with Hospitalization and Death Simulated" title
$t insert end "31-MAR-20, Kevan Hashemi, Brandeis University.\n" title
# The reset routine goes back to the no-infected state.
proc epidemic_reset {} {
global param
set param(unexposed) "100000"
set param(infected) "10"
set param(recovered) "0"
set param(hospitalized) "0"
set param(dead) "0"
set param(contact_rate) "0.25"
set param(recover_days) "14"
set param(hospitalization_rate) "0.01"
set param(death_rate) "0.001"
set param(time) "0"
set param(population) [list]
epidemic_construct
}
# The print routine prints time and the population distribution.
proc epidemic_print {} {
global param
set n [llength $param(population)]
$param(t) insert end "$param(time) "
foreach a {unexposed infected recovered hospitalized dead} {
$param(t) insert end "[format %.4f [expr 100.0*$param($a)/$n]] "
}
$param(t) insert end "\n"
$param(t) yview moveto 1
}
# We construct a new array. All infected will be set to the first
# day of infection. Each member of the population gets a number
# to describe their state. Zero means they are unexposed. A number
# 1..n means they have been infected 1..n days. When n = recover_days,
# they are recovered or dead.
proc epidemic_construct {} {
global param
if {$param(run) != "Stop"} {return}
set param(run) "Init"
update
set param(population) [list]
for {set i 0} {$i < $param(unexposed)} {incr i} {
lappend param(population) "0"
}
for {set i 0} {$i < $param(infected)} {incr i} {
lappend param(population) "1"
}
for {set i 0} {$i < $param(recovered)} {incr i} {
lappend param(population) "$param(recover_days)"
}
set param(time) "0"
set param(run) "Stop"
$param(t) insert end "\nNew Distribution Constructed:\n" title
epidemic_print
}
# We stop the simulation by setting the run flag to Stop, which will bring
# the run procedure to a stop.
proc epidemic_stop {} {
global param
set param(run) "Stop"
}
# The start procedure starts the simulation.
proc epidemic_start {} {
global param
if {$param(run) != "Stop"} {return}
set param(run) "Run"
after 10 epidemic_run
}
# The run procedure goes through all entries in the population list.
# If currently infected, increment the entry value, and at random select
# member of population for exposure. If that person is unexposed so far,
# start infection. At the end of the day, update the numbers of various
# subsets of the population, then posts itself to the event queue.
proc epidemic_run {} {
global param
if {$param(run) != "Run"} {return}
set n [llength $param(population)]
for {set i 0} {$i < $n} {incr i} {
set p [lindex $param(population) $i]
# Unexposed and recovered people don't infect anyone.
if {($p == 0) || ($p == $param(recover_days))} {
continue
}
# Those infected can infect another person, provided that person
# has not been exposed yet.
if {$p > 0} {
set cr $param(contact_rate)
while {$cr > 0} {
if {rand() < $param(contact_rate)} {
set ii [expr round(rand()*$n-0.5)]
if {$ii>$n} {set ii $n}
if {([lindex $param(population) $ii] == 0)} {
lset param(population) $ii "1"
}
}
set cr [expr $cr - 1]
}
set d [expr $p + 1]
lset param(population) $i $d
}
}
# Update our counts of the various subsets of the population.
foreach a {unexposed infected recovered hospitalized dead} {
set $a 0
}
foreach p $param(population) {
if {$p == 0} {
incr unexposed
} elseif {$p == $param(recover_days)} {
incr recovered
} else {
incr infected
}
set hospitalized [expr $param(hospitalization_rate)*$param(infected)]
set dead [expr $param(death_rate)*$param(recovered)]
}
foreach a {unexposed infected recovered hospitalized dead} {
set param($a) [set $a]
}
incr param(time)
epidemic_print
after 100 epidemic_run
}
proc epidemic_help {} {
global param
$param(t) insert end {
Summary: Set population sizes and parameter values, press Construct, press
Start. Simulation runs until epidemic is over, or you press Stop.
The simulation assumes one virus strain and fixed contact rate between infected
persons and randomly-selected other persons to determine exposure. All exposed
persons become infected. Only hospitalization_rate of those infected are
hospitalized. All infected persons stop being infectious after recovery_days. Of
the infected persions, hospitalization_rate will be hospitalized and death_rate
will die after recovery_days instead of recover. The contact rate is the number
of people each infected person exposes per day. If this number is less than one,
they sometimes infect people, and sometimes do not. If the rate is greater than
one, we treat any fraction as a probability. We press Construct to create the
population database, then Start to run the simulation, Stop to pause it. We get
the default values of all the above numbers with Reset. When there are no more
infected people, the simulation stops.
The simulation printes to the screen the day number, and the numbers of:
unexposed, unsusceptible, infected, and recovered people. These numbers are
intended for cut and past into spreadsheets for plotting. These same numbers are
displayed in their entry boxes at the top of the window.
Kevan Hashemi, 31-MAR-20
} help
}
epidemic_reset