From a4fc9b23774e6adbca622c3b9079ac8cdab01b75 Mon Sep 17 00:00:00 2001 From: Tara <37845078+tdm32@users.noreply.github.com> Date: Tue, 17 Dec 2024 10:58:59 +0000 Subject: [PATCH] add TB culture HSI (#1453) * modification to scenarios to get it running fast * define mode1 baseline properly * define mode1 baseline properly * add culture test for tb dx this occurs during program scale-up, only if person has had a negative prior test but has all symptoms indicative of tb * remove unneeded todo statement * remove ref to life expectancy in script * remove unused imports * update priority policies * add scenario version with consumables always available * update plots * add outputs to test plot file * revert analysis scripts * remove suppress_footprint from HSI_Tb_Culture * remove unused statement ACTUAL_APPT_FOOTPRINT = self.EXPECTED_APPT_FOOTPRINT * roll back other files --------- Co-authored-by: Tim Hallett <39991060+tbhallett@users.noreply.github.com> --- ...ourceFile_PriorityRanking_ALLPOLICIES.xlsx | 4 +- src/tlo/methods/tb.py | 113 ++++++++++++++++++ 2 files changed, 115 insertions(+), 2 deletions(-) diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx index d9dbac2e99..1748d3f5e9 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:734d46d83dccf15bf38ee171a487664f01035da6cf68660d4af62097a6160fb6 -size 42716 +oid sha256:59a7b6737589f04bc5fc80c3ca3c60f6dae2e1cf95e41ebefa995294298fbc84 +size 42958 diff --git a/src/tlo/methods/tb.py b/src/tlo/methods/tb.py index b0f0cd22f6..762ebf87d3 100644 --- a/src/tlo/methods/tb.py +++ b/src/tlo/methods/tb.py @@ -782,6 +782,21 @@ def get_consumables_for_dx_and_tx(self): ) ) + # TB Culture + self.item_codes_for_consumables_required['culture_test'] = \ + hs.get_item_code_from_item_name("MGIT960 Culture and DST") + + # sensitivity/specificity set for smear status of cases + self.sim.modules["HealthSystem"].dx_manager.register_dx_test( + tb_culture_test=DxTest( + property="tb_inf", + target_categories=["active"], + sensitivity=1.0, + specificity=1.0, + item_codes=self.item_codes_for_consumables_required['culture_test'] + ) + ) + # 4) -------- Define the treatment options -------- # treatment supplied as full kits for duration of treatment # adult treatment - primary @@ -1458,6 +1473,7 @@ def __init__(self, module): def apply(self, population): self.module.update_parameters_for_program_scaleup() + # note also culture test used in target/max scale-up in place of clinical dx class TbActiveEvent(RegularEvent, PopulationScopeEventMixin): @@ -1729,6 +1745,8 @@ def apply(self, person_id, squeeze_factor): # check if patient has: cough, fever, night sweat, weight loss # if none of the above conditions are present, no further action persons_symptoms = self.sim.modules["SymptomManager"].has_what(person_id=person_id) + person_has_tb_symptoms = all(symptom in persons_symptoms for symptom in self.module.symptom_list) + if not any(x in self.module.symptom_list for x in persons_symptoms): return self.make_appt_footprint({}) @@ -1944,6 +1962,27 @@ def apply(self, person_id, squeeze_factor): tclose=None, ) + # ------------------------- Culture testing if program scale-up ------------------------- # + # under program scale-up, if a person tests negative but still has symptoms + # indicative of TB, they are referred for culture test which has perfect sensitivity + # this has the effect to reduce false negatives + if not test_result and person_has_tb_symptoms: + if p['type_of_scaleup'] != 'none' and self.sim.date.year >= p['scaleup_start_year']: + logger.debug( + key="message", + data=f"HSI_Tb_ScreeningAndRefer: scheduling culture for person {person_id}", + ) + + culture_event = HSI_Tb_Culture( + self.module, person_id=person_id + ) + self.sim.modules["HealthSystem"].schedule_hsi_event( + culture_event, + priority=0, + topen=now, + tclose=None, + ) + # Return the footprint. If it should be suppressed, return a blank footprint. if self.suppress_footprint: return self.make_appt_footprint({}) @@ -1979,6 +2018,7 @@ def apply(self, person_id, squeeze_factor): df = self.sim.population.props now = self.sim.date person = df.loc[person_id] + p = self.module.parameters test_result = None # If the person is dead or already diagnosed, do nothing do not occupy any resources @@ -2021,6 +2061,79 @@ def apply(self, person_id, squeeze_factor): tclose=None, priority=0, ) + # ------------------------- Culture testing if program scale-up ------------------------- # + # under program scale-up, if a person tests negative but still has all symptoms + # indicative of TB, they are referred for culture test which has perfect sensitivity + # this has the effect to reduce false negatives + person_has_tb_symptoms = all(symptom in persons_symptoms for symptom in self.module.symptom_list) + + if not test_result and person_has_tb_symptoms: + if p['type_of_scaleup'] != 'none' and self.sim.date.year >= p['scaleup_start_year']: + + logger.debug( + key="message", + data=f"HSI_Tb_ClinicalDiagnosis: scheduling culture for person {person_id}", + ) + + culture_event = HSI_Tb_Culture( + self.module, person_id=person_id + ) + self.sim.modules["HealthSystem"].schedule_hsi_event( + culture_event, + priority=0, + topen=now, + tclose=None, + ) + + +class HSI_Tb_Culture(HSI_Event, IndividualScopeEventMixin): + """ + This the TB culture HSI used for microbiological diagnosis of TB + results (MGIT) are available after 2-6 weeks + will return drug-susceptibility + 100% sensitivity in smear-positive + 80-90% sensitivity in smear-negative + if this test is not available, not further action as this is + already preceded by a sequence of tests + """ + + def __init__(self, module, person_id): + super().__init__(module, person_id=person_id) + assert isinstance(module, Tb) + + self.TREATMENT_ID = "Tb_Test_Culture" + self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({"LabTBMicro": 1}) + self.ACCEPTED_FACILITY_LEVEL = '1b' + + def apply(self, person_id, squeeze_factor): + + df = self.sim.population.props + + if not df.at[person_id, "is_alive"] or df.at[person_id, "tb_diagnosed"]: + return self.sim.modules["HealthSystem"].get_blank_appt_footprint() + + test_result = self.sim.modules["HealthSystem"].dx_manager.run_dx_test( + dx_tests_to_run="tb_culture_test", hsi_event=self) + + # todo equipment required: MGIT instrument, MGIT tube, reagent kit included in consumables + if test_result is not None: + self.add_equipment({'Autoclave', 'Blood culture incubator', 'Vortex mixer', + 'Dispensing pumps for culture media preparation', 'Biosafety Cabinet (Class II)', + 'Centrifuge'}) + + # if test returns positive result, refer for appropriate treatment + if test_result: + df.at[person_id, "tb_diagnosed"] = True + df.at[person_id, "tb_date_diagnosed"] = self.sim.date + + self.sim.modules["HealthSystem"].schedule_hsi_event( + HSI_Tb_StartTreatment( + person_id=person_id, module=self.module, facility_level="1a" + ), + topen=self.sim.date, + tclose=None, + priority=0, + ) class HSI_Tb_Xray_level1b(HSI_Event, IndividualScopeEventMixin):