Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decouple ANC logic from tclose #1027

Merged
merged 18 commits into from
Aug 15, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 71 additions & 32 deletions src/tlo/methods/care_of_women_during_pregnancy.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,7 @@ def schedule_admission(self, individual_id):
:param individual_id: individual_id
"""
df = self.sim.population.props
mni = self.sim.modules['PregnancySupervisor'].mother_and_newborn_info

# check correct women have been sent
if not df.at[individual_id, 'ac_to_be_admitted']:
Expand All @@ -648,36 +649,15 @@ def schedule_admission(self, individual_id):

logger.info(key='anc_interventions', data={'mother': individual_id, 'intervention': 'admission'})

mni[individual_id]['date_anc_admission'] = self.sim.date

inpatient = HSI_CareOfWomenDuringPregnancy_AntenatalWardInpatientCare(
self.sim.modules['CareOfWomenDuringPregnancy'], person_id=individual_id)

self.sim.modules['HealthSystem'].schedule_hsi_event(inpatient, priority=0,
topen=self.sim.date,
tclose=self.sim.date + DateOffset(days=1))

# Reset the variable to prevent future scheduling errors
df.at[individual_id, 'ac_to_be_admitted'] = False

def call_if_maternal_emergency_assessment_cant_run(self, hsi_event):
"""
This function is called if HSI_CareOfWomenDuringPregnancy_MaternalEmergencyAssessment is unable to run to ensure
women still experience risk of death associated with the complication they had sought treatment for (as risk of
death is applied following treatment within the HSI)
:param hsi_event: HSI event in which the function has been called:
"""
df = self.sim.population.props
individual_id = hsi_event.target
mni = self.sim.modules['PregnancySupervisor'].mother_and_newborn_info

if df.at[individual_id, 'is_pregnant'] and not df.at[individual_id, 'la_currently_in_labour']:
logger.debug(key='message', data=f'HSI_CareOfWomenDuringPregnancy_MaternalEmergencyAssessment: did not'
f' run for person {individual_id}')

self.sim.modules['PregnancySupervisor'].apply_risk_of_death_from_monthly_complications(individual_id)
if df.at[individual_id, 'is_alive']:
mni[individual_id]['delay_one_two'] = False
mni[individual_id]['delay_three'] = False

# ================================= INTERVENTIONS DELIVERED DURING ANC ============================================
# The following functions contain the interventions that are delivered as part of routine ANC contacts. Functions
# are called from within the ANC HSIs. Which interventions are called depends on the mothers gestation and the
Expand Down Expand Up @@ -1388,6 +1368,31 @@ def ectopic_pregnancy_treatment_doesnt_run(self, hsi_event):
self.sim.schedule_event(EctopicPregnancyRuptureEvent(
self.sim.modules['PregnancySupervisor'], individual_id), self.sim.date + DateOffset(days=7))

def inpatient_care_doesnt_run(self, hsi_event):
"""
This function is called within HSI_CareOfWomenDuringPregnancy_AntenatalWardInpatientCare if the event cannot
run/the intervention cannot be delivered.
:param hsi_event: HSI event in which the function has been called
"""
individual_id = hsi_event.target
df = self.sim.population.props
mni = self.sim.modules['PregnancySupervisor'].mother_and_newborn_info

if df.at[individual_id, 'is_pregnant'] and not df.at[individual_id, 'la_currently_in_labour']:
logger.debug(key='message', data=f'HSI_CareOfWomenDuringPregnancy_MaternalEmergencyAssessment: did not'
f' run for person {individual_id}')

self.sim.modules['PregnancySupervisor'].apply_risk_of_death_from_monthly_complications(individual_id)

if df.at[individual_id, 'is_alive']:
mni[individual_id]['delay_one_two'] = False
mni[individual_id]['delay_three'] = False
mni[individual_id]['date_preg_emergency'] = pd.NaT
mni[individual_id]['date_anc_admission'] = pd.NaT

if df.at[individual_id, 'ac_to_be_admitted']:
df.at[individual_id, 'ac_to_be_admitted'] = False

def calculate_beddays(self, individual_id):
"""
This function is called by HSI_CareOfWomenDuringPregnancy_AntenatalWardInpatientCare to calculate the number of
Expand Down Expand Up @@ -2176,11 +2181,27 @@ def apply(self, person_id, squeeze_factor):
mother = df.loc[person_id]
mni = self.sim.modules['PregnancySupervisor'].mother_and_newborn_info

if not mother.is_alive:
if not mother.is_alive or not mother.is_pregnant or mother.la_currently_in_labour or mother.hs_is_inpatient:
tbhallett marked this conversation as resolved.
Show resolved Hide resolved
return

if not (mother.is_pregnant and not mother.la_currently_in_labour and not mother.hs_is_inpatient):
return
if pd.isnull(mni[person_id]['date_preg_emergency']) and pd.isnull(mni[person_id]['date_anc_admission']):
logger.info(key='error', data='Individual at AN inpatient HSI without topen')

# If more than 2 days have passed, keep expected footprint but assume no effect
if df.at[person_id, 'ac_to_be_admitted']:
if (self.sim.date - mni[person_id]['date_anc_admission']).days > 2:
self.module.inpatient_care_doesnt_run(person_id)
return

elif not pd.isnull(mni[person_id]['date_preg_emergency']):
if (self.sim.date - mni[person_id]['date_preg_emergency']).days > 2:
self.module.inpatient_care_doesnt_run(person_id)
return

# Reset mni/admission info
mni[person_id]['date_preg_emergency'] = pd.NaT
mni[person_id]['date_anc_admission'] = pd.NaT
df.at[person_id, 'ac_to_be_admitted'] = False

# check if she will experience delayed care
pregnancy_helper_functions.check_if_delayed_care_delivery(self.module, squeeze_factor, person_id, hsi_type='an')
Expand Down Expand Up @@ -2401,13 +2422,14 @@ def apply(self, person_id, squeeze_factor):
mni[person_id]['delay_one_two'] = False
mni[person_id]['delay_three'] = False

def never_ran(self):
self.module.inpatient_care_doesnt_run(self)

def did_not_run(self):
logger.debug(key='message', data='HSI_CareOfWomenDuringPregnancy_AntenatalWardInpatientCare: did not run')
return False
pass

def not_available(self):
logger.debug(key='message', data='HSI_CareOfWomenDuringPregnancy_AntenatalWardInpatientCare: cannot not run'
' with this configuration')
self.module.inpatient_care_doesnt_run(self)


class HSI_CareOfWomenDuringPregnancy_AntenatalOutpatientManagementOfAnaemia(HSI_Event, IndividualScopeEventMixin):
Expand All @@ -2430,6 +2452,7 @@ def __init__(self, module, person_id):
def apply(self, person_id, squeeze_factor):
df = self.sim.population.props
mother = df.loc[person_id]
mni = self.sim.modules['PregnancySupervisor'].mother_and_newborn_info

if not mother.is_alive or not mother.is_pregnant:
return
Expand All @@ -2442,6 +2465,8 @@ def apply(self, person_id, squeeze_factor):

# If she is determined to still be anaemic she is admitted for additional treatment via the inpatient event
if fbc_result in ('mild', 'moderate', 'severe'):
df.at[person_id, 'ac_to_be_admitted'] = True
mni[person_id]['date_anc_admission'] = self.sim.date

admission = HSI_CareOfWomenDuringPregnancy_AntenatalWardInpatientCare(
self.sim.modules['CareOfWomenDuringPregnancy'], person_id=person_id)
Expand Down Expand Up @@ -2571,6 +2596,11 @@ def apply(self, person_id, squeeze_factor):
'other', first=True):
return

# If more than 2 days have passed, keep expected footprint but assume no effect
mni = self.sim.modules['PregnancySupervisor'].mother_and_newborn_info
if (self.sim.date - mni[person_id]['abortion_onset']).days > 2:
return

# Determine if there will be a delay due to high squeeze
pregnancy_helper_functions.check_if_delayed_care_delivery(self.module, squeeze_factor, person_id,
hsi_type='an')
Expand Down Expand Up @@ -2652,10 +2682,20 @@ def __init__(self, module, person_id):
def apply(self, person_id, squeeze_factor):
df = self.sim.population.props
mother = df.loc[person_id]
mni = self.sim.modules['PregnancySupervisor'].mother_and_newborn_info

if not mother.is_alive or (mother.ps_ectopic_pregnancy == 'none'):
return

if df.at[person_id, 'ps_ectopic_pregnancy'] == 'not_ruptured':
if (self.sim.date - mni[person_id]['ectopic_onset']).days > 2:
self.module.ectopic_pregnancy_treatment_doesnt_run(self)
return

if df.at[person_id, 'ps_ectopic_pregnancy'] == 'ruptured':
if (self.sim.date - mni[person_id]['ectopic_rupture_onset']).days > 2:
return

# We define the required consumables and check their availability
avail = pregnancy_helper_functions.return_cons_avail(
self.module, self, self.module.item_codes_preg_consumables, core='ectopic_pregnancy_core',
Expand All @@ -2682,8 +2722,7 @@ def never_ran(self):
self.module.ectopic_pregnancy_treatment_doesnt_run(self)

def did_not_run(self):
self.module.ectopic_pregnancy_treatment_doesnt_run(self)
return False
pass

def not_available(self):
self.module.ectopic_pregnancy_treatment_doesnt_run(self)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

never called not_available `: delete?

Expand Down
53 changes: 46 additions & 7 deletions src/tlo/methods/labour.py
Original file line number Diff line number Diff line change
Expand Up @@ -2278,7 +2278,12 @@ def run_if_receives_postnatal_check_cant_run(self, hsi_event):
:param hsi_event: HSI event in which the function has been called:
"""
person_id = hsi_event.target
mni = self.sim.modules['PregnancySupervisor'].mother_and_newborn_info

logger.debug(key='message', data=f'HSI_Labour_ReceivesPostnatalCheck will not run for {person_id}')
if person_id in mni:
mni[person_id]['pnc_date'] = pd.NaT

self.apply_risk_of_early_postpartum_death(person_id)

def run_if_receives_comprehensive_emergency_obstetric_care_cant_run(self, hsi_event):
Expand All @@ -2290,12 +2295,17 @@ def run_if_receives_comprehensive_emergency_obstetric_care_cant_run(self, hsi_ev
:param hsi_event: HSI event in which the function has been called:
"""
person_id = hsi_event.target
mni = self.sim.modules['PregnancySupervisor'].mother_and_newborn_info

logger.debug(key='message', data=f'HSI_Labour_ReceivesComprehensiveEmergencyObstetricCare will not run for'
f' {person_id}')

# For women referred to this event after the postnatal SBA HSI we apply risk of death (as if should have been
# applied in this event if it ran)
if hsi_event.timing == 'postpartum':
if person_id in mni:
mni[person_id]['pnc_date'] = pd.NaT

self.apply_risk_of_early_postpartum_death(person_id)


Expand Down Expand Up @@ -2798,6 +2808,7 @@ def apply(self, mother_id):

if timing == '<48' or has_comps:
mni[mother_id]['will_receive_pnc'] = 'early'
mni[mother_id]['pnc_date'] = self.sim.date

early_event = HSI_Labour_ReceivesPostnatalCheck(
module=self.module, person_id=mother_id)
Expand Down Expand Up @@ -2857,6 +2868,10 @@ def apply(self, person_id, squeeze_factor):
if not df.at[person_id, 'is_alive']:
return

# If more than 2 days have passed, keep expected footprint but assume no effect
if (self.sim.date - df.at[person_id, 'la_due_date_current_pregnancy']).days > 2:
return

# First we capture women who have presented to this event during labour at home. Currently we just set these
# women to be delivering at a health centre (this will need to be randomised to match any available data)
if mni[person_id]['delivery_setting'] == 'home_birth' and mni[person_id]['sought_care_for_complication']:
Expand Down Expand Up @@ -3001,8 +3016,7 @@ def never_ran(self):
self.module.run_if_receives_skilled_birth_attendance_cant_run(self)

def did_not_run(self):
self.module.run_if_receives_skilled_birth_attendance_cant_run(self)
return False
pass

def not_available(self):
self.module.run_if_receives_skilled_birth_attendance_cant_run(self)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't see how not_available is ever called.

Expand Down Expand Up @@ -3032,6 +3046,10 @@ def apply(self, person_id, squeeze_factor):
if not df.at[person_id, 'is_alive'] or pd.isnull(df.at[person_id, 'la_date_most_recent_delivery']):
return None

if person_id in mni:
if pd.isnull(mni[person_id]['pnc_date']):
return None

# Ensure that women who were scheduled to receive early PNC have received care prior to passing through
# PostnatalWeekOneMaternalEvent
if (mni[person_id]['will_receive_pnc'] == 'early') and not mni[person_id]['passed_through_week_one']:
Expand All @@ -3048,9 +3066,17 @@ def apply(self, person_id, squeeze_factor):
if not df.at[person_id, 'la_pn_checks_maternal'] == 0:
logger.info(key='error', data=f'Mother {person_id} attended late PNC twice')

if pd.isnull(mni[person_id]['pnc_date']) and (df.at[person_id, 'la_pn_checks_maternal'] == 0):
logger.info(key='error', data='Individual at PNC HSI without topen')

# Run checks
self.module.postpartum_characteristics_checker(person_id)

if (self.sim.date - mni[person_id]['pnc_date']).days > 2:
mni[person_id]['pnc_date'] = pd.NaT
self.module.apply_risk_of_early_postpartum_death(person_id)
return

# log the PNC visit
logger.info(key='postnatal_check', data={'person_id': person_id,
'delivery_setting': mni[person_id]['delivery_setting'],
Expand Down Expand Up @@ -3109,6 +3135,7 @@ def apply(self, person_id, squeeze_factor):

# ====================================== APPLY RISK OF DEATH===================================================
if not mni[person_id]['referred_for_surgery'] and not mni[person_id]['referred_for_blood']:
mni[person_id]['pnc_date'] = pd.NaT
self.module.apply_risk_of_early_postpartum_death(person_id)

return self.EXPECTED_APPT_FOOTPRINT
Expand All @@ -3117,8 +3144,7 @@ def never_ran(self):
self.module.run_if_receives_postnatal_check_cant_run(self)

def did_not_run(self):
self.module.run_if_receives_postnatal_check_cant_run(self)
return False
pass

def not_available(self):
self.module.run_if_receives_postnatal_check_cant_run(self)
Expand Down Expand Up @@ -3155,6 +3181,20 @@ def apply(self, person_id, squeeze_factor):
mni = self.sim.modules['PregnancySupervisor'].mother_and_newborn_info
params = self.module.current_parameters

# If more than 2 days have passed, keep expected footprint but assume no effect
if (self.timing == 'intrapartum') and \
(self.sim.date - df.at[person_id, 'la_due_date_current_pregnancy']).days > 2:
return

if self.timing == 'postpartum':
if pd.isnull(mni[person_id]['pnc_date']) and (df.at[person_id, 'la_pn_checks_maternal'] == 0):
logger.info(key='error', data='Individual at PNC HSI (comp) without topen')

if (self.sim.date - mni[person_id]['pnc_date']).days > 2:
mni[person_id]['pnc_date'] = pd.NaT
self.module.apply_risk_of_early_postpartum_death(person_id)
return

# If the squeeze factor is too high we assume delay in receiving interventions occurs (increasing risk
# of death if complications occur)
pregnancy_helper_functions.check_if_delayed_care_delivery(self.module, squeeze_factor, person_id,
Expand Down Expand Up @@ -3232,6 +3272,7 @@ def apply(self, person_id, squeeze_factor):
# Women who have passed through the postpartum SBA HSI have not yet had their risk of death calculated because
# they required interventions delivered via this event. We now determine if these women will survive
if self.timing == 'postpartum':
mni[person_id]['pnc_date'] = pd.NaT
self.module.apply_risk_of_early_postpartum_death(person_id)

# Schedule HSI that captures inpatient days
Expand All @@ -3257,8 +3298,7 @@ def never_ran(self):
self.module.run_if_receives_comprehensive_emergency_obstetric_care_cant_run(self)

def did_not_run(self):
self.module.run_if_receives_comprehensive_emergency_obstetric_care_cant_run(self)
return False
pass

def not_available(self):
self.module.run_if_receives_comprehensive_emergency_obstetric_care_cant_run(self)
Expand Down Expand Up @@ -3286,7 +3326,6 @@ def apply(self, person_id, squeeze_factor):

def did_not_run(self):
logger.debug(key='message', data='HSI_Labour_PostnatalWardInpatientCare: did not run')
return False

def not_available(self):
logger.debug(key='message', data='HSI_Labour_PostnatalWardInpatientCare: cannot not run with '
Expand Down
Loading