Running a process

The easiest way to understand how epydemic works is to use one of the in-built disease processes to perform a simulation. After that we’ll look at how to run large-scale simulations and how to build disease models from scratch.

We first need to import the basic classes.

from epydemic import SIR, StochasticDynamics, ERNetwork

Creating a model

Let’s start with a disaese process. For simplicity we’ll using the builtin SIR process.

# create a model
m = SIR()                      # the model (process) to simulate

Providing parameters

All epydemic’s processes take a range of parameters and use them when building the model. These are provided as a dict, with the contents depending on the model we’ll be building. Continuing with the SIR process, we need to provide three paremeters for the infection probability, the removal probability, and the initial seeding probability.

param = dict()
m.setParameters(param, {SIR.P_INFECT: 0.1,      # the probability of infection
                        SIR.P_REMOVE: 0.5,      # the probability of removal
                        SIR.P_INFECTED: 0.01})  # the fraction of nodes initially infected

Note

We set the parameters relating to the process using Process.setParameters(). You can also put the parameters into the dict directly, but this way is more flexible for more complicated cases involving multiple processes.

Providing a network

We can run the simulation over any appropriate network. A network whose degree distribution followed a powerlaw with cutoff would probably be most realistic, but for now we’ll just use an ER random graph model.

param[ERNetwork.N] = 10000             # order (number of nodes) of the network
param[ERNetwork.KMEAN]= 5              # mean node degree

Running the simulation

We can now perform a single run of the simulation, using stochastic dynamics.

# create a network and tie it together with the model using a dynamics
g = ERNetwork()                # network generator for ER networks
e = StochasticDynamics(m, g)   # use stochastic (Gillespie) dynamics

# set the parameters we want and run the simulation
rc = e.set(param).run()

If for some reason we wanted to use synchronous dynamics, we’d simply replace the simulation dynamics framework: the same models work under both frameworks.

f = SynchronousDynamics(m, g)
rc = f.set(param).run()

We can re-run the simulation, with or without changing the parameters.

# re-run with the same parameters
e.run()

# change something and re-run
m.setParameters(param, {SIR.P_REMOVE: 1.0})
rc = e.set(param).run()

Retrieving results

The run method returns a dict of results. The structure of this dict is defined by epyc, and is described here: for our purposes, we will simply see a nested dict with the results of the experiment appearing in a dict under the epyc.Experiment.RESULTS key. Or you can simply use Process.getResults():

[nS, nI, nR] = m.getResults(rc, [SIR.S, SIR.I, SIR.R])

The experimental resuilts are constructed by the Process.results() method. This is overridden by CompartmentedModel.results() to contain a mapping from compartments to the number of nodes in that compartment at the end of the simulation. Sub-classes can override the method further to add more results.

This is all that’s needed to define a run individual simulations of networked processes. There are additional methods and event types that can be used in other circumstances, which we explore in Advanced topics. It is also common to want to run simulations that explore the ways in which a process changes across a range of parameters, which we discuss under Running a simulation at scale.