55
66import json
77from pathlib import Path
8- from typing import Optional
8+ from typing import List , Optional
99
1010import pandas as pd
1111
@@ -85,8 +85,10 @@ class SimplifiedBirths(Module):
8585 categories = ['none' , 'non_exclusive' , 'exclusive' ]),
8686 }
8787
88- def __init__ (self , name = None ):
88+ def __init__ (self , name = None , force_one_birth_for_one_death : bool = False ):
8989 super ().__init__ (name )
90+ # Whether to use the _really_ simplified mode, whereby number of births is just equal to number of deaths
91+ self .force_one_birth_for_one_death = force_one_birth_for_one_death
9092 self .asfr = dict ()
9193
9294 # Define defaults for properties:
@@ -162,8 +164,10 @@ def __init__(self, module):
162164 super ().__init__ (module , frequency = DateOffset (months = self .months_between_polls ))
163165 self .asfr = get_medium_variant_asfr_from_wpp_resourcefile (
164166 dat = self .module .parameters ['age_specific_fertility_rates' ], months_exposure = self .months_between_polls )
167+ self .date_of_last_poll = self .sim .date
165168
166169 def apply (self , population ):
170+
167171 # Set new pregnancies:
168172 self .set_new_pregnancies ()
169173
@@ -174,26 +178,54 @@ def apply(self, population):
174178 self .update_breastfed_status ()
175179
176180 def set_new_pregnancies (self ):
177- """Making women pregnant. Rate of doing so is based on age-specific fertility rates under assumption that every
178- pregnancy results in a birth."""
181+ """Making women pregnant."""
179182
180- df = self .sim .population .props # get the population dataframe
183+ def _make_pregnant (ids : List [int ], df : pd .DataFrame , months_between_pregnancy_and_delivery : int ) -> None :
184+ """Enact the change to make the women pregnant"""
185+ # updating properties for women who will get pregnant
186+ df .loc [ids , 'is_pregnant' ] = True
187+ df .loc [ids , 'date_of_last_pregnancy' ] = self .sim .date
188+ df .loc [ids , 'si_date_of_last_delivery' ] = \
189+ self .sim .date + pd .DateOffset (months = months_between_pregnancy_and_delivery )
190+
191+ def _choose_women_to_make_pregnant (one_birth_for_one_death : bool , df : pd .DataFrame ) -> List [int ]:
192+ """Choose women to make pregnant, depending on mode."""
193+
194+ if one_birth_for_one_death :
195+ # Rate of pregnancy matches number of deaths: simple assumption and induces stable population size
196+ # Non-pregnant women aged [15, 35) are selected randomly for pregnancy:
197+
198+ eligible_for_pregnancy = df .loc [
199+ (df .sex == 'F' ) & df .is_alive & ~ df .is_pregnant & df .age_years .between (15 , 35 , inclusive = 'left' )
200+ ]
201+
202+ num_of_deaths_since_last_poll = len (
203+ df .loc [df .date_of_death .between (self .date_of_last_poll , self .sim .date , inclusive = 'left' )])
181204
182- # find probability of becoming pregnant (using asfr for the year, limiting to alive, non-pregnant females)
183- prob_preg = df .loc [
184- (df .sex == 'F' ) & df .is_alive & ~ df .is_pregnant
185- ]['age_range' ].map (self .asfr [self .sim .date .year ]).fillna (0 )
186-
187- # determine which woman will get pregnant
188- pregnant_women_ids = prob_preg .index [
189- (self .module .rng .random_sample (size = len (prob_preg )) < prob_preg )
190- ]
191-
192- # updating properties for women who will get pregnant
193- df .loc [pregnant_women_ids , 'is_pregnant' ] = True
194- df .loc [pregnant_women_ids , 'date_of_last_pregnancy' ] = self .sim .date
195- df .loc [pregnant_women_ids , 'si_date_of_last_delivery' ] = \
196- self .sim .date + pd .DateOffset (months = self .module .parameters ['months_between_pregnancy_and_delivery' ])
205+ return self .module .rng .choice (
206+ eligible_for_pregnancy .index , size = num_of_deaths_since_last_poll , replace = False , p = None )
207+
208+ else :
209+ # Rate of pregnancy is based on age-specific fertility rates under
210+ # assumption that every pregnancy results in a birth.
211+
212+ # find probability of becoming pregnant
213+ # (using asfr for the year, limiting to alive, non-pregnant females)
214+ prob_preg = df .loc [
215+ (df .sex == 'F' ) & df .is_alive & ~ df .is_pregnant
216+ ]['age_range' ].map (self .asfr [self .sim .date .year ]).fillna (0 )
217+
218+ # determine which woman will get pregnant:
219+ return prob_preg .index [
220+ (self .module .rng .random_sample (size = len (prob_preg )) < prob_preg )
221+ ]
222+
223+ df = self .sim .population .props # get the population dataframe
224+ women_to_make_pregnant = _choose_women_to_make_pregnant (self .module .force_one_birth_for_one_death , df )
225+ _make_pregnant (ids = women_to_make_pregnant ,
226+ df = df ,
227+ months_between_pregnancy_and_delivery = self .module .parameters ['months_between_pregnancy_and_delivery' ])
228+ self .date_of_last_poll = self .sim .date
197229
198230 def do_deliveries (self ):
199231 """Checks to see if the date-of-delivery for pregnant women has been reached and implement births where
0 commit comments