T4 - Networks#

Many infectious diseases transmit when people come into contact with one another. In the basic SIR example that we covered in the first two tutorials, we used a ‘random’ contact network, which creates random pairings of people. Generally speaking, the structure of network that you use depends on what disease you’re modeling. In addition to the ‘random’ network, Starim contains some basic sexual networks for modeling sexually transmitted infections (STIs) and a ‘maternal’ network for modeling mother-to-child transmission.

In this tutorial, we’ll demonstrate a couple of the built-in networks, and give an overview of how you might create your own for your own disease modeling work.

Overview of Starsim’s network structure#

Starsim’s networks are stored in the networks.py file. At the top of this file you’ll see the Network class, which provides the template for all the other networks. At a high level, all you need to know is that network stores various parameters that determine how pairs of people form and dissolve, and a collection of all the contacts that exist at a given point in time. Let’s look at a simple example of the random network:

[1]:
import starsim as ss

# Make random network
random = ss.RandomNet()
Starsim 1.0.0 (2024-07-10) — © 2023-2024 by IDM

The network we just made stores two very important things: the list of contacts (found in random.contacts) and the parameters (random.pars).

If we just make a network on its own like this, it’s not very interesting. Like all components of Starsim, it needs to be initialized within a sim before the database of contacts gets populated:

[2]:
network = ss.RandomNet()
sir = ss.SIR()
sim = ss.Sim(n_agents=2_000, diseases=sir, networks=network)
sim.initialize()
Initializing sim with 2000 agents
[2]:
Sim(n=2000; networks=randomnet; diseases=sir)

Now sim.networks.random.contacts has all the information about which agents (referenced by their UID) are paired with which other agents.

Sexual networks#

Starsim contains a few basic sexual networks, including an mf network for modeling heterosexual partnerships and an msm network for men having sex with men. Modeling STIs is a straightforward extension of the SIR example we looked at previously. Here’s an example modeling syphilis:

[3]:
# Create the disease
syph = ss.Syphilis(
    beta = {'mf': [0.25, 0.15]},    # See notes below
)

# Create a heterosexual network
mf = ss.MFNet(
    duration=1/24,  # Using very short relationships so that we get more transmission
    acts=80,        # Distribution of the number of coital acts/year
)

pars = dict(dt=1/12, start=2000, n_years=20)
sim = ss.Sim(pars=pars, diseases=syph, networks=mf)

The main difference here is that we’ve added the line syph.pars['beta'] = {'mf': [0.25, 0.15]}. Because STIs are generally more transmissible from males to females than vice versa, we can specify beta as a list, and we can also allow it to vary between networks. For instance, if we also had an MSM network here, we could set

syph.pars.update(beta = {'mf': [0.25, 0.15], 'msm': [0.4, 0.4]})

The sexual network itself is structurally similar to the random network that we looked at previously, and can be customized by changing the pars dictionary that’s used to construct it.

Maternal networks#

Maternal networks are useful for capturing mother-to-child transmission. If you want to use them, you also need to model pregnancy. Here’s an example showing how you would do this for syphilis:

[4]:
syph = ss.Syphilis(
    beta = {'mf': [0.25, 0.15], 'maternal': [0.99, 0]}
)

# Make demographic modules
pregnancy = ss.Pregnancy(fertility_rate=20)
death = ss.Deaths(death_rate=15)

# Make maternal network
maternal = ss.MaternalNet()

# Make sim
sim = ss.Sim(pars=pars, diseases=syph, networks=[mf, maternal], demographics=[pregnancy, death])

Making your own network#

If you want to make your own network, a good place to start is by inheriting from one of the templates in networks.py. For example, if you wanted to make an mf network that has more age structure, you could do something like this:

[5]:
class age_mf(ss.MFNet):
    def add_pairs(self, people, ti=None):
        # Custom code to select pairs based on age
        return

This network would operate exactly like the existing mf network, but you could control how new pairs were added.