The SIJR model is non-standard, and further explained in the Tutorial. Briefly it defines an extra super-infectious stage to the SIR model whereby any node in the J-state in addition to acting as a normal infecting node also creates a mean field over the whole population, ignoring network structure, and influencing the probability of infecting all susceptible nodes.
The python example below is not the recommended way of implementing such a structure but was included in the Tutorial as an example.
class SIJRProcess(ExplicitStateProcess):
"""
S I (J) R process, where J is a super-spreader state of the Infected class.
For simplicity we assume that the recovery rate of the J class is the same
(gamma) as for the I class.
Attributes
----------
beta - Infection rate.
gamma - Recovery rate.
alpha - Rate at which an infected node turns into a super-spreader.
"""
def __init__(self, beta, gamma, alpha):
super(SIJRProcess, self).__init__(['S', 'I', 'J', 'R'],
[],
runNodeUpdate = True,
runEdgeUpdate = False,
runNetworkUpdate = True,
constantTopology = True)
self.beta = float(beta)
self.gamma = float(gamma)
self.alpha = float(alpha)
def nodeUpdateRule(self, node, srcNetwork, dt):
# Read original node state.
srcState = node[1][self.STATE_ATTR_NAME]
# By default we have not changed states, so set
# the destination state to be the same as the source state.
dstState = srcState
# Start out with a dictionary of zero neighbors in each state.
nNSt = dict(zip(self.nodeStateIds,[0]*len(self.nodeStateIds)))
# Calculate the actual numbers and update dictionary.
nNSt.update(attributeCount(neighbors_data_iter(srcNetwork, node[0]),
self.STATE_ATTR_NAME))
# Pick a random number.
eventp = numpy.random.random_sample()
# Go through each state name, and chose an action.
if srcState == 'S':
if eventp < ( self.beta*(nNSt['I'] +nNSt['J']) + srcNetwork.graph['fracJ'])*dt:
dstState = 'I'
elif srcState == 'I':
# Check recovery before super spreader.
if eventp < self.gamma*dt:
dstState = 'R'
elif eventp - self.gamma*dt < self.alpha*dt:
dstState = 'J'
self.Jcounter += 1
# Super spreaders are still infected and can recover.
elif srcState == 'J':
if eventp < self.gamma*dt:
dstState = 'R'
self.Jcounter -= 1
node[1][self.STATE_ATTR_NAME] = dstState
return node
def networkUpdateRule(self, network, dt):
# We have to count the fraction of the population
# in the J state here.
# However as the variable self.Jcounter contains
# the number of nodes in state J we can use that.
network.graph['fracJ'] = self.Jcounter/float(len(network))
return network
def initializeNetworkNodes(self, network, *args, **kwargs):
# Use most of the functionality in the superclass.
super(SIJRProcess, self).initializeNetworkNodes(network, *args, **kwargs)
# Now the network should be initialized so we can compute the right fraction of super-spreaders.
d = attributeCount(network.nodes_iter(data=True),self.STATE_ATTR_NAME)
self.Jcounter = d.get('J',0.0)
network.graph['fracJ'] = self.Jcounter/float(len(network))
return network
# This is the simulation section.
[Simulation]
# Run the simulation this many iterations.
iterations = 2000
# The time step taken each iteration.
dt = .1
# This is the python module containing the process we wish to use.
process_class_module = extended_SIR
# This is the name of the process object.
process_class = SIJRProcess
# This is the name of the network generation function.
network_func = BA_networkx
# We need to add another module path
module_paths = ../modules/
# Network settings.
[NetworkParameters]
# Number of nodes.
n = 1000
# Number of edges to add in each iteration.
m = 2
# Defining the process parameter values.
# The contents of this section is dependent on
# the parameters of the process class as specified by
# the option process_class in the Simulation section.
[ProcessParameters]
# Infection rate.
beta = .9e-2
# Recovery rate
gamma = 0.04
# Rate of a node to become a super spreader.
alpha = 0.007
# The fraction of nodes, alternatively the number of nodes, that will be assigned to each state initially.
# The state names must match those specified by the network process class.
[NodeStateDistribution]
# 95% S
S = 0.95
# 5% I
I = 0.05
R = 0
J = 0
# Result output settings.
[Output]
# Output directory:
output_dir = ../output/
# This is the base name of all files generated by the run.
base_name = test_SIRJ
# If unique is defined as true, yes, 1, or on, unique file names will be created (time stamp added)
unique = yes
# If this is true, yes, 1, or on, a copy of the full program config, plus an Info
# section will be saved.
save_config = yes
# If this is true/yes/on, the network node states will be counted and saved as a csv file.
# Default value True.
# Note only valid if the current process support updates. If not nothing will be saved.
save_state_count = yes
# Count nodes every ... iterations. Value should be integer >= 1.
# Default value 1.
save_state_count_interval = 1
# If this is true, yes, 1, or on, a copy of the network will be saved.
# Save interval may be set using the save_network_interval key.
save_network = yes
# This control how often the network will be saved.
# A value <= 0 means only the initial network will be saved. A positive value
# n> 0, results in the initial network being saved plus every n:th iteration
# thereafter, as well as the last network.
# Default value 0.
save_network_interval = 0