This article discusses simulating epidemics using Go and Python, focusing on the spread of a viral disease and the impact of quarantine and medication on its progression.
Abstract
The article begins by describing the author's motivation for creating an epidemic simulation due to the ongoing COVID-19 pandemic. The simulation is built using Go and Python, with a grid of cells representing the population. The model includes parameters such as infection rate, incubation duration, infection duration, fatality rate, and immunity. The simulation also considers the introduction of quarantine measures and medicine to combat the epidemic. The results of the simulation show that quarantine is highly effective in controlling the spread of the disease, while medication can also help but is less effective on its own. The combination of both quarantine and medication is the most effective way to stop the epidemic.
Opinions
The author emphasizes the importance of understanding the spread of epidemics and the impact of various interventions.
The article highlights the potential of using simulations to explore different scenarios and inform decision-making during an epidemic.
The author suggests that quarantine is the most effective way to stop the spread of an epidemic, especially when implemented early and effectively.
The article suggests that medication can be useful in slowing down the epidemic, but its effectiveness depends on its ability to cure the infected.
The author concludes that a combination of quarantine and medication is the most effective way to stop an epidemic.
The author acknowledges the limitations of simulations and models, stating that they are only approximations of reality.
The author expresses concern about the ongoing COVID-19 pandemic and hopes for its resolution.
Simulating epidemics using Go and Python
Simulate and analyse different epidemic scenarios with Go and Jupyter Notebook
This is something that’s directly impacting me even as I am typing out this story. What started out as a small outbreak of a novel coronavirus in Wuhan, China towards the end of December 2019, quickly spread to the rest of China and beyond its borders. As of writing in February 2020, less than 2 months from its initial reporting, there are about 70,000 confirmed cases and almost 1,700 deaths. While most of the cases and deaths are still in China, centering around Wuhan and surrounding cities, the situation is quickly evolving.
In Singapore where I live, the first suspected case was reported on 2 Jan. The patient, a three-year-old girl with a travel history to Wuhan. It turned out to be pneumonia.
Like everyone in Singapore, I’ve been following the situation uneasily, blow by blow. As part of business continuity planning, I’ve already segregated my teams and asked everyone else who didn’t have to have face-to-face meetings to work from home. Life and work continue but there is a simmering level of tension and anxiety.
Much of the code is the same as the cultural interactions simulation, so I won’t reproduce it here. Instead, I’ll just focus on the differences.
Let’s start with modeling an epidemic. The model is quite straightforward. Using a grid of cells, I start with a single cell, infected by a viral disease, at the center of the grid. Over a number of days, the infected cell will infect its neighbours and I will collect data from the simulation and do some analysis.
The basic parameters like width and numDays are pretty much the same as the previous simulation while filename is the name of the file to save the simulation data to.
The first parameter for the epidemic simulation is the infection rate (rate) which is the likelihood a cells infects it neighbour. Next is the incubation duration (incubation) which is the number of days the virus will stay dormant before it starts being infectious. At this stage, the cell is already infected, though it’s not infectious yet. The infection duration (duration) is how long the cell stays infectious. At the end of the infection duration, the cell will either recover or die. The likelihood that the cell will die is the fatality rate (fatality) and the likelihood the cell can be re-infected, is its immunity (immunity).
We start off the simulation with a population of healthy cells and a single infected cell at the center of the grid. In our simulation, not the entire grid will be populated, the number of cells in the grid are determined by the density parameter. At a value of 1.0 the whole grid will be populated, while at the other end of the spectrum, 0.0 means the grid is not populated at all.
While I simulate the progression of the epidemic over time, I also wanted to understand how the introduction of quarantine measures as well as effective medicine can help stop it.
The parameter medIntroduced is the day medicine is introduced in the fight against the epidemic. For example, if the value is 100 it means medicine is introduced on the 100th day. The parameter medEffectiveness is a measure of the effectiveness of the introduced medicine. A value of 1.0 means the medicine is completely effective and each cell that is medicated will have 100% chance of recovery, while a value of 0.0 means the medicine is completely ineffective. After an infected cell is medicated and fails, that’s the end of the line, it will have to depend on its own luck to survive.
The parameter qIntroduced is the day quarantine measures are similarly introduced. The parameter qEffectiveness is a measure of how successful the quarantine is, including finding the infected cell and making sure its properly quarantined. Once an infected cell is quarantined, it won’t be able to infect its neighbours though it doesn’t impact its survival rate.
Cell
With this let’s look at how we need to change the Cell struct. There are no surprises, the corresponding parameters are dutifully reflected.
I added a number of new methods to the Cell struct. Most of the methods are quite self-explanatory so I won’t bother describing all of them.
The medicate method applies medicine to the cell, with a chance of the cell recovering. If it doesn’t, I mark the cell as being medicated, and I won’t call it again. Once the medicine proves ineffective, that’s it — the cell is on its own.
The process method is where most of the action is. If the infected cell is still in incubation, I decrease its incubation counter and do nothing else. Otherwise, I will start decreasing its duration counter, and once the duration counter reaches 0, depending on the fatality rate, the cell will either recover or die.
Let’s move on to the main simulation.
Main simulation
I start off with creating the population. As mentioned before, the density parameter determines how much to populate the simulation grid. By default, the value is 0.7 meaning 70% of the grid would be (randomly) filled with cells.
Next, I infect a single cell right in the center of the simulation grid. then kick start the simulation.
The main simulation loop essentially runs through all the cells and prints out the grid as well as print some info on the screen. Here’s the sequences of steps when running through the cells:
Firstly, I only care about infected cells, if it’s not an infected cell, I simply ignore it
Next, I process the cell with the process method as above. This will decrease the incubation or duration counter accordingly, and if the duration reaches 0, will either choose recovery or death for the cell
If the cells has recovered or is still incubating, I’ll skip to the next cell
If it’s time to introduce medicine, I start medicating the cell. If medicine works for the cell, it’s recovered! Else I mark it as being medicated and will skip it in later loops (the medicine doesn’t work for it any more)
Of course, if the medicine worked, the cells would have recovered and so I’ll move on to the next cell
If it’s time to introduce quarantine measures, I’ll check if the infected cell has already been discovered and quarantine, if it’s not I’ll quarantine the cell
The last step, if it reaches here, is to look at the cell’s neighbours. If they are not already infected and if they are not immune to re-infection, I try to infect them
Simulations
The simulation as you can see is simple and straightforward. Let’s take a look at the results.
I’ll start with a typical viral epidemic, using the default values. We’ll also look at the data over different infection rates later.
In the default simulation scenario, the grid is 70% populated and runs for 300 days. The infection rate is 15%, with possibility of re-infection at 50%. The virus incubates for 3 days and remains infectious for 4 days. The fatality rate is 2%.
The results are pretty grim. As of the 300th day, the virus is still active, with almost all cells having been infected, though almost 96% have recovered from it at least once. As a result, 18.4% of the population died from the epidemic.
Although the fatality rate of 2% is per infection, because the cells can be re-infected over and over again (they are only 50% immune) the death count is much higher!
With different infection rates
Let’s look at it closer with the data. I run the simulation for an infection rate of 10%, 15%, 30% and 50%. The data that is collected from the simulation shows over time, the number of infections at any point, the number of deaths and number of cells that have been infected. If you are puzzled what the difference is between number of infections and number of infected cells — the number of infections is the number of current infections, which could include re-infections, while the number of infected cells doesn’t include re-infections and includes cells that have been infected and died or recovered.
As before, I used Python 3 over Jupyter Notebook, threw in matplotlib and did some simple charting. The code is relatively simple and I won’t explain it, you can just simply read it here.
Instead let’s look at the results. For the number of infections at any point in time, you can see that interestingly the numbers decline over time.
This isn’t necessarily a good thing because if you look at the next chart, you can see that the number of deaths simply go up quite linearly, meaning the infections drop over time because there are fewer cells alive!
Finally let’s take a look at the number of cells that are infected over time. The numbers plateau over time because all cells have been infected!
Different fatality rates
Now let’s look at different fatality rates at 1%, 2%, 5%, 10% and 20%.
The number of infections remain the same initially but as time goes by, the higher fatality rates don’t necessarily translate to more infections, in fact, it’s the reverse!
This is scary because more cells die and so there are fewer infected!
Finally, you can see that the overall number of infected cells are almost the same regardless of fatality rates.
While I can do the same for the other epidemic parameters, it’s all a bit too morbid to continue. Let’s switch over to something more positive, what can we do about the epidemic, slowing it down or even stopping it? For the simulation, I have 2 methods:
Quarantine — isolates the infected cells so that it doesn’t infect other cells
Medication — cures the viral disease so the cell recovers
At a glance, which method do you think helps better? Let’s experiment.
With quarantine
As you can quickly see from the video, once the quarantine starts (here it’s starting from day 50), the epidemic quickly comes under control!
In fact, if you compare this with the simulation without quarantine:
18% of the population were infected, as opposed to 99.4% without quarantine
0.8% of the population died, as opposed to 12% without quarantine
This is quite a startling improvement! Probing further, I ran simulations with different quarantine effectiveness of 10%, 20%, 30% and 50%.
From the chart below you can see that different quarantine effectiveness reduces the number of infections at different rates. At 10% effectiveness, the effects are low but once it hits at least 20% and above, the infections drop drastically. Even then, no matter what effectiveness quarantine has, it’s still much better than no quarantine!
As with the deaths, once quarantine is in place, the number of deaths drop drastically. Even at 10% effectiveness you can see that the numbers taper off, meaning after a while no cell dies anymore.
The number of infected cells also drop dramatically. For 20% effectiveness and above you can see that the number flatlines soon after day 50, meaning no more cells are infected (you can also see this visually from the simulation).
If quarantine starts later
What if quarantine starts later? This results in infections growing but as before once quarantine is in place, it drops quickly.
The chart for deaths is the same as when we analysed for quarantine effectiveness. After a while, no cell dies anymore.
The same goes for the number of infected cells.
Now let’s look at the second method which is to medicate.
With medication
With medication, the impact is different. Firstly, once medication is applied to a cell, there is a chance it will recover (the effectiveness of the medicine). However, if it doesn’t recover, it means the medicine doesn’t work on it and will never work even if it recovers on its own and gets re-infected.
Secondly, medicine doesn’t change the possibility of re-infection, so you can see in the chart below, at lower effectiveness of the medicine, the number of infections just slow down instead of disappearing altogether.
However, as the effectiveness of the medicine increases, it prevents the cell from being infectious by curing it altogether!
I ran the simulation at the medicine effectiveness of 0%, 30%, 50% and 75%. At 75% effectiveness the number of infections essentially dropped to 0 soon after day 50 while even at 50% effectiveness, the disease lingers on and infections even increase after a while.
Correspondingly, this translates to the number of deaths. At the lower effectiveness, the medicine just slows down the rate of death, never totally eliminating it, but if the medicine is effective enough, it will eliminate the infections altogether and prevents further deaths.
This can be seen also from the number of infected cells chart.
From this analysis, it seems medication is not as good as quarantine. However that is a matter of perspective, if you’re looking at the overall epidemic it seems quarantine is more effective, but if you’re the patient, quarantine does nothing for you personally while medicine can possibly save your life!
What if we put in quarantine measures and apply good enough medication as well?
With quarantine and medication
I used a quarantine effectiveness of 20% starting from day 50, a medicine effectiveness of 50%, also starting at day 50, then compare them with just quarantine measures alone and medication alone.
As you can see from the chart, using both results in a pretty effective stop to the spread of the epidemic! The number of infections drop drastically starting from day 50.
It also reduces the overall number of deaths, better than either by itself.
And the number of infected cells are reduced as well.
The combined effects of both quarantine and medication are very effective. If they have sufficient levels of effectiveness, (if they are implemented well) it can potentially stop the epidemic in its tracks!
Summary
I only ran partial simulations here. For example I didn’t run any simulations on the variations of incubation period or infectious durations. I didn’t explore the effects of immunisation (or vaccination) to prevent re-infection nor did I look at different population densities. If you enjoy what I did please do try it out yourself.
What we’ve found out at least from this exercise is:
Epidemics are crazy scary. If unchecked, the entire population can be infected and huge swathes of the population could be decimated. If we look back at history, we can see this from the Spanish flu (killed between 50–100 million people), the Black Death (killed 60% of the population of Europe) and so on.
Quarantine is the most effective way of stopping epidemics from spreading and the earlier it is imposed, the better. Effectiveness of quarantines is also important, and that includes finding and isolating the infected.
Medication is useful only at a higher rate of effectiveness where it cures the infected, otherwise, it merely slows down the epidemic.
A combination of quarantine and medication is the most effective way of stopping the epidemic.
Conclusion
I often make the disclaimer that models are just models and simulations are just simulations. They attempt to give us a means to explore possibilities where it is impossible to do in real life but they are not the same as the real thing. We can only provide an approximation using our parameters. This is the case in this simulation as well.
I hope this is useful in one way or another but if you disagree with my conclusions or methods, please feel free to correct me and to submit a pull request for the code!