{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Epidemics and zombies

\n",
"\n",
"(Sethna, \"Entropy, Order Parameters, and Complexity\", ex. 6.21)\n",
"\n",
"© 2018, James Sethna, all rights reserved."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This exercise is based on Alemi and Bierbaum's class project, published\n",
"in \"You Can Run, You Can Hide: The Epidemiology and Statistical Mechanics of Zombies\", Alexander A. Alemi, Matthew Bierbaum, Christopher R. Myers, and James P. Sethna, *Phys. Rev. E* **92**, 022146 (2015). See also the Zombietown\n",
"site http://hey.runat.me/pages/programming/zombietown_usa.html and\n",
"simulator http://mattbierbaum.github.io/zombies-usa. The computational aspects of the exercise start in part (e).\n",
"\n",
"Epidemics are studied by disease control specialists using statistical methods,\n",
"modeling the propagation of the disease as susceptible people are infected,\n",
"infect others, and recover. The SIR model is the simplest commonly studied\n",
"model, with three coupled differential equations:\n",
"$\\dot{S} = -\\beta S I$ reflects the rate $\\beta$ at which\n",
"each infected person $I$ infects each susceptible person $S$,\n",
"and $\\dot{R} = \\kappa I$ reflects the rate $\\kappa$ that each\n",
"infected person joins the recovered population $R$.\n",
"\n",
"(a) * What is the equation for $\\dot{I}$ implied by these first\n",
"two equations, assuming no infected people die or shift groups other than\n",
"by new infections or recoveries? *\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We shall use a less common, but even simpler SZR model,\n",
"designed to predict the evolution of a zombie outbreak.\n",
"\\begin{align}\n",
"\\dot S &= -\\beta S Z \\nonumber\\\\\n",
"\\dot Z &= (\\beta-\\kappa) S Z \\\\\n",
"\\dot R &= \\kappa S Z. \\nonumber\n",
"\\end{align}\n",
"Here the zombie population $Z$ never recovers, but if it is destroyed by\n",
"a member of the surviving population $S$, it joins the removed population $R$.\n",
"The bite parameter $\\beta$ describes the rate at which a zombie bites a human\n",
"it encounters, and the kill parameter $\\kappa$ gives the rate that a human\n",
"may destroy a zombie it finds.\n",
"\n",
"The SZR model is even simpler than the SIR model, in that one can write an\n",
"explicit solution for the evolution as a function of time. We do so in two\n",
"steps.\n",
"\n",
"(b) * Argue that the only stationary states have all zombies or all\n",
"humans.* Both $\\dot S$ and $\\dot Z$ are linear in $SZ,$ so there must be\n",
"a linear combination of the two that has no time dependence. *\n",
"Show that $P = Z + (1-\\kappa / \\beta) S$ satisfies $\\dot P = 0$.\n",
"Argue from these two facts that for $P<0$ the zombies must lose.*"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"(c) * Show that $\\chi = S/Z$\n",
"satisfies $\\dot \\chi = \\gamma \\chi$, and so $\\chi(t) = \\chi_0 \\exp(\\gamma t)$.\n",
"Show that $\\gamma = -\\beta P$.\n",
"Check that this answer concurs with your criterion for human survival in\n",
"part (b).*"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So the fraction of the doomed species exponentially decays, and the\n",
"population of the surviving species is determined by $P$. If desired, one\n",
"could use the added equation $S(t)+Z(t)+R(t)=N$ with your answers to\n",
"parts (b) and (c) to solve analytically for the explicit time evolution \n",
"of $S$, $Z$, and $R$. We shall solve these equations numerically instead (below).\n",
"\n",
"Suppose now that we start with a single zombie $Z_0=1$, and the number of\n",
"humans $S_0$ is large. It would seem from our equation for our invariant\n",
"$P$ from part (b) that if\n",
"the bite parameter $\\beta$ is greater than the kill parameter $\\kappa$ that\n",
"the humans are doomed. But surely there is some chance that we will be lucky,\n",
"and kill the zombie before it bites any of us? This will happen with\n",
"probability $\\kappa/(\\beta + \\kappa)$. If we fail the first time, we can hope\n",
"to destroy two zombies before either bites again\\dots\n",
"\n",
"Here is where the statistical fluctuations become important. The SZR differential\n",
"equations above are a continuum approximation to the discrete transitions\n",
"between integer numbers of the three species.\n",
"These three equations are similar to reaction rate equations in chemistry\n",
"(as in eqn 6.50) with molecules replaced by people:\n",
"\\begin{equation}\n",
"\\begin{aligned}\n",
"S+Z &\\xrightarrow{\\beta S Z} 2 Z\\\\\n",
"S+Z &\\xrightarrow{\\kappa S Z} S+R.\n",
"\\end{aligned}\n",
"\\end{equation}\n",
"Just as for disease outbreaks, if the number of molecules is small then\n",
"chemical reactions exhibit important statistical fluctuations. These\n",
"fluctuations are important, for example, for the biology inside cells,\n",
"where the numbers of a given species of RNA or protein can be small, and\n",
"the number of DNA sites engaging in creating RNA is usually either zero or\n",
"one (see Exercises 8.10 and 8.11).\n",
"\n",
"We can simulate each individual bite and kill event for a population\n",
"of $S$ humans and $Z$ zombies. (Indeed, this can be done rather\n",
"efficiently for the entire population of the USA;\n",
"see the simulator above.)\n",
"The time to the next event is an exponential random variable given by the\n",
"total event rate. Which event happens next is then weighted by the individual\n",
"rates for the different events.\n",
"\n",
"It is well known that decay rates add. Let us nonetheless derive this. Let\n",
"the probability density of event type \\#$n$ be $\\rho_n(t)$, with survival\n",
"probability $S_n(t) = 1-\\int_0^t \\rho_n(\\tau) d{\\tau}$. Let there be\n",
"two types of events."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"(d) * Write the probability density of the first event,\n",
"$\\rho_{\\mathrm{tot}}(t)$, in terms of $\\rho_1$, $\\rho_2$, $S_1$, and $S_2$.\n",
"(The final answer should involve no integrals or derivatives.) Specialize to systems\n",
"with constant rates, which have an exponentially decaying survival time,\n",
"$S_n(t) = \\exp(-\\gamma_n t)$. Show that the total event rate\n",
"$\\gamma_\\mathrm{tot}$ is the sum\n",
"$\\gamma_1 + \\gamma_2$. Show that the probability of the next event being\n",
"$\\gamma_1$ is $\\gamma_1/\\gamma_\\mathrm{tot}$. *"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To simulate one step of our discrete SZR model, we\n",
"\n",
" (i) find the total rate of events $\\gamma_\\mathrm{tot}$,\n",
" \n",
" (ii) increment $t$ by $\\Delta t$, a random number pulled from an\n",
"exponential distribution with decay rate $\\gamma_\\mathrm{tot}$,\n",
"\n",
" (iii) choose to bite or to kill by choosing a random number\n",
"uniform in $(0,\\gamma_{\\mathrm{tot}})$, and checking if it is less than\n",
"$\\gamma_1$,\n",
"\n",
" (iv) change $S$, $Z$, and $R$ appropriately for the event, and\n",
"\n",
" (v) perform any observations needed.\n",
"\n",
"\n",
"This is a simple example of the * Gillespie* algorithm, discussed\n",
"in more detail in Exercises 8.10 and 8.11.\n",
"\n",
"(e) * Write a routine to use the Gillespie algorithm to solve the\n",
"discrete SZR model for the two reaction-rate equations above, keeping track of\n",
"$t$, $S$, $Z$, and $R$ for each event, ending when $S=0$ or $Z=0$, and\n",
"adding an extra point at $t_\\mathrm{max}$ if the system terminates early.\n",
"Write a routine numerically solve the three continuum equations above.\n",
"Use $\\beta = 0.001$, $\\kappa = 0.0008$, and $t_\\mathrm{max}=5$.\n",
"(Should the zombies win?)\n",
"Compare the two for initial conditions $Z_0 = 100$, $S_0 = 9900$, and $R_0 = 0$\n",
"(a simultaneous outbreak of a hundred zombies). Is the continuum limit\n",
"faithfully describing the behavior for large numbers of zombies and humans?\n",
"*"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%pylab\n",
"import scipy\n",
"from scipy.integrate import odeint"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def SZR(y,t):\n",
" S, Z, R = y\n",
" dSdt = ...\n",
" ...\n",
" return (dSdt, dZdt, dRdt)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def plotIt(times, traj, new = False, loc=\"center right\"):\n",
" S,Z,R = transpose(traj)\n",
" if new:\n",
" figure()\n",
" plot(times, S, 'g-', label=\"Survivors\")\n",
" plot(...)\n",
" ...\n",
" legend(loc=loc)\n",
" xlabel('time t')\n",
" Title = \"S0, Z0, R0 = \"+str(S0)+\", \"+str(Z0)+\", \"+str(R0)\n",
" title(Title)\n",
" else:\n",
" plot(times,S,'g-')\n",
" plot(times,Z,'r-')\n",
" plot(times,R,'k-')\n",
" "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"beta = 0.001;\n",
"kappa = 0.0008;\n",
"\n",
"Z0 = ...;\n",
"S0 = ...;\n",
"R0 = 0;\n",
"\n",
"tMax = 5.;\n",
"\n",
"times = arange(0.,tMax,0.1)\n",
"traj = odeint(SZR,(S0,Z0,R0),times)\n",
"g1 = plotIt(times,traj,new=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def Gillespie(S0, Z0, R0):\n",
" \"\"\"Runs SZR model using Gillespie algorithm\"\"\"\n",
" t,S,Z,R = 0.,S0,Z0,R0\n",
" times = [t]\n",
" traj = [[S0,Z0,R0]]\n",
" while (t < ...) and (...>0):\n",
" biteRate = ...\n",
" ...\n",
" totalRate = ...\n",
" t += random.exponential(...)\n",
" whichEvent = ...\n",
" if whichEvent < ...:\n",
" # Zombie bites human\n",
" S = ...\n",
" ...\n",
" else:\n",
" # Human kills zombie\n",
" ...\n",
" ...\n",
" times.append(t)\n",
" traj.append([S,Z,R])\n",
" if t\n",
"Compare the continuum solution with the zombie simulation for twenty\n",
"initial conditions using $Z_0 = 1$, $S_0 = 9999$, and $R_0 = 0$.\n",
"Are the simulations suffering from more fluctuations than they\n",
"did for larger number of zombies? Do you see evidence for zombie extinction\n",
"early in the outbreak? What fraction of the initial outbreaks appear to\n",
"have killed off all the humans? Zoom in to early times ($Z\\le 5$, $t<0.5$) and\n",
"note a few trajectories where the first zombie is killed before biting, and\n",
"trajectories where the zombie population goes extinct after reaching a\n",
"peak population of two or three. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"Z0 = ...;\n",
"S0 = ...;\n",
"R0 = 0;\n",
"tMax = 5.;\n",
"\n",
"times = arange(0.,tMax,0.1)\n",
"traj = odeint(...)\n",
"plotIt(...,new=True)\n",
"\n",
"for run in range(20):\n",
" times, traj = Gillespie(S0,Z0,R0)\n",
" plotIt(...)\n",
"\n",
"# xlim(0,0.5)\n",
"# ylim(0,5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can estimate the probability $P^\\infty_\\mathrm{ext}$\n",
"that a single zombie with bite rate larger than kill rate will go extinct\n",
"before taking over a large initial human population $S_0\\to\\infty$.\n",
"As described in Alemi and Bierbaum's zombie paper in PRE, the probability $P_{\\mathrm{ext}}$\n",
"that the zombies go extinct, in the limit of many humans,\n",
"is equal to the probability that the first one is destroyed, plus the\n",
"probability that it bites first times the probability that both zombie\n",
"lines go extinct:\n",
"\n",
"\\begin{equation}\n",
"P^\\infty_{\\mathrm{ext}} = \\frac{\\kappa}{\\beta+\\kappa}\n",
" + \\frac{\\beta}{\\beta+\\kappa} (P^\\infty_{\\mathrm{ext}})^2.\n",
"\\end{equation}\n",
"\n",
"This can be solved to show $P^\\infty_{\\mathrm{ext}} = \\kappa/\\beta$.\n",
"\n",
"Exactly this same argument holds for regular disease outbreaks. Similar\n",
"arguments can be used to determine the likelihood that an advantageous gene\n",
"mutation will take over a large population.\n",
"\n",
"\n",
"(g) *\n",
"Was the fraction of extinctions you observed in part (f) roughly given\n",
"by the calculation above? Write a simpler routine that simulates the\n",
"Gillespie algorithm over $n$ epidemics, reporting the fraction in which\n",
"zombies go extinct (observing only whether $Z=0$ happens before $S=0$,\n",
"ignoring the time and the trajectory). For $S_0= 9999$ and 1000 epidemics,\n",
"how good is the prediction? Draw a plot of $P_\\mathrm{ext}$\n",
"versus $\\log S_0$, for $S_0 = 1$, 2, 4, ..., 512, using 1000 epidemics each.\n",
"How large must the human population be before our estimate\n",
"$P^\\infty_\\mathrm{ext}$ is within about 10% of the correct answer?\n",
"*"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"def Extinction(S0,Z0=1,R0=0,nEpidemics=1000):\n",
" \"\"\"\n",
" Calculate fraction of epidemics for which the zombies go extinct\n",
" before the humans die out\n",
" \"\"\"\n",
" nExtinct = ...;\n",
" for epidemic in range(...):\n",
" S,Z,R = S0,Z0,R0\n",
" while Z>0 and S>0:\n",
" biteRate = ...\n",
" ...\n",
" if whichEvent < ...:\n",
" # Zombie bites human\n",
" ...\n",
" else:\n",
" # Human kills zombie\n",
" ...\n",
" if S>0:\n",
" ...\n",
" return nExtinct/nEpidemics\n",
" \n",
"print(Extinction(...,nEpidemics=...), \" compared to predicted \", kappa/beta)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"initialPop, Pext = transpose([(2**n, Extinction(2**n)) for n in range(0,10)])\n",
"semilogx(initialPop,Pext,\"o-\")\n",
"xlabel(\"Initial population\")\n",
"ylabel(r\"Zombie extinction probability $P_\\mathrm{ext}$\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.1"
}
},
"nbformat": 4,
"nbformat_minor": 0
}