In this project we will be extending the DES system you implemented in the first project. You should feel free to start with your own code, or simply use the first project solution as your code base; either way is fine. Realize, however, that project 1 has not yet been graded, so starting with your own code may entail going back and making some corrections later on in the process.
We’ll introduce the updates to the project 1 solution one idea at a time: my advice is to implement the first few ideas within the current single disease framework, then extend the simulator to multiple diseases, and finally address the required extensions to Simulation. plot() and the as-yet-to-be described rewrite of the Sumulation() class constructor.
One of the traditional public health interventions used to slow the spread of disease is simply for people to stay home. The word "quarantine" comes from the Italian, when forty days ("quaranta") of isolation were required before incoming ships’ crew and passengers could come ashore in Venice during the Black Plague.
The recommended quarantine period of Q days should be a property of the disease, since each disease is contagious for a different number of days, I. Because an agent would need to develop symptoms (after E days) prior to knowing they were sick, some diseases are more amenable to quarantine, as they have relatively small E and larger I. For other diseases (those with larger E and smaller I), quarantine won’t have much of an effect on reducing the effect on the population as a whole.
We’ll add a method, quarantine(self , Q), to the Disease() class to start imposing a quarantine of Q ≤ I days for all those newly infected with the disease. Of course, not every agent is equally likely to be compliant with a quarantine order — healthcare workers are famous for working through their illness, although such misplaced heroics can actually make things worse for their weakened and susceptible patients. So the Agent() class should also be modified to reflect an individual agent’s quarantine compliance probability, q. You’ll need to modify the agent’s update() method to ensure the quarantine goes into effect at the appropriate point during the course of an agent’s illness, as long as an agent elects to comply according to their compliance probability q. If an agent honors the quarantine, they cannot infect anyone else until Q days later.
In the first project, every agent is created equal in all respects, even though they can presumably be customized with different quarantine compliance probabilities q or susceptibility parameter s. In more realistic models, agents are created of varying types, where it is the type of the agent that determines these values. Assume each agent, then, has a type variable (an integer, starting with 0) that identifies the type of that instance of class Agent(). We can use different types of agents to represent, e.g., the elderly, the hospitalized, middle-aged working agents, stay-at-home parents, young adults, children, and/or infants.
Aside from varying the values of these internal parameters, the agent types will interact with each other in different ways (e.g., small children may be less likely to interact with older adults than with the middle aged). So in addition to individualized q and s parameters for agents of different types, we need to establish an additional contact probability parameter (default 1.0) that should be factored into the Agent. infect() method’s calculations.
Because each type of agent should be capable of having a different contact probability with every other type of agent, we’ll define an agent’s contact probabilities, cp, as a list of probabilities, where each cp[i] modifies the probability that self will come into contact with an agent of type i. Thus what once relied only on s, v and t now must also factor in an agent’s cp[i] when the susceptible agent is of type i. To make this work, you’ll also need to modify Simulation(). populate() to allow one to specify the type of the agents being added and a corresponding vector of contact probabilities for that type of agent.
In project 1, we had provided a mechanism for vaccinating an agent, but had not really made any use of this mechanism. For project 2, we modify the Simulation() class to support vaccination campaigns. A vaccination campaign is characterized by the probability that a given agent will be vaccinated, and a probability that the vaccine, if given, will be effective (this is modeled by the existing v parameter of an agent).
The Simulation.campaign(self, time, disease, coverage, v) method adds a tuple containing at least (time, disease, coverage, v) toa new internal variable Simulation. events. When Simulation.run() hits time step time, all agents in the Simulation that are not infected with disease are vaccinated with probability coverage and resulting vaccine effectiveness v. Note that multiple campaigns may take place in a single simulation.
We can handle quarantine orders to use the same kind of timed event idea. Define Simulation. quarantine(self , time, disease, Q) to add a tuple containing at least (time, disease, Q) to the Simulation. events variable. In this way, we can model public health autorities’ response to a pandemic situation.
Finally, up to this point we have restricted ourselves to a single disease. In project 2, we need to lift this restriction to allow for more than one disease to be circulating at once. More specifically, we will modify the Simulation. seed() method class to operate more like the Simulation. campaign() method. By adding an additional parameter, time, we can inject new diseases into the simulation. Note that supporting multiple diseases will require significant updates to the code, since you will need to keep track of the course of each disease separately.
Extensions to Plot()
In the first project, you were asked to plot two lines showing the number of agents in state E and those in state I. In addition to I and E, modify plot() to also show the number of susceptible agents S (note that a susceptible agent who is vaccinated with effectiveness v should only contribute v <1 to the total number of agents in state S; thus the effects of a vaccination campaign should be immediately obvious in the plot).
Of course, now that there are multiple diseases, you will need to either label the lines accordingly, or create multiple plots, one per disease.
One of the fun parts of running a simulation is the ability to explore "what if" scenarios, where the impact of different conditions can be simulated to better understand the implications of public health decisions.
Should I close the schools? Should I order a quarantine? Should I order a vaccination campaign? Who should I vaccinate first? Those of you who grew up playing SimCity or the Sims can surely appreciate the usefulness of such a tool.
At this point, you should pretty much have all the components you need to deliver just this kind of simulation experience. To do so, you will need to write a top level function (not a method of any existing class) called simulate() that that supports interactive exploration of our disease simulator.
This material may consist of step-by-step explanations on how to solve a problem or examples of proper writing, including the use of citations, references, bibliographies, and formatting. This material is made available for the sole purpose of studying and learning - misuse is strictly forbidden.
import matplotlib.pyplot as plt
# Function to roll a weighted die. Returns True with probability p.
# else False.
def rolldie (p):
'''Returns True with probability p.'''
return(random() <= p)
# Our infection model is quite simple (see Carrat et al, 2008). People
# are exposed for E days (the incubation period), then infected for I
# additional days (the symptomatic period). Individuals are infectious
# as either E or I.
# Recall status starts at E+I and counts down to REC=0.
# If I=7, E=2:
# SUS REC I E+I
# | | | |
# -1 0 1 2 3 4 5 6 7 8 9
# Disease model. Each disease has a name, transmissivity coefficient,
# recovery coefficient, and exposure and infection times.
def __init__(self, name='influenza', t=0.95, E=2, I=7, r=0.0):
self.t=t # Transmissivity: how easy is it to pass on?
self.E=E # Length of exposure (in days)
self.I=I # Length of infection (in days)
self.r=r # Probability of lifelong immunity at recovery
self.Q = 0
# Quarantine function to enable quarantining of a disease
if Q <= self.I:
self.Q = Q
# Agent model. Each agent has a susceptibility value, a vaccination
# state, and a counter that is used to model their current E, I, R or
# S status.
def __init__(self, s=0.99,q=0.7,type=0,cp=[1.0]):
self.s = s # Susceptibility: how frail is my immune system?
self.v = 1.0 # Vaccination state...