Model a pandemic

This is a simple mathematical simulation (or model) of a pandemic or contagion.

Click the Simulate button to start the simulation. The graph shows the number of infections and deaths globally. The countries on the world map change colour to darker red as the number of infections in them exceeds a percentage of the population. The results panel provides the number of infections and deaths per country, and worldwide.

Please note: The data used to set the model's parameters should be considered fictitious. Don't infer anything about Covid-19 from it.

You can modify the model's parameters to create your own model. You can load and run other models, and you can save your own models to your web browser's storage for reuse later.

Technical details of the model

This is a deterministic macro, or compartmental, model that simulates daily changes as a pathogen spreads throughout a region and then between regions. It divides part of the world up into regions (usually no more fine-grained than by country) and has the following stages (or compartments) per region:

This model is very loosely based on Covid-19 but nothing about Covid-19 should be inferred from it.

Assumptions and data sources

It starts off with only 10 uncontagious infections in Wuhan. In general 8% of country populations are considered susceptible, which is the average annual influenza infection rate in the US. For countries with very weak health systems, this is set to 12%.

Travel data are from Wikipedia tourist pages. It assumes only 10% of sick people who would normally travel do so. Most countries are assumed capable of screening out 90% of sick cases. Countries with very weak health systems are considered only capable of screening 10%, with the exception of Italy which is considered to have a low screening capacity (given how Covid-19 broke out there). When a country has 100 ill people, travel to and from it halves. Population sizes are from Wikipedia except Wuhan which is set to 90m.

The transition rates between stages (compartments) have been set experimentally. (See the Change the model section.)

You will notice that a lot of the above is very presumptious indeed. And if you look at the data in the form below, you will notice that a lot of

In short, nearly every aspect of this model could be improved to be more realistic.



The number of people who cannot contract the pathogen.
The number of people who can contract the pathogen. (If lockdown is set &ndash which it isn't in the default model &ndash then the susceptible population decreases as the model progresses.)
The number of infected people who are not ill and do not transmit the pathogen.
The number of people who are not yet ill but can transmit the pathogen.
The number of people the pathogen has made sick. They can also transmit the pathogen.
The number of people who were once infected who are now no longer infected. They cannot transmit the pathogen.
The number of people who have died from the pathogen.

If any of the above are not specified they default to 0.

Transition rates

Each region also has a set of daily transition rates that determine the changes in stages (or compartments). These are:

The average number of contacts a person has per day for which there is an opportunity to transmit the infection.
The probability of a contagious infected person (i.e. people in the contagious or ill stages) transmitting to a susceptible contact. This is multiplied by avgContacts to get the infection rate per day, which determined how many people to move from the susceptible compartment to the uncontagious one. The equations for this are:
beta = avgContacts * probInfection
delta = X * beta * (Y / (X + Y))
X -= delta
U += delta
X = susceptible population
Y = infected population less uncontagious infected population
U = uncontagious infected population (Everyone who is infected starts off uncontagious.)
lockdownContactMul, lockdownAfter, lockdownIterations, lockdownMinBetween, lockdownMaxTimes
When a population has a certain number of ill people, lockdown or quarantine measures may be implemented that reduce the average number of contacts. These parameters are used to reflect this. If a region's ill people exceeds the value of lockdownAfter, then avgContacts is reduced by multiplying it by lockdownContactMult. The lockdown lasts lockdownIterations. The minimum time between successive lockdowns is lockdownMinBetween. A region can have a maximum of lockdownMaxTimes.
probInfectionSummer, summerStart, summerDuration
If the infection rate changes seasonally (e.g. influenza and coronavirus), then you can set a different infection rate for summer. probInfectionSummer is the probability of infection in summer. By default this is set to probInfection. summerStart is the simulation day that summer starts (this cycles every 365 days). summerDuration is the number of days of summer.
The rate at which people become vaccinated. This moves people from the susceptible stage to the unsusceptible one. (Set to 0.0 in this particular model but you can change it.)
The rate at which uncontagious people move to the contagious stage.
The rate at which people in the contagious stage move to the ill one. (Note that people in the ill stage remain as contagious as the people in the contagious stage.) If people who are not ill are not contagious in your model, set this to 1.0 so that everyone who is contagious is immediately made ill.
The rate at which people in the ill stage become recovered. Recovered people are neither susceptible to infection again nor contagious.
The rate at which people who are ill from the pathogen die.

The above are specified per region, but a default set of transition rates can also be specified so that you don't have to fill in every transition rate for every region.


The model also accounts for daily migration between regions. A migration route is specified with these parameters:

The region from which people are travelling.
The region to which people are travelling.
The proportion of the population that migrates this way daily. (But see actual which may make more sense to use than this.)
Instead of a rate, which may be tiny relative to the size of a region, an absolute or actual number of people who migrate in this direction daily can be specified.
Specify actual or rate, not both.
This is a measure of how effective the to country is at preventing infected people from entering it. A value of 1.0 means it is 100% effective. 0 means it is taking no effective measures against allowing infected people in.
Ill people are presumably less likely to travel. This is a rate between 0.0 and 1.0 to multiply the calculated number of ill people scheduled to travel by. So, for example, if it is set to 1.0, the number of ill people who travel this migration route is proportional to their share of the population travelling. But if set to 0.0, then no ill people travel. In the default model we've set this to 0.1, i.e. 10% of ill people who would have travelled, actually do so.
This is an optional shortcut for specifying the migration route in reverse (e.g. from the to region back to the from region). If you set this to 1.0 then the migration route is perfectly symmetrical between the two regions. If less than 1.0 more people travel from the from region to the to region. If greater than 1.0, more people travel the other way. By default this is 0.0 and a separate migration entry would need to be specified for the reverse direction. Either set symmetrical to a non-zero value or create a separate entry for the reverse direction. Don't do both. For most models it would make sense to set symmetrical to 1.0, unless you happen to have good data showing this not to be the case.
fromDetected, reducedFromTravel, toDetected, reducedToTravel
Once a country is known to have an epidemic travel to and from it will likely decrease. fromDetected specifies the number of ill people in the from region there must be for this travel decrease to kick in. The decreased rate of travel is reducedFromTravel. The toDetected and reducedToTravel are the corresponding parameters for the to area.

Default values for the above can also be specified.

Complex parameters

The following more complex model parameters are in JSON format. Feel free to fiddle with them and create a new model. The worst that can happen is that you have to refresh this page.

To have more fine-grained control, you can have multiple regions per country. But then for the map to continue working you need to specify which regions are in which countries.

This determines the map colors.

This model is for illustrative purposes only. While the inspiration to do it came from Covid-19, the real-world epidemic/pandemic has far more complexity than this model accounts for. Here are just a few of its inadequacies:
  • Many of the parameters are no more than guesses. For example, data on country-to-country travel has not been properly researched for the model. Even if more accurate data was used (e.g. based on airline travel stats), there are so many unknowns: How frequently do contagious people travel? What is the infection risk on aeroplanes? How efficient is screening at each airport? What about people crossing land borders? What about undocumented crossings? Etc.
  • The model does not account for people self-isolating themselves, which may have a big effect on reducing its spread.
  • Variations of the virus may be spreading with differing incidence and mortality rates.
  • We still do not know (as of 28 February 2020) the mortality rate of the disease because there is great uncertainty about the real number of infections.
  • We don't know the incidence rate for several reasons, e.g. some people who get infected only become mildly symptomatic or remain completely unsymptomatic.
  • Even if the model could be adjusted to correctly estimate average incidence, the virus probably spreads in fits and starts from cluster to cluster. For example, maybe it will spread through a workplace, but then "struggle" to find new hosts. A more accurate model would have to be much more fine-grained than the country-level. Even using large regions, e.g. the size of Wuhan, would probably only slightly improve the predictive power of a model.
  • The model does not account for how likely the virus is to infect or kill people of different ages (and possibly different sexes too), or how this might differ from country to country.
  • The model does not account for differences in health-care systems across countries (although it could by researching better estimates for transitions between the stages).
  • The model does not account for differences in quality of health in populations across different regions or countries, for example the prevalence of diabetes (people with diabetes are currently thought to be at higher risk of death from Covid-19).
  • The model does not account for the extraordinary but highly variable measures being taken in different cities/countries across the planet to control the virus's spread. As of the time of writing, there is still a reasonable possibility that Covid-19 may be brought under control before infecting millions of people.
  • TECHNICAL: This is a deterministic macro model. Every time you run it with the same parameters it gives the same results. A stochastic microsimulation (or agent-based) model may or may not be more appropriate depending on a bunch of factors we don't properly understand yet.

Nevertheless, with more research and care, a set of model parameters could be found, without modifying the code, that better estimates the spread of Coronavirus. Unfortunately I don't have the time or capacity to do that research, but if you have found a better set of parameters, please email them to me and I'll update the model.

Also, I suspect it may be easier to develop a plausible model of some past contagion, such as the 1918 flu pandemic.

World map showing infections