From 30d40e9471fa1b932b2ba3cf50084724deea8dda Mon Sep 17 00:00:00 2001 From: mmsuarezcosta Date: Mon, 29 Sep 2025 23:14:29 -0400 Subject: [PATCH 1/3] rti param revamp --- .../ResourceFile_RTI/parameter_values.csv | 4 +- src/tlo/methods/rti.py | 179 +++++++++++++----- 2 files changed, 134 insertions(+), 49 deletions(-) diff --git a/resources/ResourceFile_RTI/parameter_values.csv b/resources/ResourceFile_RTI/parameter_values.csv index 1167d1e7b5..35df369ecd 100644 --- a/resources/ResourceFile_RTI/parameter_values.csv +++ b/resources/ResourceFile_RTI/parameter_values.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9ca079273006733c1c5f232de53d3ecc88bc8d1f6a9b6051dea7da29cb9df3cd -size 5049 +oid sha256:83a17b8d22da0e0a4b39b9ab9c5a7efac126934a74e56a4b76cf61ec3b129636 +size 10099 diff --git a/src/tlo/methods/rti.py b/src/tlo/methods/rti.py index 994b8d1054..ccb47d25b7 100644 --- a/src/tlo/methods/rti.py +++ b/src/tlo/methods/rti.py @@ -1020,6 +1020,43 @@ def __init__(self, name=None): 'maximum_number_of_times_HSI_events_should_run': Parameter( Types.INT, "limit on the number of times an HSI event can run" + ), + 'hsi_schedule_window_days': Parameter( + Types.INT, + 'Number of days window to schedule HSI appointment' + ), + 'main_polling_frequency': Parameter( + Types.INT, + 'Frequency in months for RTI polling events that determine new injuries' + ), + 'incidence_rate_frequency': Parameter( + Types.INT, + 'Number of months per year for rate conversion calculations' + ), + 'incidence_rate_per_population': Parameter( + Types.INT, + 'Population base for incidence rate calculations' + ), + 'days_to_death_without_treatment': Parameter( + Types.INT, + 'Number of days until death for untreated RTI patients' + ), + 'max_treatment_duration_days': Parameter( + Types.INT, + 'Maximum number of days for RTI treatment duration' + ), + 'intervention_incidence_reduction_factor': Parameter( + Types.REAL, + 'Factor by which interventions reduce RTI incidence ' + '(applied when reduce_incidence in allowed_interventions)' + ), + 'laceration_recovery_days': Parameter( + Types.INT, + 'Number of days for recovery assessment period' + ), + 'hsi_opening_delay_days': Parameter( + Types.INT, + 'Number of days delay before HSI appointments can be scheduled' ) } @@ -1633,14 +1670,16 @@ def rti_do_for_major_surgeries(self, person_id, count): person_id=person_id), priority=0, topen=self.sim.date + DateOffset(days=count), - tclose=self.sim.date + DateOffset(days=15)) + tclose=self.sim.date + DateOffset(days=p['hsi_schedule_window_days'])) else: if count == 0: df.at[person_id, 'rt_injuries_left_untreated'] = df.at[person_id, 'rt_injuries_for_major_surgery'] # remove the injury code from this treatment option df.at[person_id, 'rt_injuries_for_major_surgery'] = [] # reset the time to check whether the person has died from their injuries - df.loc[person_id, 'rt_date_death_no_med'] = self.sim.date + DateOffset(days=1) + df.loc[person_id, 'rt_date_death_no_med'] = ( + self.sim.date + DateOffset(days=p['hsi_opening_delay_days']) + ) def rti_do_for_minor_surgeries(self, person_id, count): """ @@ -1655,6 +1694,8 @@ def rti_do_for_minor_surgeries(self, person_id, count): :return: """ df = self.sim.population.props + p = self.parameters + # Check to see whether they have been sent here from RTI_MedicalIntervention and they haven't been killed by the # RTI module assert df.at[person_id, 'rt_med_int'], 'Person sent for treatment did not go through rti med int' @@ -1698,14 +1739,16 @@ def rti_do_for_minor_surgeries(self, person_id, count): person_id=person_id), priority=0, topen=self.sim.date + DateOffset(days=count), - tclose=self.sim.date + DateOffset(days=15)) + tclose=self.sim.date + DateOffset(days=p['hsi_schedule_window_days'])) else: if count == 0: df.at[person_id, 'rt_injuries_left_untreated'] = df.at[person_id, 'rt_injuries_for_minor_surgery'] # remove the injury code from this treatment option df.at[person_id, 'rt_injuries_for_minor_surgery'] = [] # reset the time to check whether the person has died from their injuries - df.loc[person_id, 'rt_date_death_no_med'] = self.sim.date + DateOffset(days=1) + df.loc[person_id, 'rt_date_death_no_med'] = ( + self.sim.date + DateOffset(days=p['hsi_opening_delay_days']) + ) def rti_acute_pain_management(self, person_id): """ @@ -1716,6 +1759,7 @@ def rti_acute_pain_management(self, person_id): :return: n/a """ df = self.sim.population.props + p = self.parameters if df.at[person_id, 'is_alive']: # Check to see whether they have been sent here from RTI_MedicalIntervention and they haven't died due to @@ -1735,8 +1779,8 @@ def rti_acute_pain_management(self, person_id): hsi_event=HSI_RTI_Acute_Pain_Management(module=self, person_id=person_id), priority=0, - topen=self.sim.date + DateOffset(days=1), - tclose=self.sim.date + DateOffset(days=15)) + topen=self.sim.date + DateOffset(days=p['hsi_opening_delay_days']), + tclose=self.sim.date + DateOffset(days=p['hsi_schedule_window_days'])) def rti_ask_for_suture_kit(self, person_id): """ @@ -1747,6 +1791,8 @@ def rti_ask_for_suture_kit(self, person_id): :return: n/a """ df = self.sim.population.props + p = self.parameters + if df.at[person_id, 'is_alive']: # Check to see whether they have been sent here from RTI_MedicalIntervention and they haven't died due to # rti @@ -1765,8 +1811,8 @@ def rti_ask_for_suture_kit(self, person_id): hsi_event=HSI_RTI_Suture(module=self, person_id=person_id), priority=0, - topen=self.sim.date + DateOffset(days=1), - tclose=self.sim.date + DateOffset(days=15) + topen=self.sim.date + DateOffset(days=p['hsi_opening_delay_days']), + tclose=self.sim.date + DateOffset(days=p['hsi_schedule_window_days']) ) def rti_ask_for_shock_treatment(self, person_id): @@ -1776,6 +1822,8 @@ def rti_ask_for_shock_treatment(self, person_id): :return: """ df = self.sim.population.props + p = self.parameters + if df.at[person_id, 'is_alive']: assert df.at[person_id, 'rt_in_shock'], 'person requesting shock treatment is not in shock' @@ -1783,8 +1831,8 @@ def rti_ask_for_shock_treatment(self, person_id): hsi_event=HSI_RTI_Shock_Treatment(module=self, person_id=person_id), priority=0, - topen=self.sim.date + DateOffset(days=1), - tclose=self.sim.date + DateOffset(days=15) + topen=self.sim.date + DateOffset(days=p['hsi_opening_delay_days']), + tclose=self.sim.date + DateOffset(days=p['hsi_schedule_window_days']) ) def rti_ask_for_burn_treatment(self, person_id): @@ -1796,6 +1844,7 @@ def rti_ask_for_burn_treatment(self, person_id): :return: n/a """ df = self.sim.population.props + p = self.parameters if df.at[person_id, 'is_alive']: # Check to see whether they have been sent here from RTI_MedicalIntervention and they haven't died due to @@ -1815,8 +1864,8 @@ def rti_ask_for_burn_treatment(self, person_id): hsi_event=HSI_RTI_Burn_Management(module=self, person_id=person_id), priority=0, - topen=self.sim.date + DateOffset(days=1), - tclose=self.sim.date + DateOffset(days=15) + topen=self.sim.date + DateOffset(days=p['hsi_opening_delay_days']), + tclose=self.sim.date + DateOffset(days=p['hsi_schedule_window_days']) ) def rti_ask_for_fracture_casts(self, person_id): @@ -1829,6 +1878,8 @@ def rti_ask_for_fracture_casts(self, person_id): :return: n/a """ df = self.sim.population.props + p = self.parameters + if df.at[person_id, 'is_alive']: # Check to see whether they have been sent here from RTI_MedicalIntervention and they haven't died due to # rti @@ -1852,14 +1903,14 @@ def rti_ask_for_fracture_casts(self, person_id): hsi_event=HSI_RTI_Fracture_Cast(module=self, person_id=person_id), priority=0, - topen=self.sim.date + DateOffset(days=1), - tclose=self.sim.date + DateOffset(days=15) + topen=self.sim.date + DateOffset(days=p['hsi_opening_delay_days']), + tclose=self.sim.date + DateOffset(days=p['hsi_schedule_window_days']) ) else: df.at[person_id, 'rt_injuries_left_untreated'] = df.at[person_id, 'rt_injuries_to_cast'] df.at[person_id, 'rt_injuries_to_cast'] = [] # reset the time to check whether the person has died from their injuries - df.loc[person_id, 'rt_date_death_no_med'] = self.sim.date + DateOffset(days=1) + df.loc[person_id, 'rt_date_death_no_med'] = self.sim.date + DateOffset(days=p['hsi_opening_delay_days']) def rti_ask_for_open_fracture_treatment(self, person_id, counts): """Function called by HSI_RTI_MedicalIntervention to centralise open fracture treatment requests. This function @@ -1871,6 +1922,8 @@ def rti_ask_for_open_fracture_treatment(self, person_id, counts): :return: n/a """ df = self.sim.population.props + p = self.parameters + if df.at[person_id, 'is_alive']: # Check to see whether they have been sent here from RTI_MedicalIntervention and are haven't died due to rti assert df.at[person_id, 'rt_med_int'], 'person sent here not been through rti med int' @@ -1891,7 +1944,7 @@ def rti_ask_for_open_fracture_treatment(self, person_id, counts): hsi_event=HSI_RTI_Open_Fracture_Treatment(module=self, person_id=person_id), priority=0, topen=self.sim.date + DateOffset(days=0 + i), - tclose=self.sim.date + DateOffset(days=15 + i) + tclose=self.sim.date + DateOffset(days=p['hsi_schedule_window_days'] + i) ) def rti_ask_for_tetanus(self, person_id): @@ -1904,6 +1957,8 @@ def rti_ask_for_tetanus(self, person_id): :return: n/a """ df = self.sim.population.props + p = self.parameters + if df.at[person_id, 'is_alive']: # Check to see whether they have been sent here from RTI_MedicalIntervention and are haven't died due to rti assert df.at[person_id, 'rt_med_int'], 'person sent here not been through rti med int' @@ -1924,8 +1979,8 @@ def rti_ask_for_tetanus(self, person_id): hsi_event=HSI_RTI_Tetanus_Vaccine(module=self, person_id=person_id), priority=0, - topen=self.sim.date + DateOffset(days=1), - tclose=self.sim.date + DateOffset(days=15) + topen=self.sim.date + DateOffset(days=p['hsi_opening_delay_days']), + tclose=self.sim.date + DateOffset(days=p['hsi_schedule_window_days']) ) def schedule_hsi_event_for_tomorrow(self, hsi_event: HSI_Event = None): @@ -1933,8 +1988,14 @@ def schedule_hsi_event_for_tomorrow(self, hsi_event: HSI_Event = None): A function to reschedule requested events for the following day if they have failed to run :return: """ - self.sim.modules['HealthSystem'].schedule_hsi_event(hsi_event, topen=self.sim.date + DateOffset(days=1), - tclose=self.sim.date + DateOffset(days=15), priority=0) + p = self.parameters + + self.sim.modules['HealthSystem'].schedule_hsi_event( + hsi_event, + topen=self.sim.date + DateOffset(days=p['hsi_opening_delay_days']), + tclose=self.sim.date + DateOffset(days=p['hsi_schedule_window_days']), + priority=0 + ) def rti_find_injury_column(self, person_id, codes): """ @@ -2189,8 +2250,8 @@ def draw_days(_mean, _sd): else: days_until_treatment_end = 0 # Make sure inpatient days is less that max available - if days_until_treatment_end > 150: - days_until_treatment_end = 150 + if days_until_treatment_end > p['max_treatment_duration_days']: + days_until_treatment_end = p['max_treatment_duration_days'] # Return the LOS return max(days_until_treatment_end, 0) @@ -2563,13 +2624,20 @@ def rti_assign_injuries(self, number): # calculate the incidence of this injury in the population df = self.sim.population.props n_alive = len(df.is_alive) - inc_amputations = amputationcounts / ((n_alive - amputationcounts) * 1 / 12) * 100000 - inc_burns = burncounts / ((n_alive - burncounts) * 1 / 12) * 100000 - inc_fractures = fraccounts / ((n_alive - fraccounts) * 1 / 12) * 100000 - inc_tbi = tbicounts / ((n_alive - tbicounts) * 1 / 12) * 100000 - inc_sci = spinalcordinjurycounts / ((n_alive - spinalcordinjurycounts) * 1 / 12) * 100000 - inc_minor = minorinjurycounts / ((n_alive - minorinjurycounts) * 1 / 12) * 100000 - inc_other = other_counts / ((n_alive - other_counts) * 1 / 12) * 100000 + inc_amputations = (amputationcounts / ((n_alive - amputationcounts) * 1 / p['incidence_rate_frequency']) * + p['incidence_rate_per_population']) + inc_burns = (burncounts / ((n_alive - burncounts) * 1 / p['incidence_rate_frequency']) * + p['incidence_rate_per_population']) + inc_fractures = (fraccounts / ((n_alive - fraccounts) * 1 / p['incidence_rate_frequency']) * + p['incidence_rate_per_population']) + inc_tbi = (tbicounts / ((n_alive - tbicounts) * 1 / p['incidence_rate_frequency']) * + p['incidence_rate_per_population']) + inc_sci = (spinalcordinjurycounts / ((n_alive - spinalcordinjurycounts) * 1 / p['incidence_rate_frequency']) * + p['incidence_rate_per_population']) + inc_minor = (minorinjurycounts / ((n_alive - minorinjurycounts) * 1 / p['incidence_rate_frequency']) * + p['incidence_rate_per_population']) + inc_other = (other_counts / ((n_alive - other_counts) * 1 / p['incidence_rate_frequency']) * + p['incidence_rate_per_population']) tot_inc_all_inj = inc_amputations + inc_burns + inc_fractures + inc_tbi + inc_sci + inc_minor + inc_other if number > 0: number_of_injuries = int(inj_df['Number_of_injuries'].iloc[0]) @@ -2634,6 +2702,7 @@ def _common_first_appt_steps( """ # Things to do upon a person presenting at a Non-Emergency Generic # HSI if they have an injury. + p = self.parameters persons_injuries = [ individual_properties[injury] for injury in RTI.INJURY_COLUMNS ] @@ -2647,8 +2716,8 @@ def _common_first_appt_steps( schedule_hsi_event( event, priority=0, - topen=self.sim.date + DateOffset(days=1), - tclose=self.sim.date + DateOffset(days=15), + topen=self.sim.date + DateOffset(days=p['hsi_opening_delay_days']), + tclose=self.sim.date + DateOffset(days=p['hsi_schedule_window_days']), ) individual_properties["rt_diagnosed"] = True @@ -2692,8 +2761,8 @@ def _common_first_appt_steps( schedule_hsi_event( event, priority=0, - topen=self.sim.date + DateOffset(days=1), - tclose=self.sim.date + DateOffset(days=15), + topen=self.sim.date + DateOffset(days=p['hsi_opening_delay_days']), + tclose=self.sim.date + DateOffset(days=p['hsi_schedule_window_days']), ) def do_at_generic_first_appt( @@ -2774,14 +2843,14 @@ class RTIPollingEvent(RegularEvent, PopulationScopeEventMixin): """ def __init__(self, module): - """Schedule to take place every month + """Schedule to take place """ - super().__init__(module, frequency=DateOffset(months=1)) + super().__init__(module, frequency=DateOffset(months=module.parameters['main_polling_frequency'])) p = module.parameters # Parameters which transition the model between states self.base_1m_prob_rti = (p['base_rate_injrti'] / 12) if 'reduce_incidence' in p['allowed_interventions']: - self.base_1m_prob_rti = self.base_1m_prob_rti * 0.335 + self.base_1m_prob_rti = self.base_1m_prob_rti * p['intervention_incidence_reduction_factor'] self.rr_injrti_age04 = p['rr_injrti_age04'] self.rr_injrti_age59 = p['rr_injrti_age59'] self.rr_injrti_age1017 = p['rr_injrti_age1017'] @@ -2804,6 +2873,7 @@ def apply(self, population): """ df = population.props now = self.sim.date + p = self.module.parameters # Reset injury properties after death, get an index of people who have died due to RTI, all causes diedfromrtiidx = df.index[df.rt_imm_death | df.rt_post_med_death | df.rt_no_med_death | df.rt_death_from_shock | df.rt_unavailable_med_death] @@ -2931,9 +3001,12 @@ def apply(self, population): internal_bleeding_codes = ['361', '363', '461', '463', '813bo', '813co', '813do', '813eo'] df = self.sim.population.props - potential_shock_index, _ = \ - road_traffic_injuries.rti_find_and_count_injuries(df.loc[df.rt_road_traffic_inc, RTI.INJURY_COLUMNS], - internal_bleeding_codes) + potential_shock_index, _ = ( + road_traffic_injuries.rti_find_and_count_injuries( + df.loc[df.rt_road_traffic_inc, RTI.INJURY_COLUMNS], + internal_bleeding_codes + ) + ) rand_for_shock = self.module.rng.random_sample(len(potential_shock_index)) shock_index = potential_shock_index[self.prob_bleeding_leads_to_shock > rand_for_shock] df.loc[shock_index, 'rt_in_shock'] = True @@ -2947,7 +3020,8 @@ def apply(self, population): # todo: find better time for survival data without med int for ISS scores # Assign a date in the future for which when the simulation reaches that date, the person's mortality will be # checked if they haven't sought care - df.loc[selected_for_rti_inj.index, 'rt_date_death_no_med'] = now + DateOffset(days=7) + df.loc[selected_for_rti_inj.index, 'rt_date_death_no_med'] = (now + + DateOffset(days = p['days_to_death_without_treatment'])) # ============================ Injury severity classification ================================================= # Find those with mild injuries and update the rt_inj_severity property so they have a mild injury injured_this_month = df.loc[selected_for_rti_inj.index] @@ -4157,7 +4231,8 @@ def apply(self, person_id, squeeze_factor): 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) + df.loc[person_id, 'rt_date_death_no_med'] = (self.sim.date + + DateOffset(days=self.module.parameters['days_to_death_without_treatment'])) logger.debug(key='rti_general_message', data=f"Person {person_id} has {fracturecastcounts + slingcounts} fractures without treatment" ) @@ -4269,7 +4344,8 @@ def apply(self, person_id, squeeze_factor): 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) + df.loc[person_id, 'rt_date_death_no_med'] = (self.sim.date + + DateOffset(days=self.module.parameters['days_to_death_without_treatment'])) logger.debug(key='rti_general_message', data=f"Person {person_id}'s has {open_fracture_counts} open fractures without treatment", ) @@ -4316,6 +4392,7 @@ def __init__(self, module, person_id): def apply(self, person_id, squeeze_factor): df = self.sim.population.props + p = self.module.parameters self._number_of_times_this_event_has_run += 1 if not df.at[person_id, 'is_alive']: @@ -4352,7 +4429,7 @@ def apply(self, person_id, squeeze_factor): # wound%20and%20your%20general,have%20a%20weakened%20immune%20system. date_to_remove_daly_column = RTI.INJURY_DATE_COLUMN_MAP[injury_column] df.loc[person_id, date_to_remove_daly_column] = ( - self.sim.date + DateOffset(days=14) + self.sim.date + DateOffset(days=p['laceration_recovery_days']) ) assert df.loc[person_id, date_to_remove_daly_column] > self.sim.date df.loc[person_id, 'rt_date_death_no_med'] = pd.NaT @@ -4360,7 +4437,8 @@ def apply(self, person_id, squeeze_factor): 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) + df.loc[person_id, 'rt_date_death_no_med'] = (self.sim.date + + DateOffset(days=p['days_to_death_without_treatment'])) logger.debug(key='rti_general_message', data="This facility has no treatment for open wounds available.") return self.make_appt_footprint({}) @@ -4411,6 +4489,7 @@ def __init__(self, module, person_id): def apply(self, person_id, squeeze_factor): df = self.sim.population.props + p = self.module.parameters self._number_of_times_this_event_has_run += 1 if not df.at[person_id, 'is_alive']: @@ -4488,7 +4567,8 @@ def apply(self, person_id, squeeze_factor): 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) + df.loc[person_id, 'rt_date_death_no_med'] = (self.sim.date + + DateOffset(days= p['days_to_death_without_treatment'])) logger.debug(key='rti_general_message', data="This facility has no treatment for burns available.") @@ -4877,6 +4957,8 @@ def apply(self, person_id, squeeze_factor): self._number_of_times_this_event_has_run += 1 df = self.sim.population.props rng = self.module.rng + p = self.module.parameters + road_traffic_injuries = self.sim.modules['RTI'] # Request first draft of consumables used in major surgery @@ -5125,7 +5207,8 @@ def apply(self, person_id, squeeze_factor): 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) + df.loc[person_id, 'rt_date_death_no_med'] = (self.sim.date + + DateOffset(days=p['days_to_death_without_treatment'])) return self.make_appt_footprint({}) def did_not_run(self): @@ -5196,6 +5279,7 @@ def __init__(self, module, person_id): def apply(self, person_id, squeeze_factor): self._number_of_times_this_event_has_run += 1 df = self.sim.population.props + p = self.module.parameters if not df.at[person_id, 'is_alive']: return self.make_appt_footprint({}) @@ -5291,7 +5375,8 @@ def apply(self, person_id, squeeze_factor): 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) + df.loc[person_id, 'rt_date_death_no_med'] = (self.sim.date + + DateOffset(days=p['days_to_death_without_treatment'])) logger.debug(key='rti_general_message', data=f"This is RTI_Minor_Surgeries failing to provide minor surgeries for person {person_id} " f"on date {self.sim.date}!!!!!!") From 3a44bed1c70e0d93b3e2343e613076d3030416e5 Mon Sep 17 00:00:00 2001 From: mmsuarezcosta Date: Mon, 13 Oct 2025 22:40:14 -0400 Subject: [PATCH 2/3] update param labeling --- resources/ResourceFile_RTI/parameter_values.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_RTI/parameter_values.csv b/resources/ResourceFile_RTI/parameter_values.csv index 35df369ecd..763171f64c 100644 --- a/resources/ResourceFile_RTI/parameter_values.csv +++ b/resources/ResourceFile_RTI/parameter_values.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:83a17b8d22da0e0a4b39b9ab9c5a7efac126934a74e56a4b76cf61ec3b129636 -size 10099 +oid sha256:9ff90fdc8d4928ed997babcd78b253127bba18576e36deddb1f75f275c8ae6bf +size 9721 From 041b15a633fa9dde067414f347ef3262aabcf1ae Mon Sep 17 00:00:00 2001 From: mmsuarezcosta Date: Sat, 8 Nov 2025 22:23:03 -0500 Subject: [PATCH 3/3] rti update hardcoded params --- .../ResourceFile_RTI/parameter_values.csv | 4 +- src/tlo/methods/rti.py | 95 ++++++++++++++++--- 2 files changed, 82 insertions(+), 17 deletions(-) diff --git a/resources/ResourceFile_RTI/parameter_values.csv b/resources/ResourceFile_RTI/parameter_values.csv index 763171f64c..ed879f0694 100644 --- a/resources/ResourceFile_RTI/parameter_values.csv +++ b/resources/ResourceFile_RTI/parameter_values.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9ff90fdc8d4928ed997babcd78b253127bba18576e36deddb1f75f275c8ae6bf -size 9721 +oid sha256:7fd70f3b0e4e55b230bf6f6b3977e6089482d33d1b8ca33503569ac52d39a30e +size 10533 diff --git a/src/tlo/methods/rti.py b/src/tlo/methods/rti.py index ccb47d25b7..9097ff573d 100644 --- a/src/tlo/methods/rti.py +++ b/src/tlo/methods/rti.py @@ -557,6 +557,19 @@ def __init__(self, name=None): 'A parameter to determine which level of injury severity corresponds to the emergency health care seeking ' 'symptom and which to the non-emergency generic injury symptom' ), + 'prob_death_non_serious': Parameter( + Types.REAL, + 'A parameter to determine the probability of death for non serious condition' + ), 'prob_death_MAIS1': Parameter( + Types.REAL, + 'A parameter to determine the probability of death without medical intervention with a military AIS' + 'score of 1' + ), + 'prob_death_MAIS2': Parameter( + Types.REAL, + 'A parameter to determine the probability of death without medical intervention with a military AIS' + 'score of 2' + ), 'prob_death_MAIS3': Parameter( Types.REAL, 'A parameter to determine the probability of death without medical intervention with a military AIS' @@ -1029,6 +1042,14 @@ def __init__(self, name=None): Types.INT, 'Frequency in months for RTI polling events that determine new injuries' ), + 'rti_check_death_no_med_event_frequency_days': Parameter( + Types.INT, + 'Frequency in days for RTI check death no med event' + ), + 'rti_recovery_event_frequency_days': Parameter( + Types.INT, + 'Frequency in days for RTI recovery event' + ), 'incidence_rate_frequency': Parameter( Types.INT, 'Number of months per year for rate conversion calculations' @@ -1057,7 +1078,35 @@ def __init__(self, name=None): 'hsi_opening_delay_days': Parameter( Types.INT, 'Number of days delay before HSI appointments can be scheduled' - ) + ), + 'main_polling_initialisation_delay_months': Parameter( + Types.INT, + 'Delay in months at initialisation for first main polling event' + ), + 'rti_recovery_initialisation_delay_months': Parameter( + Types.INT, + 'Delay in months at initialisation for rti recovery event' + ), + 'rti_check_death_no_med_initialisation_delay_months': Parameter( + Types.INT, + 'Delay in months at initialisation for rti check death no med event' + ), + 'non_permanent_tbi_recovery_months': Parameter( + Types.INT, + 'Recovery duration in months for tbi if non permanent; sets date for date_to_remove_daly_column' + ), + 'rti_fracture_cast_recovery_weeks': Parameter( + Types.INT, + 'Recovery duration in weeks for fracture cast; sets date for date_to_remove_daly_column' + ), + 'rti_open_fracture_recovery_months': Parameter( + Types.INT, + 'Recovery duration in months for open fracture; sets date for date_to_remove_daly_column' + ), + 'rti_burn_recovery_weeks': Parameter( + Types.INT, + 'Recovery duration in weeks for rti burn; sets date for date_to_remove_daly_column' + ), } @@ -1558,12 +1607,16 @@ def initialise_simulation(self, sim): The final event is one which checks if this person has not sought sought care or been given care, if they haven't then it asks whether they should die away from their injuries """ + p = self.parameters # Begin modelling road traffic injuries - sim.schedule_event(RTIPollingEvent(self), sim.date + DateOffset(months=0)) + sim.schedule_event(RTIPollingEvent(self), sim.date + + DateOffset(months=p['main_polling_initialisation_delay_months'])) # Begin checking whether the persons injuries are healed - sim.schedule_event(RTI_Recovery_Event(self), sim.date + DateOffset(months=0)) + sim.schedule_event(RTI_Recovery_Event(self), sim.date + + DateOffset(months=p['rti_recovery_initialisation_delay_months'])) # Begin checking whether those with untreated injuries die - sim.schedule_event(RTI_Check_Death_No_Med(self), sim.date + DateOffset(months=0)) + sim.schedule_event(RTI_Check_Death_No_Med(self), sim.date + + DateOffset(months=p['rti_check_death_no_med_initialisation_delay_months'])) # Begin logging the RTI events sim.schedule_event(RTI_Logging_Event(self), sim.date + DateOffset(months=1)) # Look-up consumable item codes @@ -3132,10 +3185,13 @@ class RTI_Check_Death_No_Med(RegularEvent, PopulationScopeEventMixin): """ def __init__(self, module): - super().__init__(module, frequency=DateOffset(days=1)) + super().__init__(module, frequency=DateOffset( + days= module.parameters['rti_check_death_no_med_event_frequency_days'])) assert isinstance(module, RTI) p = module.parameters # Load parameters used by this event + self.prob_death_MAIS1 = p['prob_death_MAIS1'] + self.prob_death_MAIS2 = p['prob_death_MAIS2'] self.prob_death_MAIS3 = p['prob_death_MAIS3'] self.prob_death_MAIS4 = p['prob_death_MAIS4'] self.prob_death_MAIS5 = p['prob_death_MAIS5'] @@ -3164,9 +3220,11 @@ def __init__(self, module): def apply(self, population): df = population.props now = self.sim.date + p = self.module.parameters + probabilities_of_death = { - '1': 0, - '2': 0, + '1': self.prob_death_MAIS1, + '2': self.prob_death_MAIS2, '3': self.prob_death_MAIS3, '4': self.prob_death_MAIS4, '5': self.prob_death_MAIS5, @@ -3196,7 +3254,7 @@ def apply(self, population): prob_death = probabilities_of_death[str(max_untreated_injury)] if df.loc[person, 'rt_med_int'] and (max_untreated_injury < self.no_treatment_mortality_mais_cutoff): # filter out non serious injuries from the consideration of mortality - prob_death = 0 + prob_death = p['prob_death_non_serious'] if (rand_for_death < prob_death) and (df.at[person, 'rt_ISS_score'] > self.no_treatment_ISS_cut_off): # If determined to die, schedule a death without med df.loc[person, 'rt_no_med_death'] = True @@ -3339,7 +3397,8 @@ class RTI_Recovery_Event(RegularEvent, PopulationScopeEventMixin): """ def __init__(self, module): - super().__init__(module, frequency=DateOffset(days=1)) + super().__init__(module, frequency=DateOffset( + days= module.parameters['rti_recovery_event_frequency_days'])) assert isinstance(module, RTI) def apply(self, population): @@ -3873,7 +3932,8 @@ def apply(self, person_id, squeeze_factor): else: heal_with_time_codes.append(tbi_injury[0]) # using estimated 6 months PLACEHOLDER FOR TRAUMATIC BRAIN INJURY - df.loc[person_id, date_to_remove_daly_column] = self.sim.date + DateOffset(months=6) + df.loc[person_id, date_to_remove_daly_column] = (self.sim.date + + DateOffset(months=p['non_permanent_tbi_recovery_months'])) assert df.loc[person_id, date_to_remove_daly_column] > self.sim.date # swap potentially swappable codes swapping_codes = RTI.SWAPPING_CODES[:] @@ -4129,6 +4189,7 @@ def apply(self, person_id, squeeze_factor): # Get the population and health system df = self.sim.population.props p = df.loc[person_id] + params = self.module.parameters self._number_of_times_this_event_has_run += 1 # if the person isn't alive return a blank footprint @@ -4212,7 +4273,7 @@ def apply(self, person_id, squeeze_factor): # todo: update this with recovery times for casted dislocated hip date_to_remove_daly_column = RTI.INJURY_DATE_COLUMN_MAP[injury_column] df.loc[person_id, date_to_remove_daly_column] = ( - self.sim.date + DateOffset(weeks=7) + self.sim.date + DateOffset(weeks=params['rti_fracture_cast_recovery_weeks']) ) # make sure the assigned injury recovery date is in the future assert df.loc[person_id, date_to_remove_daly_column] > self.sim.date @@ -4276,6 +4337,8 @@ def __init__(self, module, person_id): def apply(self, person_id, squeeze_factor): df = self.sim.population.props + params = self.module.parameters + self._number_of_times_this_event_has_run += 1 if not df.at[person_id, 'is_alive']: return self.make_appt_footprint({}) @@ -4330,7 +4393,7 @@ def apply(self, person_id, squeeze_factor): # estimated 6-9 months recovery times for open fractures date_to_remove_daly_column = RTI.INJURY_DATE_COLUMN_MAP[columns[0]] df.loc[person_id, date_to_remove_daly_column] = ( - self.sim.date + DateOffset(months=7) + self.sim.date + DateOffset(months= params['rti_open_fracture_recovery_months']) ) assert df.loc[person_id, date_to_remove_daly_column] > self.sim.date assert not pd.isnull( @@ -4540,7 +4603,7 @@ def apply(self, person_id, squeeze_factor): date_to_remove_daly_column = RTI.INJURY_DATE_COLUMN_MAP[injury_column] # estimate burns take 4 weeks to heal df.loc[person_id, date_to_remove_daly_column] = ( - self.sim.date + DateOffset(weeks=4) + self.sim.date + DateOffset(weeks=p['rti_burn_recovery_weeks']) ) assert df.loc[person_id, date_to_remove_daly_column] > self.sim.date persons_injuries = df.loc[[person_id], RTI.INJURY_COLUMNS] @@ -5490,6 +5553,8 @@ def __init__(self, module, person_id): self.prob_death_TBI_SCI_no_treatment = p['prob_death_TBI_SCI_no_treatment'] self.prob_death_fractures_no_treatment = p['prob_death_fractures_no_treatment'] self.prop_death_burns_no_treatment = p['prop_death_burns_no_treatment'] + self.prob_death_MAIS1 = p['prob_death_MAIS1'] + self.prob_death_MAIS2 = p['prob_death_MAIS2'] self.prob_death_MAIS3 = p['prob_death_MAIS3'] self.prob_death_MAIS4 = p['prob_death_MAIS4'] self.prob_death_MAIS5 = p['prob_death_MAIS5'] @@ -5499,8 +5564,8 @@ def __init__(self, module, person_id): def apply(self, person_id): probabilities_of_death = { - '1': 0, - '2': 0, + '1': self.prob_death_MAIS1, + '2': self.prob_death_MAIS2, '3': self.prob_death_MAIS3, '4': self.prob_death_MAIS4, '5': self.prob_death_MAIS5,