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

Fixing recurrence of HSIs in RTI #1408

Merged
merged 6 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
4 changes: 2 additions & 2 deletions resources/ResourceFile_RTI.xlsx
tbhallett marked this conversation as resolved.
Show resolved Hide resolved
Git LFS file not shown
130 changes: 86 additions & 44 deletions src/tlo/methods/rti.py
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,10 @@ def __init__(self, name=None, resourcefilepath=None):
Types.INT,
"A cut-off score above which an injuries will be considered severe enough to cause mortality in those who"
"have not sought care."
),
'maximum_number_of_times_HSI_events_should_run': Parameter(
Types.INT,
"limit on the number of times an HSI event can run"
)

}
Expand Down Expand Up @@ -1526,6 +1530,7 @@ def initialise_simulation(self, sim):
# Begin logging the RTI events
sim.schedule_event(RTI_Logging_Event(self), sim.date + DateOffset(months=1))


def rti_do_when_diagnosed(self, person_id):
"""
This function is called by the generic first appointments when an injured person has been diagnosed
Expand Down Expand Up @@ -3825,9 +3830,12 @@ def __init__(self, module, person_id):
self.TREATMENT_ID = 'Rti_ShockTreatment'
self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({'AccidentsandEmerg': 1})
self.ACCEPTED_FACILITY_LEVEL = '1b'
self._number_of_times_this_event_has_run = 0
self._maximum_number_times_event_should_run = self.module.parameters['maximum_number_of_times_HSI_events_should_run']
tbhallett marked this conversation as resolved.
Show resolved Hide resolved

def apply(self, person_id, squeeze_factor):
df = self.sim.population.props
self._number_of_times_this_event_has_run += 1
# determine if this is a child
if df.loc[person_id, 'age_years'] < 15:
is_child = True
Expand All @@ -3845,27 +3853,26 @@ def apply(self, person_id, squeeze_factor):
get_item_code('Blood, one unit'): 2,
get_item_code("Oxygen, 1000 liters, primarily with oxygen cylinders"): 23_040
}
is_cons_available = self.get_consumables(
self.module.item_codes_for_consumables_required['shock_treatment_child']
)
is_cons_available = self.get_consumables(item_codes=
self.module.item_codes_for_consumables_required['shock_treatment_child'])
else:
self.module.item_codes_for_consumables_required['shock_treatment_adult'] = {
get_item_code("ringer's lactate (Hartmann's solution), 1000 ml_12_IDA"): 2000,
get_item_code('Cannula iv (winged with injection pot) 18_each_CMST'): 1,
get_item_code('Blood, one unit'): 2,
get_item_code("Oxygen, 1000 liters, primarily with oxygen cylinders"): 23_040
}
is_cons_available = self.get_consumables(
self.module.item_codes_for_consumables_required['shock_treatment_adult']
)
is_cons_available = self.get_consumables(item_codes=
self.module.item_codes_for_consumables_required['shock_treatment_adult'])

if is_cons_available:
logger.debug(key='rti_general_message',
data=f"Hypovolemic shock treatment available for person {person_id}")
df.at[person_id, 'rt_in_shock'] = False
self.add_equipment({'Infusion pump', 'Drip stand', 'Oxygen cylinder, with regulator', 'Nasal Prongs'})
else:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
if self._number_of_times_this_event_has_run < self._maximum_number_times_event_should_run:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
return self.make_appt_footprint({})
tbhallett marked this conversation as resolved.
Show resolved Hide resolved

def did_not_run(self):
Expand Down Expand Up @@ -3918,11 +3925,15 @@ def __init__(self, module, person_id):
self.TREATMENT_ID = 'Rti_FractureCast'
self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({'AccidentsandEmerg': 1})
self.ACCEPTED_FACILITY_LEVEL = '1b'
self._number_of_times_this_event_has_run = 0
self._maximum_number_times_event_should_run = self.module.parameters[
'maximum_number_of_times_HSI_events_should_run']

def apply(self, person_id, squeeze_factor):
# Get the population and health system
df = self.sim.population.props
p = df.loc[person_id]
self._number_of_times_this_event_has_run += 1
# if the person isn't alive return a blank footprint
if not df.at[person_id, 'is_alive']:
return self.make_appt_footprint({})
Expand Down Expand Up @@ -4017,12 +4028,13 @@ def apply(self, person_id, squeeze_factor):
df.loc[person_id, 'rt_injuries_to_cast'].clear()
df.loc[person_id, 'rt_date_death_no_med'] = pd.NaT
else:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
if pd.isnull(df.loc[person_id, 'rt_date_death_no_med']):
df.loc[person_id, 'rt_date_death_no_med'] = self.sim.date + DateOffset(days=7)
logger.debug(key='rti_general_message',
data=f"Person {person_id} has {fracturecastcounts + slingcounts} fractures without treatment"
)
if self._number_of_times_this_event_has_run < self._maximum_number_times_event_should_run:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
if pd.isnull(df.loc[person_id, 'rt_date_death_no_med']):
df.loc[person_id, 'rt_date_death_no_med'] = self.sim.date + DateOffset(days=7)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this needs to be un-indented, so that it's not inside the clause to do with the number of times the HSI has run. i.e. this need to happen, irrespective of whether or not we're rescheduling the HSI

tbhallett marked this conversation as resolved.
Show resolved Hide resolved
logger.debug(key='rti_general_message',
data=f"Person {person_id} has {fracturecastcounts + slingcounts}"
f" fractures without treatment")
return self.make_appt_footprint({})

def did_not_run(self):
Expand Down Expand Up @@ -4057,9 +4069,13 @@ def __init__(self, module, person_id):
self.TREATMENT_ID = 'Rti_OpenFractureTreatment'
self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({'MinorSurg': 1})
self.ACCEPTED_FACILITY_LEVEL = '1b'
self._number_of_times_this_event_has_run = 0
self._maximum_number_times_event_should_run = self.module.parameters[
'maximum_number_of_times_HSI_events_should_run']

def apply(self, person_id, squeeze_factor):
df = self.sim.population.props
self._number_of_times_this_event_has_run += 1
if not df.at[person_id, 'is_alive']:
return self.make_appt_footprint({})
road_traffic_injuries = self.sim.modules['RTI']
Expand Down Expand Up @@ -4131,12 +4147,13 @@ def apply(self, person_id, squeeze_factor):
if code[0] in df.loc[person_id, 'rt_injuries_for_open_fracture_treatment']:
df.loc[person_id, 'rt_injuries_for_open_fracture_treatment'].remove(code[0])
else:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
if pd.isnull(df.loc[person_id, 'rt_date_death_no_med']):
df.loc[person_id, 'rt_date_death_no_med'] = self.sim.date + DateOffset(days=7)
logger.debug(key='rti_general_message',
data=f"Person {person_id}'s has {open_fracture_counts} open fractures without treatment",
)
if self._number_of_times_this_event_has_run < self._maximum_number_times_event_should_run:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
if pd.isnull(df.loc[person_id, 'rt_date_death_no_med']):
df.loc[person_id, 'rt_date_death_no_med'] = self.sim.date + DateOffset(days=7)
logger.debug(key='rti_general_message',
data=f"Person {person_id}'s has {open_fracture_counts} open fractures without treatment",
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

as per the comment above, I think this need to be outside of the new clause we're introducing about the rescheduling (or not) the HSI event.

tbhallett marked this conversation as resolved.
Show resolved Hide resolved

def did_not_run(self):
person_id = self.target
Expand Down Expand Up @@ -4174,10 +4191,15 @@ def __init__(self, module, person_id):
self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({
('Under5OPD' if self.sim.population.props.at[person_id, "age_years"] < 5 else 'Over5OPD'): 1})
self.ACCEPTED_FACILITY_LEVEL = '1b'
self._number_of_times_this_event_has_run = 0
self._maximum_number_times_event_should_run = self.module.parameters[
'maximum_number_of_times_HSI_events_should_run']

def apply(self, person_id, squeeze_factor):
get_item_code = self.sim.modules['HealthSystem'].get_item_code_from_item_name
df = self.sim.population.props
self._number_of_times_this_event_has_run += 1

if not df.at[person_id, 'is_alive']:
return self.make_appt_footprint({})
road_traffic_injuries = self.sim.modules['RTI']
Expand Down Expand Up @@ -4222,11 +4244,12 @@ def apply(self, person_id, squeeze_factor):
assert df.loc[person_id, date_to_remove_daly_column] > self.sim.date
df.loc[person_id, 'rt_date_death_no_med'] = pd.NaT
else:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
if pd.isnull(df.loc[person_id, 'rt_date_death_no_med']):
df.loc[person_id, 'rt_date_death_no_med'] = self.sim.date + DateOffset(days=7)
logger.debug(key='rti_general_message',
data="This facility has no treatment for open wounds available.")
if self._number_of_times_this_event_has_run < self._maximum_number_times_event_should_run:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
if pd.isnull(df.loc[person_id, 'rt_date_death_no_med']):
df.loc[person_id, 'rt_date_death_no_med'] = self.sim.date + DateOffset(days=7)
Copy link
Collaborator

Choose a reason for hiding this comment

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

same comment as above, about moving this outside the new clause

Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if self._number_of_times_this_event_has_run < self._maximum_number_times_event_should_run:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
if pd.isnull(df.loc[person_id, 'rt_date_death_no_med']):
df.loc[person_id, 'rt_date_death_no_med'] = self.sim.date + DateOffset(days=7)
if self._number_of_times_this_event_has_run < self._maximum_number_times_event_should_run:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
if pd.isnull(df.loc[person_id, 'rt_date_death_no_med']):
df.loc[person_id, 'rt_date_death_no_med'] = self.sim.date + DateOffset(days=7)

logger.debug(key='rti_general_message',
data="This facility has no treatment for open wounds available.")
return self.make_appt_footprint({})

def did_not_run(self):
Expand Down Expand Up @@ -4269,11 +4292,15 @@ def __init__(self, module, person_id):

p = self.module.parameters
self.prob_mild_burns = p['prob_mild_burns']
self._number_of_times_this_event_has_run = 0
self._maximum_number_times_event_should_run = p['maximum_number_of_times_HSI_events_should_run']


def apply(self, person_id, squeeze_factor):
get_item_code = self.sim.modules['HealthSystem'].get_item_code_from_item_name
df = self.sim.population.props
self._number_of_times_this_event_has_run += 1

if not df.at[person_id, 'is_alive']:
return self.make_appt_footprint({})
road_traffic_injuries = self.sim.modules['RTI']
Expand Down Expand Up @@ -4346,11 +4373,12 @@ def apply(self, person_id, squeeze_factor):
)
df.loc[person_id, 'rt_date_death_no_med'] = pd.NaT
else:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
if pd.isnull(df.loc[person_id, 'rt_date_death_no_med']):
df.loc[person_id, 'rt_date_death_no_med'] = self.sim.date + DateOffset(days=7)
logger.debug(key='rti_general_message',
data="This facility has no treatment for burns available.")
if self._number_of_times_this_event_has_run < self._maximum_number_times_event_should_run:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
if pd.isnull(df.loc[person_id, 'rt_date_death_no_med']):
df.loc[person_id, 'rt_date_death_no_med'] = self.sim.date + DateOffset(days=7)
Copy link
Collaborator

Choose a reason for hiding this comment

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

same comment as above about moving this outside the new clause.

tbhallett marked this conversation as resolved.
Show resolved Hide resolved
logger.debug(key='rti_general_message',
data="This facility has no treatment for burns available.")

def did_not_run(self):
person_id = self.target
Expand All @@ -4373,9 +4401,14 @@ def __init__(self, module, person_id):
self.TREATMENT_ID = 'Rti_TetanusVaccine'
self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({'EPI': 1})
self.ACCEPTED_FACILITY_LEVEL = '1b'
self._number_of_times_this_event_has_run = 0
self._maximum_number_times_event_should_run = self.module.parameters[
'maximum_number_of_times_HSI_events_should_run']

def apply(self, person_id, squeeze_factor):
df = self.sim.population.props
self._number_of_times_this_event_has_run += 1

if not df.at[person_id, 'is_alive']:
return self.make_appt_footprint({})
person_injuries = df.loc[[person_id], RTI.INJURY_COLUMNS]
Expand Down Expand Up @@ -4404,9 +4437,10 @@ def apply(self, person_id, squeeze_factor):
logger.debug(key='rti_general_message',
data=f"Tetanus vaccine requested for person {person_id} and given")
else:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
logger.debug(key='rti_general_message',
data=f"Tetanus vaccine requested for person {person_id}, not given")
if self._number_of_times_this_event_has_run < self._maximum_number_times_event_should_run:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
logger.debug(key='rti_general_message',
data=f"Tetanus vaccine requested for person {person_id}, not given")
tbhallett marked this conversation as resolved.
Show resolved Hide resolved
return self.make_appt_footprint({})

def did_not_run(self):
Expand Down Expand Up @@ -4434,9 +4468,14 @@ def __init__(self, module, person_id):
self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({
('Under5OPD' if self.sim.population.props.at[person_id, "age_years"] < 5 else 'Over5OPD'): 1})
self.ACCEPTED_FACILITY_LEVEL = '1b'
self._number_of_times_this_event_has_run = 0
self._maximum_number_times_event_should_run = self.module.parameters[
'maximum_number_of_times_HSI_events_should_run']

def apply(self, person_id, squeeze_factor):
df = self.sim.population.props
self._number_of_times_this_event_has_run += 1

if not df.at[person_id, 'is_alive']:
return self.make_appt_footprint({})
# Check that the person sent here is alive, has been through A&E and RTI_Med_int
Expand Down Expand Up @@ -4545,10 +4584,11 @@ def apply(self, person_id, squeeze_factor):
data=dict_to_output,
description='Pain medicine successfully provided to the person')
else:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
logger.debug(key='rti_general_message',
data=f"This facility has no pain management available for their mild pain, person "
f"{person_id}.")
if self._number_of_times_this_event_has_run < self._maximum_number_times_event_should_run:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
logger.debug(key='rti_general_message',
data=f"This facility has no pain management available for their mild pain, person "
f"{person_id}.")
return self.make_appt_footprint({})

if pain_level == "moderate":
Expand Down Expand Up @@ -4576,10 +4616,11 @@ def apply(self, person_id, squeeze_factor):
data=dict_to_output,
description='Pain medicine successfully provided to the person')
else:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
logger.debug(key='rti_general_message',
data=f"This facility has no pain management available for moderate pain for person "
f"{person_id}.")
if self._number_of_times_this_event_has_run < self._maximum_number_times_event_should_run:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
logger.debug(key='rti_general_message',
data=f"This facility has no pain management available for moderate pain for person "
f"{person_id}.")
return self.make_appt_footprint({})

if pain_level == "severe":
Expand Down Expand Up @@ -4608,10 +4649,11 @@ def apply(self, person_id, squeeze_factor):
data=dict_to_output,
description='Pain medicine successfully provided to the person')
else:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
logger.debug(key='rti_general_message',
data=f"This facility has no pain management available for severe pain for person "
f"{person_id}.")
if self._number_of_times_this_event_has_run < self._maximum_number_times_event_should_run:
self.sim.modules['RTI'].schedule_hsi_event_for_tomorrow(self)
logger.debug(key='rti_general_message',
data=f"This facility has no pain management available for severe pain for person "
f"{person_id}.")
return self.make_appt_footprint({})

def did_not_run(self):
Expand Down