Skip to content

Commit

Permalink
add TB culture HSI (#1453)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
tdm32 and tbhallett authored Dec 17, 2024
1 parent cdf5b3b commit a4fc9b2
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 2 deletions.
Git LFS file not shown
113 changes: 113 additions & 0 deletions src/tlo/methods/tb.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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({})

Expand Down Expand Up @@ -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({})
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand Down

0 comments on commit a4fc9b2

Please sign in to comment.