Source code for fpsim.defaults

"""
Define defaults for use throughout FPsim
"""

import numpy as np
import sciris as sc
import starsim as ss


#%% Global defaults
useSI          = True
mpy            = 12   # Months per year, to avoid magic numbers
eps            = 1e-9 # To avoid divide-by-zero
min_age        = 15   # Minimum age to be considered eligible to use contraceptive methods
max_age        = 99   # Maximum age (inclusive)
max_age_preg   = 50   # Maximum age to become pregnant
max_parity     = 20   # Maximum number of children to track - also applies to abortions, miscarriages, stillbirths
max_parity_spline = 20   # Used for parity splines


#%% Defaults when creating a new person
[docs] class State: def __init__(self, name, val=None, dtype=None, ncols=None): """ Initialize a state Args: name (str): name of state val (list, array, float, or str): value(s) to populate array with dtype (dtype): datatype. Inferred from val if not provided. ncols (int): number of cols, needed for 2d states like birth_ages (n_agents * n_births) """ self.name = name self.val = val self.dtype = dtype self.ncols = ncols @property def ndim(self): return 1 if self.ncols is None else 2
[docs] def new(self, n, vals=None): """ Define an empty array with the correct value and data type """ if vals is None: vals = self.val # Use default if none provided if isinstance(vals, np.ndarray): assert len(vals) == n arr = vals else: if self.dtype is None: dtype = object if isinstance(vals, str) else None else: dtype = self.dtype shape = n if self.ncols is None else (n, self.ncols) arr = np.full(shape=shape, fill_value=vals, dtype=dtype) return arr
# Parse locations
[docs] def get_location(location, printmsg=False): default_location = 'senegal' if not location: if printmsg: print('Location not supplied: using parameters from Senegal') location = default_location location = location.lower() # Ensure it's lowercase if location == 'test': if printmsg: print('Running test simulation using parameters from Senegal') location = default_location if location == 'default': if printmsg: print('Running default simulation using parameters from Senegal') location = default_location # Define valid locations valid_country_locs = ['senegal', 'kenya', 'ethiopia'] if location not in valid_country_locs: errormsg = f'Location "{location}" is not currently supported' raise NotImplementedError(errormsg) return location
# Defaults states and values of any new(born) agent unless initialized with data or other strategy # or updated during the course of a simulation. person_defaults = [ # Basic demographics State('uid', -1, int), State('age', 0, float), State('age_by_group', 0, float), State('sex', 0, bool), State('alive', 1, bool), # Contraception State('on_contra', 0, bool), # whether she's on contraception State('method', 0, int), # Which method to use. 0 used for those on no method State('ti_contra', 0, int), # time point at which to set method State('barrier', 0, int), State('ever_used_contra', 0, bool), # Ever been on contraception. 0 for never having used # Sexual and reproductive history State('parity', 0, int), State('pregnant', 0, bool), State('fertile', 0, bool), State('sexually_active', 0, bool), State('sexual_debut', 0, bool), State('sexual_debut_age', -1, float), State('fated_debut', -1, float), State('first_birth_age', -1, float), State('lactating', 0, bool), State('gestation', 0, int), State('preg_dur', 0, int), State('stillbirth', 0, int), State('miscarriage', 0, int), State('abortion', 0, int), State('pregnancies', 0, int), State('months_inactive', 0, int), State('postpartum', 0, bool), State('mothers', -1, int), State('short_interval', 0, int), State('secondary_birth', 0, int), State('postpartum_dur', 0, int), State('lam', 0, bool), State('breastfeed_dur', 0, int), State('breastfeed_dur_total', 0, int), # Fecundity State('remainder_months', 0, int), State('personal_fecundity', 0, int), # Empowerment - states will remain at these values if use_empowerment is False # NOTE: to use empowerment metrics, please refer to the kenya_empowerment repo # These states will be refactored into a separate module as part of the V3 release. State('paid_employment', 0, bool), State('decision_wages', 0, bool), State('decision_health', 0, bool), State('decision_purchase', 0, bool), State('buy_decision_major', 0, bool), # whether she has decision making ability over major purchases State('buy_decision_daily', 0, bool), # whether she has decision making over daily household purchases State('buy_decision_clothes', 0, bool), # whether she has decision making over clothing purchases State('decide_spending_partner', 0, bool), # whether she has decision makking over her partner's wages State('has_savings', 0, bool), # whether she has savings State('has_fin_knowl', 0, bool), # whether she knows where to get financial info State('has_fin_goals', 0, bool), # whether she has financial goals State('sexual_autonomy', 0, bool), # whether she has ability to refuse sex # Composite empowerment attributes State('financial_autonomy', 0, float), State('decision_making', 0, float), # Empowerment - fertility intent State('fertility_intent', 0, bool), State('categorical_intent', "cannot", "<U6"), State('intent_to_use', 0, bool), # for women not on contraception, whether she has intent to use contraception # Partnership information -- states will remain at these values if use_partnership is False State('partnered', 0, bool), State('partnership_age', -1, float), # Socioeconomic State('urban', 1, bool), State('wealthquintile', 3, int), # her current wealth quintile, an indicator of the economic status of her household, 1: poorest quintile; 5: wealthiest quintile # Education - states will remain at these values if use_education is False State('edu_objective', 0, float), State('edu_attainment', 0, float), State('edu_dropout', 0, bool), State('edu_interrupted', 0, bool), State('edu_completed', 0, bool), State('edu_started', 0, bool), State('child_inds', -1, int, ncols=max_parity), State('birth_ages', np.nan, float, ncols=max_parity), # Ages at time of live births State('stillborn_ages', np.nan, float, ncols=max_parity), # Ages at time of stillbirths State('miscarriage_ages', np.nan, float, ncols=max_parity), # Ages at time of miscarriages State('abortion_ages', np.nan, float, ncols=max_parity), # Ages at time of abortions # State('short_interval_ages', np.nan, float, ncols=max_parity) # Ages of agents at short birth interval ] person_defaults = ss.ndict(person_defaults) # Postpartum keys to months postpartum_map = { 'pp0to5': [0, 6], 'pp6to11': [6, 12], 'pp12to23': [12, 24] } # Age bins for tracking age-specific fertility rate age_bin_map = { '10-14': [10, 15], '15-19': [15, 20], '20-24': [20, 25], '25-29': [25, 30], '30-34': [30, 35], '35-39': [35, 40], '40-44': [40, 45], '45-49': [45, 50] } # Age and parity splines spline_ages = np.arange(max_age + 1) spline_preg_ages = np.arange(max_age_preg + 1) spline_parities = np.arange(max_parity_spline + 1) # Define allowable keys to select all (all ages, all methods, etc) none_all_keys = [None, 'all', ':', [None], ['all'], [':']] # Age bins for different method switching matrices -- can be overwritten by locations method_age_map = { '<18': [ 0, 18], '18-20': [18, 20], '20-25': [20, 25], '25-35': [25, 35], '>35': [35, max_age+1], # +1 since we're using < rather than <= } immutable_method_age_map = { '<18': [ 0, 18], '18-20': [18, 20], '20-25': [20, 25], '25-30': [25, 30], '30-35': [30, 35], '>35': [35, max_age+1], # +1 since we're using < rather than <= } method_youth_age_map = { '<16': [10, 16], '16-17': [16, 18], '18-19': [18, 20], '20-22': [20, 23], '23-25': [23, 26], '>25': [26, max_age+1] } array_results = sc.autolist( 't', 'pop_size_months', 'pregnancies', 'births', 'deaths', 'stillbirths', 'miscarriages', 'abortions', 'total_births', 'maternal_deaths', 'infant_deaths', 'cum_maternal_deaths', 'cum_infant_deaths', 'on_methods_mcpr', 'no_methods_mcpr', 'on_methods_cpr', 'no_methods_cpr', 'on_methods_acpr', 'no_methods_acpr', 'contra_access', 'new_users', 'mcpr', 'cpr', 'acpr', 'ever_used_contra', 'switchers', 'urban_women', 'pp0to5', 'pp6to11', 'pp12to23', 'parity0to1', 'parity2to3', 'parity4to5', 'parity6plus', 'wq1', 'wq2', 'wq3', 'wq4', 'wq5', 'nonpostpartum', 'total_women_fecund', 'method_failures', 'birthday_fraction', 'short_intervals', 'secondary_births', 'proportion_short_interval', # Education 'edu_objective', 'edu_attainment', # Empowerment and intent: all zero unless using an empowerment module 'perc_contra_intent', 'perc_fertil_intent', 'paid_employment', 'decision_wages', 'decide_spending_partner', "buy_decision_major", "buy_decision_daily", "buy_decision_clothes", "decision_health", "has_savings", "has_fin_knowl", "has_fin_goals", "financial_autonomy", "decision_making", ) for age_group in age_bin_map.keys(): array_results += 'total_births_' + age_group array_results += 'total_women_' + age_group list_results = sc.autolist( 'tfr_years', 'tfr_rates', 'pop_size', 'mcpr_by_year', 'cpr_by_year', 'contra_access_over_year', 'new_users_over_year', 'method_failures_over_year', 'infant_deaths_over_year', 'total_births_over_year', 'live_births_over_year', 'stillbirths_over_year', 'miscarriages_over_year', 'abortions_over_year', 'pregnancies_over_year', 'short_intervals_over_year', 'secondary_births_over_year', 'risky_pregs_over_year', 'maternal_deaths_over_year', 'proportion_short_interval_by_year', 'mmr', 'imr', 'birthday_fraction', 'method_usage', ) # Map between key names in results and annualised results, some of them are different to_annualize = { 'method_failures' :'method_failures', 'infant_deaths' :'infant_deaths', 'total_births' :'total_births', 'births' :'live_births', # X 'stillbirths' :'stillbirths', 'miscarriages' :'miscarriages', 'abortions' :'abortions', 'short_intervals' : 'short_intervals', 'secondary_births': 'secondary_births', 'maternal_deaths' : 'maternal_deaths', 'pregnancies' : 'pregnancies', 'contra_access' : 'contra_access', 'new_users' : 'new_users'} # People's states for which we will need circular buffers longitude_keys = [ 'on_contra', 'intent_to_use', 'buy_decision_major', 'buy_decision_clothes', 'buy_decision_daily', 'has_fin_knowl', 'has_fin_goals', 'financial_autonomy', 'has_fin_goals', 'paid_employment', 'has_savings', 'decision_wages', 'decide_spending_partner', 'decision_health' ]