A Simple Model for Epidemics

Kenneth Levasseur
Mathematical Sciences
UMass Lowell
Kenneth_Levasseur@uml.edu

Around 15 years ago, when I was teaching Calculus II, I used this ice-breaker on the first day of class.  Certainly not something that we could do now, but the results are instructive.  I’ve added a another simulation that illustrates what we’ve all been hearing about the effects of social distancing.

A Mathematica Notebook can be downloaded if you would like to experiment with this model - I’m sure the programming could be streamlined.

Classroom simulation

Introduction:  We're going to model an epidemic.  Here is how it will work.   At the start of the process, one of you will be "sick"  and we will go through a series of "days"   Each day everyone will do the following: you will make contact with exactly one person by tapping him/her on the shoulder, telling whether you are sick or not, and  then you can introduce one another.  If you are sick and the person you tapped on the shoulder was well, then he/she becomes sick.   If you are well and you tapped a sick person on the shoulder, you don't become sick.   You may be tapped on the shoulder more than one time or not at all in one day, but you should tap exactly one person on the shoulder.  As the days pass, you may tap the same person on the shoulder more than once—ideally you should choose people randomly. 

Before we get started, take out a sheet of paper.   Draw what you think might be the graph of the number of people who get sick verses the days.   This will actually be a discrete graph, like a bar graph, but you can draw a continuous curve to indicate the shape of the graph

You will get a "Post-it."  If it has the number 1 on it, you are the lucky person who is sick and starts the epidemic.    When you get sick, make a note of the day on which you get sick  on the Post-it  

On the first day, the “patient zero” gets sick and we assume that day 0 has passed; so we start with day 1.

After 10 days, see if anyone is well.   Continue until almost everyone is sick.

Stack your Post-it notes in the column marked by the day you got sick.

Original Computer simulation

In this simulation, we assume that every person comes in contact with exactly one other person. It’s a one way encounter in that if A comes in contact with B.  We also assume B comes in contact with someone else, who may or may not be A.

contacts:=Map[{Random[Integer,{1,M}],#}&, Range[M]];
newsicks:=(addtosick={};Map[If[MemberQ[well,First[#]]&&MemberQ[sick,Last[#]],addtosick=Union[addtosick,{First[#]}]]&,#];
{well,sick}={Complement[well,addtosick],Union[sick,addtosick]};Length[sick])&;
M=500;
{well,sick} = {Range[M-1],{M}};
spreaddata=Table[newsicks[contacts],{M}]//.{{a___,M,M}->{a,M}}//Prepend[#,1]&;
dailydata=Differences[spreaddata];Grid[{{e1=ListPlot[spreaddata,PlotRange->{0,M},Joined->True,Ticks->{{0,Length[spreaddata]},{0,M}},PlotStyle->RGBColor[0,1,0],Epilog->{PointSize[0.02],RGBColor[1,0,0],Map[Point[{#,spreaddata[[#]]}]&,Range[Length[spreaddata]]]}],d1=ListPlot[dailydata,PlotRange->{0,Max[dailydata]},Joined->True,Ticks->{{0,Length[dailydata]},Range[0,Max[dailydata]+10,Round[Max[dailydata]/5.]]},PlotStyle->RGBColor[0,1,0],Epilog->{PointSize[0.02],RGBColor[1,0,0],Map[Point[{#,dailydata[[#]]}]&,Range[Length[dailydata]]]}]}}]

Social Distancing Simulation

In this simulation, we assume that only a certain percentage of individuals contact others.  Changing the value of contactpercentage will lengthen the epidemic but lower the peak.  Initially we assume that a random 70% of individuals are quarantined on any day.

contactpercentage=0.3
contacts:=Map[{Random[Integer,{1,M}],#}&, Range[M]]//RandomSample[#,Round[contactpercentage M]]&;
newsicks:=(addtosick={};Map[If[MemberQ[well,First[#]]&&MemberQ[sick,Last[#]],addtosick=Union[addtosick,{First[#]}]]&,#];
{well,sick}={Complement[well,addtosick],Union[sick,addtosick]};Length[sick])&;
M=500;
{well,sick} = {Range[M-1],{M}};
spreaddataSD=Table[newsicks[contacts],{M}]//.{{a___,M,M}->{a,M}}//Prepend[#,1]&;
dailydataSD=Differences[spreaddataSD];Grid[{{e2=ListPlot[spreaddataSD,PlotRange->{0,M},Joined->True,Ticks->{{0,Length[spreaddataSD]},{0,M}},PlotStyle->RGBColor[0,1,0],Epilog->{PointSize[0.02],RGBColor[0,0,1],Map[Point[{#,spreaddataSD[[#]]}]&,Range[Length[spreaddataSD]]]}],d2=ListPlot[dailydataSD,PlotRange->{0,Max[dailydataSD]},Joined->True,Ticks->{{0,Length[dailydataSD]},Range[0,Max[dailydataSD],1+Max[dailydataSD]/5.]},PlotStyle->RGBColor[0,1,0],Epilog->{PointSize[0.02],RGBColor[0,0,1],Map[Point[{#,dailydataSD[[#]]}]&,Range[Length[dailydataSD]]]}]}}]

The two sets of plots have the  same aspect ratio so you have to pay attention to the scales.  Alternatively, here are the daily exposures for the two models plotted together.

ListPlot[{dailydata,dailydataSD},PlotRange->All,Joined->True,PlotLegends->{"No Social Distancing","Social Distancing "<>ToString[contactpercentage*100]<>"%"}]