Skip to content

Commit

Permalink
Let the Scale-up of HIV, TB, Malaria services go to "MAXIMAL" levels …
Browse files Browse the repository at this point in the history
…(as well as target levels) (#1443)

* create new scenario file for testing HTM max scale-up
update ResourceFile_HIV.xlsx, ResourceFile_malaria.xlsx, ResourceFile_TB.xlsx to include max scale-up

* change parameter do_sacleup to categorical in hiv, tb and malaria modules

* add type_of_scaleup with default value=none to htm resourcefiles

* choose scale-up values from resourcefile using parameter type_of_scaleup

* set up scenarios to test max scale-up works as expected

* set up scenarios to test max scale-up works as expected

* edit figures

* switch type_of_scaleup to string

* update test_htm_scaleup.py

* enhanced_lifestly.py update np.timedelta64 as ValueError: Unit M is not supported. Only unambiguous timedelta values durations are supported. Allowed units are 'W', 'D', 'h', 'm', 's', 'ms', 'us', 'ns'

* switch scale-up parameter selection (target vs max) to update_parameters_for_program_scaleup not within read_parameters as this is read before the analysis script updates parameters

* comment out plots in analysis_maxHTM_scenario.py

* tidy up script

* move import statements used for plotting

* remove unneeded columns from scale-up_parameters sheet in resourcefiles

* switch to using maximum scale-up

* roll back change in enhanced_lifestyle.py

---------

Co-authored-by: tdm32 <[email protected]>
  • Loading branch information
tbhallett and tdm32 committed Jul 29, 2024
1 parent 965b69d commit 9561a7a
Show file tree
Hide file tree
Showing 9 changed files with 299 additions and 53 deletions.
4 changes: 2 additions & 2 deletions resources/ResourceFile_HIV.xlsx
Git LFS file not shown
4 changes: 2 additions & 2 deletions resources/ResourceFile_TB.xlsx
Git LFS file not shown
4 changes: 2 additions & 2 deletions resources/malaria/ResourceFile_malaria.xlsx
Git LFS file not shown
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
"""
This scenario file sets up the scenarios for simulating the effects of scaling up programs
The scenarios are:
*0 baseline mode 1
*1 scale-up HIV program
*2 scale-up TB program
*3 scale-up malaria program
*4 scale-up HIV and Tb and malaria programs
scale-up occurs on the default scale-up start date (01/01/2025: in parameters list of resourcefiles)
For all scenarios, keep all default health system settings
check the batch configuration gets generated without error:
tlo scenario-run --draw-only src/scripts/comparison_of_horizontal_and_vertical_programs/analysis_maxHTM_scenario.py
Run on the batch system using:
tlo batch-submit src/scripts/comparison_of_horizontal_and_vertical_programs/analysis_maxHTM_scenario.py
or locally using:
tlo scenario-run src/scripts/comparison_of_horizontal_and_vertical_programs/analysis_maxHTM_scenario.py
or execute a single run:
tlo scenario-run src/scripts/comparison_of_horizontal_and_vertical_programs/analysis_maxHTM_scenario.py --draw 1 0
"""

import datetime
from pathlib import Path

from tlo import Date, logging
from tlo.methods import (
demography,
enhanced_lifestyle,
epi,
healthburden,
healthseekingbehaviour,
healthsystem,
hiv,
malaria,
simplified_births,
symptommanager,
tb,
)
from tlo.scenario import BaseScenario

resourcefilepath = Path("./resources")
datestamp = datetime.date.today().strftime("__%Y_%m_%d")

outputspath = Path("./outputs")
scaleup_start_year = 2012
end_date = Date(2015, 1, 1)


class EffectOfProgrammes(BaseScenario):
def __init__(self):
super().__init__()
self.seed = 0
self.start_date = Date(2010, 1, 1)
self.end_date = end_date
self.pop_size = 1_000
self.number_of_draws = 5
self.runs_per_draw = 1

def log_configuration(self):
return {
'filename': 'scaleup_tests',
'directory': Path('./outputs'), # <- (specified only for local running)
'custom_levels': {
'*': logging.WARNING,
'tlo.methods.hiv': logging.INFO,
'tlo.methods.tb': logging.INFO,
'tlo.methods.malaria': logging.INFO,
'tlo.methods.demography': logging.INFO,
}
}

def modules(self):
return [
demography.Demography(resourcefilepath=self.resources),
simplified_births.SimplifiedBirths(resourcefilepath=self.resources),
enhanced_lifestyle.Lifestyle(resourcefilepath=self.resources),
healthsystem.HealthSystem(resourcefilepath=self.resources),
symptommanager.SymptomManager(resourcefilepath=self.resources),
healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=self.resources),
healthburden.HealthBurden(resourcefilepath=self.resources),
epi.Epi(resourcefilepath=self.resources),
hiv.Hiv(resourcefilepath=self.resources),
tb.Tb(resourcefilepath=self.resources),
malaria.Malaria(resourcefilepath=self.resources),
]

def draw_parameters(self, draw_number, rng):

return {
'Hiv': {
'type_of_scaleup': ['none', 'max', 'none', 'none', 'max'][draw_number],
'scaleup_start_year': scaleup_start_year,
},
'Tb': {
'type_of_scaleup': ['none', 'none', 'max', 'none', 'max'][draw_number],
'scaleup_start_year': scaleup_start_year,
},
'Malaria': {
'type_of_scaleup': ['none', 'none', 'none', 'max', 'max'][draw_number],
'scaleup_start_year': scaleup_start_year,
},
}


if __name__ == '__main__':
from tlo.cli import scenario_run

scenario_run([__file__])



# %% Produce some figures and summary info

# import pandas as pd
# import matplotlib.pyplot as plt

# # Find results_folder associated with a given batch_file (and get most recent [-1])
# results_folder = get_scenario_outputs("scaleup_tests-", outputspath)[-1]
#
# # get basic information about the results
# info = get_scenario_info(results_folder)
#
# # 1) Extract the parameters that have varied over the set of simulations
# params = extract_params(results_folder)
#
#
# # DEATHS
#
#
# def get_num_deaths_by_cause_label(_df):
# """Return total number of Deaths by label within the TARGET_PERIOD
# values are summed for all ages
# df returned: rows=COD, columns=draw
# """
# return _df \
# .loc[pd.to_datetime(_df.date).between(*TARGET_PERIOD)] \
# .groupby(_df['label']) \
# .size()
#
#
# TARGET_PERIOD = (Date(scaleup_start_year, 1, 1), end_date)
#
# # produce df of total deaths over scale-up period
# num_deaths_by_cause_label = extract_results(
# results_folder,
# module='tlo.methods.demography',
# key='death',
# custom_generate_series=get_num_deaths_by_cause_label,
# do_scaling=True
# )
#
#
# def summarise_deaths_for_one_cause(results_folder, label):
# """ returns mean deaths for each year of the simulation
# values are aggregated across the runs of each draw
# for the specified cause
# """
#
# results_deaths = extract_results(
# results_folder,
# module="tlo.methods.demography",
# key="death",
# custom_generate_series=(
# lambda df: df.assign(year=df["date"].dt.year).groupby(
# ["year", "label"])["person_id"].count()
# ),
# do_scaling=True,
# )
# # removes multi-index
# results_deaths = results_deaths.reset_index()
#
# # select only cause specified
# tmp = results_deaths.loc[
# (results_deaths.label == label)
# ]
#
# # group deaths by year
# tmp = pd.DataFrame(tmp.groupby(["year"]).sum())
#
# # get mean for each draw
# mean_deaths = pd.concat({'mean': tmp.iloc[:, 1:].groupby(level=0, axis=1).mean()}, axis=1).swaplevel(axis=1)
#
# return mean_deaths
#
#
# aids_deaths = summarise_deaths_for_one_cause(results_folder, 'AIDS')
# tb_deaths = summarise_deaths_for_one_cause(results_folder, 'TB (non-AIDS)')
# malaria_deaths = summarise_deaths_for_one_cause(results_folder, 'Malaria')
#
#
# draw_labels = ['No scale-up', 'HIV scale-up', 'TB scale-up', 'Malaria scale-up', 'HTM scale-up']
# colours = ['blue', 'green', 'red', 'purple', 'orange']
#
# # Create subplots
# fig, axs = plt.subplots(3, 1, figsize=(10, 10))
# # Plot for df1
# for i, col in enumerate(aids_deaths.columns):
# axs[0].plot(aids_deaths.index, aids_deaths[col], label=draw_labels[i],
# color=colours[i])
# axs[0].set_title('HIV/AIDS')
# axs[0].legend(loc='center left', bbox_to_anchor=(1, 0.5)) # Legend to the right of the plot
# axs[0].axvline(x=scaleup_start_year, color='gray', linestyle='--')
#
# # Plot for df2
# for i, col in enumerate(tb_deaths.columns):
# axs[1].plot(tb_deaths.index, tb_deaths[col], color=colours[i])
# axs[1].set_title('TB')
# axs[1].axvline(x=scaleup_start_year, color='gray', linestyle='--')
#
# # Plot for df3
# for i, col in enumerate(malaria_deaths.columns):
# axs[2].plot(malaria_deaths.index, malaria_deaths[col], color=colours[i])
# axs[2].set_title('Malaria')
# axs[2].axvline(x=scaleup_start_year, color='gray', linestyle='--')
#
# for ax in axs:
# ax.set_xlabel('Years')
# ax.set_ylabel('Number deaths')
#
# plt.tight_layout(rect=[0, 0, 0.85, 1]) # Adjust layout to make space for legend
# plt.show()
#
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ def hiv_scaleup(self) -> Dict:
"""The parameters for the scale-up of the HIV program"""
return {
"Hiv": {
'do_scaleup': True,
'type_of_scaleup': 'max', # <--- using MAXIMUM SCALE-UP as an experiment
'scaleup_start_year': self.YEAR_OF_CHANGE_FOR_HTM,
}
}
Expand All @@ -135,7 +135,7 @@ def tb_scaleup(self) -> Dict:
"""The parameters for the scale-up of the TB program"""
return {
"Tb": {
'do_scaleup': True,
'type_of_scaleup': 'max', # <--- using MAXIMUM SCALE-UP as an experiment
'scaleup_start_year': self.YEAR_OF_CHANGE_FOR_HTM,
}
}
Expand All @@ -144,7 +144,7 @@ def malaria_scaleup(self) -> Dict:
"""The parameters for the scale-up of the Malaria program"""
return {
'Malaria': {
'do_scaleup': True,
'type_of_scaleup': 'max', # <--- using MAXIMUM SCALE-UP as an experiment
'scaleup_start_year': self.YEAR_OF_CHANGE_FOR_HTM,
}
}
20 changes: 13 additions & 7 deletions src/tlo/methods/hiv.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,16 +398,16 @@ def __init__(self, name=None, resourcefilepath=None, run_with_checks=False):
" high-bound-exclusive]",
),
# ------------------ scale-up parameters for scenario analysis ------------------ #
"do_scaleup": Parameter(
Types.BOOL,
"argument to determine whether scale-up of program will be implemented"
"type_of_scaleup": Parameter(
Types.STRING, "argument to determine type scale-up of program which will be implemented, "
"can be 'none', 'target' or 'max'",
),
"scaleup_start_year": Parameter(
Types.INT,
"the year when the scale-up starts (it will occur on 1st January of that year)"
),
"scaleup_parameters": Parameter(
Types.DICT,
Types.DATA_FRAME,
"the parameters and values changed in scenario analysis"
),
}
Expand Down Expand Up @@ -448,7 +448,7 @@ def read_parameters(self, data_folder):
p["treatment_cascade"] = workbook["spectrum_treatment_cascade"]

# load parameters for scale-up projections
p["scaleup_parameters"] = workbook["scaleup_parameters"].set_index('parameter')['scaleup_value'].to_dict()
p['scaleup_parameters'] = workbook["scaleup_parameters"]

# DALY weights
# get the DALY weight that this module will use from the weight database (these codes are just random!)
Expand Down Expand Up @@ -914,7 +914,7 @@ def initialise_simulation(self, sim):
sim.schedule_event(HivLoggingEvent(self), sim.date + DateOffset(years=1))

# Optional: Schedule the scale-up of programs
if self.parameters["do_scaleup"]:
if self.parameters["type_of_scaleup"] != 'none':
scaleup_start_date = Date(self.parameters["scaleup_start_year"], 1, 1)
assert scaleup_start_date >= self.sim.start_date, f"Date {scaleup_start_date} is before simulation starts."
sim.schedule_event(HivScaleUpEvent(self), scaleup_start_date)
Expand Down Expand Up @@ -1102,8 +1102,14 @@ def initialise_simulation(self, sim):
)

def update_parameters_for_program_scaleup(self):
""" options for program scale-up are 'target' or 'max' """
p = self.parameters
scaled_params = p["scaleup_parameters"]
scaled_params_workbook = p["scaleup_parameters"]

if p['type_of_scaleup'] == 'target':
scaled_params = scaled_params_workbook.set_index('parameter')['target_value'].to_dict()
else:
scaled_params = scaled_params_workbook.set_index('parameter')['max_value'].to_dict()

# scale-up HIV program
# reduce risk of HIV - applies to whole adult population
Expand Down
23 changes: 14 additions & 9 deletions src/tlo/methods/malaria.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,17 +189,16 @@ def __init__(self, name=None, resourcefilepath=None):
Types.REAL,
'probability that treatment will clear malaria symptoms'
),
# ------------------ scale-up parameters for scenario analysis ------------------ #
"do_scaleup": Parameter(
Types.BOOL,
"argument to determine whether scale-up of program will be implemented"
"type_of_scaleup": Parameter(
Types.STRING, "argument to determine type scale-up of program which will be implemented, "
"can be 'none', 'target' or 'max'",
),
"scaleup_start_year": Parameter(
Types.INT,
"the year when the scale-up starts (it will occur on 1st January of that year)"
),
"scaleup_parameters": Parameter(
Types.DICT,
Types.DATA_FRAME,
"the parameters and values changed in scenario analysis"
)
}
Expand Down Expand Up @@ -261,7 +260,7 @@ def read_parameters(self, data_folder):
p['sev_inc'] = pd.read_csv(self.resourcefilepath / 'malaria' / 'ResourceFile_malaria_SevInc_expanded.csv')

# load parameters for scale-up projections
p["scaleup_parameters"] = workbook["scaleup_parameters"].set_index('parameter')['scaleup_value'].to_dict()
p['scaleup_parameters'] = workbook["scaleup_parameters"]

# check itn projected values are <=0.7 and rounded to 1dp for matching to incidence tables
p['itn'] = round(p['itn'], 1)
Expand Down Expand Up @@ -602,7 +601,7 @@ def initialise_simulation(self, sim):
sim.schedule_event(MalariaPrevDistrictLoggingEvent(self), sim.date + DateOffset(months=1))

# Optional: Schedule the scale-up of programs
if self.parameters["do_scaleup"]:
if self.parameters["type_of_scaleup"] != 'none':
scaleup_start_date = Date(self.parameters["scaleup_start_year"], 1, 1)
assert scaleup_start_date >= self.sim.start_date, f"Date {scaleup_start_date} is before simulation starts."
sim.schedule_event(MalariaScaleUpEvent(self), scaleup_start_date)
Expand Down Expand Up @@ -659,8 +658,14 @@ def initialise_simulation(self, sim):
)

def update_parameters_for_program_scaleup(self):
""" options for program scale-up are 'target' or 'max' """
p = self.parameters
scaled_params = p["scaleup_parameters"]
scaled_params_workbook = p["scaleup_parameters"]

if p['type_of_scaleup'] == 'target':
scaled_params = scaled_params_workbook.set_index('parameter')['target_value'].to_dict()
else:
scaled_params = scaled_params_workbook.set_index('parameter')['max_value'].to_dict()

# scale-up malaria program
# increase testing
Expand Down Expand Up @@ -1164,7 +1169,7 @@ def apply(self, person_id, squeeze_factor):
facility_level=self.ACCEPTED_FACILITY_LEVEL,
treatment_id=self.TREATMENT_ID,
)

logger.info(key='rdt_log', data=person_details_for_test)

# if positive, refer for a confirmatory test at level 1a
Expand Down
Loading

0 comments on commit 9561a7a

Please sign in to comment.