Source code for rsvsim.defaults

'''
Set the defaults across each of the different files.

To change the default precision from 32 bit (default) to 64 bit, use::

    cv.options.set(precision=64)
'''

import numpy as np
import numba as nb
import sciris as sc
from .settings import options as cvo # To set options

# Specify all externally visible functions this file defines -- other things are available as e.g. cv.defaults.default_int
__all__ = ['default_float', 'default_int', 'get_default_colors', 'get_default_plots']

#%% Global defaults
dpw            = 7    # Days per week
dpm            = 30   # Days per month
dpy            = 365  # Days per year
wpy            = 52   # Weeks per year
mpy            = 12   # Months per year, to avoid magic numbers

#%% Specify what data types to use

result_float = np.float64 # Always use float64 for results, for simplicity
if cvo.precision == 32:
    default_float = np.float32
    default_int   = np.int32
    nbfloat       = nb.float32
    nbint         = nb.int32
elif cvo.precision == 64: # pragma: no cover
    default_float = np.float64
    default_int   = np.int64
    nbfloat       = nb.float64
    nbint         = nb.int64
else:
    raise NotImplementedError(f'Precision must be either 32 bit or 64 bit, not {cvo.precision}')


#%% Define all properties of people

class PeopleMeta(sc.prettyobj):
    ''' For storing all the keys relating to a person and people '''

    def __init__(self):

        # Set the properties of a person
        self.person = [
            'uid',              # Int
            'age',              # Int
            'weekage',          # Int
            'hhid',             # Int
            'scid',             # Int
            'sc_type',          # Float
            'sc_student',       # Int
            'gestation',        # Float (age of pregnancy, measured in weeks)
            'sex',              # Float
            'symp_prob',        # Float
            'severe_prob',      # Float
            'crit_prob',        # Float
            'death_prob',       # Float
            'rel_trans',        # Float
            'rel_sus',          # Float
            'rel_dur',          # Float
            'n_infections',     # Int
        ]

        # Set the states that a person can be in: these are all booleans per person -- used in people.py
        self.states = [
            'susceptible',
            'naive',
            'exposed',
            'infectious',
            'symptomatic',
            'severe',
            'critical',
            'tested',
            'diagnosed',
            'recovered',
            'known_dead',
            'dead',
            'vaccinated',
            'pregnant',
            'post_partum',
        ]

        # genotype states -- these are ints
        self.genotype_states = [
            'exposed_genotype',
            'infectious_genotype',
            'recovered_genotype',
        ]

        # genotype states -- these are ints, by genotype
        self.by_genotype_states = [
            'exposed_by_genotype',
            'infectious_by_genotype',
        ]

        # Immune states, by genotype
        self.imm_states = [
            'sus_imm',          # Float, by genotype
            't_imm_event',      # Float, time since nab-conferring event
            'peak_imm',         # Float, peak immunity level
        ]

        # Additional vaccination states
        self.vacc_states = [
            'vaccinations',     # Number of doses given per person
            'vaccine_source',   # index of vaccine that individual received
        ]

        # Set the dates various events took place: these are floats per person -- used in people.py
        self.dates = [f'date_{state}' for state in self.states] # Convert each state into a date
        self.dates.append('date_pos_test') # Store the date when a person tested which will come back positive
        self.dates.append('date_delivery')

        # Duration of different states: these are floats per person -- used in people.py
        self.durs = [
            'dur_exp2inf',
            'dur_inf2sym',
            'dur_sym2sev',
            'dur_sev2crit',
            'dur_disease',
            'dur_preg',
        ]

        self.all_states = self.person + self.states + self.genotype_states + self.by_genotype_states + self.imm_states + self.vacc_states + self.dates + self.durs

        # Validate
        self.state_types = ['person', 'states', 'genotype_states', 'by_genotype_states', 'imm_states',
                            'vacc_states', 'dates', 'durs', 'all_states']
        for state_type in self.state_types:
            states = getattr(self, state_type)
            n_states        = len(states)
            n_unique_states = len(set(states))
            if n_states != n_unique_states: # pragma: no cover
                errormsg = f'In {state_type}, only {n_unique_states} of {n_states} state names are unique'
                raise ValueError(errormsg)

        return



#%% Define other defaults

# A subset of the above states are used for results
result_stocks = {
    'susceptible': 'Number susceptible',
    'exposed':     'Number exposed',
    'infectious':  'Number infectious',
    'symptomatic': 'Number symptomatic',
    'severe':      'Number of severe cases',
    'critical':    'Number of critical cases',
    'recovered':   'Number recovered',
    'dead':        'Number dead',
    'diagnosed':   'Number of confirmed cases',
    'known_dead':  'Number of confirmed deaths',
    'vaccinated':  'Number of people vaccinated',
}

result_stocks_by_genotype = {
    'exposed_by_genotype':    'Number exposed by genotype',
    'infectious_by_genotype': 'Number infectious by genotype',
}

# The types of result that are counted as flows -- used in sim.py; value is the label suffix
result_flows = {
    'infections':   'infections',
    'reinfections': 'reinfections',
    'infectious':   'infectious',
    'symptomatic':  'symptomatic cases',
    'severe':       'severe cases',
    'critical':     'critical cases',
    'recoveries':   'recoveries',
    'deaths':       'deaths',
    'non_RSV_deaths': 'non-RSV deaths',
    'tests':        'tests',
    'diagnoses':    'diagnoses',
    'known_deaths': 'known deaths',
    'vaccinations': 'vaccinations',
    'vaccinated':   'vaccinated people'
}

result_flows_by_genotype = {
    'infections_by_genotype':  'infections by genotype',
    'symptomatic_by_genotype': 'symptomatic by genotype',
    'severe_by_genotype':      'severe by genotype',
    'infectious_by_genotype':  'infectious by genotype',
}

result_imm = {
    'pop_protection': 'Population average protective immunity'
}

# Define new and cumulative flows
new_result_flows = [f'new_{key}' for key in result_flows.keys()]
cum_result_flows = [f'cum_{key}' for key in result_flows.keys()]
new_result_flows_by_genotype = [f'new_{key}' for key in result_flows_by_genotype.keys()]
cum_result_flows_by_genotype = [f'cum_{key}' for key in result_flows_by_genotype.keys()]

# Parameters that can vary by genotype
genotype_pars = [
    'rel_imm_genotype',
    'rel_beta',
    'rel_symp_prob',
    'rel_severe_prob',
    'rel_crit_prob',
    'rel_death_prob',
]


# Default age data, based on Kenya 2020 census data -- used in population.py
default_age_data = np.array([
            [ 0,  4, 0.066175507],
            [ 5,  9, 0.06524423],
            [10, 14, 0.063143537],
            [15, 19, 0.056198401],
            [20, 24, 0.048710038],
            [25, 29, 0.040303676],
            [30, 34, 0.037057836],
            [35, 39, 0.031697672],
            [40, 44, 0.025336955],
            [45, 49, 0.019623219],
            [50, 54, 0.014544897],
            [55, 59, 0.010669093],
            [60, 64, 0.007640935],
            [65, 69, 0.005197587],
            [70, 74, 0.002994813],
            [75, 79, 0.001420907],
            [80, 84, 0.00067934],
            [85, 89, 0.000219876],
            [90, 99, 3.34565E-05],
            ])

# Default probability of dying by age data, based on Kenya 2019 WHO data (https://www.who.int/data/gho/data/indicators/indicator-details/GHO/gho-ghe-life-tables-by-country) -- used in people.py
default_mortality_data = dict(
    age_cutoffs=np.array([0, 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85]),
    life_exp=np.array([
            [0.036, 0.03],
            [0.012, 0.011],
            [0.006, 0.005],
            [0.005, 0.004],
            [0.008, 0.005],
            [0.01, 0.007],
            [0.012, 0.011],
            [0.016, 0.016],
            [0.025, 0.022],
            [0.038, 0.03],
            [0.052, 0.039],
            [0.071, 0.048],
            [0.095, 0.059],
            [0.13, 0.08],
            [0.18, 0.12],
            [0.26, 0.18],
            [0.35, 0.27],
            [0.49, 0.41],
            [1, 1],
            ])
)

# Default fertility rate (births per woman) based on age data, based on Kenya 2019 (https://knoema.com/atlas/Kenya/topics/Demographics/Fertility/Fertility-rates-at-age-15-19-years)
default_fertility_data = dict(
    age_cutoffs=np.array([20, 25, 30, 35, 40, 45]),
    fert_rate=np.array([0.17654, 0.17977, 0.12959, 0.08585, 0.03478, 0.02239])
)



[docs]def get_default_colors(): ''' Specify plot colors -- used in sim.py. NB, includes duplicates since stocks and flows are named differently. ''' c = sc.objdict() c.susceptible = '#4d771e' c.exposed = '#c78f65' c.exposed_by_genotype = '#c75649' c.infectious = '#e45226' c.infectious_by_genotype = c.infectious c.infections = '#b62413' c.reinfections = '#732e26' c.infections_by_genotype = '#b62413' c.tests = '#aaa8ff' c.diagnoses = '#5f5cd2' c.diagnosed = c.diagnoses c.vaccinations = c.diagnoses # TODO: new color c.vaccinated = c.diagnoses c.recoveries = '#9e1149' c.recovered = c.recoveries c.symptomatic = '#c1ad71' c.symptomatic_by_genotype= c.symptomatic c.severe = '#c1981d' c.severe_by_genotype = c.severe c.critical = '#b86113' c.deaths = '#000000' c.non_RSV_deaths = '#9e1149' c.dead = c.deaths c.known_dead = c.deaths c.known_deaths = c.deaths c.default = '#000000' c.pop_protection = '#9e1149' return c
# Define the 'overview plots', i.e. the most useful set of plots to explore different aspects of a simulation overview_plots = [ 'cum_infections', 'cum_severe', 'cum_critical', 'cum_deaths', 'cum_known_deaths', 'cum_diagnoses', 'new_infections', 'new_severe', 'new_critical', 'new_deaths', 'new_diagnoses', 'n_infectious', 'n_severe', 'n_critical', 'n_susceptible', 'new_tests', 'n_symptomatic', 'new_vaccinations', 'new_vaccinated', 'cum_vaccinated', 'cum_vaccinations', 'test_yield', 'r_eff', ] overview_genotype_plots = [ 'cum_infections_by_genotype', 'new_infections_by_genotype', 'n_infectious_by_genotype', 'cum_reinfections', 'new_reinfections', 'pop_protection', 'pop_symp_protection', ]
[docs]def get_default_plots(which='default', kind='sim', sim=None): ''' Specify which quantities to plot; used in sim.py. Args: which (str): either 'default' or 'overview' ''' # Default plots -- different for sims and scenarios if which in [None, 'default']: if 'sim' in kind: plots = sc.odict({ 'Total counts': [ 'cum_infections', 'n_infectious', 'cum_diagnoses', ], 'Daily counts': [ 'new_infections', 'new_diagnoses', ], 'Health outcomes': [ 'cum_severe', 'cum_critical', 'cum_deaths', 'cum_known_deaths', ], }) elif 'scen' in kind: # pragma: no cover plots = sc.odict({ 'Cumulative infections': [ 'cum_infections', ], 'New infections per day': [ 'new_infections', ], 'Cumulative deaths': [ 'cum_deaths', 'cum_known_deaths', ], }) else: errormsg = f'Expecting "sim" or "scens", not "{kind}"' raise ValueError(errormsg) # Show an overview elif which == 'overview': # pragma: no cover plots = sc.dcp(overview_plots) # Plot absolutely everything elif which.lower() == 'all': # pragma: no cover plots = sim.result_keys('all') # Show an overview plus genotypees elif 'overview' in which and 'genotype' in which: # pragma: no cover plots = sc.dcp(overview_plots) + sc.dcp(overview_genotype_plots) # Show default but with genotypees elif 'genotype' in which: # pragma: no cover plots = sc.odict({ 'Cumulative infections by genotype': [ 'cum_infections_by_genotype', ], 'New infections by genotype': [ 'new_infections_by_genotype', ], 'Diagnoses': [ 'cum_diagnoses', 'new_diagnoses', ], 'Health outcomes': [ 'cum_severe', 'cum_critical', 'cum_deaths', ], }) # Plot SEIR compartments elif which.lower() == 'seir': # pragma: no cover plots = [ 'n_susceptible', 'n_preinfectious', 'n_infectious', 'n_removed', ], else: # pragma: no cover errormsg = f'The choice which="{which}" is not supported: choices are "default", "overview", "all", "genotype", "overview-genotype", or "seir"' raise ValueError(errormsg) return plots