simpar package

simpar.sim module

SIR-style model simulation.

The module defines a [Sim] class. The class is initialized with base parameters for the simulation. The [step] method allows one to step through the simulation one or many time periods at a time. Infection spread and discovery parameters can be specified and the base parameters are used by default.

class simpar.sim.Sim(max_T: int, init_susceptible: ndarray, init_infected: ndarray, init_recovered: ndarray, infection_rate: ndarray, infection_discovery_frac: Union[float, ndarray] = 1, recovered_discovery_frac: Union[float, ndarray] = 1, outside_rate: ndarray = 0)[source]

Bases: object

Maintains an SIR-style model simulation on a heterogeneous population.

Infections last a single generation, after which people recover and are immune for the remainder of the simulation. Infections may be discovered immediately (e.g., through symptomatic self-reporting or surveillance) or may be discovered later (e.g., because of an asymptomatic test applied to the whole population).

During execution, S, I, and R are TxK matrices that track the number of susceptible, infectious, and recovered people in each of the K groups over T time periods. Additionally, D and H track the number of discovered and hidden non-susceptible people.

Initialize an SIR-style model simulation.

The initial state of the simulation is passed through the [init_susceptible], [init_infected], and [init_recovered] parameters. Note: the initial discovered and hidden assumes all recovered are discovered and [infection_discovery_frac] of infected are discovered.

Internal infection spread is determined by the [infection_rate] matrix parameter which indicates the number new infections that an infected person in one group creates in another. Additionally, the [outside_rate] parameter specifies the outside rate of infection.

To model infection discovery, the [infection_discovery_frac] parameter determines what fraction of infected are discovered in the generation they are infected. Otherwise, they become “hidden recovered.” Furthermore, the [recovered_discovery_frac] parameter determines what fraction of hidden recovered infections are discovered in each generation.

Parameters:
  • max_T (int) – Maximum number of time periods to simulate.

  • init_susceptible (np.ndarray) – Vector of the initial number of people in each group that are susceptible.

  • init_infected (np.ndarray) – Vector of the initial number of people in each group that are infected.

  • init_recovered (np.ndarray) – Vector of the initial number of people in each group that are recovered.

  • infection_rate (np.ndarray) – Matrix where infection_rate[i,j] is the number of new infections that an infected person in group i creates in group j

  • infection_discovery_frac (float or np.ndarray) – Fraction of infections discovered in the generation they are infected. Can be specified globally (as a float) or separately for each group (as a np.ndarray). Defaults to 1.

  • recovered_discovery_frac (float or np.ndarray) – Fraction of hidden recovered discovered in each generation. Can be specified globally (as a float) or separately for each group (as a np.ndarray). Defaults to 1.

  • outside_rate (np.ndarray) – infections per time period, weighed by population of each group in a meta-group.

static from_dictionary(d: Dict)[source]

Initialize an instance of Sim from a dictionary.

step(n: int = 1, infection_rate: Optional[ndarray] = None, infection_discovery_frac: Optional[Union[float, ndarray]] = None, recovered_discovery_frac: Optional[Union[float, ndarray]] = None, outside_rate: Optional[ndarray] = None)[source]

Take [n] steps forward in the simulation.

To model change in infection and discovery parameters over time, these parameters can be provided to be applied to the next [n] time periods.

Parameters:
  • infection_rate (np.ndarray) – Matrix where infection_rate[i,j] is the number of new infections that an infected person in group i creates in group j

  • infection_discovery_frac (float or np.ndarray) – Fraction of infections discovered in the generation they are infected. Can be specified globally (as a float) or separately for each group (as a np.ndarray). Defaults to 1.

  • recovered_discovery_frac (float or np.ndarray) – Fraction of hidden recovered discovered in each generation. Can be specified globally (as a float) or separately for each group (as a np.ndarray). Defaults to 1.

  • outside_rate (np.ndarray) – infections per time period, weighed by population of each group in a meta-group.

simpar.groups module

Heterogeneous population manager.

This module defines a [MetaGroup] class which describes a group of people for which most parameters are similar but who have varying degrees of social contact. Furthermore, it defines a [Population] which is comprised of multiple [MetaGroup]s. Testing strategies can be set at granularity of [MetaGroup]s.

class simpar.groups.MetaGroup(name, pop, contact_units)[source]

Bases: object

Initialize a meta-group.

A “meta-group” is a collection of groups. Each group within the meta-group is associated with a level of social contact.

The population is assumed to be well-mixed meaning that group i’s amount of interaction with group j is proportional to group j’s fraction of the population and both groups contact levels.

In a school setting, example meta-groups could be undergraduates, professional students, graduate students, and faculty/staff.

static from_truncated_pareto(name: str, population: float, a: float, ub: int)[source]

Initialize a meta-group from a truncated Pareto distribution.

Parameters:
  • name (str) – Name of the metagroup.

  • population (float) – Total population in this metagroup.

  • a (float) – Shape parameter (alpha) for the Pareto distribution.

  • ub (int) – Truncation point for the Pareto distribution.

get_init_SIR(init_infections: float, init_recovered: float, weight: str = 'population')[source]

Return initial SIR vectors.

Given [init_infections] and [init_recovered] aggregated at the meta-group level, the [weight] parameter specifies how these counts should be distributed across the groups within this metagroup. The available options for [weight] are:

  • “population”: Each person is equally likely to be infected.

  • “population x contacts”: A person’s probability of being infected is proportional to their amount of contact.

  • “most social”: The initial infections are in the most social group.

Parameters:
  • init_infections (float) – Initial infections count in meta-group.

  • init_recovered (float) – Initial recovered count in meta-group.

  • weight (str) – {population, population x contacts, most_social}

infection_matrix(infections_per_contact_unit: float)[source]

Return the infection matrix.

outside_rate(outside_rate: float)[source]

Return the outside rate.

class simpar.groups.Population(meta_groups_dict: Dict[str, MetaGroup], meta_group_contact_matrix: ndarray)[source]

Bases: object

A population is a collection of meta-groups.

Initialize a population.

A population is defined by a dictionary of meta-groups: [meta_groups_dict]. Meta-group interactions are not assumed to be well-mixed. The matrix [meta_group_contact_matrix] indicates how metagroups interact with one another. This is encoded in the [infection_matrix] which is normalized to be in “contact units.”

Parameters:
  • meta_groups_dict (Dict[str, MetaGroup]) – Dictionary of meta-groups.

  • meta_group_contact_matrix (np.ndarray) – Interactions between meta-groups where entry (i,j) is the conditional probability that the exposed is in meta-group j, given that the source is in meta-group i.

static from_truncated_paretos_dictionary(d: Dict)[source]

Return a [Population] initialized from the given dictionary.

get_init_SIR(init_infections: ndarray, init_recovered: ndarray, weight: str = 'population')[source]

Return initial SIR vectors.

Given [init_infections] and [init_recovered] at the meta-group level, the [weight] parameter specifies how these counts should be distributed across the groups within each metagroup. The available options for [weight] are:

  • “population”: Each person is equally likely to be infected.

  • “population x contacts”: A person’s probability of being infected is proportional to their amount of contact.

  • “most social”: The initial infections are in the most social group.

Parameters:
  • init_infections (np.ndarray) – Initial infections per meta-group.

  • init_recovered (np.ndarray) – Initial recovered per meta-group.

  • weight (str) – {population, population x contacts, most_social}

infection_discovery_frac(infection_discovery_frac)[source]

Return the fraction of infections that are discovered.

infection_matrix(infections_per_contact_unit: float)[source]

Return the infection matrix.

meta_group_ids(meta_group)[source]

Return the group ids of the groups in the given meta-group.

outside_rate(outside_rates: ndarray)[source]

Return the outside rate.

recovered_discovery_frac(recovered_discovery_frac)[source]

Return the fraction of recovered that are discovered.

simpar.micro module

Methods to perform “microscopic” calculations that predict days infectious.

T | time between surveillance tests
X | beginning of period when an individual is infectious (and detectable)
D | delay to isolate after testing positive
R | total length of the infectious period
N | index of first surveillance to test
I | total time an individual is infectious AND free

========================================
Example timeline:
Individual tests positive on second test

|---|------|-----|----|-----|----|----|
0   X      T    T+D   2T    I    3T   R

N          0          1          2
========================================

We will use the above notation to discuss the calculations performed in this module. The infection begins between two surveillance tests at some point X which is uniformly distributed on [0,T]. Hence, the number of days between infection and the first surveillance test is T-X.

Note: We (pessimistically) assume a person is infectious the entire time they are PCR-detectable and that the infection level remains constant.

Using this notation, the number of days when the person is infectious is I = min(T-X+NT+D, R) where the first case represents isolating the individual before the end of their infectious period.

simpar.micro.days_infectious(days_between_tests: float, isolation_delay: float, sensitivity: float, max_infectious_days: float)[source]

Return the expected time someone is infectious and free.

Equivalently, Compute E[I]. Note that the number of surveillance tests N that are required for a person to test positive is a geometric random variable with probability given by [sensitivity]. So the person tests positive on test n (where the first test is n=0) with probability P(N=n) = [sensitivity] * np.pow(1-[sensitivity], n).

Parameters:
  • days_between_tests (float) – Number of days between surveillance tests. Provide np.inf for no surveillance testing.

  • isolation_delay (float) – Number of days to isolate after positive test.

  • sensitivity (float) – Sensitivity of surveillance test.

  • max_infectious_days (float) – Maximum infectious period.

simpar.micro.days_infectious_perfect_sensitivity(days_between_tests: float, isolation_delay: float, max_infectious_days: float)[source]

Return the expected time someone is infectious and free assuming perfect test sensitivity.

simpar.strategy module

Manage types of surveillance tests and strategies.

This module defines a [Test] class which maintains properties about a specific surveillance test. Furthermore, it defines an [ArrivalTestingRegime] and [TestingRegime] which are used to comprise a [Strategy]. This specifies how people are tested upon arrival and what testing regime(s) are used after they arrive and for what periods of time.

class simpar.strategy.ArrivalTestingRegime(pre_departure_test_type: List[Test], arrival_test_type: List[Test])[source]

Bases: object

This class maintains an arrival testing regime.

It offers methods to return the percentage of people that are discovered in pre-departure testing and the percentage of people that are discovered upon arrival. This allows for planning surrounding potential isolation of those who arrive and test positive.

Initialize an arrival testing regime.

Parameters:
  • pre_departure_test_type (List[Test]) – The type of test to be used for pre-departure testing per meta-group.

  • arrival_test_type (List[Test]) – The type of test to be used for arrival testing per meta-group.

static from_dictionary(d: Dict, tests: Dict[str, Test])[source]

Initialize a [ArrivalTestingRegime] instance.

The dictionary [d] should contain two keys: [pre_departure_test_type] and [arrival_test_type] which contain list of strings. These are interpreted as keys in the [tests] dictionary which provides the corresponding [Test] instance.

Parameters:
  • d (Dict) – Dictionary representing the arrival testing regime.

  • tests (Dict[str, Test]) – Dictionary of [Test] instances.

get_pct_discovered_in_arrival_test()[source]

Return the percentage of infections discovered upon arrival.

get_pct_discovered_in_pre_departure()[source]

Return the percentage of infections discovered in pre-departure.

class simpar.strategy.Strategy(name: str, period_lengths: List[int], testing_regimes: List[TestingRegime], transmission_multipliers: Optional[List[float]] = None, arrival_testing_regime: Optional[ArrivalTestingRegime] = None)[source]

Bases: object

This class maintains a testing strategy comprised of an [ArrivalTestingRegime] and a list of [TestingRegime]s.

If offers methods to return the initial number of infections, the initial number of recovered, and the arrival discovered (useful for understanding isolation capacity needs).

Initialize a testing strategy.

Parameters:
  • name (str) – Name for this strategy.

  • period_lengths (List[int]) – Length (in generations) of each period of the simulation.

  • testing_regimes (List[TestingRegime]) – Testing regime to be used in each period of the simulation.

  • transmission_multipliers (List[float]) – Transmission multiplier to be used in each period of the simulation. Defaults to 1.

  • arrival_testing_regime (ArrivalTestingRegime) – Arrival testing regime to be used. Defaults to None.

static from_dictionary(d: Dict, arrival_testing_regimes: Dict, testing_regimes: Dict)[source]

Initialize a [Strategy] instance.

The dictionary [d] should contain a key [testing_regimes] and may contain a key [arrival_testing_regime]. These should be keys in [arrival_testing_regimes] and [testing_regimes] respectively.

Parameters:
  • d (Dict) – Dictionary representing the strategy.

  • arrival_testing_regimes (Dict) – Dictionary of [ArrivalTestingRegimes] instances.

  • testing_regimes (Dict) – Dictionary of [TestingRegimes] instances.

get_arrival_discovered(recovered: ndarray, active_infections: ndarray, pct_recovered_discovered_arrival: ndarray)[source]

Return the infections discovered in arrival.

Parameters:
  • recovered (np.ndarray) – Recovered per meta-group.

  • active_infections (np.ndarray) – True number of active infections per meta-group.

  • pct_recovered_discovered_arrival (np.ndarray) – The percent of recovered (inactive) people who discover they are positive for the first time during arrival testing.

get_initial_infections(active_infections: ndarray)[source]

Return the initial infections when this strategy is used.

Parameters:

active_infections (np.ndarray) – True number of active infections per meta-group.

get_initial_recovered(recovered: ndarray, active_infections: ndarray)[source]

Return the initial recovered when this strategy is used.

Parameters:
  • recovered (np.ndarray) – Recovered per meta-group.

  • active_infections (np.ndarray) – True number of active infections per meta-group.

class simpar.strategy.Test(name: str, sensitivity: float, test_delay: float, compliance: float = 1)[source]

Bases: object

Initialize a test

Parameters:
  • name (str) – Name of the surveillance test.

  • sensitivity (float) – Probability of positive given infectious.

  • test_delay (float) – Delay in receiving results from test (in days).

  • compliance (float, optional) – Compliance with test. Defaults to 1.

static from_dictionary(name, d)[source]

Initialize a [Test] from a dictionary

class simpar.strategy.TestingRegime(test_type: List[Test], tests_per_week: ndarray)[source]

Bases: object

Initialize a testing regime.

Parameters:
  • test_type (List[Test]) – The test type to be used per meta-group.

  • tests_per_week (np.ndarray) – Test frequency per meta-group.

static from_dictionary(d: Dict, tests: Dict[str, Test])[source]

Initialize a [TestingRegime] instance.

The dictionary [d] should contain a key [test_type] which contain list of strings. These are interpreted as keys in the [tests] dictionary which provides the corresponding [Test] instance.

Parameters:
  • d (Dict) – Dictionary representing the testing regime.

  • tests (Dict[str, Test]) – Dictionary of [Test] instances.

get_days_infectious(max_infectious_days: float)[source]

Return the expected number of days infectious.

This value requires the context of the maximum infectious days.

Parameters:

max_infectious_days (float) – Max days someone is infected.

get_infection_discovery_frac(symptomatic_rate: float)[source]

Return the discovery rate among infected people.

This value requires the context of the fraction of people who experience symptoms (this becomes the infected discovery fraction when no surveillance testing is done).

Parameters:

symptomatic_rate (float) – Symptomatic rate.

get_recovered_discovery_frac(no_surveillance_test_rate: ndarray)[source]

Return the discovery rate among recovered people.

This value requires the context of the test rate when no surveillance testing is being done. E.g. testing done by cautious individuals.

Parameters:

no_surveillance_test_rate (np.ndarray) – Test rate per meta-group.

simpar.strategy.strategies_from_dictionary(d: Dict, tests: Dict)[source]

Return a dictionary of strategies.

Parameters:
  • d (Dict) – Dictionary maintaining strategies.

  • tests (Dict) – Dictionary of test types used in the strategies.

simpar.scenario module

Scenario for disease spread.

This module defines a [Scenario] class which maintains a scenario on which a testing strategy can be applied. By combining a scenario with a testing strategy, a simulation can be run allowing for the comparison of multiple testing strategies on a single scenario.

class simpar.scenario.Scenario(population: Population, max_T: int, generation_time: float, infections_per_contact_unit: ndarray, init_infections: ndarray, init_recovered: ndarray, outside_rate: ndarray, max_infectious_days: float, symptomatic_rate: float, no_surveillance_test_rate: ndarray, pct_recovered_discovered_arrival: ndarray, hospitalization_rates: ndarray, isolation_lengths: ndarray, isolation_fracs: ndarray, arrival_period: float, tests: Dict[str, Test])[source]

Bases: object

This class maintains a scenario on which a testing strategy can be applied.

A scenario is a list of parameters which describe the population of people, the environment, and the disease spreading. By combining a scenario with a testing strategy, a simulation can be run allowing for the comparison of multiple testing strategies on a single scenario.

Initialize a [Scenario] instance.

Parameters:
  • population (Population) – The population.

  • max_T (int) – The length of the simulation.

  • generation_time (float) – Number of days per generation of sim.

  • infections_per_contact_unit (np.ndarray) – Number of infections per contact unit across meta-groups.

  • init_infections (np.ndarray) – Number of initial infections across meta-groups.

  • init_recovered (np.ndarray) – Number of initial recovered across meta-groups.

  • outside_rate (np.ndarray) – The number of infections caused by outside infection in a generation time across meta-groups.

  • max_infectious_days (float) – Maximum period someone is infectious.

  • symptomatic_rate (float) – Symptomatic rate.

  • no_surveillance_test_rate (np.ndarray) – Rate at which people test under no surveillance testing across meta-groups.

  • pct_recovered_discovered_arrival (np.ndarray) – Percentage of the recovered population who discover they are positive (but no longer infectious) during arrival testing.

  • hospitalization_rates (np.ndarray) – Rate of hospitalizations among those who get infected across meta-groups.

  • isolation_lengths (np.ndarray) – List of isolation periods in days.

  • isolation_fracs (np.ndarray) – Combined with [isolation_lengths], indicates what fraction of people isolate for each length.

  • arrival_period (float) – The number of generations the arrival occurs over. Testing is assumed constant over these days.

  • tests (Dict[str, Test]) – Dictionary of available tests.

static from_dictionary(d: Dict)[source]

Initialize a [Scenario] instance from a dictionary.

simulate_strategy(strategy: Strategy)[source]

Return a simulation of the given strategy on this scenario.

simpar.trajectory module

Simulation trajectory manager.

Defines a [Trajectory] class which is comprised of a fully run [Sim] that was the result of applying a given [Strategy] to a [Scenario].

class simpar.trajectory.Trajectory(scenario: Scenario, strategy: Strategy, sim: Sim, color: str = 'black', name: Optional[str] = None)[source]

Bases: object

Manages all of the attributes of a simulation run.

This includes the underlying simulation [Sim] and the scenario [Scenario] and the strategy [Strategy] that was used. It also maintains a color and name for use when plotting trajectories.

Initialize a [Trajectory] instance.

Parameters:
  • scenario (Scenario) – Scenario that the simulation was run under.

  • strategy (Strategy) – Strategy that was used to run the simulation.

  • sim (sim) – Simulation which used the provided strategy.

  • color (str) – Color of the trajectory when plotting.

  • name (str) – Name of the trajectory when plotting.

simpar.metrics module

Trajectory metrics manager.

Contains all metric methods which take a Trajectory as input.

simpar.metrics.get_bucket(trajectory: Trajectory, bucket: str, meta_groups: Optional[List[str]] = None, aggregate: bool = True, cumulative: bool = False, normalize: bool = False)[source]

Return the given bucket vector.

Parameters:
  • trajectory (Trajectory) – Trajectory to compute metric for,.

  • bucket (str) – One of the simulation buckets: {S, I, R, D, H}.

  • meta_groups (List[str]) – Meta-groups to aggregate over. Default to all.

  • aggregate (bool) – Aggregate over the meta-groups if True.

  • cumulative (bool) – Return cumulative metric over time if True.

  • normalize (bool) – Normalize relative to total population.

simpar.metrics.get_hospitalizations(trajectory: Trajectory, meta_groups: Optional[List[str]] = None, aggregate: bool = True, cumulative: bool = False, normalize: bool = False)[source]

Return hospitalizations as computed from hospitalization rates.

Parameters:
  • trajectory (Trajectory) – Trajectory to compute metric for,.

  • meta_groups (List[str]) – Meta-groups to aggregate over. Default to all.

  • aggregate (bool) – Aggregate over the meta-groups if True.

  • cumulative (bool) – Return cumulative metric over time if True.

  • normalize (bool) – Normalize relative to total population.

simpar.metrics.get_total_discovered(trajectory: Trajectory, meta_groups: Optional[List[str]] = None, aggregate: bool = True, cumulative: bool = False, normalize: bool = False)[source]

Return the number of discovered individuals at each iteration.

This includes those discovered in arrival spread across the arrival period.

Parameters:
  • trajectory (Trajectory) – Trajectory object.

  • meta_groups (List[str]) – Limit to isolated in these metagroups.

  • aggregate (bool) – Aggregate over the meta-groups if True.

  • cumulative (bool) – Return cumulative metric over time if True.

  • normalize (bool) – Normalize relative to total population.

simpar.metrics.get_total_isolated(trajectory: Trajectory, meta_groups: Optional[List[str]] = None, aggregate: bool = True, cumulative: bool = False, normalize: bool = False)[source]

Return the number of isolated individuals at each generation.

This includes those isolating as a result of being discovered upon arrival.

Parameters:
  • trajectory (Trajectory) – Trajectory object.

  • meta_groups (List[str]) – Limit to isolated in these metagroups.

  • aggregate (bool) – Aggregate over the meta-groups if True.

  • cumulative (bool) – Return cumulative metric over time if True.

  • normalize (bool) – Normalize relative to total population.