From 1b3c72e41a708144fda2bd3af5806d2c4dce1c37 Mon Sep 17 00:00:00 2001 From: Tim Hallett Date: Wed, 6 Apr 2022 16:51:21 +0100 Subject: [PATCH 001/755] add test_wasting.py --- tests/test_wasting.py | 930 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 930 insertions(+) create mode 100644 tests/test_wasting.py diff --git a/tests/test_wasting.py b/tests/test_wasting.py new file mode 100644 index 0000000000..53239a6dcf --- /dev/null +++ b/tests/test_wasting.py @@ -0,0 +1,930 @@ +""" + Basic tests for the Wasting Module + """ + import os + from pathlib import Path + + import numpy as np + import pandas as pd + import pytest + + from tlo import Date, Simulation, logging + from tlo.analysis.utils import parse_log_file + from tlo.lm import LinearModel, LinearModelType + from tlo.methods import ( + demography, + wasting, + dx_algorithm_child, + enhanced_lifestyle, + healthburden, + healthseekingbehaviour, + healthsystem, + simplified_births, + symptommanager, + ) + + from tlo.methods.healthsystem import HSI_Event + + from tlo.methods.wasting import ( + AcuteMalnutritionDeathPollingEvent, + SevereAcuteMalnutritionDeathEvent, + ProgressionSevereWastingEvent, + WastingNaturalRecoveryEvent, + ClinicalAcuteMalnutritionRecoveryEvent, + WastingPollingEvent, + UpdateToMAM, + HSI_supplementary_feeding_programme_for_MAM, + HSI_outpatient_therapeutic_programme_for_SAM, + HSI_inpatient_care_for_complicated_SAM, + PropertiesOfOtherModules + ) + + # Path to the resource files used by the disease and intervention methods + resourcefilepath = Path(os.path.dirname(__file__)) / '../resources' + + # Default date for the start of simulations + start_date = Date(2010, 1, 1) + + + def get_sim(tmpdir): + """Return simulation objection with Wasting and other necessary modules registered.""" + sim = Simulation(start_date=start_date, seed=0, show_progress_bar=False, log_config={ + 'filename': 'tmp', + 'directory': tmpdir, + 'custom_levels': { + "*": logging.WARNING, + "tlo.methods.wasting": logging.INFO} + }) + + sim.register(demography.Demography(resourcefilepath=resourcefilepath), + enhanced_lifestyle.Lifestyle(resourcefilepath=resourcefilepath), + healthsystem.HealthSystem(resourcefilepath=resourcefilepath, disable=True), + symptommanager.SymptomManager(resourcefilepath=resourcefilepath), + healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resourcefilepath), + healthburden.HealthBurden(resourcefilepath=resourcefilepath), + simplified_births.SimplifiedBirths(resourcefilepath=resourcefilepath), + wasting.Wasting(resourcefilepath=resourcefilepath), + wasting.PropertiesOfOtherModules(), + dx_algorithm_child.DxAlgorithmChild(resourcefilepath=resourcefilepath) + ) + return sim + + + def check_dtypes(sim): + # Check types of columns + df = sim.population.props + orig = sim.population.new_row + assert (df.dtypes == orig.dtypes).all() + + + def check_configuration_of_properties(sim): + # check that the properties are ok: + + df = sim.population.props + + # Those that were never wasted, should have normal WHZ score: + assert (df.loc[~df.un_ever_wasted & ~df.date_of_birth.isna(), 'un_WHZ_category'] == 'WHZ>=-2').all().all() + + # Those that were never wasted and not clinically malnourished, + # should have not_applicable/null values for all the other properties: + # assert pd.isnull(df.loc[(~df.un_ever_wasted & ~df.date_of_birth.isna() & + # (df.un_clinical_acute_malnutrition == 'well')), + # ['un_last_wasting_date_of_onset', + # 'un_sam_death_date' + # ] + # ]).all().all() + + # # Those that were ever wasted, should have a WHZ score below <-2 + # assert (df.loc[df.un_ever_wasted, 'un_WHZ_category'] != 'WHZ>=-2').all().all() + # + # # Those that had wasting and no treatment, should have either a recovery date or a death_date + # # (but not both) + # has_recovery_date = ~pd.isnull(df.loc[df.un_ever_wasted & pd.isnull(df.un_acute_malnutrition_tx_start_date), + # 'un_am_recovery_date']) + # has_death_date = ~pd.isnull(df.loc[df.un_ever_wasted & pd.isnull(df.un_acute_malnutrition_tx_start_date), + # 'un_sam_death_date']) + + # has_recovery_date_or_death_date = has_recovery_date | has_death_date + # has_both_recovery_date_and_death_date = has_recovery_date & has_death_date + # # assert has_recovery_date_or_death_date.all() + # assert not has_both_recovery_date_and_death_date.any() + + # Those for whom the death date has past should be dead + assert not df.loc[df.un_ever_wasted & (df['un_sam_death_date'] < sim.date), 'is_alive'].any() + assert not df.loc[(df.un_clinical_acute_malnutrition == 'SAM') & ( + df['un_sam_death_date'] < sim.date), 'is_alive'].any() + + # Check that those in a current episode have symptoms of diarrhoea [caused by the diarrhoea module] + # but not others (among those who are alive) + has_symptoms_of_wasting = set(sim.modules['SymptomManager'].who_has('weight_loss')) + has_symptoms = set([p for p in has_symptoms_of_wasting if + 'Wasting' in sim.modules['SymptomManager'].causes_of(p, 'weight_loss') + ]) + + in_current_episode_before_recovery = \ + df.is_alive & \ + df.un_ever_wasted & \ + (df.un_last_wasting_date_of_onset <= sim.date) & \ + (sim.date <= df.un_am_recovery_date) + set_of_person_id_in_current_episode_before_recovery = set( + in_current_episode_before_recovery[in_current_episode_before_recovery].index + ) + + in_current_episode_before_death = \ + df.is_alive & \ + df.un_ever_wasted & \ + (df.un_last_wasting_date_of_onset <= sim.date) & \ + (sim.date <= df.un_sam_death_date) + set_of_person_id_in_current_episode_before_death = set( + in_current_episode_before_death[in_current_episode_before_death].index + ) + + in_current_episode_before_cure = \ + df.is_alive & \ + df.un_ever_wasted & \ + (df.un_last_wasting_date_of_onset <= sim.date) & \ + (df.un_acute_malnutrition_tx_start_date <= sim.date) & \ + pd.isnull(df.un_am_recovery_date) & \ + pd.isnull(df.un_sam_death_date) + set_of_person_id_in_current_episode_before_cure = set( + in_current_episode_before_cure[in_current_episode_before_cure].index + ) + + assert set() == set_of_person_id_in_current_episode_before_recovery.intersection( + set_of_person_id_in_current_episode_before_death + ) + + set_of_person_id_in_current_episode = set_of_person_id_in_current_episode_before_recovery.union( + set_of_person_id_in_current_episode_before_death, set_of_person_id_in_current_episode_before_cure + ) + assert set_of_person_id_in_current_episode == has_symptoms + + + def test_basic_run(tmpdir): + """Short run of the module using default parameters with check on dtypes""" + dur = pd.DateOffset(months=3) + popsize = 1000 + sim = get_sim(tmpdir) + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + check_dtypes(sim) + check_configuration_of_properties(sim) + + + def test_wasting_polling(tmpdir): + """Check polling events leads to incident cases""" + # get simulation object: + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + # Make incidence of wasting very high : + params = sim.modules['Wasting'].parameters + for p in params: + if p.startswith('base_inc_rate_wasting_by_agegp'): + params[p] = [3 * v for v in params[p]] + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Run polling event: check that a severe incident case is produced: + polling = WastingPollingEvent(sim.modules['Wasting']) + polling.apply(sim.population) + assert len([q for q in sim.event_queue.queue if isinstance(q[2], ProgressionSevereWastingEvent)]) > 0 + + # Check properties of this individual: should now be moderately wasted + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + person = df.loc[person_id] + assert person['un_ever_wasted'] == True + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + + + def test_recovery_moderate_wasting(tmpdir): + """Check natual recovery of moderate wasting """ + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 0% death rate by replacing with empty linear model 0.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 0.0) + + # increase incidence of wasting + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # remove progression to severe wasting + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 0.0) + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: should now be moderately wasted + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Check that there is a WastingNaturalRecoveryEvent scheduled for this person: + recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], WastingNaturalRecoveryEvent) + ][0] + date_of_scheduled_recov = recov_event_tuple[0] + recov_event = recov_event_tuple[1] + assert date_of_scheduled_recov > sim.date + + # Run the recovery event: + sim.date = date_of_scheduled_recov + recov_event.apply(person_id=person_id) + + # Check properties of this individual + person = df.loc[person_id] + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert person['un_am_recovery_date'] == sim.date + assert pd.isnull(person['un_sam_death_date']) + + + def test_recovery_severe_wasting(tmpdir): + """ Check natural recovery to MAM by removing death rate for those with severe wasting, + and check the onset of symptoms with SAM and revolving of symptoms when recovered to MAM """ + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 0% death rate by replacing with empty linear model 0.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 0.0) + + # increase incidence of wasting and progression to severe + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: should now be moderately wasted + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Check that there is a ProgressionSevereWastingEvent scheduled for this person: + progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ProgressionSevereWastingEvent) + ][0] + date_of_scheduled_progression = progression_event_tuple[0] + progression_event = progression_event_tuple[1] + assert date_of_scheduled_progression > sim.date + + # Run the progression to severe wasting event: + sim.date = date_of_scheduled_progression + progression_event.apply(person_id=person_id) + + # Check that they have some symptoms caused by Wasting (SAM only) + assert 0 < len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) + + # Check properties of this individual: (should now be severely wasted and without a scheduled death date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == 'WHZ<-3' + assert person['un_clinical_acute_malnutrition'] == 'SAM' + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Run Death Polling Polling event to apply death: + death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) + death_polling.apply(sim.population) + + # Check that there is a UpdateToMAM scheduled for this person: + recovery_to_mam_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], UpdateToMAM) + ][0] + print(sim.find_events_for_person(person_id)) + date_of_scheduled_recovery_to_mam = recovery_to_mam_event_tuple[0] + recovery_to_mam_event = recovery_to_mam_event_tuple[1] + assert date_of_scheduled_recovery_to_mam > sim.date + + # Run a Recovery SAM to MAM Event + sim.date = date_of_scheduled_recovery_to_mam + recovery_to_mam_event.apply(person_id=person_id) + + # Check properties of this individual + person = df.loc[person_id] + assert person['un_WHZ_category'] != 'WHZ<-3' + assert (person['un_am_MUAC_category'] == '115-<125mm' or person['un_WHZ_category'] == '-3<=WHZ<-2') + assert pd.isnull(person['un_sam_death_date']) + + # check they have no symptoms: + assert 0 == len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) + + + def test_nat_hist_death(tmpdir): + """Check: Wasting onset --> death""" + """ Check if the risk of death is 100% does everyone with SAM die? """ + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 100% death rate by replacing with empty linear model 1.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # increase incidence of wasting and progression to severe + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # Get the children to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Check that there is a ProgressionSevereWastingEvent scheduled for this person: + progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ProgressionSevereWastingEvent) + ][0] + date_of_scheduled_progression = progression_event_tuple[0] + progression_event = progression_event_tuple[1] + assert date_of_scheduled_progression > sim.date + + # Run the progression to severe wasting event: + sim.date = date_of_scheduled_progression + progression_event.apply(person_id=person_id) + + # Check properties of this individual: (should now be severely wasted and without a scheduled death date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == 'WHZ<-3' + assert person['un_clinical_acute_malnutrition'] == 'SAM' + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Run Death Polling Polling event to apply death: + death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) + death_polling.apply(sim.population) + + # Check that there is a SevereAcuteMalnutritionDeathEvent scheduled for this person: + death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) + ][0] + date_of_scheduled_death = death_event_tuple[0] + death_event = death_event_tuple[1] + assert date_of_scheduled_death > sim.date + + # Run the death event: + sim.date = date_of_scheduled_death + death_event.apply(person_id=person_id) + + # Check properties of this individual: (should now be dead) + person = df.loc[person_id] + assert not pd.isnull(person['un_sam_death_date']) + assert person['un_sam_death_date'] == sim.date + assert not person['is_alive'] + + + def test_nat_hist_cure_if_recovery_scheduled(tmpdir): + """Show that if a cure event is run before when a person was going to recover naturally, it cause the episode to + end earlier.""" + + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 0% death rate by replacing with empty linear model 0.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 0.0) + + # increase incidence of wasting + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # decrease progression to severe of wasting - so all children stay in moderate wasting state only + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 0.0) + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: (should now be moderately wasted without progression to severe) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + print(sim.find_events_for_person(person_id)) + + # Check that there is a WastingNaturalRecoveryEvent scheduled for this person: + recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], WastingNaturalRecoveryEvent) + ][0] + date_of_scheduled_recov = recov_event_tuple[0] + recov_event = recov_event_tuple[1] + assert date_of_scheduled_recov > sim.date + + # Run a Cure Event + cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) + cure_event.apply(person_id=person_id) + + # Check that the person is not wasted and is alive still: + person = df.loc[person_id] + assert person['is_alive'] + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert not pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Run the recovery event that was originally scheduled - this should have no effect + sim.date = date_of_scheduled_recov + recov_event.apply(person_id=person_id) + person = df.loc[person_id] + assert person['is_alive'] + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert not pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + + def test_nat_hist_cure_if_death_scheduled(tmpdir): + """Show that if a cure event is run before when a person was going to die, it cause the episode to end without + the person dying.""" + + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 100% death rate by replacing with empty linear model 1.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # increase incidence of wasting and progression to severe + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + # increase parameters in moderate wasting for clinical SAM (MUAC and oedema) to be polled for death + params = sim.modules['Wasting'].parameters + params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = [5 * params['proportion_-3<=WHZ<-2_with_MUAC<115mm']] + params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] = [params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] / 5] + params['proportion_oedema_with_WHZ<-2'] = 0.9 + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Check that there is a ProgressionSevereWastingEvent scheduled for this person: + progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ProgressionSevereWastingEvent) + ][0] + date_of_scheduled_progression = progression_event_tuple[0] + progression_event = progression_event_tuple[1] + assert date_of_scheduled_progression > sim.date + + # Run the progression to severe wasting event: + sim.date = date_of_scheduled_progression + progression_event.apply(person_id=person_id) + + # Check properties of this individual: (should now be severely wasted and without a scheduled death date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == 'WHZ<-3' + assert person['un_clinical_acute_malnutrition'] == 'SAM' + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Run Death Polling Polling event to apply death: + death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) + death_polling.apply(sim.population) + + # Check that there is a SevereAcuteMalnutritionDeathEvent scheduled for this person: + death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) + ][0] + date_of_scheduled_death = death_event_tuple[0] + death_event = death_event_tuple[1] + assert date_of_scheduled_death > sim.date + + # Run a Cure Event now + cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) + cure_event.apply(person_id=person_id) + + # Check that the person is not wasted and is alive still: + person = df.loc[person_id] + assert person['is_alive'] + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert not pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Run the death event that was originally scheduled - this should have no effect and the person should not die + sim.date = date_of_scheduled_death + death_event.apply(person_id=person_id) + person = df.loc[person_id] + assert person['is_alive'] + + + def test_treatment(tmpdir): + """ Test that providing a treatment prevent death and causes there to be a + CureEvent (ClinicalAcuteMalnutritionRecoveryEvent) Scheduled """ + """ + This test sets the linear model of acute_malnutrition_recovery_based_on_interventions to be 1.0 (100% cure rate), + when this lm is called in the do_when_am_treatment function (usually called in HSIs), 100% cure rate schedules the + ClinicalAcuteMalnutritionRecoveryEvent (CureEvent). + Death is prevented. ---> check + """ + # TODO: CHECK THIS - MAYBE NOT NEEDED + + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 100% death rate by replacing with empty linear model 1.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # increase incidence of wasting and progression to severe + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # increase parameters in moderate wasting for clinical SAM (MUAC and oedema) to be polled for death + params = sim.modules['Wasting'].parameters + params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = [5 * params['proportion_-3<=WHZ<-2_with_MUAC<115mm']] + params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] = [params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] / 5] + params['proportion_oedema_with_WHZ<-2'] = 0.9 + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Check that there is a ProgressionSevereWastingEvent scheduled for this person: + progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ProgressionSevereWastingEvent) + ][0] + date_of_scheduled_progression = progression_event_tuple[0] + progression_event = progression_event_tuple[1] + assert date_of_scheduled_progression > sim.date + + # Run the progression to severe wasting event: + sim.date = date_of_scheduled_progression + progression_event.apply(person_id=person_id) + + # Check properties of this individual: (should now be severely wasted and without a scheduled death date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == 'WHZ<-3' + assert person['un_clinical_acute_malnutrition'] == 'SAM' + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Run Death Polling event to apply death: + death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) + death_polling.apply(sim.population) + + # Check that there is a SevereAcuteMalnutritionDeathEvent scheduled for this person: + death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) + ][0] + date_of_scheduled_death = death_event_tuple[0] + death_event = death_event_tuple[1] + assert date_of_scheduled_death > sim.date + + # # change coverage and treatment effectiveness set to be 100% + # params['coverage_supplementary_feeding_program'] = 1.0 + # params['coverage_outpatient_therapeutic_care'] = 1.0 + # params['coverage_inpatient_care'] = 1.0 + # params['recovery_rate_with_soy_RUSF'] = 1.0 + # params['recovery_rate_with_CSB++'] = 1.0 + # params['recovery_rate_with_standard_RUTF'] = 1.0 + # params['recovery_rate_with_inpatient_care'] = 1.0 + + # Make 100% death rate by replacing with empty linear model 1.0 + for am in ['MAM', 'SAM']: + sim.modules['Wasting'].acute_malnutrition_recovery_based_on_interventions[am] = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # Run the 'do_when_am_treatment' function + interventions = ['SFP', 'OTC', 'ITC'] + for int in interventions: + sim.modules['Wasting'].do_when_am_treatment(person_id=person_id, intervention=int) + + # Run the death event that was originally scheduled - this should have no effect and the person should not die + sim.date = date_of_scheduled_death + death_event.apply(person_id=person_id) + person = df.loc[person_id] + assert person['is_alive'] + + # print(sim.find_events_for_person(person_id)) + + # Check that a CureEvent has been scheduled + cure_event = [event_tuple[1] for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] + + # Run the CureEvent + cure_event.apply(person_id=person_id) + + # Check that the person is not infected and is alive still: + person = df.loc[person_id] + assert person['is_alive'] + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert not pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + + def test_use_of_HSI_for_MAM(tmpdir): + """ Check that the HSIs works""" + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 100% death rate by replacing with empty linear model 1.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # increase incidence of wasting + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # reduce progression to severe wasting + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 0.0) + + # decrease MUAC and oedema parameters in moderate wasting for clinical SAM + params = sim.modules['Wasting'].parameters + params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = 0.0 # no SAM with moderate wasting + params['proportion_oedema_with_WHZ<-2'] = 0.0 # no SAM based on oedema + params['prevalence_nutritional_oedema'] = 0.0 # no SAM based on oedema + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_clinical_acute_malnutrition'] == 'MAM' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + # Check not on treatment: + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + + # Run the HSI event + hsi = HSI_supplementary_feeding_programme_for_MAM(person_id=person_id, module=sim.modules['Wasting']) + hsi.run(squeeze_factor=0.0) + + # Check that person is now on treatment: + assert sim.date == df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + + # Check that a CureEvent has been scheduled + cure_event = [event_tuple[1] for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] + + # Run the CureEvent + cure_event.apply(person_id=person_id) + + # Check that the person is cured and is alive still: + person = df.loc[person_id] + assert person['is_alive'] + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert person['un_clinical_acute_malnutrition'] == 'well' + assert not pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + + def test_use_of_HSI_for_SAM(tmpdir): + """ Check that the HSI_outpatient_therapeutic_programme_for_SAM and HSI_inpatient_care_for_complicated_SAM work""" + + def test_use_of_HSI_by_complication(complications): + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 100% death rate by replacing with empty linear model 1.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # Make 100% treatment effectiveness by replacing with empty linear model 1.0 + for am in ['MAM', 'SAM']: + sim.modules['Wasting'].acute_malnutrition_recovery_based_on_interventions[am] = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # increase incidence of wasting and progression to severe + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # remove the probability of complications in SAM + params = sim.modules['Wasting'].parameters + if complications: + params['prob_complications_in_SAM'] = 1.0 # only SAM with complications + else: + params['prob_complications_in_SAM'] = 0.0 # no SAM with complications + + # # change coverage and treatment effectiveness set to be 100% + # params['coverage_supplementary_feeding_program'] = 1.0 + # params['coverage_outpatient_therapeutic_care'] = 1.0 + # params['coverage_inpatient_care'] = 1.0 + # params['recovery_rate_with_soy_RUSF'] = 1.0 + # params['recovery_rate_with_CSB++'] = 1.0 + # params['recovery_rate_with_standard_RUTF'] = 1.0 + # params['recovery_rate_with_inpatient_care'] = 1.0 + + # Make 100% death rate by replacing with empty linear model 1.0 + sim.modules['Wasting'].acute_malnutrition_recovery_based_on_interventions['SAM'] = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + # Check not on treatment: + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + + # Check that there is a ProgressionSevereWastingEvent scheduled for this person: + progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ProgressionSevereWastingEvent) + ][0] + date_of_scheduled_progression = progression_event_tuple[0] + progression_event = progression_event_tuple[1] + assert date_of_scheduled_progression > sim.date + + # Run the progression to severe wasting event: + sim.date = date_of_scheduled_progression + progression_event.apply(person_id=person_id) + + # Check properties of this individual: (should now be severely wasted and without a scheduled death date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == 'WHZ<-3' + assert person['un_clinical_acute_malnutrition'] == 'SAM' + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Run the HSI event + if complications: + hsi = HSI_inpatient_care_for_complicated_SAM(person_id=person_id, module=sim.modules['Wasting']) + hsi.run(squeeze_factor=0.0) + else: + hsi = HSI_outpatient_therapeutic_programme_for_SAM(person_id=person_id, module=sim.modules['Wasting']) + hsi.run(squeeze_factor=0.0) + + # Check that person is now on treatment: + assert sim.date == df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + + print(sim.find_events_for_person(person_id)) + + # Check that a CureEvent has been scheduled + cure_event = [event_tuple[1] for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] + + # Run the CureEvent + cure_event.apply(person_id=person_id) + + # Check that the person is cured and is alive still: + person = df.loc[person_id] + assert person['is_alive'] + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert person['un_clinical_acute_malnutrition'] == 'well' + assert not pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + test_use_of_HSI_by_complication(complications=True) + test_use_of_HSI_by_complication(complications=False) From 7c57737798a0045587541220dd44555374160157 Mon Sep 17 00:00:00 2001 From: Tim Hallett Date: Wed, 6 Apr 2022 17:02:30 +0100 Subject: [PATCH 002/755] add wasting.py --- src/tlo/methods/wasting.py | 1655 +++++++++++++++++++++++++++++++++++- 1 file changed, 1644 insertions(+), 11 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index c8d3517ad5..bd2fde898e 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1,4 +1,22 @@ -"""Placeholder for childhood wasting module.""" +"""Childhood wasting module""" + +import copy +from pathlib import Path +from scipy.stats import norm + +import numpy as np +import pandas as pd + +from tlo import DateOffset, Module, Parameter, Property, Types, logging +from tlo.events import Event, IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent +from tlo.lm import LinearModel, LinearModelType, Predictor +from tlo.methods import Metadata, demography +from tlo.methods.healthsystem import HSI_Event +from tlo.methods.symptommanager import Symptom +from tlo.methods.causes import Cause + +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) from tlo import Module, Property, Types, logging @@ -6,36 +24,1651 @@ logger.setLevel(logging.INFO) +# --------------------------------------------------------------------------------------------------------- +# MODULE DEFINITIONS +# --------------------------------------------------------------------------------------------------------- + + class Wasting(Module): - """Placeholder for childhood wasting module. + """ + This module applies the prevalence of wasting at the population-level, + based on the Malawi DHS Survey 2015-2016. + The definitions: + - moderate wasting: height-for-age Z-score (WHZ) <-2 SD from the reference mean + - severe wasting: height-for-age Z-score (WHZ) <-3 SD from the reference mean - Provides dummy values for properties required by other modules. """ INIT_DEPENDENCIES = {'Demography'} + METADATA = { + Metadata.DISEASE_MODULE, + Metadata.USES_SYMPTOMMANAGER, + Metadata.USES_HEALTHSYSTEM, + Metadata.USES_HEALTHBURDEN + } + + # Declare Causes of Death + CAUSES_OF_DEATH = { + 'SAM': Cause(gbd_causes='Protein-energy malnutrition', label='Childhood Wasting') + } + + # Declare Causes of Death and Disability + CAUSES_OF_DISABILITY = { + 'SAM': Cause(gbd_causes='Protein-energy malnutrition', label='Childhood Wasting') + } + + wasting_states = ['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2'] + + PARAMETERS = { + # prevalence of wasting by age group + 'prev_WHZ_distribution_age_0_5mo': Parameter( + Types.LIST, 'distribution of WHZ among less than 6 months of age in 2015'), + 'prev_WHZ_distribution_age_6_11mo': Parameter( + Types.LIST, 'distribution of WHZ among 6 months and 1 year of age in 2015'), + 'prev_WHZ_distribution_age_12_23mo': Parameter( + Types.LIST, 'distribution of WHZ among 1 year olds in 2015'), + 'prev_WHZ_distribution_age_24_35mo': Parameter( + Types.LIST, 'distribution of WHZ among 2 year olds in 2015'), + 'prev_WHZ_distribution_age_36_47mo': Parameter( + Types.LIST, 'distribution of WHZ among 3 year olds in 2015'), + 'prev_WHZ_distribution_age_48_59mo': Parameter( + Types.LIST, 'distribution of WHZ among 4 year olds in 2015'), + # effect of risk factors on wasting prevalence + 'or_wasting_hhwealth_Q5': Parameter( + Types.REAL, 'odds ratio of wasting if household wealth is poorest Q5, ref group Q1'), + 'or_wasting_hhwealth_Q4': Parameter( + Types.REAL, 'odds ratio of wasting if household wealth is poorer Q4, ref group Q1'), + 'or_wasting_hhwealth_Q3': Parameter( + Types.REAL, 'odds ratio of wasting if household wealth is middle Q3, ref group Q1'), + 'or_wasting_hhwealth_Q2': Parameter( + Types.REAL, 'odds ratio of wasting if household wealth is richer Q2, ref group Q1'), + 'or_wasting_preterm_and_AGA': Parameter( + Types.REAL, 'odds ratio of wasting if born preterm and adequate for gestational age'), + 'or_wasting_SGA_and_term': Parameter( + Types.REAL, 'odds ratio of wasting if born term and small for geatational age'), + 'or_wasting_SGA_and_preterm': Parameter( + Types.REAL, 'odds ratio of wasting if born preterm and small for gestational age'), + # incidence parameters + 'base_inc_rate_wasting_by_agegp': Parameter( + Types.LIST, 'List with baseline incidence of wasting by age group'), + 'rr_wasting_preterm_and_AGA': Parameter( + Types.REAL, 'relative risk of wasting if born preterm and adequate for gestational age'), + 'rr_wasting_SGA_and_term': Parameter( + Types.REAL, 'relative risk of wasting if born term and small for geatational age'), + 'rr_wasting_SGA_and_preterm': Parameter( + Types.REAL, 'relative risk of wasting if born preterm and small for gestational age'), + 'rr_wasting_wealth_level': Parameter( + Types.REAL, 'relative risk of wasting per 1 unit decrease in wealth level'), + 'min_days_duration_of_wasting': Parameter( + Types.REAL, 'minimum duration in days of wasting (MAM and SAM)'), + 'average_duration_of_untreated_MAM': Parameter( + Types.REAL, 'average duration of untreated MAM'), + # progression to severe parameters + 'progression_severe_wasting_by_agegp': Parameter( + Types.LIST, 'List with progression rates to severe wasting by age group'), + 'average_duration_of_untreated_SAM': Parameter( + Types.REAL, 'average duration of untreated SAM'), + 'prob_complications_in_SAM': Parameter( + Types.REAL, 'probability of medical complications in SAM '), + # recovery parameters + 'recovery_rate_with_standard_RUTF': Parameter( + Types.REAL, 'probability of recovery from wasting following treatment with standard RUTF'), + 'recovery_rate_with_soy_RUSF': Parameter( + Types.REAL, 'probability of recovery from wasting following treatment with soy RUSF'), + 'recovery_rate_with_CSB++': Parameter( + Types.REAL, 'probability of recovery from wasting following treatment with CSB++'), + 'recovery_rate_with_inpatient_care': Parameter( + Types.REAL, 'probability of recovery from wasting following treatment with inpatient care'), + # MUAC distributions + 'MUAC_distribution_WHZ<-3': Parameter( + Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ<-3'), + 'MUAC_distribution_-3<=WHZ<-2': Parameter( + Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for -3<=WHZ<-2'), + 'MUAC_distribution_WHZ>=-2': Parameter( + Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ>=-2'), + + 'proportion_WHZ<-3_with_MUAC<115mm': Parameter( + Types.REAL, 'proportion of severe weight-for-height Z-score with MUAC<115mm'), + 'proportion_-3<=WHZ<-2_with_MUAC<115mm': Parameter( + Types.REAL, 'proportion of moderate weight-for-height Z-score with MUAC<115mm'), + 'proportion_-3<=WHZ<-2_with_MUAC_115-<125mm': Parameter( + Types.REAL, 'proportion of moderate weight-for-height Z-score with MUAC between 115mm and 125mm'), + 'proportion_mam_with_MUAC_115-<125mm_and_normal_whz': Parameter( + Types.REAL, 'proportion of mam cases with MUAC between 115mm and 125mm and normal/mild WHZ'), + 'proportion_mam_with_MUAC_115-<125mm_and_-3<=WHZ<-2': Parameter( + Types.REAL, 'proportion of mam cases with both MUAC between 115mm and 125mm and moderate wasting'), + 'proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC': Parameter( + Types.REAL, 'proportion of mam cases with moderate wasting and normal MUAC'), + + # bilateral oedema + 'prevalence_nutritional_oedema': Parameter( + Types.REAL, 'prevalence of nutritional oedema in children under 5 in Malawi'), + 'proportion_oedema_with_WHZ<-2': Parameter( + Types.REAL, 'proportion of oedematous malnutrition with concurrent wasting'), + # death CFR, risk factors + 'base_death_rate_untreated_SAM': Parameter( + Types.REAL, 'baseline death rate of untreated SAM'), + 'rr_SAM_death_with_complications': Parameter( + Types.REAL, 'relative rate of death for complicated SAM'), + 'rr_SAM_death_WHZ<-3_only': Parameter( + Types.REAL, 'relative risk of death from SAM if indices of WHZ<-3, compared to MUAC<115mm'), + 'rr_SAM_death_both_WHZ<-3_&_MUAC<115mm': Parameter( + Types.REAL, 'relative risk of death from SAM if both indices WHZ<-3 & MUAC<115mm are present, ' + 'compared to MUAC<115mm alone'), + 'rr_SAM_death_kwashiorkor_only': Parameter( + Types.REAL, 'relative risk of death from SAM if bilateral oedema present (kwashiorkor), ' + 'compared to MUAC<115mm alone'), + 'rr_SAM_death_kwashiorkor_MUAC<115mm_only': Parameter( + Types.REAL, 'relative risk of death from SAM if bilateral oedema present and MUAC<115mm, ' + 'compared to MUAC<115mm alone'), + 'rr_SAM_death_kwashiorkor_WHZ<-3_only': Parameter( + Types.REAL, 'relative risk of death from SAM if bilateral oedema present and WHZ<-3, ' + 'compared to MUAC<115mm alone'), + 'rr_SAM_death_kwashiorkor_both_WHZ<-3_&_MUAC<115mm': Parameter( + Types.REAL, 'relative risk of death from SAM if bilateral oedema present, WHZ<-3 and MUAC<115mm, ' + 'compared to MUAC<115mm alone'), + # treatment parameters + 'coverage_supplementary_feeding_program': Parameter( + Types.REAL, 'coverage of supplementary feeding program for MAM in health centres'), + 'coverage_outpatient_therapeutic_care': Parameter( + Types.REAL, 'coverage of outpatient therapeutic care for SAM in health centres'), + 'coverage_inpatient_care': Parameter( + Types.REAL, 'coverage of inpatient care for complicated SAM in hospitals'), + } + PROPERTIES = { - 'un_clinical_acute_malnutrition': Property(Types.CATEGORICAL, - 'temporary property', categories=['MAM', 'SAM', 'well']), - 'un_ever_wasted': Property(Types.BOOL, 'temporary property') + # Properties related to wasting + 'un_ever_wasted': Property(Types.BOOL, 'had wasting before WHZ <-2'), + 'un_WHZ_category': Property(Types.CATEGORICAL, 'height-for-age z-score group', + categories=['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2']), + 'un_last_wasting_date_of_onset': Property(Types.DATE, 'date of onset of lastest wasting episode'), + + # Properties related to clinical acute malnutrition + 'un_clinical_acute_malnutrition': Property(Types.CATEGORICAL, 'clinical acute malnutrition state based on WHZ', + categories=['MAM', 'SAM'] + ['well']), + 'un_am_bilateral_oedema': Property(Types.BOOL, 'bilateral oedema present in wasting'), + 'un_am_MUAC_category': Property(Types.CATEGORICAL, 'MUAC measurement categories', + categories=['<115mm', '115-<125mm', '>=125mm']), + 'un_sam_with_complications': Property(Types.BOOL, 'medical complications in SAM'), + 'un_sam_death_date': Property(Types.DATE, 'death date from severe acute malnutrition'), + 'un_am_recovery_date': Property(Types.DATE, 'recovery date from acute malnutrition'), + 'un_am_discharge_date': Property(Types.DATE, 'discharge date from treatment of MAM/ SAM'), + 'un_acute_malnutrition_tx_start_date': Property(Types.DATE, 'intervention start date'), + 'un_am_treatment_type': Property(Types.CATEGORICAL, 'treatment types for acute malnutrition', + categories=['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care'] + + ['none', 'not_applicable']), } def __init__(self, name=None, resourcefilepath=None): - super().__init__(name=name) + super().__init__(name) self.resourcefilepath = resourcefilepath + # Store the symptoms that this module will use: + self.symptoms = { + 'palmar_pallor', + 'weight_loss', + 'poor_appetite', + 'lethargic', + # 'dehydration' + } + + # dict to hold counters for the number of episodes by wasting-type and age-group + blank_counter = dict(zip(self.wasting_states, [list() for _ in self.wasting_states])) + self.wasting_incident_case_tracker_blank = { + '0y': copy.deepcopy(blank_counter), + '1y': copy.deepcopy(blank_counter), + '2y': copy.deepcopy(blank_counter), + '3y': copy.deepcopy(blank_counter), + '4y': copy.deepcopy(blank_counter), + '5+y': copy.deepcopy(blank_counter) + } + self.wasting_incident_case_tracker = copy.deepcopy(self.wasting_incident_case_tracker_blank) + + zeros_counter = dict(zip(self.wasting_states, [0] * len(self.wasting_states))) + self.wasting_incident_case_tracker_zeros = { + '0y': copy.deepcopy(zeros_counter), + '1y': copy.deepcopy(zeros_counter), + '2y': copy.deepcopy(zeros_counter), + '3y': copy.deepcopy(zeros_counter), + '4y': copy.deepcopy(zeros_counter), + '5+y': copy.deepcopy(zeros_counter) + } + + # dict to hold the DALY weights + self.daly_wts = dict() + + # --------------------- linear models of the natural history --------------------- # + + # set the linear model equations for prevalence and incidence + self.prevalence_equations_by_age = dict() + self.wasting_incidence_equation = dict() + + # set the linear model for progression to severe wasting + self.severe_wasting_progression_equation = dict() + + # set the linear model for death from severe acute malnutrition + self.sam_death_equation = dict() + + # --------------------- linear models following HSI interventions --------------------- # + + # set the linear models for MAM and SAM recovery by intervention + self.acute_malnutrition_recovery_based_on_interventions = dict() + def read_parameters(self, data_folder): - pass + """ + :param data_folder: path of a folder supplied to the Simulation containing data files. + Typically modules would read a particular file within here. + :return: + """ + # Update parameters from the resource dataframe + # Read parameters from the resourcefile + self.load_parameters_from_dataframe( + pd.read_excel(Path(self.resourcefilepath) / 'ResourceFile_Undernutrition.xlsx', + sheet_name='Parameter_values_AM')) + p = self.parameters + + # Check that every value has been read-in successfully + for param_name, param_type in self.PARAMETERS.items(): + assert param_name in p, f'Parameter "{param_name}" is not read in correctly from the resourcefile.' + assert param_name is not None, f'Parameter "{param_name}" is not read in correctly from the resourcefile.' + assert isinstance(p[param_name], + param_type.python_type), f'Parameter "{param_name}" is not read in correctly from the ' \ + f'resourcefile.' + + # Declare symptoms that this module will cause and which are not included in the generic symptoms: + generic_symptoms = self.sim.modules['SymptomManager'].generic_symptoms + for symptom_name in self.symptoms: + if symptom_name not in generic_symptoms: + self.sim.modules['SymptomManager'].register_symptom( + Symptom(name=symptom_name) # (give non-generic symptom 'average' healthcare seeking) + ) + + def muac_cutoff_by_WHZ(self, idx, whz): + """ + Proportion of MUAC<115mm in WHZ<-3 and -3<=WHZ<-2, + and proportion of wasted children with oedematous malnutrition (Kwashiokor, marasmic-kwashiorkor) + :param idx: index of children ages 6-59 months or person_id + :param whz: + :return: + """ + df = self.sim.population.props + p = self.parameters + + # ---------- MUAC <115mm in severe wasting (WHZ<-3) and moderate (-3<=WHZ<-2) ---------- + if whz == 'WHZ<-3': + # apply probability of MUAC<115mm in severe wasting + low_muac_in_severe_wasting = self.rng.random_sample(size=len(idx)) < p['proportion_WHZ<-3_with_MUAC<115mm'] + df.loc[idx[low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '<115mm' + # other severe wasting will have MUAC between 115-<125mm + df.loc[idx[low_muac_in_severe_wasting == False], 'un_am_MUAC_category'] = '115-<125mm' + + if whz == '-3<=WHZ<-2': + # apply probability of MUAC<115mm in moderate wasting + low_muac_in_moderate_wasting = self.rng.random_sample(size=len(idx)) < p[ + 'proportion_-3<=WHZ<-2_with_MUAC<115mm'] + df.loc[idx[low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = '<115mm' + # apply probability of MUAC between 115-<125mm in moderate wasting + moderate_low_muac_in_moderate_wasting = self.rng.random_sample(size=len( + idx[low_muac_in_moderate_wasting == False])) < p['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] + df.loc[idx[low_muac_in_moderate_wasting == False][moderate_low_muac_in_moderate_wasting], + 'un_am_MUAC_category'] = '115-<125mm' + # other moderate wasting will have normal MUAC + df.loc[idx[low_muac_in_moderate_wasting == False][moderate_low_muac_in_moderate_wasting == False], + 'un_am_MUAC_category'] = '>=125mm' + + if whz == 'WHZ>=-2': + # Give MUAC distribution for WHZ>=-2 ('well' group) --------- + muac_distribution_in_well_group = norm(loc=p['MUAC_distribution_WHZ>=-2'][0], + scale=p['MUAC_distribution_WHZ>=-2'][1]) + # get probability of MUAC <115mm + probability_over_or_equal_115 = muac_distribution_in_well_group.sf(11.5) + probability_over_or_equal_125 = muac_distribution_in_well_group.sf(12.5) + + prob_less_than_115 = 1 - probability_over_or_equal_115 + pro_between_115_125 = probability_over_or_equal_115 - probability_over_or_equal_125 + + for id in idx: + muac_cat = self.rng.choice(['<115mm', '115-<125mm', '>=125mm'], + p=[prob_less_than_115, pro_between_115_125, probability_over_or_equal_125]) + df.at[id, 'un_am_MUAC_category'] = muac_cat + + def nutritional_oedema_present(self, idx): + """ + This function applies the probability of bilateral oedema present in wasting and non-wasted cases + :param idx: index of children under 5, or person_id + :return: + """ + df = self.sim.population.props + p = self.parameters + + # Knowing the prevalence of nutritional oedema in under 5 population, apply the probability of oedema in WHZ<-2 + # get those children with wasting + children_with_wasting = idx.intersection(df.index[df.un_WHZ_category != 'WHZ>=-2']) + children_without_wasting = idx.intersection(df.index[df.un_WHZ_category == 'WHZ>=-2']) + + # oedema among wasted children + oedema_in_wasted_children = self.rng.random_sample(size=len( + children_with_wasting)) < p['prevalence_nutritional_oedema'] * p['proportion_oedema_with_WHZ<-2'] + df.loc[children_with_wasting[oedema_in_wasted_children], 'un_am_bilateral_oedema'] = True + df.loc[children_with_wasting[oedema_in_wasted_children == False], 'un_am_bilateral_oedema'] = False + + # oedema among non-wasted children + oedema_in_non_wasted = self.rng.random_sample(size=len( + children_without_wasting)) < p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) + df.loc[children_without_wasting[oedema_in_non_wasted], 'un_am_bilateral_oedema'] = True + df.loc[children_without_wasting[oedema_in_non_wasted == False], 'un_am_bilateral_oedema'] = False + + def clinical_acute_malnutrition_state(self, person_id): + """ + This fuction will determine the clinical acute malnutrition status (MAM, SAM) based on anthropometric indices + and presence of bilateral oedema (Kwashiorkor); + And help determine whether the individual will have medical complications, applicable to SAM cases only, + requiring inpatient care. + :param person_id: + :return: + """ + df = self.sim.population.props + p = self.parameters + + # check if person is not wasted + if ( + (df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2') & + (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & + (df.at[person_id, 'un_am_bilateral_oedema'] == False) + ): + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' + + # severe acute malnutrition - MUAC<115mm and/or WHZ<-3 and/or bilateral oedema + elif ( + (df.at[person_id, 'un_am_MUAC_category'] == '<115mm') | + (df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3') | + (df.at[person_id, 'un_am_bilateral_oedema']) + ): + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' + + else: + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' + + # Determine if SAM episode has complications + if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM': + if p['prob_complications_in_SAM'] > self.rng.rand(): + df.at[person_id, 'un_sam_with_complications'] = True + else: + df.at[person_id, 'un_sam_with_complications'] = False + else: + df.at[person_id, 'un_sam_with_complications'] = False + + assert not (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') & \ + (df.at[person_id, 'un_sam_with_complications']) + + def date_of_outcome_for_untreated_am(self, person_id, duration_am): + """ + helper funtion to get the duration and the wasting episode and date of outcome (recovery, progression, or death) + :param person_id: + :param duration_am: + :return: + """ + df = self.sim.population.props + p = self.parameters + + # moderate wasting (for progression to severe, or recovery from MAM) ----- + if duration_am == 'MAM': + # Allocate the duration of the moderate wasting episode + duration_mam = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'])) + # Allocate a date of outcome (progression, recovery or death) + date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_mam) + return date_of_outcome + + # severe wasting (for death, or recovery to moderate wasting) ----- + if duration_am == 'SAM': + # determine the duration of SAM episode + duration_sam = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'] + + p['average_duration_of_untreated_SAM'])) + # Allocate a date of outcome (progression, recovery or death) + date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_sam) + return date_of_outcome + + def population_poll_clinical_am(self, population): + """ + Update at the population level other anthropometric indices and clinical signs + (MUAC, oedema, medical complications) that determine the clinical state of acute malnutrition + This will include both wasted and non-wasted children with other signs of acute malnutrition + :param population: + :return: + """ + df = population + + # give MUAC measurement category for all WHZ, including well nourished children ----- + for whz in ['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2']: + index_6_59mo_by_whz = df.index[df.is_alive & ((df.age_exact_years >= 0.5) & ( + df.age_exact_years < 5)) & (df.un_WHZ_category == whz)] + self.muac_cutoff_by_WHZ(idx=index_6_59mo_by_whz, whz=whz) + + # determine the presence of bilateral oedema / oedematous malnutrition ----- + index_under5 = df.index[df.is_alive & (df.age_exact_years < 5)] + self.nutritional_oedema_present(idx=index_under5) + + # determine the clinical acute malnutrition state ----- + for person_id in index_under5: + self.clinical_acute_malnutrition_state(person_id=person_id) def initialise_population(self, population): + """ + Set our property values for the initial population. + + This method is called by the simulation when creating the initial population, and is + responsible for assigning initial values, for every individual, of those properties + 'owned' by this module, i.e. those declared in the PROPERTIES dictionary above. + + :param population: + :return: + """ df = population.props - df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' + p = self.parameters + + # Set initial properties df.loc[df.is_alive, 'un_ever_wasted'] = False + df.loc[df.is_alive, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished + df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' + df.loc[df.is_alive, 'un_last_wasting_date_of_onset'] = pd.NaT + df.loc[df.is_alive, 'un_acute_malnutrition_tx_start_date'] = pd.NaT + df.loc[df.is_alive, 'un_sam_death_date'] = pd.NaT + df.loc[df.is_alive, 'un_am_bilateral_oedema'] = False + df.loc[df.is_alive, 'un_am_MUAC_category'] = '>=125mm' + df.loc[df.is_alive, 'un_am_treatment_type'] = 'not_applicable' + + # ----------------------------------------------------------------------------------------------------- + # # # # # allocate initial prevalence of wasting at the start of the simulation # # # # # + + def make_scaled_linear_model_wasting(agegp): + """ Makes the unscaled linear model with intercept of baseline odds of wasting (WHZ <-2). + Calculates the mean odds of wasting by age group and then creates a new linear model + with adjusted intercept so odds in 1-year-olds matches the specified value in the model + when averaged across the population + """ + + def get_odds_wasting(agegp): + """ + This function will calculate the WHZ scores by categories and return the odds of wasting + :param agegp: age grouped in months + :return: + """ + # generate random numbers from N(meean, sd) + baseline_WHZ_prevalence_by_agegp = f'prev_WHZ_distribution_age_{agegp}' + WHZ_normal_distribution = norm(loc=p[baseline_WHZ_prevalence_by_agegp][0], + scale=p[baseline_WHZ_prevalence_by_agegp][1]) + + # get all wasting: WHZ <-2 + probability_over_or_equal_minus2sd = WHZ_normal_distribution.sf(-2) + probability_less_than_minus2sd = 1 - probability_over_or_equal_minus2sd + + # convert probability to odds + base_odds_of_wasting = probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) + + return base_odds_of_wasting + + def make_linear_model_wasting(agegp, intercept=get_odds_wasting(agegp=agegp)): + return LinearModel( + LinearModelType.LOGISTIC, + intercept, # baseline odds: get_odds_wasting(agegp=agegp) + Predictor('li_wealth').when(2, p['or_wasting_hhwealth_Q2']) + .when(3, p['or_wasting_hhwealth_Q3']) + .when(4, p['or_wasting_hhwealth_Q4']) + .when(5, p['or_wasting_hhwealth_Q5']) + .otherwise(1.0), + Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == False) & (nb_early_preterm == False)', + p['or_wasting_SGA_and_term']), + Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + p['or_wasting_SGA_and_preterm']), + Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") ' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + p['or_wasting_preterm_and_AGA']) + ) + + unscaled_lm = make_linear_model_wasting(agegp, intercept=get_odds_wasting(agegp=agegp)) + target_mean = get_odds_wasting(agegp='12_23mo') + actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1)]).mean() + scaled_intercept = get_odds_wasting(agegp) * (target_mean / actual_mean) if \ + (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else get_odds_wasting(agegp) + scaled_lm = make_linear_model_wasting(agegp, intercept=scaled_intercept) + return scaled_lm + + # the linear model returns the probability that is implied by the model prob = odds / (1 + odds) + for agegp in ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo']: + self.prevalence_equations_by_age[agegp] = make_scaled_linear_model_wasting(agegp) + + # get the initial prevalence values for each age group using the lm equation (scaled) + prevalence_of_wasting = pd.DataFrame(index=df.loc[df.is_alive & (df.age_exact_years < 5)].index) + + prevalence_of_wasting['0_5mo'] = self.prevalence_equations_by_age['0_5mo'] \ + .predict(df.loc[df.is_alive & (df.age_exact_years < 0.5)]) + prevalence_of_wasting['6_11mo'] = self.prevalence_equations_by_age['6_11mo'] \ + .predict(df.loc[df.is_alive & ((df.age_exact_years >= 0.5) & (df.age_exact_years < 1))]) + prevalence_of_wasting['12_23mo'] = self.prevalence_equations_by_age['12_23mo'] \ + .predict(df.loc[df.is_alive & ((df.age_exact_years >= 1) & (df.age_exact_years < 2))]) + prevalence_of_wasting['24_35mo'] = self.prevalence_equations_by_age['24_35mo'] \ + .predict(df.loc[df.is_alive & ((df.age_exact_years >= 2) & (df.age_exact_years < 3))]) + prevalence_of_wasting['36_47mo'] = self.prevalence_equations_by_age['36_47mo'] \ + .predict(df.loc[df.is_alive & ((df.age_exact_years >= 3) & (df.age_exact_years < 4))]) + prevalence_of_wasting['48_59mo'] = self.prevalence_equations_by_age['48_59mo'] \ + .predict(df.loc[df.is_alive & ((df.age_exact_years >= 4) & (df.age_exact_years < 5))]) + + # ----------------------------------------------------------------------------------------------------- + # # # # # # further categorize into moderate (-3<=WHZ<-2) or severe (WHZ<-3) wasting # # # # # + def get_prob_severe_in_overall_wasting(agegp): + """ + This function will calculate the WHZ scores by categories and return probability of severe wasting + for those with wasting status + :param agegp: age grouped in months + :return: + """ + # generate random numbers from N(meean, sd) + baseline_WHZ_prevalence_by_agegp = f'prev_WHZ_distribution_age_{agegp}' + WHZ_normal_distribution = norm(loc=p[baseline_WHZ_prevalence_by_agegp][0], + scale=p[baseline_WHZ_prevalence_by_agegp][1]) + + # get all wasting: WHZ <-2 + probability_over_or_equal_minus2sd = WHZ_normal_distribution.sf(-2) + probability_less_than_minus2sd = 1 - probability_over_or_equal_minus2sd + # get severe wasting zcores: WHZ <-3 + probability_over_or_equal_minus3sd = WHZ_normal_distribution.sf(-3) + probability_less_than_minus3sd = 1 - probability_over_or_equal_minus3sd + + # make WHZ <-2 as the 100% and get the adjusted probability of severe wasting within overall wasting + proportion_severe_in_overall_wasting = probability_less_than_minus3sd * probability_less_than_minus2sd + + # get the probability of severe wasting + return proportion_severe_in_overall_wasting + + # differentiate into severe wasting and moderate wasting, by age group + for agegp in ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo']: + wasted = self.rng.random_sample(len(prevalence_of_wasting[agegp])) < prevalence_of_wasting[agegp] + for id in wasted[wasted].index: + probability_of_severe = get_prob_severe_in_overall_wasting(agegp) + wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], + p=[probability_of_severe, 1 - probability_of_severe]) + df.at[id, 'un_WHZ_category'] = wasted_category + df.at[id, 'un_last_wasting_date_of_onset'] = self.sim.date + df.at[id, 'un_ever_wasted'] = True + df.at[id, 'un_am_treatment_type'] = 'none' # start without treatment + # update clinical symptoms for severe wasting + self.wasting_clinical_symptoms(person_id=id) + + df.loc[wasted[wasted == False].index, 'un_WHZ_category'] = 'WHZ>=-2' + + # ----------------------------------------------------------------------------------------------------- + # # # # # # Give MUAC category, presence of oedema, and determine acute malnutrition state # # # # # + self.population_poll_clinical_am(df) + + # ----------------------------------------------------------------------------------------------------- + # # # # # Treatment coverage and cure rates at initiation # # # # # + # inpatient care + sam_requiring_inpatient_care = df.index[df.is_alive & (df.age_exact_years < 5) & ( + df.un_clinical_acute_malnutrition == 'SAM') & df.un_sam_with_complications] + recovered_complic_sam = self.rng.random_sample(len(sam_requiring_inpatient_care)) > ( + p['coverage_inpatient_care'] * p['recovery_rate_with_inpatient_care']) + # schedule recovery, and reset properties + for person in sam_requiring_inpatient_care[recovered_complic_sam]: + self.sim.schedule_event( + event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), + date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months + + for person in sam_requiring_inpatient_care[recovered_complic_sam == False]: + self.sim.schedule_event( + event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person), + date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months + + # outpatient care + uncomplicated_sam = df.index[df.is_alive & (df.age_exact_years < 5) & ( + df.un_clinical_acute_malnutrition == 'SAM') & df.un_sam_with_complications == False] + recovered_uncompl_sam = self.rng.random_sample(len(uncomplicated_sam)) > ( + p['coverage_outpatient_therapeutic_care'] * p['recovery_rate_with_standard_RUTF']) + for person in uncomplicated_sam[recovered_uncompl_sam]: + self.sim.schedule_event( + event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), + date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months + for person in uncomplicated_sam[recovered_uncompl_sam == False]: + self.sim.schedule_event( + event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person), + date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months + + # supplementary feeding for MAM + children_with_mam = df.index[df.is_alive & (df.age_exact_years < 5) & ( + df.un_clinical_acute_malnutrition == 'MAM') & df.un_sam_with_complications == False] + recovered_mam = self.rng.random_sample(len(children_with_mam)) > ( + p['coverage_supplementary_feeding_program'] * p['recovery_rate_with_CSB++']) + for person in children_with_mam[recovered_mam]: + self.sim.schedule_event( + event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), + date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months + for person in children_with_mam[recovered_mam == False]: + self.sim.schedule_event( + event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person), + date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months + + def initialise_simulation(self, sim): + """Prepares for simulation: + * Schedules the main polling event + * Schedules the main logging event + * Establishes the incidence linear models and other data structures using the parameters that have been read-in + * Store the consumables that are required in each of the HSI + """ + df = self.sim.population.props + p = self.parameters + + event = WastingPollingEvent(self) + sim.schedule_event(event, sim.date + DateOffset(months=3)) + sim.schedule_event(AcuteMalnutritionDeathPollingEvent(self), sim.date + DateOffset(months=3)) + + event = WastingLoggingEvent(self) + sim.schedule_event(event, sim.date + DateOffset(months=12)) + + # Get DALY weights + get_daly_weight = self.sim.modules['HealthBurden'].get_daly_weight + if 'HealthBurden' in self.sim.modules.keys(): + # self.daly_wts['MAM_w/o_oedema'] = get_daly_weight(sequlae_code=460) ## no value given + self.daly_wts['MAM_with_oedema'] = get_daly_weight(sequlae_code=461) + self.daly_wts['SAM_w/o_oedema'] = get_daly_weight(sequlae_code=462) + self.daly_wts['SAM_with_oedema'] = get_daly_weight(sequlae_code=463) + + # -------------------------------------------------------------------------------------------- + # Make a linear model equation that govern the probability that a person becomes wasted WHZ<-2 + def make_scaled_lm_wasting_incidence(): + """ + Makes the unscaled linear model with default intercept of 1. Calculates the mean incidents rate for + 1-year-olds and then creates a new linear model with adjusted intercept so incidents in 1-year-olds + matches the specified value in the model when averaged across the population + """ + + def make_lm_wasting_incidence(intercept=1.0): + return LinearModel( + LinearModelType.MULTIPLICATIVE, + intercept, + Predictor('age_exact_years').when('<0.5', p['base_inc_rate_wasting_by_agegp'][0]) + .when('<1.0', p['base_inc_rate_wasting_by_agegp'][1]) + .when('.between(1,1.9999)', p['base_inc_rate_wasting_by_agegp'][2]) + .when('.between(2,2.9999)', p['base_inc_rate_wasting_by_agegp'][3]) + .when('.between(3,3.9999)', p['base_inc_rate_wasting_by_agegp'][4]) + .when('.between(4,4.9999)', p['base_inc_rate_wasting_by_agegp'][5]) + .otherwise(0.0), + Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == False) & (nb_early_preterm == False)', + p['rr_wasting_SGA_and_term']), + Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + p['rr_wasting_SGA_and_preterm']), + Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") ' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + p['rr_wasting_preterm_and_AGA']), + Predictor('li_wealth').apply(lambda x: 1 if x == 1 else (x - 1) ** (p['rr_wasting_wealth_level'])), + ) + + unscaled_lm = make_lm_wasting_incidence() + target_mean = p[f'base_inc_rate_wasting_by_agegp'][2] + actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1) & + (df.un_WHZ_category == 'WHZ>=-2')]).mean() + scaled_intercept = 1.0 * (target_mean / actual_mean) \ + if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else 1.0 + scaled_lm = make_lm_wasting_incidence(intercept=scaled_intercept) + + return scaled_lm + + self.wasting_incidence_equation = make_scaled_lm_wasting_incidence() + + # -------------------------------------------------------------------------------------------- + # Linear model for the probability of progression to severe wasting (age-dependent only) + # (natural history only, no interventions) + self.severe_wasting_progression_equation = \ + LinearModel(LinearModelType.MULTIPLICATIVE, + 1.0, + Predictor('age_exact_years') + .when('<0.5', p['progression_severe_wasting_by_agegp'][0]) + .when('.between(0.5,0.9999)', p['progression_severe_wasting_by_agegp'][1]) + .when('.between(1,1.9999)', p['progression_severe_wasting_by_agegp'][2]) + .when('.between(2,2.9999)', p['progression_severe_wasting_by_agegp'][3]) + .when('.between(3,3.9999)', p['progression_severe_wasting_by_agegp'][4]) + .when('.between(4,4.9999)', p['progression_severe_wasting_by_agegp'][5]) + .otherwise(0.0), + ) + + # -------------------------------------------------------------------------------------------- + # Linear model for the probability of recovery based on interventions + self.acute_malnutrition_recovery_based_on_interventions.update({ + 'MAM': + LinearModel(LinearModelType.MULTIPLICATIVE, + 1.0, + Predictor('un_am_treatment_type').when('soy_RUSF', p['recovery_rate_with_soy_RUSF']) + .when('CSB++', p['recovery_rate_with_CSB++']) + .otherwise(0.0), + ), + 'SAM': + LinearModel(LinearModelType.MULTIPLICATIVE, + 1.0, + Predictor('un_am_treatment_type') + .when('standard_RUTF', p['recovery_rate_with_standard_RUTF']) + .when('inpatient_care', p['recovery_rate_with_inpatient_care']) + .otherwise(0.0), + ) + }) + + # -------------------------------------------------------------------------------------------- + # Make a linear model equation of death from severe acute malnutrition + def make_scaled_lm_sam_death(): + """ + Makes the unscaled linear model with default intercept of 1. Calculates the mean death rate for + 1-year-olds and then creates a new linear model with adjusted intercept so incidents in 1-year-olds + matches the specified value in the model when averaged across the population + """ + + def make_lm_sam_death(intercept=1.0): + return LinearModel( + LinearModelType.MULTIPLICATIVE, + intercept, + Predictor('un_am_treatment_type').when('none', p['base_death_rate_untreated_SAM']).otherwise(0.0), + Predictor('un_sam_with_complications').when(True, + p['rr_SAM_death_with_complications']), + Predictor().when('(un_am_bilateral_oedema == False) & ' + '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "115-<125mm")', + p['rr_SAM_death_WHZ<-3_only']), + Predictor().when('(un_am_bilateral_oedema == False) & ' + '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "<115mm")', + p['rr_SAM_death_both_WHZ<-3_&_MUAC<115mm']), + Predictor().when('(un_am_bilateral_oedema == True) & ' + '(un_WHZ_category == "-3<=WHZ<-2") & (un_am_MUAC_category == "<115mm")', + p['rr_SAM_death_kwashiorkor_only']), + Predictor().when('(un_am_bilateral_oedema == True) & ' + '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "115-<125mm")', + p['rr_SAM_death_kwashiorkor_WHZ<-3_only']), + Predictor().when('(un_am_bilateral_oedema == True) & ' + '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "<115mm")', + p['rr_SAM_death_kwashiorkor_both_WHZ<-3_&_MUAC<115mm']), + Predictor().when('(un_am_bilateral_oedema == True) & ' + '(un_WHZ_category == "-3<=WHZ<-2") & (un_am_MUAC_category == "<115mm")', + p['rr_SAM_death_kwashiorkor_MUAC<115mm_only']), + ) + + unscaled_lm = make_lm_sam_death() + target_mean = p[f'base_death_rate_untreated_SAM'] + actual_mean = unscaled_lm.predict( + df.loc[df.is_alive & ((df.age_exact_years > 0.5) & (df.age_exact_years < 5)) & + (df.un_clinical_acute_malnutrition == 'SAM')]).mean() + scaled_intercept = 1.0 * (target_mean / actual_mean) \ + if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else 1.0 + scaled_lm = make_lm_sam_death(intercept=scaled_intercept) + return scaled_lm + + self.sam_death_equation = make_scaled_lm_sam_death() + + def on_birth(self, mother_id, child_id): + """Initialise properties for a newborn individual. + :param mother_id: the mother for this child + :param child_id: the new child + """ + + df = self.sim.population.props + + df.at[child_id, 'un_WHZ_category'] = 'WHZ>=-2' + + def on_hsi_alert(self, person_id, treatment_id): + """ + This is called whenever there is an HSI event commissioned by one of the other disease modules. + """ + logger.debug(key='message', + data=f'This is Wasting, being alerted about a health system interaction for person' + f'{person_id} and treatment {treatment_id}') + + def report_daly_values(self): + """ + This must send back a pd.Series or pd.DataFrame that reports on the average daly-weights that have been + experienced by persons in the previous month. Only rows for alive-persons must be returned. + The names of the series of columns is taken to be the label of the cause of this disability. + It will be recorded by the healthburden module as _. + """ + df = self.sim.population.props + + total_daly_values = pd.Series(data=0.0, index=df.index[df.is_alive]) + total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & + df.un_am_bilateral_oedema] = self.daly_wts['SAM_with_oedema'] + total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & + (df.un_am_bilateral_oedema == False)] = self.daly_wts['SAM_w/o_oedema'] + total_daly_values.loc[df.is_alive & ( + ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | + ((df.un_WHZ_category != 'WHZ<-3') & (df.un_am_MUAC_category != "115-<125mm")) + ) & df.un_am_bilateral_oedema] = self.daly_wts['MAM_with_oedema'] + # total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'MAM')] = \ + # self.daly_wts['MAM_w/o_oedema'] + + return total_daly_values + + def wasting_clinical_symptoms(self, person_id): + """ + assign clinical symptoms to new acute malnutrition cases + :param person_id: + """ + df = self.sim.population.props + + if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': + return + + # currently symptoms list is applied to all (who are SAM) + for symptom in self.symptoms: + self.sim.modules["SymptomManager"].change_symptom( + person_id=person_id, + symptom_string=symptom, + add_or_remove="+", + disease_module=self, + # duration_in_days=None, + ) + + def do_when_acute_malnutrition_assessment(self, person_id): + """ + This is called by the a generic HSI event when acute malnutrition is checked. + :param person_id: + :param hsi_event: The HSI event that has called this event + :return: + """ + df = self.sim.population.props + p = self.parameters + + # get the clinical states + clinical_am = df.at[person_id, 'un_clinical_acute_malnutrition'] + complications = df.at[person_id, 'un_sam_with_complications'] + + # Interventions for MAM + if clinical_am == 'MAM': + # Check for coverage of supplementary feeding + if p['coverage_supplementary_feeding_program'] > self.rng.rand(): + # schedule HSI for supplementary feeding program for MAM + self.sim.modules['HealthSystem'].schedule_hsi_event( + hsi_event=HSI_supplementary_feeding_programme_for_MAM + (module=self, + person_id=person_id), + priority=0, + topen=self.sim.date + ) + else: + return + # Interventions for uncomplicated SAM + if clinical_am == 'SAM': + if not complications: + # Check for coverage of outpatient therapeutic care + if p['coverage_outpatient_therapeutic_care'] > self.rng.rand(): + # schedule HSI for supplementary feeding program for MAM + self.sim.modules['HealthSystem'].schedule_hsi_event( + hsi_event=HSI_outpatient_therapeutic_programme_for_SAM + (module=self, + person_id=person_id), + priority=0, + topen=self.sim.date + ) + else: + return + # Interventions for complicated SAM + if complications: + # Check for coverage of outpatient therapeutic care + if p['coverage_inpatient_care'] > self.rng.rand(): + # schedule HSI for supplementary feeding program for MAM + self.sim.modules['HealthSystem'].schedule_hsi_event( + hsi_event=HSI_inpatient_care_for_complicated_SAM + (module=self, + person_id=person_id), + priority=0, + topen=self.sim.date + ) + else: + return + + def do_when_am_treatment(self, person_id, intervention): + """ + This function will apply the linear model of recovery based on intervention given + :param person_id: + :param intervention: + :return: + """ + df = self.sim.population.props + # Log that the treatment is provided: + df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date + + if intervention == 'SFP': + mam_recovery = self.acute_malnutrition_recovery_based_on_interventions['MAM'].predict( + df.loc[[person_id]]).values[0] + if self.rng.rand() < mam_recovery: + # schedule recovery date + self.sim.schedule_event( + event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) + # cancel progression date (in ProgressionEvent) + else: + # remained MAM + return + + if intervention == 'OTC': + sam_recovery = self.acute_malnutrition_recovery_based_on_interventions['SAM'].predict( + df.loc[[person_id]]).values[0] + if self.rng.rand() < sam_recovery: + # schedule recovery date + self.sim.schedule_event( + event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) + # cancel death date + df.at[person_id, 'un_sam_death_date'] = pd.NaT + else: + # remained MAM or death + outcome = self.rng.choice(['remained_mam', 'death'], + p=[0.5, 0.5]) + if outcome == 'remained_mam': + self.sim.schedule_event( + event=UpdateToMAM(module=self, person_id=person_id), + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) + if outcome == 'death': + self.sim.schedule_event( + event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person_id), + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) + + if intervention == 'ITC': + sam_recovery = self.acute_malnutrition_recovery_based_on_interventions['SAM'].predict( + df.loc[[person_id]]).values[0] + if self.rng.rand() < sam_recovery: + # schedule recovery date + self.sim.schedule_event( + event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=4)) + # cancel death date + df.at[person_id, 'un_sam_death_date'] = pd.NaT + else: + # remained MAM or death + outcome = self.rng.choice(['remained_mam', 'death'], + p=[0.5, 0.5]) + if outcome == 'remained_mam': + self.sim.schedule_event( + event=UpdateToMAM(module=self, person_id=person_id), + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=4)) + if outcome == 'death': + self.sim.schedule_event( + event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person_id), + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=4)) + + +class WastingPollingEvent(RegularEvent, PopulationScopeEventMixin): + """ + Regular event that determines new cases of wasting (WHZ<-2) to the under-5 population, + and schedules individual incident cases to represent onset. + It determines those who will progress to severe wasting (WHZ<-3) and schedules the event to update on properties. + These are events occurring without the input of interventions, these events reflect the natural history only. + """ + AGE_GROUPS = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} + + def __init__(self, module): + """schedule to run every month + :param module: the module that created this event + """ + self.repeat_months = 1 + super().__init__(module, frequency=DateOffset(months=self.repeat_months)) + assert isinstance(module, Wasting) + + def apply(self, population): + """Apply this event to the population. + :param population: the current population + """ + df = population.props + rng = self.module.rng + + # # # # # # # # # # # # # # # # # # # # # INCIDENCE OF WASTING # # # # # # # # # # # # # # # # # # # # # + + # Determine who will be onset with wasting among those who are not currently wasted ------------- + incidence_of_wasting = self.module.wasting_incidence_equation.predict( + df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == 'WHZ>=-2')]) + wasted = rng.random_sample(len(incidence_of_wasting)) < incidence_of_wasting + + # update the properties for wasted children + df.loc[wasted[wasted].index, 'un_ever_wasted'] = True + df.loc[wasted[wasted].index, 'un_last_wasting_date_of_onset'] = self.sim.date + df.loc[wasted[wasted].index, 'un_WHZ_category'] = '-3<=WHZ<-2' # start as moderate wasting + df.loc[wasted[wasted].index, 'un_am_treatment_type'] = 'none' # start without treatment + + # ------------------------------------------------------------------------------------------- + # Add this incident case to the tracker + for person in wasted[wasted].index: + wasting_severity = df.at[person, 'un_WHZ_category'] + age_group = WastingPollingEvent.AGE_GROUPS.get(df.loc[person].age_years, '5+y') + if wasting_severity != 'WHZ>=-2': + self.module.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) + # ------------------------------------------------------------------------------------------- + + # # # # # # # # # # # # # # # # # # # # # PROGRESS TO SEVERE WASTING # # # # # # # # # # # # # # # # # # # # # + + # Determine those that will progress to severe wasting ( WHZ<-3) and schedule progression event --------- + progression_severe_wasting = self.module.severe_wasting_progression_equation.predict( + df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == '-3<=WHZ<-2')]) + will_be_severely_wasted = rng.random_sample(len(progression_severe_wasting)) < progression_severe_wasting + + # determine those individuals who will progress to severe wasting and time of progression + for person in will_be_severely_wasted[will_be_severely_wasted].index: + outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') + # schedule severe wasting WHZ<-3 onset + if outcome_date <= self.sim.date: + # schedule severe wasting WHZ<-3 onset today + self.sim.schedule_event( + event=ProgressionSevereWastingEvent(module=self.module, person_id=person), + date=self.sim.date) + else: + # schedule severe wasting WHZ<-3 onset according to duration + self.sim.schedule_event( + event=ProgressionSevereWastingEvent(module=self.module, person_id=person), + date=outcome_date) + + # # # # # # # # # # # # # # # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # # # + + # moderate wasting not progressed to severe, schedule recovery + for person in will_be_severely_wasted[will_be_severely_wasted == False].index: + outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') + if outcome_date <= self.sim.date: + # schedule recovery for today + self.sim.schedule_event( + event=WastingNaturalRecoveryEvent(module=self.module, person_id=person), + date=self.sim.date) + else: + # schedule recovery according to duration + self.sim.schedule_event( + event=WastingNaturalRecoveryEvent(module=self.module, person_id=person), + date=outcome_date) + + # ------------------------------------------------------------------------------------------ + # # # # # # # # # UPDATE PROPERTIES RELATED TO CLINICAL ACUTE MALNUTRITION # # # # # # # # # + # ------------------------------------------------------------------------------------------ + # This applies to all children under 5 + + # give MUAC measurement category for all WHZ, including well nourished children ----- + # determine the presence of bilateral oedema / oedematous malnutrition ----- + # determine the clinical state of acute malnutrition, and check complications if SAM + self.module.population_poll_clinical_am(df) + + # then, update clinical symptoms for those with severe acute malnutrition + children_with_sam = df.loc[df.is_alive & (df.age_exact_years < 5) & + (df.un_clinical_acute_malnutrition == 'SAM')] + for person in children_with_sam.index: + self.module.wasting_clinical_symptoms(person_id=person) + + +class ProgressionSevereWastingEvent(Event, IndividualScopeEventMixin): + """ + This Event is for the onset of severe wasting (WHZ <-3). + * Refreshes all the properties so that they pertain to this current episode of wasting + * Imposes the symptoms + """ + + def __init__(self, module, person_id): + super().__init__(module, person_id=person_id) + + def apply(self, person_id): + df = self.sim.population.props # shortcut to the dataframe + m = self.module + + # before progression to severe wasting, check those who started supplementary feeding programme before today + if df.at[person_id, + 'un_last_wasting_date_of_onset'] < df.at[person_id, + 'un_acute_malnutrition_tx_start_date'] < self.sim.date: + return + + # continue with progression to severe if not treated/recovered + else: + # update properties + df.at[person_id, 'un_WHZ_category'] = 'WHZ<-3' + + # Give MUAC measurement category for WHZ<-3 + if df.at[person_id, 'age_exact_years'] > 0.5: + m.muac_cutoff_by_WHZ(idx=df.loc[[person_id]].index, whz='WHZ<-3') + + # update the clinical state of acute malnutrition, and check complications if SAM + m.clinical_acute_malnutrition_state(person_id) + + # update clinical symptoms for severe wasting + m.wasting_clinical_symptoms(person_id=person_id) + + # ------------------------------------------------------------------------------------------- + # Add this incident case to the tracker + wasting_severity = df.at[person_id, 'un_WHZ_category'] + age_group = WastingPollingEvent.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') + if wasting_severity != 'WHZ>=-2': + m.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) + + +class AcuteMalnutritionDeathPollingEvent(RegularEvent, PopulationScopeEventMixin): + """ + Regular event that determines death due to acute malnutrition to the under-5 population, + and schedules individual death events. + It also determines those who will improve nutritional state. + """ + AGE_GROUPS = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} + + def __init__(self, module): + """schedule to run every month + :param module: the module that created this event + """ + self.repeat_months = 1 + super().__init__(module, frequency=DateOffset(months=self.repeat_months)) + assert isinstance(module, Wasting) + + def apply(self, population): + """Apply this event to the population. + :param population: the current population + """ + df = population.props + rng = self.module.rng + + # # # # # # # # # # # # # # # # # # # # # DEATH # # # # # # # # # # # # # # # # # # # # # + + # Determine those that will die ----------------------------------------------- + prob_death = self.module.sam_death_equation.predict(df.loc[df.is_alive & (df.age_exact_years < 5) & + (df.un_clinical_acute_malnutrition != 'well')]) + will_die = rng.random_sample(len(prob_death)) < prob_death + + # schedule death date + for person in will_die[will_die].index: + death_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='SAM') + if death_date <= self.sim.date: + # schedule death for today + self.sim.schedule_event( + event=SevereAcuteMalnutritionDeathEvent(module=self.module, person_id=person), + date=self.sim.date) + # df.at[person, 'un_sam_death_date'] = self.sim.date + else: + # schedule death according to duration + self.sim.schedule_event( + event=SevereAcuteMalnutritionDeathEvent(module=self.module, person_id=person), + date=death_date) + # df.at[person, 'un_sam_death_date'] = death_date + + # # # # # # # # # # # # # # # # # # # # # IMPROVEMENT FROM SAM TO MAM # # # # # # # # # # # # # # # # # # # # # + # SAM = severe wasting (WHZ<-3) and/or MUAC <115mm, or nutritional oedema + # Those not scheduled to die, will have improved WHZ status by 1sd (-3<=WHZ<-2) + + # schedule improvement to MAM for those not scheduled to die + for person in will_die[will_die == False].index: + outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='SAM') + if outcome_date <= self.sim.date: + # schedule improvement to moderate wasting date for today + self.sim.schedule_event( + event=UpdateToMAM(module=self.module, person_id=person), + date=self.sim.date) + if outcome_date > self.sim.date: + # schedule improvement to moderate wasting date according to duration + self.sim.schedule_event( + event=UpdateToMAM(module=self.module, person_id=person), + date=outcome_date) + + +class SevereAcuteMalnutritionDeathEvent(Event, IndividualScopeEventMixin): + """ + This event applies the death function + """ + + def __init__(self, module, person_id): + super().__init__(module, person_id=person_id) + + def apply(self, person_id): + df = self.sim.population.props # shortcut to the dataframe + + # The event should not run if the person is not currently alive + if not df.at[person_id, 'is_alive']: + return + + if df.at[person_id, 'un_acute_malnutrition_tx_start_date'] < self.sim.date: + return + + # Check if this person should still die from SAM: + if pd.isnull(df.at[person_id, 'un_am_recovery_date']): + # Cause the death to happen immediately + df.at[person_id, 'un_sam_death_date'] = self.sim.date + self.sim.modules['Demography'].do_death( + individual_id=person_id, + cause='SAM', + originating_module=self.module + ) + + +class WastingNaturalRecoveryEvent(Event, IndividualScopeEventMixin): + """ + This event sets wasting properties back to normal state, based on home care/ improvement without interventions, + low-moderate MUAC categories oedema may or may not be present + """ + + def __init__(self, module, person_id): + super().__init__(module, person_id=person_id) + + def apply(self, person_id): + df = self.sim.population.props # shortcut to the dataframe + m = self.module + + if not df.at[person_id, 'is_alive']: + return + + df.at[person_id, 'un_am_recovery_date'] = self.sim.date + df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished + + # For cases with normal WHZ, attribute probability of MUAC category + if df.at[person_id, 'age_exact_years'] > 0.5: + m.muac_cutoff_by_WHZ(idx=df.loc[[person_id]].index, whz='WHZ>=-2') + + # Note assumption: prob of oedema remained the same as applied in wasting onset + + # update the clinical acute malnutrition state + m.clinical_acute_malnutrition_state(person_id) + + if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well': + # this will clear all wasting symptoms + self.sim.modules["SymptomManager"].clear_symptoms( + person_id=person_id, disease_module=self.module + ) + + +class ClinicalAcuteMalnutritionRecoveryEvent(Event, IndividualScopeEventMixin): + """ + This event sets wasting properties back to normal state. + """ + + def __init__(self, module, person_id): + super().__init__(module, person_id=person_id) + + def apply(self, person_id): + df = self.sim.population.props # shortcut to the dataframe + + if not df.at[person_id, 'is_alive']: + return + + df.at[person_id, 'un_am_recovery_date'] = self.sim.date + df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' + df.at[person_id, 'un_sam_death_date'] = pd.NaT + df.at[person_id, 'un_am_bilateral_oedema'] = False + df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' + df.at[person_id, 'un_sam_with_complications'] = False + df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = pd.NaT + df.at[person_id, 'un_am_treatment_type'] = 'not_applicable' + + # this will clear all wasting symptoms + self.sim.modules["SymptomManager"].clear_symptoms( + person_id=person_id, disease_module=self.module + ) + + +class UpdateToMAM(Event, IndividualScopeEventMixin): + """ + This event updates the properties for those cases that remained/ improved from SAM to MAM following treatment + """ + + def __init__(self, module, person_id): + super().__init__(module, person_id=person_id) + + def apply(self, person_id): + df = self.sim.population.props # shortcut to the dataframe + m = self.module + rng = m.rng + p = m.parameters + + if not df.at[person_id, 'is_alive']: + return + + # For cases with normal WHZ and other acute malnutrition signs: oedema, or low muac - do not change the WHZ + if df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2': + df.at[person_id, 'un_am_MUAC_category'] = '115-<125mm' # mam by muac only + + else: + # using the probability of mam classification by anthropometric indices + mam_classification = rng.choice(['mam_by_muac_only', 'mam_by_muac_and_whz', 'mam_by_whz_only'], + p=[p['proportion_mam_with_MUAC_115-<125mm_and_normal_whz'], + p['proportion_mam_with_MUAC_115-<125mm_and_-3<=WHZ<-2'], + p['proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC']]) + + if mam_classification == 'mam_by_muac_only': + df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' + df.at[person_id, 'un_am_MUAC_category'] = '115-<125mm' + + if mam_classification == 'mam_by_muac_and_whz': + df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' + df.at[person_id, 'un_am_MUAC_category'] = '115-<125mm' + + if mam_classification == 'mam_by_whz_only': + df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' + df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' + + # Update all other properties equally + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' + df.at[person_id, 'un_am_bilateral_oedema'] = False + df.at[person_id, 'un_sam_with_complications'] = False + df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = pd.NaT + df.at[person_id, 'un_am_recovery_date'] = pd.NaT + df.at[person_id, 'un_am_discharge_date'] = pd.NaT + df.at[person_id, 'un_am_treatment_type'] = 'not_applicable' # will start the process again + + # this will clear all wasting symptoms (applicable for SAM, not MAM) + self.sim.modules["SymptomManager"].clear_symptoms( + person_id=person_id, disease_module=self.module + ) + + +class HSI_supplementary_feeding_programme_for_MAM(HSI_Event, IndividualScopeEventMixin): + """ + This is the supplementary feeding programme for MAM without complications + """ + + def __init__(self, module, person_id): + super().__init__(module, person_id=person_id) + assert isinstance(module, Wasting) + + # Get a blank footprint and then edit to define call on resources of this treatment event + the_appt_footprint = self.sim.modules["HealthSystem"].get_blank_appt_footprint() + the_appt_footprint['Under5OPD'] = 1 # This requires one out patient + + # Define the necessary information for an HSI + self.TREATMENT_ID = 'supplementary_feeding_programme_for_MAM' + self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint + self.ACCEPTED_FACILITY_LEVEL = 1 + self.ALERT_OTHER_DISEASES = [] + + def apply(self, person_id, squeeze_factor): + + df = self.sim.population.props + + # Stop the person from dying of acute malnutrition (if they were going to die) + if not df.at[person_id, 'is_alive']: + return + + # Do here whatever happens to an individual during this health system interaction event + # ~~~~~~~~~~~~~~~~~~~~~~ + # Make request for some consumables + consumables = self.sim.modules['HealthSystem'].parameters['Consumables'] + # whole package of interventions + pkg_code_mam = pd.unique( + consumables.loc[consumables['Intervention_Pkg'] == 'Management of moderate acute malnutrition (children)', + 'Intervention_Pkg_Code'])[0] # This package includes only CSB(or supercereal or CSB++) + # individual items + item_code1 = pd.unique( + consumables.loc[consumables['Items'] == 'Corn Soya Blend (or Supercereal - CSB++)', 'Item_Code'])[0] + + consumables_needed = {'Intervention_Package_Code': {pkg_code_mam: 1}, 'Item_Code': {item_code1: 1}} + + # check availability of consumables + outcome_of_request_for_consumables = self.sim.modules['HealthSystem'].request_consumables( + hsi_event=self, cons_req_as_footprint=consumables_needed) + # answer comes back in the same format, but with quantities replaced with bools indicating availability + if outcome_of_request_for_consumables['Intervention_Package_Code'][pkg_code_mam]: + logger.debug(key='debug', data='PkgCode1 is available, so use it.') + # Log that the treatment is provided: + df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date + df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=3) + df.at[person_id, 'un_am_treatment_type'] = 'CSB++' + self.module.do_when_am_treatment(person_id, intervention='SFP') + else: + logger.debug(key='debug', data="PkgCode1 is not available, so can't use it.") + + # -------------------------------------------------------------------------------------------------- + # # check to see if all consumables returned (for demonstration purposes): + # all_available = (outcome_of_request_for_consumables['Intervention_Package_Code'][pkg_code_mam]) and \ + # (outcome_of_request_for_consumables['Item_Code'][item_code1]) + # # use helper function instead (for demonstration purposes) + # all_available_using_helper_function = self.get_all_consumables( + # item_codes=[item_code1], + # pkg_codes=[pkg_code_mam] + # ) + # # Demonstrate equivalence + # assert all_available == all_available_using_helper_function + + def did_not_run(self): + logger.debug("supplementary_feeding_programme_for_MAM: did not run") + pass + + +class HSI_outpatient_therapeutic_programme_for_SAM(HSI_Event, IndividualScopeEventMixin): + """ + This is the outpatient management of SAM without any medical complications + """ + + def __init__(self, module, person_id): + super().__init__(module, person_id=person_id) + assert isinstance(module, Wasting) + + # Get a blank footprint and then edit to define call on resources of this treatment event + the_appt_footprint = self.sim.modules["HealthSystem"].get_blank_appt_footprint() + the_appt_footprint['U5Malnutr'] = 1 + + # Define the necessary information for an HSI + self.TREATMENT_ID = 'outpatient_therapeutic_programme_for_SAM' + self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint + self.ACCEPTED_FACILITY_LEVEL = 1 + self.ALERT_OTHER_DISEASES = [] + + def apply(self, person_id, squeeze_factor): + + df = self.sim.population.props + + # Stop the person from dying of acute malnutrition (if they were going to die) + if not df.at[person_id, 'is_alive']: + return + + # Do here whatever happens to an individual during this health system interaction event + # ~~~~~~~~~~~~~~~~~~~~~~ + # Make request for some consumables + consumables = self.sim.modules['HealthSystem'].parameters['Consumables'] + # whole package of interventions + pkg_code_sam = pd.unique( + consumables.loc[consumables['Intervention_Pkg'] == 'Management of severe malnutrition (children)', + 'Intervention_Pkg_Code'])[0] + # individual items + item_code1 = pd.unique( + consumables.loc[consumables['Items'] == 'SAM theraputic foods', 'Item_Code'])[0] + item_code2 = pd.unique( + consumables.loc[consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] + + consumables_needed = {'Intervention_Package_Code': {pkg_code_sam: 1}, 'Item_Code': {item_code1: 1, + item_code2: 1}} + + # check availability of consumables + outcome_of_request_for_consumables = self.sim.modules['HealthSystem'].request_consumables( + hsi_event=self, cons_req_as_footprint=consumables_needed) + # answer comes back in the same format, but with quantities replaced with bools indicating availability + if outcome_of_request_for_consumables['Intervention_Package_Code'][pkg_code_sam]: + logger.debug(key='debug', data='PkgCode1 is available, so use it.') + # Log that the treatment is provided: + df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date + df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=3) + df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' + self.module.do_when_am_treatment(person_id, intervention='OTC') + else: + logger.debug(key='debug', data="PkgCode1 is not available, so can't use it.") + # -------------------------------------------------------------------------------------------------- + # # check to see if all consumables returned (for demonstration purposes): + # all_available = (outcome_of_request_for_consumables['Intervention_Package_Code'][pkg_code_sam]) and \ + # (outcome_of_request_for_consumables['Item_Code'][item_code1][item_code2]) + # + # # use helper function instead (for demonstration purposes) + # all_available_using_helper_function = self.get_all_consumables( + # item_codes=[item_code1, item_code2], + # pkg_codes=[pkg_code_sam] + # ) + # # Demonstrate equivalence + # assert all_available == all_available_using_helper_function + + def did_not_run(self): + logger.debug("HSI_outpatient_therapeutic_programme_for_SAM: did not run") + pass + + +class HSI_inpatient_care_for_complicated_SAM(HSI_Event, IndividualScopeEventMixin): + """ + This is the inpatient management of SAM with medical complications + """ + + def __init__(self, module, person_id): + super().__init__(module, person_id=person_id) + assert isinstance(module, Wasting) + + # Get a blank footprint and then edit to define call on resources of this treatment event + the_appt_footprint = self.sim.modules["HealthSystem"].get_blank_appt_footprint() + the_appt_footprint['U5Malnutr'] = 1 + + # Define the necessary information for an HSI + self.TREATMENT_ID = 'inpatient_care_for_complicated_SAM' + self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint + self.ACCEPTED_FACILITY_LEVEL = 2 + self.ALERT_OTHER_DISEASES = [] + self.BEDDAYS_FOOTPRINT = self.make_beddays_footprint({'general_bed': 7}) + + def apply(self, person_id, squeeze_factor): + + df = self.sim.population.props + + # Stop the person from dying of acute malnutrition (if they were going to die) + if not df.at[person_id, 'is_alive']: + return + + # Do here whatever happens to an individual during this health system interaction event + # ~~~~~~~~~~~~~~~~~~~~~~ + # Make request for some consumables + consumables = self.sim.modules['HealthSystem'].parameters['Consumables'] + # whole package of interventions + pkg_code_sam = pd.unique( + consumables.loc[consumables['Intervention_Pkg'] == 'Management of severe malnutrition (children)', + 'Intervention_Pkg_Code'])[0] + # individual items + item_code1 = pd.unique( + consumables.loc[consumables['Items'] == 'SAM theraputic foods', 'Item_Code'])[0] + item_code2 = pd.unique( + consumables.loc[consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] + + consumables_needed = {'Intervention_Package_Code': {pkg_code_sam: 1}, 'Item_Code': {item_code1: 1, + item_code2: 1}} + + # check availability of consumables + outcome_of_request_for_consumables = self.sim.modules['HealthSystem'].request_consumables( + hsi_event=self, cons_req_as_footprint=consumables_needed) + # answer comes back in the same format, but with quantities replaced with bools indicating availability + if outcome_of_request_for_consumables['Intervention_Package_Code'][pkg_code_sam]: + logger.debug(key='debug', data='PkgCode1 is available, so use it.') + # Log that the treatment is provided: + df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date + df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=4) + df.at[person_id, 'un_am_treatment_type'] = 'inpatient_care' + self.module.do_when_am_treatment(person_id, intervention='ITC') + else: + logger.debug(key='debug', data="PkgCode1 is not available, so can't use it.") + # -------------------------------------------------------------------------------------------------- + # # check to see if all consumables returned (for demonstration purposes): + # all_available = (outcome_of_request_for_consumables['Intervention_Package_Code'][pkg_code_sam]) and \ + # (outcome_of_request_for_consumables['Item_Code'][item_code1][item_code2]) + # # use helper function instead (for demonstration purposes) + # all_available_using_helper_function = self.get_all_consumables( + # item_codes=[item_code1, item_code2], + # pkg_codes=[pkg_code_sam] + # ) + # # Demonstrate equivalence + # assert all_available == all_available_using_helper_function + + def did_not_run(self): + logger.debug("HSI_inpatient_care_for_complicated_SAM: did not run") + pass + + +class WastingLoggingEvent(RegularEvent, PopulationScopeEventMixin): + """ + This Event logs the number of incident cases that have occurred since the previous logging event. + Analysis scripts expect that the frequency of this logging event is once per year. + """ + + def __init__(self, module): + # This event to occur every year + self.repeat = 12 + super().__init__(module, frequency=DateOffset(months=self.repeat)) + self.date_last_run = self.sim.date + + def apply(self, population): + df = self.sim.population.props + # Convert the list of timestamps into a number of timestamps + # and check that all the dates have occurred since self.date_last_run + counts_am = copy.deepcopy(self.module.wasting_incident_case_tracker_zeros) + + for age_grp in self.module.wasting_incident_case_tracker.keys(): + for state in self.module.wasting_states: + list_of_times = self.module.wasting_incident_case_tracker[age_grp][state] + counts_am[age_grp][state] = len(list_of_times) + for t in list_of_times: + assert self.date_last_run <= t <= self.sim.date + + logger.info(key='wasting_incidence_count', data=counts_am) + + # Reset the counters and the date_last_run + self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) + self.date_last_run = self.sim.date + + # Wasting totals (prevalence at logging time) + currently_wasted_age_0_5mo = (df.is_alive & (df.age_exact_years < 0.5) & + (df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_6_11mo = (df.is_alive & ((df.age_exact_years >= 0.5) & ( + df.age_exact_years < 1)) & (df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_12_23mo = (df.is_alive & ((df.age_exact_years >= 1) & ( + df.age_exact_years < 2)) & (df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_24_35mo = (df.is_alive & ((df.age_exact_years >= 2) & ( + df.age_exact_years < 3)) & (df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_36_47mo = (df.is_alive & ((df.age_exact_years >= 3) & ( + df.age_exact_years < 4)) & (df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_48_59mo = (df.is_alive & ((df.age_exact_years >= 4) & ( + df.age_exact_years < 5)) & (df.un_WHZ_category != 'WHZ>=-2')).sum() + + currently_wasted = {'0_5mo': currently_wasted_age_0_5mo, + '6_11mo': currently_wasted_age_6_11mo, + '12_23mo': currently_wasted_age_12_23mo, + '24_35mo': currently_wasted_age_24_35mo, + '36_47mo': currently_wasted_age_36_47mo, + '48_59mo': currently_wasted_age_48_59mo} + + logger.info(key='wasting_prevalence_count', data=currently_wasted) + + +class PropertiesOfOtherModules(Module): + """For the purpose of the testing, this module generates the properties upon which the Wasting module relies""" + + PROPERTIES = { + 'hv_inf': Property(Types.BOOL, 'temporary property'), + 'nb_low_birth_weight_status': Property(Types.CATEGORICAL, 'temporary property', + categories=['extremely_low_birth_weight', 'very_low_birth_weight', + 'low_birth_weight', 'normal_birth_weight']), + 'nb_size_for_gestational_age': Property(Types.CATEGORICAL, 'temporary property', + categories=['small_for_gestational_age', + 'average_for_gestational_age']), + 'nb_late_preterm': Property(Types.BOOL, 'temporary property'), + 'nb_early_preterm': Property(Types.BOOL, 'temporary property'), + + 'nb_breastfeeding_status': Property(Types.CATEGORICAL, 'temporary property', + categories=['none', 'non_exclusive', 'exclusive']), + + } + + def __init__(self, name=None): + super().__init__(name) + + def read_parameters(self, data_folder): + pass + + def initialise_population(self, population): + df = population.props + df.loc[df.is_alive, 'hv_inf'] = False + df.loc[df.is_alive, 'nb_low_birth_weight_status'] = 'normal_birth_weight' + df.loc[df.is_alive, 'nb_breastfeeding_status'] = 'exclusive' + df.loc[df.is_alive, 'nb_size_for_gestational_age'] = 'average_for_gestational_age' + df.loc[df.is_alive, 'nb_late_preterm'] = False + df.loc[df.is_alive, 'nb_early_preterm'] = False def initialise_simulation(self, sim): pass def on_birth(self, mother, child): df = self.sim.population.props - df.at[child, 'un_clinical_acute_malnutrition'] = 'well' - df.at[child, 'un_ever_wasted'] = False + df.at[child, 'hv_inf'] = False + df.at[child, 'nb_low_birth_weight_status'] = 'normal_birth_weight' + df.at[child, 'nb_breastfeeding_status'] = 'exclusive' + df.at[child, 'nb_size_for_gestational_age'] = 'average_for_gestational_age' + df.at[child, 'nb_late_preterm'] = False + df.at[child, 'nb_early_preterm'] = False From d35833cec83d6a15255016e5abd5f4a51f11a7c6 Mon Sep 17 00:00:00 2001 From: Tim Hallett Date: Wed, 6 Apr 2022 17:06:54 +0100 Subject: [PATCH 003/755] edit hsi_generic_first_appts.py --- src/tlo/methods/hsi_generic_first_appts.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/tlo/methods/hsi_generic_first_appts.py b/src/tlo/methods/hsi_generic_first_appts.py index a256505e72..37a4ab3830 100644 --- a/src/tlo/methods/hsi_generic_first_appts.py +++ b/src/tlo/methods/hsi_generic_first_appts.py @@ -169,6 +169,14 @@ def do_at_generic_first_appt_non_emergency(hsi_event, squeeze_factor): topen=sim.date, tclose=None) + # routine assessment for acute malnutrition + if 'Wasting' in sim.modules: + sim.modules['Wasting'].do_when_acute_malnutrition_assessment(person_id=person_id) + + # routine assessment for chronic malnutrition + if 'Stunting' in sim.modules: + sim.modules['Stunting'].do_routine_assessment_for_chronic_undernutrition(person_id=person_id) + elif age < 15: # ----------------------------------- CHILD 5-14 ----------------------------------- if 'fever' in symptoms and "Malaria" in sim.modules: From 55aa12c6035bd46b287f247016cb667dab575fad Mon Sep 17 00:00:00 2001 From: mnjowe Date: Thu, 5 Oct 2023 09:01:21 +0200 Subject: [PATCH 004/755] made some changes in wasting to ensure all tests in test_wasting are running without errors. added wasting analysis file to get more understanding of the current outputs before applying some major changes. added wasting resource file --- resources/ResourceFile_Wasting.xlsx | 3 + .../wasting_analyses/analysis_wasting.py | 62 + src/tlo/methods/wasting.py | 106 +- tests/test_wasting.py | 1847 ++++++++--------- 4 files changed, 1016 insertions(+), 1002 deletions(-) create mode 100644 resources/ResourceFile_Wasting.xlsx create mode 100644 src/scripts/wasting_analyses/analysis_wasting.py diff --git a/resources/ResourceFile_Wasting.xlsx b/resources/ResourceFile_Wasting.xlsx new file mode 100644 index 0000000000..fa109671a5 --- /dev/null +++ b/resources/ResourceFile_Wasting.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e7f03fe6554fde5e6285cf1fe8c49302feb70ab13169fe68ebfb926f03df3622 +size 11433 diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py new file mode 100644 index 0000000000..e2897a56eb --- /dev/null +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -0,0 +1,62 @@ +""" +An analysis file for the wasting module +""" +from pathlib import Path + +# %% Import statements + +from tlo import Date, Simulation, logging +from tlo.analysis.utils import parse_log_file +from tlo.methods import wasting, demography, healthsystem, symptommanager, healthseekingbehaviour, healthburden, \ + enhanced_lifestyle, labour, newborn_outcomes, care_of_women_during_pregnancy, contraception, pregnancy_supervisor, \ + postnatal_supervisor, hiv + +seed = 1 + +# Path to the resource files used by the disease and intervention methods +resources = Path("./resources") + +# configure logging +log_config = { + "filename": "wasting", # output filename. A timestamp will be added to this. + "custom_levels": { # Customise the output of specific loggers. They are applied in order: + "tlo.methods.demography": logging.INFO, + "tlo.methods.wasting": logging.INFO, + '*': logging.WARNING + } +} + +# Basic arguments required for the simulation +start_date = Date(2010, 1, 1) +end_date = Date(2020, 1, 1) +pop_size = 10000 + +# Create simulation instance for this run. +sim = Simulation(start_date=start_date, seed=seed, log_config=log_config) + +# Register modules for simulation +sim.register( + demography.Demography(resourcefilepath=resources), + healthsystem.HealthSystem(resourcefilepath=resources, + service_availability=['*'], + cons_availability='default'), + healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resources), + healthburden.HealthBurden(resourcefilepath=resources), + symptommanager.SymptomManager(resourcefilepath=resources), + enhanced_lifestyle.Lifestyle(resourcefilepath=resources), + labour.Labour(resourcefilepath=resources), + care_of_women_during_pregnancy.CareOfWomenDuringPregnancy(resourcefilepath=resources), + contraception.Contraception(resourcefilepath=resources), + pregnancy_supervisor.PregnancySupervisor(resourcefilepath=resources), + postnatal_supervisor.PostnatalSupervisor(resourcefilepath=resources), + newborn_outcomes.NewbornOutcomes(resourcefilepath=resources), + hiv.Hiv(resourcefilepath=resources), + wasting.Wasting(resourcefilepath=resources), +) + +sim.make_initial_population(n=pop_size) +sim.simulate(end_date=end_date) + +# %% read the results +output = parse_log_file(sim.log_filepath) +print(output) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index bd2fde898e..7254b394f7 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -34,8 +34,8 @@ class Wasting(Module): This module applies the prevalence of wasting at the population-level, based on the Malawi DHS Survey 2015-2016. The definitions: - - moderate wasting: height-for-age Z-score (WHZ) <-2 SD from the reference mean - - severe wasting: height-for-age Z-score (WHZ) <-3 SD from the reference mean + - moderate wasting: weight_for_height Z-score (WHZ) <-2 SD from the reference mean + - severe wasting: weight_for_height Z-score (WHZ) <-3 SD from the reference mean """ @@ -58,8 +58,6 @@ class Wasting(Module): 'SAM': Cause(gbd_causes='Protein-energy malnutrition', label='Childhood Wasting') } - wasting_states = ['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2'] - PARAMETERS = { # prevalence of wasting by age group 'prev_WHZ_distribution_age_0_5mo': Parameter( @@ -180,9 +178,9 @@ class Wasting(Module): PROPERTIES = { # Properties related to wasting 'un_ever_wasted': Property(Types.BOOL, 'had wasting before WHZ <-2'), - 'un_WHZ_category': Property(Types.CATEGORICAL, 'height-for-age z-score group', + 'un_WHZ_category': Property(Types.CATEGORICAL, 'weight-for-height z-score group', categories=['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2']), - 'un_last_wasting_date_of_onset': Property(Types.DATE, 'date of onset of lastest wasting episode'), + 'un_last_wasting_date_of_onset': Property(Types.DATE, 'date of onset of latest wasting episode'), # Properties related to clinical acute malnutrition 'un_clinical_acute_malnutrition': Property(Types.CATEGORICAL, 'clinical acute malnutrition state based on WHZ', @@ -200,6 +198,8 @@ class Wasting(Module): ['none', 'not_applicable']), } + wasting_states = ['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2'] + def __init__(self, name=None, resourcefilepath=None): super().__init__(name) self.resourcefilepath = resourcefilepath @@ -264,7 +264,7 @@ def read_parameters(self, data_folder): # Update parameters from the resource dataframe # Read parameters from the resourcefile self.load_parameters_from_dataframe( - pd.read_excel(Path(self.resourcefilepath) / 'ResourceFile_Undernutrition.xlsx', + pd.read_excel(Path(self.resourcefilepath) / 'ResourceFile_Wasting.xlsx', sheet_name='Parameter_values_AM')) p = self.parameters @@ -1366,7 +1366,7 @@ def __init__(self, module, person_id): # Define the necessary information for an HSI self.TREATMENT_ID = 'supplementary_feeding_programme_for_MAM' self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint - self.ACCEPTED_FACILITY_LEVEL = 1 + self.ACCEPTED_FACILITY_LEVEL = '1a' self.ALERT_OTHER_DISEASES = [] def apply(self, person_id, squeeze_factor): @@ -1380,7 +1380,7 @@ def apply(self, person_id, squeeze_factor): # Do here whatever happens to an individual during this health system interaction event # ~~~~~~~~~~~~~~~~~~~~~~ # Make request for some consumables - consumables = self.sim.modules['HealthSystem'].parameters['Consumables'] + consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] # whole package of interventions pkg_code_mam = pd.unique( consumables.loc[consumables['Intervention_Pkg'] == 'Management of moderate acute malnutrition (children)', @@ -1392,11 +1392,11 @@ def apply(self, person_id, squeeze_factor): consumables_needed = {'Intervention_Package_Code': {pkg_code_mam: 1}, 'Item_Code': {item_code1: 1}} # check availability of consumables - outcome_of_request_for_consumables = self.sim.modules['HealthSystem'].request_consumables( - hsi_event=self, cons_req_as_footprint=consumables_needed) + # outcome_of_request_for_consumables = self.sim.modules['HealthSystem'].request_consumables( + # hsi_event=self, cons_req_as_footprint=consumables_needed) # answer comes back in the same format, but with quantities replaced with bools indicating availability - if outcome_of_request_for_consumables['Intervention_Package_Code'][pkg_code_mam]: - logger.debug(key='debug', data='PkgCode1 is available, so use it.') + if self.get_consumables([item_code1]): + logger.debug(key='debug', data='consumables are available') # Log that the treatment is provided: df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=3) @@ -1438,7 +1438,7 @@ def __init__(self, module, person_id): # Define the necessary information for an HSI self.TREATMENT_ID = 'outpatient_therapeutic_programme_for_SAM' self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint - self.ACCEPTED_FACILITY_LEVEL = 1 + self.ACCEPTED_FACILITY_LEVEL = '1a' self.ALERT_OTHER_DISEASES = [] def apply(self, person_id, squeeze_factor): @@ -1452,7 +1452,7 @@ def apply(self, person_id, squeeze_factor): # Do here whatever happens to an individual during this health system interaction event # ~~~~~~~~~~~~~~~~~~~~~~ # Make request for some consumables - consumables = self.sim.modules['HealthSystem'].parameters['Consumables'] + consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] # whole package of interventions pkg_code_sam = pd.unique( consumables.loc[consumables['Intervention_Pkg'] == 'Management of severe malnutrition (children)', @@ -1467,18 +1467,18 @@ def apply(self, person_id, squeeze_factor): item_code2: 1}} # check availability of consumables - outcome_of_request_for_consumables = self.sim.modules['HealthSystem'].request_consumables( - hsi_event=self, cons_req_as_footprint=consumables_needed) + # outcome_of_request_for_consumables = self.sim.modules['HealthSystem'].request_consumables( + # hsi_event=self, cons_req_as_footprint=consumables_needed) # answer comes back in the same format, but with quantities replaced with bools indicating availability - if outcome_of_request_for_consumables['Intervention_Package_Code'][pkg_code_sam]: - logger.debug(key='debug', data='PkgCode1 is available, so use it.') + if self.get_consumables(item_code1) and self.get_consumables(item_code2): + logger.debug(key='debug', data='consumables are available.') # Log that the treatment is provided: df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=3) df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' self.module.do_when_am_treatment(person_id, intervention='OTC') else: - logger.debug(key='debug', data="PkgCode1 is not available, so can't use it.") + logger.debug(key='debug', data="consumables not available, so can't use it.") # -------------------------------------------------------------------------------------------------- # # check to see if all consumables returned (for demonstration purposes): # all_available = (outcome_of_request_for_consumables['Intervention_Package_Code'][pkg_code_sam]) and \ @@ -1513,7 +1513,7 @@ def __init__(self, module, person_id): # Define the necessary information for an HSI self.TREATMENT_ID = 'inpatient_care_for_complicated_SAM' self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint - self.ACCEPTED_FACILITY_LEVEL = 2 + self.ACCEPTED_FACILITY_LEVEL = '2' self.ALERT_OTHER_DISEASES = [] self.BEDDAYS_FOOTPRINT = self.make_beddays_footprint({'general_bed': 7}) @@ -1528,7 +1528,7 @@ def apply(self, person_id, squeeze_factor): # Do here whatever happens to an individual during this health system interaction event # ~~~~~~~~~~~~~~~~~~~~~~ # Make request for some consumables - consumables = self.sim.modules['HealthSystem'].parameters['Consumables'] + consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] # whole package of interventions pkg_code_sam = pd.unique( consumables.loc[consumables['Intervention_Pkg'] == 'Management of severe malnutrition (children)', @@ -1539,22 +1539,25 @@ def apply(self, person_id, squeeze_factor): item_code2 = pd.unique( consumables.loc[consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] + pkg_codes = self.sim.modules['HealthSystem'].get_item_codes_from_package_name + pkg_codes_num = pkg_codes('Management of severe malnutrition (children)') + consumables_needed = {'Intervention_Package_Code': {pkg_code_sam: 1}, 'Item_Code': {item_code1: 1, item_code2: 1}} - # check availability of consumables - outcome_of_request_for_consumables = self.sim.modules['HealthSystem'].request_consumables( - hsi_event=self, cons_req_as_footprint=consumables_needed) + # # check availability of consumables + # outcome_of_request_for_consumables = self.sim.modules['HealthSystem'].request_consumables( + # hsi_event=self, cons_req_as_footprint=consumables_needed) # answer comes back in the same format, but with quantities replaced with bools indicating availability - if outcome_of_request_for_consumables['Intervention_Package_Code'][pkg_code_sam]: - logger.debug(key='debug', data='PkgCode1 is available, so use it.') + if self.get_consumables(item_code1) and self.get_consumables(item_code2): + logger.debug(key='debug', data='consumables available, so use it.') # Log that the treatment is provided: df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=4) df.at[person_id, 'un_am_treatment_type'] = 'inpatient_care' self.module.do_when_am_treatment(person_id, intervention='ITC') else: - logger.debug(key='debug', data="PkgCode1 is not available, so can't use it.") + logger.debug(key='debug', data="consumables not available, so can't use it.") # -------------------------------------------------------------------------------------------------- # # check to see if all consumables returned (for demonstration purposes): # all_available = (outcome_of_request_for_consumables['Intervention_Package_Code'][pkg_code_sam]) and \ @@ -1625,50 +1628,3 @@ def apply(self, population): '48_59mo': currently_wasted_age_48_59mo} logger.info(key='wasting_prevalence_count', data=currently_wasted) - - -class PropertiesOfOtherModules(Module): - """For the purpose of the testing, this module generates the properties upon which the Wasting module relies""" - - PROPERTIES = { - 'hv_inf': Property(Types.BOOL, 'temporary property'), - 'nb_low_birth_weight_status': Property(Types.CATEGORICAL, 'temporary property', - categories=['extremely_low_birth_weight', 'very_low_birth_weight', - 'low_birth_weight', 'normal_birth_weight']), - 'nb_size_for_gestational_age': Property(Types.CATEGORICAL, 'temporary property', - categories=['small_for_gestational_age', - 'average_for_gestational_age']), - 'nb_late_preterm': Property(Types.BOOL, 'temporary property'), - 'nb_early_preterm': Property(Types.BOOL, 'temporary property'), - - 'nb_breastfeeding_status': Property(Types.CATEGORICAL, 'temporary property', - categories=['none', 'non_exclusive', 'exclusive']), - - } - - def __init__(self, name=None): - super().__init__(name) - - def read_parameters(self, data_folder): - pass - - def initialise_population(self, population): - df = population.props - df.loc[df.is_alive, 'hv_inf'] = False - df.loc[df.is_alive, 'nb_low_birth_weight_status'] = 'normal_birth_weight' - df.loc[df.is_alive, 'nb_breastfeeding_status'] = 'exclusive' - df.loc[df.is_alive, 'nb_size_for_gestational_age'] = 'average_for_gestational_age' - df.loc[df.is_alive, 'nb_late_preterm'] = False - df.loc[df.is_alive, 'nb_early_preterm'] = False - - def initialise_simulation(self, sim): - pass - - def on_birth(self, mother, child): - df = self.sim.population.props - df.at[child, 'hv_inf'] = False - df.at[child, 'nb_low_birth_weight_status'] = 'normal_birth_weight' - df.at[child, 'nb_breastfeeding_status'] = 'exclusive' - df.at[child, 'nb_size_for_gestational_age'] = 'average_for_gestational_age' - df.at[child, 'nb_late_preterm'] = False - df.at[child, 'nb_early_preterm'] = False diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 53239a6dcf..382314d167 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -1,930 +1,923 @@ """ Basic tests for the Wasting Module """ - import os - from pathlib import Path - - import numpy as np - import pandas as pd - import pytest - - from tlo import Date, Simulation, logging - from tlo.analysis.utils import parse_log_file - from tlo.lm import LinearModel, LinearModelType - from tlo.methods import ( - demography, - wasting, - dx_algorithm_child, - enhanced_lifestyle, - healthburden, - healthseekingbehaviour, - healthsystem, - simplified_births, - symptommanager, - ) - - from tlo.methods.healthsystem import HSI_Event - - from tlo.methods.wasting import ( - AcuteMalnutritionDeathPollingEvent, - SevereAcuteMalnutritionDeathEvent, - ProgressionSevereWastingEvent, - WastingNaturalRecoveryEvent, - ClinicalAcuteMalnutritionRecoveryEvent, - WastingPollingEvent, - UpdateToMAM, - HSI_supplementary_feeding_programme_for_MAM, - HSI_outpatient_therapeutic_programme_for_SAM, - HSI_inpatient_care_for_complicated_SAM, - PropertiesOfOtherModules - ) - - # Path to the resource files used by the disease and intervention methods - resourcefilepath = Path(os.path.dirname(__file__)) / '../resources' - - # Default date for the start of simulations - start_date = Date(2010, 1, 1) - - - def get_sim(tmpdir): - """Return simulation objection with Wasting and other necessary modules registered.""" - sim = Simulation(start_date=start_date, seed=0, show_progress_bar=False, log_config={ - 'filename': 'tmp', - 'directory': tmpdir, - 'custom_levels': { - "*": logging.WARNING, - "tlo.methods.wasting": logging.INFO} - }) - - sim.register(demography.Demography(resourcefilepath=resourcefilepath), - enhanced_lifestyle.Lifestyle(resourcefilepath=resourcefilepath), - healthsystem.HealthSystem(resourcefilepath=resourcefilepath, disable=True), - symptommanager.SymptomManager(resourcefilepath=resourcefilepath), - healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resourcefilepath), - healthburden.HealthBurden(resourcefilepath=resourcefilepath), - simplified_births.SimplifiedBirths(resourcefilepath=resourcefilepath), - wasting.Wasting(resourcefilepath=resourcefilepath), - wasting.PropertiesOfOtherModules(), - dx_algorithm_child.DxAlgorithmChild(resourcefilepath=resourcefilepath) - ) - return sim - - - def check_dtypes(sim): - # Check types of columns - df = sim.population.props - orig = sim.population.new_row - assert (df.dtypes == orig.dtypes).all() - - - def check_configuration_of_properties(sim): - # check that the properties are ok: - - df = sim.population.props - - # Those that were never wasted, should have normal WHZ score: - assert (df.loc[~df.un_ever_wasted & ~df.date_of_birth.isna(), 'un_WHZ_category'] == 'WHZ>=-2').all().all() - - # Those that were never wasted and not clinically malnourished, - # should have not_applicable/null values for all the other properties: - # assert pd.isnull(df.loc[(~df.un_ever_wasted & ~df.date_of_birth.isna() & - # (df.un_clinical_acute_malnutrition == 'well')), - # ['un_last_wasting_date_of_onset', - # 'un_sam_death_date' - # ] - # ]).all().all() - - # # Those that were ever wasted, should have a WHZ score below <-2 - # assert (df.loc[df.un_ever_wasted, 'un_WHZ_category'] != 'WHZ>=-2').all().all() - # - # # Those that had wasting and no treatment, should have either a recovery date or a death_date - # # (but not both) - # has_recovery_date = ~pd.isnull(df.loc[df.un_ever_wasted & pd.isnull(df.un_acute_malnutrition_tx_start_date), - # 'un_am_recovery_date']) - # has_death_date = ~pd.isnull(df.loc[df.un_ever_wasted & pd.isnull(df.un_acute_malnutrition_tx_start_date), - # 'un_sam_death_date']) - - # has_recovery_date_or_death_date = has_recovery_date | has_death_date - # has_both_recovery_date_and_death_date = has_recovery_date & has_death_date - # # assert has_recovery_date_or_death_date.all() - # assert not has_both_recovery_date_and_death_date.any() - - # Those for whom the death date has past should be dead - assert not df.loc[df.un_ever_wasted & (df['un_sam_death_date'] < sim.date), 'is_alive'].any() - assert not df.loc[(df.un_clinical_acute_malnutrition == 'SAM') & ( - df['un_sam_death_date'] < sim.date), 'is_alive'].any() - - # Check that those in a current episode have symptoms of diarrhoea [caused by the diarrhoea module] - # but not others (among those who are alive) - has_symptoms_of_wasting = set(sim.modules['SymptomManager'].who_has('weight_loss')) - has_symptoms = set([p for p in has_symptoms_of_wasting if - 'Wasting' in sim.modules['SymptomManager'].causes_of(p, 'weight_loss') - ]) - - in_current_episode_before_recovery = \ - df.is_alive & \ - df.un_ever_wasted & \ - (df.un_last_wasting_date_of_onset <= sim.date) & \ - (sim.date <= df.un_am_recovery_date) - set_of_person_id_in_current_episode_before_recovery = set( - in_current_episode_before_recovery[in_current_episode_before_recovery].index - ) - - in_current_episode_before_death = \ - df.is_alive & \ - df.un_ever_wasted & \ - (df.un_last_wasting_date_of_onset <= sim.date) & \ - (sim.date <= df.un_sam_death_date) - set_of_person_id_in_current_episode_before_death = set( - in_current_episode_before_death[in_current_episode_before_death].index - ) - - in_current_episode_before_cure = \ - df.is_alive & \ - df.un_ever_wasted & \ - (df.un_last_wasting_date_of_onset <= sim.date) & \ - (df.un_acute_malnutrition_tx_start_date <= sim.date) & \ - pd.isnull(df.un_am_recovery_date) & \ - pd.isnull(df.un_sam_death_date) - set_of_person_id_in_current_episode_before_cure = set( - in_current_episode_before_cure[in_current_episode_before_cure].index - ) - - assert set() == set_of_person_id_in_current_episode_before_recovery.intersection( - set_of_person_id_in_current_episode_before_death - ) - - set_of_person_id_in_current_episode = set_of_person_id_in_current_episode_before_recovery.union( - set_of_person_id_in_current_episode_before_death, set_of_person_id_in_current_episode_before_cure - ) - assert set_of_person_id_in_current_episode == has_symptoms - - - def test_basic_run(tmpdir): - """Short run of the module using default parameters with check on dtypes""" - dur = pd.DateOffset(months=3) - popsize = 1000 - sim = get_sim(tmpdir) - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - check_dtypes(sim) - check_configuration_of_properties(sim) - - - def test_wasting_polling(tmpdir): - """Check polling events leads to incident cases""" - # get simulation object: - dur = pd.DateOffset(days=0) - popsize = 1000 - sim = get_sim(tmpdir) - - # Make incidence of wasting very high : - params = sim.modules['Wasting'].parameters - for p in params: - if p.startswith('base_inc_rate_wasting_by_agegp'): - params[p] = [3 * v for v in params[p]] - - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - - # Run polling event: check that a severe incident case is produced: - polling = WastingPollingEvent(sim.modules['Wasting']) - polling.apply(sim.population) - assert len([q for q in sim.event_queue.queue if isinstance(q[2], ProgressionSevereWastingEvent)]) > 0 - - # Check properties of this individual: should now be moderately wasted - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - person = df.loc[person_id] - assert person['un_ever_wasted'] == True - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date - - - def test_recovery_moderate_wasting(tmpdir): - """Check natual recovery of moderate wasting """ - dur = pd.DateOffset(days=0) - popsize = 1000 - sim = get_sim(tmpdir) - - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - - # Make 0% death rate by replacing with empty linear model 0.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 0.0) - - # increase incidence of wasting - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # remove progression to severe wasting - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 0.0) - - # Get person to use: - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' - - # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) - polling.apply(sim.population) - - # Check properties of this individual: should now be moderately wasted - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Check that there is a WastingNaturalRecoveryEvent scheduled for this person: - recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], WastingNaturalRecoveryEvent) - ][0] - date_of_scheduled_recov = recov_event_tuple[0] - recov_event = recov_event_tuple[1] - assert date_of_scheduled_recov > sim.date - - # Run the recovery event: - sim.date = date_of_scheduled_recov - recov_event.apply(person_id=person_id) - - # Check properties of this individual - person = df.loc[person_id] - assert person['un_WHZ_category'] == 'WHZ>=-2' - assert person['un_am_recovery_date'] == sim.date - assert pd.isnull(person['un_sam_death_date']) - - - def test_recovery_severe_wasting(tmpdir): - """ Check natural recovery to MAM by removing death rate for those with severe wasting, - and check the onset of symptoms with SAM and revolving of symptoms when recovered to MAM """ - dur = pd.DateOffset(days=0) - popsize = 1000 - sim = get_sim(tmpdir) - - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - - # Make 0% death rate by replacing with empty linear model 0.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 0.0) - - # increase incidence of wasting and progression to severe - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # Get person to use: - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' - - # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) - polling.apply(sim.population) - - # Check properties of this individual: should now be moderately wasted - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Check that there is a ProgressionSevereWastingEvent scheduled for this person: - progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ProgressionSevereWastingEvent) - ][0] - date_of_scheduled_progression = progression_event_tuple[0] - progression_event = progression_event_tuple[1] - assert date_of_scheduled_progression > sim.date - - # Run the progression to severe wasting event: - sim.date = date_of_scheduled_progression - progression_event.apply(person_id=person_id) - - # Check that they have some symptoms caused by Wasting (SAM only) - assert 0 < len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) - - # Check properties of this individual: (should now be severely wasted and without a scheduled death date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == 'WHZ<-3' - assert person['un_clinical_acute_malnutrition'] == 'SAM' - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Run Death Polling Polling event to apply death: - death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) - death_polling.apply(sim.population) - - # Check that there is a UpdateToMAM scheduled for this person: - recovery_to_mam_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], UpdateToMAM) - ][0] - print(sim.find_events_for_person(person_id)) - date_of_scheduled_recovery_to_mam = recovery_to_mam_event_tuple[0] - recovery_to_mam_event = recovery_to_mam_event_tuple[1] - assert date_of_scheduled_recovery_to_mam > sim.date - - # Run a Recovery SAM to MAM Event - sim.date = date_of_scheduled_recovery_to_mam - recovery_to_mam_event.apply(person_id=person_id) - - # Check properties of this individual - person = df.loc[person_id] - assert person['un_WHZ_category'] != 'WHZ<-3' - assert (person['un_am_MUAC_category'] == '115-<125mm' or person['un_WHZ_category'] == '-3<=WHZ<-2') - assert pd.isnull(person['un_sam_death_date']) - - # check they have no symptoms: - assert 0 == len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) - - - def test_nat_hist_death(tmpdir): - """Check: Wasting onset --> death""" - """ Check if the risk of death is 100% does everyone with SAM die? """ - dur = pd.DateOffset(days=0) - popsize = 1000 - sim = get_sim(tmpdir) - - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - - # Make 100% death rate by replacing with empty linear model 1.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # increase incidence of wasting and progression to severe - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # Get the children to use: - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' - - # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) - polling.apply(sim.population) - - # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Check that there is a ProgressionSevereWastingEvent scheduled for this person: - progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ProgressionSevereWastingEvent) - ][0] - date_of_scheduled_progression = progression_event_tuple[0] - progression_event = progression_event_tuple[1] - assert date_of_scheduled_progression > sim.date - - # Run the progression to severe wasting event: - sim.date = date_of_scheduled_progression - progression_event.apply(person_id=person_id) - - # Check properties of this individual: (should now be severely wasted and without a scheduled death date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == 'WHZ<-3' - assert person['un_clinical_acute_malnutrition'] == 'SAM' - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Run Death Polling Polling event to apply death: - death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) - death_polling.apply(sim.population) - - # Check that there is a SevereAcuteMalnutritionDeathEvent scheduled for this person: - death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) - ][0] - date_of_scheduled_death = death_event_tuple[0] - death_event = death_event_tuple[1] - assert date_of_scheduled_death > sim.date - - # Run the death event: - sim.date = date_of_scheduled_death - death_event.apply(person_id=person_id) - - # Check properties of this individual: (should now be dead) - person = df.loc[person_id] - assert not pd.isnull(person['un_sam_death_date']) - assert person['un_sam_death_date'] == sim.date - assert not person['is_alive'] - - - def test_nat_hist_cure_if_recovery_scheduled(tmpdir): - """Show that if a cure event is run before when a person was going to recover naturally, it cause the episode to - end earlier.""" - - dur = pd.DateOffset(days=0) - popsize = 1000 - sim = get_sim(tmpdir) - - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - - # Make 0% death rate by replacing with empty linear model 0.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 0.0) - - # increase incidence of wasting - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # decrease progression to severe of wasting - so all children stay in moderate wasting state only - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 0.0) - - # Get person to use: - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' - - # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) - polling.apply(sim.population) - - # Check properties of this individual: (should now be moderately wasted without progression to severe) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - print(sim.find_events_for_person(person_id)) - - # Check that there is a WastingNaturalRecoveryEvent scheduled for this person: - recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], WastingNaturalRecoveryEvent) - ][0] - date_of_scheduled_recov = recov_event_tuple[0] - recov_event = recov_event_tuple[1] - assert date_of_scheduled_recov > sim.date - - # Run a Cure Event - cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) - cure_event.apply(person_id=person_id) - - # Check that the person is not wasted and is alive still: - person = df.loc[person_id] - assert person['is_alive'] - assert person['un_WHZ_category'] == 'WHZ>=-2' - assert not pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Run the recovery event that was originally scheduled - this should have no effect - sim.date = date_of_scheduled_recov - recov_event.apply(person_id=person_id) - person = df.loc[person_id] - assert person['is_alive'] - assert person['un_WHZ_category'] == 'WHZ>=-2' - assert not pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - - def test_nat_hist_cure_if_death_scheduled(tmpdir): - """Show that if a cure event is run before when a person was going to die, it cause the episode to end without - the person dying.""" - - dur = pd.DateOffset(days=0) - popsize = 1000 - sim = get_sim(tmpdir) - - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - - # Make 100% death rate by replacing with empty linear model 1.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # increase incidence of wasting and progression to severe - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - # increase parameters in moderate wasting for clinical SAM (MUAC and oedema) to be polled for death - params = sim.modules['Wasting'].parameters - params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = [5 * params['proportion_-3<=WHZ<-2_with_MUAC<115mm']] - params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] = [params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] / 5] - params['proportion_oedema_with_WHZ<-2'] = 0.9 - - # Get person to use: - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' - - # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) - polling.apply(sim.population) - - # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Check that there is a ProgressionSevereWastingEvent scheduled for this person: - progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ProgressionSevereWastingEvent) - ][0] - date_of_scheduled_progression = progression_event_tuple[0] - progression_event = progression_event_tuple[1] - assert date_of_scheduled_progression > sim.date - - # Run the progression to severe wasting event: - sim.date = date_of_scheduled_progression - progression_event.apply(person_id=person_id) - - # Check properties of this individual: (should now be severely wasted and without a scheduled death date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == 'WHZ<-3' - assert person['un_clinical_acute_malnutrition'] == 'SAM' - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Run Death Polling Polling event to apply death: - death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) - death_polling.apply(sim.population) - - # Check that there is a SevereAcuteMalnutritionDeathEvent scheduled for this person: - death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) - ][0] - date_of_scheduled_death = death_event_tuple[0] - death_event = death_event_tuple[1] - assert date_of_scheduled_death > sim.date - - # Run a Cure Event now - cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) - cure_event.apply(person_id=person_id) - - # Check that the person is not wasted and is alive still: - person = df.loc[person_id] - assert person['is_alive'] - assert person['un_WHZ_category'] == 'WHZ>=-2' - assert not pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Run the death event that was originally scheduled - this should have no effect and the person should not die - sim.date = date_of_scheduled_death - death_event.apply(person_id=person_id) - person = df.loc[person_id] - assert person['is_alive'] - - - def test_treatment(tmpdir): - """ Test that providing a treatment prevent death and causes there to be a - CureEvent (ClinicalAcuteMalnutritionRecoveryEvent) Scheduled """ - """ - This test sets the linear model of acute_malnutrition_recovery_based_on_interventions to be 1.0 (100% cure rate), - when this lm is called in the do_when_am_treatment function (usually called in HSIs), 100% cure rate schedules the - ClinicalAcuteMalnutritionRecoveryEvent (CureEvent). - Death is prevented. ---> check - """ - # TODO: CHECK THIS - MAYBE NOT NEEDED - - dur = pd.DateOffset(days=0) - popsize = 1000 - sim = get_sim(tmpdir) - - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - - # Make 100% death rate by replacing with empty linear model 1.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # increase incidence of wasting and progression to severe - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # increase parameters in moderate wasting for clinical SAM (MUAC and oedema) to be polled for death - params = sim.modules['Wasting'].parameters - params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = [5 * params['proportion_-3<=WHZ<-2_with_MUAC<115mm']] - params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] = [params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] / 5] - params['proportion_oedema_with_WHZ<-2'] = 0.9 - - # Get person to use: - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' - - # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) - polling.apply(sim.population) - - # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Check that there is a ProgressionSevereWastingEvent scheduled for this person: - progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ProgressionSevereWastingEvent) - ][0] - date_of_scheduled_progression = progression_event_tuple[0] - progression_event = progression_event_tuple[1] - assert date_of_scheduled_progression > sim.date - - # Run the progression to severe wasting event: - sim.date = date_of_scheduled_progression - progression_event.apply(person_id=person_id) - - # Check properties of this individual: (should now be severely wasted and without a scheduled death date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == 'WHZ<-3' - assert person['un_clinical_acute_malnutrition'] == 'SAM' - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Run Death Polling event to apply death: - death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) - death_polling.apply(sim.population) - - # Check that there is a SevereAcuteMalnutritionDeathEvent scheduled for this person: - death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) - ][0] - date_of_scheduled_death = death_event_tuple[0] - death_event = death_event_tuple[1] - assert date_of_scheduled_death > sim.date - - # # change coverage and treatment effectiveness set to be 100% - # params['coverage_supplementary_feeding_program'] = 1.0 - # params['coverage_outpatient_therapeutic_care'] = 1.0 - # params['coverage_inpatient_care'] = 1.0 - # params['recovery_rate_with_soy_RUSF'] = 1.0 - # params['recovery_rate_with_CSB++'] = 1.0 - # params['recovery_rate_with_standard_RUTF'] = 1.0 - # params['recovery_rate_with_inpatient_care'] = 1.0 - - # Make 100% death rate by replacing with empty linear model 1.0 - for am in ['MAM', 'SAM']: - sim.modules['Wasting'].acute_malnutrition_recovery_based_on_interventions[am] = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # Run the 'do_when_am_treatment' function - interventions = ['SFP', 'OTC', 'ITC'] - for int in interventions: - sim.modules['Wasting'].do_when_am_treatment(person_id=person_id, intervention=int) - - # Run the death event that was originally scheduled - this should have no effect and the person should not die - sim.date = date_of_scheduled_death - death_event.apply(person_id=person_id) - person = df.loc[person_id] - assert person['is_alive'] - - # print(sim.find_events_for_person(person_id)) - - # Check that a CureEvent has been scheduled - cure_event = [event_tuple[1] for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] - - # Run the CureEvent - cure_event.apply(person_id=person_id) - - # Check that the person is not infected and is alive still: - person = df.loc[person_id] - assert person['is_alive'] - assert person['un_WHZ_category'] == 'WHZ>=-2' - assert not pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - - def test_use_of_HSI_for_MAM(tmpdir): - """ Check that the HSIs works""" - dur = pd.DateOffset(days=0) - popsize = 1000 - sim = get_sim(tmpdir) - - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - - # Make 100% death rate by replacing with empty linear model 1.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # increase incidence of wasting - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # reduce progression to severe wasting - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 0.0) - - # decrease MUAC and oedema parameters in moderate wasting for clinical SAM - params = sim.modules['Wasting'].parameters - params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = 0.0 # no SAM with moderate wasting - params['proportion_oedema_with_WHZ<-2'] = 0.0 # no SAM based on oedema - params['prevalence_nutritional_oedema'] = 0.0 # no SAM based on oedema - - # Get person to use: - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' - - # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) - polling.apply(sim.population) - - # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_clinical_acute_malnutrition'] == 'MAM' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - # Check not on treatment: - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - - # Run the HSI event - hsi = HSI_supplementary_feeding_programme_for_MAM(person_id=person_id, module=sim.modules['Wasting']) - hsi.run(squeeze_factor=0.0) - - # Check that person is now on treatment: - assert sim.date == df.at[person_id, 'un_acute_malnutrition_tx_start_date'] - - # Check that a CureEvent has been scheduled - cure_event = [event_tuple[1] for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] - - # Run the CureEvent - cure_event.apply(person_id=person_id) - - # Check that the person is cured and is alive still: - person = df.loc[person_id] - assert person['is_alive'] - assert person['un_WHZ_category'] == 'WHZ>=-2' - assert person['un_clinical_acute_malnutrition'] == 'well' - assert not pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - - def test_use_of_HSI_for_SAM(tmpdir): - """ Check that the HSI_outpatient_therapeutic_programme_for_SAM and HSI_inpatient_care_for_complicated_SAM work""" - - def test_use_of_HSI_by_complication(complications): - dur = pd.DateOffset(days=0) - popsize = 1000 - sim = get_sim(tmpdir) - - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - - # Make 100% death rate by replacing with empty linear model 1.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # Make 100% treatment effectiveness by replacing with empty linear model 1.0 - for am in ['MAM', 'SAM']: - sim.modules['Wasting'].acute_malnutrition_recovery_based_on_interventions[am] = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # increase incidence of wasting and progression to severe - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # remove the probability of complications in SAM - params = sim.modules['Wasting'].parameters - if complications: - params['prob_complications_in_SAM'] = 1.0 # only SAM with complications - else: - params['prob_complications_in_SAM'] = 0.0 # no SAM with complications - - # # change coverage and treatment effectiveness set to be 100% - # params['coverage_supplementary_feeding_program'] = 1.0 - # params['coverage_outpatient_therapeutic_care'] = 1.0 - # params['coverage_inpatient_care'] = 1.0 - # params['recovery_rate_with_soy_RUSF'] = 1.0 - # params['recovery_rate_with_CSB++'] = 1.0 - # params['recovery_rate_with_standard_RUTF'] = 1.0 - # params['recovery_rate_with_inpatient_care'] = 1.0 - - # Make 100% death rate by replacing with empty linear model 1.0 - sim.modules['Wasting'].acute_malnutrition_recovery_based_on_interventions['SAM'] = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # Get person to use: - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' - - # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) - polling.apply(sim.population) - - # Check properties of this individual: - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - # Check not on treatment: - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - - # Check that there is a ProgressionSevereWastingEvent scheduled for this person: - progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ProgressionSevereWastingEvent) - ][0] - date_of_scheduled_progression = progression_event_tuple[0] - progression_event = progression_event_tuple[1] - assert date_of_scheduled_progression > sim.date - - # Run the progression to severe wasting event: - sim.date = date_of_scheduled_progression - progression_event.apply(person_id=person_id) - - # Check properties of this individual: (should now be severely wasted and without a scheduled death date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == 'WHZ<-3' - assert person['un_clinical_acute_malnutrition'] == 'SAM' - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Run the HSI event - if complications: - hsi = HSI_inpatient_care_for_complicated_SAM(person_id=person_id, module=sim.modules['Wasting']) - hsi.run(squeeze_factor=0.0) - else: - hsi = HSI_outpatient_therapeutic_programme_for_SAM(person_id=person_id, module=sim.modules['Wasting']) - hsi.run(squeeze_factor=0.0) - - # Check that person is now on treatment: - assert sim.date == df.at[person_id, 'un_acute_malnutrition_tx_start_date'] - - print(sim.find_events_for_person(person_id)) - - # Check that a CureEvent has been scheduled - cure_event = [event_tuple[1] for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] - - # Run the CureEvent - cure_event.apply(person_id=person_id) - - # Check that the person is cured and is alive still: - person = df.loc[person_id] - assert person['is_alive'] - assert person['un_WHZ_category'] == 'WHZ>=-2' - assert person['un_clinical_acute_malnutrition'] == 'well' - assert not pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - test_use_of_HSI_by_complication(complications=True) - test_use_of_HSI_by_complication(complications=False) +import os +from pathlib import Path + +import pandas as pd + +from tlo import Date, Simulation, logging +from tlo.lm import LinearModel, LinearModelType +from tlo.methods import ( + demography, + wasting, + enhanced_lifestyle, + healthburden, + healthseekingbehaviour, + healthsystem, + simplified_births, + symptommanager, +) + +from tlo.methods.healthsystem import HSI_Event + +from tlo.methods.wasting import ( + AcuteMalnutritionDeathPollingEvent, + SevereAcuteMalnutritionDeathEvent, + ProgressionSevereWastingEvent, + WastingNaturalRecoveryEvent, + ClinicalAcuteMalnutritionRecoveryEvent, + WastingPollingEvent, + UpdateToMAM, + HSI_supplementary_feeding_programme_for_MAM, + HSI_outpatient_therapeutic_programme_for_SAM, + HSI_inpatient_care_for_complicated_SAM, +) + +# Path to the resource files used by the disease and intervention methods +resourcefilepath = Path(os.path.dirname(__file__)) / '../resources' + +# Default date for the start of simulations +start_date = Date(2010, 1, 1) + + +def get_sim(tmpdir): + """Return simulation objection with Wasting and other necessary modules registered.""" + sim = Simulation(start_date=start_date, seed=0, show_progress_bar=False, log_config={ + 'filename': 'tmp', + 'directory': tmpdir, + 'custom_levels': { + "*": logging.WARNING, + "tlo.methods.wasting": logging.INFO} + }) + + sim.register(demography.Demography(resourcefilepath=resourcefilepath), + enhanced_lifestyle.Lifestyle(resourcefilepath=resourcefilepath), + healthsystem.HealthSystem(resourcefilepath=resourcefilepath, disable=True), + symptommanager.SymptomManager(resourcefilepath=resourcefilepath), + healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resourcefilepath), + healthburden.HealthBurden(resourcefilepath=resourcefilepath), + simplified_births.SimplifiedBirths(resourcefilepath=resourcefilepath), + wasting.Wasting(resourcefilepath=resourcefilepath) + ) + return sim + + +def check_dtypes(sim): + # Check types of columns + df = sim.population.props + orig = sim.population.new_row + assert (df.dtypes == orig.dtypes).all() + + +def check_configuration_of_properties(sim): + # check that the properties are ok: + + df = sim.population.props + + # Those that were never wasted, should have normal WHZ score: + assert (df.loc[~df.un_ever_wasted & ~df.date_of_birth.isna(), 'un_WHZ_category'] == 'WHZ>=-2').all().all() + + # Those that were never wasted and not clinically malnourished, + # should have not_applicable/null values for all the other properties: + # assert pd.isnull(df.loc[(~df.un_ever_wasted & ~df.date_of_birth.isna() & + # (df.un_clinical_acute_malnutrition == 'well')), + # ['un_last_wasting_date_of_onset', + # 'un_sam_death_date' + # ] + # ]).all().all() + + # # Those that were ever wasted, should have a WHZ score below <-2 + # assert (df.loc[df.un_ever_wasted, 'un_WHZ_category'] != 'WHZ>=-2').all().all() + # + # # Those that had wasting and no treatment, should have either a recovery date or a death_date + # # (but not both) + # has_recovery_date = ~pd.isnull(df.loc[df.un_ever_wasted & pd.isnull(df.un_acute_malnutrition_tx_start_date), + # 'un_am_recovery_date']) + # has_death_date = ~pd.isnull(df.loc[df.un_ever_wasted & pd.isnull(df.un_acute_malnutrition_tx_start_date), + # 'un_sam_death_date']) + + # has_recovery_date_or_death_date = has_recovery_date | has_death_date + # has_both_recovery_date_and_death_date = has_recovery_date & has_death_date + # # assert has_recovery_date_or_death_date.all() + # assert not has_both_recovery_date_and_death_date.any() + + # Those for whom the death date has past should be dead + assert not df.loc[df.un_ever_wasted & (df['un_sam_death_date'] < sim.date), 'is_alive'].any() + assert not df.loc[(df.un_clinical_acute_malnutrition == 'SAM') & ( + df['un_sam_death_date'] < sim.date), 'is_alive'].any() + + # Check that those in a current episode have symptoms of diarrhoea [caused by the diarrhoea module] + # but not others (among those who are alive) + has_symptoms_of_wasting = set(sim.modules['SymptomManager'].who_has('weight_loss')) + has_symptoms = set([p for p in has_symptoms_of_wasting if + 'Wasting' in sim.modules['SymptomManager'].causes_of(p, 'weight_loss') + ]) + + in_current_episode_before_recovery = \ + df.is_alive & \ + df.un_ever_wasted & \ + (df.un_last_wasting_date_of_onset <= sim.date) & \ + (sim.date <= df.un_am_recovery_date) + set_of_person_id_in_current_episode_before_recovery = set( + in_current_episode_before_recovery[in_current_episode_before_recovery].index + ) + + in_current_episode_before_death = \ + df.is_alive & \ + df.un_ever_wasted & \ + (df.un_last_wasting_date_of_onset <= sim.date) & \ + (sim.date <= df.un_sam_death_date) + set_of_person_id_in_current_episode_before_death = set( + in_current_episode_before_death[in_current_episode_before_death].index + ) + + in_current_episode_before_cure = \ + df.is_alive & \ + df.un_ever_wasted & \ + (df.un_last_wasting_date_of_onset <= sim.date) & \ + (df.un_acute_malnutrition_tx_start_date <= sim.date) & \ + pd.isnull(df.un_am_recovery_date) & \ + pd.isnull(df.un_sam_death_date) + set_of_person_id_in_current_episode_before_cure = set( + in_current_episode_before_cure[in_current_episode_before_cure].index + ) + + assert set() == set_of_person_id_in_current_episode_before_recovery.intersection( + set_of_person_id_in_current_episode_before_death + ) + + set_of_person_id_in_current_episode = set_of_person_id_in_current_episode_before_recovery.union( + set_of_person_id_in_current_episode_before_death, set_of_person_id_in_current_episode_before_cure + ) + assert set_of_person_id_in_current_episode == has_symptoms + + +def test_basic_run(tmpdir): + """Short run of the module using default parameters with check on dtypes""" + dur = pd.DateOffset(months=3) + popsize = 1000 + sim = get_sim(tmpdir) + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + check_dtypes(sim) + check_configuration_of_properties(sim) + + +def test_wasting_polling(tmpdir): + """Check polling events leads to incident cases""" + # get simulation object: + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + # Make incidence of wasting very high : + params = sim.modules['Wasting'].parameters + for p in params: + if p.startswith('base_inc_rate_wasting_by_agegp'): + params[p] = [3 * v for v in params[p]] + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Run polling event: check that a severe incident case is produced: + polling = WastingPollingEvent(sim.modules['Wasting']) + polling.apply(sim.population) + assert len([q for q in sim.event_queue.queue if isinstance(q[2], ProgressionSevereWastingEvent)]) > 0 + + # Check properties of this individual: should now be moderately wasted + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + person = df.loc[person_id] + assert person['un_ever_wasted'] == True + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + + +def test_recovery_moderate_wasting(tmpdir): + """Check natual recovery of moderate wasting """ + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 0% death rate by replacing with empty linear model 0.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 0.0) + + # increase incidence of wasting + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # remove progression to severe wasting + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 0.0) + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: should now be moderately wasted + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Check that there is a WastingNaturalRecoveryEvent scheduled for this person: + recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], WastingNaturalRecoveryEvent) + ][0] + date_of_scheduled_recov = recov_event_tuple[0] + recov_event = recov_event_tuple[1] + assert date_of_scheduled_recov > sim.date + + # Run the recovery event: + sim.date = date_of_scheduled_recov + recov_event.apply(person_id=person_id) + + # Check properties of this individual + person = df.loc[person_id] + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert person['un_am_recovery_date'] == sim.date + assert pd.isnull(person['un_sam_death_date']) + + +def test_recovery_severe_wasting(tmpdir): + """ Check natural recovery to MAM by removing death rate for those with severe wasting, + and check the onset of symptoms with SAM and revolving of symptoms when recovered to MAM """ + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 0% death rate by replacing with empty linear model 0.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 0.0) + + # increase incidence of wasting and progression to severe + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: should now be moderately wasted + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Check that there is a ProgressionSevereWastingEvent scheduled for this person: + progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ProgressionSevereWastingEvent) + ][0] + date_of_scheduled_progression = progression_event_tuple[0] + progression_event = progression_event_tuple[1] + assert date_of_scheduled_progression > sim.date + + # Run the progression to severe wasting event: + sim.date = date_of_scheduled_progression + progression_event.apply(person_id=person_id) + + # Check that they have some symptoms caused by Wasting (SAM only) + assert 0 < len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) + + # Check properties of this individual: (should now be severely wasted and without a scheduled death date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == 'WHZ<-3' + assert person['un_clinical_acute_malnutrition'] == 'SAM' + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Run Death Polling Polling event to apply death: + death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) + death_polling.apply(sim.population) + + # Check that there is a UpdateToMAM scheduled for this person: + recovery_to_mam_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], UpdateToMAM) + ][0] + print(sim.find_events_for_person(person_id)) + date_of_scheduled_recovery_to_mam = recovery_to_mam_event_tuple[0] + recovery_to_mam_event = recovery_to_mam_event_tuple[1] + assert date_of_scheduled_recovery_to_mam > sim.date + + # Run a Recovery SAM to MAM Event + sim.date = date_of_scheduled_recovery_to_mam + recovery_to_mam_event.apply(person_id=person_id) + + # Check properties of this individual + person = df.loc[person_id] + assert person['un_WHZ_category'] != 'WHZ<-3' + assert (person['un_am_MUAC_category'] == '115-<125mm' or person['un_WHZ_category'] == '-3<=WHZ<-2') + assert pd.isnull(person['un_sam_death_date']) + + # check they have no symptoms: + assert 0 == len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) + + +def test_nat_hist_death(tmpdir): + """Check: Wasting onset --> death""" + """ Check if the risk of death is 100% does everyone with SAM die? """ + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 100% death rate by replacing with empty linear model 1.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # increase incidence of wasting and progression to severe + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # Get the children to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Check that there is a ProgressionSevereWastingEvent scheduled for this person: + progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ProgressionSevereWastingEvent) + ][0] + date_of_scheduled_progression = progression_event_tuple[0] + progression_event = progression_event_tuple[1] + assert date_of_scheduled_progression > sim.date + + # Run the progression to severe wasting event: + sim.date = date_of_scheduled_progression + progression_event.apply(person_id=person_id) + + # Check properties of this individual: (should now be severely wasted and without a scheduled death date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == 'WHZ<-3' + assert person['un_clinical_acute_malnutrition'] == 'SAM' + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Run Death Polling Polling event to apply death: + death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) + death_polling.apply(sim.population) + + # Check that there is a SevereAcuteMalnutritionDeathEvent scheduled for this person: + death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) + ][0] + date_of_scheduled_death = death_event_tuple[0] + death_event = death_event_tuple[1] + assert date_of_scheduled_death > sim.date + + # Run the death event: + sim.date = date_of_scheduled_death + death_event.apply(person_id=person_id) + + # Check properties of this individual: (should now be dead) + person = df.loc[person_id] + assert not pd.isnull(person['un_sam_death_date']) + assert person['un_sam_death_date'] == sim.date + assert not person['is_alive'] + + +def test_nat_hist_cure_if_recovery_scheduled(tmpdir): + """Show that if a cure event is run before when a person was going to recover naturally, it cause the episode to + end earlier.""" + + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 0% death rate by replacing with empty linear model 0.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 0.0) + + # increase incidence of wasting + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # decrease progression to severe of wasting - so all children stay in moderate wasting state only + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 0.0) + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: (should now be moderately wasted without progression to severe) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + print(sim.find_events_for_person(person_id)) + + # Check that there is a WastingNaturalRecoveryEvent scheduled for this person: + recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], WastingNaturalRecoveryEvent) + ][0] + date_of_scheduled_recov = recov_event_tuple[0] + recov_event = recov_event_tuple[1] + assert date_of_scheduled_recov > sim.date + + # Run a Cure Event + cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) + cure_event.apply(person_id=person_id) + + # Check that the person is not wasted and is alive still: + person = df.loc[person_id] + assert person['is_alive'] + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert not pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Run the recovery event that was originally scheduled - this should have no effect + sim.date = date_of_scheduled_recov + recov_event.apply(person_id=person_id) + person = df.loc[person_id] + assert person['is_alive'] + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert not pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + +def test_nat_hist_cure_if_death_scheduled(tmpdir): + """Show that if a cure event is run before when a person was going to die, it cause the episode to end without + the person dying.""" + + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 100% death rate by replacing with empty linear model 1.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # increase incidence of wasting and progression to severe + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + # increase parameters in moderate wasting for clinical SAM (MUAC and oedema) to be polled for death + params = sim.modules['Wasting'].parameters + params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = [5 * params['proportion_-3<=WHZ<-2_with_MUAC<115mm']] + params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] = [params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] / 5] + params['proportion_oedema_with_WHZ<-2'] = 0.9 + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Check that there is a ProgressionSevereWastingEvent scheduled for this person: + progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ProgressionSevereWastingEvent) + ][0] + date_of_scheduled_progression = progression_event_tuple[0] + progression_event = progression_event_tuple[1] + assert date_of_scheduled_progression > sim.date + + # Run the progression to severe wasting event: + sim.date = date_of_scheduled_progression + progression_event.apply(person_id=person_id) + + # Check properties of this individual: (should now be severely wasted and without a scheduled death date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == 'WHZ<-3' + assert person['un_clinical_acute_malnutrition'] == 'SAM' + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Run Death Polling Polling event to apply death: + death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) + death_polling.apply(sim.population) + + # Check that there is a SevereAcuteMalnutritionDeathEvent scheduled for this person: + death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) + ][0] + date_of_scheduled_death = death_event_tuple[0] + death_event = death_event_tuple[1] + assert date_of_scheduled_death > sim.date + + # Run a Cure Event now + cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) + cure_event.apply(person_id=person_id) + + # Check that the person is not wasted and is alive still: + person = df.loc[person_id] + assert person['is_alive'] + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert not pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Run the death event that was originally scheduled - this should have no effect and the person should not die + sim.date = date_of_scheduled_death + death_event.apply(person_id=person_id) + person = df.loc[person_id] + assert person['is_alive'] + + +def test_treatment(tmpdir): + """ Test that providing a treatment prevent death and causes there to be a + CureEvent (ClinicalAcuteMalnutritionRecoveryEvent) Scheduled """ + """ + This test sets the linear model of acute_malnutrition_recovery_based_on_interventions to be 1.0 (100% cure rate), + when this lm is called in the do_when_am_treatment function (usually called in HSIs), 100% cure rate schedules the + ClinicalAcuteMalnutritionRecoveryEvent (CureEvent). + Death is prevented. ---> check + """ + # TODO: CHECK THIS - MAYBE NOT NEEDED + + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 100% death rate by replacing with empty linear model 1.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # increase incidence of wasting and progression to severe + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # increase parameters in moderate wasting for clinical SAM (MUAC and oedema) to be polled for death + params = sim.modules['Wasting'].parameters + params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = [5 * params['proportion_-3<=WHZ<-2_with_MUAC<115mm']] + params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] = [params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] / 5] + params['proportion_oedema_with_WHZ<-2'] = 0.9 + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Check that there is a ProgressionSevereWastingEvent scheduled for this person: + progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ProgressionSevereWastingEvent) + ][0] + date_of_scheduled_progression = progression_event_tuple[0] + progression_event = progression_event_tuple[1] + assert date_of_scheduled_progression > sim.date + + # Run the progression to severe wasting event: + sim.date = date_of_scheduled_progression + progression_event.apply(person_id=person_id) + + # Check properties of this individual: (should now be severely wasted and without a scheduled death date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == 'WHZ<-3' + assert person['un_clinical_acute_malnutrition'] == 'SAM' + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Run Death Polling event to apply death: + death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) + death_polling.apply(sim.population) + + # Check that there is a SevereAcuteMalnutritionDeathEvent scheduled for this person: + death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) + ][0] + date_of_scheduled_death = death_event_tuple[0] + death_event = death_event_tuple[1] + assert date_of_scheduled_death > sim.date + + # # change coverage and treatment effectiveness set to be 100% + # params['coverage_supplementary_feeding_program'] = 1.0 + # params['coverage_outpatient_therapeutic_care'] = 1.0 + # params['coverage_inpatient_care'] = 1.0 + # params['recovery_rate_with_soy_RUSF'] = 1.0 + # params['recovery_rate_with_CSB++'] = 1.0 + # params['recovery_rate_with_standard_RUTF'] = 1.0 + # params['recovery_rate_with_inpatient_care'] = 1.0 + + # Make 100% death rate by replacing with empty linear model 1.0 + for am in ['MAM', 'SAM']: + sim.modules['Wasting'].acute_malnutrition_recovery_based_on_interventions[am] = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # Run the 'do_when_am_treatment' function + interventions = ['SFP', 'OTC', 'ITC'] + for int in interventions: + sim.modules['Wasting'].do_when_am_treatment(person_id=person_id, intervention=int) + + # Run the death event that was originally scheduled - this should have no effect and the person should not die + sim.date = date_of_scheduled_death + death_event.apply(person_id=person_id) + person = df.loc[person_id] + assert person['is_alive'] + + # print(sim.find_events_for_person(person_id)) + + # Check that a CureEvent has been scheduled + cure_event = [event_tuple[1] for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] + + # Run the CureEvent + cure_event.apply(person_id=person_id) + + # Check that the person is not infected and is alive still: + person = df.loc[person_id] + assert person['is_alive'] + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert not pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + +def test_use_of_HSI_for_MAM(tmpdir): + """ Check that the HSIs works""" + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 100% death rate by replacing with empty linear model 1.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # increase incidence of wasting + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # reduce progression to severe wasting + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 0.0) + + # decrease MUAC and oedema parameters in moderate wasting for clinical SAM + params = sim.modules['Wasting'].parameters + params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = 0.0 # no SAM with moderate wasting + params['proportion_oedema_with_WHZ<-2'] = 0.0 # no SAM based on oedema + params['prevalence_nutritional_oedema'] = 0.0 # no SAM based on oedema + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_clinical_acute_malnutrition'] == 'MAM' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + # Check not on treatment: + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + + # Run the HSI event + hsi = HSI_supplementary_feeding_programme_for_MAM(person_id=person_id, module=sim.modules['Wasting']) + hsi.run(squeeze_factor=0.0) + + # Check that person is now on treatment: + assert sim.date == df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + + # Check that a CureEvent has been scheduled + cure_event = [event_tuple[1] for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] + + # Run the CureEvent + cure_event.apply(person_id=person_id) + + # Check that the person is cured and is alive still: + person = df.loc[person_id] + assert person['is_alive'] + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert person['un_clinical_acute_malnutrition'] == 'well' + assert not pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + +def test_use_of_HSI_for_SAM(tmpdir): + """ Check that the HSI_outpatient_therapeutic_programme_for_SAM and HSI_inpatient_care_for_complicated_SAM work""" + + def test_use_of_HSI_by_complication(complications): + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Make 100% death rate by replacing with empty linear model 1.0 + sim.modules['Wasting'].sam_death_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # Make 100% treatment effectiveness by replacing with empty linear model 1.0 + for am in ['MAM', 'SAM']: + sim.modules['Wasting'].acute_malnutrition_recovery_based_on_interventions[am] = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # increase incidence of wasting and progression to severe + sim.modules['Wasting'].wasting_incidence_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # remove the probability of complications in SAM + params = sim.modules['Wasting'].parameters + if complications: + params['prob_complications_in_SAM'] = 1.0 # only SAM with complications + else: + params['prob_complications_in_SAM'] = 0.0 # no SAM with complications + + # # change coverage and treatment effectiveness set to be 100% + # params['coverage_supplementary_feeding_program'] = 1.0 + # params['coverage_outpatient_therapeutic_care'] = 1.0 + # params['coverage_inpatient_care'] = 1.0 + # params['recovery_rate_with_soy_RUSF'] = 1.0 + # params['recovery_rate_with_CSB++'] = 1.0 + # params['recovery_rate_with_standard_RUTF'] = 1.0 + # params['recovery_rate_with_inpatient_care'] = 1.0 + + # Make 100% death rate by replacing with empty linear model 1.0 + sim.modules['Wasting'].acute_malnutrition_recovery_based_on_interventions['SAM'] = LinearModel( + LinearModelType.MULTIPLICATIVE, 1.0) + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + + # Run Wasting Polling event to get new incident cases: + polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling.apply(sim.population) + + # Check properties of this individual: + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + # Check not on treatment: + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + + # Check that there is a ProgressionSevereWastingEvent scheduled for this person: + progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ProgressionSevereWastingEvent) + ][0] + date_of_scheduled_progression = progression_event_tuple[0] + progression_event = progression_event_tuple[1] + assert date_of_scheduled_progression > sim.date + + # Run the progression to severe wasting event: + sim.date = date_of_scheduled_progression + progression_event.apply(person_id=person_id) + + # Check properties of this individual: (should now be severely wasted and without a scheduled death date) + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == 'WHZ<-3' + assert person['un_clinical_acute_malnutrition'] == 'SAM' + assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + # Run the HSI event + if complications: + hsi = HSI_inpatient_care_for_complicated_SAM(person_id=person_id, module=sim.modules['Wasting']) + hsi.run(squeeze_factor=0.0) + else: + hsi = HSI_outpatient_therapeutic_programme_for_SAM(person_id=person_id, module=sim.modules['Wasting']) + hsi.run(squeeze_factor=0.0) + + # Check that person is now on treatment: + assert sim.date == df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + + print(sim.find_events_for_person(person_id)) + + # Check that a CureEvent has been scheduled + cure_event = [event_tuple[1] for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] + + # Run the CureEvent + cure_event.apply(person_id=person_id) + + # Check that the person is cured and is alive still: + person = df.loc[person_id] + assert person['is_alive'] + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert person['un_clinical_acute_malnutrition'] == 'well' + assert not pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) + + test_use_of_HSI_by_complication(complications=True) + test_use_of_HSI_by_complication(complications=False) From f399fbf0e54bf0e75e2fb1e7bc5221b89443e4f8 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Fri, 6 Oct 2023 08:45:24 +0200 Subject: [PATCH 005/755] getting things running in the current wasting state and generate some outputs --- .../wasting_analyses/analysis_wasting.py | 132 ++++++++++++++++-- tests/test_wasting.py | 21 ++- 2 files changed, 133 insertions(+), 20 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index e2897a56eb..004f98968e 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -1,26 +1,129 @@ """ An analysis file for the wasting module """ +import datetime +# %% Import statements from pathlib import Path -# %% Import statements +import pandas as pd +from matplotlib import pyplot as plt from tlo import Date, Simulation, logging -from tlo.analysis.utils import parse_log_file -from tlo.methods import wasting, demography, healthsystem, symptommanager, healthseekingbehaviour, healthburden, \ - enhanced_lifestyle, labour, newborn_outcomes, care_of_women_during_pregnancy, contraception, pregnancy_supervisor, \ - postnatal_supervisor, hiv +from tlo.analysis.utils import parse_log_file, compare_number_of_deaths +from tlo.methods import ( + care_of_women_during_pregnancy, + contraception, + demography, + enhanced_lifestyle, + healthburden, + healthseekingbehaviour, + healthsystem, + hiv, + labour, + newborn_outcomes, + postnatal_supervisor, + pregnancy_supervisor, + symptommanager, + wasting, + tb, epi +) + + +class WastingAnalyses: + """This class looks at plotting all import outputs from the wasting module """ + + def __init__(self, log_file_path): + self.__log_file_path = log_file_path + # parse wasting logs + self.__logs_dict = parse_log_file(self.__log_file_path)['tlo.methods.wasting'] + + # gender description + self.__gender_desc = {'M': 'Males', + 'F': 'Females'} + + # wasting types description + self.__wasting_types_desc = {'WHZ<-3': 'severe wasting', + '-3≥WHZ<-2': 'moderate wasting', + 'WHZ>=-2': 'not undernourished'} + + def plot_wasting_incidence(self): + """ plot the incidence of wasting over time """ + w_inc_df = self.__logs_dict['wasting_incidence_count'] + w_inc_df.set_index(w_inc_df.date.dt.year, inplace=True) + w_inc_df.drop(columns='date', inplace=True) + new_df = pd.DataFrame(index=w_inc_df.index, data=w_inc_df.loc[w_inc_df.index[0], '0y']) + _row_counter = 0 + _col_counter = 0 + fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True) # plot setup + for _year in w_inc_df.columns: + for _index in range(len(new_df.index)): + new_df.loc[new_df.index[_index], new_df.columns] = \ + w_inc_df.loc[w_inc_df.index[_index], _year].values() + new_df = new_df.apply(lambda _row: _row / _row.sum(), axis=1) + # convert into proportions + ax = new_df.plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], + title=f"incidence of wasting in {_year} infants") + ax.legend(self.__wasting_types_desc.values(), loc='lower right') + ax.set_xlabel('year') + ax.set_ylabel('proportions') + # move to another row + if _col_counter == 2: + _row_counter += 1 + _col_counter = -1 + _col_counter += 1 # increment column counter + plt.tight_layout() + + plt.show() + + def plot_wasting_prevalence(self): + w_prev_df = self.__logs_dict['wasting_prevalence_count'] + w_prev_df.set_index(w_prev_df.date.dt.year, inplace=True) + w_prev_df.drop(columns='date', inplace=True) + w_prev_df = w_prev_df.apply(lambda _row: _row / _row.sum(), axis=1) + w_prev_df.plot(kind='bar', stacked=True, title="Wasting prevalence in children 0-59 months", + ) + plt.ylabel('proportions') + plt.xlabel('year') + plt.show() + + def plot_modal_gbd_deaths_by_gender(self): + """ compare modal and GBD deaths by gender """ + death_compare = compare_number_of_deaths(self.__log_file_path, resources) + fig, axs = plt.subplots(nrows=1, ncols=2, sharey=True, sharex=True) + for _col, sex in enumerate(('M', 'F')): + plot_df = death_compare.loc[(['2010-2014'], sex, slice(None), 'Childhood Wasting')].groupby('period').sum() + ax = plot_df['model'].plot.bar(label='Model', ax=axs[_col], rot=0) + ax.errorbar(x=plot_df['model'].index, y=plot_df.GBD_mean, + yerr=[plot_df.GBD_lower, plot_df.GBD_upper], + fmt='o', color='#000', label="GBD") + # ax.set_title(f'{self.__gender_desc[sex]} mean annual deaths, 2010-2019') + ax.set_title(f'{self.__gender_desc[sex]} wasting deaths, 2010-2014') + ax.set_xlabel("Time period") + ax.set_ylabel("Number of deaths") + ax.legend(loc=2) + plt.tight_layout() + plt.savefig( + outputs / ('modal_gbd_deaths_by_gender' + datestamp + ".pdf"), format="pdf" + ) + plt.savefig(Path('.outputs')) + plt.show() + seed = 1 # Path to the resource files used by the disease and intervention methods resources = Path("./resources") +outputs = Path("./outputs") + +# create a datestamp +datestamp = datetime.date.today().strftime("__%Y_%m_%d") + datetime.datetime.now().strftime("%H_%M_%S") # configure logging log_config = { "filename": "wasting", # output filename. A timestamp will be added to this. "custom_levels": { # Customise the output of specific loggers. They are applied in order: "tlo.methods.demography": logging.INFO, + "tlo.methods.population": logging.INFO, "tlo.methods.wasting": logging.INFO, '*': logging.WARNING } @@ -28,7 +131,7 @@ # Basic arguments required for the simulation start_date = Date(2010, 1, 1) -end_date = Date(2020, 1, 1) +end_date = Date(2030, 1, 1) pop_size = 10000 # Create simulation instance for this run. @@ -51,6 +154,8 @@ postnatal_supervisor.PostnatalSupervisor(resourcefilepath=resources), newborn_outcomes.NewbornOutcomes(resourcefilepath=resources), hiv.Hiv(resourcefilepath=resources), + tb.Tb(resourcefilepath=resources), + epi.Epi(resourcefilepath=resources), wasting.Wasting(resourcefilepath=resources), ) @@ -58,5 +163,16 @@ sim.simulate(end_date=end_date) # %% read the results -output = parse_log_file(sim.log_filepath) -print(output) +output_path = sim.log_filepath + +# initialise the wasting class +wasting_analyses = WastingAnalyses(output_path) + +# plot wasting incidence +wasting_analyses.plot_wasting_incidence() + +# plot wasting prevalence +wasting_analyses.plot_wasting_prevalence() + +# plot wasting deaths by gender as compared to GBD deaths +wasting_analyses.plot_modal_gbd_deaths_by_gender() diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 382314d167..a9e5b58d1a 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -10,28 +10,25 @@ from tlo.lm import LinearModel, LinearModelType from tlo.methods import ( demography, - wasting, enhanced_lifestyle, healthburden, healthseekingbehaviour, healthsystem, simplified_births, symptommanager, + wasting, ) - -from tlo.methods.healthsystem import HSI_Event - from tlo.methods.wasting import ( AcuteMalnutritionDeathPollingEvent, - SevereAcuteMalnutritionDeathEvent, + ClinicalAcuteMalnutritionRecoveryEvent, + HSI_inpatient_care_for_complicated_SAM, + HSI_outpatient_therapeutic_programme_for_SAM, + HSI_supplementary_feeding_programme_for_MAM, ProgressionSevereWastingEvent, + SevereAcuteMalnutritionDeathEvent, + UpdateToMAM, WastingNaturalRecoveryEvent, - ClinicalAcuteMalnutritionRecoveryEvent, WastingPollingEvent, - UpdateToMAM, - HSI_supplementary_feeding_programme_for_MAM, - HSI_outpatient_therapeutic_programme_for_SAM, - HSI_inpatient_care_for_complicated_SAM, ) # Path to the resource files used by the disease and intervention methods @@ -184,14 +181,14 @@ def test_wasting_polling(tmpdir): # Run polling event: check that a severe incident case is produced: polling = WastingPollingEvent(sim.modules['Wasting']) polling.apply(sim.population) - assert len([q for q in sim.event_queue.queue if isinstance(q[2], ProgressionSevereWastingEvent)]) > 0 + assert len([q for q in sim.event_queue.queue if isinstance(q[3], ProgressionSevereWastingEvent)]) > 0 # Check properties of this individual: should now be moderately wasted df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] person = df.loc[person_id] - assert person['un_ever_wasted'] == True + assert person['un_ever_wasted'] assert person['un_WHZ_category'] == '-3<=WHZ<-2' assert person['un_last_wasting_date_of_onset'] == sim.date From 75ebb3a82dfa50cb7fc0f8e9e1b8b5db5dde4f1c Mon Sep 17 00:00:00 2001 From: mnjowe Date: Fri, 6 Oct 2023 08:46:43 +0200 Subject: [PATCH 006/755] not import but important --- src/scripts/wasting_analyses/analysis_wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 004f98968e..0684eaa745 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -30,7 +30,7 @@ class WastingAnalyses: - """This class looks at plotting all import outputs from the wasting module """ + """This class looks at plotting all important outputs from the wasting module """ def __init__(self, log_file_path): self.__log_file_path = log_file_path From 5f120107b732d927017f93330383194002c5c182 Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Mon, 9 Oct 2023 15:44:17 +0200 Subject: [PATCH 007/755] Linter Changes --- src/tlo/methods/wasting.py | 99 +++++++++++++++++++------------------- 1 file changed, 49 insertions(+), 50 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 7254b394f7..f87ffd435e 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -2,24 +2,22 @@ import copy from pathlib import Path -from scipy.stats import norm import numpy as np import pandas as pd +from scipy.stats import norm from tlo import DateOffset, Module, Parameter, Property, Types, logging from tlo.events import Event, IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.lm import LinearModel, LinearModelType, Predictor -from tlo.methods import Metadata, demography +from tlo.methods import Metadata +from tlo.methods.causes import Cause from tlo.methods.healthsystem import HSI_Event from tlo.methods.symptommanager import Symptom -from tlo.methods.causes import Cause logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -from tlo import Module, Property, Types, logging - logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -299,9 +297,10 @@ def muac_cutoff_by_WHZ(self, idx, whz): if whz == 'WHZ<-3': # apply probability of MUAC<115mm in severe wasting low_muac_in_severe_wasting = self.rng.random_sample(size=len(idx)) < p['proportion_WHZ<-3_with_MUAC<115mm'] + df.loc[idx[low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '<115mm' # other severe wasting will have MUAC between 115-<125mm - df.loc[idx[low_muac_in_severe_wasting == False], 'un_am_MUAC_category'] = '115-<125mm' + df.loc[idx[~low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '115-<125mm' if whz == '-3<=WHZ<-2': # apply probability of MUAC<115mm in moderate wasting @@ -310,11 +309,11 @@ def muac_cutoff_by_WHZ(self, idx, whz): df.loc[idx[low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = '<115mm' # apply probability of MUAC between 115-<125mm in moderate wasting moderate_low_muac_in_moderate_wasting = self.rng.random_sample(size=len( - idx[low_muac_in_moderate_wasting == False])) < p['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] - df.loc[idx[low_muac_in_moderate_wasting == False][moderate_low_muac_in_moderate_wasting], + idx[~low_muac_in_moderate_wasting])) < p['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] + df.loc[idx[~low_muac_in_moderate_wasting][moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = '115-<125mm' # other moderate wasting will have normal MUAC - df.loc[idx[low_muac_in_moderate_wasting == False][moderate_low_muac_in_moderate_wasting == False], + df.loc[idx[~low_muac_in_moderate_wasting][~moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = '>=125mm' if whz == 'WHZ>=-2': @@ -351,13 +350,13 @@ def nutritional_oedema_present(self, idx): oedema_in_wasted_children = self.rng.random_sample(size=len( children_with_wasting)) < p['prevalence_nutritional_oedema'] * p['proportion_oedema_with_WHZ<-2'] df.loc[children_with_wasting[oedema_in_wasted_children], 'un_am_bilateral_oedema'] = True - df.loc[children_with_wasting[oedema_in_wasted_children == False], 'un_am_bilateral_oedema'] = False + df.loc[children_with_wasting[~oedema_in_wasted_children], 'un_am_bilateral_oedema'] = False # oedema among non-wasted children oedema_in_non_wasted = self.rng.random_sample(size=len( children_without_wasting)) < p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) df.loc[children_without_wasting[oedema_in_non_wasted], 'un_am_bilateral_oedema'] = True - df.loc[children_without_wasting[oedema_in_non_wasted == False], 'un_am_bilateral_oedema'] = False + df.loc[children_without_wasting[~oedema_in_non_wasted], 'un_am_bilateral_oedema'] = False def clinical_acute_malnutrition_state(self, person_id): """ @@ -375,7 +374,7 @@ def clinical_acute_malnutrition_state(self, person_id): if ( (df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2') & (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & - (df.at[person_id, 'un_am_bilateral_oedema'] == False) + (~df.at[person_id, 'un_am_bilateral_oedema']) ): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' @@ -513,10 +512,10 @@ def make_linear_model_wasting(agegp, intercept=get_odds_wasting(agegp=agegp)): LinearModelType.LOGISTIC, intercept, # baseline odds: get_odds_wasting(agegp=agegp) Predictor('li_wealth').when(2, p['or_wasting_hhwealth_Q2']) - .when(3, p['or_wasting_hhwealth_Q3']) - .when(4, p['or_wasting_hhwealth_Q4']) - .when(5, p['or_wasting_hhwealth_Q5']) - .otherwise(1.0), + .when(3, p['or_wasting_hhwealth_Q3']) + .when(4, p['or_wasting_hhwealth_Q4']) + .when(5, p['or_wasting_hhwealth_Q5']) + .otherwise(1.0), Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' '& (nb_late_preterm == False) & (nb_early_preterm == False)', p['or_wasting_SGA_and_term']), @@ -597,7 +596,7 @@ def get_prob_severe_in_overall_wasting(agegp): # update clinical symptoms for severe wasting self.wasting_clinical_symptoms(person_id=id) - df.loc[wasted[wasted == False].index, 'un_WHZ_category'] = 'WHZ>=-2' + df.loc[wasted[~wasted].index, 'un_WHZ_category'] = 'WHZ>=-2' # ----------------------------------------------------------------------------------------------------- # # # # # # Give MUAC category, presence of oedema, and determine acute malnutrition state # # # # # @@ -616,35 +615,35 @@ def get_prob_severe_in_overall_wasting(agegp): event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months - for person in sam_requiring_inpatient_care[recovered_complic_sam == False]: + for person in sam_requiring_inpatient_care[~recovered_complic_sam]: self.sim.schedule_event( event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person), date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months # outpatient care uncomplicated_sam = df.index[df.is_alive & (df.age_exact_years < 5) & ( - df.un_clinical_acute_malnutrition == 'SAM') & df.un_sam_with_complications == False] + df.un_clinical_acute_malnutrition == 'SAM') & ~df.un_sam_with_complications] recovered_uncompl_sam = self.rng.random_sample(len(uncomplicated_sam)) > ( p['coverage_outpatient_therapeutic_care'] * p['recovery_rate_with_standard_RUTF']) for person in uncomplicated_sam[recovered_uncompl_sam]: self.sim.schedule_event( event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months - for person in uncomplicated_sam[recovered_uncompl_sam == False]: + for person in uncomplicated_sam[~recovered_uncompl_sam]: self.sim.schedule_event( event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person), date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months # supplementary feeding for MAM children_with_mam = df.index[df.is_alive & (df.age_exact_years < 5) & ( - df.un_clinical_acute_malnutrition == 'MAM') & df.un_sam_with_complications == False] + df.un_clinical_acute_malnutrition == 'MAM') & ~df.un_sam_with_complications] recovered_mam = self.rng.random_sample(len(children_with_mam)) > ( p['coverage_supplementary_feeding_program'] * p['recovery_rate_with_CSB++']) for person in children_with_mam[recovered_mam]: self.sim.schedule_event( event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months - for person in children_with_mam[recovered_mam == False]: + for person in children_with_mam[~recovered_mam]: self.sim.schedule_event( event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person), date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months @@ -688,12 +687,12 @@ def make_lm_wasting_incidence(intercept=1.0): LinearModelType.MULTIPLICATIVE, intercept, Predictor('age_exact_years').when('<0.5', p['base_inc_rate_wasting_by_agegp'][0]) - .when('<1.0', p['base_inc_rate_wasting_by_agegp'][1]) - .when('.between(1,1.9999)', p['base_inc_rate_wasting_by_agegp'][2]) - .when('.between(2,2.9999)', p['base_inc_rate_wasting_by_agegp'][3]) - .when('.between(3,3.9999)', p['base_inc_rate_wasting_by_agegp'][4]) - .when('.between(4,4.9999)', p['base_inc_rate_wasting_by_agegp'][5]) - .otherwise(0.0), + .when('<1.0', p['base_inc_rate_wasting_by_agegp'][1]) + .when('.between(1,1.9999)', p['base_inc_rate_wasting_by_agegp'][2]) + .when('.between(2,2.9999)', p['base_inc_rate_wasting_by_agegp'][3]) + .when('.between(3,3.9999)', p['base_inc_rate_wasting_by_agegp'][4]) + .when('.between(4,4.9999)', p['base_inc_rate_wasting_by_agegp'][5]) + .otherwise(0.0), Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' '& (nb_late_preterm == False) & (nb_early_preterm == False)', p['rr_wasting_SGA_and_term']), @@ -707,7 +706,7 @@ def make_lm_wasting_incidence(intercept=1.0): ) unscaled_lm = make_lm_wasting_incidence() - target_mean = p[f'base_inc_rate_wasting_by_agegp'][2] + target_mean = p['base_inc_rate_wasting_by_agegp'][2] actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1) & (df.un_WHZ_category == 'WHZ>=-2')]).mean() scaled_intercept = 1.0 * (target_mean / actual_mean) \ @@ -791,7 +790,7 @@ def make_lm_sam_death(intercept=1.0): ) unscaled_lm = make_lm_sam_death() - target_mean = p[f'base_death_rate_untreated_SAM'] + target_mean = p['base_death_rate_untreated_SAM'] actual_mean = unscaled_lm.predict( df.loc[df.is_alive & ((df.age_exact_years > 0.5) & (df.age_exact_years < 5)) & (df.un_clinical_acute_malnutrition == 'SAM')]).mean() @@ -833,7 +832,7 @@ def report_daly_values(self): total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & df.un_am_bilateral_oedema] = self.daly_wts['SAM_with_oedema'] total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & - (df.un_am_bilateral_oedema == False)] = self.daly_wts['SAM_w/o_oedema'] + (~df.un_am_bilateral_oedema)] = self.daly_wts['SAM_w/o_oedema'] total_daly_values.loc[df.is_alive & ( ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | ((df.un_WHZ_category != 'WHZ<-3') & (df.un_am_MUAC_category != "115-<125mm")) @@ -1063,7 +1062,7 @@ def apply(self, population): # # # # # # # # # # # # # # # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # # # # moderate wasting not progressed to severe, schedule recovery - for person in will_be_severely_wasted[will_be_severely_wasted == False].index: + for person in will_be_severely_wasted[~will_be_severely_wasted].index: outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') if outcome_date <= self.sim.date: # schedule recovery for today @@ -1187,7 +1186,7 @@ def apply(self, population): # Those not scheduled to die, will have improved WHZ status by 1sd (-3<=WHZ<-2) # schedule improvement to MAM for those not scheduled to die - for person in will_die[will_die == False].index: + for person in will_die[~will_die].index: outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='SAM') if outcome_date <= self.sim.date: # schedule improvement to moderate wasting date for today @@ -1382,14 +1381,14 @@ def apply(self, person_id, squeeze_factor): # Make request for some consumables consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] # whole package of interventions - pkg_code_mam = pd.unique( - consumables.loc[consumables['Intervention_Pkg'] == 'Management of moderate acute malnutrition (children)', - 'Intervention_Pkg_Code'])[0] # This package includes only CSB(or supercereal or CSB++) + # pkg_code_mam = pd.unique( + # consumables.loc[consumables['Intervention_Pkg'] == 'Management of moderate acute malnutrition (children)', + # 'Intervention_Pkg_Code'])[0] # This package includes only CSB(or supercereal or CSB++) # individual items item_code1 = pd.unique( consumables.loc[consumables['Items'] == 'Corn Soya Blend (or Supercereal - CSB++)', 'Item_Code'])[0] - consumables_needed = {'Intervention_Package_Code': {pkg_code_mam: 1}, 'Item_Code': {item_code1: 1}} + # consumables_needed = {'Intervention_Package_Code': {pkg_code_mam: 1}, 'Item_Code': {item_code1: 1}} # check availability of consumables # outcome_of_request_for_consumables = self.sim.modules['HealthSystem'].request_consumables( @@ -1454,17 +1453,17 @@ def apply(self, person_id, squeeze_factor): # Make request for some consumables consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] # whole package of interventions - pkg_code_sam = pd.unique( - consumables.loc[consumables['Intervention_Pkg'] == 'Management of severe malnutrition (children)', - 'Intervention_Pkg_Code'])[0] + # pkg_code_sam = pd.unique( + # consumables.loc[consumables['Intervention_Pkg'] == 'Management of severe malnutrition (children)', + # 'Intervention_Pkg_Code'])[0] # individual items item_code1 = pd.unique( consumables.loc[consumables['Items'] == 'SAM theraputic foods', 'Item_Code'])[0] item_code2 = pd.unique( consumables.loc[consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] - consumables_needed = {'Intervention_Package_Code': {pkg_code_sam: 1}, 'Item_Code': {item_code1: 1, - item_code2: 1}} + # consumables_needed = {'Intervention_Package_Code': {pkg_code_sam: 1}, 'Item_Code': {item_code1: 1, + # item_code2: 1}} # check availability of consumables # outcome_of_request_for_consumables = self.sim.modules['HealthSystem'].request_consumables( @@ -1530,20 +1529,20 @@ def apply(self, person_id, squeeze_factor): # Make request for some consumables consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] # whole package of interventions - pkg_code_sam = pd.unique( - consumables.loc[consumables['Intervention_Pkg'] == 'Management of severe malnutrition (children)', - 'Intervention_Pkg_Code'])[0] + # pkg_code_sam = pd.unique( + # consumables.loc[consumables['Intervention_Pkg'] == 'Management of severe malnutrition (children)', + # 'Intervention_Pkg_Code'])[0] # individual items item_code1 = pd.unique( consumables.loc[consumables['Items'] == 'SAM theraputic foods', 'Item_Code'])[0] item_code2 = pd.unique( consumables.loc[consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] - pkg_codes = self.sim.modules['HealthSystem'].get_item_codes_from_package_name - pkg_codes_num = pkg_codes('Management of severe malnutrition (children)') - - consumables_needed = {'Intervention_Package_Code': {pkg_code_sam: 1}, 'Item_Code': {item_code1: 1, - item_code2: 1}} + # pkg_codes = self.sim.modules['HealthSystem'].get_item_codes_from_package_name + # pkg_codes_num = pkg_codes('Management of severe malnutrition (children)') + # + # consumables_needed = {'Intervention_Package_Code': {pkg_code_sam: 1}, 'Item_Code': {item_code1: 1, + # item_code2: 1}} # # check availability of consumables # outcome_of_request_for_consumables = self.sim.modules['HealthSystem'].request_consumables( From 25d44933c346940a9aa3c8e8fbd43a1a106e3cec Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Tue, 10 Oct 2023 10:45:50 +0200 Subject: [PATCH 008/755] added more treatment ids to color map --- src/tlo/analysis/utils.py | 2 ++ src/tlo/methods/wasting.py | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/tlo/analysis/utils.py b/src/tlo/analysis/utils.py index 2504493a4d..3682727617 100644 --- a/src/tlo/analysis/utils.py +++ b/src/tlo/analysis/utils.py @@ -735,6 +735,8 @@ def get_color_coarse_appt(coarse_appt_type: str) -> str: 'FirstAttendance*': 'darkgrey', 'Inpatient*': 'silver', + 'Outpatient*': 'grey', + 'Supplementary*': 'darkslategrey', 'Contraception*': 'darkseagreen', 'AntenatalCare*': 'green', diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index f87ffd435e..5bc501ee0b 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1363,7 +1363,7 @@ def __init__(self, module, person_id): the_appt_footprint['Under5OPD'] = 1 # This requires one out patient # Define the necessary information for an HSI - self.TREATMENT_ID = 'supplementary_feeding_programme_for_MAM' + self.TREATMENT_ID = 'Supplementary_feeding_programme_for_MAM' self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint self.ACCEPTED_FACILITY_LEVEL = '1a' self.ALERT_OTHER_DISEASES = [] @@ -1435,7 +1435,7 @@ def __init__(self, module, person_id): the_appt_footprint['U5Malnutr'] = 1 # Define the necessary information for an HSI - self.TREATMENT_ID = 'outpatient_therapeutic_programme_for_SAM' + self.TREATMENT_ID = 'Outpatient_therapeutic_programme_for_SAM' self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint self.ACCEPTED_FACILITY_LEVEL = '1a' self.ALERT_OTHER_DISEASES = [] @@ -1510,7 +1510,7 @@ def __init__(self, module, person_id): the_appt_footprint['U5Malnutr'] = 1 # Define the necessary information for an HSI - self.TREATMENT_ID = 'inpatient_care_for_complicated_SAM' + self.TREATMENT_ID = 'Inpatient_care_for_complicated_SAM' self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint self.ACCEPTED_FACILITY_LEVEL = '2' self.ALERT_OTHER_DISEASES = [] From 22e013d780807f8b0dfb7053568db8a00d8303bd Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Wed, 11 Oct 2023 17:33:27 +0200 Subject: [PATCH 009/755] Updated policies excel and wasting dependencies python files --- .../ResourceFile_PriorityRanking_ALLPOLICIES.xlsx | 4 ++-- src/tlo/methods/wasting.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx index 8821260c1d..e7dc4972c9 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:a10eb13154221475ed3b3ba03b62936b8dfc79c023475a4930a25a5b666599a9 -size 30493 +oid sha256:af1a8f771bd93522fe018c916466ffa05b357aca4f9be54284ebd23d5fc472e9 +size 38448 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 5bc501ee0b..618979f3b9 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -37,7 +37,8 @@ class Wasting(Module): """ - INIT_DEPENDENCIES = {'Demography'} + INIT_DEPENDENCIES = {'Demography', 'SymptomManager'} + METADATA = { Metadata.DISEASE_MODULE, From 0c12856a6a640daf3500ea241b6972bd62dcc175 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Thu, 12 Oct 2023 12:59:20 +0200 Subject: [PATCH 010/755] module dependencies, cause of death color map, linting --- .../wasting_analyses/analysis_wasting.py | 5 +-- src/tlo/analysis/utils.py | 1 + src/tlo/methods/wasting.py | 36 +++++++++---------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 0684eaa745..9dc5915ee7 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -9,12 +9,13 @@ from matplotlib import pyplot as plt from tlo import Date, Simulation, logging -from tlo.analysis.utils import parse_log_file, compare_number_of_deaths +from tlo.analysis.utils import compare_number_of_deaths, parse_log_file from tlo.methods import ( care_of_women_during_pregnancy, contraception, demography, enhanced_lifestyle, + epi, healthburden, healthseekingbehaviour, healthsystem, @@ -24,8 +25,8 @@ postnatal_supervisor, pregnancy_supervisor, symptommanager, + tb, wasting, - tb, epi ) diff --git a/src/tlo/analysis/utils.py b/src/tlo/analysis/utils.py index 3682727617..10ef25506a 100644 --- a/src/tlo/analysis/utils.py +++ b/src/tlo/analysis/utils.py @@ -807,6 +807,7 @@ def get_color_short_treatment_id(short_treatment_id: str) -> str: 'Lower respiratory infections': 'darkorange', 'Childhood Diarrhoea': 'tan', + 'Childhood Wasting': 'darkslategrey', 'AIDS': 'deepskyblue', 'Malaria': 'lightsteelblue', diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 618979f3b9..93f502c81b 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -37,8 +37,7 @@ class Wasting(Module): """ - INIT_DEPENDENCIES = {'Demography', 'SymptomManager'} - + INIT_DEPENDENCIES = {'Demography', 'SymptomManager', 'NewbornOutcomes', 'HealthBurden'} METADATA = { Metadata.DISEASE_MODULE, @@ -311,11 +310,11 @@ def muac_cutoff_by_WHZ(self, idx, whz): # apply probability of MUAC between 115-<125mm in moderate wasting moderate_low_muac_in_moderate_wasting = self.rng.random_sample(size=len( idx[~low_muac_in_moderate_wasting])) < p['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] - df.loc[idx[~low_muac_in_moderate_wasting][moderate_low_muac_in_moderate_wasting], - 'un_am_MUAC_category'] = '115-<125mm' + df.loc[idx[~low_muac_in_moderate_wasting][moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = \ + '115-<125mm' # other moderate wasting will have normal MUAC - df.loc[idx[~low_muac_in_moderate_wasting][~moderate_low_muac_in_moderate_wasting], - 'un_am_MUAC_category'] = '>=125mm' + df.loc[idx[~low_muac_in_moderate_wasting][~moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] \ + = '>=125mm' if whz == 'WHZ>=-2': # Give MUAC distribution for WHZ>=-2 ('well' group) --------- @@ -513,10 +512,10 @@ def make_linear_model_wasting(agegp, intercept=get_odds_wasting(agegp=agegp)): LinearModelType.LOGISTIC, intercept, # baseline odds: get_odds_wasting(agegp=agegp) Predictor('li_wealth').when(2, p['or_wasting_hhwealth_Q2']) - .when(3, p['or_wasting_hhwealth_Q3']) - .when(4, p['or_wasting_hhwealth_Q4']) - .when(5, p['or_wasting_hhwealth_Q5']) - .otherwise(1.0), + .when(3, p['or_wasting_hhwealth_Q3']) + .when(4, p['or_wasting_hhwealth_Q4']) + .when(5, p['or_wasting_hhwealth_Q5']) + .otherwise(1.0), Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' '& (nb_late_preterm == False) & (nb_early_preterm == False)', p['or_wasting_SGA_and_term']), @@ -688,12 +687,12 @@ def make_lm_wasting_incidence(intercept=1.0): LinearModelType.MULTIPLICATIVE, intercept, Predictor('age_exact_years').when('<0.5', p['base_inc_rate_wasting_by_agegp'][0]) - .when('<1.0', p['base_inc_rate_wasting_by_agegp'][1]) - .when('.between(1,1.9999)', p['base_inc_rate_wasting_by_agegp'][2]) - .when('.between(2,2.9999)', p['base_inc_rate_wasting_by_agegp'][3]) - .when('.between(3,3.9999)', p['base_inc_rate_wasting_by_agegp'][4]) - .when('.between(4,4.9999)', p['base_inc_rate_wasting_by_agegp'][5]) - .otherwise(0.0), + .when('<1.0', p['base_inc_rate_wasting_by_agegp'][1]) + .when('.between(1,1.9999)', p['base_inc_rate_wasting_by_agegp'][2]) + .when('.between(2,2.9999)', p['base_inc_rate_wasting_by_agegp'][3]) + .when('.between(3,3.9999)', p['base_inc_rate_wasting_by_agegp'][4]) + .when('.between(4,4.9999)', p['base_inc_rate_wasting_by_agegp'][5]) + .otherwise(0.0), Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' '& (nb_late_preterm == False) & (nb_early_preterm == False)', p['rr_wasting_SGA_and_term']), @@ -1108,9 +1107,8 @@ def apply(self, person_id): m = self.module # before progression to severe wasting, check those who started supplementary feeding programme before today - if df.at[person_id, - 'un_last_wasting_date_of_onset'] < df.at[person_id, - 'un_acute_malnutrition_tx_start_date'] < self.sim.date: + if df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[person_id, 'un_acute_malnutrition_tx_start_date'] \ + < self.sim.date: return # continue with progression to severe if not treated/recovered From 44cb17651af38d359bd0f191f467495cd51ff017 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Tue, 17 Oct 2023 18:06:08 +0200 Subject: [PATCH 011/755] HSI event name should include module name --- src/tlo/methods/wasting.py | 440 ++++++++++++++++++------------------- tests/test_wasting.py | 17 +- 2 files changed, 228 insertions(+), 229 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 93f502c81b..d8bb8ede59 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1,6 +1,5 @@ """Childhood wasting module""" -import copy from pathlib import Path import numpy as np @@ -214,24 +213,14 @@ def __init__(self, name=None, resourcefilepath=None): # dict to hold counters for the number of episodes by wasting-type and age-group blank_counter = dict(zip(self.wasting_states, [list() for _ in self.wasting_states])) self.wasting_incident_case_tracker_blank = { - '0y': copy.deepcopy(blank_counter), - '1y': copy.deepcopy(blank_counter), - '2y': copy.deepcopy(blank_counter), - '3y': copy.deepcopy(blank_counter), - '4y': copy.deepcopy(blank_counter), - '5+y': copy.deepcopy(blank_counter) - } - self.wasting_incident_case_tracker = copy.deepcopy(self.wasting_incident_case_tracker_blank) + _agrp: blank_counter for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} + + self.wasting_incident_case_tracker = dict(self.wasting_incident_case_tracker_blank) zeros_counter = dict(zip(self.wasting_states, [0] * len(self.wasting_states))) + self.wasting_incident_case_tracker_zeros = { - '0y': copy.deepcopy(zeros_counter), - '1y': copy.deepcopy(zeros_counter), - '2y': copy.deepcopy(zeros_counter), - '3y': copy.deepcopy(zeros_counter), - '4y': copy.deepcopy(zeros_counter), - '5+y': copy.deepcopy(zeros_counter) - } + _agrp: zeros_counter for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} # dict to hold the DALY weights self.daly_wts = dict() @@ -256,7 +245,7 @@ def __init__(self, name=None, resourcefilepath=None): def read_parameters(self, data_folder): """ :param data_folder: path of a folder supplied to the Simulation containing data files. - Typically modules would read a particular file within here. + Typically, modules would read a particular file within here. :return: """ # Update parameters from the resource dataframe @@ -266,14 +255,6 @@ def read_parameters(self, data_folder): sheet_name='Parameter_values_AM')) p = self.parameters - # Check that every value has been read-in successfully - for param_name, param_type in self.PARAMETERS.items(): - assert param_name in p, f'Parameter "{param_name}" is not read in correctly from the resourcefile.' - assert param_name is not None, f'Parameter "{param_name}" is not read in correctly from the resourcefile.' - assert isinstance(p[param_name], - param_type.python_type), f'Parameter "{param_name}" is not read in correctly from the ' \ - f'resourcefile.' - # Declare symptoms that this module will cause and which are not included in the generic symptoms: generic_symptoms = self.sim.modules['SymptomManager'].generic_symptoms for symptom_name in self.symptoms: @@ -282,176 +263,6 @@ def read_parameters(self, data_folder): Symptom(name=symptom_name) # (give non-generic symptom 'average' healthcare seeking) ) - def muac_cutoff_by_WHZ(self, idx, whz): - """ - Proportion of MUAC<115mm in WHZ<-3 and -3<=WHZ<-2, - and proportion of wasted children with oedematous malnutrition (Kwashiokor, marasmic-kwashiorkor) - :param idx: index of children ages 6-59 months or person_id - :param whz: - :return: - """ - df = self.sim.population.props - p = self.parameters - - # ---------- MUAC <115mm in severe wasting (WHZ<-3) and moderate (-3<=WHZ<-2) ---------- - if whz == 'WHZ<-3': - # apply probability of MUAC<115mm in severe wasting - low_muac_in_severe_wasting = self.rng.random_sample(size=len(idx)) < p['proportion_WHZ<-3_with_MUAC<115mm'] - - df.loc[idx[low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '<115mm' - # other severe wasting will have MUAC between 115-<125mm - df.loc[idx[~low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '115-<125mm' - - if whz == '-3<=WHZ<-2': - # apply probability of MUAC<115mm in moderate wasting - low_muac_in_moderate_wasting = self.rng.random_sample(size=len(idx)) < p[ - 'proportion_-3<=WHZ<-2_with_MUAC<115mm'] - df.loc[idx[low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = '<115mm' - # apply probability of MUAC between 115-<125mm in moderate wasting - moderate_low_muac_in_moderate_wasting = self.rng.random_sample(size=len( - idx[~low_muac_in_moderate_wasting])) < p['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] - df.loc[idx[~low_muac_in_moderate_wasting][moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = \ - '115-<125mm' - # other moderate wasting will have normal MUAC - df.loc[idx[~low_muac_in_moderate_wasting][~moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] \ - = '>=125mm' - - if whz == 'WHZ>=-2': - # Give MUAC distribution for WHZ>=-2 ('well' group) --------- - muac_distribution_in_well_group = norm(loc=p['MUAC_distribution_WHZ>=-2'][0], - scale=p['MUAC_distribution_WHZ>=-2'][1]) - # get probability of MUAC <115mm - probability_over_or_equal_115 = muac_distribution_in_well_group.sf(11.5) - probability_over_or_equal_125 = muac_distribution_in_well_group.sf(12.5) - - prob_less_than_115 = 1 - probability_over_or_equal_115 - pro_between_115_125 = probability_over_or_equal_115 - probability_over_or_equal_125 - - for id in idx: - muac_cat = self.rng.choice(['<115mm', '115-<125mm', '>=125mm'], - p=[prob_less_than_115, pro_between_115_125, probability_over_or_equal_125]) - df.at[id, 'un_am_MUAC_category'] = muac_cat - - def nutritional_oedema_present(self, idx): - """ - This function applies the probability of bilateral oedema present in wasting and non-wasted cases - :param idx: index of children under 5, or person_id - :return: - """ - df = self.sim.population.props - p = self.parameters - - # Knowing the prevalence of nutritional oedema in under 5 population, apply the probability of oedema in WHZ<-2 - # get those children with wasting - children_with_wasting = idx.intersection(df.index[df.un_WHZ_category != 'WHZ>=-2']) - children_without_wasting = idx.intersection(df.index[df.un_WHZ_category == 'WHZ>=-2']) - - # oedema among wasted children - oedema_in_wasted_children = self.rng.random_sample(size=len( - children_with_wasting)) < p['prevalence_nutritional_oedema'] * p['proportion_oedema_with_WHZ<-2'] - df.loc[children_with_wasting[oedema_in_wasted_children], 'un_am_bilateral_oedema'] = True - df.loc[children_with_wasting[~oedema_in_wasted_children], 'un_am_bilateral_oedema'] = False - - # oedema among non-wasted children - oedema_in_non_wasted = self.rng.random_sample(size=len( - children_without_wasting)) < p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) - df.loc[children_without_wasting[oedema_in_non_wasted], 'un_am_bilateral_oedema'] = True - df.loc[children_without_wasting[~oedema_in_non_wasted], 'un_am_bilateral_oedema'] = False - - def clinical_acute_malnutrition_state(self, person_id): - """ - This fuction will determine the clinical acute malnutrition status (MAM, SAM) based on anthropometric indices - and presence of bilateral oedema (Kwashiorkor); - And help determine whether the individual will have medical complications, applicable to SAM cases only, - requiring inpatient care. - :param person_id: - :return: - """ - df = self.sim.population.props - p = self.parameters - - # check if person is not wasted - if ( - (df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2') & - (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & - (~df.at[person_id, 'un_am_bilateral_oedema']) - ): - df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' - - # severe acute malnutrition - MUAC<115mm and/or WHZ<-3 and/or bilateral oedema - elif ( - (df.at[person_id, 'un_am_MUAC_category'] == '<115mm') | - (df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3') | - (df.at[person_id, 'un_am_bilateral_oedema']) - ): - df.at[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' - - else: - df.at[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' - - # Determine if SAM episode has complications - if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM': - if p['prob_complications_in_SAM'] > self.rng.rand(): - df.at[person_id, 'un_sam_with_complications'] = True - else: - df.at[person_id, 'un_sam_with_complications'] = False - else: - df.at[person_id, 'un_sam_with_complications'] = False - - assert not (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') & \ - (df.at[person_id, 'un_sam_with_complications']) - - def date_of_outcome_for_untreated_am(self, person_id, duration_am): - """ - helper funtion to get the duration and the wasting episode and date of outcome (recovery, progression, or death) - :param person_id: - :param duration_am: - :return: - """ - df = self.sim.population.props - p = self.parameters - - # moderate wasting (for progression to severe, or recovery from MAM) ----- - if duration_am == 'MAM': - # Allocate the duration of the moderate wasting episode - duration_mam = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'])) - # Allocate a date of outcome (progression, recovery or death) - date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_mam) - return date_of_outcome - - # severe wasting (for death, or recovery to moderate wasting) ----- - if duration_am == 'SAM': - # determine the duration of SAM episode - duration_sam = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'] + - p['average_duration_of_untreated_SAM'])) - # Allocate a date of outcome (progression, recovery or death) - date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_sam) - return date_of_outcome - - def population_poll_clinical_am(self, population): - """ - Update at the population level other anthropometric indices and clinical signs - (MUAC, oedema, medical complications) that determine the clinical state of acute malnutrition - This will include both wasted and non-wasted children with other signs of acute malnutrition - :param population: - :return: - """ - df = population - - # give MUAC measurement category for all WHZ, including well nourished children ----- - for whz in ['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2']: - index_6_59mo_by_whz = df.index[df.is_alive & ((df.age_exact_years >= 0.5) & ( - df.age_exact_years < 5)) & (df.un_WHZ_category == whz)] - self.muac_cutoff_by_WHZ(idx=index_6_59mo_by_whz, whz=whz) - - # determine the presence of bilateral oedema / oedematous malnutrition ----- - index_under5 = df.index[df.is_alive & (df.age_exact_years < 5)] - self.nutritional_oedema_present(idx=index_under5) - - # determine the clinical acute malnutrition state ----- - for person_id in index_under5: - self.clinical_acute_malnutrition_state(person_id=person_id) - def initialise_population(self, population): """ Set our property values for the initial population. @@ -504,7 +315,6 @@ def get_odds_wasting(agegp): # convert probability to odds base_odds_of_wasting = probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) - return base_odds_of_wasting def make_linear_model_wasting(agegp, intercept=get_odds_wasting(agegp=agegp)): @@ -528,6 +338,7 @@ def make_linear_model_wasting(agegp, intercept=get_odds_wasting(agegp=agegp)): ) unscaled_lm = make_linear_model_wasting(agegp, intercept=get_odds_wasting(agegp=agegp)) + target_mean = get_odds_wasting(agegp='12_23mo') actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1)]).mean() scaled_intercept = get_odds_wasting(agegp) * (target_mean / actual_mean) if \ @@ -604,13 +415,16 @@ def get_prob_severe_in_overall_wasting(agegp): # ----------------------------------------------------------------------------------------------------- # # # # # Treatment coverage and cure rates at initiation # # # # # + # inpatient care sam_requiring_inpatient_care = df.index[df.is_alive & (df.age_exact_years < 5) & ( df.un_clinical_acute_malnutrition == 'SAM') & df.un_sam_with_complications] + print(f'require in patient {sam_requiring_inpatient_care}') recovered_complic_sam = self.rng.random_sample(len(sam_requiring_inpatient_care)) > ( p['coverage_inpatient_care'] * p['recovery_rate_with_inpatient_care']) # schedule recovery, and reset properties for person in sam_requiring_inpatient_care[recovered_complic_sam]: + print(f'the person is {person}') self.sim.schedule_event( event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months @@ -658,12 +472,14 @@ def initialise_simulation(self, sim): df = self.sim.population.props p = self.parameters - event = WastingPollingEvent(self) - sim.schedule_event(event, sim.date + DateOffset(months=3)) + # schedule wasting pool event + sim.schedule_event(WastingPollingEvent(self), sim.date + DateOffset(months=3)) + + # schedule acute malnutrition event sim.schedule_event(AcuteMalnutritionDeathPollingEvent(self), sim.date + DateOffset(months=3)) - event = WastingLoggingEvent(self) - sim.schedule_event(event, sim.date + DateOffset(months=12)) + # schedule wasting logging event + sim.schedule_event(WastingLoggingEvent(self), sim.date + DateOffset(months=12)) # Get DALY weights get_daly_weight = self.sim.modules['HealthBurden'].get_daly_weight @@ -811,6 +627,182 @@ def on_birth(self, mother_id, child_id): df.at[child_id, 'un_WHZ_category'] = 'WHZ>=-2' + def muac_cutoff_by_WHZ(self, idx, whz): + """ + Proportion of MUAC<115mm in WHZ<-3 and -3<=WHZ<-2, + and proportion of wasted children with oedematous malnutrition (Kwashiokor, marasmic-kwashiorkor) + :param idx: index of children ages 6-59 months or person_id + :param whz: + :return: + """ + df = self.sim.population.props + p = self.parameters + + # ---------- MUAC <115mm in severe wasting (WHZ<-3) and moderate (-3<=WHZ<-2) ---------- + if whz == 'WHZ<-3': + # apply probability of MUAC<115mm in severe wasting + low_muac_in_severe_wasting = self.rng.random_sample(size=len(idx)) < p['proportion_WHZ<-3_with_MUAC<115mm'] + + df.loc[idx[low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '<115mm' + # other severe wasting will have MUAC between 115-<125mm + df.loc[idx[~low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '115-<125mm' + + if whz == '-3<=WHZ<-2': + # apply probability of MUAC<115mm in moderate wasting + low_muac_in_moderate_wasting = self.rng.random_sample(size=len(idx)) < p[ + 'proportion_-3<=WHZ<-2_with_MUAC<115mm'] + df.loc[idx[low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = '<115mm' + + # apply probability of MUAC between 115-<125mm in moderate wasting + moderate_low_muac_in_moderate_wasting = self.rng.random_sample(size=len( + idx[~low_muac_in_moderate_wasting])) < p['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] + df.loc[idx[~low_muac_in_moderate_wasting][moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = \ + '115-<125mm' + # other moderate wasting will have normal MUAC + df.loc[idx[~low_muac_in_moderate_wasting][~moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] \ + = '>=125mm' + + if whz == 'WHZ>=-2': + # Give MUAC distribution for WHZ>=-2 ('well' group) --------- + muac_distribution_in_well_group = norm(loc=p['MUAC_distribution_WHZ>=-2'][0], + scale=p['MUAC_distribution_WHZ>=-2'][1]) + # get probability of MUAC <115mm + probability_over_or_equal_115 = muac_distribution_in_well_group.sf(11.5) + probability_over_or_equal_125 = muac_distribution_in_well_group.sf(12.5) + + prob_less_than_115 = 1 - probability_over_or_equal_115 + pro_between_115_125 = probability_over_or_equal_115 - probability_over_or_equal_125 + + for id in idx: + muac_cat = self.rng.choice(['<115mm', '115-<125mm', '>=125mm'], + p=[prob_less_than_115, pro_between_115_125, probability_over_or_equal_125]) + df.at[id, 'un_am_MUAC_category'] = muac_cat + + def nutritional_oedema_present(self, idx): + """ + This function applies the probability of bilateral oedema present in wasting and non-wasted cases + :param idx: index of children under 5, or person_id + :return: + """ + df = self.sim.population.props + p = self.parameters + + # Knowing the prevalence of nutritional oedema in under 5 population, apply the probability of oedema in WHZ<-2 + # get those children with wasting + children_with_wasting = idx.intersection(df.index[df.un_WHZ_category != 'WHZ>=-2']) + children_without_wasting = idx.intersection(df.index[df.un_WHZ_category == 'WHZ>=-2']) + + # oedema among wasted children + oedema_in_wasted_children = self.rng.random_sample(size=len( + children_with_wasting)) < p['prevalence_nutritional_oedema'] * p['proportion_oedema_with_WHZ<-2'] + df.loc[children_with_wasting[oedema_in_wasted_children], 'un_am_bilateral_oedema'] = True + df.loc[children_with_wasting[~oedema_in_wasted_children], 'un_am_bilateral_oedema'] = False + + # oedema among non-wasted children + oedema_in_non_wasted = self.rng.random_sample(size=len( + children_without_wasting)) < p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) + df.loc[children_without_wasting[oedema_in_non_wasted], 'un_am_bilateral_oedema'] = True + df.loc[children_without_wasting[~oedema_in_non_wasted], 'un_am_bilateral_oedema'] = False + + def clinical_acute_malnutrition_state(self, person_id): + """ + This fuction will determine the clinical acute malnutrition status (MAM, SAM) based on anthropometric indices + and presence of bilateral oedema (Kwashiorkor); + And help determine whether the individual will have medical complications, applicable to SAM cases only, + requiring inpatient care. + :param person_id: + :return: + """ + df = self.sim.population.props + p = self.parameters + + # check if person is not wasted + if ( + (df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2') & + (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & + (~df.at[person_id, 'un_am_bilateral_oedema']) + ): + print('WELL: un_clinical_acute_malnutrition') + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' + + # severe acute malnutrition - MUAC<115mm and/or WHZ<-3 and/or bilateral oedema + elif ( + (df.at[person_id, 'un_am_MUAC_category'] == '<115mm') | + (df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3') | + (df.at[person_id, 'un_am_bilateral_oedema']) + ): + print('SAM: un_clinical_acute_malnutrition') + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' + + else: + print('MAM: un_clinical_acute_malnutrition') + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' + + # Determine if SAM episode has complications + if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM': + if p['prob_complications_in_SAM'] > self.rng.random_sample(): + df.at[person_id, 'un_sam_with_complications'] = True + else: + df.at[person_id, 'un_sam_with_complications'] = False + else: + df.at[person_id, 'un_sam_with_complications'] = False + + assert not (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') & \ + (df.at[person_id, 'un_sam_with_complications']) + + def date_of_outcome_for_untreated_am(self, person_id, duration_am): + """ + helper funtion to get the duration and the wasting episode and date of outcome (recovery, progression, or death) + :param person_id: + :param duration_am: + :return: + """ + df = self.sim.population.props + p = self.parameters + + # moderate wasting (for progression to severe, or recovery from MAM) ----- + if duration_am == 'MAM': + # Allocate the duration of the moderate wasting episode + duration_mam = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'])) + # Allocate a date of outcome (progression, recovery or death) + date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_mam) + return date_of_outcome + + # severe wasting (for death, or recovery to moderate wasting) ----- + if duration_am == 'SAM': + # determine the duration of SAM episode + duration_sam = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'] + + p['average_duration_of_untreated_SAM'])) + # Allocate a date of outcome (progression, recovery or death) + date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_sam) + return date_of_outcome + + def population_poll_clinical_am(self, population): + """ + Update at the population level other anthropometric indices and clinical signs + (MUAC, oedema, medical complications) that determine the clinical state of acute malnutrition + This will include both wasted and non-wasted children with other signs of acute malnutrition + :param population: + :return: + """ + df = population + + # give MUAC measurement category for all WHZ, including well nourished children ----- + for whz in ['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2']: + index_6_59mo_by_whz = df.index[df.is_alive & ((df.age_exact_years >= 0.5) & ( + df.age_exact_years < 5)) & (df.un_WHZ_category == whz)] + self.muac_cutoff_by_WHZ(idx=index_6_59mo_by_whz, whz=whz) + + # determine the presence of bilateral oedema / oedematous malnutrition ----- + index_under5 = df.index[df.is_alive & (df.age_exact_years < 5)] + self.nutritional_oedema_present(idx=index_under5) + + print('population clinical poll') + # determine the clinical acute malnutrition state ----- + for person_id in index_under5: + print('population under 5') + self.clinical_acute_malnutrition_state(person_id=person_id) + def on_hsi_alert(self, person_id, treatment_id): """ This is called whenever there is an HSI event commissioned by one of the other disease modules. @@ -864,9 +856,8 @@ def wasting_clinical_symptoms(self, person_id): def do_when_acute_malnutrition_assessment(self, person_id): """ - This is called by the a generic HSI event when acute malnutrition is checked. + This is called by the generic HSI event when acute malnutrition is checked. :param person_id: - :param hsi_event: The HSI event that has called this event :return: """ df = self.sim.population.props @@ -879,10 +870,10 @@ def do_when_acute_malnutrition_assessment(self, person_id): # Interventions for MAM if clinical_am == 'MAM': # Check for coverage of supplementary feeding - if p['coverage_supplementary_feeding_program'] > self.rng.rand(): + if p['coverage_supplementary_feeding_program'] > self.rng.random_sample(): # schedule HSI for supplementary feeding program for MAM self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=HSI_supplementary_feeding_programme_for_MAM + hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM (module=self, person_id=person_id), priority=0, @@ -894,10 +885,10 @@ def do_when_acute_malnutrition_assessment(self, person_id): if clinical_am == 'SAM': if not complications: # Check for coverage of outpatient therapeutic care - if p['coverage_outpatient_therapeutic_care'] > self.rng.rand(): + if p['coverage_outpatient_therapeutic_care'] > self.rng.random_sample(): # schedule HSI for supplementary feeding program for MAM self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=HSI_outpatient_therapeutic_programme_for_SAM + hsi_event=HSI_Wasting_OutpatientTherapeuticProgramme_SAM (module=self, person_id=person_id), priority=0, @@ -908,10 +899,10 @@ def do_when_acute_malnutrition_assessment(self, person_id): # Interventions for complicated SAM if complications: # Check for coverage of outpatient therapeutic care - if p['coverage_inpatient_care'] > self.rng.rand(): + if p['coverage_inpatient_care'] > self.rng.random_sample(): # schedule HSI for supplementary feeding program for MAM self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=HSI_inpatient_care_for_complicated_SAM + hsi_event=HSI_Wasting_InpatientCareForComplicated_SAM (module=self, person_id=person_id), priority=0, @@ -934,7 +925,7 @@ def do_when_am_treatment(self, person_id, intervention): if intervention == 'SFP': mam_recovery = self.acute_malnutrition_recovery_based_on_interventions['MAM'].predict( df.loc[[person_id]]).values[0] - if self.rng.rand() < mam_recovery: + if self.rng.random_sample() < mam_recovery: # schedule recovery date self.sim.schedule_event( event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), @@ -947,7 +938,7 @@ def do_when_am_treatment(self, person_id, intervention): if intervention == 'OTC': sam_recovery = self.acute_malnutrition_recovery_based_on_interventions['SAM'].predict( df.loc[[person_id]]).values[0] - if self.rng.rand() < sam_recovery: + if self.rng.random_sample() < sam_recovery: # schedule recovery date self.sim.schedule_event( event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), @@ -970,7 +961,7 @@ def do_when_am_treatment(self, person_id, intervention): if intervention == 'ITC': sam_recovery = self.acute_malnutrition_recovery_based_on_interventions['SAM'].predict( df.loc[[person_id]]).values[0] - if self.rng.rand() < sam_recovery: + if self.rng.random_sample() < sam_recovery: # schedule recovery date self.sim.schedule_event( event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), @@ -1016,17 +1007,17 @@ def apply(self, population): rng = self.module.rng # # # # # # # # # # # # # # # # # # # # # INCIDENCE OF WASTING # # # # # # # # # # # # # # # # # # # # # - # Determine who will be onset with wasting among those who are not currently wasted ------------- incidence_of_wasting = self.module.wasting_incidence_equation.predict( df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == 'WHZ>=-2')]) wasted = rng.random_sample(len(incidence_of_wasting)) < incidence_of_wasting + wasting_idx = incidence_of_wasting.index # update the properties for wasted children - df.loc[wasted[wasted].index, 'un_ever_wasted'] = True - df.loc[wasted[wasted].index, 'un_last_wasting_date_of_onset'] = self.sim.date - df.loc[wasted[wasted].index, 'un_WHZ_category'] = '-3<=WHZ<-2' # start as moderate wasting - df.loc[wasted[wasted].index, 'un_am_treatment_type'] = 'none' # start without treatment + df.loc[wasting_idx[wasted], 'un_ever_wasted'] = True + df.loc[wasting_idx[wasted], 'un_last_wasting_date_of_onset'] = self.sim.date + df.loc[wasting_idx[wasted], 'un_WHZ_category'] = '-3<=WHZ<-2' # start as moderate wasting + df.loc[wasting_idx[wasted], 'un_am_treatment_type'] = 'none' # start without treatment # ------------------------------------------------------------------------------------------- # Add this incident case to the tracker @@ -1219,6 +1210,8 @@ def apply(self, person_id): # Check if this person should still die from SAM: if pd.isnull(df.at[person_id, 'un_am_recovery_date']): + # person_ids = df.at[person_id, 'un_am_recovery_date'])] + print(f"this person is going to die {df.at[person_id, 'un_clinical_acute_malnutrition']}") # Cause the death to happen immediately df.at[person_id, 'un_sam_death_date'] = self.sim.date self.sim.modules['Demography'].do_death( @@ -1348,7 +1341,7 @@ def apply(self, person_id): ) -class HSI_supplementary_feeding_programme_for_MAM(HSI_Event, IndividualScopeEventMixin): +class HSI_Wasting_SupplementaryFeedingProgramme_MAM(HSI_Event, IndividualScopeEventMixin): """ This is the supplementary feeding programme for MAM without complications """ @@ -1420,7 +1413,7 @@ def did_not_run(self): pass -class HSI_outpatient_therapeutic_programme_for_SAM(HSI_Event, IndividualScopeEventMixin): +class HSI_Wasting_OutpatientTherapeuticProgramme_SAM(HSI_Event, IndividualScopeEventMixin): """ This is the outpatient management of SAM without any medical complications """ @@ -1495,7 +1488,7 @@ def did_not_run(self): pass -class HSI_inpatient_care_for_complicated_SAM(HSI_Event, IndividualScopeEventMixin): +class HSI_Wasting_InpatientCareForComplicated_SAM(HSI_Event, IndividualScopeEventMixin): """ This is the inpatient management of SAM with medical complications """ @@ -1573,6 +1566,9 @@ def did_not_run(self): pass +class WastingModels: + """ houses all wasting linear moddels """ + class WastingLoggingEvent(RegularEvent, PopulationScopeEventMixin): """ This Event logs the number of incident cases that have occurred since the previous logging event. @@ -1589,7 +1585,7 @@ def apply(self, population): df = self.sim.population.props # Convert the list of timestamps into a number of timestamps # and check that all the dates have occurred since self.date_last_run - counts_am = copy.deepcopy(self.module.wasting_incident_case_tracker_zeros) + counts_am = self.module.wasting_incident_case_tracker_zeros for age_grp in self.module.wasting_incident_case_tracker.keys(): for state in self.module.wasting_states: @@ -1601,7 +1597,8 @@ def apply(self, population): logger.info(key='wasting_incidence_count', data=counts_am) # Reset the counters and the date_last_run - self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) + self.module.wasting_incident_case_tracker = self.module.wasting_incident_case_tracker_blank + self.date_last_run = self.sim.date # Wasting totals (prevalence at logging time) @@ -1626,3 +1623,4 @@ def apply(self, population): '48_59mo': currently_wasted_age_48_59mo} logger.info(key='wasting_prevalence_count', data=currently_wasted) + diff --git a/tests/test_wasting.py b/tests/test_wasting.py index a9e5b58d1a..31de2fa9bf 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -21,9 +21,9 @@ from tlo.methods.wasting import ( AcuteMalnutritionDeathPollingEvent, ClinicalAcuteMalnutritionRecoveryEvent, - HSI_inpatient_care_for_complicated_SAM, - HSI_outpatient_therapeutic_programme_for_SAM, - HSI_supplementary_feeding_programme_for_MAM, + HSI_Wasting_InpatientCareForComplicated_SAM, + HSI_Wasting_OutpatientTherapeuticProgramme_SAM, + HSI_Wasting_SupplementaryFeedingProgramme_MAM, ProgressionSevereWastingEvent, SevereAcuteMalnutritionDeathEvent, UpdateToMAM, @@ -36,6 +36,7 @@ # Default date for the start of simulations start_date = Date(2010, 1, 1) +end_date = Date(2011, 1, 2) def get_sim(tmpdir): @@ -317,7 +318,7 @@ def test_recovery_severe_wasting(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Run Death Polling Polling event to apply death: + # Run Death Polling event to apply death: death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) death_polling.apply(sim.population) @@ -778,7 +779,7 @@ def test_use_of_HSI_for_MAM(tmpdir): assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) # Run the HSI event - hsi = HSI_supplementary_feeding_programme_for_MAM(person_id=person_id, module=sim.modules['Wasting']) + hsi = HSI_Wasting_SupplementaryFeedingProgramme_MAM(person_id=person_id, module=sim.modules['Wasting']) hsi.run(squeeze_factor=0.0) # Check that person is now on treatment: @@ -801,7 +802,7 @@ def test_use_of_HSI_for_MAM(tmpdir): def test_use_of_HSI_for_SAM(tmpdir): - """ Check that the HSI_outpatient_therapeutic_programme_for_SAM and HSI_inpatient_care_for_complicated_SAM work""" + """ Check that the HSI_Wasting_OutpatientTherapeuticProgramme_SAM and HSI_Wasting_InpatientCareForComplicated_SAM work""" def test_use_of_HSI_by_complication(complications): dur = pd.DateOffset(days=0) @@ -890,10 +891,10 @@ def test_use_of_HSI_by_complication(complications): # Run the HSI event if complications: - hsi = HSI_inpatient_care_for_complicated_SAM(person_id=person_id, module=sim.modules['Wasting']) + hsi = HSI_Wasting_InpatientCareForComplicated_SAM(person_id=person_id, module=sim.modules['Wasting']) hsi.run(squeeze_factor=0.0) else: - hsi = HSI_outpatient_therapeutic_programme_for_SAM(person_id=person_id, module=sim.modules['Wasting']) + hsi = HSI_Wasting_OutpatientTherapeuticProgramme_SAM(person_id=person_id, module=sim.modules['Wasting']) hsi.run(squeeze_factor=0.0) # Check that person is now on treatment: From 3e6c6f07109ae62c76d8826a7b4ec3a31e0ad420 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Fri, 20 Oct 2023 15:10:35 +0200 Subject: [PATCH 012/755] changed some logic, linting, progress individuals to SAM instead of killing them --- src/tlo/methods/wasting.py | 119 +++++++++++++++++-------------------- 1 file changed, 54 insertions(+), 65 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index d8bb8ede59..80629ffb2a 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -253,7 +253,6 @@ def read_parameters(self, data_folder): self.load_parameters_from_dataframe( pd.read_excel(Path(self.resourcefilepath) / 'ResourceFile_Wasting.xlsx', sheet_name='Parameter_values_AM')) - p = self.parameters # Declare symptoms that this module will cause and which are not included in the generic symptoms: generic_symptoms = self.sim.modules['SymptomManager'].generic_symptoms @@ -317,7 +316,7 @@ def get_odds_wasting(agegp): base_odds_of_wasting = probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) return base_odds_of_wasting - def make_linear_model_wasting(agegp, intercept=get_odds_wasting(agegp=agegp)): + def make_linear_model_wasting(intercept=get_odds_wasting(agegp=agegp)): return LinearModel( LinearModelType.LOGISTIC, intercept, # baseline odds: get_odds_wasting(agegp=agegp) @@ -337,13 +336,13 @@ def make_linear_model_wasting(agegp, intercept=get_odds_wasting(agegp=agegp)): p['or_wasting_preterm_and_AGA']) ) - unscaled_lm = make_linear_model_wasting(agegp, intercept=get_odds_wasting(agegp=agegp)) + unscaled_lm = make_linear_model_wasting(intercept=get_odds_wasting(agegp=agegp)) target_mean = get_odds_wasting(agegp='12_23mo') actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1)]).mean() scaled_intercept = get_odds_wasting(agegp) * (target_mean / actual_mean) if \ (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else get_odds_wasting(agegp) - scaled_lm = make_linear_model_wasting(agegp, intercept=scaled_intercept) + scaled_lm = make_linear_model_wasting(intercept=scaled_intercept) return scaled_lm # the linear model returns the probability that is implied by the model prob = odds / (1 + odds) @@ -351,20 +350,20 @@ def make_linear_model_wasting(agegp, intercept=get_odds_wasting(agegp=agegp)): self.prevalence_equations_by_age[agegp] = make_scaled_linear_model_wasting(agegp) # get the initial prevalence values for each age group using the lm equation (scaled) - prevalence_of_wasting = pd.DataFrame(index=df.loc[df.is_alive & (df.age_exact_years < 5)].index) + prevalence_of_wasting = pd.DataFrame(index=df.index[df.is_alive & (df.age_exact_years < 5)]) prevalence_of_wasting['0_5mo'] = self.prevalence_equations_by_age['0_5mo'] \ .predict(df.loc[df.is_alive & (df.age_exact_years < 0.5)]) prevalence_of_wasting['6_11mo'] = self.prevalence_equations_by_age['6_11mo'] \ - .predict(df.loc[df.is_alive & ((df.age_exact_years >= 0.5) & (df.age_exact_years < 1))]) + .predict(df.loc[df.is_alive & (df.age_exact_years.between(0.5, 1, inclusive='left'))]) prevalence_of_wasting['12_23mo'] = self.prevalence_equations_by_age['12_23mo'] \ - .predict(df.loc[df.is_alive & ((df.age_exact_years >= 1) & (df.age_exact_years < 2))]) + .predict(df.loc[df.is_alive & (df.age_exact_years.between(1, 2, inclusive='left'))]) prevalence_of_wasting['24_35mo'] = self.prevalence_equations_by_age['24_35mo'] \ - .predict(df.loc[df.is_alive & ((df.age_exact_years >= 2) & (df.age_exact_years < 3))]) + .predict(df.loc[df.is_alive & (df.age_exact_years.between(2, 3, inclusive='left'))]) prevalence_of_wasting['36_47mo'] = self.prevalence_equations_by_age['36_47mo'] \ - .predict(df.loc[df.is_alive & ((df.age_exact_years >= 3) & (df.age_exact_years < 4))]) + .predict(df.loc[df.is_alive & (df.age_exact_years.between(3, 4, inclusive='left'))]) prevalence_of_wasting['48_59mo'] = self.prevalence_equations_by_age['48_59mo'] \ - .predict(df.loc[df.is_alive & ((df.age_exact_years >= 4) & (df.age_exact_years < 5))]) + .predict(df.loc[df.is_alive & (df.age_exact_years.between(4, 5, inclusive='left'))]) # ----------------------------------------------------------------------------------------------------- # # # # # # further categorize into moderate (-3<=WHZ<-2) or severe (WHZ<-3) wasting # # # # # @@ -393,21 +392,22 @@ def get_prob_severe_in_overall_wasting(agegp): # get the probability of severe wasting return proportion_severe_in_overall_wasting + prev_wasting_idx = prevalence_of_wasting.index # get index of prevalence of wasting dataframe # differentiate into severe wasting and moderate wasting, by age group for agegp in ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo']: wasted = self.rng.random_sample(len(prevalence_of_wasting[agegp])) < prevalence_of_wasting[agegp] - for id in wasted[wasted].index: + for idx in prev_wasting_idx[wasted]: probability_of_severe = get_prob_severe_in_overall_wasting(agegp) wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], p=[probability_of_severe, 1 - probability_of_severe]) - df.at[id, 'un_WHZ_category'] = wasted_category - df.at[id, 'un_last_wasting_date_of_onset'] = self.sim.date - df.at[id, 'un_ever_wasted'] = True - df.at[id, 'un_am_treatment_type'] = 'none' # start without treatment + df.at[idx, 'un_WHZ_category'] = wasted_category + df.at[idx, 'un_last_wasting_date_of_onset'] = self.sim.date + df.at[idx, 'un_ever_wasted'] = True + df.at[idx, 'un_am_treatment_type'] = 'none' # start without treatment # update clinical symptoms for severe wasting - self.wasting_clinical_symptoms(person_id=id) + self.wasting_clinical_symptoms(person_id=idx) - df.loc[wasted[~wasted].index, 'un_WHZ_category'] = 'WHZ>=-2' + df.loc[prev_wasting_idx[~wasted], 'un_WHZ_category'] = 'WHZ>=-2' # ----------------------------------------------------------------------------------------------------- # # # # # # Give MUAC category, presence of oedema, and determine acute malnutrition state # # # # # @@ -419,12 +419,10 @@ def get_prob_severe_in_overall_wasting(agegp): # inpatient care sam_requiring_inpatient_care = df.index[df.is_alive & (df.age_exact_years < 5) & ( df.un_clinical_acute_malnutrition == 'SAM') & df.un_sam_with_complications] - print(f'require in patient {sam_requiring_inpatient_care}') - recovered_complic_sam = self.rng.random_sample(len(sam_requiring_inpatient_care)) > ( + recovered_complic_sam = self.rng.random_sample(len(sam_requiring_inpatient_care)) < ( p['coverage_inpatient_care'] * p['recovery_rate_with_inpatient_care']) # schedule recovery, and reset properties for person in sam_requiring_inpatient_care[recovered_complic_sam]: - print(f'the person is {person}') self.sim.schedule_event( event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months @@ -442,25 +440,26 @@ def get_prob_severe_in_overall_wasting(agegp): for person in uncomplicated_sam[recovered_uncompl_sam]: self.sim.schedule_event( event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), - date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months + date=self.sim.date + DateOffset(months=3)) # in the next 3 months for person in uncomplicated_sam[~recovered_uncompl_sam]: self.sim.schedule_event( event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person), - date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months + date=self.sim.date + DateOffset(months=3)) # in the next 3 months # supplementary feeding for MAM children_with_mam = df.index[df.is_alive & (df.age_exact_years < 5) & ( df.un_clinical_acute_malnutrition == 'MAM') & ~df.un_sam_with_complications] - recovered_mam = self.rng.random_sample(len(children_with_mam)) > ( + recovered_mam = self.rng.random_sample(len(children_with_mam)) < ( p['coverage_supplementary_feeding_program'] * p['recovery_rate_with_CSB++']) for person in children_with_mam[recovered_mam]: self.sim.schedule_event( event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months + # we suggest progressing to severe wasting if not recovered for person in children_with_mam[~recovered_mam]: self.sim.schedule_event( - event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person), - date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months + event=ProgressionSevereWastingEvent(module=self, person_id=person), + date=self.sim.date + DateOffset(months=3)) # in the next 3 months def initialise_simulation(self, sim): """Prepares for simulation: @@ -704,16 +703,17 @@ def nutritional_oedema_present(self, idx): df.loc[children_without_wasting[oedema_in_non_wasted], 'un_am_bilateral_oedema'] = True df.loc[children_without_wasting[~oedema_in_non_wasted], 'un_am_bilateral_oedema'] = False - def clinical_acute_malnutrition_state(self, person_id): + def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): """ This fuction will determine the clinical acute malnutrition status (MAM, SAM) based on anthropometric indices and presence of bilateral oedema (Kwashiorkor); And help determine whether the individual will have medical complications, applicable to SAM cases only, requiring inpatient care. - :param person_id: + :param person_id: individual id + :param pop_dataframe: population dataframe :return: """ - df = self.sim.population.props + df = pop_dataframe p = self.parameters # check if person is not wasted @@ -722,7 +722,6 @@ def clinical_acute_malnutrition_state(self, person_id): (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & (~df.at[person_id, 'un_am_bilateral_oedema']) ): - print('WELL: un_clinical_acute_malnutrition') df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' # severe acute malnutrition - MUAC<115mm and/or WHZ<-3 and/or bilateral oedema @@ -731,11 +730,9 @@ def clinical_acute_malnutrition_state(self, person_id): (df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3') | (df.at[person_id, 'un_am_bilateral_oedema']) ): - print('SAM: un_clinical_acute_malnutrition') df.at[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' else: - print('MAM: un_clinical_acute_malnutrition') df.at[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' # Determine if SAM episode has complications @@ -789,19 +786,18 @@ def population_poll_clinical_am(self, population): # give MUAC measurement category for all WHZ, including well nourished children ----- for whz in ['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2']: - index_6_59mo_by_whz = df.index[df.is_alive & ((df.age_exact_years >= 0.5) & ( - df.age_exact_years < 5)) & (df.un_WHZ_category == whz)] + index_6_59mo_by_whz = df.index[df.is_alive & (df.age_exact_years.between(0.5, 5, inclusive='left')) + & (df.un_WHZ_category == whz)] self.muac_cutoff_by_WHZ(idx=index_6_59mo_by_whz, whz=whz) # determine the presence of bilateral oedema / oedematous malnutrition ----- index_under5 = df.index[df.is_alive & (df.age_exact_years < 5)] self.nutritional_oedema_present(idx=index_under5) - print('population clinical poll') # determine the clinical acute malnutrition state ----- + df = self.sim.population.props for person_id in index_under5: - print('population under 5') - self.clinical_acute_malnutrition_state(person_id=person_id) + self.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) def on_hsi_alert(self, person_id, treatment_id): """ @@ -840,7 +836,6 @@ def wasting_clinical_symptoms(self, person_id): :param person_id: """ df = self.sim.population.props - if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': return @@ -1008,20 +1003,19 @@ def apply(self, population): # # # # # # # # # # # # # # # # # # # # # INCIDENCE OF WASTING # # # # # # # # # # # # # # # # # # # # # # Determine who will be onset with wasting among those who are not currently wasted ------------- - incidence_of_wasting = self.module.wasting_incidence_equation.predict( - df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == 'WHZ>=-2')]) - wasted = rng.random_sample(len(incidence_of_wasting)) < incidence_of_wasting + inc_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == 'WHZ>=-2')] + incidence_of_wasting = self.module.wasting_incidence_equation.predict(inc_wasting, rng) - wasting_idx = incidence_of_wasting.index + wasting_idx = inc_wasting.index # update the properties for wasted children - df.loc[wasting_idx[wasted], 'un_ever_wasted'] = True - df.loc[wasting_idx[wasted], 'un_last_wasting_date_of_onset'] = self.sim.date - df.loc[wasting_idx[wasted], 'un_WHZ_category'] = '-3<=WHZ<-2' # start as moderate wasting - df.loc[wasting_idx[wasted], 'un_am_treatment_type'] = 'none' # start without treatment + df.loc[wasting_idx[incidence_of_wasting], 'un_ever_wasted'] = True + df.loc[wasting_idx[incidence_of_wasting], 'un_last_wasting_date_of_onset'] = self.sim.date + df.loc[wasting_idx[incidence_of_wasting], 'un_WHZ_category'] = '-3<=WHZ<-2' # start as moderate wasting + df.loc[wasting_idx[incidence_of_wasting], 'un_am_treatment_type'] = 'none' # start without treatment # ------------------------------------------------------------------------------------------- # Add this incident case to the tracker - for person in wasted[wasted].index: + for person in wasting_idx[incidence_of_wasting]: wasting_severity = df.at[person, 'un_WHZ_category'] age_group = WastingPollingEvent.AGE_GROUPS.get(df.loc[person].age_years, '5+y') if wasting_severity != 'WHZ>=-2': @@ -1031,12 +1025,12 @@ def apply(self, population): # # # # # # # # # # # # # # # # # # # # # PROGRESS TO SEVERE WASTING # # # # # # # # # # # # # # # # # # # # # # Determine those that will progress to severe wasting ( WHZ<-3) and schedule progression event --------- - progression_severe_wasting = self.module.severe_wasting_progression_equation.predict( - df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == '-3<=WHZ<-2')]) - will_be_severely_wasted = rng.random_sample(len(progression_severe_wasting)) < progression_severe_wasting - + progression_sev_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == '-3<=WHZ<-2')] + progression_severe_wasting = self.module.severe_wasting_progression_equation.predict(progression_sev_wasting, + rng) + progression_sev_wasting_idx = progression_sev_wasting.index # determine those individuals who will progress to severe wasting and time of progression - for person in will_be_severely_wasted[will_be_severely_wasted].index: + for person in progression_sev_wasting_idx[progression_severe_wasting]: outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') # schedule severe wasting WHZ<-3 onset if outcome_date <= self.sim.date: @@ -1053,7 +1047,7 @@ def apply(self, population): # # # # # # # # # # # # # # # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # # # # moderate wasting not progressed to severe, schedule recovery - for person in will_be_severely_wasted[~will_be_severely_wasted].index: + for person in progression_sev_wasting_idx[~progression_severe_wasting]: outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') if outcome_date <= self.sim.date: # schedule recovery for today @@ -1112,7 +1106,7 @@ def apply(self, person_id): m.muac_cutoff_by_WHZ(idx=df.loc[[person_id]].index, whz='WHZ<-3') # update the clinical state of acute malnutrition, and check complications if SAM - m.clinical_acute_malnutrition_state(person_id) + m.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) # update clinical symptoms for severe wasting m.wasting_clinical_symptoms(person_id=person_id) @@ -1151,12 +1145,11 @@ def apply(self, population): # # # # # # # # # # # # # # # # # # # # # DEATH # # # # # # # # # # # # # # # # # # # # # # Determine those that will die ----------------------------------------------- - prob_death = self.module.sam_death_equation.predict(df.loc[df.is_alive & (df.age_exact_years < 5) & - (df.un_clinical_acute_malnutrition != 'well')]) - will_die = rng.random_sample(len(prob_death)) < prob_death - + _to_die = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_clinical_acute_malnutrition != 'well')] + will_die = self.module.sam_death_equation.predict(_to_die, rng) + _to_die_idx = _to_die.index # schedule death date - for person in will_die[will_die].index: + for person in _to_die_idx[will_die]: death_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='SAM') if death_date <= self.sim.date: # schedule death for today @@ -1209,9 +1202,9 @@ def apply(self, person_id): return # Check if this person should still die from SAM: - if pd.isnull(df.at[person_id, 'un_am_recovery_date']): + if pd.isnull(df.at[person_id, 'un_am_recovery_date']) &\ + (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM'): # person_ids = df.at[person_id, 'un_am_recovery_date'])] - print(f"this person is going to die {df.at[person_id, 'un_clinical_acute_malnutrition']}") # Cause the death to happen immediately df.at[person_id, 'un_sam_death_date'] = self.sim.date self.sim.modules['Demography'].do_death( @@ -1247,7 +1240,7 @@ def apply(self, person_id): # Note assumption: prob of oedema remained the same as applied in wasting onset # update the clinical acute malnutrition state - m.clinical_acute_malnutrition_state(person_id) + m.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well': # this will clear all wasting symptoms @@ -1566,9 +1559,6 @@ def did_not_run(self): pass -class WastingModels: - """ houses all wasting linear moddels """ - class WastingLoggingEvent(RegularEvent, PopulationScopeEventMixin): """ This Event logs the number of incident cases that have occurred since the previous logging event. @@ -1623,4 +1613,3 @@ def apply(self, population): '48_59mo': currently_wasted_age_48_59mo} logger.info(key='wasting_prevalence_count', data=currently_wasted) - From 9df52aa7769f7709389ded977e247726c87eadb9 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Fri, 20 Oct 2023 15:18:49 +0200 Subject: [PATCH 013/755] code cleaning --- src/tlo/methods/wasting.py | 75 ++------------------------------------ 1 file changed, 3 insertions(+), 72 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 80629ffb2a..f6efadf20f 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -825,8 +825,6 @@ def report_daly_values(self): ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | ((df.un_WHZ_category != 'WHZ<-3') & (df.un_am_MUAC_category != "115-<125mm")) ) & df.un_am_bilateral_oedema] = self.daly_wts['MAM_with_oedema'] - # total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'MAM')] = \ - # self.daly_wts['MAM_w/o_oedema'] return total_daly_values @@ -1156,13 +1154,12 @@ def apply(self, population): self.sim.schedule_event( event=SevereAcuteMalnutritionDeathEvent(module=self.module, person_id=person), date=self.sim.date) - # df.at[person, 'un_sam_death_date'] = self.sim.date + else: # schedule death according to duration self.sim.schedule_event( event=SevereAcuteMalnutritionDeathEvent(module=self.module, person_id=person), date=death_date) - # df.at[person, 'un_sam_death_date'] = death_date # # # # # # # # # # # # # # # # # # # # # IMPROVEMENT FROM SAM TO MAM # # # # # # # # # # # # # # # # # # # # # # SAM = severe wasting (WHZ<-3) and/or MUAC <115mm, or nutritional oedema @@ -1204,7 +1201,6 @@ def apply(self, person_id): # Check if this person should still die from SAM: if pd.isnull(df.at[person_id, 'un_am_recovery_date']) &\ (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM'): - # person_ids = df.at[person_id, 'un_am_recovery_date'])] # Cause the death to happen immediately df.at[person_id, 'un_sam_death_date'] = self.sim.date self.sim.modules['Demography'].do_death( @@ -1365,20 +1361,11 @@ def apply(self, person_id, squeeze_factor): # ~~~~~~~~~~~~~~~~~~~~~~ # Make request for some consumables consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] - # whole package of interventions - # pkg_code_mam = pd.unique( - # consumables.loc[consumables['Intervention_Pkg'] == 'Management of moderate acute malnutrition (children)', - # 'Intervention_Pkg_Code'])[0] # This package includes only CSB(or supercereal or CSB++) # individual items item_code1 = pd.unique( consumables.loc[consumables['Items'] == 'Corn Soya Blend (or Supercereal - CSB++)', 'Item_Code'])[0] - # consumables_needed = {'Intervention_Package_Code': {pkg_code_mam: 1}, 'Item_Code': {item_code1: 1}} - # check availability of consumables - # outcome_of_request_for_consumables = self.sim.modules['HealthSystem'].request_consumables( - # hsi_event=self, cons_req_as_footprint=consumables_needed) - # answer comes back in the same format, but with quantities replaced with bools indicating availability if self.get_consumables([item_code1]): logger.debug(key='debug', data='consumables are available') # Log that the treatment is provided: @@ -1389,18 +1376,6 @@ def apply(self, person_id, squeeze_factor): else: logger.debug(key='debug', data="PkgCode1 is not available, so can't use it.") - # -------------------------------------------------------------------------------------------------- - # # check to see if all consumables returned (for demonstration purposes): - # all_available = (outcome_of_request_for_consumables['Intervention_Package_Code'][pkg_code_mam]) and \ - # (outcome_of_request_for_consumables['Item_Code'][item_code1]) - # # use helper function instead (for demonstration purposes) - # all_available_using_helper_function = self.get_all_consumables( - # item_codes=[item_code1], - # pkg_codes=[pkg_code_mam] - # ) - # # Demonstrate equivalence - # assert all_available == all_available_using_helper_function - def did_not_run(self): logger.debug("supplementary_feeding_programme_for_MAM: did not run") pass @@ -1437,23 +1412,14 @@ def apply(self, person_id, squeeze_factor): # ~~~~~~~~~~~~~~~~~~~~~~ # Make request for some consumables consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] - # whole package of interventions - # pkg_code_sam = pd.unique( - # consumables.loc[consumables['Intervention_Pkg'] == 'Management of severe malnutrition (children)', - # 'Intervention_Pkg_Code'])[0] + # individual items item_code1 = pd.unique( consumables.loc[consumables['Items'] == 'SAM theraputic foods', 'Item_Code'])[0] item_code2 = pd.unique( consumables.loc[consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] - # consumables_needed = {'Intervention_Package_Code': {pkg_code_sam: 1}, 'Item_Code': {item_code1: 1, - # item_code2: 1}} - # check availability of consumables - # outcome_of_request_for_consumables = self.sim.modules['HealthSystem'].request_consumables( - # hsi_event=self, cons_req_as_footprint=consumables_needed) - # answer comes back in the same format, but with quantities replaced with bools indicating availability if self.get_consumables(item_code1) and self.get_consumables(item_code2): logger.debug(key='debug', data='consumables are available.') # Log that the treatment is provided: @@ -1463,18 +1429,6 @@ def apply(self, person_id, squeeze_factor): self.module.do_when_am_treatment(person_id, intervention='OTC') else: logger.debug(key='debug', data="consumables not available, so can't use it.") - # -------------------------------------------------------------------------------------------------- - # # check to see if all consumables returned (for demonstration purposes): - # all_available = (outcome_of_request_for_consumables['Intervention_Package_Code'][pkg_code_sam]) and \ - # (outcome_of_request_for_consumables['Item_Code'][item_code1][item_code2]) - # - # # use helper function instead (for demonstration purposes) - # all_available_using_helper_function = self.get_all_consumables( - # item_codes=[item_code1, item_code2], - # pkg_codes=[pkg_code_sam] - # ) - # # Demonstrate equivalence - # assert all_available == all_available_using_helper_function def did_not_run(self): logger.debug("HSI_outpatient_therapeutic_programme_for_SAM: did not run") @@ -1513,26 +1467,14 @@ def apply(self, person_id, squeeze_factor): # ~~~~~~~~~~~~~~~~~~~~~~ # Make request for some consumables consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] - # whole package of interventions - # pkg_code_sam = pd.unique( - # consumables.loc[consumables['Intervention_Pkg'] == 'Management of severe malnutrition (children)', - # 'Intervention_Pkg_Code'])[0] + # individual items item_code1 = pd.unique( consumables.loc[consumables['Items'] == 'SAM theraputic foods', 'Item_Code'])[0] item_code2 = pd.unique( consumables.loc[consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] - # pkg_codes = self.sim.modules['HealthSystem'].get_item_codes_from_package_name - # pkg_codes_num = pkg_codes('Management of severe malnutrition (children)') - # - # consumables_needed = {'Intervention_Package_Code': {pkg_code_sam: 1}, 'Item_Code': {item_code1: 1, - # item_code2: 1}} - # # check availability of consumables - # outcome_of_request_for_consumables = self.sim.modules['HealthSystem'].request_consumables( - # hsi_event=self, cons_req_as_footprint=consumables_needed) - # answer comes back in the same format, but with quantities replaced with bools indicating availability if self.get_consumables(item_code1) and self.get_consumables(item_code2): logger.debug(key='debug', data='consumables available, so use it.') # Log that the treatment is provided: @@ -1542,17 +1484,6 @@ def apply(self, person_id, squeeze_factor): self.module.do_when_am_treatment(person_id, intervention='ITC') else: logger.debug(key='debug', data="consumables not available, so can't use it.") - # -------------------------------------------------------------------------------------------------- - # # check to see if all consumables returned (for demonstration purposes): - # all_available = (outcome_of_request_for_consumables['Intervention_Package_Code'][pkg_code_sam]) and \ - # (outcome_of_request_for_consumables['Item_Code'][item_code1][item_code2]) - # # use helper function instead (for demonstration purposes) - # all_available_using_helper_function = self.get_all_consumables( - # item_codes=[item_code1, item_code2], - # pkg_codes=[pkg_code_sam] - # ) - # # Demonstrate equivalence - # assert all_available == all_available_using_helper_function def did_not_run(self): logger.debug("HSI_inpatient_care_for_complicated_SAM: did not run") From 4cae5125701e8f986aa837ed783b194a0747b75f Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Mon, 23 Oct 2023 08:51:58 +0200 Subject: [PATCH 014/755] fixed line error --- tests/test_wasting.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 31de2fa9bf..94fefb7b42 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -802,7 +802,9 @@ def test_use_of_HSI_for_MAM(tmpdir): def test_use_of_HSI_for_SAM(tmpdir): - """ Check that the HSI_Wasting_OutpatientTherapeuticProgramme_SAM and HSI_Wasting_InpatientCareForComplicated_SAM work""" + """ + Check that the HSI_Wasting_OutpatientTherapeuticProgramme_SAM and HSI_Wasting_InpatientCareForComplicated_SAM work + """ def test_use_of_HSI_by_complication(complications): dur = pd.DateOffset(days=0) From c416d7a53dc5908846aaa14ad8bd08500a8d018f Mon Sep 17 00:00:00 2001 From: inesll <44782255+inesll@users.noreply.github.com> Date: Fri, 3 Nov 2023 13:36:44 +0000 Subject: [PATCH 015/755] added oedema reset to Wasting Natural Recovery called the function nutritional_oedema_present within the WastingNaturalRecoveryEvent to reset the values for the oedema status based on WHZ>=-2 --- src/tlo/methods/wasting.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index f6efadf20f..63ab90d8ca 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1232,6 +1232,7 @@ def apply(self, person_id): # For cases with normal WHZ, attribute probability of MUAC category if df.at[person_id, 'age_exact_years'] > 0.5: m.muac_cutoff_by_WHZ(idx=df.loc[[person_id]].index, whz='WHZ>=-2') + m.nutritional_oedema_present(idx==df.loc[[person_id]].index, whz='WHZ>=-2') # Note assumption: prob of oedema remained the same as applied in wasting onset From 3c8082590e83e41868bd06e1aba91449e8b684f0 Mon Sep 17 00:00:00 2001 From: inesll <44782255+inesll@users.noreply.github.com> Date: Fri, 3 Nov 2023 13:59:45 +0000 Subject: [PATCH 016/755] Remove progression to severe following treatment failure for MAM. Removed progression to severe following treatment failure for MAM, at initialise population. These individuals will be called at the next polling event (in 3 months) to determine their outcome - recovery, remain, or death. --- src/tlo/methods/wasting.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 63ab90d8ca..66600118da 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -455,11 +455,8 @@ def get_prob_severe_in_overall_wasting(agegp): self.sim.schedule_event( event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months - # we suggest progressing to severe wasting if not recovered - for person in children_with_mam[~recovered_mam]: - self.sim.schedule_event( - event=ProgressionSevereWastingEvent(module=self, person_id=person), - date=self.sim.date + DateOffset(months=3)) # in the next 3 months + # if not cured by the intervention, remain as MAM and outcome will be determined in the + # natural history of the next polling event def initialise_simulation(self, sim): """Prepares for simulation: From d4fff87ab8810330efe91d35867192b4771905e4 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Mon, 4 Dec 2023 15:59:52 +0200 Subject: [PATCH 017/755] re-structuring wasting module, activated HSI events, modified some parameter values in wasting resource file --- resources/ResourceFile_Wasting.xlsx | 4 +- .../wasting_analyses/analysis_wasting.py | 19 +- src/tlo/methods/hsi_generic_first_appts.py | 3 + src/tlo/methods/wasting.py | 780 ++++++++---------- tests/test_wasting.py | 752 ++++++----------- 5 files changed, 609 insertions(+), 949 deletions(-) diff --git a/resources/ResourceFile_Wasting.xlsx b/resources/ResourceFile_Wasting.xlsx index fa109671a5..b4e5b19824 100644 --- a/resources/ResourceFile_Wasting.xlsx +++ b/resources/ResourceFile_Wasting.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e7f03fe6554fde5e6285cf1fe8c49302feb70ab13169fe68ebfb926f03df3622 -size 11433 +oid sha256:7dac7ad9e1578600b390cab4817f1732f19ccc5cd05c136741e0b506dcd50aff +size 11489 diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 9dc5915ee7..56eae98c5f 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -52,18 +52,21 @@ def plot_wasting_incidence(self): w_inc_df = self.__logs_dict['wasting_incidence_count'] w_inc_df.set_index(w_inc_df.date.dt.year, inplace=True) w_inc_df.drop(columns='date', inplace=True) - new_df = pd.DataFrame(index=w_inc_df.index, data=w_inc_df.loc[w_inc_df.index[0], '0y']) + # get age year. doesn't matter what wasting category you choose for they all have same age groups + age_years = w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys() + _row_counter = 0 _col_counter = 0 fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True) # plot setup - for _year in w_inc_df.columns: - for _index in range(len(new_df.index)): - new_df.loc[new_df.index[_index], new_df.columns] = \ - w_inc_df.loc[w_inc_df.index[_index], _year].values() + for _age in age_years: + new_df = pd.DataFrame() + for state in w_inc_df.columns: + new_df[state] = w_inc_df.apply(lambda row: row[state][_age], axis=1) + new_df = new_df.apply(lambda _row: _row / _row.sum(), axis=1) # convert into proportions ax = new_df.plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], - title=f"incidence of wasting in {_year} infants") + title=f"incidence of wasting in {_age} infants") ax.legend(self.__wasting_types_desc.values(), loc='lower right') ax.set_xlabel('year') ax.set_ylabel('proportions') @@ -72,7 +75,7 @@ def plot_wasting_incidence(self): _row_counter += 1 _col_counter = -1 _col_counter += 1 # increment column counter - plt.tight_layout() + plt.tight_layout() plt.show() @@ -163,7 +166,7 @@ def plot_modal_gbd_deaths_by_gender(self): sim.make_initial_population(n=pop_size) sim.simulate(end_date=end_date) -# %% read the results +# read the results output_path = sim.log_filepath # initialise the wasting class diff --git a/src/tlo/methods/hsi_generic_first_appts.py b/src/tlo/methods/hsi_generic_first_appts.py index f84518b4a3..b35a062acc 100644 --- a/src/tlo/methods/hsi_generic_first_appts.py +++ b/src/tlo/methods/hsi_generic_first_appts.py @@ -183,6 +183,9 @@ def do_at_generic_first_appt_non_emergency(hsi_event, squeeze_factor): if 'Stunting' in sim.modules: sim.modules['Stunting'].do_routine_assessment_for_chronic_undernutrition(person_id=person_id) + if 'Wasting' in sim.modules: + sim.modules['Wasting'].do_when_acute_malnutrition_assessment(person_id) + else: # ----------------------------------- ADULT ----------------------------------- if 'OesophagealCancer' in sim.modules: diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index f6efadf20f..ad1c221742 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1,5 +1,5 @@ """Childhood wasting module""" - +import copy from pathlib import Path import numpy as np @@ -24,8 +24,6 @@ # --------------------------------------------------------------------------------------------------------- # MODULE DEFINITIONS # --------------------------------------------------------------------------------------------------------- - - class Wasting(Module): """ This module applies the prevalence of wasting at the population-level, @@ -199,6 +197,7 @@ class Wasting(Module): def __init__(self, name=None, resourcefilepath=None): super().__init__(name) + self.wasting_models = None self.resourcefilepath = resourcefilepath # Store the symptoms that this module will use: @@ -213,34 +212,19 @@ def __init__(self, name=None, resourcefilepath=None): # dict to hold counters for the number of episodes by wasting-type and age-group blank_counter = dict(zip(self.wasting_states, [list() for _ in self.wasting_states])) self.wasting_incident_case_tracker_blank = { - _agrp: blank_counter for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} - - self.wasting_incident_case_tracker = dict(self.wasting_incident_case_tracker_blank) - - zeros_counter = dict(zip(self.wasting_states, [0] * len(self.wasting_states))) - - self.wasting_incident_case_tracker_zeros = { - _agrp: zeros_counter for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} - - # dict to hold the DALY weights - self.daly_wts = dict() - - # --------------------- linear models of the natural history --------------------- # + _agrp: copy.deepcopy(blank_counter) for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} - # set the linear model equations for prevalence and incidence - self.prevalence_equations_by_age = dict() - self.wasting_incidence_equation = dict() + self.wasting_incident_case_tracker = copy.deepcopy(self.wasting_incident_case_tracker_blank) - # set the linear model for progression to severe wasting - self.severe_wasting_progression_equation = dict() + # wasting prevalence odds by age groups + self.wasting_prevalence_odds_by_age_grp: dict = dict() - # set the linear model for death from severe acute malnutrition - self.sam_death_equation = dict() + # wasting prevalence scaling by age group + self.age_grps_dict: dict = {_agrp: 1.0 for _agrp in + ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo']} - # --------------------- linear models following HSI interventions --------------------- # - - # set the linear models for MAM and SAM recovery by intervention - self.acute_malnutrition_recovery_based_on_interventions = dict() + # store severe wasting by age groups probabilities + self.age_grps_sev_wasting_probs: dict = dict() def read_parameters(self, data_folder): """ @@ -262,6 +246,12 @@ def read_parameters(self, data_folder): Symptom(name=symptom_name) # (give non-generic symptom 'average' healthcare seeking) ) + def pre_initialise_population(self): + """Things to do before processing the population: + * Generate wasting models + """ + self.wasting_models = WastingModels(self) + def initialise_population(self, population): """ Set our property values for the initial population. @@ -274,7 +264,6 @@ def initialise_population(self, population): :return: """ df = population.props - p = self.parameters # Set initial properties df.loc[df.is_alive, 'un_ever_wasted'] = False @@ -287,335 +276,55 @@ def initialise_population(self, population): df.loc[df.is_alive, 'un_am_MUAC_category'] = '>=125mm' df.loc[df.is_alive, 'un_am_treatment_type'] = 'not_applicable' - # ----------------------------------------------------------------------------------------------------- - # # # # # allocate initial prevalence of wasting at the start of the simulation # # # # # - - def make_scaled_linear_model_wasting(agegp): - """ Makes the unscaled linear model with intercept of baseline odds of wasting (WHZ <-2). - Calculates the mean odds of wasting by age group and then creates a new linear model - with adjusted intercept so odds in 1-year-olds matches the specified value in the model - when averaged across the population - """ - - def get_odds_wasting(agegp): - """ - This function will calculate the WHZ scores by categories and return the odds of wasting - :param agegp: age grouped in months - :return: - """ - # generate random numbers from N(meean, sd) - baseline_WHZ_prevalence_by_agegp = f'prev_WHZ_distribution_age_{agegp}' - WHZ_normal_distribution = norm(loc=p[baseline_WHZ_prevalence_by_agegp][0], - scale=p[baseline_WHZ_prevalence_by_agegp][1]) - - # get all wasting: WHZ <-2 - probability_over_or_equal_minus2sd = WHZ_normal_distribution.sf(-2) - probability_less_than_minus2sd = 1 - probability_over_or_equal_minus2sd - - # convert probability to odds - base_odds_of_wasting = probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) - return base_odds_of_wasting - - def make_linear_model_wasting(intercept=get_odds_wasting(agegp=agegp)): - return LinearModel( - LinearModelType.LOGISTIC, - intercept, # baseline odds: get_odds_wasting(agegp=agegp) - Predictor('li_wealth').when(2, p['or_wasting_hhwealth_Q2']) - .when(3, p['or_wasting_hhwealth_Q3']) - .when(4, p['or_wasting_hhwealth_Q4']) - .when(5, p['or_wasting_hhwealth_Q5']) - .otherwise(1.0), - Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& (nb_late_preterm == False) & (nb_early_preterm == False)', - p['or_wasting_SGA_and_term']), - Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', - p['or_wasting_SGA_and_preterm']), - Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") ' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', - p['or_wasting_preterm_and_AGA']) - ) - - unscaled_lm = make_linear_model_wasting(intercept=get_odds_wasting(agegp=agegp)) - - target_mean = get_odds_wasting(agegp='12_23mo') - actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1)]).mean() - scaled_intercept = get_odds_wasting(agegp) * (target_mean / actual_mean) if \ - (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else get_odds_wasting(agegp) - scaled_lm = make_linear_model_wasting(intercept=scaled_intercept) - return scaled_lm - - # the linear model returns the probability that is implied by the model prob = odds / (1 + odds) - for agegp in ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo']: - self.prevalence_equations_by_age[agegp] = make_scaled_linear_model_wasting(agegp) - - # get the initial prevalence values for each age group using the lm equation (scaled) - prevalence_of_wasting = pd.DataFrame(index=df.index[df.is_alive & (df.age_exact_years < 5)]) - - prevalence_of_wasting['0_5mo'] = self.prevalence_equations_by_age['0_5mo'] \ - .predict(df.loc[df.is_alive & (df.age_exact_years < 0.5)]) - prevalence_of_wasting['6_11mo'] = self.prevalence_equations_by_age['6_11mo'] \ - .predict(df.loc[df.is_alive & (df.age_exact_years.between(0.5, 1, inclusive='left'))]) - prevalence_of_wasting['12_23mo'] = self.prevalence_equations_by_age['12_23mo'] \ - .predict(df.loc[df.is_alive & (df.age_exact_years.between(1, 2, inclusive='left'))]) - prevalence_of_wasting['24_35mo'] = self.prevalence_equations_by_age['24_35mo'] \ - .predict(df.loc[df.is_alive & (df.age_exact_years.between(2, 3, inclusive='left'))]) - prevalence_of_wasting['36_47mo'] = self.prevalence_equations_by_age['36_47mo'] \ - .predict(df.loc[df.is_alive & (df.age_exact_years.between(3, 4, inclusive='left'))]) - prevalence_of_wasting['48_59mo'] = self.prevalence_equations_by_age['48_59mo'] \ - .predict(df.loc[df.is_alive & (df.age_exact_years.between(4, 5, inclusive='left'))]) - - # ----------------------------------------------------------------------------------------------------- - # # # # # # further categorize into moderate (-3<=WHZ<-2) or severe (WHZ<-3) wasting # # # # # - def get_prob_severe_in_overall_wasting(agegp): - """ - This function will calculate the WHZ scores by categories and return probability of severe wasting - for those with wasting status - :param agegp: age grouped in months - :return: - """ - # generate random numbers from N(meean, sd) - baseline_WHZ_prevalence_by_agegp = f'prev_WHZ_distribution_age_{agegp}' - WHZ_normal_distribution = norm(loc=p[baseline_WHZ_prevalence_by_agegp][0], - scale=p[baseline_WHZ_prevalence_by_agegp][1]) + # update wasting prevalence odds dictionary + self.wasting_models.get_age_grps_odds() - # get all wasting: WHZ <-2 - probability_over_or_equal_minus2sd = WHZ_normal_distribution.sf(-2) - probability_less_than_minus2sd = 1 - probability_over_or_equal_minus2sd - # get severe wasting zcores: WHZ <-3 - probability_over_or_equal_minus3sd = WHZ_normal_distribution.sf(-3) - probability_less_than_minus3sd = 1 - probability_over_or_equal_minus3sd + # update wasting prevalence scaling dictionary + self.wasting_models.get_wasting_prevalence_scaling(df) - # make WHZ <-2 as the 100% and get the adjusted probability of severe wasting within overall wasting - proportion_severe_in_overall_wasting = probability_less_than_minus3sd * probability_less_than_minus2sd + # initialise wasting prevalence linear model + wasting_prevalence = self.wasting_models.get_wasting_prevalence() - # get the probability of severe wasting - return proportion_severe_in_overall_wasting + # Assign wasting categories in young children at initiation + for agegp in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months + low_bound_age_in_years = agegp[0] / 12.0 + high_bound_age_in_years = (1 + agegp[1]) / 12.0 + lm_ext_var = f'{agegp[0]}_{agegp[1]}mo' # linear model external variables + mask = (df.is_alive & + df.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, inclusive='left') + ) + prevalence_of_wasting = wasting_prevalence.predict(df.loc[mask], agrp='None', agrp_scaling=lm_ext_var) - prev_wasting_idx = prevalence_of_wasting.index # get index of prevalence of wasting dataframe - # differentiate into severe wasting and moderate wasting, by age group - for agegp in ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo']: - wasted = self.rng.random_sample(len(prevalence_of_wasting[agegp])) < prevalence_of_wasting[agegp] - for idx in prev_wasting_idx[wasted]: - probability_of_severe = get_prob_severe_in_overall_wasting(agegp) + # categorize into moderate (-3<=WHZ<-2) or severe (WHZ<-3) wasting + wasted = self.rng.random_sample(len(prevalence_of_wasting)) < prevalence_of_wasting + for idx in prevalence_of_wasting.index[wasted]: + probability_of_severe = self.age_grps_sev_wasting_probs[lm_ext_var] wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], p=[probability_of_severe, 1 - probability_of_severe]) df.at[idx, 'un_WHZ_category'] = wasted_category df.at[idx, 'un_last_wasting_date_of_onset'] = self.sim.date df.at[idx, 'un_ever_wasted'] = True df.at[idx, 'un_am_treatment_type'] = 'none' # start without treatment + # update clinical symptoms for severe wasting self.wasting_clinical_symptoms(person_id=idx) - df.loc[prev_wasting_idx[~wasted], 'un_WHZ_category'] = 'WHZ>=-2' - # ----------------------------------------------------------------------------------------------------- # # # # # # Give MUAC category, presence of oedema, and determine acute malnutrition state # # # # # self.population_poll_clinical_am(df) - # ----------------------------------------------------------------------------------------------------- - # # # # # Treatment coverage and cure rates at initiation # # # # # - - # inpatient care - sam_requiring_inpatient_care = df.index[df.is_alive & (df.age_exact_years < 5) & ( - df.un_clinical_acute_malnutrition == 'SAM') & df.un_sam_with_complications] - recovered_complic_sam = self.rng.random_sample(len(sam_requiring_inpatient_care)) < ( - p['coverage_inpatient_care'] * p['recovery_rate_with_inpatient_care']) - # schedule recovery, and reset properties - for person in sam_requiring_inpatient_care[recovered_complic_sam]: - self.sim.schedule_event( - event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), - date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months - - for person in sam_requiring_inpatient_care[~recovered_complic_sam]: - self.sim.schedule_event( - event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person), - date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months - - # outpatient care - uncomplicated_sam = df.index[df.is_alive & (df.age_exact_years < 5) & ( - df.un_clinical_acute_malnutrition == 'SAM') & ~df.un_sam_with_complications] - recovered_uncompl_sam = self.rng.random_sample(len(uncomplicated_sam)) > ( - p['coverage_outpatient_therapeutic_care'] * p['recovery_rate_with_standard_RUTF']) - for person in uncomplicated_sam[recovered_uncompl_sam]: - self.sim.schedule_event( - event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), - date=self.sim.date + DateOffset(months=3)) # in the next 3 months - for person in uncomplicated_sam[~recovered_uncompl_sam]: - self.sim.schedule_event( - event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person), - date=self.sim.date + DateOffset(months=3)) # in the next 3 months - - # supplementary feeding for MAM - children_with_mam = df.index[df.is_alive & (df.age_exact_years < 5) & ( - df.un_clinical_acute_malnutrition == 'MAM') & ~df.un_sam_with_complications] - recovered_mam = self.rng.random_sample(len(children_with_mam)) < ( - p['coverage_supplementary_feeding_program'] * p['recovery_rate_with_CSB++']) - for person in children_with_mam[recovered_mam]: - self.sim.schedule_event( - event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), - date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months - # we suggest progressing to severe wasting if not recovered - for person in children_with_mam[~recovered_mam]: - self.sim.schedule_event( - event=ProgressionSevereWastingEvent(module=self, person_id=person), - date=self.sim.date + DateOffset(months=3)) # in the next 3 months - def initialise_simulation(self, sim): """Prepares for simulation: * Schedules the main polling event * Schedules the main logging event - * Establishes the incidence linear models and other data structures using the parameters that have been read-in - * Store the consumables that are required in each of the HSI """ - df = self.sim.population.props - p = self.parameters # schedule wasting pool event sim.schedule_event(WastingPollingEvent(self), sim.date + DateOffset(months=3)) - # schedule acute malnutrition event - sim.schedule_event(AcuteMalnutritionDeathPollingEvent(self), sim.date + DateOffset(months=3)) - # schedule wasting logging event sim.schedule_event(WastingLoggingEvent(self), sim.date + DateOffset(months=12)) - # Get DALY weights - get_daly_weight = self.sim.modules['HealthBurden'].get_daly_weight - if 'HealthBurden' in self.sim.modules.keys(): - # self.daly_wts['MAM_w/o_oedema'] = get_daly_weight(sequlae_code=460) ## no value given - self.daly_wts['MAM_with_oedema'] = get_daly_weight(sequlae_code=461) - self.daly_wts['SAM_w/o_oedema'] = get_daly_weight(sequlae_code=462) - self.daly_wts['SAM_with_oedema'] = get_daly_weight(sequlae_code=463) - - # -------------------------------------------------------------------------------------------- - # Make a linear model equation that govern the probability that a person becomes wasted WHZ<-2 - def make_scaled_lm_wasting_incidence(): - """ - Makes the unscaled linear model with default intercept of 1. Calculates the mean incidents rate for - 1-year-olds and then creates a new linear model with adjusted intercept so incidents in 1-year-olds - matches the specified value in the model when averaged across the population - """ - - def make_lm_wasting_incidence(intercept=1.0): - return LinearModel( - LinearModelType.MULTIPLICATIVE, - intercept, - Predictor('age_exact_years').when('<0.5', p['base_inc_rate_wasting_by_agegp'][0]) - .when('<1.0', p['base_inc_rate_wasting_by_agegp'][1]) - .when('.between(1,1.9999)', p['base_inc_rate_wasting_by_agegp'][2]) - .when('.between(2,2.9999)', p['base_inc_rate_wasting_by_agegp'][3]) - .when('.between(3,3.9999)', p['base_inc_rate_wasting_by_agegp'][4]) - .when('.between(4,4.9999)', p['base_inc_rate_wasting_by_agegp'][5]) - .otherwise(0.0), - Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& (nb_late_preterm == False) & (nb_early_preterm == False)', - p['rr_wasting_SGA_and_term']), - Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', - p['rr_wasting_SGA_and_preterm']), - Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") ' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', - p['rr_wasting_preterm_and_AGA']), - Predictor('li_wealth').apply(lambda x: 1 if x == 1 else (x - 1) ** (p['rr_wasting_wealth_level'])), - ) - - unscaled_lm = make_lm_wasting_incidence() - target_mean = p['base_inc_rate_wasting_by_agegp'][2] - actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1) & - (df.un_WHZ_category == 'WHZ>=-2')]).mean() - scaled_intercept = 1.0 * (target_mean / actual_mean) \ - if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else 1.0 - scaled_lm = make_lm_wasting_incidence(intercept=scaled_intercept) - - return scaled_lm - - self.wasting_incidence_equation = make_scaled_lm_wasting_incidence() - - # -------------------------------------------------------------------------------------------- - # Linear model for the probability of progression to severe wasting (age-dependent only) - # (natural history only, no interventions) - self.severe_wasting_progression_equation = \ - LinearModel(LinearModelType.MULTIPLICATIVE, - 1.0, - Predictor('age_exact_years') - .when('<0.5', p['progression_severe_wasting_by_agegp'][0]) - .when('.between(0.5,0.9999)', p['progression_severe_wasting_by_agegp'][1]) - .when('.between(1,1.9999)', p['progression_severe_wasting_by_agegp'][2]) - .when('.between(2,2.9999)', p['progression_severe_wasting_by_agegp'][3]) - .when('.between(3,3.9999)', p['progression_severe_wasting_by_agegp'][4]) - .when('.between(4,4.9999)', p['progression_severe_wasting_by_agegp'][5]) - .otherwise(0.0), - ) - - # -------------------------------------------------------------------------------------------- - # Linear model for the probability of recovery based on interventions - self.acute_malnutrition_recovery_based_on_interventions.update({ - 'MAM': - LinearModel(LinearModelType.MULTIPLICATIVE, - 1.0, - Predictor('un_am_treatment_type').when('soy_RUSF', p['recovery_rate_with_soy_RUSF']) - .when('CSB++', p['recovery_rate_with_CSB++']) - .otherwise(0.0), - ), - 'SAM': - LinearModel(LinearModelType.MULTIPLICATIVE, - 1.0, - Predictor('un_am_treatment_type') - .when('standard_RUTF', p['recovery_rate_with_standard_RUTF']) - .when('inpatient_care', p['recovery_rate_with_inpatient_care']) - .otherwise(0.0), - ) - }) - - # -------------------------------------------------------------------------------------------- - # Make a linear model equation of death from severe acute malnutrition - def make_scaled_lm_sam_death(): - """ - Makes the unscaled linear model with default intercept of 1. Calculates the mean death rate for - 1-year-olds and then creates a new linear model with adjusted intercept so incidents in 1-year-olds - matches the specified value in the model when averaged across the population - """ - - def make_lm_sam_death(intercept=1.0): - return LinearModel( - LinearModelType.MULTIPLICATIVE, - intercept, - Predictor('un_am_treatment_type').when('none', p['base_death_rate_untreated_SAM']).otherwise(0.0), - Predictor('un_sam_with_complications').when(True, - p['rr_SAM_death_with_complications']), - Predictor().when('(un_am_bilateral_oedema == False) & ' - '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "115-<125mm")', - p['rr_SAM_death_WHZ<-3_only']), - Predictor().when('(un_am_bilateral_oedema == False) & ' - '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "<115mm")', - p['rr_SAM_death_both_WHZ<-3_&_MUAC<115mm']), - Predictor().when('(un_am_bilateral_oedema == True) & ' - '(un_WHZ_category == "-3<=WHZ<-2") & (un_am_MUAC_category == "<115mm")', - p['rr_SAM_death_kwashiorkor_only']), - Predictor().when('(un_am_bilateral_oedema == True) & ' - '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "115-<125mm")', - p['rr_SAM_death_kwashiorkor_WHZ<-3_only']), - Predictor().when('(un_am_bilateral_oedema == True) & ' - '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "<115mm")', - p['rr_SAM_death_kwashiorkor_both_WHZ<-3_&_MUAC<115mm']), - Predictor().when('(un_am_bilateral_oedema == True) & ' - '(un_WHZ_category == "-3<=WHZ<-2") & (un_am_MUAC_category == "<115mm")', - p['rr_SAM_death_kwashiorkor_MUAC<115mm_only']), - ) - - unscaled_lm = make_lm_sam_death() - target_mean = p['base_death_rate_untreated_SAM'] - actual_mean = unscaled_lm.predict( - df.loc[df.is_alive & ((df.age_exact_years > 0.5) & (df.age_exact_years < 5)) & - (df.un_clinical_acute_malnutrition == 'SAM')]).mean() - scaled_intercept = 1.0 * (target_mean / actual_mean) \ - if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else 1.0 - scaled_lm = make_lm_sam_death(intercept=scaled_intercept) - return scaled_lm - - self.sam_death_equation = make_scaled_lm_sam_death() - def on_birth(self, mother_id, child_id): """Initialise properties for a newborn individual. :param mother_id: the mother for this child @@ -624,7 +333,16 @@ def on_birth(self, mother_id, child_id): df = self.sim.population.props - df.at[child_id, 'un_WHZ_category'] = 'WHZ>=-2' + # Set initial properties + df.at[child_id, 'un_ever_wasted'] = False + df.at[child_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished + df.at[child_id, 'un_clinical_acute_malnutrition'] = 'well' + df.at[child_id, 'un_last_wasting_date_of_onset'] = pd.NaT + df.at[child_id, 'un_acute_malnutrition_tx_start_date'] = pd.NaT + df.at[child_id, 'un_sam_death_date'] = pd.NaT + df.at[child_id, 'un_am_bilateral_oedema'] = False + df.at[child_id, 'un_am_MUAC_category'] = '>=125mm' + df.at[child_id, 'un_am_treatment_type'] = 'not_applicable' def muac_cutoff_by_WHZ(self, idx, whz): """ @@ -705,7 +423,7 @@ def nutritional_oedema_present(self, idx): def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): """ - This fuction will determine the clinical acute malnutrition status (MAM, SAM) based on anthropometric indices + This function will determine the clinical acute malnutrition status (MAM, SAM) based on anthropometric indices and presence of bilateral oedema (Kwashiorkor); And help determine whether the individual will have medical complications, applicable to SAM cases only, requiring inpatient care. @@ -737,7 +455,7 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): # Determine if SAM episode has complications if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM': - if p['prob_complications_in_SAM'] > self.rng.random_sample(): + if self.rng.random_sample() < p['prob_complications_in_SAM']: df.at[person_id, 'un_sam_with_complications'] = True else: df.at[person_id, 'un_sam_with_complications'] = False @@ -814,19 +532,30 @@ def report_daly_values(self): The names of the series of columns is taken to be the label of the cause of this disability. It will be recorded by the healthburden module as _. """ - df = self.sim.population.props + # dict to hold the DALY weights + daly_wts = dict() - total_daly_values = pd.Series(data=0.0, index=df.index[df.is_alive]) - total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & - df.un_am_bilateral_oedema] = self.daly_wts['SAM_with_oedema'] - total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & - (~df.un_am_bilateral_oedema)] = self.daly_wts['SAM_w/o_oedema'] - total_daly_values.loc[df.is_alive & ( - ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | - ((df.un_WHZ_category != 'WHZ<-3') & (df.un_am_MUAC_category != "115-<125mm")) - ) & df.un_am_bilateral_oedema] = self.daly_wts['MAM_with_oedema'] + if 'HealthBurden' in self.sim.modules.keys(): + df = self.sim.population.props + # Get DALY weights + get_daly_weight = self.sim.modules['HealthBurden'].get_daly_weight - return total_daly_values + # self.daly_wts['MAM_w/o_oedema'] = get_daly_weight(sequlae_code=460) ## no value given + daly_wts['MAM_with_oedema'] = get_daly_weight(sequlae_code=461) + daly_wts['SAM_w/o_oedema'] = get_daly_weight(sequlae_code=462) + daly_wts['SAM_with_oedema'] = get_daly_weight(sequlae_code=463) + + total_daly_values = pd.Series(data=0.0, index=df.index[df.is_alive]) + total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & + df.un_am_bilateral_oedema] = daly_wts['SAM_with_oedema'] + total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & + (~df.un_am_bilateral_oedema)] = daly_wts['SAM_w/o_oedema'] + total_daly_values.loc[df.is_alive & ( + ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | + ((df.un_WHZ_category != 'WHZ<-3') & (df.un_am_MUAC_category != "115-<125mm")) + ) & df.un_am_bilateral_oedema] = daly_wts['MAM_with_oedema'] + + return total_daly_values def wasting_clinical_symptoms(self, person_id): """ @@ -853,6 +582,7 @@ def do_when_acute_malnutrition_assessment(self, person_id): :param person_id: :return: """ + df = self.sim.population.props p = self.parameters @@ -863,7 +593,7 @@ def do_when_acute_malnutrition_assessment(self, person_id): # Interventions for MAM if clinical_am == 'MAM': # Check for coverage of supplementary feeding - if p['coverage_supplementary_feeding_program'] > self.rng.random_sample(): + if self.rng.random_sample() < p['coverage_supplementary_feeding_program']: # schedule HSI for supplementary feeding program for MAM self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM @@ -878,7 +608,7 @@ def do_when_acute_malnutrition_assessment(self, person_id): if clinical_am == 'SAM': if not complications: # Check for coverage of outpatient therapeutic care - if p['coverage_outpatient_therapeutic_care'] > self.rng.random_sample(): + if self.rng.random_sample() < p['coverage_outpatient_therapeutic_care']: # schedule HSI for supplementary feeding program for MAM self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_OutpatientTherapeuticProgramme_SAM @@ -892,7 +622,7 @@ def do_when_acute_malnutrition_assessment(self, person_id): # Interventions for complicated SAM if complications: # Check for coverage of outpatient therapeutic care - if p['coverage_inpatient_care'] > self.rng.random_sample(): + if self.rng.random_sample() < p['coverage_inpatient_care']: # schedule HSI for supplementary feeding program for MAM self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_InpatientCareForComplicated_SAM @@ -916,9 +646,10 @@ def do_when_am_treatment(self, person_id, intervention): df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date if intervention == 'SFP': - mam_recovery = self.acute_malnutrition_recovery_based_on_interventions['MAM'].predict( - df.loc[[person_id]]).values[0] - if self.rng.random_sample() < mam_recovery: + mam_recovery = \ + self.wasting_models.get_moderate_acute_malnutrition_recovery().predict(df.loc[[person_id]], self.rng) + + if mam_recovery: # schedule recovery date self.sim.schedule_event( event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), @@ -929,9 +660,9 @@ def do_when_am_treatment(self, person_id, intervention): return if intervention == 'OTC': - sam_recovery = self.acute_malnutrition_recovery_based_on_interventions['SAM'].predict( - df.loc[[person_id]]).values[0] - if self.rng.random_sample() < sam_recovery: + sam_recovery = self.wasting_models.get_severe_acute_malnutrition_recovery().predict( + df.loc[[person_id]], self.rng) + if sam_recovery: # schedule recovery date self.sim.schedule_event( event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), @@ -939,22 +670,22 @@ def do_when_am_treatment(self, person_id, intervention): # cancel death date df.at[person_id, 'un_sam_death_date'] = pd.NaT else: - # remained MAM or death - outcome = self.rng.choice(['remained_mam', 'death'], - p=[0.5, 0.5]) - if outcome == 'remained_mam': - self.sim.schedule_event( - event=UpdateToMAM(module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) + outcome = self.rng.choice(['remained_mam', 'death'], p=[0.32, 0.68]) if outcome == 'death': self.sim.schedule_event( event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person_id), date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) + else: + self.sim.schedule_event( + event=UpdateToMAM(module=self, person_id=person_id), + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) + if intervention == 'ITC': - sam_recovery = self.acute_malnutrition_recovery_based_on_interventions['SAM'].predict( - df.loc[[person_id]]).values[0] - if self.rng.random_sample() < sam_recovery: + sam_recovery = self.wasting_models.get_severe_acute_malnutrition_recovery().predict( + df.loc[[person_id]], self.rng) + + if sam_recovery: # schedule recovery date self.sim.schedule_event( event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), @@ -962,17 +693,15 @@ def do_when_am_treatment(self, person_id, intervention): # cancel death date df.at[person_id, 'un_sam_death_date'] = pd.NaT else: - # remained MAM or death - outcome = self.rng.choice(['remained_mam', 'death'], - p=[0.5, 0.5]) - if outcome == 'remained_mam': - self.sim.schedule_event( - event=UpdateToMAM(module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=4)) + outcome = self.rng.choice(['remained_mam', 'death'], p=[0.32, 0.68]) if outcome == 'death': self.sim.schedule_event( event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person_id), date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=4)) + else: + self.sim.schedule_event( + event=UpdateToMAM(module=self, person_id=person_id), + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=4)) class WastingPollingEvent(RegularEvent, PopulationScopeEventMixin): @@ -1002,31 +731,34 @@ def apply(self, population): # # # # # # # # # # # # # # # # # # # # # INCIDENCE OF WASTING # # # # # # # # # # # # # # # # # # # # # # Determine who will be onset with wasting among those who are not currently wasted ------------- inc_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == 'WHZ>=-2')] - incidence_of_wasting = self.module.wasting_incidence_equation.predict(inc_wasting, rng) + get_incidence_of_wasting = self.module.wasting_models.get_wasting_incidence(inc_wasting) + incidence_of_wasting = rng.random_sample(len(get_incidence_of_wasting)) < get_incidence_of_wasting wasting_idx = inc_wasting.index # update the properties for wasted children df.loc[wasting_idx[incidence_of_wasting], 'un_ever_wasted'] = True df.loc[wasting_idx[incidence_of_wasting], 'un_last_wasting_date_of_onset'] = self.sim.date df.loc[wasting_idx[incidence_of_wasting], 'un_WHZ_category'] = '-3<=WHZ<-2' # start as moderate wasting df.loc[wasting_idx[incidence_of_wasting], 'un_am_treatment_type'] = 'none' # start without treatment - # ------------------------------------------------------------------------------------------- # Add this incident case to the tracker - for person in wasting_idx[incidence_of_wasting]: + for person in wasting_idx: wasting_severity = df.at[person, 'un_WHZ_category'] age_group = WastingPollingEvent.AGE_GROUPS.get(df.loc[person].age_years, '5+y') - if wasting_severity != 'WHZ>=-2': - self.module.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) + # if wasting_severity != 'WHZ>=-2': + self.module.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) + # ------------------------------------------------------------------------------------------- # # # # # # # # # # # # # # # # # # # # # PROGRESS TO SEVERE WASTING # # # # # # # # # # # # # # # # # # # # # # Determine those that will progress to severe wasting ( WHZ<-3) and schedule progression event --------- progression_sev_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == '-3<=WHZ<-2')] - progression_severe_wasting = self.module.severe_wasting_progression_equation.predict(progression_sev_wasting, - rng) + progression_severe_wasting = \ + self.module.wasting_models.get_wasting_progression().predict(progression_sev_wasting, rng) + progression_sev_wasting_idx = progression_sev_wasting.index + # determine those individuals who will progress to severe wasting and time of progression for person in progression_sev_wasting_idx[progression_severe_wasting]: outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') @@ -1117,69 +849,6 @@ def apply(self, person_id): m.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) -class AcuteMalnutritionDeathPollingEvent(RegularEvent, PopulationScopeEventMixin): - """ - Regular event that determines death due to acute malnutrition to the under-5 population, - and schedules individual death events. - It also determines those who will improve nutritional state. - """ - AGE_GROUPS = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} - - def __init__(self, module): - """schedule to run every month - :param module: the module that created this event - """ - self.repeat_months = 1 - super().__init__(module, frequency=DateOffset(months=self.repeat_months)) - assert isinstance(module, Wasting) - - def apply(self, population): - """Apply this event to the population. - :param population: the current population - """ - df = population.props - rng = self.module.rng - - # # # # # # # # # # # # # # # # # # # # # DEATH # # # # # # # # # # # # # # # # # # # # # - - # Determine those that will die ----------------------------------------------- - _to_die = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_clinical_acute_malnutrition != 'well')] - will_die = self.module.sam_death_equation.predict(_to_die, rng) - _to_die_idx = _to_die.index - # schedule death date - for person in _to_die_idx[will_die]: - death_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='SAM') - if death_date <= self.sim.date: - # schedule death for today - self.sim.schedule_event( - event=SevereAcuteMalnutritionDeathEvent(module=self.module, person_id=person), - date=self.sim.date) - - else: - # schedule death according to duration - self.sim.schedule_event( - event=SevereAcuteMalnutritionDeathEvent(module=self.module, person_id=person), - date=death_date) - - # # # # # # # # # # # # # # # # # # # # # IMPROVEMENT FROM SAM TO MAM # # # # # # # # # # # # # # # # # # # # # - # SAM = severe wasting (WHZ<-3) and/or MUAC <115mm, or nutritional oedema - # Those not scheduled to die, will have improved WHZ status by 1sd (-3<=WHZ<-2) - - # schedule improvement to MAM for those not scheduled to die - for person in will_die[~will_die].index: - outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='SAM') - if outcome_date <= self.sim.date: - # schedule improvement to moderate wasting date for today - self.sim.schedule_event( - event=UpdateToMAM(module=self.module, person_id=person), - date=self.sim.date) - if outcome_date > self.sim.date: - # schedule improvement to moderate wasting date according to duration - self.sim.schedule_event( - event=UpdateToMAM(module=self.module, person_id=person), - date=outcome_date) - - class SevereAcuteMalnutritionDeathEvent(Event, IndividualScopeEventMixin): """ This event applies the death function @@ -1195,11 +864,8 @@ def apply(self, person_id): if not df.at[person_id, 'is_alive']: return - if df.at[person_id, 'un_acute_malnutrition_tx_start_date'] < self.sim.date: - return - - # Check if this person should still die from SAM: - if pd.isnull(df.at[person_id, 'un_am_recovery_date']) &\ + # # Check if this person should still die from SAM: + if pd.isnull(df.at[person_id, 'un_am_recovery_date']) & \ (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM'): # Cause the death to happen immediately df.at[person_id, 'un_sam_death_date'] = self.sim.date @@ -1237,8 +903,7 @@ def apply(self, person_id): # update the clinical acute malnutrition state m.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) - - if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well': + if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': # this will clear all wasting symptoms self.sim.modules["SymptomManager"].clear_symptoms( person_id=person_id, disease_module=self.module @@ -1350,7 +1015,6 @@ def __init__(self, module, person_id): self.ALERT_OTHER_DISEASES = [] def apply(self, person_id, squeeze_factor): - df = self.sim.population.props # Stop the person from dying of acute malnutrition (if they were going to die) @@ -1401,7 +1065,6 @@ def __init__(self, module, person_id): self.ALERT_OTHER_DISEASES = [] def apply(self, person_id, squeeze_factor): - df = self.sim.population.props # Stop the person from dying of acute malnutrition (if they were going to die) @@ -1456,7 +1119,6 @@ def __init__(self, module, person_id): self.BEDDAYS_FOOTPRINT = self.make_beddays_footprint({'general_bed': 7}) def apply(self, person_id, squeeze_factor): - df = self.sim.population.props # Stop the person from dying of acute malnutrition (if they were going to die) @@ -1490,6 +1152,214 @@ def did_not_run(self): pass +class WastingModels: + """ houses all wasting linear models """ + + def __init__(self, module): + self.module = module + self.params = module.parameters + self.rng = module.rng + + # linear model to predict the incidence of wasting + self.__Wasting_Incidence = LinearModel.multiplicative( + Predictor('age_exact_years').when('<0.5', self.params['base_inc_rate_wasting_by_agegp'][0]) + .when('<1.0', self.params['base_inc_rate_wasting_by_agegp'][1]) + .when('.between(1,1.9999)', self.params['base_inc_rate_wasting_by_agegp'][2]) + .when('.between(2,2.9999)', self.params['base_inc_rate_wasting_by_agegp'][3]) + .when('.between(3,3.9999)', self.params['base_inc_rate_wasting_by_agegp'][4]) + .when('.between(4,4.9999)', self.params['base_inc_rate_wasting_by_agegp'][5]) + .otherwise(0.0), + Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == False) & (nb_early_preterm == False)', + self.params['rr_wasting_SGA_and_term']), + Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + self.params['rr_wasting_SGA_and_preterm']), + Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") ' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + self.params['rr_wasting_preterm_and_AGA']), + Predictor('li_wealth').apply( + lambda x: 1 if x == 1 else (x - 1) ** (self.params['rr_wasting_wealth_level'])), + ) + + # a linear model to predict the probability of individual's recovery from moderate acute malnutrition + self.__Acute_Malnutrition_Recovery_MAM = LinearModel.multiplicative( + Predictor('un_am_treatment_type').when('soy_RUSF', self.params['recovery_rate_with_soy_RUSF']) + .when('CSB++', self.params['recovery_rate_with_CSB++']) + .otherwise(0.0), + ) + + # a linear model to predict the probability of individual's recovery from severe acute malnutrition + self.__Acute_Malnutrition_Recovery_SAM = LinearModel.multiplicative( + Predictor('un_am_treatment_type') + .when('standard_RUTF', self.params['recovery_rate_with_standard_RUTF']) + .when('inpatient_care', self.params['recovery_rate_with_inpatient_care']) + .otherwise(0.0), + ) + + # Linear model for the probability of progression to severe wasting (age-dependent only) + # (natural history only, no interventions) + self.__Severe_Wasting_Progression = LinearModel.multiplicative( + Predictor('age_exact_years') + .when('<0.5', self.params['progression_severe_wasting_by_agegp'][0]) + .when('.between(0.5,0.9999)', self.params['progression_severe_wasting_by_agegp'][1]) + .when('.between(1,1.9999)', self.params['progression_severe_wasting_by_agegp'][2]) + .when('.between(2,2.9999)', self.params['progression_severe_wasting_by_agegp'][3]) + .when('.between(3,3.9999)', self.params['progression_severe_wasting_by_agegp'][4]) + .when('.between(4,4.9999)', self.params['progression_severe_wasting_by_agegp'][5]) + .otherwise(0.0), + ) + + self.__SAM_Death = LinearModel.multiplicative( + Predictor('un_am_treatment_type').when('none', self.params['base_death_rate_untreated_SAM']), + Predictor('un_sam_with_complications').when(True, + self.params['rr_SAM_death_with_complications']), + Predictor().when('(un_am_bilateral_oedema == False) & ' + '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "115-<125mm")', + self.params['rr_SAM_death_WHZ<-3_only']), + Predictor().when('(un_am_bilateral_oedema == False) & ' + '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "<115mm")', + self.params['rr_SAM_death_both_WHZ<-3_&_MUAC<115mm']), + Predictor().when('(un_am_bilateral_oedema == True) & ' + '(un_WHZ_category == "-3<=WHZ<-2") & (un_am_MUAC_category == "<115mm")', + self.params['rr_SAM_death_kwashiorkor_only']), + Predictor().when('(un_am_bilateral_oedema == True) & ' + '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "115-<125mm")', + self.params['rr_SAM_death_kwashiorkor_WHZ<-3_only']), + Predictor().when('(un_am_bilateral_oedema == True) & ' + '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "<115mm")', + self.params['rr_SAM_death_kwashiorkor_both_WHZ<-3_&_MUAC<115mm']), + Predictor().when('(un_am_bilateral_oedema == True) & ' + '(un_WHZ_category == "-3<=WHZ<-2") & (un_am_MUAC_category == "<115mm")', + self.params['rr_SAM_death_kwashiorkor_MUAC<115mm_only']), + ) + + def get_wasting_incidence(self, df) -> pd.Series: + """ predict the incidence of wasting amongst young children + :params df: population dataframe """ + unscaled_lm = self.__Wasting_Incidence + target_mean = self.params['base_inc_rate_wasting_by_agegp'][2] + actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1) & + (df.un_WHZ_category == 'WHZ>=-2')]).mean() + + scaled_intercept = 1.0 * (target_mean / actual_mean) \ + if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else 1.0 + scaled_lm = unscaled_lm.predict(df) + return scaled_lm.apply(lambda row: row * scaled_intercept) + + def get_wasting_prevalence(self): + """ predict wasting prevalence amongst young children less than 5 years + :params df: population dataframe + """ + # linear model to predict the prevalence of wasting + wasting_prevalence = LinearModel( + LinearModelType.LOGISTIC, + 1.0, + Predictor('agrp', external=True) + .when('0_5mo', self.module.wasting_prevalence_odds_by_age_grp['0_5mo']) + .when('6_11mo', self.module.wasting_prevalence_odds_by_age_grp['6_11mo']) + .when('12_23mo', self.module.wasting_prevalence_odds_by_age_grp['12_23mo']) + .when('24_35mo', self.module.wasting_prevalence_odds_by_age_grp['24_35mo']) + .when('36_47mo', self.module.wasting_prevalence_odds_by_age_grp['36_47mo']) + .when('48_59mo', self.module.wasting_prevalence_odds_by_age_grp['48_59mo']) + .otherwise(1.0), + + Predictor('agrp_scaling', external=True) + .when('0_5mo', self.module.age_grps_dict['0_5mo']) + .when('6_11mo', self.module.age_grps_dict['6_11mo']) + .when('12_23mo', self.module.age_grps_dict['12_23mo']) + .when('24_35mo', self.module.age_grps_dict['24_35mo']) + .when('36_47mo', self.module.age_grps_dict['36_47mo']) + .when('48_59mo', self.module.age_grps_dict['48_59mo']) + .otherwise(1.0), + + Predictor('li_wealth').when(2, self.params['or_wasting_hhwealth_Q2']) + .when(3, self.params['or_wasting_hhwealth_Q3']) + .when(4, self.params['or_wasting_hhwealth_Q4']) + .when(5, self.params['or_wasting_hhwealth_Q5']) + .otherwise(1.0), + Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == False) & (nb_early_preterm == False)', + self.params['or_wasting_SGA_and_term']), + Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + self.params['or_wasting_SGA_and_preterm']), + Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") ' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + self.params['or_wasting_preterm_and_AGA']) + ) + + return wasting_prevalence + + def get_moderate_acute_malnutrition_recovery(self): + """ predict moderate acute malnutrition recovery amongst young children less than 5 years + :params df: population dataframe + """ + return self.__Acute_Malnutrition_Recovery_MAM + + def get_severe_acute_malnutrition_recovery(self): + """ predict severe acute malnutrition recovery amongst young children less than 5 years + :params df: population dataframe + """ + return self.__Acute_Malnutrition_Recovery_SAM + + def get_wasting_progression(self): + """ predict wasting progression amongst young children less than 5 years + :params df: population dataframe + """ + return self.__Severe_Wasting_Progression + + def get_sam_deaths(self, df) -> pd.Series: + """ predict severe acute malnutrition deaths amongst young children less than 5 years + :params df: population dataframe + """ + pop = self.module.sim.population.props + pop_wanted = pop.loc[pop.is_alive & pop.age_exact_years.between(0.5, 5, inclusive='neither') & + (pop.un_clinical_acute_malnutrition == 'SAM')] + + unscaled_lm = self.__SAM_Death + target_mean = self.params['base_death_rate_untreated_SAM'] + actual_mean = unscaled_lm.predict(pop_wanted).mean() + scaled_intercept = 1.0 * (target_mean / actual_mean) \ + if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else 1.0 + scaled_lm = self.__SAM_Death.predict(df) + + return scaled_lm.apply(lambda row: row * scaled_intercept) + + def get_age_grps_odds(self): + """ Return odds determined by age groups. This will be applied in wasting prevalence linear model """ + for agegp in self.module.age_grps_dict.keys(): + mean, stdev = self.params[f'prev_WHZ_distribution_age_{agegp}'] + whz_normal_distribution = norm(loc=mean, scale=stdev) + # get all wasting: WHZ <-2 + probability_less_than_minus2sd = 1 - whz_normal_distribution.sf(-2) + # convert probability to odds and update odds by age group dictionary + self.module.wasting_prevalence_odds_by_age_grp[agegp] = \ + probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) + + # get severe wasting zcores: WHZ <-3 + probability_less_than_minus3sd = 1 - whz_normal_distribution.sf(-3) + # make WHZ <-2 as the 100% and get the adjusted probability of severe wasting within overall wasting + self.module.age_grps_sev_wasting_probs[ + agegp] = probability_less_than_minus3sd * probability_less_than_minus2sd + + def get_wasting_prevalence_scaling(self, df): + """ get values for scaling wasting prevalence linear model + :params df: population dataframe """ + # initialise wasting prevalence linear model + wasting_prevalence = self.get_wasting_prevalence() + # index the age groups dictionary + for agegp in self.module.age_grps_dict.keys(): + target_mean = self.module.wasting_prevalence_odds_by_age_grp['12_23mo'] + actual_mean = wasting_prevalence.predict(df.loc[df.is_alive & (df.age_years == 1)], + agrp=agegp, agrp_scaling='None').mean() + # update and return age groups dictionary + self.module.age_grps_dict[agegp] = \ + self.module.wasting_prevalence_odds_by_age_grp[agegp] * (target_mean / actual_mean) \ + if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) \ + else self.module.wasting_prevalence_odds_by_age_grp[agegp] + + class WastingLoggingEvent(RegularEvent, PopulationScopeEventMixin): """ This Event logs the number of incident cases that have occurred since the previous logging event. @@ -1506,20 +1376,16 @@ def apply(self, population): df = self.sim.population.props # Convert the list of timestamps into a number of timestamps # and check that all the dates have occurred since self.date_last_run - counts_am = self.module.wasting_incident_case_tracker_zeros - + inc_df = pd.DataFrame(index=self.module.wasting_incident_case_tracker.keys(), + columns=self.module.wasting_states) for age_grp in self.module.wasting_incident_case_tracker.keys(): for state in self.module.wasting_states: - list_of_times = self.module.wasting_incident_case_tracker[age_grp][state] - counts_am[age_grp][state] = len(list_of_times) - for t in list_of_times: - assert self.date_last_run <= t <= self.sim.date + inc_df.loc[age_grp, state] = len(self.module.wasting_incident_case_tracker[age_grp][state]) - logger.info(key='wasting_incidence_count', data=counts_am) + logger.info(key='wasting_incidence_count', data=inc_df.to_dict()) # Reset the counters and the date_last_run - self.module.wasting_incident_case_tracker = self.module.wasting_incident_case_tracker_blank - + self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) self.date_last_run = self.sim.date # Wasting totals (prevalence at logging time) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 94fefb7b42..2468da3a1a 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -5,6 +5,7 @@ from pathlib import Path import pandas as pd +import pytest from tlo import Date, Simulation, logging from tlo.lm import LinearModel, LinearModelType @@ -14,19 +15,18 @@ healthburden, healthseekingbehaviour, healthsystem, + hsi_generic_first_appts, simplified_births, symptommanager, wasting, ) +from tlo.methods.healthseekingbehaviour import HealthSeekingBehaviourPoll from tlo.methods.wasting import ( - AcuteMalnutritionDeathPollingEvent, ClinicalAcuteMalnutritionRecoveryEvent, HSI_Wasting_InpatientCareForComplicated_SAM, HSI_Wasting_OutpatientTherapeuticProgramme_SAM, - HSI_Wasting_SupplementaryFeedingProgramme_MAM, ProgressionSevereWastingEvent, SevereAcuteMalnutritionDeathEvent, - UpdateToMAM, WastingNaturalRecoveryEvent, WastingPollingEvent, ) @@ -36,7 +36,7 @@ # Default date for the start of simulations start_date = Date(2010, 1, 1) -end_date = Date(2011, 1, 2) +end_date = Date(2011, 1, 1) def get_sim(tmpdir): @@ -51,7 +51,9 @@ def get_sim(tmpdir): sim.register(demography.Demography(resourcefilepath=resourcefilepath), enhanced_lifestyle.Lifestyle(resourcefilepath=resourcefilepath), - healthsystem.HealthSystem(resourcefilepath=resourcefilepath, disable=True), + healthsystem.HealthSystem(resourcefilepath=resourcefilepath, + disable=False, + cons_availability='all'), symptommanager.SymptomManager(resourcefilepath=resourcefilepath), healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resourcefilepath), healthburden.HealthBurden(resourcefilepath=resourcefilepath), @@ -70,42 +72,17 @@ def check_dtypes(sim): def check_configuration_of_properties(sim): # check that the properties are ok: - df = sim.population.props # Those that were never wasted, should have normal WHZ score: - assert (df.loc[~df.un_ever_wasted & ~df.date_of_birth.isna(), 'un_WHZ_category'] == 'WHZ>=-2').all().all() - - # Those that were never wasted and not clinically malnourished, - # should have not_applicable/null values for all the other properties: - # assert pd.isnull(df.loc[(~df.un_ever_wasted & ~df.date_of_birth.isna() & - # (df.un_clinical_acute_malnutrition == 'well')), - # ['un_last_wasting_date_of_onset', - # 'un_sam_death_date' - # ] - # ]).all().all() - - # # Those that were ever wasted, should have a WHZ score below <-2 - # assert (df.loc[df.un_ever_wasted, 'un_WHZ_category'] != 'WHZ>=-2').all().all() - # - # # Those that had wasting and no treatment, should have either a recovery date or a death_date - # # (but not both) - # has_recovery_date = ~pd.isnull(df.loc[df.un_ever_wasted & pd.isnull(df.un_acute_malnutrition_tx_start_date), - # 'un_am_recovery_date']) - # has_death_date = ~pd.isnull(df.loc[df.un_ever_wasted & pd.isnull(df.un_acute_malnutrition_tx_start_date), - # 'un_sam_death_date']) - - # has_recovery_date_or_death_date = has_recovery_date | has_death_date - # has_both_recovery_date_and_death_date = has_recovery_date & has_death_date - # # assert has_recovery_date_or_death_date.all() - # assert not has_both_recovery_date_and_death_date.any() + assert (df.loc[~df.un_ever_wasted & ~df.date_of_birth.isna(), 'un_WHZ_category'] == 'WHZ>=-2').all() # Those for whom the death date has past should be dead assert not df.loc[df.un_ever_wasted & (df['un_sam_death_date'] < sim.date), 'is_alive'].any() assert not df.loc[(df.un_clinical_acute_malnutrition == 'SAM') & ( df['un_sam_death_date'] < sim.date), 'is_alive'].any() - # Check that those in a current episode have symptoms of diarrhoea [caused by the diarrhoea module] + # Check that those in a current episode have symptoms of wasting [caused by the wasting module] # but not others (among those who are alive) has_symptoms_of_wasting = set(sim.modules['SymptomManager'].who_has('weight_loss')) has_symptoms = set([p for p in has_symptoms_of_wasting if @@ -130,34 +107,34 @@ def check_configuration_of_properties(sim): in_current_episode_before_death[in_current_episode_before_death].index ) - in_current_episode_before_cure = \ - df.is_alive & \ - df.un_ever_wasted & \ - (df.un_last_wasting_date_of_onset <= sim.date) & \ - (df.un_acute_malnutrition_tx_start_date <= sim.date) & \ - pd.isnull(df.un_am_recovery_date) & \ - pd.isnull(df.un_sam_death_date) - set_of_person_id_in_current_episode_before_cure = set( - in_current_episode_before_cure[in_current_episode_before_cure].index - ) - assert set() == set_of_person_id_in_current_episode_before_recovery.intersection( set_of_person_id_in_current_episode_before_death ) - set_of_person_id_in_current_episode = set_of_person_id_in_current_episode_before_recovery.union( - set_of_person_id_in_current_episode_before_death, set_of_person_id_in_current_episode_before_cure - ) - assert set_of_person_id_in_current_episode == has_symptoms + # WHZ standard deviation of -3, oedema, and MUAC <115mm should cause severe acute malnutrition + whz_index = df.index[df['un_WHZ_category'] == 'WHZ<-3'] + oedema_index = df.index[df['un_am_bilateral_oedema']] + muac_index = df.index[df['un_am_MUAC_category'] == '<115mm'] + assert (df.loc[whz_index, 'un_clinical_acute_malnutrition'] == "SAM").all() + assert (df.loc[oedema_index, 'un_clinical_acute_malnutrition'] == "SAM").all() + assert (df.loc[muac_index, 'un_clinical_acute_malnutrition'] == "SAM").all() + + # all SAM individuals should have symptoms of wasting + assert set(df.index[df.is_alive & (df.age_exact_years < 5) & + (df.un_clinical_acute_malnutrition == 'SAM')]).issubset(has_symptoms) + + # All MAM individuals should have no symptoms of wasting + assert not set(df.index[df.is_alive & (df.age_exact_years < 5) & + (df.un_clinical_acute_malnutrition == 'MAM')]) in has_symptoms +@pytest.mark.slow def test_basic_run(tmpdir): """Short run of the module using default parameters with check on dtypes""" - dur = pd.DateOffset(months=3) - popsize = 1000 + popsize = 10_000 sim = get_sim(tmpdir) sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) + sim.simulate(end_date=end_date) check_dtypes(sim) check_configuration_of_properties(sim) @@ -171,9 +148,11 @@ def test_wasting_polling(tmpdir): # Make incidence of wasting very high : params = sim.modules['Wasting'].parameters - for p in params: - if p.startswith('base_inc_rate_wasting_by_agegp'): - params[p] = [3 * v for v in params[p]] + params['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + params['progression_severe_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + + # re-initialise wasting linear models to use the updated parameter + sim.modules['Wasting'].pre_initialise_population() sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) @@ -182,6 +161,7 @@ def test_wasting_polling(tmpdir): # Run polling event: check that a severe incident case is produced: polling = WastingPollingEvent(sim.modules['Wasting']) polling.apply(sim.population) + assert len([q for q in sim.event_queue.queue if isinstance(q[3], ProgressionSevereWastingEvent)]) > 0 # Check properties of this individual: should now be moderately wasted @@ -195,7 +175,7 @@ def test_wasting_polling(tmpdir): def test_recovery_moderate_wasting(tmpdir): - """Check natual recovery of moderate wasting """ + """Check natural recovery of moderate wasting """ dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) @@ -204,24 +184,21 @@ def test_recovery_moderate_wasting(tmpdir): sim.simulate(end_date=start_date + dur) sim.event_queue.queue = [] # clear the queue - # Make 0% death rate by replacing with empty linear model 0.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 0.0) - - # increase incidence of wasting - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # remove progression to severe wasting - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 0.0) - # Get person to use: df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + # get wasting module + wmodule = sim.modules['Wasting'] + # increase wasting incidence rate to 100% for all age groups(less than 5 years) + wmodule.parameters['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + wmodule.parameters['progression_severe_wasting_by_agegp'] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + + # re-initialise wasting linear models to use the updated parameter + wmodule.pre_initialise_population() + # Run Wasting Polling event to get new incident cases: polling = WastingPollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) @@ -254,7 +231,7 @@ def test_recovery_moderate_wasting(tmpdir): assert pd.isnull(person['un_sam_death_date']) -def test_recovery_severe_wasting(tmpdir): +def test_recovery_severe_wasting_without_complications(tmpdir): """ Check natural recovery to MAM by removing death rate for those with severe wasting, and check the onset of symptoms with SAM and revolving of symptoms when recovered to MAM """ dur = pd.DateOffset(days=0) @@ -265,22 +242,21 @@ def test_recovery_severe_wasting(tmpdir): sim.simulate(end_date=start_date + dur) sim.event_queue.queue = [] # clear the queue - # Make 0% death rate by replacing with empty linear model 0.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 0.0) - - # increase incidence of wasting and progression to severe - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - # Get person to use: df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + # get wasting module + wmodule = sim.modules['Wasting'] + # increase wasting incidence rate to 100% for all age groups(less than 5 years) + wmodule.parameters['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + wmodule.parameters['progression_severe_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + + # re-initialise wasting linear models to use the updated parameter + wmodule.pre_initialise_population() + # Run Wasting Polling event to get new incident cases: polling = WastingPollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) @@ -306,7 +282,7 @@ def test_recovery_severe_wasting(tmpdir): sim.date = date_of_scheduled_progression progression_event.apply(person_id=person_id) - # Check that they have some symptoms caused by Wasting (SAM only) + # Check individuals have symptoms caused by Wasting (SAM only) assert 0 < len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) # Check properties of this individual: (should now be severely wasted and without a scheduled death date) @@ -318,27 +294,142 @@ def test_recovery_severe_wasting(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Run Death Polling event to apply death: - death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) - death_polling.apply(sim.population) - - # Check that there is a UpdateToMAM scheduled for this person: - recovery_to_mam_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], UpdateToMAM) - ][0] - print(sim.find_events_for_person(person_id)) - date_of_scheduled_recovery_to_mam = recovery_to_mam_event_tuple[0] - recovery_to_mam_event = recovery_to_mam_event_tuple[1] + hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) + hsp.run() + + # check non-emergency care event is scheduled + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + + # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought + ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] + ge.run(squeeze_factor=0.0) + + # check HSI event is scheduled + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + + # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] + sam_ev.run(squeeze_factor=0.0) + + # check recovery event is scheduled + assert isinstance(sim.find_events_for_person(person_id)[1][1], ClinicalAcuteMalnutritionRecoveryEvent) + + # Run the recovery event and check the individual has recovered from SAM: + sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent) + ][0] + + date_of_scheduled_recovery_to_mam = sam_recovery_event_tuple[0] + sam_recovery_event = sam_recovery_event_tuple[1] assert date_of_scheduled_recovery_to_mam > sim.date - # Run a Recovery SAM to MAM Event + # Run SAM recovery sim.date = date_of_scheduled_recovery_to_mam - recovery_to_mam_event.apply(person_id=person_id) + sam_recovery_event.apply(person_id=person_id) # Check properties of this individual person = df.loc[person_id] - assert person['un_WHZ_category'] != 'WHZ<-3' - assert (person['un_am_MUAC_category'] == '115-<125mm' or person['un_WHZ_category'] == '-3<=WHZ<-2') + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert (person['un_am_MUAC_category'] == '>=125mm') + assert pd.isnull(person['un_sam_death_date']) + + # check they have no symptoms: + assert 0 == len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) + + +def test_recovery_severe_wasting_with_complications(tmpdir): + """ test individual's recovery from wasting with complications """ + dur = pd.DateOffset(days=3) + popsize = 1000 + sim = get_sim(tmpdir) + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + + # get wasting module + wmodule = sim.modules['Wasting'] + + # Manually set this individual properties to have severe acute malnutrition with complications + df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' + + # make the individual have wasting complications + wmodule.parameters['prob_complications_in_SAM'] = 1.0 + + # assign diagnosis + wmodule.clinical_acute_malnutrition_state(person_id, df) + + # apply symptoms + wmodule.wasting_clinical_symptoms(person_id) + + # by having severe wasting, this individual should be diagnosed as SAM + assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' + + # symptoms should be applied + assert person_id in set(sim.modules['SymptomManager'].who_has('weight_loss')) + + # should have complications + assert df.at[person_id, 'un_sam_with_complications'] + + # make recovery rate to 100% and death rate to zero so that this individual should recover + wasting_module = sim.modules['Wasting'] + wasting_module.parameters['recovery_rate_with_inpatient_care'] = 1.0 + wasting_module.parameters['base_death_rate_untreated_SAM'] = 0.0 + + # re-initialise wasting models + wasting_module.pre_initialise_population() + + # run care seeking event and ensure HSI for complicated SAM is scheduled + hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) + hsp.run() + + # check non-emergency care event is scheduled + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + + # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought + ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] + ge.run(squeeze_factor=0.0) + + # check HSI event for complicated SAM is scheduled + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + HSI_Wasting_InpatientCareForComplicated_SAM) + + # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], HSI_Wasting_InpatientCareForComplicated_SAM)][0] + sam_ev.run(squeeze_factor=0.0) + + # check recovery event is scheduled + assert isinstance(sim.find_events_for_person(person_id)[0][1], ClinicalAcuteMalnutritionRecoveryEvent) + + # Run the recovery event and check the individual has recovered from SAM: + sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent) + ][0] + + date_of_scheduled_recovery_to_mam = sam_recovery_event_tuple[0] + sam_recovery_event = sam_recovery_event_tuple[1] + assert date_of_scheduled_recovery_to_mam > sim.date + + # Run SAM recovery + sim.date = date_of_scheduled_recovery_to_mam + sam_recovery_event.apply(person_id=person_id) + + # Check properties of this individual + person = df.loc[person_id] + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert (person['un_am_MUAC_category'] == '>=125mm') assert pd.isnull(person['un_sam_death_date']) # check they have no symptoms: @@ -356,69 +447,68 @@ def test_nat_hist_death(tmpdir): sim.simulate(end_date=start_date + dur) sim.event_queue.queue = [] # clear the queue + # get wasting module + wasting_module = sim.modules['Wasting'] # Make 100% death rate by replacing with empty linear model 1.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # increase incidence of wasting and progression to severe - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( + wasting_module.sam_death_equation = LinearModel( LinearModelType.MULTIPLICATIVE, 1.0) # Get the children to use: df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' - # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) - polling.apply(sim.population) + # re-set parameter values to make zero recovery rate and 100% death rate + wasting_module.parameters['recovery_rate_with_standard_RUTF'] = 0.0 + wasting_module.parameters['recovery_rate_with_inpatient_care'] = 0.0 + wasting_module.parameters['base_death_rate_untreated_SAM'] = 1.0 - # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) + # re-initialise wasting models + wasting_module.pre_initialise_population() - # Check that there is a ProgressionSevereWastingEvent scheduled for this person: - progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ProgressionSevereWastingEvent) - ][0] - date_of_scheduled_progression = progression_event_tuple[0] - progression_event = progression_event_tuple[1] - assert date_of_scheduled_progression > sim.date + # make an individual diagnosed as SAM by WHZ category. We want to make this individual qualify for death + df.loc[person_id, 'un_ever_wasted'] = True + df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' + df.loc[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' - # Run the progression to severe wasting event: - sim.date = date_of_scheduled_progression - progression_event.apply(person_id=person_id) + # apply wasting symptoms to this individual + wasting_module.wasting_clinical_symptoms(person_id) - # Check properties of this individual: (should now be severely wasted and without a scheduled death date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == 'WHZ<-3' - assert person['un_clinical_acute_malnutrition'] == 'SAM' - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) + # check symptoms are applied + assert person_id in set(sim.modules['SymptomManager'].who_has('weight_loss')) + + # run health seeking behavior and ensure non-emergency event is scheduled + hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) + hsp.run() + + # check non-emergency care event is scheduled + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + + # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought + ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] + ge.run(squeeze_factor=0.0) + + # check inpatient care event is scheduled + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + HSI_Wasting_OutpatientTherapeuticProgramme_SAM) - # Run Death Polling Polling event to apply death: - death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) - death_polling.apply(sim.population) + # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] + sam_ev.run(squeeze_factor=0.0) - # Check that there is a SevereAcuteMalnutritionDeathEvent scheduled for this person: + # since there is zero recovery rate, check death event is scheduled + assert isinstance(sim.find_events_for_person(person_id)[0][1], SevereAcuteMalnutritionDeathEvent) + + # # Run the acute death event and ensure the person is now dead: death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) ][0] date_of_scheduled_death = death_event_tuple[0] death_event = death_event_tuple[1] assert date_of_scheduled_death > sim.date - - # Run the death event: sim.date = date_of_scheduled_death death_event.apply(person_id=person_id) @@ -444,14 +534,12 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): # Make 0% death rate by replacing with empty linear model 0.0 sim.modules['Wasting'].sam_death_equation = LinearModel( LinearModelType.MULTIPLICATIVE, 0.0) + wasting_module = sim.modules['Wasting'] - # increase incidence of wasting - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # decrease progression to severe of wasting - so all children stay in moderate wasting state only - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 0.0) + # increase wasting incidence rate to 100% and reduce rate of progress to severe wasting to zero. + # Wwe don't want individuals to progress to SAM as we are testing for MAM natural recovery + wasting_module.parameters['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + wasting_module.parameters['progression_severe_wasting_by_agegp'] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] # Get person to use: df = sim.population.props @@ -472,8 +560,6 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - print(sim.find_events_for_person(person_id)) - # Check that there is a WastingNaturalRecoveryEvent scheduled for this person: recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if isinstance(event_tuple[1], WastingNaturalRecoveryEvent) @@ -504,7 +590,7 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): def test_nat_hist_cure_if_death_scheduled(tmpdir): - """Show that if a cure event is run before when a person was going to die, it cause the episode to end without + """Show that if a cure event is run before when a person was going to die, it causes the episode to end without the person dying.""" dur = pd.DateOffset(days=0) @@ -515,21 +601,25 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): sim.simulate(end_date=start_date + dur) sim.event_queue.queue = [] # clear the queue - # Make 100% death rate by replacing with empty linear model 1.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) + # get wasting module parameters + params = sim.modules['Wasting'].parameters + # increase to 100% death rate, incidence and progress to severe wasting + params['base_death_rate_untreated_SAM'] = 1.0 + params['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + params['progression_severe_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + # reduce to 100% recovery rate. This is to ensure death event is scheduled for the individual each time we run this + # test + params['recovery_rate_with_standard_RUTF'] = 0.0 + params['recovery_rate_with_inpatient_care'] = 0.0 - # increase incidence of wasting and progression to severe - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) # increase parameters in moderate wasting for clinical SAM (MUAC and oedema) to be polled for death - params = sim.modules['Wasting'].parameters params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = [5 * params['proportion_-3<=WHZ<-2_with_MUAC<115mm']] params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] = [params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] / 5] params['proportion_oedema_with_WHZ<-2'] = 0.9 + # re-initialise wasting models + sim.modules['Wasting'].pre_initialise_population() + # Get person to use: df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] @@ -570,11 +660,32 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Run Death Polling Polling event to apply death: - death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) - death_polling.apply(sim.population) + # run health seeking behavior and ensure non-emergency event is scheduled + hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) + hsp.run() + + # check non-emergency care event is scheduled + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + + # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought + ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] + ge.run(squeeze_factor=0.0) + + # check inpatient care event is scheduled + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + HSI_Wasting_OutpatientTherapeuticProgramme_SAM) - # Check that there is a SevereAcuteMalnutritionDeathEvent scheduled for this person: + # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] + sam_ev.run(squeeze_factor=0.0) + + # since there is zero recovery rate, check death event is scheduled + assert isinstance(sim.find_events_for_person(person_id)[1][1], SevereAcuteMalnutritionDeathEvent) + + # Run Severe Acute Malnutrition Death Event scheduled for this person: death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) ][0] @@ -598,326 +709,3 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): death_event.apply(person_id=person_id) person = df.loc[person_id] assert person['is_alive'] - - -def test_treatment(tmpdir): - """ Test that providing a treatment prevent death and causes there to be a - CureEvent (ClinicalAcuteMalnutritionRecoveryEvent) Scheduled """ - """ - This test sets the linear model of acute_malnutrition_recovery_based_on_interventions to be 1.0 (100% cure rate), - when this lm is called in the do_when_am_treatment function (usually called in HSIs), 100% cure rate schedules the - ClinicalAcuteMalnutritionRecoveryEvent (CureEvent). - Death is prevented. ---> check - """ - # TODO: CHECK THIS - MAYBE NOT NEEDED - - dur = pd.DateOffset(days=0) - popsize = 1000 - sim = get_sim(tmpdir) - - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - - # Make 100% death rate by replacing with empty linear model 1.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # increase incidence of wasting and progression to severe - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # increase parameters in moderate wasting for clinical SAM (MUAC and oedema) to be polled for death - params = sim.modules['Wasting'].parameters - params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = [5 * params['proportion_-3<=WHZ<-2_with_MUAC<115mm']] - params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] = [params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] / 5] - params['proportion_oedema_with_WHZ<-2'] = 0.9 - - # Get person to use: - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' - - # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) - polling.apply(sim.population) - - # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Check that there is a ProgressionSevereWastingEvent scheduled for this person: - progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ProgressionSevereWastingEvent) - ][0] - date_of_scheduled_progression = progression_event_tuple[0] - progression_event = progression_event_tuple[1] - assert date_of_scheduled_progression > sim.date - - # Run the progression to severe wasting event: - sim.date = date_of_scheduled_progression - progression_event.apply(person_id=person_id) - - # Check properties of this individual: (should now be severely wasted and without a scheduled death date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == 'WHZ<-3' - assert person['un_clinical_acute_malnutrition'] == 'SAM' - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Run Death Polling event to apply death: - death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) - death_polling.apply(sim.population) - - # Check that there is a SevereAcuteMalnutritionDeathEvent scheduled for this person: - death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) - ][0] - date_of_scheduled_death = death_event_tuple[0] - death_event = death_event_tuple[1] - assert date_of_scheduled_death > sim.date - - # # change coverage and treatment effectiveness set to be 100% - # params['coverage_supplementary_feeding_program'] = 1.0 - # params['coverage_outpatient_therapeutic_care'] = 1.0 - # params['coverage_inpatient_care'] = 1.0 - # params['recovery_rate_with_soy_RUSF'] = 1.0 - # params['recovery_rate_with_CSB++'] = 1.0 - # params['recovery_rate_with_standard_RUTF'] = 1.0 - # params['recovery_rate_with_inpatient_care'] = 1.0 - - # Make 100% death rate by replacing with empty linear model 1.0 - for am in ['MAM', 'SAM']: - sim.modules['Wasting'].acute_malnutrition_recovery_based_on_interventions[am] = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # Run the 'do_when_am_treatment' function - interventions = ['SFP', 'OTC', 'ITC'] - for int in interventions: - sim.modules['Wasting'].do_when_am_treatment(person_id=person_id, intervention=int) - - # Run the death event that was originally scheduled - this should have no effect and the person should not die - sim.date = date_of_scheduled_death - death_event.apply(person_id=person_id) - person = df.loc[person_id] - assert person['is_alive'] - - # print(sim.find_events_for_person(person_id)) - - # Check that a CureEvent has been scheduled - cure_event = [event_tuple[1] for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] - - # Run the CureEvent - cure_event.apply(person_id=person_id) - - # Check that the person is not infected and is alive still: - person = df.loc[person_id] - assert person['is_alive'] - assert person['un_WHZ_category'] == 'WHZ>=-2' - assert not pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - -def test_use_of_HSI_for_MAM(tmpdir): - """ Check that the HSIs works""" - dur = pd.DateOffset(days=0) - popsize = 1000 - sim = get_sim(tmpdir) - - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - - # Make 100% death rate by replacing with empty linear model 1.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # increase incidence of wasting - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # reduce progression to severe wasting - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 0.0) - - # decrease MUAC and oedema parameters in moderate wasting for clinical SAM - params = sim.modules['Wasting'].parameters - params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = 0.0 # no SAM with moderate wasting - params['proportion_oedema_with_WHZ<-2'] = 0.0 # no SAM based on oedema - params['prevalence_nutritional_oedema'] = 0.0 # no SAM based on oedema - - # Get person to use: - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' - - # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) - polling.apply(sim.population) - - # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_clinical_acute_malnutrition'] == 'MAM' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - # Check not on treatment: - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - - # Run the HSI event - hsi = HSI_Wasting_SupplementaryFeedingProgramme_MAM(person_id=person_id, module=sim.modules['Wasting']) - hsi.run(squeeze_factor=0.0) - - # Check that person is now on treatment: - assert sim.date == df.at[person_id, 'un_acute_malnutrition_tx_start_date'] - - # Check that a CureEvent has been scheduled - cure_event = [event_tuple[1] for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] - - # Run the CureEvent - cure_event.apply(person_id=person_id) - - # Check that the person is cured and is alive still: - person = df.loc[person_id] - assert person['is_alive'] - assert person['un_WHZ_category'] == 'WHZ>=-2' - assert person['un_clinical_acute_malnutrition'] == 'well' - assert not pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - -def test_use_of_HSI_for_SAM(tmpdir): - """ - Check that the HSI_Wasting_OutpatientTherapeuticProgramme_SAM and HSI_Wasting_InpatientCareForComplicated_SAM work - """ - - def test_use_of_HSI_by_complication(complications): - dur = pd.DateOffset(days=0) - popsize = 1000 - sim = get_sim(tmpdir) - - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - - # Make 100% death rate by replacing with empty linear model 1.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # Make 100% treatment effectiveness by replacing with empty linear model 1.0 - for am in ['MAM', 'SAM']: - sim.modules['Wasting'].acute_malnutrition_recovery_based_on_interventions[am] = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # increase incidence of wasting and progression to severe - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # remove the probability of complications in SAM - params = sim.modules['Wasting'].parameters - if complications: - params['prob_complications_in_SAM'] = 1.0 # only SAM with complications - else: - params['prob_complications_in_SAM'] = 0.0 # no SAM with complications - - # # change coverage and treatment effectiveness set to be 100% - # params['coverage_supplementary_feeding_program'] = 1.0 - # params['coverage_outpatient_therapeutic_care'] = 1.0 - # params['coverage_inpatient_care'] = 1.0 - # params['recovery_rate_with_soy_RUSF'] = 1.0 - # params['recovery_rate_with_CSB++'] = 1.0 - # params['recovery_rate_with_standard_RUTF'] = 1.0 - # params['recovery_rate_with_inpatient_care'] = 1.0 - - # Make 100% death rate by replacing with empty linear model 1.0 - sim.modules['Wasting'].acute_malnutrition_recovery_based_on_interventions['SAM'] = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # Get person to use: - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' - - # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) - polling.apply(sim.population) - - # Check properties of this individual: - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - # Check not on treatment: - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - - # Check that there is a ProgressionSevereWastingEvent scheduled for this person: - progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ProgressionSevereWastingEvent) - ][0] - date_of_scheduled_progression = progression_event_tuple[0] - progression_event = progression_event_tuple[1] - assert date_of_scheduled_progression > sim.date - - # Run the progression to severe wasting event: - sim.date = date_of_scheduled_progression - progression_event.apply(person_id=person_id) - - # Check properties of this individual: (should now be severely wasted and without a scheduled death date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == 'WHZ<-3' - assert person['un_clinical_acute_malnutrition'] == 'SAM' - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Run the HSI event - if complications: - hsi = HSI_Wasting_InpatientCareForComplicated_SAM(person_id=person_id, module=sim.modules['Wasting']) - hsi.run(squeeze_factor=0.0) - else: - hsi = HSI_Wasting_OutpatientTherapeuticProgramme_SAM(person_id=person_id, module=sim.modules['Wasting']) - hsi.run(squeeze_factor=0.0) - - # Check that person is now on treatment: - assert sim.date == df.at[person_id, 'un_acute_malnutrition_tx_start_date'] - - print(sim.find_events_for_person(person_id)) - - # Check that a CureEvent has been scheduled - cure_event = [event_tuple[1] for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] - - # Run the CureEvent - cure_event.apply(person_id=person_id) - - # Check that the person is cured and is alive still: - person = df.loc[person_id] - assert person['is_alive'] - assert person['un_WHZ_category'] == 'WHZ>=-2' - assert person['un_clinical_acute_malnutrition'] == 'well' - assert not pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - test_use_of_HSI_by_complication(complications=True) - test_use_of_HSI_by_complication(complications=False) From 344cf92321bf26e75ea3578254ed79595342138c Mon Sep 17 00:00:00 2001 From: mnjowe Date: Tue, 5 Dec 2023 08:56:07 +0200 Subject: [PATCH 018/755] added a new sheet as per same file in master --- .../ResourceFile_PriorityRanking_ALLPOLICIES.xlsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx index e7dc4972c9..0443bd6fb1 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:af1a8f771bd93522fe018c916466ffa05b357aca4f9be54284ebd23d5fc472e9 -size 38448 +oid sha256:d0fe5f27b48430519dc01264d36d150862510adb46fe07ce82363bbc254136d7 +size 41283 From a711061423373c1455ee5ef9426ea895e7d2d0f0 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Tue, 5 Dec 2023 09:44:54 +0200 Subject: [PATCH 019/755] addressing the test membership error --- tests/test_wasting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 2468da3a1a..14cb829e5e 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -124,8 +124,8 @@ def check_configuration_of_properties(sim): (df.un_clinical_acute_malnutrition == 'SAM')]).issubset(has_symptoms) # All MAM individuals should have no symptoms of wasting - assert not set(df.index[df.is_alive & (df.age_exact_years < 5) & - (df.un_clinical_acute_malnutrition == 'MAM')]) in has_symptoms + assert set(df.index[df.is_alive & (df.age_exact_years < 5) & + (df.un_clinical_acute_malnutrition == 'MAM')]) not in has_symptoms @pytest.mark.slow From 1cecf268724c3b7bbfe50b6e444a42bedf1b7da4 Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Tue, 5 Dec 2023 09:50:37 +0200 Subject: [PATCH 020/755] update --- resources/ResourceFile_Wasting.xlsx | 4 +- .../wasting_analyses/analysis_wasting.py | 81 +++++- src/tlo/methods/hsi_generic_first_appts.py | 3 + src/tlo/methods/wasting.py | 170 ++++++----- tests/test_wasting.py | 274 +++++++++--------- 5 files changed, 330 insertions(+), 202 deletions(-) diff --git a/resources/ResourceFile_Wasting.xlsx b/resources/ResourceFile_Wasting.xlsx index fa109671a5..f9d8edd576 100644 --- a/resources/ResourceFile_Wasting.xlsx +++ b/resources/ResourceFile_Wasting.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e7f03fe6554fde5e6285cf1fe8c49302feb70ab13169fe68ebfb926f03df3622 -size 11433 +oid sha256:114093cdc002bf28b200865843afb448605bbf81075a38f3de0011b0b8d40ea3 +size 11670 diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 9dc5915ee7..c7291eac33 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -47,12 +47,70 @@ def __init__(self, log_file_path): '-3≥WHZ<-2': 'moderate wasting', 'WHZ>=-2': 'not undernourished'} + # self.__wasting_types_desc = {'WHZ<-3': 'severe wasting', + # '-3≥WHZ<-2': 'moderate wasting'} + + # def plot_wasting_incidence(self): + # """ plot the incidence of wasting over time """ + # w_inc_df = self.__logs_dict['wasting_incidence_count'] + # w_inc_df.set_index(w_inc_df.date.dt.year, inplace=True) + # w_inc_df.drop(columns='date', inplace=True) + # new_df = pd.DataFrame(index=w_inc_df.index, data=w_inc_df.loc[w_inc_df.index[0], '0y']) + # print(f'Before LOOPING and dropping {new_df}') + # print(f'After dropping {new_df}') + # _row_counter = 0 + # _col_counter = 0 + # fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True) # plot setup + # for _year in w_inc_df.columns: + # for _index in range(len(new_df.index)): + # new_df.loc[new_df.index[_index], new_df.columns] = \ + # w_inc_df.loc[w_inc_df.index[_index], _year].values() + # new_df = new_df.apply(lambda _row: _row / _row.sum(), axis=1) + # print(f'Inside DF{new_df}') + # # convert into proportions + # ax = new_df.plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], + # title=f"incidence of wasting in {_year} infants") + # ax.legend(self.__wasting_types_desc.values(), loc='lower right') + # ax.set_xlabel('year') + # ax.set_ylabel('proportions') + # # move to another row + # if _col_counter == 2: + # _row_counter += 1 + # _col_counter = -1 + # _col_counter += 1 # increment column counter + # plt.tight_layout() + # + # plt.show() + def plot_wasting_incidence(self): """ plot the incidence of wasting over time """ w_inc_df = self.__logs_dict['wasting_incidence_count'] w_inc_df.set_index(w_inc_df.date.dt.year, inplace=True) w_inc_df.drop(columns='date', inplace=True) - new_df = pd.DataFrame(index=w_inc_df.index, data=w_inc_df.loc[w_inc_df.index[0], '0y']) + print(f'Wasting Incidence DF {w_inc_df}') + # keytoextract = ['WHZ>=-2'] + + # for i in w_inc_df.index: + # print(f'GET VAL {w_inc_df["0y"][i]}') + # for key, value in w_inc_df["0y"][i].copy().items(): + # if key in keytoextract: + # w_inc_df["0y"][i].pop(key) + + # for i in w_inc_df.index: + # print(f'GET VAL {w_inc_df["0y"][i]}') + # for c in w_inc_df: + # print(f'ARE AT {w_inc_df[c][i]}') + # for key, value in w_inc_df[c][i].copy().items(): + # if key in keytoextract: + # w_inc_df[c][i].pop(key) + + print(f'Extracted DF {w_inc_df}') + www = w_inc_df + print(print(f'www {www}')) + new_df = pd.DataFrame(index=www.index, data=w_inc_df.loc[w_inc_df.index[0], '0y']) + print(f'Before LOOPING and dropping {new_df}') + #new_datf = new_df.drop(['WHZ>=-2'], axis=1) + #print(f'After dropping {new_datf}') _row_counter = 0 _col_counter = 0 fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True) # plot setup @@ -61,10 +119,12 @@ def plot_wasting_incidence(self): new_df.loc[new_df.index[_index], new_df.columns] = \ w_inc_df.loc[w_inc_df.index[_index], _year].values() new_df = new_df.apply(lambda _row: _row / _row.sum(), axis=1) + print(f'Inside DF{new_df}') # convert into proportions - ax = new_df.plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], + ax = new_df[["WHZ<-3", "-3<=WHZ<-2"]].plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], title=f"incidence of wasting in {_year} infants") ax.legend(self.__wasting_types_desc.values(), loc='lower right') + ax.set_ylim(0, 0.04) ax.set_xlabel('year') ax.set_ylabel('proportions') # move to another row @@ -93,6 +153,12 @@ def plot_modal_gbd_deaths_by_gender(self): fig, axs = plt.subplots(nrows=1, ncols=2, sharey=True, sharex=True) for _col, sex in enumerate(('M', 'F')): plot_df = death_compare.loc[(['2010-2014'], sex, slice(None), 'Childhood Wasting')].groupby('period').sum() + #plot_df.index = plot_df + print(f'the df is {plot_df}') + print(f'The PERIOD {plot_df.loc[["2010-2014"]]}') + print(f'ALL COLS {plot_df.to_string(index=False)}') + #print(f'The YEARS {plot_df["period"]}') + plot_df = plot_df.loc[['2010-2014']] ax = plot_df['model'].plot.bar(label='Model', ax=axs[_col], rot=0) ax.errorbar(x=plot_df['model'].index, y=plot_df.GBD_mean, yerr=[plot_df.GBD_lower, plot_df.GBD_upper], @@ -132,7 +198,7 @@ def plot_modal_gbd_deaths_by_gender(self): # Basic arguments required for the simulation start_date = Date(2010, 1, 1) -end_date = Date(2030, 1, 1) +end_date = Date(2015, 2, 1) pop_size = 10000 # Create simulation instance for this run. @@ -161,10 +227,14 @@ def plot_modal_gbd_deaths_by_gender(self): ) sim.make_initial_population(n=pop_size) -sim.simulate(end_date=end_date) +#sim.simulate(end_date=end_date) # %% read the results -output_path = sim.log_filepath +#output_path = sim.log_filepath +#output_path = Path("./outputs/wasting__2023-10-25T101305.log") +#output_path = Path("./outputs/wasting__2023-11-06T091607.log") +output_path = Path("./outputs/wasting__2023-12-04T140722.log") + # initialise the wasting class wasting_analyses = WastingAnalyses(output_path) @@ -177,3 +247,4 @@ def plot_modal_gbd_deaths_by_gender(self): # plot wasting deaths by gender as compared to GBD deaths wasting_analyses.plot_modal_gbd_deaths_by_gender() + diff --git a/src/tlo/methods/hsi_generic_first_appts.py b/src/tlo/methods/hsi_generic_first_appts.py index f84518b4a3..0294d3367f 100644 --- a/src/tlo/methods/hsi_generic_first_appts.py +++ b/src/tlo/methods/hsi_generic_first_appts.py @@ -183,6 +183,9 @@ def do_at_generic_first_appt_non_emergency(hsi_event, squeeze_factor): if 'Stunting' in sim.modules: sim.modules['Stunting'].do_routine_assessment_for_chronic_undernutrition(person_id=person_id) + if 'Wasting' in sim.modules: + sim.modules['Wasting'].do_when_acute_malnutrition_assessment(person_id=person_id) + else: # ----------------------------------- ADULT ----------------------------------- if 'OesophagealCancer' in sim.modules: diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 66600118da..20641eef74 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1,5 +1,5 @@ """Childhood wasting module""" - +import copy from pathlib import Path import numpy as np @@ -213,14 +213,14 @@ def __init__(self, name=None, resourcefilepath=None): # dict to hold counters for the number of episodes by wasting-type and age-group blank_counter = dict(zip(self.wasting_states, [list() for _ in self.wasting_states])) self.wasting_incident_case_tracker_blank = { - _agrp: blank_counter for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} + _agrp: copy.deepcopy(blank_counter) for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} - self.wasting_incident_case_tracker = dict(self.wasting_incident_case_tracker_blank) + self.wasting_incident_case_tracker = copy.deepcopy(self.wasting_incident_case_tracker_blank) zeros_counter = dict(zip(self.wasting_states, [0] * len(self.wasting_states))) self.wasting_incident_case_tracker_zeros = { - _agrp: zeros_counter for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} + _agrp: copy.deepcopy(zeros_counter) for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} # dict to hold the DALY weights self.daly_wts = dict() @@ -321,10 +321,10 @@ def make_linear_model_wasting(intercept=get_odds_wasting(agegp=agegp)): LinearModelType.LOGISTIC, intercept, # baseline odds: get_odds_wasting(agegp=agegp) Predictor('li_wealth').when(2, p['or_wasting_hhwealth_Q2']) - .when(3, p['or_wasting_hhwealth_Q3']) - .when(4, p['or_wasting_hhwealth_Q4']) - .when(5, p['or_wasting_hhwealth_Q5']) - .otherwise(1.0), + .when(3, p['or_wasting_hhwealth_Q3']) + .when(4, p['or_wasting_hhwealth_Q4']) + .when(5, p['or_wasting_hhwealth_Q5']) + .otherwise(1.0), Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' '& (nb_late_preterm == False) & (nb_early_preterm == False)', p['or_wasting_SGA_and_term']), @@ -417,45 +417,46 @@ def get_prob_severe_in_overall_wasting(agegp): # # # # # Treatment coverage and cure rates at initiation # # # # # # inpatient care - sam_requiring_inpatient_care = df.index[df.is_alive & (df.age_exact_years < 5) & ( - df.un_clinical_acute_malnutrition == 'SAM') & df.un_sam_with_complications] - recovered_complic_sam = self.rng.random_sample(len(sam_requiring_inpatient_care)) < ( - p['coverage_inpatient_care'] * p['recovery_rate_with_inpatient_care']) - # schedule recovery, and reset properties - for person in sam_requiring_inpatient_care[recovered_complic_sam]: - self.sim.schedule_event( - event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), - date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months - - for person in sam_requiring_inpatient_care[~recovered_complic_sam]: - self.sim.schedule_event( - event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person), - date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months - - # outpatient care - uncomplicated_sam = df.index[df.is_alive & (df.age_exact_years < 5) & ( - df.un_clinical_acute_malnutrition == 'SAM') & ~df.un_sam_with_complications] - recovered_uncompl_sam = self.rng.random_sample(len(uncomplicated_sam)) > ( - p['coverage_outpatient_therapeutic_care'] * p['recovery_rate_with_standard_RUTF']) - for person in uncomplicated_sam[recovered_uncompl_sam]: - self.sim.schedule_event( - event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), - date=self.sim.date + DateOffset(months=3)) # in the next 3 months - for person in uncomplicated_sam[~recovered_uncompl_sam]: - self.sim.schedule_event( - event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person), - date=self.sim.date + DateOffset(months=3)) # in the next 3 months - - # supplementary feeding for MAM - children_with_mam = df.index[df.is_alive & (df.age_exact_years < 5) & ( - df.un_clinical_acute_malnutrition == 'MAM') & ~df.un_sam_with_complications] - recovered_mam = self.rng.random_sample(len(children_with_mam)) < ( - p['coverage_supplementary_feeding_program'] * p['recovery_rate_with_CSB++']) - for person in children_with_mam[recovered_mam]: - self.sim.schedule_event( - event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), - date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months - # if not cured by the intervention, remain as MAM and outcome will be determined in the + # sam_requiring_inpatient_care = df.index[df.is_alive & (df.age_exact_years < 5) & ( + # df.un_clinical_acute_malnutrition == 'SAM') & df.un_sam_with_complications] + # recovered_complic_sam = self.rng.random_sample(len(sam_requiring_inpatient_care)) < ( + # p['coverage_inpatient_care'] * p['recovery_rate_with_inpatient_care']) + # # schedule recovery, and reset properties + # for person in sam_requiring_inpatient_care[recovered_complic_sam]: + # self.sim.schedule_event( + # event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), + # date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months + # + # for person in sam_requiring_inpatient_care[~recovered_complic_sam]: + # self.sim.schedule_event( + # event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person), + # date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months + # + # # outpatient care + # uncomplicated_sam = df.index[df.is_alive & (df.age_exact_years < 5) & ( + # df.un_clinical_acute_malnutrition == 'SAM') & ~df.un_sam_with_complications] + # recovered_uncompl_sam = self.rng.random_sample(len(uncomplicated_sam)) > ( + # p['coverage_outpatient_therapeutic_care'] * p['recovery_rate_with_standard_RUTF']) + # for person in uncomplicated_sam[recovered_uncompl_sam]: + # self.sim.schedule_event( + # event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), + # date=self.sim.date + DateOffset(months=3)) # in the next 3 months + # for person in uncomplicated_sam[~recovered_uncompl_sam]: + # self.sim.schedule_event( + # event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person), + # date=self.sim.date + DateOffset(months=3)) # in the next 3 months + # + # # supplementary feeding for MAM + # children_with_mam = df.index[df.is_alive & (df.age_exact_years < 5) & ( + # df.un_clinical_acute_malnutrition == 'MAM') & ~df.un_sam_with_complications] + # recovered_mam = self.rng.random_sample(len(children_with_mam)) < ( + # p['coverage_supplementary_feeding_program'] * p['recovery_rate_with_CSB++']) + # for person in children_with_mam[recovered_mam]: + # self.sim.schedule_event( + # event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person), + # date=self.sim.date + DateOffset(days=self.rng.randint(0, 90))) # in the next 3 months + + # if not cured by the intervention, remain as MAM and outcome will be determined in the # natural history of the next polling event def initialise_simulation(self, sim): @@ -472,7 +473,7 @@ def initialise_simulation(self, sim): sim.schedule_event(WastingPollingEvent(self), sim.date + DateOffset(months=3)) # schedule acute malnutrition event - sim.schedule_event(AcuteMalnutritionDeathPollingEvent(self), sim.date + DateOffset(months=3)) + # sim.schedule_event(AcuteMalnutritionDeathPollingEvent(self), sim.date + DateOffset(months=3)) # schedule wasting logging event sim.schedule_event(WastingLoggingEvent(self), sim.date + DateOffset(months=12)) @@ -499,12 +500,12 @@ def make_lm_wasting_incidence(intercept=1.0): LinearModelType.MULTIPLICATIVE, intercept, Predictor('age_exact_years').when('<0.5', p['base_inc_rate_wasting_by_agegp'][0]) - .when('<1.0', p['base_inc_rate_wasting_by_agegp'][1]) - .when('.between(1,1.9999)', p['base_inc_rate_wasting_by_agegp'][2]) - .when('.between(2,2.9999)', p['base_inc_rate_wasting_by_agegp'][3]) - .when('.between(3,3.9999)', p['base_inc_rate_wasting_by_agegp'][4]) - .when('.between(4,4.9999)', p['base_inc_rate_wasting_by_agegp'][5]) - .otherwise(0.0), + .when('<1.0', p['base_inc_rate_wasting_by_agegp'][1]) + .when('.between(1,1.9999)', p['base_inc_rate_wasting_by_agegp'][2]) + .when('.between(2,2.9999)', p['base_inc_rate_wasting_by_agegp'][3]) + .when('.between(3,3.9999)', p['base_inc_rate_wasting_by_agegp'][4]) + .when('.between(4,4.9999)', p['base_inc_rate_wasting_by_agegp'][5]) + .otherwise(0.0), Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' '& (nb_late_preterm == False) & (nb_early_preterm == False)', p['rr_wasting_SGA_and_term']), @@ -913,9 +914,11 @@ def do_when_am_treatment(self, person_id, intervention): df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date if intervention == 'SFP': + print('SFP') mam_recovery = self.acute_malnutrition_recovery_based_on_interventions['MAM'].predict( df.loc[[person_id]]).values[0] if self.rng.random_sample() < mam_recovery: + print('schedulling event') # schedule recovery date self.sim.schedule_event( event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), @@ -938,7 +941,7 @@ def do_when_am_treatment(self, person_id, intervention): else: # remained MAM or death outcome = self.rng.choice(['remained_mam', 'death'], - p=[0.5, 0.5]) + p=[0.7, 0.3]) if outcome == 'remained_mam': self.sim.schedule_event( event=UpdateToMAM(module=self, person_id=person_id), @@ -961,7 +964,7 @@ def do_when_am_treatment(self, person_id, intervention): else: # remained MAM or death outcome = self.rng.choice(['remained_mam', 'death'], - p=[0.5, 0.5]) + p=[0.7, 0.3]) if outcome == 'remained_mam': self.sim.schedule_event( event=UpdateToMAM(module=self, person_id=person_id), @@ -1000,6 +1003,7 @@ def apply(self, population): # Determine who will be onset with wasting among those who are not currently wasted ------------- inc_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == 'WHZ>=-2')] incidence_of_wasting = self.module.wasting_incidence_equation.predict(inc_wasting, rng) + print(f'Inc Wasting total {len(inc_wasting)}') wasting_idx = inc_wasting.index # update the properties for wasted children @@ -1008,6 +1012,20 @@ def apply(self, population): df.loc[wasting_idx[incidence_of_wasting], 'un_WHZ_category'] = '-3<=WHZ<-2' # start as moderate wasting df.loc[wasting_idx[incidence_of_wasting], 'un_am_treatment_type'] = 'none' # start without treatment + print(f'Actual Inc total {len(df.loc[wasting_idx[incidence_of_wasting], "un_ever_wasted"])}') + print(f'Actual False Inc total {len(df.loc[wasting_idx[~incidence_of_wasting], "un_ever_wasted"])}') + truval = df.loc[wasting_idx[incidence_of_wasting], "un_ever_wasted"] + print(f'Truval {truval}') + combo = df.loc[wasting_idx[~incidence_of_wasting], "un_ever_wasted"] + print(f'Combo {combo}') + #print(f'Simple idx {wasting_idx[~incidence_of_wasting]}') + + for munthu in wasting_idx[~incidence_of_wasting]: + wasting_severity = df.at[munthu, 'un_WHZ_category'] + age_group = WastingPollingEvent.AGE_GROUPS.get(df.loc[munthu].age_years, '5+y') + # if wasting_severity == 'WHZ>=-2': + self.module.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) + # ------------------------------------------------------------------------------------------- # Add this incident case to the tracker for person in wasting_idx[incidence_of_wasting]: @@ -1088,7 +1106,7 @@ def apply(self, person_id): # before progression to severe wasting, check those who started supplementary feeding programme before today if df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[person_id, 'un_acute_malnutrition_tx_start_date'] \ - < self.sim.date: + < self.sim.date: return # continue with progression to severe if not treated/recovered @@ -1191,13 +1209,16 @@ def apply(self, person_id): # The event should not run if the person is not currently alive if not df.at[person_id, 'is_alive']: return - - if df.at[person_id, 'un_acute_malnutrition_tx_start_date'] < self.sim.date: - return + print(f"treatment date {df.at[person_id, 'un_acute_malnutrition_tx_start_date']}") + print(f"simulation date {self.sim.date}") + print(f"recovery date {df.at[person_id, 'un_am_recovery_date']}") + # if df.at[person_id, 'un_acute_malnutrition_tx_start_date'] < self.sim.date: + # return # Check if this person should still die from SAM: - if pd.isnull(df.at[person_id, 'un_am_recovery_date']) &\ - (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM'): + if pd.isnull(df.at[person_id, 'un_am_recovery_date']) & \ + (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM'): + print("dying") # Cause the death to happen immediately df.at[person_id, 'un_sam_death_date'] = self.sim.date self.sim.modules['Demography'].do_death( @@ -1229,7 +1250,8 @@ def apply(self, person_id): # For cases with normal WHZ, attribute probability of MUAC category if df.at[person_id, 'age_exact_years'] > 0.5: m.muac_cutoff_by_WHZ(idx=df.loc[[person_id]].index, whz='WHZ>=-2') - m.nutritional_oedema_present(idx==df.loc[[person_id]].index, whz='WHZ>=-2') + m.nutritional_oedema_present(idx=df.loc[[person_id]].index) + # m.nutritional_oedema_present(idx=df.loc[[person_id]].index, whz='WHZ>=-2') # Note assumption: prob of oedema remained the same as applied in wasting onset @@ -1266,6 +1288,7 @@ def apply(self, person_id): df.at[person_id, 'un_sam_with_complications'] = False df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = pd.NaT df.at[person_id, 'un_am_treatment_type'] = 'not_applicable' + print(f'Running Clinical Maln') # this will clear all wasting symptoms self.sim.modules["SymptomManager"].clear_symptoms( @@ -1348,7 +1371,7 @@ def __init__(self, module, person_id): self.ALERT_OTHER_DISEASES = [] def apply(self, person_id, squeeze_factor): - + print('running') df = self.sim.population.props # Stop the person from dying of acute malnutrition (if they were going to die) @@ -1370,6 +1393,7 @@ def apply(self, person_id, squeeze_factor): df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=3) df.at[person_id, 'un_am_treatment_type'] = 'CSB++' + print('also running') self.module.do_when_am_treatment(person_id, intervention='SFP') else: logger.debug(key='debug', data="PkgCode1 is not available, so can't use it.") @@ -1504,22 +1528,34 @@ def apply(self, population): df = self.sim.population.props # Convert the list of timestamps into a number of timestamps # and check that all the dates have occurred since self.date_last_run - counts_am = self.module.wasting_incident_case_tracker_zeros + counts_am = copy.deepcopy(self.module.wasting_incident_case_tracker_zeros) + # counts_am = list(self.module.wasting_incident_case_tracker_zeros) #added line + # for age_grp, state in zip(self.module.wasting_incident_case_tracker.keys(), self.module.wasting_states): + # list_of_times = self.module.wasting_incident_case_tracker[age_grp][state] + # counts_am[age_grp][state] = len(list_of_times) + # for t in list_of_times: + # logger.debug(self.date_last_run, t, self.sim.date) + # # assert self.date_last_run <= t <= self.sim.date + + # From here for age_grp in self.module.wasting_incident_case_tracker.keys(): for state in self.module.wasting_states: list_of_times = self.module.wasting_incident_case_tracker[age_grp][state] counts_am[age_grp][state] = len(list_of_times) for t in list_of_times: + logger.debug(self.date_last_run, t, self.sim.date) assert self.date_last_run <= t <= self.sim.date + # End here logger.info(key='wasting_incidence_count', data=counts_am) # Reset the counters and the date_last_run - self.module.wasting_incident_case_tracker = self.module.wasting_incident_case_tracker_blank + self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) self.date_last_run = self.sim.date + # Wasting totals (prevalence at logging time) currently_wasted_age_0_5mo = (df.is_alive & (df.age_exact_years < 0.5) & (df.un_WHZ_category != 'WHZ>=-2')).sum() @@ -1533,6 +1569,8 @@ def apply(self, population): df.age_exact_years < 4)) & (df.un_WHZ_category != 'WHZ>=-2')).sum() currently_wasted_age_48_59mo = (df.is_alive & ((df.age_exact_years >= 4) & ( df.age_exact_years < 5)) & (df.un_WHZ_category != 'WHZ>=-2')).sum() + #'WHZ<-3', '-3<=WHZ<-2' + # total_not_wasted = (df.is_alive & (df.un_WHZ_category != 'WHZ<-3') & (df.un_WHZ_category != '-3<=WHZ<-2')).sum() currently_wasted = {'0_5mo': currently_wasted_age_0_5mo, '6_11mo': currently_wasted_age_6_11mo, diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 94fefb7b42..e33062bdc7 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -51,7 +51,7 @@ def get_sim(tmpdir): sim.register(demography.Demography(resourcefilepath=resourcefilepath), enhanced_lifestyle.Lifestyle(resourcefilepath=resourcefilepath), - healthsystem.HealthSystem(resourcefilepath=resourcefilepath, disable=True), + healthsystem.HealthSystem(resourcefilepath=resourcefilepath, disable=False, cons_availability='all'), symptommanager.SymptomManager(resourcefilepath=resourcefilepath), healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resourcefilepath), healthburden.HealthBurden(resourcefilepath=resourcefilepath), @@ -182,6 +182,10 @@ def test_wasting_polling(tmpdir): # Run polling event: check that a severe incident case is produced: polling = WastingPollingEvent(sim.modules['Wasting']) polling.apply(sim.population) + + for q in sim.event_queue.queue: + print(f'Qui {q[3]}') + assert len([q for q in sim.event_queue.queue if isinstance(q[3], ProgressionSevereWastingEvent)]) > 0 # Check properties of this individual: should now be moderately wasted @@ -600,133 +604,133 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): assert person['is_alive'] -def test_treatment(tmpdir): - """ Test that providing a treatment prevent death and causes there to be a - CureEvent (ClinicalAcuteMalnutritionRecoveryEvent) Scheduled """ - """ - This test sets the linear model of acute_malnutrition_recovery_based_on_interventions to be 1.0 (100% cure rate), - when this lm is called in the do_when_am_treatment function (usually called in HSIs), 100% cure rate schedules the - ClinicalAcuteMalnutritionRecoveryEvent (CureEvent). - Death is prevented. ---> check - """ - # TODO: CHECK THIS - MAYBE NOT NEEDED - - dur = pd.DateOffset(days=0) - popsize = 1000 - sim = get_sim(tmpdir) - - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - - # Make 100% death rate by replacing with empty linear model 1.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # increase incidence of wasting and progression to severe - sim.modules['Wasting'].wasting_incidence_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # increase parameters in moderate wasting for clinical SAM (MUAC and oedema) to be polled for death - params = sim.modules['Wasting'].parameters - params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = [5 * params['proportion_-3<=WHZ<-2_with_MUAC<115mm']] - params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] = [params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] / 5] - params['proportion_oedema_with_WHZ<-2'] = 0.9 - - # Get person to use: - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' - - # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) - polling.apply(sim.population) - - # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Check that there is a ProgressionSevereWastingEvent scheduled for this person: - progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ProgressionSevereWastingEvent) - ][0] - date_of_scheduled_progression = progression_event_tuple[0] - progression_event = progression_event_tuple[1] - assert date_of_scheduled_progression > sim.date - - # Run the progression to severe wasting event: - sim.date = date_of_scheduled_progression - progression_event.apply(person_id=person_id) - - # Check properties of this individual: (should now be severely wasted and without a scheduled death date) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == 'WHZ<-3' - assert person['un_clinical_acute_malnutrition'] == 'SAM' - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Run Death Polling event to apply death: - death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) - death_polling.apply(sim.population) - - # Check that there is a SevereAcuteMalnutritionDeathEvent scheduled for this person: - death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) - ][0] - date_of_scheduled_death = death_event_tuple[0] - death_event = death_event_tuple[1] - assert date_of_scheduled_death > sim.date - - # # change coverage and treatment effectiveness set to be 100% - # params['coverage_supplementary_feeding_program'] = 1.0 - # params['coverage_outpatient_therapeutic_care'] = 1.0 - # params['coverage_inpatient_care'] = 1.0 - # params['recovery_rate_with_soy_RUSF'] = 1.0 - # params['recovery_rate_with_CSB++'] = 1.0 - # params['recovery_rate_with_standard_RUTF'] = 1.0 - # params['recovery_rate_with_inpatient_care'] = 1.0 - - # Make 100% death rate by replacing with empty linear model 1.0 - for am in ['MAM', 'SAM']: - sim.modules['Wasting'].acute_malnutrition_recovery_based_on_interventions[am] = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) - - # Run the 'do_when_am_treatment' function - interventions = ['SFP', 'OTC', 'ITC'] - for int in interventions: - sim.modules['Wasting'].do_when_am_treatment(person_id=person_id, intervention=int) - - # Run the death event that was originally scheduled - this should have no effect and the person should not die - sim.date = date_of_scheduled_death - death_event.apply(person_id=person_id) - person = df.loc[person_id] - assert person['is_alive'] - - # print(sim.find_events_for_person(person_id)) - - # Check that a CureEvent has been scheduled - cure_event = [event_tuple[1] for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] - - # Run the CureEvent - cure_event.apply(person_id=person_id) - - # Check that the person is not infected and is alive still: - person = df.loc[person_id] - assert person['is_alive'] - assert person['un_WHZ_category'] == 'WHZ>=-2' - assert not pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) +# def test_treatment(tmpdir): +# """ Test that providing a treatment prevent death and causes there to be a +# CureEvent (ClinicalAcuteMalnutritionRecoveryEvent) Scheduled """ +# """ +# This test sets the linear model of acute_malnutrition_recovery_based_on_interventions to be 1.0 (100% cure rate), +# when this lm is called in the do_when_am_treatment function (usually called in HSIs), 100% cure rate schedules the +# ClinicalAcuteMalnutritionRecoveryEvent (CureEvent). +# Death is prevented. ---> check +# """ +# # TODO: CHECK THIS - MAYBE NOT NEEDED +# +# dur = pd.DateOffset(days=0) +# popsize = 1000 +# sim = get_sim(tmpdir) +# +# sim.make_initial_population(n=popsize) +# sim.simulate(end_date=start_date + dur) +# sim.event_queue.queue = [] # clear the queue +# +# # Make 100% death rate by replacing with empty linear model 1.0 +# sim.modules['Wasting'].sam_death_equation = LinearModel( +# LinearModelType.MULTIPLICATIVE, 1.0) +# +# # increase incidence of wasting and progression to severe +# sim.modules['Wasting'].wasting_incidence_equation = LinearModel( +# LinearModelType.MULTIPLICATIVE, 1.0) +# sim.modules['Wasting'].severe_wasting_progression_equation = LinearModel( +# LinearModelType.MULTIPLICATIVE, 1.0) +# +# # increase parameters in moderate wasting for clinical SAM (MUAC and oedema) to be polled for death +# params = sim.modules['Wasting'].parameters +# params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = [5 * params['proportion_-3<=WHZ<-2_with_MUAC<115mm']] +# params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] = [params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] / 5] +# params['proportion_oedema_with_WHZ<-2'] = 0.9 +# +# # Get person to use: +# df = sim.population.props +# under5s = df.loc[df.is_alive & (df['age_years'] < 5)] +# person_id = under5s.index[0] +# assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' +# +# # Run Wasting Polling event to get new incident cases: +# polling = WastingPollingEvent(module=sim.modules['Wasting']) +# polling.apply(sim.population) +# +# # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) +# person = df.loc[person_id] +# assert person['un_ever_wasted'] +# assert person['un_WHZ_category'] == '-3<=WHZ<-2' +# assert person['un_last_wasting_date_of_onset'] == sim.date +# assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) +# assert pd.isnull(person['un_am_recovery_date']) +# assert pd.isnull(person['un_sam_death_date']) +# +# # Check that there is a ProgressionSevereWastingEvent scheduled for this person: +# progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if +# isinstance(event_tuple[1], ProgressionSevereWastingEvent) +# ][0] +# date_of_scheduled_progression = progression_event_tuple[0] +# progression_event = progression_event_tuple[1] +# assert date_of_scheduled_progression > sim.date +# +# # Run the progression to severe wasting event: +# sim.date = date_of_scheduled_progression +# progression_event.apply(person_id=person_id) +# +# # Check properties of this individual: (should now be severely wasted and without a scheduled death date) +# person = df.loc[person_id] +# assert person['un_ever_wasted'] +# assert person['un_WHZ_category'] == 'WHZ<-3' +# assert person['un_clinical_acute_malnutrition'] == 'SAM' +# assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) +# assert pd.isnull(person['un_am_recovery_date']) +# assert pd.isnull(person['un_sam_death_date']) +# +# # Run Death Polling event to apply death: +# death_polling = AcuteMalnutritionDeathPollingEvent(module=sim.modules['Wasting']) +# death_polling.apply(sim.population) +# +# # Check that there is a SevereAcuteMalnutritionDeathEvent scheduled for this person: +# death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if +# isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) +# ][0] +# date_of_scheduled_death = death_event_tuple[0] +# death_event = death_event_tuple[1] +# assert date_of_scheduled_death > sim.date +# +# # # change coverage and treatment effectiveness set to be 100% +# # params['coverage_supplementary_feeding_program'] = 1.0 +# # params['coverage_outpatient_therapeutic_care'] = 1.0 +# # params['coverage_inpatient_care'] = 1.0 +# # params['recovery_rate_with_soy_RUSF'] = 1.0 +# # params['recovery_rate_with_CSB++'] = 1.0 +# # params['recovery_rate_with_standard_RUTF'] = 1.0 +# # params['recovery_rate_with_inpatient_care'] = 1.0 +# +# # Make 100% death rate by replacing with empty linear model 1.0 +# for am in ['MAM', 'SAM']: +# sim.modules['Wasting'].acute_malnutrition_recovery_based_on_interventions[am] = LinearModel( +# LinearModelType.MULTIPLICATIVE, 1.0) +# +# # Run the 'do_when_am_treatment' function +# interventions = ['SFP', 'OTC', 'ITC'] +# for intv in interventions: +# sim.modules['Wasting'].do_when_am_treatment(person_id=person_id, intervention=intv) +# +# # Run the death event that was originally scheduled - this should have no effect and the person should not die +# sim.date = date_of_scheduled_death +# death_event.apply(person_id=person_id) +# person = df.loc[person_id] +# assert person['is_alive'] +# +# # print(sim.find_events_for_person(person_id)) +# +# # Check that a CureEvent has been scheduled +# cure_event = [event_tuple[1] for event_tuple in sim.find_events_for_person(person_id) if +# isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] +# +# # Run the CureEvent +# cure_event.apply(person_id=person_id) +# +# # Check that the person is not infected and is alive still: +# person = df.loc[person_id] +# assert person['is_alive'] +# assert person['un_WHZ_category'] == 'WHZ>=-2' +# assert not pd.isnull(person['un_am_recovery_date']) +# assert pd.isnull(person['un_sam_death_date']) def test_use_of_HSI_for_MAM(tmpdir): @@ -780,14 +784,26 @@ def test_use_of_HSI_for_MAM(tmpdir): # Run the HSI event hsi = HSI_Wasting_SupplementaryFeedingProgramme_MAM(person_id=person_id, module=sim.modules['Wasting']) + print(f'------') + print(f'personia {person}') + print(f'------') hsi.run(squeeze_factor=0.0) # Check that person is now on treatment: assert sim.date == df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + print(f'person trt start date {df.at[person_id, "un_acute_malnutrition_tx_start_date"]}') + print(f'trt type {df.at[person_id, "un_am_treatment_type"]}') + + showme = sim.find_events_for_person(person_id) + print(f'Show Me {showme}') + + for event_tuple in sim.find_events_for_person(person_id): + print(f'Ev {event_tuple[1]}') + print(f'events {sim.find_events_for_person(person_id)}') # Check that a CureEvent has been scheduled cure_event = [event_tuple[1] for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] + isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] #add wastingnaturalrecoveryevent # Run the CureEvent cure_event.apply(person_id=person_id) From 7563c94005a73f6ba319b5ead9fd17821705a44a Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Tue, 5 Dec 2023 17:35:46 +0200 Subject: [PATCH 021/755] Worked on graphs --- resources/ResourceFile_Wasting.xlsx | 4 ++-- src/scripts/wasting_analyses/analysis_wasting.py | 13 ++++++++++--- src/tlo/methods/wasting.py | 4 ++-- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/resources/ResourceFile_Wasting.xlsx b/resources/ResourceFile_Wasting.xlsx index b4e5b19824..c99349de5e 100644 --- a/resources/ResourceFile_Wasting.xlsx +++ b/resources/ResourceFile_Wasting.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7dac7ad9e1578600b390cab4817f1732f19ccc5cd05c136741e0b506dcd50aff -size 11489 +oid sha256:b40d7f5ff8c168a30da1660c007ed6dcc2bc0f0c44db50608c80b66165538844 +size 11617 diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 56eae98c5f..3417a763c5 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -65,9 +65,14 @@ def plot_wasting_incidence(self): new_df = new_df.apply(lambda _row: _row / _row.sum(), axis=1) # convert into proportions - ax = new_df.plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], - title=f"incidence of wasting in {_age} infants") + + ax = new_df[["WHZ<-3", "-3<=WHZ<-2"]].plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], + title=f"incidence of wasting in {_age} infants") + + # ax = new_df.plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], + # title=f"incidence of wasting in {_age} infants") ax.legend(self.__wasting_types_desc.values(), loc='lower right') + ax.set_ylim(0, 0.04) ax.set_xlabel('year') ax.set_ylabel('proportions') # move to another row @@ -96,6 +101,7 @@ def plot_modal_gbd_deaths_by_gender(self): fig, axs = plt.subplots(nrows=1, ncols=2, sharey=True, sharex=True) for _col, sex in enumerate(('M', 'F')): plot_df = death_compare.loc[(['2010-2014'], sex, slice(None), 'Childhood Wasting')].groupby('period').sum() + plot_df = plot_df.loc[['2010-2014']] ax = plot_df['model'].plot.bar(label='Model', ax=axs[_col], rot=0) ax.errorbar(x=plot_df['model'].index, y=plot_df.GBD_mean, yerr=[plot_df.GBD_lower, plot_df.GBD_upper], @@ -135,7 +141,7 @@ def plot_modal_gbd_deaths_by_gender(self): # Basic arguments required for the simulation start_date = Date(2010, 1, 1) -end_date = Date(2030, 1, 1) +end_date = Date(2013, 1, 1) pop_size = 10000 # Create simulation instance for this run. @@ -168,6 +174,7 @@ def plot_modal_gbd_deaths_by_gender(self): # read the results output_path = sim.log_filepath +#output_path = Path("./outputs/wasting__2023-12-05T105434.log") # initialise the wasting class wasting_analyses = WastingAnalyses(output_path) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index ad1c221742..1679c83e9d 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -670,7 +670,7 @@ def do_when_am_treatment(self, person_id, intervention): # cancel death date df.at[person_id, 'un_sam_death_date'] = pd.NaT else: - outcome = self.rng.choice(['remained_mam', 'death'], p=[0.32, 0.68]) + outcome = self.rng.choice(['remained_mam', 'death'], p=[0.7, 0.3]) if outcome == 'death': self.sim.schedule_event( event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person_id), @@ -693,7 +693,7 @@ def do_when_am_treatment(self, person_id, intervention): # cancel death date df.at[person_id, 'un_sam_death_date'] = pd.NaT else: - outcome = self.rng.choice(['remained_mam', 'death'], p=[0.32, 0.68]) + outcome = self.rng.choice(['remained_mam', 'death'], p=[0.7, 0.3]) if outcome == 'death': self.sim.schedule_event( event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person_id), From c57438f1bffc41d348527797954cb5d70be37802 Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Tue, 5 Dec 2023 17:42:27 +0200 Subject: [PATCH 022/755] Wasting Graphs --- src/scripts/wasting_analyses/analysis_wasting.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 3417a763c5..1bb2f17b8b 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -68,9 +68,6 @@ def plot_wasting_incidence(self): ax = new_df[["WHZ<-3", "-3<=WHZ<-2"]].plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], title=f"incidence of wasting in {_age} infants") - - # ax = new_df.plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], - # title=f"incidence of wasting in {_age} infants") ax.legend(self.__wasting_types_desc.values(), loc='lower right') ax.set_ylim(0, 0.04) ax.set_xlabel('year') From 5176fbc2a9781e7b904ccc7ee629c06b3be51136 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Thu, 7 Dec 2023 12:14:01 +0200 Subject: [PATCH 023/755] remove hard-corded parameters and add them to resource file, reformat graphs, address flake8 79 characters length limit --- resources/ResourceFile_Wasting.xlsx | 4 +- .../wasting_analyses/analysis_wasting.py | 130 +- src/tlo/methods/wasting.py | 1142 +++++++++++------ tests/test_wasting.py | 408 +++--- 4 files changed, 1100 insertions(+), 584 deletions(-) diff --git a/resources/ResourceFile_Wasting.xlsx b/resources/ResourceFile_Wasting.xlsx index b4e5b19824..f3ea31b1d3 100644 --- a/resources/ResourceFile_Wasting.xlsx +++ b/resources/ResourceFile_Wasting.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7dac7ad9e1578600b390cab4817f1732f19ccc5cd05c136741e0b506dcd50aff -size 11489 +oid sha256:88f8a9ed379ca3216fe2db19cef499bd6d150d40ed9233f2085e010db6f00150 +size 12511 diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 56eae98c5f..2f1555c507 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -31,12 +31,15 @@ class WastingAnalyses: - """This class looks at plotting all important outputs from the wasting module """ + """ + This class looks at plotting all important outputs from the wasting module + """ def __init__(self, log_file_path): self.__log_file_path = log_file_path # parse wasting logs - self.__logs_dict = parse_log_file(self.__log_file_path)['tlo.methods.wasting'] + self.__logs_dict = \ + parse_log_file(self.__log_file_path)['tlo.methods.wasting'] # gender description self.__gender_desc = {'M': 'Males', @@ -44,7 +47,7 @@ def __init__(self, log_file_path): # wasting types description self.__wasting_types_desc = {'WHZ<-3': 'severe wasting', - '-3≥WHZ<-2': 'moderate wasting', + '-3<=WHZ<-2': 'moderate wasting', 'WHZ>=-2': 'not undernourished'} def plot_wasting_incidence(self): @@ -52,21 +55,27 @@ def plot_wasting_incidence(self): w_inc_df = self.__logs_dict['wasting_incidence_count'] w_inc_df.set_index(w_inc_df.date.dt.year, inplace=True) w_inc_df.drop(columns='date', inplace=True) - # get age year. doesn't matter what wasting category you choose for they all have same age groups + # get age year. doesn't matter what wasting category you choose for + # they all have same age groups age_years = w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys() _row_counter = 0 _col_counter = 0 - fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True) # plot setup + # plot setup + fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True) for _age in age_years: new_df = pd.DataFrame() for state in w_inc_df.columns: - new_df[state] = w_inc_df.apply(lambda row: row[state][_age], axis=1) + new_df[state] = \ + w_inc_df.apply(lambda row: row[state][_age], axis=1) new_df = new_df.apply(lambda _row: _row / _row.sum(), axis=1) + plotting = new_df[["WHZ<-3", "-3<=WHZ<-2"]] # convert into proportions - ax = new_df.plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], - title=f"incidence of wasting in {_age} infants") + ax = plotting.plot(kind='bar', stacked=True, + ax=axes[_row_counter, _col_counter], + title=f"incidence of wasting in {_age} infants", + ylim=[0, 0.05]) ax.legend(self.__wasting_types_desc.values(), loc='lower right') ax.set_xlabel('year') ax.set_ylabel('proportions') @@ -75,42 +84,43 @@ def plot_wasting_incidence(self): _row_counter += 1 _col_counter = -1 _col_counter += 1 # increment column counter - plt.tight_layout() - - plt.show() + fig.tight_layout() def plot_wasting_prevalence(self): w_prev_df = self.__logs_dict['wasting_prevalence_count'] w_prev_df.set_index(w_prev_df.date.dt.year, inplace=True) w_prev_df.drop(columns='date', inplace=True) w_prev_df = w_prev_df.apply(lambda _row: _row / _row.sum(), axis=1) - w_prev_df.plot(kind='bar', stacked=True, title="Wasting prevalence in children 0-59 months", + w_prev_df.plot(kind='bar', stacked=True, + title="Wasting prevalence in children 0-59 months", + ylabel='proportions', + xlabel='year' ) - plt.ylabel('proportions') - plt.xlabel('year') - plt.show() def plot_modal_gbd_deaths_by_gender(self): """ compare modal and GBD deaths by gender """ - death_compare = compare_number_of_deaths(self.__log_file_path, resources) + death_compare = \ + compare_number_of_deaths(self.__log_file_path, resources) fig, axs = plt.subplots(nrows=1, ncols=2, sharey=True, sharex=True) for _col, sex in enumerate(('M', 'F')): - plot_df = death_compare.loc[(['2010-2014'], sex, slice(None), 'Childhood Wasting')].groupby('period').sum() - ax = plot_df['model'].plot.bar(label='Model', ax=axs[_col], rot=0) - ax.errorbar(x=plot_df['model'].index, y=plot_df.GBD_mean, - yerr=[plot_df.GBD_lower, plot_df.GBD_upper], + plot_df = death_compare.loc[(['2010-2014', '2015-2019'], + sex, slice(None), 'Childhood Wasting' + )].groupby('period').sum() + plotting = plot_df.loc[['2010-2014', '2015-2019']] + ax = plotting['model'].plot.bar(label='Model', ax=axs[_col], rot=0) + ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, + yerr=[plotting.GBD_lower, plotting.GBD_upper], fmt='o', color='#000', label="GBD") - # ax.set_title(f'{self.__gender_desc[sex]} mean annual deaths, 2010-2019') - ax.set_title(f'{self.__gender_desc[sex]} wasting deaths, 2010-2014') + ax.set_title(f'{self.__gender_desc[sex]} ' + f'wasting deaths, 2010-2014') ax.set_xlabel("Time period") ax.set_ylabel("Number of deaths") ax.legend(loc=2) - plt.tight_layout() - plt.savefig( - outputs / ('modal_gbd_deaths_by_gender' + datestamp + ".pdf"), format="pdf" + fig.tight_layout() + fig.savefig( + outputs / ('modal_gbd_deaths_by_gender' + datestamp + ".pdf"), + format="pdf" ) - plt.savefig(Path('.outputs')) - plt.show() seed = 1 @@ -120,12 +130,14 @@ def plot_modal_gbd_deaths_by_gender(self): outputs = Path("./outputs") # create a datestamp -datestamp = datetime.date.today().strftime("__%Y_%m_%d") + datetime.datetime.now().strftime("%H_%M_%S") +datestamp = datetime.date.today().strftime("__%Y_%m_%d") + \ + datetime.datetime.now().strftime("%H_%M_%S") # configure logging log_config = { - "filename": "wasting", # output filename. A timestamp will be added to this. - "custom_levels": { # Customise the output of specific loggers. They are applied in order: + # output filename. A timestamp will be added to this. + "filename": "wasting", + "custom_levels": { # Customise the output of specific loggers "tlo.methods.demography": logging.INFO, "tlo.methods.population": logging.INFO, "tlo.methods.wasting": logging.INFO, @@ -135,39 +147,41 @@ def plot_modal_gbd_deaths_by_gender(self): # Basic arguments required for the simulation start_date = Date(2010, 1, 1) -end_date = Date(2030, 1, 1) +end_date = Date(2030, 1, 2) pop_size = 10000 # Create simulation instance for this run. -sim = Simulation(start_date=start_date, seed=seed, log_config=log_config) - -# Register modules for simulation -sim.register( - demography.Demography(resourcefilepath=resources), - healthsystem.HealthSystem(resourcefilepath=resources, - service_availability=['*'], - cons_availability='default'), - healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resources), - healthburden.HealthBurden(resourcefilepath=resources), - symptommanager.SymptomManager(resourcefilepath=resources), - enhanced_lifestyle.Lifestyle(resourcefilepath=resources), - labour.Labour(resourcefilepath=resources), - care_of_women_during_pregnancy.CareOfWomenDuringPregnancy(resourcefilepath=resources), - contraception.Contraception(resourcefilepath=resources), - pregnancy_supervisor.PregnancySupervisor(resourcefilepath=resources), - postnatal_supervisor.PostnatalSupervisor(resourcefilepath=resources), - newborn_outcomes.NewbornOutcomes(resourcefilepath=resources), - hiv.Hiv(resourcefilepath=resources), - tb.Tb(resourcefilepath=resources), - epi.Epi(resourcefilepath=resources), - wasting.Wasting(resourcefilepath=resources), -) - -sim.make_initial_population(n=pop_size) -sim.simulate(end_date=end_date) +# sim = Simulation(start_date=start_date, seed=seed, log_config=log_config) +# +# # Register modules for simulation +# sim.register( +# demography.Demography(resourcefilepath=resources), +# healthsystem.HealthSystem(resourcefilepath=resources, +# service_availability=['*'], +# cons_availability='default'), +# healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resources), +# healthburden.HealthBurden(resourcefilepath=resources), +# symptommanager.SymptomManager(resourcefilepath=resources), +# enhanced_lifestyle.Lifestyle(resourcefilepath=resources), +# labour.Labour(resourcefilepath=resources), +# care_of_women_during_pregnancy.CareOfWomenDuringPregnancy( +# resourcefilepath=resources), +# contraception.Contraception(resourcefilepath=resources), +# pregnancy_supervisor.PregnancySupervisor(resourcefilepath=resources), +# postnatal_supervisor.PostnatalSupervisor(resourcefilepath=resources), +# newborn_outcomes.NewbornOutcomes(resourcefilepath=resources), +# hiv.Hiv(resourcefilepath=resources), +# tb.Tb(resourcefilepath=resources), +# epi.Epi(resourcefilepath=resources), +# wasting.Wasting(resourcefilepath=resources), +# ) +# +# sim.make_initial_population(n=pop_size) +# sim.simulate(end_date=end_date) # read the results -output_path = sim.log_filepath +# output_path = sim.log_filepath +output_path = Path('./outputs/wasting__2023-12-06T214307.log') # initialise the wasting class wasting_analyses = WastingAnalyses(output_path) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index ad1c221742..b792059422 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -21,20 +21,24 @@ logger.setLevel(logging.INFO) -# --------------------------------------------------------------------------------------------------------- +# --------------------------------------------------------------------------- # MODULE DEFINITIONS -# --------------------------------------------------------------------------------------------------------- +# --------------------------------------------------------------------------- class Wasting(Module): """ This module applies the prevalence of wasting at the population-level, based on the Malawi DHS Survey 2015-2016. The definitions: - - moderate wasting: weight_for_height Z-score (WHZ) <-2 SD from the reference mean - - severe wasting: weight_for_height Z-score (WHZ) <-3 SD from the reference mean + - moderate wasting: weight_for_height Z-score (WHZ) <-2 SD from the + reference mean + - severe wasting: weight_for_height Z-score (WHZ) <-3 SD from the + reference mean """ - INIT_DEPENDENCIES = {'Demography', 'SymptomManager', 'NewbornOutcomes', 'HealthBurden'} + INIT_DEPENDENCIES = {'Demography', 'SymptomManager', 'NewbornOutcomes', + 'HealthBurden' + } METADATA = { Metadata.DISEASE_MODULE, @@ -45,20 +49,24 @@ class Wasting(Module): # Declare Causes of Death CAUSES_OF_DEATH = { - 'SAM': Cause(gbd_causes='Protein-energy malnutrition', label='Childhood Wasting') + 'SAM': Cause(gbd_causes='Protein-energy malnutrition', + label='Childhood Wasting') } # Declare Causes of Death and Disability CAUSES_OF_DISABILITY = { - 'SAM': Cause(gbd_causes='Protein-energy malnutrition', label='Childhood Wasting') + 'SAM': Cause(gbd_causes='Protein-energy malnutrition', + label='Childhood Wasting') } PARAMETERS = { # prevalence of wasting by age group 'prev_WHZ_distribution_age_0_5mo': Parameter( - Types.LIST, 'distribution of WHZ among less than 6 months of age in 2015'), + Types.LIST, + 'distribution of WHZ among less than 6 months of age in 2015'), 'prev_WHZ_distribution_age_6_11mo': Parameter( - Types.LIST, 'distribution of WHZ among 6 months and 1 year of age in 2015'), + Types.LIST, + 'distribution of WHZ among 6 months and 1 year of age in 2015'), 'prev_WHZ_distribution_age_12_23mo': Parameter( Types.LIST, 'distribution of WHZ among 1 year olds in 2015'), 'prev_WHZ_distribution_age_24_35mo': Parameter( @@ -69,128 +77,218 @@ class Wasting(Module): Types.LIST, 'distribution of WHZ among 4 year olds in 2015'), # effect of risk factors on wasting prevalence 'or_wasting_hhwealth_Q5': Parameter( - Types.REAL, 'odds ratio of wasting if household wealth is poorest Q5, ref group Q1'), + Types.REAL, 'odds ratio of wasting if household wealth is ' + 'poorest Q5, ref group Q1'), 'or_wasting_hhwealth_Q4': Parameter( - Types.REAL, 'odds ratio of wasting if household wealth is poorer Q4, ref group Q1'), + Types.REAL, 'odds ratio of wasting if household wealth is ' + 'poorer Q4, ref group Q1'), 'or_wasting_hhwealth_Q3': Parameter( - Types.REAL, 'odds ratio of wasting if household wealth is middle Q3, ref group Q1'), + Types.REAL, 'odds ratio of wasting if household wealth is ' + 'middle Q3, ref group Q1'), 'or_wasting_hhwealth_Q2': Parameter( - Types.REAL, 'odds ratio of wasting if household wealth is richer Q2, ref group Q1'), + Types.REAL, 'odds ratio of wasting if household wealth is ' + 'richer Q2, ref group Q1'), 'or_wasting_preterm_and_AGA': Parameter( - Types.REAL, 'odds ratio of wasting if born preterm and adequate for gestational age'), + Types.REAL, 'odds ratio of wasting if born preterm and adequate ' + 'for gestational age'), 'or_wasting_SGA_and_term': Parameter( - Types.REAL, 'odds ratio of wasting if born term and small for geatational age'), + Types.REAL, + 'odds ratio of wasting if born term and small for gestational ' + 'age'), 'or_wasting_SGA_and_preterm': Parameter( - Types.REAL, 'odds ratio of wasting if born preterm and small for gestational age'), + Types.REAL, + 'odds ratio of wasting if born preterm and small for ' + 'gestational age'), # incidence parameters 'base_inc_rate_wasting_by_agegp': Parameter( - Types.LIST, 'List with baseline incidence of wasting by age group'), + Types.LIST, + 'List with baseline incidence of wasting by age group'), 'rr_wasting_preterm_and_AGA': Parameter( - Types.REAL, 'relative risk of wasting if born preterm and adequate for gestational age'), + Types.REAL, + 'relative risk of wasting if born preterm and adequate for ' + 'gestational age'), 'rr_wasting_SGA_and_term': Parameter( - Types.REAL, 'relative risk of wasting if born term and small for geatational age'), + Types.REAL, + 'relative risk of wasting if born term and small for ' + 'geatational age'), 'rr_wasting_SGA_and_preterm': Parameter( - Types.REAL, 'relative risk of wasting if born preterm and small for gestational age'), + Types.REAL, + 'relative risk of wasting if born preterm and small for ' + 'gestational age'), 'rr_wasting_wealth_level': Parameter( - Types.REAL, 'relative risk of wasting per 1 unit decrease in wealth level'), + Types.REAL, + 'relative risk of wasting per 1 unit decrease in wealth level'), 'min_days_duration_of_wasting': Parameter( Types.REAL, 'minimum duration in days of wasting (MAM and SAM)'), 'average_duration_of_untreated_MAM': Parameter( Types.REAL, 'average duration of untreated MAM'), # progression to severe parameters 'progression_severe_wasting_by_agegp': Parameter( - Types.LIST, 'List with progression rates to severe wasting by age group'), + Types.LIST, + 'List with progression rates to severe wasting by age group'), 'average_duration_of_untreated_SAM': Parameter( Types.REAL, 'average duration of untreated SAM'), 'prob_complications_in_SAM': Parameter( Types.REAL, 'probability of medical complications in SAM '), # recovery parameters 'recovery_rate_with_standard_RUTF': Parameter( - Types.REAL, 'probability of recovery from wasting following treatment with standard RUTF'), + Types.REAL, + 'probability of recovery from wasting following treatment with ' + 'standard RUTF'), 'recovery_rate_with_soy_RUSF': Parameter( - Types.REAL, 'probability of recovery from wasting following treatment with soy RUSF'), + Types.REAL, + 'probability of recovery from wasting following treatment with ' + 'soy RUSF'), 'recovery_rate_with_CSB++': Parameter( - Types.REAL, 'probability of recovery from wasting following treatment with CSB++'), + Types.REAL, + 'probability of recovery from wasting following treatment with ' + 'CSB++'), 'recovery_rate_with_inpatient_care': Parameter( - Types.REAL, 'probability of recovery from wasting following treatment with inpatient care'), + Types.REAL, + 'probability of recovery from wasting following treatment with ' + 'inpatient care'), # MUAC distributions 'MUAC_distribution_WHZ<-3': Parameter( - Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ<-3'), + Types.LIST, + 'mean and standard deviation of a normal distribution of MUAC ' + 'measurements for WHZ<-3'), 'MUAC_distribution_-3<=WHZ<-2': Parameter( - Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for -3<=WHZ<-2'), + Types.LIST, + 'mean and standard deviation of a normal distribution of MUAC ' + 'measurements for -3<=WHZ<-2'), 'MUAC_distribution_WHZ>=-2': Parameter( - Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ>=-2'), + Types.LIST, + 'mean and standard deviation of a normal distribution of MUAC ' + 'measurements for WHZ>=-2'), 'proportion_WHZ<-3_with_MUAC<115mm': Parameter( - Types.REAL, 'proportion of severe weight-for-height Z-score with MUAC<115mm'), + Types.REAL, + 'proportion of severe weight-for-height Z-score with MUAC<115mm'), 'proportion_-3<=WHZ<-2_with_MUAC<115mm': Parameter( - Types.REAL, 'proportion of moderate weight-for-height Z-score with MUAC<115mm'), + Types.REAL, + 'proportion of moderate weight-for-height Z-score with ' + 'MUAC<115mm'), 'proportion_-3<=WHZ<-2_with_MUAC_115-<125mm': Parameter( - Types.REAL, 'proportion of moderate weight-for-height Z-score with MUAC between 115mm and 125mm'), + Types.REAL, + 'proportion of moderate weight-for-height Z-score with MUAC ' + 'between 115mm and 125mm'), 'proportion_mam_with_MUAC_115-<125mm_and_normal_whz': Parameter( - Types.REAL, 'proportion of mam cases with MUAC between 115mm and 125mm and normal/mild WHZ'), + Types.REAL, + 'proportion of mam cases with MUAC between 115mm and 125mm and ' + 'normal/mild WHZ'), 'proportion_mam_with_MUAC_115-<125mm_and_-3<=WHZ<-2': Parameter( - Types.REAL, 'proportion of mam cases with both MUAC between 115mm and 125mm and moderate wasting'), + Types.REAL, + 'proportion of mam cases with both MUAC between 115mm and ' + '125mm and moderate wasting'), 'proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC': Parameter( - Types.REAL, 'proportion of mam cases with moderate wasting and normal MUAC'), + Types.REAL, + 'proportion of mam cases with moderate wasting and normal MUAC'), # bilateral oedema 'prevalence_nutritional_oedema': Parameter( - Types.REAL, 'prevalence of nutritional oedema in children under 5 in Malawi'), + Types.REAL, + 'prevalence of nutritional oedema in children under 5 in Malawi'), 'proportion_oedema_with_WHZ<-2': Parameter( - Types.REAL, 'proportion of oedematous malnutrition with concurrent wasting'), + Types.REAL, + 'proportion of oedematous malnutrition with concurrent wasting'), # death CFR, risk factors 'base_death_rate_untreated_SAM': Parameter( Types.REAL, 'baseline death rate of untreated SAM'), 'rr_SAM_death_with_complications': Parameter( Types.REAL, 'relative rate of death for complicated SAM'), 'rr_SAM_death_WHZ<-3_only': Parameter( - Types.REAL, 'relative risk of death from SAM if indices of WHZ<-3, compared to MUAC<115mm'), + Types.REAL, + 'relative risk of death from SAM if indices of WHZ<-3, ' + 'compared to MUAC<115mm'), 'rr_SAM_death_both_WHZ<-3_&_MUAC<115mm': Parameter( - Types.REAL, 'relative risk of death from SAM if both indices WHZ<-3 & MUAC<115mm are present, ' - 'compared to MUAC<115mm alone'), + Types.REAL, + 'relative risk of death from SAM if both indices WHZ<-3 & ' + 'MUAC<115mm are present, ' + 'compared to MUAC<115mm alone'), 'rr_SAM_death_kwashiorkor_only': Parameter( - Types.REAL, 'relative risk of death from SAM if bilateral oedema present (kwashiorkor), ' - 'compared to MUAC<115mm alone'), + Types.REAL, + 'relative risk of death from SAM if bilateral oedema present (' + 'kwashiorkor), ' + 'compared to MUAC<115mm alone'), 'rr_SAM_death_kwashiorkor_MUAC<115mm_only': Parameter( - Types.REAL, 'relative risk of death from SAM if bilateral oedema present and MUAC<115mm, ' - 'compared to MUAC<115mm alone'), + Types.REAL, + 'relative risk of death from SAM if bilateral oedema present ' + 'and MUAC<115mm, ' + 'compared to MUAC<115mm alone'), 'rr_SAM_death_kwashiorkor_WHZ<-3_only': Parameter( - Types.REAL, 'relative risk of death from SAM if bilateral oedema present and WHZ<-3, ' - 'compared to MUAC<115mm alone'), + Types.REAL, + 'relative risk of death from SAM if bilateral oedema present ' + 'and WHZ<-3, ' + 'compared to MUAC<115mm alone'), 'rr_SAM_death_kwashiorkor_both_WHZ<-3_&_MUAC<115mm': Parameter( - Types.REAL, 'relative risk of death from SAM if bilateral oedema present, WHZ<-3 and MUAC<115mm, ' - 'compared to MUAC<115mm alone'), + Types.REAL, + 'relative risk of death from SAM if bilateral oedema present, ' + 'WHZ<-3 and MUAC<115mm, ' + 'compared to MUAC<115mm alone'), # treatment parameters 'coverage_supplementary_feeding_program': Parameter( - Types.REAL, 'coverage of supplementary feeding program for MAM in health centres'), + Types.REAL, + 'coverage of supplementary feeding program for MAM in health ' + 'centres'), 'coverage_outpatient_therapeutic_care': Parameter( - Types.REAL, 'coverage of outpatient therapeutic care for SAM in health centres'), + Types.REAL, + 'coverage of outpatient therapeutic care for SAM in health ' + 'centres'), 'coverage_inpatient_care': Parameter( - Types.REAL, 'coverage of inpatient care for complicated SAM in hospitals'), + Types.REAL, + 'coverage of inpatient care for complicated SAM in hospitals'), + 'prob_mam_death_after_care': Parameter( + Types.LIST, + 'probability of dying or returning to MAM after seeking care'), } PROPERTIES = { # Properties related to wasting 'un_ever_wasted': Property(Types.BOOL, 'had wasting before WHZ <-2'), - 'un_WHZ_category': Property(Types.CATEGORICAL, 'weight-for-height z-score group', - categories=['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2']), - 'un_last_wasting_date_of_onset': Property(Types.DATE, 'date of onset of latest wasting episode'), + 'un_WHZ_category': Property(Types.CATEGORICAL, + 'weight-for-height z-score group', + categories=['WHZ<-3', '-3<=WHZ<-2', + 'WHZ>=-2']), + 'un_last_wasting_date_of_onset': Property(Types.DATE, + 'date of onset of latest ' + 'wasting episode'), # Properties related to clinical acute malnutrition - 'un_clinical_acute_malnutrition': Property(Types.CATEGORICAL, 'clinical acute malnutrition state based on WHZ', - categories=['MAM', 'SAM'] + ['well']), - 'un_am_bilateral_oedema': Property(Types.BOOL, 'bilateral oedema present in wasting'), - 'un_am_MUAC_category': Property(Types.CATEGORICAL, 'MUAC measurement categories', - categories=['<115mm', '115-<125mm', '>=125mm']), - 'un_sam_with_complications': Property(Types.BOOL, 'medical complications in SAM'), - 'un_sam_death_date': Property(Types.DATE, 'death date from severe acute malnutrition'), - 'un_am_recovery_date': Property(Types.DATE, 'recovery date from acute malnutrition'), - 'un_am_discharge_date': Property(Types.DATE, 'discharge date from treatment of MAM/ SAM'), - 'un_acute_malnutrition_tx_start_date': Property(Types.DATE, 'intervention start date'), - 'un_am_treatment_type': Property(Types.CATEGORICAL, 'treatment types for acute malnutrition', - categories=['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care'] + - ['none', 'not_applicable']), + 'un_clinical_acute_malnutrition': Property(Types.CATEGORICAL, + 'clinical acute ' + 'malnutrition state ' + 'based on WHZ', + categories=['MAM', + 'SAM'] + [ + 'well']), + 'un_am_bilateral_oedema': Property(Types.BOOL, + 'bilateral oedema present in ' + 'wasting'), + 'un_am_MUAC_category': Property(Types.CATEGORICAL, + 'MUAC measurement categories', + categories=['<115mm', '115-<125mm', + '>=125mm']), + 'un_sam_with_complications': Property(Types.BOOL, + 'medical complications in SAM'), + 'un_sam_death_date': Property(Types.DATE, + 'death date from severe acute ' + 'malnutrition'), + 'un_am_recovery_date': Property(Types.DATE, + 'recovery date from acute ' + 'malnutrition'), + 'un_am_discharge_date': Property(Types.DATE, + 'discharge date from treatment of ' + 'MAM/ SAM'), + 'un_acute_malnutrition_tx_start_date': Property(Types.DATE, + 'intervention ' + 'start date'), + 'un_am_treatment_type': Property(Types.CATEGORICAL, + 'treatment types for acute ' + 'malnutrition', + categories=['standard_RUTF', + 'soy_RUSF', 'CSB++', + 'inpatient_care'] + [ + 'none', 'not_applicable']), } wasting_states = ['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2'] @@ -209,41 +307,51 @@ def __init__(self, name=None, resourcefilepath=None): # 'dehydration' } - # dict to hold counters for the number of episodes by wasting-type and age-group - blank_counter = dict(zip(self.wasting_states, [list() for _ in self.wasting_states])) + # dict to hold counters for the number of episodes by wasting-type + # and age-group + blank_counter = dict( + zip(self.wasting_states, [list() for _ in self.wasting_states])) self.wasting_incident_case_tracker_blank = { - _agrp: copy.deepcopy(blank_counter) for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} + _agrp: copy.deepcopy(blank_counter) for _agrp in + ['0y', '1y', '2y', '3y', '4y', '5+y']} - self.wasting_incident_case_tracker = copy.deepcopy(self.wasting_incident_case_tracker_blank) + self.wasting_incident_case_tracker = copy.deepcopy( + self.wasting_incident_case_tracker_blank) # wasting prevalence odds by age groups self.wasting_prevalence_odds_by_age_grp: dict = dict() # wasting prevalence scaling by age group self.age_grps_dict: dict = {_agrp: 1.0 for _agrp in - ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo']} + ['0_5mo', '6_11mo', '12_23mo', '24_35mo', + '36_47mo', '48_59mo']} # store severe wasting by age groups probabilities self.age_grps_sev_wasting_probs: dict = dict() def read_parameters(self, data_folder): """ - :param data_folder: path of a folder supplied to the Simulation containing data files. - Typically, modules would read a particular file within here. + :param data_folder: path of a folder supplied to the Simulation + containing data files. + + Typically, modules would read a particular file within here. :return: """ # Update parameters from the resource dataframe # Read parameters from the resourcefile self.load_parameters_from_dataframe( - pd.read_excel(Path(self.resourcefilepath) / 'ResourceFile_Wasting.xlsx', - sheet_name='Parameter_values_AM')) + pd.read_excel( + Path(self.resourcefilepath) / 'ResourceFile_Wasting.xlsx', + sheet_name='Parameter_values_AM')) - # Declare symptoms that this module will cause and which are not included in the generic symptoms: + # Declare symptoms that this module will cause and which are not + # included in the generic symptoms: generic_symptoms = self.sim.modules['SymptomManager'].generic_symptoms for symptom_name in self.symptoms: if symptom_name not in generic_symptoms: self.sim.modules['SymptomManager'].register_symptom( - Symptom(name=symptom_name) # (give non-generic symptom 'average' healthcare seeking) + Symptom(name=symptom_name) + # (give non-generic symptom 'average' healthcare seeking) ) def pre_initialise_population(self): @@ -256,9 +364,10 @@ def initialise_population(self, population): """ Set our property values for the initial population. - This method is called by the simulation when creating the initial population, and is - responsible for assigning initial values, for every individual, of those properties - 'owned' by this module, i.e. those declared in the PROPERTIES dictionary above. + This method is called by the simulation when creating the initial + population, and is responsible for assigning initial values, + for every individual, of those properties 'owned' by this module, + i.e. those declared in the PROPERTIES dictionary above. :param population: :return: @@ -267,7 +376,8 @@ def initialise_population(self, population): # Set initial properties df.loc[df.is_alive, 'un_ever_wasted'] = False - df.loc[df.is_alive, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished + df.loc[ + df.is_alive, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' df.loc[df.is_alive, 'un_last_wasting_date_of_onset'] = pd.NaT df.loc[df.is_alive, 'un_acute_malnutrition_tx_start_date'] = pd.NaT @@ -286,31 +396,43 @@ def initialise_population(self, population): wasting_prevalence = self.wasting_models.get_wasting_prevalence() # Assign wasting categories in young children at initiation - for agegp in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months + for agegp in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), + (48, 59)]: # in months low_bound_age_in_years = agegp[0] / 12.0 high_bound_age_in_years = (1 + agegp[1]) / 12.0 - lm_ext_var = f'{agegp[0]}_{agegp[1]}mo' # linear model external variables + # linear model external variables + lm_ext_var = f'{agegp[0]}_{agegp[1]}mo' mask = (df.is_alive & - df.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, inclusive='left') + df.age_exact_years.between(low_bound_age_in_years, + high_bound_age_in_years, + inclusive='left') ) - prevalence_of_wasting = wasting_prevalence.predict(df.loc[mask], agrp='None', agrp_scaling=lm_ext_var) + prevalence_of_wasting = \ + wasting_prevalence.predict(df.loc[mask], agrp='None', + agrp_scaling=lm_ext_var) # categorize into moderate (-3<=WHZ<-2) or severe (WHZ<-3) wasting - wasted = self.rng.random_sample(len(prevalence_of_wasting)) < prevalence_of_wasting + wasted = self.rng.random_sample( + len(prevalence_of_wasting)) < prevalence_of_wasting for idx in prevalence_of_wasting.index[wasted]: - probability_of_severe = self.age_grps_sev_wasting_probs[lm_ext_var] - wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], - p=[probability_of_severe, 1 - probability_of_severe]) + probability_of_severe = self.age_grps_sev_wasting_probs[ + lm_ext_var] + wasted_category = \ + self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], + p=[probability_of_severe, + 1 - probability_of_severe]) df.at[idx, 'un_WHZ_category'] = wasted_category df.at[idx, 'un_last_wasting_date_of_onset'] = self.sim.date df.at[idx, 'un_ever_wasted'] = True - df.at[idx, 'un_am_treatment_type'] = 'none' # start without treatment + # start without treatment + df.at[idx, 'un_am_treatment_type'] = 'none' # update clinical symptoms for severe wasting self.wasting_clinical_symptoms(person_id=idx) - # ----------------------------------------------------------------------------------------------------- - # # # # # # Give MUAC category, presence of oedema, and determine acute malnutrition state # # # # # + # ------------------------------------------------------------------ + # # # # # # Give MUAC category, presence of oedema, and determine + # acute malnutrition state # # # # # self.population_poll_clinical_am(df) def initialise_simulation(self, sim): @@ -320,10 +442,12 @@ def initialise_simulation(self, sim): """ # schedule wasting pool event - sim.schedule_event(WastingPollingEvent(self), sim.date + DateOffset(months=3)) + sim.schedule_event(WastingPollingEvent(self), + sim.date + DateOffset(months=3)) # schedule wasting logging event - sim.schedule_event(WastingLoggingEvent(self), sim.date + DateOffset(months=12)) + sim.schedule_event(WastingLoggingEvent(self), + sim.date + DateOffset(months=12)) def on_birth(self, mother_id, child_id): """Initialise properties for a newborn individual. @@ -347,85 +471,114 @@ def on_birth(self, mother_id, child_id): def muac_cutoff_by_WHZ(self, idx, whz): """ Proportion of MUAC<115mm in WHZ<-3 and -3<=WHZ<-2, - and proportion of wasted children with oedematous malnutrition (Kwashiokor, marasmic-kwashiorkor) + and proportion of wasted children with oedematous malnutrition ( + Kwashiokor, marasmic-kwashiorkor) + :param idx: index of children ages 6-59 months or person_id - :param whz: - :return: + :param whz: weight for height category """ df = self.sim.population.props p = self.parameters - # ---------- MUAC <115mm in severe wasting (WHZ<-3) and moderate (-3<=WHZ<-2) ---------- + # -- MUAC <115mm in severe wasting (WHZ<-3) and moderate (-3<=WHZ<-2)-- if whz == 'WHZ<-3': # apply probability of MUAC<115mm in severe wasting - low_muac_in_severe_wasting = self.rng.random_sample(size=len(idx)) < p['proportion_WHZ<-3_with_MUAC<115mm'] + low_muac_in_severe_wasting = self.rng.random_sample( + size=len(idx)) < p['proportion_WHZ<-3_with_MUAC<115mm'] - df.loc[idx[low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '<115mm' + df.loc[idx[ + low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '<115mm' # other severe wasting will have MUAC between 115-<125mm - df.loc[idx[~low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '115-<125mm' + df.loc[idx[ + ~low_muac_in_severe_wasting], 'un_am_MUAC_category'] = \ + '115-<125mm' if whz == '-3<=WHZ<-2': # apply probability of MUAC<115mm in moderate wasting - low_muac_in_moderate_wasting = self.rng.random_sample(size=len(idx)) < p[ - 'proportion_-3<=WHZ<-2_with_MUAC<115mm'] - df.loc[idx[low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = '<115mm' + low_muac_in_moderate_wasting = self.rng.random_sample( + size=len(idx)) < p['proportion_-3<=WHZ<-2_with_MUAC<115mm'] + df.loc[idx[ + low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = \ + '<115mm' # apply probability of MUAC between 115-<125mm in moderate wasting - moderate_low_muac_in_moderate_wasting = self.rng.random_sample(size=len( - idx[~low_muac_in_moderate_wasting])) < p['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] - df.loc[idx[~low_muac_in_moderate_wasting][moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = \ - '115-<125mm' + moderate_low_muac_in_moderate_wasting = self.rng.random_sample( + size=len( + idx[~low_muac_in_moderate_wasting])) < p[ + 'proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] + df.loc[idx[~low_muac_in_moderate_wasting][ + moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category']\ + = '115-<125mm' # other moderate wasting will have normal MUAC - df.loc[idx[~low_muac_in_moderate_wasting][~moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] \ - = '>=125mm' + df.loc[idx[~low_muac_in_moderate_wasting][ + ~moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category' + ] = '>=125mm' if whz == 'WHZ>=-2': # Give MUAC distribution for WHZ>=-2 ('well' group) --------- - muac_distribution_in_well_group = norm(loc=p['MUAC_distribution_WHZ>=-2'][0], - scale=p['MUAC_distribution_WHZ>=-2'][1]) + muac_distribution_in_well_group = norm( + loc=p['MUAC_distribution_WHZ>=-2'][0], + scale=p['MUAC_distribution_WHZ>=-2'][1]) # get probability of MUAC <115mm - probability_over_or_equal_115 = muac_distribution_in_well_group.sf(11.5) - probability_over_or_equal_125 = muac_distribution_in_well_group.sf(12.5) + probability_over_or_equal_115 = muac_distribution_in_well_group.sf( + 11.5) + probability_over_or_equal_125 = muac_distribution_in_well_group.sf( + 12.5) prob_less_than_115 = 1 - probability_over_or_equal_115 - pro_between_115_125 = probability_over_or_equal_115 - probability_over_or_equal_125 + pro_between_115_125 = \ + probability_over_or_equal_115 - probability_over_or_equal_125 for id in idx: muac_cat = self.rng.choice(['<115mm', '115-<125mm', '>=125mm'], - p=[prob_less_than_115, pro_between_115_125, probability_over_or_equal_125]) + p=[prob_less_than_115, + pro_between_115_125, + probability_over_or_equal_125]) df.at[id, 'un_am_MUAC_category'] = muac_cat def nutritional_oedema_present(self, idx): """ - This function applies the probability of bilateral oedema present in wasting and non-wasted cases + This function applies the probability of bilateral oedema present + in wasting and non-wasted cases :param idx: index of children under 5, or person_id :return: """ df = self.sim.population.props p = self.parameters - # Knowing the prevalence of nutritional oedema in under 5 population, apply the probability of oedema in WHZ<-2 + # Knowing the prevalence of nutritional oedema in under 5 + # population, apply the probability of oedema in WHZ<-2 # get those children with wasting - children_with_wasting = idx.intersection(df.index[df.un_WHZ_category != 'WHZ>=-2']) - children_without_wasting = idx.intersection(df.index[df.un_WHZ_category == 'WHZ>=-2']) + children_with_wasting = idx.intersection( + df.index[df.un_WHZ_category != 'WHZ>=-2']) + children_without_wasting = idx.intersection( + df.index[df.un_WHZ_category == 'WHZ>=-2']) # oedema among wasted children oedema_in_wasted_children = self.rng.random_sample(size=len( - children_with_wasting)) < p['prevalence_nutritional_oedema'] * p['proportion_oedema_with_WHZ<-2'] - df.loc[children_with_wasting[oedema_in_wasted_children], 'un_am_bilateral_oedema'] = True - df.loc[children_with_wasting[~oedema_in_wasted_children], 'un_am_bilateral_oedema'] = False + children_with_wasting)) < p['prevalence_nutritional_oedema'] * p[ + 'proportion_oedema_with_WHZ<-2'] + df.loc[children_with_wasting[ + oedema_in_wasted_children], 'un_am_bilateral_oedema'] = True + df.loc[children_with_wasting[ + ~oedema_in_wasted_children], 'un_am_bilateral_oedema'] = False # oedema among non-wasted children oedema_in_non_wasted = self.rng.random_sample(size=len( - children_without_wasting)) < p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) - df.loc[children_without_wasting[oedema_in_non_wasted], 'un_am_bilateral_oedema'] = True - df.loc[children_without_wasting[~oedema_in_non_wasted], 'un_am_bilateral_oedema'] = False + children_without_wasting)) < p['prevalence_nutritional_oedema'] * ( + 1 - p['proportion_oedema_with_WHZ<-2']) + df.loc[children_without_wasting[ + oedema_in_non_wasted], 'un_am_bilateral_oedema'] = True + df.loc[children_without_wasting[ + ~oedema_in_non_wasted], 'un_am_bilateral_oedema'] = False def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): """ - This function will determine the clinical acute malnutrition status (MAM, SAM) based on anthropometric indices + This function will determine the clinical acute malnutrition status + (MAM, SAM) based on anthropometric indices and presence of bilateral oedema (Kwashiorkor); - And help determine whether the individual will have medical complications, applicable to SAM cases only, + And help determine whether the individual will have medical + complications, applicable to SAM cases only, requiring inpatient care. :param person_id: individual id :param pop_dataframe: population dataframe @@ -436,17 +589,18 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): # check if person is not wasted if ( - (df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2') & - (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & - (~df.at[person_id, 'un_am_bilateral_oedema']) + (df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2') & + (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & + (~df.at[person_id, 'un_am_bilateral_oedema']) ): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' - # severe acute malnutrition - MUAC<115mm and/or WHZ<-3 and/or bilateral oedema + # severe acute malnutrition - MUAC<115mm and/or WHZ<-3 and/or + # bilateral oedema elif ( - (df.at[person_id, 'un_am_MUAC_category'] == '<115mm') | - (df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3') | - (df.at[person_id, 'un_am_bilateral_oedema']) + (df.at[person_id, 'un_am_MUAC_category'] == '<115mm') | + (df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3') | + (df.at[person_id, 'un_am_bilateral_oedema']) ): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' @@ -462,12 +616,14 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): else: df.at[person_id, 'un_sam_with_complications'] = False - assert not (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') & \ - (df.at[person_id, 'un_sam_with_complications']) + assert not (df.at[ + person_id, 'un_clinical_acute_malnutrition'] == + 'MAM') & (df.at[person_id, 'un_sam_with_complications']) def date_of_outcome_for_untreated_am(self, person_id, duration_am): """ - helper funtion to get the duration and the wasting episode and date of outcome (recovery, progression, or death) + helper funtion to get the duration and the wasting episode and + date of outcome (recovery, progression, or death) :param person_id: :param duration_am: :return: @@ -475,61 +631,77 @@ def date_of_outcome_for_untreated_am(self, person_id, duration_am): df = self.sim.population.props p = self.parameters - # moderate wasting (for progression to severe, or recovery from MAM) ----- + # moderate wasting (for progression to severe, or recovery from + # MAM) ----- if duration_am == 'MAM': # Allocate the duration of the moderate wasting episode - duration_mam = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'])) + duration_mam = int(max(p['min_days_duration_of_wasting'], + p['average_duration_of_untreated_MAM'])) # Allocate a date of outcome (progression, recovery or death) - date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_mam) + date_of_outcome = df.at[person_id, + 'un_last_wasting_date_of_onset'] + \ + DateOffset(days=duration_mam) return date_of_outcome # severe wasting (for death, or recovery to moderate wasting) ----- if duration_am == 'SAM': # determine the duration of SAM episode - duration_sam = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'] + + duration_sam = int(max(p['min_days_duration_of_wasting'], + p['average_duration_of_untreated_MAM'] + p['average_duration_of_untreated_SAM'])) # Allocate a date of outcome (progression, recovery or death) - date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_sam) + date_of_outcome = df.at[ + person_id, 'un_last_wasting_date_of_onset'] +\ + DateOffset(days=duration_sam) return date_of_outcome def population_poll_clinical_am(self, population): """ - Update at the population level other anthropometric indices and clinical signs - (MUAC, oedema, medical complications) that determine the clinical state of acute malnutrition - This will include both wasted and non-wasted children with other signs of acute malnutrition + Update at the population level other anthropometric indices and + clinical signs (MUAC, oedema, medical complications) that determine + the clinical state of acute malnutrition + This will include both wasted and non-wasted children with other + signs of acute malnutrition :param population: :return: """ df = population - # give MUAC measurement category for all WHZ, including well nourished children ----- + # give MUAC measurement category for all WHZ, including well + # nourished children ----- for whz in ['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2']: - index_6_59mo_by_whz = df.index[df.is_alive & (df.age_exact_years.between(0.5, 5, inclusive='left')) + index_6_59mo_by_whz = df.index[df.is_alive & ( + df.age_exact_years.between(0.5, 5, inclusive='left')) & (df.un_WHZ_category == whz)] self.muac_cutoff_by_WHZ(idx=index_6_59mo_by_whz, whz=whz) - # determine the presence of bilateral oedema / oedematous malnutrition ----- + # determine the presence of bilateral oedema / oedematous malnutrition index_under5 = df.index[df.is_alive & (df.age_exact_years < 5)] self.nutritional_oedema_present(idx=index_under5) # determine the clinical acute malnutrition state ----- df = self.sim.population.props for person_id in index_under5: - self.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) + self.clinical_acute_malnutrition_state(person_id=person_id, + pop_dataframe=df) def on_hsi_alert(self, person_id, treatment_id): """ - This is called whenever there is an HSI event commissioned by one of the other disease modules. + This is called whenever there is an HSI event commissioned by one + of the other disease modules. """ logger.debug(key='message', - data=f'This is Wasting, being alerted about a health system interaction for person' + data=f'This is Wasting, being alerted about a health ' + f'system interaction for person' f'{person_id} and treatment {treatment_id}') def report_daly_values(self): """ - This must send back a pd.Series or pd.DataFrame that reports on the average daly-weights that have been - experienced by persons in the previous month. Only rows for alive-persons must be returned. - The names of the series of columns is taken to be the label of the cause of this disability. + This must send back a pd.Series or pd.DataFrame that reports on the + average daly-weights that have been experienced by persons in the + previous month. Only rows for alive-persons must be returned. + The names of the series of columns is taken to be the label of the + cause of this disability. It will be recorded by the healthburden module as _. """ # dict to hold the DALY weights @@ -540,19 +712,23 @@ def report_daly_values(self): # Get DALY weights get_daly_weight = self.sim.modules['HealthBurden'].get_daly_weight - # self.daly_wts['MAM_w/o_oedema'] = get_daly_weight(sequlae_code=460) ## no value given daly_wts['MAM_with_oedema'] = get_daly_weight(sequlae_code=461) daly_wts['SAM_w/o_oedema'] = get_daly_weight(sequlae_code=462) daly_wts['SAM_with_oedema'] = get_daly_weight(sequlae_code=463) - total_daly_values = pd.Series(data=0.0, index=df.index[df.is_alive]) - total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & - df.un_am_bilateral_oedema] = daly_wts['SAM_with_oedema'] - total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & - (~df.un_am_bilateral_oedema)] = daly_wts['SAM_w/o_oedema'] + total_daly_values = pd.Series(data=0.0, + index=df.index[df.is_alive]) + total_daly_values.loc[ + df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & + df.un_am_bilateral_oedema] = daly_wts['SAM_with_oedema'] + total_daly_values.loc[ + df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & + (~df.un_am_bilateral_oedema)] = daly_wts['SAM_w/o_oedema'] total_daly_values.loc[df.is_alive & ( - ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | - ((df.un_WHZ_category != 'WHZ<-3') & (df.un_am_MUAC_category != "115-<125mm")) + ((df.un_WHZ_category == '-3<=WHZ<-2') & ( + df.un_am_MUAC_category != "<115mm")) | + ((df.un_WHZ_category != 'WHZ<-3') & ( + df.un_am_MUAC_category != "115-<125mm")) ) & df.un_am_bilateral_oedema] = daly_wts['MAM_with_oedema'] return total_daly_values @@ -578,7 +754,8 @@ def wasting_clinical_symptoms(self, person_id): def do_when_acute_malnutrition_assessment(self, person_id): """ - This is called by the generic HSI event when acute malnutrition is checked. + This is called by the generic HSI event when acute malnutrition is + checked. :param person_id: :return: """ @@ -593,7 +770,8 @@ def do_when_acute_malnutrition_assessment(self, person_id): # Interventions for MAM if clinical_am == 'MAM': # Check for coverage of supplementary feeding - if self.rng.random_sample() < p['coverage_supplementary_feeding_program']: + if self.rng.random_sample() < p[ + 'coverage_supplementary_feeding_program']: # schedule HSI for supplementary feeding program for MAM self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM @@ -608,14 +786,13 @@ def do_when_acute_malnutrition_assessment(self, person_id): if clinical_am == 'SAM': if not complications: # Check for coverage of outpatient therapeutic care - if self.rng.random_sample() < p['coverage_outpatient_therapeutic_care']: + if self.rng.random_sample() < p[ + 'coverage_outpatient_therapeutic_care']: # schedule HSI for supplementary feeding program for MAM self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=HSI_Wasting_OutpatientTherapeuticProgramme_SAM - (module=self, - person_id=person_id), - priority=0, - topen=self.sim.date + hsi_event=HSI_Wasting_OutpatientTherapeuticProgramme_SAM + (module=self, person_id=person_id), priority=0, + topen=self.sim.date ) else: return @@ -636,7 +813,8 @@ def do_when_acute_malnutrition_assessment(self, person_id): def do_when_am_treatment(self, person_id, intervention): """ - This function will apply the linear model of recovery based on intervention given + This function will apply the linear model of recovery based on + intervention given :param person_id: :param intervention: :return: @@ -647,69 +825,104 @@ def do_when_am_treatment(self, person_id, intervention): if intervention == 'SFP': mam_recovery = \ - self.wasting_models.get_moderate_acute_malnutrition_recovery().predict(df.loc[[person_id]], self.rng) + self.wasting_models.get_moderate_acute_malnutrition_recovery( + ).predict( + df.loc[[person_id]], self.rng) if mam_recovery: # schedule recovery date self.sim.schedule_event( - event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) + event=ClinicalAcuteMalnutritionRecoveryEvent( + module=self, person_id=person_id), + date=df.at[ + person_id, + 'un_acute_malnutrition_tx_start_date'] + + DateOffset(weeks=3)) # cancel progression date (in ProgressionEvent) else: # remained MAM return if intervention == 'OTC': - sam_recovery = self.wasting_models.get_severe_acute_malnutrition_recovery().predict( - df.loc[[person_id]], self.rng) + sam_recovery = \ + self.wasting_models.get_severe_acute_malnutrition_recovery( + ).predict(df.loc[[person_id]], self.rng) if sam_recovery: # schedule recovery date self.sim.schedule_event( - event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) + event=ClinicalAcuteMalnutritionRecoveryEvent( + module=self, person_id=person_id), + date=df.at[ + person_id, 'un_acute_malnutrition_tx_start_date'] + + DateOffset(weeks=3)) # cancel death date df.at[person_id, 'un_sam_death_date'] = pd.NaT else: - outcome = self.rng.choice(['remained_mam', 'death'], p=[0.32, 0.68]) + outcome = self.rng.choice(['remained_mam', 'death'], + p=self.parameters[ + 'prob_mam_death_after_care']) if outcome == 'death': self.sim.schedule_event( - event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) + event=SevereAcuteMalnutritionDeathEvent( + module=self, person_id=person_id), + date=df.at[ + person_id, + 'un_acute_malnutrition_tx_start_date'] + + DateOffset(weeks=3)) else: self.sim.schedule_event( event=UpdateToMAM(module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) + date=df.at[ + person_id, + 'un_acute_malnutrition_tx_start_date'] + + DateOffset(weeks=3)) if intervention == 'ITC': - sam_recovery = self.wasting_models.get_severe_acute_malnutrition_recovery().predict( - df.loc[[person_id]], self.rng) + sam_recovery = \ + self.wasting_models.get_severe_acute_malnutrition_recovery( + ).predict(df.loc[[person_id]], self.rng) if sam_recovery: # schedule recovery date self.sim.schedule_event( - event=ClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=4)) + event=ClinicalAcuteMalnutritionRecoveryEvent( + module=self, person_id=person_id), + date=df.at[ + person_id, + 'un_acute_malnutrition_tx_start_date'] + + DateOffset(weeks=4)) # cancel death date df.at[person_id, 'un_sam_death_date'] = pd.NaT else: - outcome = self.rng.choice(['remained_mam', 'death'], p=[0.32, 0.68]) + outcome = self.rng.choice(['remained_mam', 'death'], + p=self.parameters[ + 'prob_mam_death_after_care']) if outcome == 'death': self.sim.schedule_event( - event=SevereAcuteMalnutritionDeathEvent(module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=4)) + event=SevereAcuteMalnutritionDeathEvent( + module=self, person_id=person_id), + date=df.at[ + person_id, + 'un_acute_malnutrition_tx_start_date'] + + DateOffset(weeks=4)) else: self.sim.schedule_event( event=UpdateToMAM(module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=4)) + date=df.at[ + person_id, + 'un_acute_malnutrition_tx_start_date'] + + DateOffset(weeks=4)) class WastingPollingEvent(RegularEvent, PopulationScopeEventMixin): """ - Regular event that determines new cases of wasting (WHZ<-2) to the under-5 population, - and schedules individual incident cases to represent onset. - It determines those who will progress to severe wasting (WHZ<-3) and schedules the event to update on properties. - These are events occurring without the input of interventions, these events reflect the natural history only. + Regular event that determines new cases of wasting (WHZ<-2) to the + under-5 population, and schedules individual incident cases to + represent onset. It determines those who will progress to + severe wasting (WHZ<-3) and schedules the event to update on properties. + These are events occurring without the input of interventions, these + events reflect the natural history only. """ AGE_GROUPS = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} @@ -718,7 +931,8 @@ def __init__(self, module): :param module: the module that created this event """ self.repeat_months = 1 - super().__init__(module, frequency=DateOffset(months=self.repeat_months)) + super().__init__(module, + frequency=DateOffset(months=self.repeat_months)) assert isinstance(module, Wasting) def apply(self, population): @@ -728,81 +942,107 @@ def apply(self, population): df = population.props rng = self.module.rng - # # # # # # # # # # # # # # # # # # # # # INCIDENCE OF WASTING # # # # # # # # # # # # # # # # # # # # # - # Determine who will be onset with wasting among those who are not currently wasted ------------- - inc_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == 'WHZ>=-2')] - get_incidence_of_wasting = self.module.wasting_models.get_wasting_incidence(inc_wasting) + # # # INCIDENCE OF WASTING # # # # # # # # # # # # # # # # # # # # # + # Determine who will be onset with wasting among those who are not + # currently wasted ------------- + inc_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & ( + df.un_WHZ_category == 'WHZ>=-2')] + get_incidence_of_wasting = \ + self.module.wasting_models.get_wasting_incidence(inc_wasting) - incidence_of_wasting = rng.random_sample(len(get_incidence_of_wasting)) < get_incidence_of_wasting + incidence_of_wasting = rng.random_sample( + len(get_incidence_of_wasting)) < get_incidence_of_wasting wasting_idx = inc_wasting.index # update the properties for wasted children df.loc[wasting_idx[incidence_of_wasting], 'un_ever_wasted'] = True - df.loc[wasting_idx[incidence_of_wasting], 'un_last_wasting_date_of_onset'] = self.sim.date - df.loc[wasting_idx[incidence_of_wasting], 'un_WHZ_category'] = '-3<=WHZ<-2' # start as moderate wasting - df.loc[wasting_idx[incidence_of_wasting], 'un_am_treatment_type'] = 'none' # start without treatment - # ------------------------------------------------------------------------------------------- + df.loc[wasting_idx[ + incidence_of_wasting], 'un_last_wasting_date_of_onset'] = \ + self.sim.date + # start as moderate wasting + df.loc[wasting_idx[ + incidence_of_wasting], 'un_WHZ_category'] = '-3<=WHZ<-2' + # start without treatment + df.loc[wasting_idx[ + incidence_of_wasting], 'un_am_treatment_type'] = 'none' + # -------------------------------------------------------------------- # Add this incident case to the tracker for person in wasting_idx: wasting_severity = df.at[person, 'un_WHZ_category'] - age_group = WastingPollingEvent.AGE_GROUPS.get(df.loc[person].age_years, '5+y') + age_group = WastingPollingEvent.AGE_GROUPS.get( + df.loc[person].age_years, '5+y') # if wasting_severity != 'WHZ>=-2': - self.module.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) + self.module.wasting_incident_case_tracker[age_group][ + wasting_severity].append(self.sim.date) - # ------------------------------------------------------------------------------------------- + # --------------------------------------------------------------------- - # # # # # # # # # # # # # # # # # # # # # PROGRESS TO SEVERE WASTING # # # # # # # # # # # # # # # # # # # # # + # # # # # # # #PROGRESS TO SEVERE WASTING # # # # # # # # # # # # # # # - # Determine those that will progress to severe wasting ( WHZ<-3) and schedule progression event --------- - progression_sev_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == '-3<=WHZ<-2')] + # Determine those that will progress to severe wasting ( WHZ<-3) + # and schedule progression event --------- + progression_sev_wasting = df.loc[ + df.is_alive & (df.age_exact_years < 5) & ( + df.un_WHZ_category == '-3<=WHZ<-2')] progression_severe_wasting = \ - self.module.wasting_models.get_wasting_progression().predict(progression_sev_wasting, rng) + self.module.wasting_models.get_wasting_progression().predict( + progression_sev_wasting, rng) progression_sev_wasting_idx = progression_sev_wasting.index - - # determine those individuals who will progress to severe wasting and time of progression + # determine those individuals who will progress to severe wasting + # and time of progression for person in progression_sev_wasting_idx[progression_severe_wasting]: - outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') + outcome_date = self.module.date_of_outcome_for_untreated_am( + person_id=person, duration_am='MAM') # schedule severe wasting WHZ<-3 onset if outcome_date <= self.sim.date: # schedule severe wasting WHZ<-3 onset today self.sim.schedule_event( - event=ProgressionSevereWastingEvent(module=self.module, person_id=person), + event=ProgressionSevereWastingEvent(module=self.module, + person_id=person), date=self.sim.date) else: # schedule severe wasting WHZ<-3 onset according to duration self.sim.schedule_event( - event=ProgressionSevereWastingEvent(module=self.module, person_id=person), + event=ProgressionSevereWastingEvent(module=self.module, + person_id=person), date=outcome_date) - # # # # # # # # # # # # # # # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # # # + # # # # # # #MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # moderate wasting not progressed to severe, schedule recovery for person in progression_sev_wasting_idx[~progression_severe_wasting]: - outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') + outcome_date = self.module.date_of_outcome_for_untreated_am( + person_id=person, duration_am='MAM') if outcome_date <= self.sim.date: # schedule recovery for today self.sim.schedule_event( - event=WastingNaturalRecoveryEvent(module=self.module, person_id=person), + event=WastingNaturalRecoveryEvent(module=self.module, + person_id=person), date=self.sim.date) else: # schedule recovery according to duration self.sim.schedule_event( - event=WastingNaturalRecoveryEvent(module=self.module, person_id=person), + event=WastingNaturalRecoveryEvent(module=self.module, + person_id=person), date=outcome_date) # ------------------------------------------------------------------------------------------ - # # # # # # # # # UPDATE PROPERTIES RELATED TO CLINICAL ACUTE MALNUTRITION # # # # # # # # # + # ## UPDATE PROPERTIES RELATED TO CLINICAL ACUTE MALNUTRITION # # # # # ------------------------------------------------------------------------------------------ # This applies to all children under 5 - # give MUAC measurement category for all WHZ, including well nourished children ----- - # determine the presence of bilateral oedema / oedematous malnutrition ----- - # determine the clinical state of acute malnutrition, and check complications if SAM + # give MUAC measurement category for all WHZ, including well + # nourished children ----- + # determine the presence of bilateral oedema / oedematous malnutrition + # determine the clinical state of acute malnutrition, and check + # complications if SAM self.module.population_poll_clinical_am(df) - # then, update clinical symptoms for those with severe acute malnutrition + # then, update clinical symptoms for those with severe acute + # malnutrition children_with_sam = df.loc[df.is_alive & (df.age_exact_years < 5) & - (df.un_clinical_acute_malnutrition == 'SAM')] + (df.un_clinical_acute_malnutrition == + 'SAM')] for person in children_with_sam.index: self.module.wasting_clinical_symptoms(person_id=person) @@ -810,7 +1050,8 @@ def apply(self, population): class ProgressionSevereWastingEvent(Event, IndividualScopeEventMixin): """ This Event is for the onset of severe wasting (WHZ <-3). - * Refreshes all the properties so that they pertain to this current episode of wasting + * Refreshes all the properties so that they pertain to this current + episode of wasting * Imposes the symptoms """ @@ -821,8 +1062,10 @@ def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe m = self.module - # before progression to severe wasting, check those who started supplementary feeding programme before today - if df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[person_id, 'un_acute_malnutrition_tx_start_date'] \ + # before progression to severe wasting, check those who started + # supplementary feeding programme before today + if df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[ + person_id, 'un_acute_malnutrition_tx_start_date'] \ < self.sim.date: return @@ -833,10 +1076,13 @@ def apply(self, person_id): # Give MUAC measurement category for WHZ<-3 if df.at[person_id, 'age_exact_years'] > 0.5: - m.muac_cutoff_by_WHZ(idx=df.loc[[person_id]].index, whz='WHZ<-3') + m.muac_cutoff_by_WHZ(idx=df.loc[[person_id]].index, + whz='WHZ<-3') - # update the clinical state of acute malnutrition, and check complications if SAM - m.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) + # update the clinical state of acute malnutrition, and check + # complications if SAM + m.clinical_acute_malnutrition_state(person_id=person_id, + pop_dataframe=df) # update clinical symptoms for severe wasting m.wasting_clinical_symptoms(person_id=person_id) @@ -844,9 +1090,11 @@ def apply(self, person_id): # ------------------------------------------------------------------------------------------- # Add this incident case to the tracker wasting_severity = df.at[person_id, 'un_WHZ_category'] - age_group = WastingPollingEvent.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') + age_group = WastingPollingEvent.AGE_GROUPS.get( + df.loc[person_id].age_years, '5+y') if wasting_severity != 'WHZ>=-2': - m.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) + m.wasting_incident_case_tracker[age_group][ + wasting_severity].append(self.sim.date) class SevereAcuteMalnutritionDeathEvent(Event, IndividualScopeEventMixin): @@ -878,7 +1126,8 @@ def apply(self, person_id): class WastingNaturalRecoveryEvent(Event, IndividualScopeEventMixin): """ - This event sets wasting properties back to normal state, based on home care/ improvement without interventions, + This event sets wasting properties back to normal state, based on home + care/ improvement without interventions, low-moderate MUAC categories oedema may or may not be present """ @@ -899,10 +1148,12 @@ def apply(self, person_id): if df.at[person_id, 'age_exact_years'] > 0.5: m.muac_cutoff_by_WHZ(idx=df.loc[[person_id]].index, whz='WHZ>=-2') - # Note assumption: prob of oedema remained the same as applied in wasting onset + # Note assumption: prob of oedema remained the same as applied in + # wasting onset # update the clinical acute malnutrition state - m.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) + m.clinical_acute_malnutrition_state(person_id=person_id, + pop_dataframe=df) if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': # this will clear all wasting symptoms self.sim.modules["SymptomManager"].clear_symptoms( @@ -942,7 +1193,8 @@ def apply(self, person_id): class UpdateToMAM(Event, IndividualScopeEventMixin): """ - This event updates the properties for those cases that remained/ improved from SAM to MAM following treatment + This event updates the properties for those cases that remained/ + improved from SAM to MAM following treatment """ def __init__(self, module, person_id): @@ -957,16 +1209,21 @@ def apply(self, person_id): if not df.at[person_id, 'is_alive']: return - # For cases with normal WHZ and other acute malnutrition signs: oedema, or low muac - do not change the WHZ + # For cases with normal WHZ and other acute malnutrition signs: + # oedema, or low muac - do not change the WHZ if df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2': - df.at[person_id, 'un_am_MUAC_category'] = '115-<125mm' # mam by muac only + # mam by muac only + df.at[ + person_id, 'un_am_MUAC_category'] = '115-<125mm' else: - # using the probability of mam classification by anthropometric indices - mam_classification = rng.choice(['mam_by_muac_only', 'mam_by_muac_and_whz', 'mam_by_whz_only'], - p=[p['proportion_mam_with_MUAC_115-<125mm_and_normal_whz'], - p['proportion_mam_with_MUAC_115-<125mm_and_-3<=WHZ<-2'], - p['proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC']]) + # using the probability of mam classification by anthropometric + # indices + mam_classification = rng.choice( + ['mam_by_muac_only', 'mam_by_muac_and_whz', 'mam_by_whz_only'], + p=[p['proportion_mam_with_MUAC_115-<125mm_and_normal_whz'], + p['proportion_mam_with_MUAC_115-<125mm_and_-3<=WHZ<-2'], + p['proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC']]) if mam_classification == 'mam_by_muac_only': df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' @@ -987,7 +1244,9 @@ def apply(self, person_id): df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = pd.NaT df.at[person_id, 'un_am_recovery_date'] = pd.NaT df.at[person_id, 'un_am_discharge_date'] = pd.NaT - df.at[person_id, 'un_am_treatment_type'] = 'not_applicable' # will start the process again + # will start the process again + df.at[ + person_id, 'un_am_treatment_type'] = 'not_applicable' # this will clear all wasting symptoms (applicable for SAM, not MAM) self.sim.modules["SymptomManager"].clear_symptoms( @@ -995,7 +1254,8 @@ def apply(self, person_id): ) -class HSI_Wasting_SupplementaryFeedingProgramme_MAM(HSI_Event, IndividualScopeEventMixin): +class HSI_Wasting_SupplementaryFeedingProgramme_MAM(HSI_Event, + IndividualScopeEventMixin): """ This is the supplementary feeding programme for MAM without complications """ @@ -1004,8 +1264,10 @@ def __init__(self, module, person_id): super().__init__(module, person_id=person_id) assert isinstance(module, Wasting) - # Get a blank footprint and then edit to define call on resources of this treatment event - the_appt_footprint = self.sim.modules["HealthSystem"].get_blank_appt_footprint() + # Get a blank footprint and then edit to define call on resources + # of this treatment event + the_appt_footprint = self.sim.modules[ + "HealthSystem"].get_blank_appt_footprint() the_appt_footprint['Under5OPD'] = 1 # This requires one out patient # Define the necessary information for an HSI @@ -1017,35 +1279,47 @@ def __init__(self, module, person_id): def apply(self, person_id, squeeze_factor): df = self.sim.population.props - # Stop the person from dying of acute malnutrition (if they were going to die) + # Stop the person from dying of acute malnutrition (if they were + # going to die) if not df.at[person_id, 'is_alive']: return - # Do here whatever happens to an individual during this health system interaction event + # Do here whatever happens to an individual during this health + # system interaction event # ~~~~~~~~~~~~~~~~~~~~~~ # Make request for some consumables - consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] + consumables = self.sim.modules['HealthSystem'].parameters[ + 'item_and_package_code_lookups'] # individual items item_code1 = pd.unique( - consumables.loc[consumables['Items'] == 'Corn Soya Blend (or Supercereal - CSB++)', 'Item_Code'])[0] + consumables.loc[consumables[ + 'Items'] == 'Corn Soya Blend (or ' + 'Supercereal - CSB++)', + 'Item_Code'])[0] # check availability of consumables if self.get_consumables([item_code1]): logger.debug(key='debug', data='consumables are available') # Log that the treatment is provided: - df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date - df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=3) + df.at[ + person_id, 'un_acute_malnutrition_tx_start_date'] = \ + self.sim.date + df.at[ + person_id, 'un_am_discharge_date'] = \ + self.sim.date + DateOffset(weeks=3) df.at[person_id, 'un_am_treatment_type'] = 'CSB++' self.module.do_when_am_treatment(person_id, intervention='SFP') else: - logger.debug(key='debug', data="PkgCode1 is not available, so can't use it.") + logger.debug(key='debug', + data="PkgCode1 is not available, so can't use it.") def did_not_run(self): logger.debug("supplementary_feeding_programme_for_MAM: did not run") pass -class HSI_Wasting_OutpatientTherapeuticProgramme_SAM(HSI_Event, IndividualScopeEventMixin): +class HSI_Wasting_OutpatientTherapeuticProgramme_SAM( + HSI_Event, IndividualScopeEventMixin): """ This is the outpatient management of SAM without any medical complications """ @@ -1054,8 +1328,10 @@ def __init__(self, module, person_id): super().__init__(module, person_id=person_id) assert isinstance(module, Wasting) - # Get a blank footprint and then edit to define call on resources of this treatment event - the_appt_footprint = self.sim.modules["HealthSystem"].get_blank_appt_footprint() + # Get a blank footprint and then edit to define call on resources + # of this treatment event + the_appt_footprint = self.sim.modules[ + "HealthSystem"].get_blank_appt_footprint() the_appt_footprint['U5Malnutr'] = 1 # Define the necessary information for an HSI @@ -1067,38 +1343,52 @@ def __init__(self, module, person_id): def apply(self, person_id, squeeze_factor): df = self.sim.population.props - # Stop the person from dying of acute malnutrition (if they were going to die) + # Stop the person from dying of acute malnutrition (if they were + # going to die) if not df.at[person_id, 'is_alive']: return - # Do here whatever happens to an individual during this health system interaction event + # Do here whatever happens to an individual during this health + # system interaction event # ~~~~~~~~~~~~~~~~~~~~~~ # Make request for some consumables - consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] + consumables = self.sim.modules['HealthSystem'].parameters[ + 'item_and_package_code_lookups'] # individual items item_code1 = pd.unique( - consumables.loc[consumables['Items'] == 'SAM theraputic foods', 'Item_Code'])[0] + consumables.loc[ + consumables['Items'] == 'SAM theraputic foods', 'Item_Code'])[ + 0] item_code2 = pd.unique( - consumables.loc[consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] + consumables.loc[ + consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] # check availability of consumables - if self.get_consumables(item_code1) and self.get_consumables(item_code2): + if self.get_consumables(item_code1) and self.get_consumables( + item_code2): logger.debug(key='debug', data='consumables are available.') # Log that the treatment is provided: - df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date - df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=3) + df.at[ + person_id, 'un_acute_malnutrition_tx_start_date'] = \ + self.sim.date + df.at[ + person_id, 'un_am_discharge_date'] = self.sim.date + \ + DateOffset(weeks=3) df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' self.module.do_when_am_treatment(person_id, intervention='OTC') else: - logger.debug(key='debug', data="consumables not available, so can't use it.") + logger.debug(key='debug', + data="consumables not available, so can't use it.") def did_not_run(self): - logger.debug("HSI_outpatient_therapeutic_programme_for_SAM: did not run") + logger.debug( + "HSI_outpatient_therapeutic_programme_for_SAM: did not run") pass -class HSI_Wasting_InpatientCareForComplicated_SAM(HSI_Event, IndividualScopeEventMixin): +class HSI_Wasting_InpatientCareForComplicated_SAM(HSI_Event, + IndividualScopeEventMixin): """ This is the inpatient management of SAM with medical complications """ @@ -1107,8 +1397,10 @@ def __init__(self, module, person_id): super().__init__(module, person_id=person_id) assert isinstance(module, Wasting) - # Get a blank footprint and then edit to define call on resources of this treatment event - the_appt_footprint = self.sim.modules["HealthSystem"].get_blank_appt_footprint() + # Get a blank footprint and then edit to define call on resources + # of this treatment event + the_appt_footprint = self.sim.modules[ + "HealthSystem"].get_blank_appt_footprint() the_appt_footprint['U5Malnutr'] = 1 # Define the necessary information for an HSI @@ -1116,36 +1408,49 @@ def __init__(self, module, person_id): self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint self.ACCEPTED_FACILITY_LEVEL = '2' self.ALERT_OTHER_DISEASES = [] - self.BEDDAYS_FOOTPRINT = self.make_beddays_footprint({'general_bed': 7}) + self.BEDDAYS_FOOTPRINT = self.make_beddays_footprint( + {'general_bed': 7}) def apply(self, person_id, squeeze_factor): df = self.sim.population.props - # Stop the person from dying of acute malnutrition (if they were going to die) + # Stop the person from dying of acute malnutrition (if they were + # going to die) if not df.at[person_id, 'is_alive']: return - # Do here whatever happens to an individual during this health system interaction event + # Do here whatever happens to an individual during this health + # system interaction event # ~~~~~~~~~~~~~~~~~~~~~~ # Make request for some consumables - consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] + consumables = self.sim.modules['HealthSystem'].parameters[ + 'item_and_package_code_lookups'] # individual items item_code1 = pd.unique( - consumables.loc[consumables['Items'] == 'SAM theraputic foods', 'Item_Code'])[0] + consumables.loc[ + consumables['Items'] == 'SAM theraputic foods', 'Item_Code'])[ + 0] item_code2 = pd.unique( - consumables.loc[consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] + consumables.loc[ + consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] # # check availability of consumables - if self.get_consumables(item_code1) and self.get_consumables(item_code2): + if self.get_consumables(item_code1) and self.get_consumables( + item_code2): logger.debug(key='debug', data='consumables available, so use it.') # Log that the treatment is provided: - df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date - df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=4) + df.at[ + person_id, 'un_acute_malnutrition_tx_start_date'] = \ + self.sim.date + df.at[ + person_id, 'un_am_discharge_date'] = self.sim.date + \ + DateOffset(weeks=4) df.at[person_id, 'un_am_treatment_type'] = 'inpatient_care' self.module.do_when_am_treatment(person_id, intervention='ITC') else: - logger.debug(key='debug', data="consumables not available, so can't use it.") + logger.debug(key='debug', + data="consumables not available, so can't use it.") def did_not_run(self): logger.debug("HSI_inpatient_care_for_complicated_SAM: did not run") @@ -1162,76 +1467,112 @@ def __init__(self, module): # linear model to predict the incidence of wasting self.__Wasting_Incidence = LinearModel.multiplicative( - Predictor('age_exact_years').when('<0.5', self.params['base_inc_rate_wasting_by_agegp'][0]) + Predictor('age_exact_years').when('<0.5', self.params[ + 'base_inc_rate_wasting_by_agegp'][0]) .when('<1.0', self.params['base_inc_rate_wasting_by_agegp'][1]) - .when('.between(1,1.9999)', self.params['base_inc_rate_wasting_by_agegp'][2]) - .when('.between(2,2.9999)', self.params['base_inc_rate_wasting_by_agegp'][3]) - .when('.between(3,3.9999)', self.params['base_inc_rate_wasting_by_agegp'][4]) - .when('.between(4,4.9999)', self.params['base_inc_rate_wasting_by_agegp'][5]) + .when('.between(1,1.9999)', + self.params['base_inc_rate_wasting_by_agegp'][2]) + .when('.between(2,2.9999)', + self.params['base_inc_rate_wasting_by_agegp'][3]) + .when('.between(3,3.9999)', + self.params['base_inc_rate_wasting_by_agegp'][4]) + .when('.between(4,4.9999)', + self.params['base_inc_rate_wasting_by_agegp'][5]) .otherwise(0.0), - Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& (nb_late_preterm == False) & (nb_early_preterm == False)', - self.params['rr_wasting_SGA_and_term']), - Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', - self.params['rr_wasting_SGA_and_preterm']), - Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") ' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', - self.params['rr_wasting_preterm_and_AGA']), + Predictor().when( + '(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == False) & (nb_early_preterm == False)', + self.params['rr_wasting_SGA_and_term']), + Predictor().when( + '(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + self.params['rr_wasting_SGA_and_preterm']), + Predictor().when( + '(nb_size_for_gestational_age == ' + '"average_for_gestational_age")' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + self.params['rr_wasting_preterm_and_AGA']), Predictor('li_wealth').apply( - lambda x: 1 if x == 1 else (x - 1) ** (self.params['rr_wasting_wealth_level'])), + lambda x: 1 if x == 1 else (x - 1) ** ( + self.params['rr_wasting_wealth_level'])), ) - # a linear model to predict the probability of individual's recovery from moderate acute malnutrition + # a linear model to predict the probability of individual's + # recovery from moderate acute malnutrition self.__Acute_Malnutrition_Recovery_MAM = LinearModel.multiplicative( - Predictor('un_am_treatment_type').when('soy_RUSF', self.params['recovery_rate_with_soy_RUSF']) + Predictor('un_am_treatment_type').when('soy_RUSF', self.params[ + 'recovery_rate_with_soy_RUSF']) .when('CSB++', self.params['recovery_rate_with_CSB++']) .otherwise(0.0), ) - # a linear model to predict the probability of individual's recovery from severe acute malnutrition + # a linear model to predict the probability of individual's + # recovery from severe acute malnutrition self.__Acute_Malnutrition_Recovery_SAM = LinearModel.multiplicative( Predictor('un_am_treatment_type') - .when('standard_RUTF', self.params['recovery_rate_with_standard_RUTF']) - .when('inpatient_care', self.params['recovery_rate_with_inpatient_care']) + .when('standard_RUTF', + self.params['recovery_rate_with_standard_RUTF']) + .when('inpatient_care', + self.params['recovery_rate_with_inpatient_care']) .otherwise(0.0), ) - # Linear model for the probability of progression to severe wasting (age-dependent only) + # Linear model for the probability of progression to severe wasting + # (age-dependent only) # (natural history only, no interventions) self.__Severe_Wasting_Progression = LinearModel.multiplicative( Predictor('age_exact_years') - .when('<0.5', self.params['progression_severe_wasting_by_agegp'][0]) - .when('.between(0.5,0.9999)', self.params['progression_severe_wasting_by_agegp'][1]) - .when('.between(1,1.9999)', self.params['progression_severe_wasting_by_agegp'][2]) - .when('.between(2,2.9999)', self.params['progression_severe_wasting_by_agegp'][3]) - .when('.between(3,3.9999)', self.params['progression_severe_wasting_by_agegp'][4]) - .when('.between(4,4.9999)', self.params['progression_severe_wasting_by_agegp'][5]) + .when('<0.5', + self.params['progression_severe_wasting_by_agegp'][0]) + .when('.between(0.5,0.9999)', + self.params['progression_severe_wasting_by_agegp'][1]) + .when('.between(1,1.9999)', + self.params['progression_severe_wasting_by_agegp'][2]) + .when('.between(2,2.9999)', + self.params['progression_severe_wasting_by_agegp'][3]) + .when('.between(3,3.9999)', + self.params['progression_severe_wasting_by_agegp'][4]) + .when('.between(4,4.9999)', + self.params['progression_severe_wasting_by_agegp'][5]) .otherwise(0.0), ) self.__SAM_Death = LinearModel.multiplicative( - Predictor('un_am_treatment_type').when('none', self.params['base_death_rate_untreated_SAM']), - Predictor('un_sam_with_complications').when(True, - self.params['rr_SAM_death_with_complications']), + Predictor('un_am_treatment_type').when('none', self.params[ + 'base_death_rate_untreated_SAM']), + Predictor( + 'un_sam_with_complications' + ).when(True, self.params['rr_SAM_death_with_complications']), Predictor().when('(un_am_bilateral_oedema == False) & ' - '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "115-<125mm")', + '(un_WHZ_category == "WHZ<-3") ' + '& (un_am_MUAC_category == "115-<125mm")', self.params['rr_SAM_death_WHZ<-3_only']), Predictor().when('(un_am_bilateral_oedema == False) & ' - '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "<115mm")', - self.params['rr_SAM_death_both_WHZ<-3_&_MUAC<115mm']), + '(un_WHZ_category == "WHZ<-3") & ' + '(un_am_MUAC_category == "<115mm")', + self.params[ + 'rr_SAM_death_both_WHZ<-3_&_MUAC<115mm']), Predictor().when('(un_am_bilateral_oedema == True) & ' - '(un_WHZ_category == "-3<=WHZ<-2") & (un_am_MUAC_category == "<115mm")', + '(un_WHZ_category == "-3<=WHZ<-2") & ' + '(un_am_MUAC_category == "<115mm")', self.params['rr_SAM_death_kwashiorkor_only']), Predictor().when('(un_am_bilateral_oedema == True) & ' - '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "115-<125mm")', - self.params['rr_SAM_death_kwashiorkor_WHZ<-3_only']), - Predictor().when('(un_am_bilateral_oedema == True) & ' - '(un_WHZ_category == "WHZ<-3") & (un_am_MUAC_category == "<115mm")', - self.params['rr_SAM_death_kwashiorkor_both_WHZ<-3_&_MUAC<115mm']), + '(un_WHZ_category == "WHZ<-3") & ' + '(un_am_MUAC_category == "115-<125mm")', + self.params[ + 'rr_SAM_death_kwashiorkor_WHZ<-3_only']), + Predictor().when( + '(un_am_bilateral_oedema == True) & ' + '(un_WHZ_category == "WHZ<-3") & ' + '(un_am_MUAC_category == "<115mm")', + self.params['rr_SAM_death_kwashiorkor_both_WHZ<-3_&_MUAC<115mm' + ] + ), Predictor().when('(un_am_bilateral_oedema == True) & ' - '(un_WHZ_category == "-3<=WHZ<-2") & (un_am_MUAC_category == "<115mm")', - self.params['rr_SAM_death_kwashiorkor_MUAC<115mm_only']), + '(un_WHZ_category == "-3<=WHZ<-2") & ' + '(un_am_MUAC_category == "<115mm")', + self.params[ + 'rr_SAM_death_kwashiorkor_MUAC<115mm_only']), ) def get_wasting_incidence(self, df) -> pd.Series: @@ -1239,11 +1580,13 @@ def get_wasting_incidence(self, df) -> pd.Series: :params df: population dataframe """ unscaled_lm = self.__Wasting_Incidence target_mean = self.params['base_inc_rate_wasting_by_agegp'][2] - actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1) & - (df.un_WHZ_category == 'WHZ>=-2')]).mean() + actual_mean = unscaled_lm.predict( + df.loc[df.is_alive & (df.age_years == 1) & + (df.un_WHZ_category == 'WHZ>=-2')]).mean() scaled_intercept = 1.0 * (target_mean / actual_mean) \ - if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else 1.0 + if (target_mean != 0 and actual_mean != 0 and + ~np.isnan(actual_mean)) else 1.0 scaled_lm = unscaled_lm.predict(df) return scaled_lm.apply(lambda row: row * scaled_intercept) @@ -1256,12 +1599,18 @@ def get_wasting_prevalence(self): LinearModelType.LOGISTIC, 1.0, Predictor('agrp', external=True) - .when('0_5mo', self.module.wasting_prevalence_odds_by_age_grp['0_5mo']) - .when('6_11mo', self.module.wasting_prevalence_odds_by_age_grp['6_11mo']) - .when('12_23mo', self.module.wasting_prevalence_odds_by_age_grp['12_23mo']) - .when('24_35mo', self.module.wasting_prevalence_odds_by_age_grp['24_35mo']) - .when('36_47mo', self.module.wasting_prevalence_odds_by_age_grp['36_47mo']) - .when('48_59mo', self.module.wasting_prevalence_odds_by_age_grp['48_59mo']) + .when('0_5mo', + self.module.wasting_prevalence_odds_by_age_grp['0_5mo']) + .when('6_11mo', + self.module.wasting_prevalence_odds_by_age_grp['6_11mo']) + .when('12_23mo', + self.module.wasting_prevalence_odds_by_age_grp['12_23mo']) + .when('24_35mo', + self.module.wasting_prevalence_odds_by_age_grp['24_35mo']) + .when('36_47mo', + self.module.wasting_prevalence_odds_by_age_grp['36_47mo']) + .when('48_59mo', + self.module.wasting_prevalence_odds_by_age_grp['48_59mo']) .otherwise(1.0), Predictor('agrp_scaling', external=True) @@ -1273,75 +1622,92 @@ def get_wasting_prevalence(self): .when('48_59mo', self.module.age_grps_dict['48_59mo']) .otherwise(1.0), - Predictor('li_wealth').when(2, self.params['or_wasting_hhwealth_Q2']) + Predictor('li_wealth').when(2, + self.params['or_wasting_hhwealth_Q2']) .when(3, self.params['or_wasting_hhwealth_Q3']) .when(4, self.params['or_wasting_hhwealth_Q4']) .when(5, self.params['or_wasting_hhwealth_Q5']) .otherwise(1.0), - Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& (nb_late_preterm == False) & (nb_early_preterm == False)', - self.params['or_wasting_SGA_and_term']), - Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', - self.params['or_wasting_SGA_and_preterm']), - Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") ' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', - self.params['or_wasting_preterm_and_AGA']) + Predictor().when( + '(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == False) & (nb_early_preterm == False)', + self.params['or_wasting_SGA_and_term']), + Predictor().when( + '(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + self.params['or_wasting_SGA_and_preterm']), + Predictor().when( + '(nb_size_for_gestational_age == ' + '"average_for_gestational_age") ' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + self.params['or_wasting_preterm_and_AGA']) ) return wasting_prevalence def get_moderate_acute_malnutrition_recovery(self): - """ predict moderate acute malnutrition recovery amongst young children less than 5 years + """ predict moderate acute malnutrition recovery amongst young + children less than 5 years :params df: population dataframe """ return self.__Acute_Malnutrition_Recovery_MAM def get_severe_acute_malnutrition_recovery(self): - """ predict severe acute malnutrition recovery amongst young children less than 5 years + """ predict severe acute malnutrition recovery amongst young + children less than 5 years :params df: population dataframe """ return self.__Acute_Malnutrition_Recovery_SAM def get_wasting_progression(self): - """ predict wasting progression amongst young children less than 5 years + """ predict wasting progression amongst young children less than 5 + years :params df: population dataframe """ return self.__Severe_Wasting_Progression def get_sam_deaths(self, df) -> pd.Series: - """ predict severe acute malnutrition deaths amongst young children less than 5 years + """ predict severe acute malnutrition deaths amongst young children + less than 5 years :params df: population dataframe """ pop = self.module.sim.population.props - pop_wanted = pop.loc[pop.is_alive & pop.age_exact_years.between(0.5, 5, inclusive='neither') & + pop_wanted = pop.loc[pop.is_alive & + pop.age_exact_years.between(0.5, 5, + inclusive='neither') & (pop.un_clinical_acute_malnutrition == 'SAM')] unscaled_lm = self.__SAM_Death target_mean = self.params['base_death_rate_untreated_SAM'] actual_mean = unscaled_lm.predict(pop_wanted).mean() scaled_intercept = 1.0 * (target_mean / actual_mean) \ - if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else 1.0 + if (target_mean != 0 and actual_mean != 0 and + ~np.isnan(actual_mean)) else 1.0 scaled_lm = self.__SAM_Death.predict(df) return scaled_lm.apply(lambda row: row * scaled_intercept) def get_age_grps_odds(self): - """ Return odds determined by age groups. This will be applied in wasting prevalence linear model """ + """ Return odds determined by age groups. This will be applied in + wasting prevalence linear model """ for agegp in self.module.age_grps_dict.keys(): mean, stdev = self.params[f'prev_WHZ_distribution_age_{agegp}'] whz_normal_distribution = norm(loc=mean, scale=stdev) # get all wasting: WHZ <-2 probability_less_than_minus2sd = 1 - whz_normal_distribution.sf(-2) - # convert probability to odds and update odds by age group dictionary + # convert probability to odds and update odds by age group + # dictionary self.module.wasting_prevalence_odds_by_age_grp[agegp] = \ - probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) + probability_less_than_minus2sd / ( + 1 - probability_less_than_minus2sd) # get severe wasting zcores: WHZ <-3 probability_less_than_minus3sd = 1 - whz_normal_distribution.sf(-3) - # make WHZ <-2 as the 100% and get the adjusted probability of severe wasting within overall wasting + # make WHZ <-2 as the 100% and get the adjusted probability of + # severe wasting within overall wasting self.module.age_grps_sev_wasting_probs[ - agegp] = probability_less_than_minus3sd * probability_less_than_minus2sd + agegp] = \ + probability_less_than_minus3sd * probability_less_than_minus2sd def get_wasting_prevalence_scaling(self, df): """ get values for scaling wasting prevalence linear model @@ -1350,20 +1716,26 @@ def get_wasting_prevalence_scaling(self, df): wasting_prevalence = self.get_wasting_prevalence() # index the age groups dictionary for agegp in self.module.age_grps_dict.keys(): - target_mean = self.module.wasting_prevalence_odds_by_age_grp['12_23mo'] - actual_mean = wasting_prevalence.predict(df.loc[df.is_alive & (df.age_years == 1)], - agrp=agegp, agrp_scaling='None').mean() + target_mean = self.module.wasting_prevalence_odds_by_age_grp[ + '12_23mo'] + actual_mean = wasting_prevalence.predict( + df.loc[df.is_alive & (df.age_years == 1)], + agrp=agegp, agrp_scaling='None').mean() # update and return age groups dictionary self.module.age_grps_dict[agegp] = \ - self.module.wasting_prevalence_odds_by_age_grp[agegp] * (target_mean / actual_mean) \ - if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) \ + self.module.wasting_prevalence_odds_by_age_grp[agegp] * ( + target_mean / actual_mean) \ + if (target_mean != 0 and actual_mean != 0 and ~np.isnan( + actual_mean)) \ else self.module.wasting_prevalence_odds_by_age_grp[agegp] class WastingLoggingEvent(RegularEvent, PopulationScopeEventMixin): """ - This Event logs the number of incident cases that have occurred since the previous logging event. - Analysis scripts expect that the frequency of this logging event is once per year. + This Event logs the number of incident cases that have occurred + since the previous logging event. + Analysis scripts expect that the frequency of this logging event + is once per year. """ def __init__(self, module): @@ -1376,31 +1748,45 @@ def apply(self, population): df = self.sim.population.props # Convert the list of timestamps into a number of timestamps # and check that all the dates have occurred since self.date_last_run - inc_df = pd.DataFrame(index=self.module.wasting_incident_case_tracker.keys(), - columns=self.module.wasting_states) + inc_df = pd.DataFrame( + index=self.module.wasting_incident_case_tracker.keys(), + columns=self.module.wasting_states) for age_grp in self.module.wasting_incident_case_tracker.keys(): for state in self.module.wasting_states: - inc_df.loc[age_grp, state] = len(self.module.wasting_incident_case_tracker[age_grp][state]) + inc_df.loc[age_grp, state] = len( + self.module.wasting_incident_case_tracker[age_grp][state]) logger.info(key='wasting_incidence_count', data=inc_df.to_dict()) # Reset the counters and the date_last_run - self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) + self.module.wasting_incident_case_tracker = copy.deepcopy( + self.module.wasting_incident_case_tracker_blank) self.date_last_run = self.sim.date # Wasting totals (prevalence at logging time) - currently_wasted_age_0_5mo = (df.is_alive & (df.age_exact_years < 0.5) & - (df.un_WHZ_category != 'WHZ>=-2')).sum() - currently_wasted_age_6_11mo = (df.is_alive & ((df.age_exact_years >= 0.5) & ( - df.age_exact_years < 1)) & (df.un_WHZ_category != 'WHZ>=-2')).sum() - currently_wasted_age_12_23mo = (df.is_alive & ((df.age_exact_years >= 1) & ( - df.age_exact_years < 2)) & (df.un_WHZ_category != 'WHZ>=-2')).sum() - currently_wasted_age_24_35mo = (df.is_alive & ((df.age_exact_years >= 2) & ( - df.age_exact_years < 3)) & (df.un_WHZ_category != 'WHZ>=-2')).sum() - currently_wasted_age_36_47mo = (df.is_alive & ((df.age_exact_years >= 3) & ( - df.age_exact_years < 4)) & (df.un_WHZ_category != 'WHZ>=-2')).sum() - currently_wasted_age_48_59mo = (df.is_alive & ((df.age_exact_years >= 4) & ( - df.age_exact_years < 5)) & (df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_0_5mo = ( + df.is_alive & (df.age_exact_years < 0.5) & + (df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_6_11mo = ( + df.is_alive & ((df.age_exact_years >= 0.5) & ( + df.age_exact_years < 1)) & ( + df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_12_23mo = ( + df.is_alive & ((df.age_exact_years >= 1) & ( + df.age_exact_years < 2)) & ( + df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_24_35mo = ( + df.is_alive & ((df.age_exact_years >= 2) & ( + df.age_exact_years < 3)) & ( + df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_36_47mo = ( + df.is_alive & ((df.age_exact_years >= 3) & ( + df.age_exact_years < 4)) & ( + df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_48_59mo = ( + df.is_alive & ((df.age_exact_years >= 4) & ( + df.age_exact_years < 5)) & ( + df.un_WHZ_category != 'WHZ>=-2')).sum() currently_wasted = {'0_5mo': currently_wasted_age_0_5mo, '6_11mo': currently_wasted_age_6_11mo, diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 14cb829e5e..8779b3e0d0 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -40,24 +40,34 @@ def get_sim(tmpdir): - """Return simulation objection with Wasting and other necessary modules registered.""" - sim = Simulation(start_date=start_date, seed=0, show_progress_bar=False, log_config={ - 'filename': 'tmp', - 'directory': tmpdir, - 'custom_levels': { - "*": logging.WARNING, - "tlo.methods.wasting": logging.INFO} - }) + """ + Return simulation objection with Wasting and other necessary + modules registered. + """ + sim = Simulation(start_date=start_date, seed=0, + show_progress_bar=False, + log_config={ + 'filename': 'tmp', + 'directory': tmpdir, + 'custom_levels': { + "*": logging.WARNING, + "tlo.methods.wasting": logging.INFO} + }) sim.register(demography.Demography(resourcefilepath=resourcefilepath), - enhanced_lifestyle.Lifestyle(resourcefilepath=resourcefilepath), + enhanced_lifestyle.Lifestyle( + resourcefilepath=resourcefilepath), healthsystem.HealthSystem(resourcefilepath=resourcefilepath, disable=False, cons_availability='all'), - symptommanager.SymptomManager(resourcefilepath=resourcefilepath), - healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resourcefilepath), - healthburden.HealthBurden(resourcefilepath=resourcefilepath), - simplified_births.SimplifiedBirths(resourcefilepath=resourcefilepath), + symptommanager.SymptomManager( + resourcefilepath=resourcefilepath), + healthseekingbehaviour.HealthSeekingBehaviour( + resourcefilepath=resourcefilepath), + healthburden.HealthBurden( + resourcefilepath=resourcefilepath), + simplified_births.SimplifiedBirths( + resourcefilepath=resourcefilepath), wasting.Wasting(resourcefilepath=resourcefilepath) ) return sim @@ -75,18 +85,25 @@ def check_configuration_of_properties(sim): df = sim.population.props # Those that were never wasted, should have normal WHZ score: - assert (df.loc[~df.un_ever_wasted & ~df.date_of_birth.isna(), 'un_WHZ_category'] == 'WHZ>=-2').all() + assert ( + df.loc[~df.un_ever_wasted & + ~df.date_of_birth.isna(), 'un_WHZ_category'] == 'WHZ>=-2' + ).all() # Those for whom the death date has past should be dead - assert not df.loc[df.un_ever_wasted & (df['un_sam_death_date'] < sim.date), 'is_alive'].any() + assert not df.loc[df.un_ever_wasted & + (df['un_sam_death_date'] < sim.date), 'is_alive'].any() assert not df.loc[(df.un_clinical_acute_malnutrition == 'SAM') & ( - df['un_sam_death_date'] < sim.date), 'is_alive'].any() + df['un_sam_death_date'] < sim.date), 'is_alive'].any() - # Check that those in a current episode have symptoms of wasting [caused by the wasting module] - # but not others (among those who are alive) - has_symptoms_of_wasting = set(sim.modules['SymptomManager'].who_has('weight_loss')) + # Check that those in a current episode have symptoms of wasting + # [caused by the wasting module] but not others (among those alive) + has_symptoms_of_wasting = \ + set(sim.modules['SymptomManager'].who_has('weight_loss')) has_symptoms = set([p for p in has_symptoms_of_wasting if - 'Wasting' in sim.modules['SymptomManager'].causes_of(p, 'weight_loss') + 'Wasting' in + sim.modules['SymptomManager'].causes_of(p, + 'weight_loss') ]) in_current_episode_before_recovery = \ @@ -95,7 +112,8 @@ def check_configuration_of_properties(sim): (df.un_last_wasting_date_of_onset <= sim.date) & \ (sim.date <= df.un_am_recovery_date) set_of_person_id_in_current_episode_before_recovery = set( - in_current_episode_before_recovery[in_current_episode_before_recovery].index + in_current_episode_before_recovery[ + in_current_episode_before_recovery].index ) in_current_episode_before_death = \ @@ -107,25 +125,31 @@ def check_configuration_of_properties(sim): in_current_episode_before_death[in_current_episode_before_death].index ) - assert set() == set_of_person_id_in_current_episode_before_recovery.intersection( + assert set() == \ + set_of_person_id_in_current_episode_before_recovery.intersection( set_of_person_id_in_current_episode_before_death ) - # WHZ standard deviation of -3, oedema, and MUAC <115mm should cause severe acute malnutrition + # WHZ standard deviation of -3, oedema, and MUAC <115mm should cause + # severe acute malnutrition whz_index = df.index[df['un_WHZ_category'] == 'WHZ<-3'] oedema_index = df.index[df['un_am_bilateral_oedema']] muac_index = df.index[df['un_am_MUAC_category'] == '<115mm'] assert (df.loc[whz_index, 'un_clinical_acute_malnutrition'] == "SAM").all() - assert (df.loc[oedema_index, 'un_clinical_acute_malnutrition'] == "SAM").all() - assert (df.loc[muac_index, 'un_clinical_acute_malnutrition'] == "SAM").all() + assert (df.loc[ + oedema_index, 'un_clinical_acute_malnutrition'] == "SAM").all() + assert (df.loc[ + muac_index, 'un_clinical_acute_malnutrition'] == "SAM").all() # all SAM individuals should have symptoms of wasting assert set(df.index[df.is_alive & (df.age_exact_years < 5) & - (df.un_clinical_acute_malnutrition == 'SAM')]).issubset(has_symptoms) + (df.un_clinical_acute_malnutrition == 'SAM')] + ).issubset(has_symptoms) # All MAM individuals should have no symptoms of wasting assert set(df.index[df.is_alive & (df.age_exact_years < 5) & - (df.un_clinical_acute_malnutrition == 'MAM')]) not in has_symptoms + (df.un_clinical_acute_malnutrition == 'MAM')]) \ + not in has_symptoms @pytest.mark.slow @@ -149,7 +173,8 @@ def test_wasting_polling(tmpdir): # Make incidence of wasting very high : params = sim.modules['Wasting'].parameters params['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] - params['progression_severe_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + params['progression_severe_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, + 1.0] # re-initialise wasting linear models to use the updated parameter sim.modules['Wasting'].pre_initialise_population() @@ -162,7 +187,8 @@ def test_wasting_polling(tmpdir): polling = WastingPollingEvent(sim.modules['Wasting']) polling.apply(sim.population) - assert len([q for q in sim.event_queue.queue if isinstance(q[3], ProgressionSevereWastingEvent)]) > 0 + assert len([q for q in sim.event_queue.queue if + isinstance(q[3], ProgressionSevereWastingEvent)]) > 0 # Check properties of this individual: should now be moderately wasted df = sim.population.props @@ -192,9 +218,12 @@ def test_recovery_moderate_wasting(tmpdir): # get wasting module wmodule = sim.modules['Wasting'] - # increase wasting incidence rate to 100% for all age groups(less than 5 years) - wmodule.parameters['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] - wmodule.parameters['progression_severe_wasting_by_agegp'] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + # increase wasting incidence rate to 100% for all + # age groups(less than 5 years) + wmodule.parameters['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, + 1.0, 1.0] + wmodule.parameters['progression_severe_wasting_by_agegp'] = [0.0, 0.0, 0.0, + 0.0, 0.0, 0.0] # re-initialise wasting linear models to use the updated parameter wmodule.pre_initialise_population() @@ -212,10 +241,11 @@ def test_recovery_moderate_wasting(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Check that there is a WastingNaturalRecoveryEvent scheduled for this person: - recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], WastingNaturalRecoveryEvent) - ][0] + # Check that there is a WastingNaturalRecoveryEvent scheduled + # for this person + recov_event_tuple = \ + [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], WastingNaturalRecoveryEvent)][0] date_of_scheduled_recov = recov_event_tuple[0] recov_event = recov_event_tuple[1] assert date_of_scheduled_recov > sim.date @@ -232,8 +262,9 @@ def test_recovery_moderate_wasting(tmpdir): def test_recovery_severe_wasting_without_complications(tmpdir): - """ Check natural recovery to MAM by removing death rate for those with severe wasting, - and check the onset of symptoms with SAM and revolving of symptoms when recovered to MAM """ + """ Check natural recovery to MAM by removing death rate for those with + severe wasting, and check the onset of symptoms with SAM and revolving + of symptoms when recovered to MAM """ dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) @@ -250,9 +281,12 @@ def test_recovery_severe_wasting_without_complications(tmpdir): # get wasting module wmodule = sim.modules['Wasting'] - # increase wasting incidence rate to 100% for all age groups(less than 5 years) - wmodule.parameters['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] - wmodule.parameters['progression_severe_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + # increase wasting incidence rate to 100% for all + # age groups(less than 5 years) + wmodule.parameters['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, + 1.0, 1.0] + wmodule.parameters['progression_severe_wasting_by_agegp'] = [1.0, 1.0, 1.0, + 1.0, 1.0, 1.0] # re-initialise wasting linear models to use the updated parameter wmodule.pre_initialise_population() @@ -270,10 +304,11 @@ def test_recovery_severe_wasting_without_complications(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Check that there is a ProgressionSevereWastingEvent scheduled for this person: - progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ProgressionSevereWastingEvent) - ][0] + # Check that there is a ProgressionSevereWastingEvent scheduled + # for this person: + progression_event_tuple = \ + [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], ProgressionSevereWastingEvent)][0] date_of_scheduled_progression = progression_event_tuple[0] progression_event = progression_event_tuple[1] assert date_of_scheduled_progression > sim.date @@ -283,9 +318,12 @@ def test_recovery_severe_wasting_without_complications(tmpdir): progression_event.apply(person_id=person_id) # Check individuals have symptoms caused by Wasting (SAM only) - assert 0 < len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) + assert 0 < len(sim.modules['SymptomManager'].has_what(person_id, + sim.modules[ + 'Wasting'])) - # Check properties of this individual: (should now be severely wasted and without a scheduled death date) + # Check properties of this individual: (should now be severely wasted and + # without a scheduled death date) person = df.loc[person_id] assert person['un_ever_wasted'] assert person['un_WHZ_category'] == 'WHZ<-3' @@ -298,30 +336,41 @@ def test_recovery_severe_wasting_without_complications(tmpdir): hsp.run() # check non-emergency care event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - - # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought - ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] + assert isinstance( + sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + + # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and + # check care was sought + ge = [ev[1] for ev in + sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + ][0] ge.run(squeeze_factor=0.0) # check HSI event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - HSI_Wasting_OutpatientTherapeuticProgramme_SAM) - - # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought - sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] + assert isinstance( + sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + + # Run the created instance of + # HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + sam_ev = [ev[1] for ev in + sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], + HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] sam_ev.run(squeeze_factor=0.0) # check recovery event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[1][1], ClinicalAcuteMalnutritionRecoveryEvent) + assert isinstance(sim.find_events_for_person(person_id)[1][1], + ClinicalAcuteMalnutritionRecoveryEvent) # Run the recovery event and check the individual has recovered from SAM: - sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent) - ][0] + sam_recovery_event_tuple = \ + [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent) + ][0] date_of_scheduled_recovery_to_mam = sam_recovery_event_tuple[0] sam_recovery_event = sam_recovery_event_tuple[1] @@ -338,7 +387,9 @@ def test_recovery_severe_wasting_without_complications(tmpdir): assert pd.isnull(person['un_sam_death_date']) # check they have no symptoms: - assert 0 == len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) + assert 0 == len(sim.modules['SymptomManager'].has_what(person_id, + sim.modules[ + 'Wasting'])) def test_recovery_severe_wasting_with_complications(tmpdir): @@ -359,7 +410,8 @@ def test_recovery_severe_wasting_with_complications(tmpdir): # get wasting module wmodule = sim.modules['Wasting'] - # Manually set this individual properties to have severe acute malnutrition with complications + # Manually set this individual properties to have + # severe acute malnutrition with complications df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' # make the individual have wasting complications @@ -375,12 +427,14 @@ def test_recovery_severe_wasting_with_complications(tmpdir): assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' # symptoms should be applied - assert person_id in set(sim.modules['SymptomManager'].who_has('weight_loss')) + assert person_id in set( + sim.modules['SymptomManager'].who_has('weight_loss')) # should have complications assert df.at[person_id, 'un_sam_with_complications'] - # make recovery rate to 100% and death rate to zero so that this individual should recover + # make recovery rate to 100% and death rate to zero so that + # this individual should recover wasting_module = sim.modules['Wasting'] wasting_module.parameters['recovery_rate_with_inpatient_care'] = 1.0 wasting_module.parameters['base_death_rate_untreated_SAM'] = 0.0 @@ -393,30 +447,41 @@ def test_recovery_severe_wasting_with_complications(tmpdir): hsp.run() # check non-emergency care event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - - # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought - ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] + assert isinstance( + sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + + # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and + # check care was sought + ge = [ev[1] for ev in + sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + ][0] ge.run(squeeze_factor=0.0) # check HSI event for complicated SAM is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - HSI_Wasting_InpatientCareForComplicated_SAM) - - # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought - sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], HSI_Wasting_InpatientCareForComplicated_SAM)][0] + assert isinstance( + sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + HSI_Wasting_InpatientCareForComplicated_SAM) + + # Run the created instance of + # HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + sam_ev = [ev[1] for ev in + sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], HSI_Wasting_InpatientCareForComplicated_SAM)][ + 0] sam_ev.run(squeeze_factor=0.0) # check recovery event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[0][1], ClinicalAcuteMalnutritionRecoveryEvent) + assert isinstance(sim.find_events_for_person(person_id)[0][1], + ClinicalAcuteMalnutritionRecoveryEvent) # Run the recovery event and check the individual has recovered from SAM: - sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent) - ][0] + sam_recovery_event_tuple = \ + [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], + ClinicalAcuteMalnutritionRecoveryEvent)][0] date_of_scheduled_recovery_to_mam = sam_recovery_event_tuple[0] sam_recovery_event = sam_recovery_event_tuple[1] @@ -433,7 +498,9 @@ def test_recovery_severe_wasting_with_complications(tmpdir): assert pd.isnull(person['un_sam_death_date']) # check they have no symptoms: - assert 0 == len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) + assert 0 == len(sim.modules['SymptomManager'].has_what(person_id, + sim.modules[ + 'Wasting'])) def test_nat_hist_death(tmpdir): @@ -466,7 +533,8 @@ def test_nat_hist_death(tmpdir): # re-initialise wasting models wasting_module.pre_initialise_population() - # make an individual diagnosed as SAM by WHZ category. We want to make this individual qualify for death + # make an individual diagnosed as SAM by WHZ category. + # We want to make this individual qualify for death df.loc[person_id, 'un_ever_wasted'] = True df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' df.loc[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' @@ -475,37 +543,48 @@ def test_nat_hist_death(tmpdir): wasting_module.wasting_clinical_symptoms(person_id) # check symptoms are applied - assert person_id in set(sim.modules['SymptomManager'].who_has('weight_loss')) + assert person_id in set( + sim.modules['SymptomManager'].who_has('weight_loss')) # run health seeking behavior and ensure non-emergency event is scheduled hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) hsp.run() # check non-emergency care event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - - # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought - ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] + assert isinstance( + sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + + # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 + # and check care was sought + ge = [ev[1] for ev in + sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + ][0] ge.run(squeeze_factor=0.0) # check inpatient care event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - HSI_Wasting_OutpatientTherapeuticProgramme_SAM) - - # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought - sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] + assert isinstance( + sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + + # Run the created instance of + # HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + sam_ev = [ev[1] for ev in + sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], + HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] sam_ev.run(squeeze_factor=0.0) # since there is zero recovery rate, check death event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[0][1], SevereAcuteMalnutritionDeathEvent) + assert isinstance(sim.find_events_for_person(person_id)[0][1], + SevereAcuteMalnutritionDeathEvent) # # Run the acute death event and ensure the person is now dead: - death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) - ][0] + death_event_tuple = \ + [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent)][0] date_of_scheduled_death = death_event_tuple[0] death_event = death_event_tuple[1] assert date_of_scheduled_death > sim.date @@ -520,8 +599,8 @@ def test_nat_hist_death(tmpdir): def test_nat_hist_cure_if_recovery_scheduled(tmpdir): - """Show that if a cure event is run before when a person was going to recover naturally, it cause the episode to - end earlier.""" + """ Show that if a cure event is run before when a person was going to + recover naturally, it causes the episode to end earlier. """ dur = pd.DateOffset(days=0) popsize = 1000 @@ -536,10 +615,19 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): LinearModelType.MULTIPLICATIVE, 0.0) wasting_module = sim.modules['Wasting'] - # increase wasting incidence rate to 100% and reduce rate of progress to severe wasting to zero. - # Wwe don't want individuals to progress to SAM as we are testing for MAM natural recovery - wasting_module.parameters['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] - wasting_module.parameters['progression_severe_wasting_by_agegp'] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + # increase wasting incidence rate to 100% and reduce rate of progress to + # severe wasting to zero.We don't want individuals to progress to SAM as + # we are testing for MAM natural recovery + wasting_module.parameters['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, + 1.0, 1.0, + 1.0, 1.0] + wasting_module.parameters['progression_severe_wasting_by_agegp'] = [0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0] + wasting_module.pre_initialise_population() # Get person to use: df = sim.population.props @@ -551,7 +639,8 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): polling = WastingPollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) - # Check properties of this individual: (should now be moderately wasted without progression to severe) + # Check properties of this individual: (should now be moderately wasted + # without progression to severe) person = df.loc[person_id] assert person['un_ever_wasted'] assert person['un_WHZ_category'] == '-3<=WHZ<-2' @@ -560,16 +649,19 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Check that there is a WastingNaturalRecoveryEvent scheduled for this person: - recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], WastingNaturalRecoveryEvent) - ][0] + # Check that there is a WastingNaturalRecoveryEvent scheduled for + # this person: + recov_event_tuple = \ + [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], WastingNaturalRecoveryEvent)][0] date_of_scheduled_recov = recov_event_tuple[0] recov_event = recov_event_tuple[1] assert date_of_scheduled_recov > sim.date # Run a Cure Event - cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) + cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, + module=sim.modules[ + 'Wasting']) cure_event.apply(person_id=person_id) # Check that the person is not wasted and is alive still: @@ -579,7 +671,8 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): assert not pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Run the recovery event that was originally scheduled - this should have no effect + # Run the recovery event that was originally scheduled - + # this should have no effect sim.date = date_of_scheduled_recov recov_event.apply(person_id=person_id) person = df.loc[person_id] @@ -590,8 +683,8 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): def test_nat_hist_cure_if_death_scheduled(tmpdir): - """Show that if a cure event is run before when a person was going to die, it causes the episode to end without - the person dying.""" + """Show that if a cure event is run before when a person was going to die, + it causes the episode to end without the person dying.""" dur = pd.DateOffset(days=0) popsize = 1000 @@ -606,15 +699,22 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): # increase to 100% death rate, incidence and progress to severe wasting params['base_death_rate_untreated_SAM'] = 1.0 params['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] - params['progression_severe_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] - # reduce to 100% recovery rate. This is to ensure death event is scheduled for the individual each time we run this + params['progression_severe_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, + 1.0] + params['prob_mam_death_after_care'] = [0.0, 1.0] + + # reduce to 100% recovery rate. This is to ensure death event is scheduled + # for the individual each time we run this # test params['recovery_rate_with_standard_RUTF'] = 0.0 params['recovery_rate_with_inpatient_care'] = 0.0 - # increase parameters in moderate wasting for clinical SAM (MUAC and oedema) to be polled for death - params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = [5 * params['proportion_-3<=WHZ<-2_with_MUAC<115mm']] - params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] = [params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] / 5] + # increase parameters in moderate wasting for clinical SAM + # (MUAC and oedema) to be polled for death + params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = [ + 5 * params['proportion_-3<=WHZ<-2_with_MUAC<115mm']] + params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] = [ + params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] / 5] params['proportion_oedema_with_WHZ<-2'] = 0.9 # re-initialise wasting models @@ -630,7 +730,8 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): polling = WastingPollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) - # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) + # Check properties of this individual: (should now be moderately wasted + # with a scheduled progression to severe date) person = df.loc[person_id] assert person['un_ever_wasted'] assert person['un_WHZ_category'] == '-3<=WHZ<-2' @@ -639,10 +740,11 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Check that there is a ProgressionSevereWastingEvent scheduled for this person: - progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ProgressionSevereWastingEvent) - ][0] + # Check that there is a ProgressionSevereWastingEvent scheduled for this + # person: + progression_event_tuple = \ + [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], ProgressionSevereWastingEvent)][0] date_of_scheduled_progression = progression_event_tuple[0] progression_event = progression_event_tuple[1] assert date_of_scheduled_progression > sim.date @@ -651,7 +753,8 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): sim.date = date_of_scheduled_progression progression_event.apply(person_id=person_id) - # Check properties of this individual: (should now be severely wasted and without a scheduled death date) + # Check properties of this individual: (should now be severely wasted and + # without a scheduled death date) person = df.loc[person_id] assert person['un_ever_wasted'] assert person['un_WHZ_category'] == 'WHZ<-3' @@ -665,36 +768,48 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): hsp.run() # check non-emergency care event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - - # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought - ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] + assert isinstance( + sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + + # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and + # check care was sought + ge = [ev[1] for ev in + sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + ][0] ge.run(squeeze_factor=0.0) # check inpatient care event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - HSI_Wasting_OutpatientTherapeuticProgramme_SAM) - - # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought - sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] + assert isinstance( + sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + + # Run the created instance of + # HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + sam_ev = [ev[1] for ev in + sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], + HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] sam_ev.run(squeeze_factor=0.0) # since there is zero recovery rate, check death event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[1][1], SevereAcuteMalnutritionDeathEvent) + assert isinstance(sim.find_events_for_person(person_id)[1][1], + SevereAcuteMalnutritionDeathEvent) # Run Severe Acute Malnutrition Death Event scheduled for this person: - death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent) - ][0] + death_event_tuple = \ + [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent)][0] date_of_scheduled_death = death_event_tuple[0] death_event = death_event_tuple[1] assert date_of_scheduled_death > sim.date # Run a Cure Event now - cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) + cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, + module=sim.modules[ + 'Wasting']) cure_event.apply(person_id=person_id) # Check that the person is not wasted and is alive still: @@ -704,7 +819,8 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): assert not pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Run the death event that was originally scheduled - this should have no effect and the person should not die + # Run the death event that was originally scheduled - this should have no + # effect and the person should not die sim.date = date_of_scheduled_death death_event.apply(person_id=person_id) person = df.loc[person_id] From 2e68ce4012b6d8665da62397ab0cd3a4e843b9dc Mon Sep 17 00:00:00 2001 From: mnjowe Date: Thu, 7 Dec 2023 12:25:02 +0200 Subject: [PATCH 024/755] run from simulation --- .../wasting_analyses/analysis_wasting.py | 57 +++++++++---------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 2f1555c507..d9094b26d9 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -151,37 +151,36 @@ def plot_modal_gbd_deaths_by_gender(self): pop_size = 10000 # Create simulation instance for this run. -# sim = Simulation(start_date=start_date, seed=seed, log_config=log_config) -# -# # Register modules for simulation -# sim.register( -# demography.Demography(resourcefilepath=resources), -# healthsystem.HealthSystem(resourcefilepath=resources, -# service_availability=['*'], -# cons_availability='default'), -# healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resources), -# healthburden.HealthBurden(resourcefilepath=resources), -# symptommanager.SymptomManager(resourcefilepath=resources), -# enhanced_lifestyle.Lifestyle(resourcefilepath=resources), -# labour.Labour(resourcefilepath=resources), -# care_of_women_during_pregnancy.CareOfWomenDuringPregnancy( -# resourcefilepath=resources), -# contraception.Contraception(resourcefilepath=resources), -# pregnancy_supervisor.PregnancySupervisor(resourcefilepath=resources), -# postnatal_supervisor.PostnatalSupervisor(resourcefilepath=resources), -# newborn_outcomes.NewbornOutcomes(resourcefilepath=resources), -# hiv.Hiv(resourcefilepath=resources), -# tb.Tb(resourcefilepath=resources), -# epi.Epi(resourcefilepath=resources), -# wasting.Wasting(resourcefilepath=resources), -# ) -# -# sim.make_initial_population(n=pop_size) -# sim.simulate(end_date=end_date) +sim = Simulation(start_date=start_date, seed=seed, log_config=log_config) + +# Register modules for simulation +sim.register( + demography.Demography(resourcefilepath=resources), + healthsystem.HealthSystem(resourcefilepath=resources, + service_availability=['*'], + cons_availability='default'), + healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resources), + healthburden.HealthBurden(resourcefilepath=resources), + symptommanager.SymptomManager(resourcefilepath=resources), + enhanced_lifestyle.Lifestyle(resourcefilepath=resources), + labour.Labour(resourcefilepath=resources), + care_of_women_during_pregnancy.CareOfWomenDuringPregnancy( + resourcefilepath=resources), + contraception.Contraception(resourcefilepath=resources), + pregnancy_supervisor.PregnancySupervisor(resourcefilepath=resources), + postnatal_supervisor.PostnatalSupervisor(resourcefilepath=resources), + newborn_outcomes.NewbornOutcomes(resourcefilepath=resources), + hiv.Hiv(resourcefilepath=resources), + tb.Tb(resourcefilepath=resources), + epi.Epi(resourcefilepath=resources), + wasting.Wasting(resourcefilepath=resources), +) + +sim.make_initial_population(n=pop_size) +sim.simulate(end_date=end_date) # read the results -# output_path = sim.log_filepath -output_path = Path('./outputs/wasting__2023-12-06T214307.log') +output_path = sim.log_filepath # initialise the wasting class wasting_analyses = WastingAnalyses(output_path) From b9029229e20ae183be3640400ec502c3630618e5 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Mon, 11 Dec 2023 14:25:08 +0200 Subject: [PATCH 025/755] resolving test health system error, changed values in resource file for plotting --- resources/ResourceFile_Wasting.xlsx | 4 ++-- .../wasting_analyses/analysis_wasting.py | 9 ++++++++- src/tlo/methods/wasting.py | 18 +++++++++++++----- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/resources/ResourceFile_Wasting.xlsx b/resources/ResourceFile_Wasting.xlsx index f3ea31b1d3..162099f180 100644 --- a/resources/ResourceFile_Wasting.xlsx +++ b/resources/ResourceFile_Wasting.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:88f8a9ed379ca3216fe2db19cef499bd6d150d40ed9233f2085e010db6f00150 -size 12511 +oid sha256:8bb674c8313b23ab955828ece7805a4fa2dc7c37d0b9d39322327b73c5dc2989 +size 12512 diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index d9094b26d9..b2ec48d82c 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -57,7 +57,10 @@ def plot_wasting_incidence(self): w_inc_df.drop(columns='date', inplace=True) # get age year. doesn't matter what wasting category you choose for # they all have same age groups - age_years = w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys() + age_years = list(w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys( + + )) + age_years.remove('5+y') _row_counter = 0 _col_counter = 0 @@ -85,6 +88,7 @@ def plot_wasting_incidence(self): _col_counter = -1 _col_counter += 1 # increment column counter fig.tight_layout() + plt.show() def plot_wasting_prevalence(self): w_prev_df = self.__logs_dict['wasting_prevalence_count'] @@ -96,6 +100,7 @@ def plot_wasting_prevalence(self): ylabel='proportions', xlabel='year' ) + plt.show() def plot_modal_gbd_deaths_by_gender(self): """ compare modal and GBD deaths by gender """ @@ -122,6 +127,8 @@ def plot_modal_gbd_deaths_by_gender(self): format="pdf" ) + plt.show() + seed = 1 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index b792059422..d23398edac 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -7,7 +7,12 @@ from scipy.stats import norm from tlo import DateOffset, Module, Parameter, Property, Types, logging -from tlo.events import Event, IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent +from tlo.events import ( + Event, + IndividualScopeEventMixin, + PopulationScopeEventMixin, + RegularEvent +) from tlo.lm import LinearModel, LinearModelType, Predictor from tlo.methods import Metadata from tlo.methods.causes import Cause @@ -985,12 +990,14 @@ def apply(self, population): df.un_WHZ_category == '-3<=WHZ<-2')] progression_severe_wasting = \ self.module.wasting_models.get_wasting_progression().predict( - progression_sev_wasting, rng) + progression_sev_wasting) - progression_sev_wasting_idx = progression_sev_wasting.index + progression_severe_wasting = rng.random_sample(len( + progression_sev_wasting)) < progression_severe_wasting # determine those individuals who will progress to severe wasting # and time of progression - for person in progression_sev_wasting_idx[progression_severe_wasting]: + for person in progression_sev_wasting.index[ + progression_severe_wasting]: outcome_date = self.module.date_of_outcome_for_untreated_am( person_id=person, duration_am='MAM') # schedule severe wasting WHZ<-3 onset @@ -1010,7 +1017,8 @@ def apply(self, population): # # # # # # #MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # moderate wasting not progressed to severe, schedule recovery - for person in progression_sev_wasting_idx[~progression_severe_wasting]: + for person in progression_sev_wasting.index[ + ~progression_severe_wasting]: outcome_date = self.module.date_of_outcome_for_untreated_am( person_id=person, duration_am='MAM') if outcome_date <= self.sim.date: From 07687754c86e9697b6a5c68b23bea48a0fc43ae9 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Mon, 11 Dec 2023 14:40:47 +0200 Subject: [PATCH 026/755] correcting imports --- src/tlo/methods/wasting.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index d23398edac..aaa5f19da5 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -7,12 +7,7 @@ from scipy.stats import norm from tlo import DateOffset, Module, Parameter, Property, Types, logging -from tlo.events import ( - Event, - IndividualScopeEventMixin, - PopulationScopeEventMixin, - RegularEvent -) +from tlo.events import Event, IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.lm import LinearModel, LinearModelType, Predictor from tlo.methods import Metadata from tlo.methods.causes import Cause From 721ed0ce27daf05166192ff145aca8277213f168 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Tue, 19 Dec 2023 12:12:41 +0200 Subject: [PATCH 027/755] linting --- src/tlo/methods/wasting.py | 1072 ++++++++++++------------------------ 1 file changed, 356 insertions(+), 716 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index aaa5f19da5..f020345547 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -26,19 +26,14 @@ # --------------------------------------------------------------------------- class Wasting(Module): """ - This module applies the prevalence of wasting at the population-level, - based on the Malawi DHS Survey 2015-2016. + This module applies the prevalence of wasting at the population-level, based on the Malawi DHS Survey 2015-2016. The definitions: - - moderate wasting: weight_for_height Z-score (WHZ) <-2 SD from the - reference mean - - severe wasting: weight_for_height Z-score (WHZ) <-3 SD from the - reference mean + - moderate wasting: weight_for_height Z-score (WHZ) <-2 SD from the reference mean + - severe wasting: weight_for_height Z-score (WHZ) <-3 SD from the reference mean """ - INIT_DEPENDENCIES = {'Demography', 'SymptomManager', 'NewbornOutcomes', - 'HealthBurden' - } + INIT_DEPENDENCIES = {'Demography', 'SymptomManager', 'NewbornOutcomes', 'HealthBurden'} METADATA = { Metadata.DISEASE_MODULE, @@ -62,11 +57,9 @@ class Wasting(Module): PARAMETERS = { # prevalence of wasting by age group 'prev_WHZ_distribution_age_0_5mo': Parameter( - Types.LIST, - 'distribution of WHZ among less than 6 months of age in 2015'), + Types.LIST, 'distribution of WHZ among less than 6 months of age in 2015'), 'prev_WHZ_distribution_age_6_11mo': Parameter( - Types.LIST, - 'distribution of WHZ among 6 months and 1 year of age in 2015'), + Types.LIST, 'distribution of WHZ among 6 months and 1 year of age in 2015'), 'prev_WHZ_distribution_age_12_23mo': Parameter( Types.LIST, 'distribution of WHZ among 1 year olds in 2015'), 'prev_WHZ_distribution_age_24_35mo': Parameter( @@ -77,105 +70,65 @@ class Wasting(Module): Types.LIST, 'distribution of WHZ among 4 year olds in 2015'), # effect of risk factors on wasting prevalence 'or_wasting_hhwealth_Q5': Parameter( - Types.REAL, 'odds ratio of wasting if household wealth is ' - 'poorest Q5, ref group Q1'), + Types.REAL, 'odds ratio of wasting if household wealth is poorest Q5, ref group Q1'), 'or_wasting_hhwealth_Q4': Parameter( - Types.REAL, 'odds ratio of wasting if household wealth is ' - 'poorer Q4, ref group Q1'), + Types.REAL, 'odds ratio of wasting if household wealth is poorer Q4, ref group Q1'), 'or_wasting_hhwealth_Q3': Parameter( - Types.REAL, 'odds ratio of wasting if household wealth is ' - 'middle Q3, ref group Q1'), + Types.REAL, 'odds ratio of wasting if household wealth is middle Q3, ref group Q1'), 'or_wasting_hhwealth_Q2': Parameter( - Types.REAL, 'odds ratio of wasting if household wealth is ' - 'richer Q2, ref group Q1'), + Types.REAL, 'odds ratio of wasting if household wealth is richer Q2, ref group Q1'), 'or_wasting_preterm_and_AGA': Parameter( - Types.REAL, 'odds ratio of wasting if born preterm and adequate ' - 'for gestational age'), + Types.REAL, 'odds ratio of wasting if born preterm and adequate for gestational age'), 'or_wasting_SGA_and_term': Parameter( - Types.REAL, - 'odds ratio of wasting if born term and small for gestational ' - 'age'), + Types.REAL, 'odds ratio of wasting if born term and small for gestational age'), 'or_wasting_SGA_and_preterm': Parameter( - Types.REAL, - 'odds ratio of wasting if born preterm and small for ' - 'gestational age'), + Types.REAL, 'odds ratio of wasting if born preterm and small for gestational age'), # incidence parameters 'base_inc_rate_wasting_by_agegp': Parameter( - Types.LIST, - 'List with baseline incidence of wasting by age group'), + Types.LIST, 'List with baseline incidence of wasting by age group'), 'rr_wasting_preterm_and_AGA': Parameter( - Types.REAL, - 'relative risk of wasting if born preterm and adequate for ' - 'gestational age'), + Types.REAL, 'relative risk of wasting if born preterm and adequate for gestational age'), 'rr_wasting_SGA_and_term': Parameter( - Types.REAL, - 'relative risk of wasting if born term and small for ' - 'geatational age'), + Types.REAL, 'relative risk of wasting if born term and small for geatational age'), 'rr_wasting_SGA_and_preterm': Parameter( - Types.REAL, - 'relative risk of wasting if born preterm and small for ' - 'gestational age'), + Types.REAL, 'relative risk of wasting if born preterm and small for gestational age'), 'rr_wasting_wealth_level': Parameter( - Types.REAL, - 'relative risk of wasting per 1 unit decrease in wealth level'), + Types.REAL, 'relative risk of wasting per 1 unit decrease in wealth level'), 'min_days_duration_of_wasting': Parameter( Types.REAL, 'minimum duration in days of wasting (MAM and SAM)'), 'average_duration_of_untreated_MAM': Parameter( Types.REAL, 'average duration of untreated MAM'), # progression to severe parameters 'progression_severe_wasting_by_agegp': Parameter( - Types.LIST, - 'List with progression rates to severe wasting by age group'), + Types.LIST, 'List with progression rates to severe wasting by age group'), 'average_duration_of_untreated_SAM': Parameter( Types.REAL, 'average duration of untreated SAM'), 'prob_complications_in_SAM': Parameter( Types.REAL, 'probability of medical complications in SAM '), # recovery parameters 'recovery_rate_with_standard_RUTF': Parameter( - Types.REAL, - 'probability of recovery from wasting following treatment with ' - 'standard RUTF'), + Types.REAL, 'probability of recovery from wasting following treatment with standard RUTF'), 'recovery_rate_with_soy_RUSF': Parameter( - Types.REAL, - 'probability of recovery from wasting following treatment with ' - 'soy RUSF'), + Types.REAL, 'probability of recovery from wasting following treatment with soy RUSF'), 'recovery_rate_with_CSB++': Parameter( - Types.REAL, - 'probability of recovery from wasting following treatment with ' - 'CSB++'), + Types.REAL, 'probability of recovery from wasting following treatment with CSB++'), 'recovery_rate_with_inpatient_care': Parameter( - Types.REAL, - 'probability of recovery from wasting following treatment with ' - 'inpatient care'), + Types.REAL, 'probability of recovery from wasting following treatment with inpatient care'), # MUAC distributions 'MUAC_distribution_WHZ<-3': Parameter( - Types.LIST, - 'mean and standard deviation of a normal distribution of MUAC ' - 'measurements for WHZ<-3'), + Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ<-3'), 'MUAC_distribution_-3<=WHZ<-2': Parameter( - Types.LIST, - 'mean and standard deviation of a normal distribution of MUAC ' - 'measurements for -3<=WHZ<-2'), + Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for -3<=WHZ<-2'), 'MUAC_distribution_WHZ>=-2': Parameter( - Types.LIST, - 'mean and standard deviation of a normal distribution of MUAC ' - 'measurements for WHZ>=-2'), - + Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ>=-2'), 'proportion_WHZ<-3_with_MUAC<115mm': Parameter( - Types.REAL, - 'proportion of severe weight-for-height Z-score with MUAC<115mm'), + Types.REAL, 'proportion of severe weight-for-height Z-score with MUAC<115mm'), 'proportion_-3<=WHZ<-2_with_MUAC<115mm': Parameter( - Types.REAL, - 'proportion of moderate weight-for-height Z-score with ' - 'MUAC<115mm'), + Types.REAL, 'proportion of moderate weight-for-height Z-score with MUAC<115mm'), 'proportion_-3<=WHZ<-2_with_MUAC_115-<125mm': Parameter( - Types.REAL, - 'proportion of moderate weight-for-height Z-score with MUAC ' - 'between 115mm and 125mm'), + Types.REAL, 'proportion of moderate weight-for-height Z-score with MUAC between 115mm and 125mm'), 'proportion_mam_with_MUAC_115-<125mm_and_normal_whz': Parameter( - Types.REAL, - 'proportion of mam cases with MUAC between 115mm and 125mm and ' - 'normal/mild WHZ'), + Types.REAL, 'proportion of mam cases with MUAC between 115mm and 125mm and normal/mild WHZ'), 'proportion_mam_with_MUAC_115-<125mm_and_-3<=WHZ<-2': Parameter( Types.REAL, 'proportion of mam cases with both MUAC between 115mm and ' @@ -183,111 +136,64 @@ class Wasting(Module): 'proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC': Parameter( Types.REAL, 'proportion of mam cases with moderate wasting and normal MUAC'), - # bilateral oedema 'prevalence_nutritional_oedema': Parameter( - Types.REAL, - 'prevalence of nutritional oedema in children under 5 in Malawi'), + Types.REAL, 'prevalence of nutritional oedema in children under 5 in Malawi'), 'proportion_oedema_with_WHZ<-2': Parameter( - Types.REAL, - 'proportion of oedematous malnutrition with concurrent wasting'), + Types.REAL, 'proportion of oedematous malnutrition with concurrent wasting'), # death CFR, risk factors 'base_death_rate_untreated_SAM': Parameter( Types.REAL, 'baseline death rate of untreated SAM'), 'rr_SAM_death_with_complications': Parameter( Types.REAL, 'relative rate of death for complicated SAM'), 'rr_SAM_death_WHZ<-3_only': Parameter( - Types.REAL, - 'relative risk of death from SAM if indices of WHZ<-3, ' - 'compared to MUAC<115mm'), + Types.REAL, 'relative risk of death from SAM if indices of WHZ<-3, compared to MUAC<115mm'), 'rr_SAM_death_both_WHZ<-3_&_MUAC<115mm': Parameter( - Types.REAL, - 'relative risk of death from SAM if both indices WHZ<-3 & ' - 'MUAC<115mm are present, ' - 'compared to MUAC<115mm alone'), + Types.REAL, 'relative risk of death from SAM if both indices WHZ<-3 & MUAC<115mm are present, ' + 'compared to MUAC<115mm alone'), 'rr_SAM_death_kwashiorkor_only': Parameter( Types.REAL, - 'relative risk of death from SAM if bilateral oedema present (' - 'kwashiorkor), ' - 'compared to MUAC<115mm alone'), + 'relative risk of death from SAM if bilateral oedema present (kwashiorkor), compared to MUAC<115mm alone'), 'rr_SAM_death_kwashiorkor_MUAC<115mm_only': Parameter( - Types.REAL, - 'relative risk of death from SAM if bilateral oedema present ' - 'and MUAC<115mm, ' - 'compared to MUAC<115mm alone'), + Types.REAL, 'relative risk of death from SAM if bilateral oedema present and MUAC<115mm, compared to ' + 'MUAC<115mm alone'), 'rr_SAM_death_kwashiorkor_WHZ<-3_only': Parameter( - Types.REAL, - 'relative risk of death from SAM if bilateral oedema present ' - 'and WHZ<-3, ' - 'compared to MUAC<115mm alone'), + Types.REAL, 'relative risk of death from SAM if bilateral oedema present and WHZ<-3, compared to ' + 'MUAC<115mm alone'), 'rr_SAM_death_kwashiorkor_both_WHZ<-3_&_MUAC<115mm': Parameter( - Types.REAL, - 'relative risk of death from SAM if bilateral oedema present, ' - 'WHZ<-3 and MUAC<115mm, ' - 'compared to MUAC<115mm alone'), + Types.REAL, 'relative risk of death from SAM if bilateral oedema present, WHZ<-3 and MUAC<115mm, ' + 'compared to MUAC<115mm alone'), # treatment parameters 'coverage_supplementary_feeding_program': Parameter( - Types.REAL, - 'coverage of supplementary feeding program for MAM in health ' - 'centres'), + Types.REAL, 'coverage of supplementary feeding program for MAM in health centres'), 'coverage_outpatient_therapeutic_care': Parameter( - Types.REAL, - 'coverage of outpatient therapeutic care for SAM in health ' - 'centres'), + Types.REAL, 'coverage of outpatient therapeutic care for SAM in health centres'), 'coverage_inpatient_care': Parameter( - Types.REAL, - 'coverage of inpatient care for complicated SAM in hospitals'), + Types.REAL, 'coverage of inpatient care for complicated SAM in hospitals'), 'prob_mam_death_after_care': Parameter( - Types.LIST, - 'probability of dying or returning to MAM after seeking care'), + Types.LIST, 'probability of dying or returning to MAM after seeking care'), } PROPERTIES = { # Properties related to wasting 'un_ever_wasted': Property(Types.BOOL, 'had wasting before WHZ <-2'), - 'un_WHZ_category': Property(Types.CATEGORICAL, - 'weight-for-height z-score group', - categories=['WHZ<-3', '-3<=WHZ<-2', - 'WHZ>=-2']), - 'un_last_wasting_date_of_onset': Property(Types.DATE, - 'date of onset of latest ' - 'wasting episode'), + 'un_WHZ_category': Property(Types.CATEGORICAL, 'weight-for-height z-score group', + categories=['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2']), + 'un_last_wasting_date_of_onset': Property(Types.DATE, 'date of onset of latest wasting episode'), # Properties related to clinical acute malnutrition - 'un_clinical_acute_malnutrition': Property(Types.CATEGORICAL, - 'clinical acute ' - 'malnutrition state ' - 'based on WHZ', - categories=['MAM', - 'SAM'] + [ - 'well']), - 'un_am_bilateral_oedema': Property(Types.BOOL, - 'bilateral oedema present in ' - 'wasting'), - 'un_am_MUAC_category': Property(Types.CATEGORICAL, - 'MUAC measurement categories', - categories=['<115mm', '115-<125mm', - '>=125mm']), - 'un_sam_with_complications': Property(Types.BOOL, - 'medical complications in SAM'), - 'un_sam_death_date': Property(Types.DATE, - 'death date from severe acute ' - 'malnutrition'), - 'un_am_recovery_date': Property(Types.DATE, - 'recovery date from acute ' - 'malnutrition'), - 'un_am_discharge_date': Property(Types.DATE, - 'discharge date from treatment of ' - 'MAM/ SAM'), - 'un_acute_malnutrition_tx_start_date': Property(Types.DATE, - 'intervention ' - 'start date'), - 'un_am_treatment_type': Property(Types.CATEGORICAL, - 'treatment types for acute ' - 'malnutrition', - categories=['standard_RUTF', - 'soy_RUSF', 'CSB++', - 'inpatient_care'] + [ + 'un_clinical_acute_malnutrition': Property(Types.CATEGORICAL, 'clinical acute malnutrition state based on WHZ', + categories=['MAM', 'SAM'] + ['well']), + 'un_am_bilateral_oedema': Property(Types.BOOL, 'bilateral oedema present in wasting'), + 'un_am_MUAC_category': Property(Types.CATEGORICAL, 'MUAC measurement categories', + categories=['<115mm', '115-<125mm', '>=125mm']), + 'un_sam_with_complications': Property(Types.BOOL, 'medical complications in SAM'), + 'un_sam_death_date': Property(Types.DATE, 'death date from severe acute malnutrition'), + 'un_am_recovery_date': Property(Types.DATE, 'recovery date from acute malnutrition'), + 'un_am_discharge_date': Property(Types.DATE, 'discharge date from treatment of MAM/ SAM'), + 'un_acute_malnutrition_tx_start_date': Property(Types.DATE, 'intervention start date'), + 'un_am_treatment_type': Property(Types.CATEGORICAL, 'treatment types for acute malnutrition', + categories=['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care'] + [ 'none', 'not_applicable']), } @@ -312,37 +218,30 @@ def __init__(self, name=None, resourcefilepath=None): blank_counter = dict( zip(self.wasting_states, [list() for _ in self.wasting_states])) self.wasting_incident_case_tracker_blank = { - _agrp: copy.deepcopy(blank_counter) for _agrp in - ['0y', '1y', '2y', '3y', '4y', '5+y']} + _agrp: copy.deepcopy(blank_counter) for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} - self.wasting_incident_case_tracker = copy.deepcopy( - self.wasting_incident_case_tracker_blank) + self.wasting_incident_case_tracker = copy.deepcopy(self.wasting_incident_case_tracker_blank) # wasting prevalence odds by age groups self.wasting_prevalence_odds_by_age_grp: dict = dict() # wasting prevalence scaling by age group - self.age_grps_dict: dict = {_agrp: 1.0 for _agrp in - ['0_5mo', '6_11mo', '12_23mo', '24_35mo', - '36_47mo', '48_59mo']} + self.age_grps_dict: dict = {_agrp: 1.0 for _agrp in ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', + '48_59mo']} # store severe wasting by age groups probabilities self.age_grps_sev_wasting_probs: dict = dict() def read_parameters(self, data_folder): """ - :param data_folder: path of a folder supplied to the Simulation - containing data files. - - Typically, modules would read a particular file within here. + :param data_folder: path of a folder supplied to the Simulation containing data files. Typically, + modules would read a particular file within here. :return: """ # Update parameters from the resource dataframe # Read parameters from the resourcefile self.load_parameters_from_dataframe( - pd.read_excel( - Path(self.resourcefilepath) / 'ResourceFile_Wasting.xlsx', - sheet_name='Parameter_values_AM')) + pd.read_excel(Path(self.resourcefilepath) / 'ResourceFile_Wasting.xlsx', sheet_name='Parameter_values_AM')) # Declare symptoms that this module will cause and which are not # included in the generic symptoms: @@ -362,12 +261,9 @@ def pre_initialise_population(self): def initialise_population(self, population): """ - Set our property values for the initial population. - - This method is called by the simulation when creating the initial - population, and is responsible for assigning initial values, - for every individual, of those properties 'owned' by this module, - i.e. those declared in the PROPERTIES dictionary above. + Set our property values for the initial population. This method is called by the simulation when creating + the initial population, and is responsible for assigning initial values, for every individual, + of those properties 'owned' by this module, i.e. those declared in the PROPERTIES dictionary above. :param population: :return: @@ -396,31 +292,21 @@ def initialise_population(self, population): wasting_prevalence = self.wasting_models.get_wasting_prevalence() # Assign wasting categories in young children at initiation - for agegp in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), - (48, 59)]: # in months + for agegp in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months low_bound_age_in_years = agegp[0] / 12.0 high_bound_age_in_years = (1 + agegp[1]) / 12.0 # linear model external variables lm_ext_var = f'{agegp[0]}_{agegp[1]}mo' - mask = (df.is_alive & - df.age_exact_years.between(low_bound_age_in_years, - high_bound_age_in_years, - inclusive='left') - ) - prevalence_of_wasting = \ - wasting_prevalence.predict(df.loc[mask], agrp='None', - agrp_scaling=lm_ext_var) + mask = (df.is_alive & df.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, + inclusive='left')) + prevalence_of_wasting = wasting_prevalence.predict(df.loc[mask], agrp='None', agrp_scaling=lm_ext_var) # categorize into moderate (-3<=WHZ<-2) or severe (WHZ<-3) wasting - wasted = self.rng.random_sample( - len(prevalence_of_wasting)) < prevalence_of_wasting + wasted = self.rng.random_sample(len(prevalence_of_wasting)) < prevalence_of_wasting for idx in prevalence_of_wasting.index[wasted]: - probability_of_severe = self.age_grps_sev_wasting_probs[ - lm_ext_var] - wasted_category = \ - self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], - p=[probability_of_severe, - 1 - probability_of_severe]) + probability_of_severe = self.age_grps_sev_wasting_probs[lm_ext_var] + wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], p=[probability_of_severe, + 1 - probability_of_severe]) df.at[idx, 'un_WHZ_category'] = wasted_category df.at[idx, 'un_last_wasting_date_of_onset'] = self.sim.date df.at[idx, 'un_ever_wasted'] = True @@ -442,12 +328,10 @@ def initialise_simulation(self, sim): """ # schedule wasting pool event - sim.schedule_event(WastingPollingEvent(self), - sim.date + DateOffset(months=3)) + sim.schedule_event(WastingPollingEvent(self), sim.date + DateOffset(months=3)) # schedule wasting logging event - sim.schedule_event(WastingLoggingEvent(self), - sim.date + DateOffset(months=12)) + sim.schedule_event(WastingLoggingEvent(self), sim.date + DateOffset(months=12)) def on_birth(self, mother_id, child_id): """Initialise properties for a newborn individual. @@ -470,9 +354,8 @@ def on_birth(self, mother_id, child_id): def muac_cutoff_by_WHZ(self, idx, whz): """ - Proportion of MUAC<115mm in WHZ<-3 and -3<=WHZ<-2, - and proportion of wasted children with oedematous malnutrition ( - Kwashiokor, marasmic-kwashiorkor) + Proportion of MUAC<115mm in WHZ<-3 and -3<=WHZ<-2, and proportion of wasted children with oedematous + malnutrition ( Kwashiokor, marasmic-kwashiorkor) :param idx: index of children ages 6-59 months or person_id :param whz: weight for height category @@ -483,63 +366,47 @@ def muac_cutoff_by_WHZ(self, idx, whz): # -- MUAC <115mm in severe wasting (WHZ<-3) and moderate (-3<=WHZ<-2)-- if whz == 'WHZ<-3': # apply probability of MUAC<115mm in severe wasting - low_muac_in_severe_wasting = self.rng.random_sample( - size=len(idx)) < p['proportion_WHZ<-3_with_MUAC<115mm'] + low_muac_in_severe_wasting = self.rng.random_sample(size=len(idx)) < p['proportion_WHZ<-3_with_MUAC<115mm'] - df.loc[idx[ - low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '<115mm' + df.loc[idx[low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '<115mm' # other severe wasting will have MUAC between 115-<125mm - df.loc[idx[ - ~low_muac_in_severe_wasting], 'un_am_MUAC_category'] = \ - '115-<125mm' + df.loc[idx[~low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '115-<125mm' if whz == '-3<=WHZ<-2': # apply probability of MUAC<115mm in moderate wasting - low_muac_in_moderate_wasting = self.rng.random_sample( - size=len(idx)) < p['proportion_-3<=WHZ<-2_with_MUAC<115mm'] - df.loc[idx[ - low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = \ - '<115mm' + low_muac_in_moderate_wasting = self.rng.random_sample(size=len(idx)) < \ + p['proportion_-3<=WHZ<-2_with_MUAC<115mm'] + df.loc[idx[low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = '<115mm' # apply probability of MUAC between 115-<125mm in moderate wasting - moderate_low_muac_in_moderate_wasting = self.rng.random_sample( - size=len( - idx[~low_muac_in_moderate_wasting])) < p[ - 'proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] - df.loc[idx[~low_muac_in_moderate_wasting][ - moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category']\ + moderate_low_muac_in_moderate_wasting = \ + self.rng.random_sample(size=len(idx[~low_muac_in_moderate_wasting])) < \ + p['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] + df.loc[idx[~low_muac_in_moderate_wasting][moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] \ = '115-<125mm' # other moderate wasting will have normal MUAC - df.loc[idx[~low_muac_in_moderate_wasting][ - ~moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category' - ] = '>=125mm' + df.loc[idx[~low_muac_in_moderate_wasting][~moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category']\ + = '>=125mm' if whz == 'WHZ>=-2': # Give MUAC distribution for WHZ>=-2 ('well' group) --------- - muac_distribution_in_well_group = norm( - loc=p['MUAC_distribution_WHZ>=-2'][0], - scale=p['MUAC_distribution_WHZ>=-2'][1]) + muac_distribution_in_well_group = norm(loc=p['MUAC_distribution_WHZ>=-2'][0], + scale=p['MUAC_distribution_WHZ>=-2'][1]) # get probability of MUAC <115mm - probability_over_or_equal_115 = muac_distribution_in_well_group.sf( - 11.5) - probability_over_or_equal_125 = muac_distribution_in_well_group.sf( - 12.5) + probability_over_or_equal_115 = muac_distribution_in_well_group.sf(11.5) + probability_over_or_equal_125 = muac_distribution_in_well_group.sf(12.5) prob_less_than_115 = 1 - probability_over_or_equal_115 - pro_between_115_125 = \ - probability_over_or_equal_115 - probability_over_or_equal_125 + pro_between_115_125 = probability_over_or_equal_115 - probability_over_or_equal_125 for id in idx: muac_cat = self.rng.choice(['<115mm', '115-<125mm', '>=125mm'], - p=[prob_less_than_115, - pro_between_115_125, - probability_over_or_equal_125]) + p=[prob_less_than_115, pro_between_115_125, probability_over_or_equal_125]) df.at[id, 'un_am_MUAC_category'] = muac_cat def nutritional_oedema_present(self, idx): """ - This function applies the probability of bilateral oedema present - in wasting and non-wasted cases + This function applies the probability of bilateral oedema present in wasting and non-wasted cases :param idx: index of children under 5, or person_id :return: """ @@ -549,37 +416,26 @@ def nutritional_oedema_present(self, idx): # Knowing the prevalence of nutritional oedema in under 5 # population, apply the probability of oedema in WHZ<-2 # get those children with wasting - children_with_wasting = idx.intersection( - df.index[df.un_WHZ_category != 'WHZ>=-2']) - children_without_wasting = idx.intersection( - df.index[df.un_WHZ_category == 'WHZ>=-2']) + children_with_wasting = idx.intersection(df.index[df.un_WHZ_category != 'WHZ>=-2']) + children_without_wasting = idx.intersection(df.index[df.un_WHZ_category == 'WHZ>=-2']) # oedema among wasted children oedema_in_wasted_children = self.rng.random_sample(size=len( - children_with_wasting)) < p['prevalence_nutritional_oedema'] * p[ - 'proportion_oedema_with_WHZ<-2'] - df.loc[children_with_wasting[ - oedema_in_wasted_children], 'un_am_bilateral_oedema'] = True - df.loc[children_with_wasting[ - ~oedema_in_wasted_children], 'un_am_bilateral_oedema'] = False + children_with_wasting)) < p['prevalence_nutritional_oedema'] * p['proportion_oedema_with_WHZ<-2'] + df.loc[children_with_wasting[oedema_in_wasted_children], 'un_am_bilateral_oedema'] = True + df.loc[children_with_wasting[~oedema_in_wasted_children], 'un_am_bilateral_oedema'] = False # oedema among non-wasted children oedema_in_non_wasted = self.rng.random_sample(size=len( - children_without_wasting)) < p['prevalence_nutritional_oedema'] * ( - 1 - p['proportion_oedema_with_WHZ<-2']) - df.loc[children_without_wasting[ - oedema_in_non_wasted], 'un_am_bilateral_oedema'] = True - df.loc[children_without_wasting[ - ~oedema_in_non_wasted], 'un_am_bilateral_oedema'] = False + children_without_wasting)) < p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) + df.loc[children_without_wasting[oedema_in_non_wasted], 'un_am_bilateral_oedema'] = True + df.loc[children_without_wasting[~oedema_in_non_wasted], 'un_am_bilateral_oedema'] = False def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): """ - This function will determine the clinical acute malnutrition status - (MAM, SAM) based on anthropometric indices - and presence of bilateral oedema (Kwashiorkor); - And help determine whether the individual will have medical - complications, applicable to SAM cases only, - requiring inpatient care. + This function will determine the clinical acute malnutrition status (MAM, SAM) based on anthropometric indices + and presence of bilateral oedema (Kwashiorkor); And help determine whether the individual will have medical + complications, applicable to SAM cases only, requiring inpatient care. :param person_id: individual id :param pop_dataframe: population dataframe :return: @@ -588,20 +444,14 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): p = self.parameters # check if person is not wasted - if ( - (df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2') & - (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & - (~df.at[person_id, 'un_am_bilateral_oedema']) - ): + if ((df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2') & + (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & (~df.at[person_id, 'un_am_bilateral_oedema'])): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' # severe acute malnutrition - MUAC<115mm and/or WHZ<-3 and/or # bilateral oedema - elif ( - (df.at[person_id, 'un_am_MUAC_category'] == '<115mm') | - (df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3') | - (df.at[person_id, 'un_am_bilateral_oedema']) - ): + elif ((df.at[person_id, 'un_am_MUAC_category'] == '<115mm') | (df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3') + | (df.at[person_id, 'un_am_bilateral_oedema'])): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' else: @@ -616,14 +466,12 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): else: df.at[person_id, 'un_sam_with_complications'] = False - assert not (df.at[ - person_id, 'un_clinical_acute_malnutrition'] == - 'MAM') & (df.at[person_id, 'un_sam_with_complications']) + assert not (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') & \ + (df.at[person_id, 'un_sam_with_complications']) def date_of_outcome_for_untreated_am(self, person_id, duration_am): """ - helper funtion to get the duration and the wasting episode and - date of outcome (recovery, progression, or death) + helper funtion to get the duration and the wasting episode and date of outcome (recovery, progression, or death) :param person_id: :param duration_am: :return: @@ -635,34 +483,26 @@ def date_of_outcome_for_untreated_am(self, person_id, duration_am): # MAM) ----- if duration_am == 'MAM': # Allocate the duration of the moderate wasting episode - duration_mam = int(max(p['min_days_duration_of_wasting'], - p['average_duration_of_untreated_MAM'])) + duration_mam = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'])) # Allocate a date of outcome (progression, recovery or death) - date_of_outcome = df.at[person_id, - 'un_last_wasting_date_of_onset'] + \ - DateOffset(days=duration_mam) + date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_mam) return date_of_outcome # severe wasting (for death, or recovery to moderate wasting) ----- if duration_am == 'SAM': # determine the duration of SAM episode - duration_sam = int(max(p['min_days_duration_of_wasting'], - p['average_duration_of_untreated_MAM'] + - p['average_duration_of_untreated_SAM'])) + duration_sam = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'] + + p['average_duration_of_untreated_SAM'])) # Allocate a date of outcome (progression, recovery or death) - date_of_outcome = df.at[ - person_id, 'un_last_wasting_date_of_onset'] +\ - DateOffset(days=duration_sam) + date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_sam) return date_of_outcome def population_poll_clinical_am(self, population): """ - Update at the population level other anthropometric indices and - clinical signs (MUAC, oedema, medical complications) that determine - the clinical state of acute malnutrition - This will include both wasted and non-wasted children with other - signs of acute malnutrition - :param population: + Update at the population level other anthropometric indices and clinical signs (MUAC, oedema, + medical complications) that determine the clinical state of acute malnutrition This will include both wasted + and non-wasted children with other signs of acute malnutrition + :param population: population dataframe :return: """ df = population @@ -670,8 +510,7 @@ def population_poll_clinical_am(self, population): # give MUAC measurement category for all WHZ, including well # nourished children ----- for whz in ['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2']: - index_6_59mo_by_whz = df.index[df.is_alive & ( - df.age_exact_years.between(0.5, 5, inclusive='left')) + index_6_59mo_by_whz = df.index[df.is_alive & (df.age_exact_years.between(0.5, 5, inclusive='left')) & (df.un_WHZ_category == whz)] self.muac_cutoff_by_WHZ(idx=index_6_59mo_by_whz, whz=whz) @@ -682,27 +521,21 @@ def population_poll_clinical_am(self, population): # determine the clinical acute malnutrition state ----- df = self.sim.population.props for person_id in index_under5: - self.clinical_acute_malnutrition_state(person_id=person_id, - pop_dataframe=df) + self.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) def on_hsi_alert(self, person_id, treatment_id): """ - This is called whenever there is an HSI event commissioned by one - of the other disease modules. + This is called whenever there is an HSI event commissioned by one of the other disease modules. """ - logger.debug(key='message', - data=f'This is Wasting, being alerted about a health ' - f'system interaction for person' - f'{person_id} and treatment {treatment_id}') + logger.debug(key='message', data=f'This is Wasting, being alerted about a health system interaction for ' + f'person {person_id} and treatment {treatment_id}') def report_daly_values(self): """ - This must send back a pd.Series or pd.DataFrame that reports on the - average daly-weights that have been experienced by persons in the - previous month. Only rows for alive-persons must be returned. - The names of the series of columns is taken to be the label of the - cause of this disability. - It will be recorded by the healthburden module as _. + This must send back a pd.Series or pd.DataFrame that reports on the average daly-weights that have been + experienced by persons in the previous month. Only rows for alive-persons must be returned. The names of the + series of columns is taken to be the label of the cause of this disability. It will be recorded by the + healthburden module as _. """ # dict to hold the DALY weights daly_wts = dict() @@ -718,18 +551,15 @@ def report_daly_values(self): total_daly_values = pd.Series(data=0.0, index=df.index[df.is_alive]) - total_daly_values.loc[ - df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & - df.un_am_bilateral_oedema] = daly_wts['SAM_with_oedema'] - total_daly_values.loc[ - df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & - (~df.un_am_bilateral_oedema)] = daly_wts['SAM_w/o_oedema'] + total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & + df.un_am_bilateral_oedema] = daly_wts['SAM_with_oedema'] + total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & + (~df.un_am_bilateral_oedema)] = daly_wts['SAM_w/o_oedema'] total_daly_values.loc[df.is_alive & ( - ((df.un_WHZ_category == '-3<=WHZ<-2') & ( - df.un_am_MUAC_category != "<115mm")) | - ((df.un_WHZ_category != 'WHZ<-3') & ( - df.un_am_MUAC_category != "115-<125mm")) - ) & df.un_am_bilateral_oedema] = daly_wts['MAM_with_oedema'] + ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | ( + (df.un_WHZ_category != 'WHZ<-3') & ( + df.un_am_MUAC_category != "115-<125mm"))) & df.un_am_bilateral_oedema] = daly_wts[ + 'MAM_with_oedema'] return total_daly_values @@ -754,8 +584,7 @@ def wasting_clinical_symptoms(self, person_id): def do_when_acute_malnutrition_assessment(self, person_id): """ - This is called by the generic HSI event when acute malnutrition is - checked. + This is called by the generic HSI event when acute malnutrition is checked. :param person_id: :return: """ @@ -770,30 +599,20 @@ def do_when_acute_malnutrition_assessment(self, person_id): # Interventions for MAM if clinical_am == 'MAM': # Check for coverage of supplementary feeding - if self.rng.random_sample() < p[ - 'coverage_supplementary_feeding_program']: + if self.rng.random_sample() < p['coverage_supplementary_feeding_program']: # schedule HSI for supplementary feeding program for MAM - self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM - (module=self, - person_id=person_id), - priority=0, - topen=self.sim.date - ) + self.sim.modules['HealthSystem'].schedule_hsi_event(hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), priority=0, topen=self.sim.date) else: return # Interventions for uncomplicated SAM if clinical_am == 'SAM': if not complications: # Check for coverage of outpatient therapeutic care - if self.rng.random_sample() < p[ - 'coverage_outpatient_therapeutic_care']: + if self.rng.random_sample() < p['coverage_outpatient_therapeutic_care']: # schedule HSI for supplementary feeding program for MAM self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=HSI_Wasting_OutpatientTherapeuticProgramme_SAM - (module=self, person_id=person_id), priority=0, - topen=self.sim.date - ) + hsi_event=HSI_Wasting_OutpatientTherapeuticProgramme_SAM( + module=self, person_id=person_id), priority=0, topen=self.sim.date) else: return # Interventions for complicated SAM @@ -802,19 +621,14 @@ def do_when_acute_malnutrition_assessment(self, person_id): if self.rng.random_sample() < p['coverage_inpatient_care']: # schedule HSI for supplementary feeding program for MAM self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=HSI_Wasting_InpatientCareForComplicated_SAM - (module=self, - person_id=person_id), - priority=0, - topen=self.sim.date - ) + hsi_event=HSI_Wasting_InpatientCareForComplicated_SAM( + module=self, person_id=person_id), priority=0, topen=self.sim.date) else: return def do_when_am_treatment(self, person_id, intervention): """ - This function will apply the linear model of recovery based on - intervention given + This function will apply the linear model of recovery based on intervention given :param person_id: :param intervention: :return: @@ -824,105 +638,72 @@ def do_when_am_treatment(self, person_id, intervention): df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date if intervention == 'SFP': - mam_recovery = \ - self.wasting_models.get_moderate_acute_malnutrition_recovery( - ).predict( - df.loc[[person_id]], self.rng) + mam_recovery = self.wasting_models.get_moderate_acute_malnutrition_recovery().predict( + df.loc[[person_id]], self.rng) if mam_recovery: # schedule recovery date - self.sim.schedule_event( - event=ClinicalAcuteMalnutritionRecoveryEvent( - module=self, person_id=person_id), - date=df.at[ - person_id, - 'un_acute_malnutrition_tx_start_date'] + - DateOffset(weeks=3)) + self.sim.schedule_event(event=ClinicalAcuteMalnutritionRecoveryEvent( + module=self, person_id=person_id), + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) # cancel progression date (in ProgressionEvent) else: # remained MAM return if intervention == 'OTC': - sam_recovery = \ - self.wasting_models.get_severe_acute_malnutrition_recovery( - ).predict(df.loc[[person_id]], self.rng) + sam_recovery = self.wasting_models.get_severe_acute_malnutrition_recovery().predict( + df.loc[[person_id]], self.rng) if sam_recovery: # schedule recovery date - self.sim.schedule_event( - event=ClinicalAcuteMalnutritionRecoveryEvent( - module=self, person_id=person_id), - date=df.at[ - person_id, 'un_acute_malnutrition_tx_start_date'] - + DateOffset(weeks=3)) + self.sim.schedule_event(event=ClinicalAcuteMalnutritionRecoveryEvent( + module=self, person_id=person_id), + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) # cancel death date df.at[person_id, 'un_sam_death_date'] = pd.NaT else: - outcome = self.rng.choice(['remained_mam', 'death'], - p=self.parameters[ - 'prob_mam_death_after_care']) + outcome = self.rng.choice(['remained_mam', 'death'], p=self.parameters[ + 'prob_mam_death_after_care']) if outcome == 'death': - self.sim.schedule_event( - event=SevereAcuteMalnutritionDeathEvent( - module=self, person_id=person_id), - date=df.at[ - person_id, - 'un_acute_malnutrition_tx_start_date'] + - DateOffset(weeks=3)) + self.sim.schedule_event(event=SevereAcuteMalnutritionDeathEvent( + module=self, person_id=person_id), + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) else: - self.sim.schedule_event( - event=UpdateToMAM(module=self, person_id=person_id), - date=df.at[ - person_id, - 'un_acute_malnutrition_tx_start_date'] + - DateOffset(weeks=3)) + self.sim.schedule_event(event=UpdateToMAM(module=self, person_id=person_id), + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + + DateOffset(weeks=3)) if intervention == 'ITC': - sam_recovery = \ - self.wasting_models.get_severe_acute_malnutrition_recovery( - ).predict(df.loc[[person_id]], self.rng) + sam_recovery = self.wasting_models.get_severe_acute_malnutrition_recovery().predict( + df.loc[[person_id]], self.rng) if sam_recovery: # schedule recovery date - self.sim.schedule_event( - event=ClinicalAcuteMalnutritionRecoveryEvent( - module=self, person_id=person_id), - date=df.at[ - person_id, - 'un_acute_malnutrition_tx_start_date'] + - DateOffset(weeks=4)) + self.sim.schedule_event(event=ClinicalAcuteMalnutritionRecoveryEvent( + module=self, person_id=person_id), + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=4)) # cancel death date df.at[person_id, 'un_sam_death_date'] = pd.NaT else: outcome = self.rng.choice(['remained_mam', 'death'], - p=self.parameters[ - 'prob_mam_death_after_care']) + p=self.parameters['prob_mam_death_after_care']) if outcome == 'death': - self.sim.schedule_event( - event=SevereAcuteMalnutritionDeathEvent( - module=self, person_id=person_id), - date=df.at[ - person_id, - 'un_acute_malnutrition_tx_start_date'] + - DateOffset(weeks=4)) + self.sim.schedule_event(event=SevereAcuteMalnutritionDeathEvent( + module=self, person_id=person_id), + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=4)) else: self.sim.schedule_event( event=UpdateToMAM(module=self, person_id=person_id), - date=df.at[ - person_id, - 'un_acute_malnutrition_tx_start_date'] + - DateOffset(weeks=4)) + date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=4)) class WastingPollingEvent(RegularEvent, PopulationScopeEventMixin): """ - Regular event that determines new cases of wasting (WHZ<-2) to the - under-5 population, and schedules individual incident cases to - represent onset. It determines those who will progress to - severe wasting (WHZ<-3) and schedules the event to update on properties. - These are events occurring without the input of interventions, these - events reflect the natural history only. + Regular event that determines new cases of wasting (WHZ<-2) to the under-5 population, and schedules + individual incident cases to represent onset. It determines those who will progress to severe wasting + (WHZ<-3) and schedules the event to update on properties. These are events occurring without the input + of interventions, these events reflect the natural history only. """ AGE_GROUPS = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} @@ -931,8 +712,7 @@ def __init__(self, module): :param module: the module that created this event """ self.repeat_months = 1 - super().__init__(module, - frequency=DateOffset(months=self.repeat_months)) + super().__init__(module, frequency=DateOffset(months=self.repeat_months)) assert isinstance(module, Wasting) def apply(self, population): @@ -943,36 +723,27 @@ def apply(self, population): rng = self.module.rng # # # INCIDENCE OF WASTING # # # # # # # # # # # # # # # # # # # # # - # Determine who will be onset with wasting among those who are not - # currently wasted ------------- + # Determine who will be onset with wasting among those who are not currently wasted ------------- inc_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & ( - df.un_WHZ_category == 'WHZ>=-2')] - get_incidence_of_wasting = \ + df.un_WHZ_category == 'WHZ>=-2')]; get_incidence_of_wasting = \ self.module.wasting_models.get_wasting_incidence(inc_wasting) - incidence_of_wasting = rng.random_sample( - len(get_incidence_of_wasting)) < get_incidence_of_wasting + incidence_of_wasting = rng.random_sample(len(get_incidence_of_wasting)) < get_incidence_of_wasting wasting_idx = inc_wasting.index # update the properties for wasted children df.loc[wasting_idx[incidence_of_wasting], 'un_ever_wasted'] = True - df.loc[wasting_idx[ - incidence_of_wasting], 'un_last_wasting_date_of_onset'] = \ - self.sim.date + df.loc[wasting_idx[incidence_of_wasting], 'un_last_wasting_date_of_onset'] = self.sim.date # start as moderate wasting - df.loc[wasting_idx[ - incidence_of_wasting], 'un_WHZ_category'] = '-3<=WHZ<-2' + df.loc[wasting_idx[incidence_of_wasting], 'un_WHZ_category'] = '-3<=WHZ<-2' # start without treatment - df.loc[wasting_idx[ - incidence_of_wasting], 'un_am_treatment_type'] = 'none' + df.loc[wasting_idx[incidence_of_wasting], 'un_am_treatment_type'] = 'none' # -------------------------------------------------------------------- # Add this incident case to the tracker for person in wasting_idx: wasting_severity = df.at[person, 'un_WHZ_category'] - age_group = WastingPollingEvent.AGE_GROUPS.get( - df.loc[person].age_years, '5+y') + age_group = WastingPollingEvent.AGE_GROUPS.get(df.loc[person].age_years, '5+y') # if wasting_severity != 'WHZ>=-2': - self.module.wasting_incident_case_tracker[age_group][ - wasting_severity].append(self.sim.date) + self.module.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) # --------------------------------------------------------------------- @@ -980,72 +751,55 @@ def apply(self, population): # Determine those that will progress to severe wasting ( WHZ<-3) # and schedule progression event --------- - progression_sev_wasting = df.loc[ - df.is_alive & (df.age_exact_years < 5) & ( - df.un_WHZ_category == '-3<=WHZ<-2')] - progression_severe_wasting = \ - self.module.wasting_models.get_wasting_progression().predict( + progression_sev_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & + (df.un_WHZ_category == '-3<=WHZ<-2')] + progression_severe_wasting = self.module.wasting_models.get_wasting_progression().predict( progression_sev_wasting) - progression_severe_wasting = rng.random_sample(len( - progression_sev_wasting)) < progression_severe_wasting - # determine those individuals who will progress to severe wasting - # and time of progression - for person in progression_sev_wasting.index[ - progression_severe_wasting]: - outcome_date = self.module.date_of_outcome_for_untreated_am( - person_id=person, duration_am='MAM') + progression_severe_wasting = \ + rng.random_sample(len(progression_sev_wasting)) < progression_severe_wasting + # determine those individuals who will progress to severe wasting and time of progression + for person in progression_sev_wasting.index[progression_severe_wasting]: + outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') # schedule severe wasting WHZ<-3 onset if outcome_date <= self.sim.date: # schedule severe wasting WHZ<-3 onset today - self.sim.schedule_event( - event=ProgressionSevereWastingEvent(module=self.module, - person_id=person), - date=self.sim.date) + self.sim.schedule_event(event=ProgressionSevereWastingEvent( + module=self.module, person_id=person), date=self.sim.date) else: # schedule severe wasting WHZ<-3 onset according to duration self.sim.schedule_event( - event=ProgressionSevereWastingEvent(module=self.module, - person_id=person), - date=outcome_date) + event=ProgressionSevereWastingEvent( + module=self.module, person_id=person), date=outcome_date) # # # # # # #MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # moderate wasting not progressed to severe, schedule recovery - for person in progression_sev_wasting.index[ - ~progression_severe_wasting]: - outcome_date = self.module.date_of_outcome_for_untreated_am( - person_id=person, duration_am='MAM') + for person in progression_sev_wasting.index[~progression_severe_wasting]: + outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') if outcome_date <= self.sim.date: # schedule recovery for today - self.sim.schedule_event( - event=WastingNaturalRecoveryEvent(module=self.module, - person_id=person), - date=self.sim.date) + self.sim.schedule_event(event=WastingNaturalRecoveryEvent( + module=self.module, person_id=person), date=self.sim.date) else: # schedule recovery according to duration - self.sim.schedule_event( - event=WastingNaturalRecoveryEvent(module=self.module, - person_id=person), - date=outcome_date) + self.sim.schedule_event(event=WastingNaturalRecoveryEvent( + module=self.module, person_id=person), date=outcome_date) # ------------------------------------------------------------------------------------------ # ## UPDATE PROPERTIES RELATED TO CLINICAL ACUTE MALNUTRITION # # # # # ------------------------------------------------------------------------------------------ # This applies to all children under 5 - # give MUAC measurement category for all WHZ, including well - # nourished children ----- + # give MUAC measurement category for all WHZ, including well nourished children ----- # determine the presence of bilateral oedema / oedematous malnutrition - # determine the clinical state of acute malnutrition, and check - # complications if SAM + # determine the clinical state of acute malnutrition, and check complications if SAM self.module.population_poll_clinical_am(df) # then, update clinical symptoms for those with severe acute # malnutrition - children_with_sam = df.loc[df.is_alive & (df.age_exact_years < 5) & - (df.un_clinical_acute_malnutrition == - 'SAM')] + children_with_sam = df.loc[df.is_alive & (df.age_exact_years < 5) + & (df.un_clinical_acute_malnutrition == 'SAM')] for person in children_with_sam.index: self.module.wasting_clinical_symptoms(person_id=person) @@ -1053,8 +807,7 @@ def apply(self, population): class ProgressionSevereWastingEvent(Event, IndividualScopeEventMixin): """ This Event is for the onset of severe wasting (WHZ <-3). - * Refreshes all the properties so that they pertain to this current - episode of wasting + * Refreshes all the properties so that they pertain to this current episode of wasting * Imposes the symptoms """ @@ -1067,9 +820,8 @@ def apply(self, person_id): # before progression to severe wasting, check those who started # supplementary feeding programme before today - if df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[ - person_id, 'un_acute_malnutrition_tx_start_date'] \ - < self.sim.date: + if df.at[person_id, 'un_last_wasting_date_of_onset'] < \ + df.at[person_id, 'un_acute_malnutrition_tx_start_date'] < self.sim.date: return # continue with progression to severe if not treated/recovered @@ -1079,13 +831,11 @@ def apply(self, person_id): # Give MUAC measurement category for WHZ<-3 if df.at[person_id, 'age_exact_years'] > 0.5: - m.muac_cutoff_by_WHZ(idx=df.loc[[person_id]].index, - whz='WHZ<-3') + m.muac_cutoff_by_WHZ(idx=df.loc[[person_id]].index, whz='WHZ<-3') # update the clinical state of acute malnutrition, and check # complications if SAM - m.clinical_acute_malnutrition_state(person_id=person_id, - pop_dataframe=df) + m.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) # update clinical symptoms for severe wasting m.wasting_clinical_symptoms(person_id=person_id) @@ -1093,11 +843,9 @@ def apply(self, person_id): # ------------------------------------------------------------------------------------------- # Add this incident case to the tracker wasting_severity = df.at[person_id, 'un_WHZ_category'] - age_group = WastingPollingEvent.AGE_GROUPS.get( - df.loc[person_id].age_years, '5+y') + age_group = WastingPollingEvent.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') if wasting_severity != 'WHZ>=-2': - m.wasting_incident_case_tracker[age_group][ - wasting_severity].append(self.sim.date) + m.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) class SevereAcuteMalnutritionDeathEvent(Event, IndividualScopeEventMixin): @@ -1123,15 +871,13 @@ def apply(self, person_id): self.sim.modules['Demography'].do_death( individual_id=person_id, cause='SAM', - originating_module=self.module - ) + originating_module=self.module) class WastingNaturalRecoveryEvent(Event, IndividualScopeEventMixin): """ - This event sets wasting properties back to normal state, based on home - care/ improvement without interventions, - low-moderate MUAC categories oedema may or may not be present + This event sets wasting properties back to normal state, based on home care/ improvement without + interventions, low-moderate MUAC categories oedema may or may not be present """ def __init__(self, module, person_id): @@ -1155,8 +901,7 @@ def apply(self, person_id): # wasting onset # update the clinical acute malnutrition state - m.clinical_acute_malnutrition_state(person_id=person_id, - pop_dataframe=df) + m.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': # this will clear all wasting symptoms self.sim.modules["SymptomManager"].clear_symptoms( @@ -1196,8 +941,8 @@ def apply(self, person_id): class UpdateToMAM(Event, IndividualScopeEventMixin): """ - This event updates the properties for those cases that remained/ - improved from SAM to MAM following treatment + This event updates the properties for those cases that remained/improved from SAM to MAM following + treatment """ def __init__(self, module, person_id): @@ -1216,17 +961,15 @@ def apply(self, person_id): # oedema, or low muac - do not change the WHZ if df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2': # mam by muac only - df.at[ - person_id, 'un_am_MUAC_category'] = '115-<125mm' + df.at[person_id, 'un_am_MUAC_category'] = '115-<125mm' else: # using the probability of mam classification by anthropometric # indices - mam_classification = rng.choice( - ['mam_by_muac_only', 'mam_by_muac_and_whz', 'mam_by_whz_only'], - p=[p['proportion_mam_with_MUAC_115-<125mm_and_normal_whz'], - p['proportion_mam_with_MUAC_115-<125mm_and_-3<=WHZ<-2'], - p['proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC']]) + mam_classification = rng.choice(['mam_by_muac_only', 'mam_by_muac_and_whz', 'mam_by_whz_only'], + p=[p['proportion_mam_with_MUAC_115-<125mm_and_normal_whz'], + p['proportion_mam_with_MUAC_115-<125mm_and_-3<=WHZ<-2'], + p['proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC']]) if mam_classification == 'mam_by_muac_only': df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' @@ -1248,8 +991,7 @@ def apply(self, person_id): df.at[person_id, 'un_am_recovery_date'] = pd.NaT df.at[person_id, 'un_am_discharge_date'] = pd.NaT # will start the process again - df.at[ - person_id, 'un_am_treatment_type'] = 'not_applicable' + df.at[person_id, 'un_am_treatment_type'] = 'not_applicable' # this will clear all wasting symptoms (applicable for SAM, not MAM) self.sim.modules["SymptomManager"].clear_symptoms( @@ -1257,8 +999,7 @@ def apply(self, person_id): ) -class HSI_Wasting_SupplementaryFeedingProgramme_MAM(HSI_Event, - IndividualScopeEventMixin): +class HSI_Wasting_SupplementaryFeedingProgramme_MAM(HSI_Event, IndividualScopeEventMixin): """ This is the supplementary feeding programme for MAM without complications """ @@ -1269,8 +1010,7 @@ def __init__(self, module, person_id): # Get a blank footprint and then edit to define call on resources # of this treatment event - the_appt_footprint = self.sim.modules[ - "HealthSystem"].get_blank_appt_footprint() + the_appt_footprint = self.sim.modules["HealthSystem"].get_blank_appt_footprint() the_appt_footprint['Under5OPD'] = 1 # This requires one out patient # Define the necessary information for an HSI @@ -1291,38 +1031,28 @@ def apply(self, person_id, squeeze_factor): # system interaction event # ~~~~~~~~~~~~~~~~~~~~~~ # Make request for some consumables - consumables = self.sim.modules['HealthSystem'].parameters[ - 'item_and_package_code_lookups'] + consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] # individual items - item_code1 = pd.unique( - consumables.loc[consumables[ - 'Items'] == 'Corn Soya Blend (or ' - 'Supercereal - CSB++)', - 'Item_Code'])[0] + item_code1 = pd.unique(consumables.loc[consumables['Items'] == + 'Corn Soya Blend (or Supercereal - CSB++)', 'Item_Code'])[0] # check availability of consumables if self.get_consumables([item_code1]): logger.debug(key='debug', data='consumables are available') # Log that the treatment is provided: - df.at[ - person_id, 'un_acute_malnutrition_tx_start_date'] = \ - self.sim.date - df.at[ - person_id, 'un_am_discharge_date'] = \ - self.sim.date + DateOffset(weeks=3) + df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date + df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=3) df.at[person_id, 'un_am_treatment_type'] = 'CSB++' self.module.do_when_am_treatment(person_id, intervention='SFP') else: - logger.debug(key='debug', - data="PkgCode1 is not available, so can't use it.") + logger.debug(key='debug', data="PkgCode1 is not available, so can't use it.") def did_not_run(self): logger.debug("supplementary_feeding_programme_for_MAM: did not run") pass -class HSI_Wasting_OutpatientTherapeuticProgramme_SAM( - HSI_Event, IndividualScopeEventMixin): +class HSI_Wasting_OutpatientTherapeuticProgramme_SAM(HSI_Event, IndividualScopeEventMixin): """ This is the outpatient management of SAM without any medical complications """ @@ -1333,8 +1063,7 @@ def __init__(self, module, person_id): # Get a blank footprint and then edit to define call on resources # of this treatment event - the_appt_footprint = self.sim.modules[ - "HealthSystem"].get_blank_appt_footprint() + the_appt_footprint = self.sim.modules["HealthSystem"].get_blank_appt_footprint() the_appt_footprint['U5Malnutr'] = 1 # Define the necessary information for an HSI @@ -1359,39 +1088,27 @@ def apply(self, person_id, squeeze_factor): 'item_and_package_code_lookups'] # individual items - item_code1 = pd.unique( - consumables.loc[ - consumables['Items'] == 'SAM theraputic foods', 'Item_Code'])[ - 0] - item_code2 = pd.unique( - consumables.loc[ - consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] + item_code1 = pd.unique(consumables.loc[consumables['Items'] == + 'SAM theraputic foods', 'Item_Code'])[0] + item_code2 = pd.unique(consumables.loc[consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] # check availability of consumables - if self.get_consumables(item_code1) and self.get_consumables( - item_code2): + if self.get_consumables(item_code1) and self.get_consumables(item_code2): logger.debug(key='debug', data='consumables are available.') # Log that the treatment is provided: - df.at[ - person_id, 'un_acute_malnutrition_tx_start_date'] = \ - self.sim.date - df.at[ - person_id, 'un_am_discharge_date'] = self.sim.date + \ - DateOffset(weeks=3) + df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date + df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=3) df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' self.module.do_when_am_treatment(person_id, intervention='OTC') else: - logger.debug(key='debug', - data="consumables not available, so can't use it.") + logger.debug(key='debug', data="consumables not available, so can't use it.") def did_not_run(self): - logger.debug( - "HSI_outpatient_therapeutic_programme_for_SAM: did not run") + logger.debug("HSI_outpatient_therapeutic_programme_for_SAM: did not run") pass -class HSI_Wasting_InpatientCareForComplicated_SAM(HSI_Event, - IndividualScopeEventMixin): +class HSI_Wasting_InpatientCareForComplicated_SAM(HSI_Event, IndividualScopeEventMixin): """ This is the inpatient management of SAM with medical complications """ @@ -1400,10 +1117,8 @@ def __init__(self, module, person_id): super().__init__(module, person_id=person_id) assert isinstance(module, Wasting) - # Get a blank footprint and then edit to define call on resources - # of this treatment event - the_appt_footprint = self.sim.modules[ - "HealthSystem"].get_blank_appt_footprint() + # Get a blank footprint and then edit to define call on resources of this treatment event + the_appt_footprint = self.sim.modules["HealthSystem"].get_blank_appt_footprint() the_appt_footprint['U5Malnutr'] = 1 # Define the necessary information for an HSI @@ -1411,49 +1126,35 @@ def __init__(self, module, person_id): self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint self.ACCEPTED_FACILITY_LEVEL = '2' self.ALERT_OTHER_DISEASES = [] - self.BEDDAYS_FOOTPRINT = self.make_beddays_footprint( - {'general_bed': 7}) + self.BEDDAYS_FOOTPRINT = self.make_beddays_footprint({'general_bed': 7}) def apply(self, person_id, squeeze_factor): df = self.sim.population.props - # Stop the person from dying of acute malnutrition (if they were - # going to die) + # Stop the person from dying of acute malnutrition (if they were going to die) if not df.at[person_id, 'is_alive']: return - # Do here whatever happens to an individual during this health - # system interaction event + # Do here whatever happens to an individual during this health system interaction event # ~~~~~~~~~~~~~~~~~~~~~~ # Make request for some consumables - consumables = self.sim.modules['HealthSystem'].parameters[ - 'item_and_package_code_lookups'] + consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] # individual items item_code1 = pd.unique( - consumables.loc[ - consumables['Items'] == 'SAM theraputic foods', 'Item_Code'])[ - 0] - item_code2 = pd.unique( - consumables.loc[ - consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] + consumables.loc[consumables['Items'] == 'SAM theraputic foods', 'Item_Code'])[0] + item_code2 = pd.unique(consumables.loc[consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] # # check availability of consumables - if self.get_consumables(item_code1) and self.get_consumables( - item_code2): + if self.get_consumables(item_code1) and self.get_consumables(item_code2): logger.debug(key='debug', data='consumables available, so use it.') # Log that the treatment is provided: - df.at[ - person_id, 'un_acute_malnutrition_tx_start_date'] = \ - self.sim.date - df.at[ - person_id, 'un_am_discharge_date'] = self.sim.date + \ - DateOffset(weeks=4) + df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date + df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=4) df.at[person_id, 'un_am_treatment_type'] = 'inpatient_care' self.module.do_when_am_treatment(person_id, intervention='ITC') else: - logger.debug(key='debug', - data="consumables not available, so can't use it.") + logger.debug(key='debug', data="consumables not available, so can't use it.") def did_not_run(self): logger.debug("HSI_inpatient_care_for_complicated_SAM: did not run") @@ -1470,91 +1171,66 @@ def __init__(self, module): # linear model to predict the incidence of wasting self.__Wasting_Incidence = LinearModel.multiplicative( - Predictor('age_exact_years').when('<0.5', self.params[ - 'base_inc_rate_wasting_by_agegp'][0]) + Predictor('age_exact_years').when('<0.5', self.params['base_inc_rate_wasting_by_agegp'][0]) .when('<1.0', self.params['base_inc_rate_wasting_by_agegp'][1]) - .when('.between(1,1.9999)', - self.params['base_inc_rate_wasting_by_agegp'][2]) - .when('.between(2,2.9999)', - self.params['base_inc_rate_wasting_by_agegp'][3]) - .when('.between(3,3.9999)', - self.params['base_inc_rate_wasting_by_agegp'][4]) - .when('.between(4,4.9999)', - self.params['base_inc_rate_wasting_by_agegp'][5]) + .when('.between(1,1.9999)', self.params['base_inc_rate_wasting_by_agegp'][2]) + .when('.between(2,2.9999)', self.params['base_inc_rate_wasting_by_agegp'][3]) + .when('.between(3,3.9999)', self.params['base_inc_rate_wasting_by_agegp'][4]) + .when('.between(4,4.9999)', self.params['base_inc_rate_wasting_by_agegp'][5]) .otherwise(0.0), - Predictor().when( - '(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& (nb_late_preterm == False) & (nb_early_preterm == False)', - self.params['rr_wasting_SGA_and_term']), - Predictor().when( - '(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', - self.params['rr_wasting_SGA_and_preterm']), - Predictor().when( - '(nb_size_for_gestational_age == ' - '"average_for_gestational_age")' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', - self.params['rr_wasting_preterm_and_AGA']), - Predictor('li_wealth').apply( - lambda x: 1 if x == 1 else (x - 1) ** ( - self.params['rr_wasting_wealth_level'])), + Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") &' + '(nb_late_preterm == False) & (nb_early_preterm == False)', + self.params['rr_wasting_SGA_and_term']), + Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") & ' + '(nb_late_preterm == True) | (nb_early_preterm == True)', + self.params['rr_wasting_SGA_and_preterm']), + Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") &' + '(nb_late_preterm == True) | (nb_early_preterm == True)', + self.params['rr_wasting_preterm_and_AGA']), + Predictor('li_wealth').apply(lambda x: 1 if x == 1 else (x - 1) ** ( + self.params['rr_wasting_wealth_level'])), ) - # a linear model to predict the probability of individual's - # recovery from moderate acute malnutrition + # a linear model to predict the probability of individual's recovery from moderate acute malnutrition self.__Acute_Malnutrition_Recovery_MAM = LinearModel.multiplicative( - Predictor('un_am_treatment_type').when('soy_RUSF', self.params[ - 'recovery_rate_with_soy_RUSF']) + Predictor('un_am_treatment_type').when('soy_RUSF', self.params['recovery_rate_with_soy_RUSF']) .when('CSB++', self.params['recovery_rate_with_CSB++']) .otherwise(0.0), ) - # a linear model to predict the probability of individual's - # recovery from severe acute malnutrition + # a linear model to predict the probability of individual's recovery from severe acute malnutrition self.__Acute_Malnutrition_Recovery_SAM = LinearModel.multiplicative( Predictor('un_am_treatment_type') - .when('standard_RUTF', - self.params['recovery_rate_with_standard_RUTF']) - .when('inpatient_care', - self.params['recovery_rate_with_inpatient_care']) + .when('standard_RUTF', self.params['recovery_rate_with_standard_RUTF']) + .when('inpatient_care', self.params['recovery_rate_with_inpatient_care']) .otherwise(0.0), ) - # Linear model for the probability of progression to severe wasting - # (age-dependent only) + # Linear model for the probability of progression to severe wasting (age-dependent only) # (natural history only, no interventions) self.__Severe_Wasting_Progression = LinearModel.multiplicative( Predictor('age_exact_years') - .when('<0.5', - self.params['progression_severe_wasting_by_agegp'][0]) - .when('.between(0.5,0.9999)', - self.params['progression_severe_wasting_by_agegp'][1]) - .when('.between(1,1.9999)', - self.params['progression_severe_wasting_by_agegp'][2]) - .when('.between(2,2.9999)', - self.params['progression_severe_wasting_by_agegp'][3]) - .when('.between(3,3.9999)', - self.params['progression_severe_wasting_by_agegp'][4]) - .when('.between(4,4.9999)', - self.params['progression_severe_wasting_by_agegp'][5]) + .when('<0.5', self.params['progression_severe_wasting_by_agegp'][0]) + .when('.between(0.5,0.9999)', self.params['progression_severe_wasting_by_agegp'][1]) + .when('.between(1,1.9999)', self.params['progression_severe_wasting_by_agegp'][2]) + .when('.between(2,2.9999)', self.params['progression_severe_wasting_by_agegp'][3]) + .when('.between(3,3.9999)', self.params['progression_severe_wasting_by_agegp'][4]) + .when('.between(4,4.9999)', self.params['progression_severe_wasting_by_agegp'][5]) .otherwise(0.0), ) self.__SAM_Death = LinearModel.multiplicative( - Predictor('un_am_treatment_type').when('none', self.params[ - 'base_death_rate_untreated_SAM']), - Predictor( - 'un_sam_with_complications' - ).when(True, self.params['rr_SAM_death_with_complications']), + Predictor('un_am_treatment_type').when('none', self.params['base_death_rate_untreated_SAM']), + Predictor('un_sam_with_complications') + .when(True, self.params['rr_SAM_death_with_complications']), Predictor().when('(un_am_bilateral_oedema == False) & ' - '(un_WHZ_category == "WHZ<-3") ' - '& (un_am_MUAC_category == "115-<125mm")', + '(un_WHZ_category == "WHZ<-3") &' + '(un_am_MUAC_category == "115-<125mm")', self.params['rr_SAM_death_WHZ<-3_only']), Predictor().when('(un_am_bilateral_oedema == False) & ' '(un_WHZ_category == "WHZ<-3") & ' '(un_am_MUAC_category == "<115mm")', - self.params[ - 'rr_SAM_death_both_WHZ<-3_&_MUAC<115mm']), + self.params['rr_SAM_death_both_WHZ<-3_&_MUAC<115mm']), Predictor().when('(un_am_bilateral_oedema == True) & ' '(un_WHZ_category == "-3<=WHZ<-2") & ' '(un_am_MUAC_category == "<115mm")', @@ -1562,20 +1238,17 @@ def __init__(self, module): Predictor().when('(un_am_bilateral_oedema == True) & ' '(un_WHZ_category == "WHZ<-3") & ' '(un_am_MUAC_category == "115-<125mm")', - self.params[ - 'rr_SAM_death_kwashiorkor_WHZ<-3_only']), + self.params['rr_SAM_death_kwashiorkor_WHZ<-3_only']), Predictor().when( '(un_am_bilateral_oedema == True) & ' '(un_WHZ_category == "WHZ<-3") & ' '(un_am_MUAC_category == "<115mm")', - self.params['rr_SAM_death_kwashiorkor_both_WHZ<-3_&_MUAC<115mm' - ] + self.params['rr_SAM_death_kwashiorkor_both_WHZ<-3_&_MUAC<115mm'] ), Predictor().when('(un_am_bilateral_oedema == True) & ' '(un_WHZ_category == "-3<=WHZ<-2") & ' '(un_am_MUAC_category == "<115mm")', - self.params[ - 'rr_SAM_death_kwashiorkor_MUAC<115mm_only']), + self.params['rr_SAM_death_kwashiorkor_MUAC<115mm_only']), ) def get_wasting_incidence(self, df) -> pd.Series: @@ -1583,13 +1256,11 @@ def get_wasting_incidence(self, df) -> pd.Series: :params df: population dataframe """ unscaled_lm = self.__Wasting_Incidence target_mean = self.params['base_inc_rate_wasting_by_agegp'][2] - actual_mean = unscaled_lm.predict( - df.loc[df.is_alive & (df.age_years == 1) & - (df.un_WHZ_category == 'WHZ>=-2')]).mean() + actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1) & + (df.un_WHZ_category == 'WHZ>=-2')]).mean() scaled_intercept = 1.0 * (target_mean / actual_mean) \ - if (target_mean != 0 and actual_mean != 0 and - ~np.isnan(actual_mean)) else 1.0 + if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else 1.0 scaled_lm = unscaled_lm.predict(df) return scaled_lm.apply(lambda row: row * scaled_intercept) @@ -1602,18 +1273,12 @@ def get_wasting_prevalence(self): LinearModelType.LOGISTIC, 1.0, Predictor('agrp', external=True) - .when('0_5mo', - self.module.wasting_prevalence_odds_by_age_grp['0_5mo']) - .when('6_11mo', - self.module.wasting_prevalence_odds_by_age_grp['6_11mo']) - .when('12_23mo', - self.module.wasting_prevalence_odds_by_age_grp['12_23mo']) - .when('24_35mo', - self.module.wasting_prevalence_odds_by_age_grp['24_35mo']) - .when('36_47mo', - self.module.wasting_prevalence_odds_by_age_grp['36_47mo']) - .when('48_59mo', - self.module.wasting_prevalence_odds_by_age_grp['48_59mo']) + .when('0_5mo', self.module.wasting_prevalence_odds_by_age_grp['0_5mo']) + .when('6_11mo', self.module.wasting_prevalence_odds_by_age_grp['6_11mo']) + .when('12_23mo', self.module.wasting_prevalence_odds_by_age_grp['12_23mo']) + .when('24_35mo', self.module.wasting_prevalence_odds_by_age_grp['24_35mo']) + .when('36_47mo', self.module.wasting_prevalence_odds_by_age_grp['36_47mo']) + .when('48_59mo', self.module.wasting_prevalence_odds_by_age_grp['48_59mo']) .otherwise(1.0), Predictor('agrp_scaling', external=True) @@ -1625,8 +1290,7 @@ def get_wasting_prevalence(self): .when('48_59mo', self.module.age_grps_dict['48_59mo']) .otherwise(1.0), - Predictor('li_wealth').when(2, - self.params['or_wasting_hhwealth_Q2']) + Predictor('li_wealth').when(2, self.params['or_wasting_hhwealth_Q2']) .when(3, self.params['or_wasting_hhwealth_Q3']) .when(4, self.params['or_wasting_hhwealth_Q4']) .when(5, self.params['or_wasting_hhwealth_Q5']) @@ -1649,50 +1313,42 @@ def get_wasting_prevalence(self): return wasting_prevalence def get_moderate_acute_malnutrition_recovery(self): - """ predict moderate acute malnutrition recovery amongst young - children less than 5 years + """ predict moderate acute malnutrition recovery amongst young children less than 5 years :params df: population dataframe """ return self.__Acute_Malnutrition_Recovery_MAM def get_severe_acute_malnutrition_recovery(self): - """ predict severe acute malnutrition recovery amongst young - children less than 5 years + """ predict severe acute malnutrition recovery amongst young children less than 5 years :params df: population dataframe """ return self.__Acute_Malnutrition_Recovery_SAM def get_wasting_progression(self): - """ predict wasting progression amongst young children less than 5 - years + """ predict wasting progression amongst young children less than 5 years :params df: population dataframe """ return self.__Severe_Wasting_Progression def get_sam_deaths(self, df) -> pd.Series: - """ predict severe acute malnutrition deaths amongst young children - less than 5 years + """ predict severe acute malnutrition deaths amongst young children less than 5 years :params df: population dataframe """ pop = self.module.sim.population.props - pop_wanted = pop.loc[pop.is_alive & - pop.age_exact_years.between(0.5, 5, - inclusive='neither') & + pop_wanted = pop.loc[pop.is_alive & pop.age_exact_years.between(0.5, 5, inclusive='neither') & (pop.un_clinical_acute_malnutrition == 'SAM')] unscaled_lm = self.__SAM_Death target_mean = self.params['base_death_rate_untreated_SAM'] actual_mean = unscaled_lm.predict(pop_wanted).mean() - scaled_intercept = 1.0 * (target_mean / actual_mean) \ - if (target_mean != 0 and actual_mean != 0 and - ~np.isnan(actual_mean)) else 1.0 + scaled_intercept = 1.0 * (target_mean / actual_mean) if (target_mean != 0 and actual_mean != 0 and + ~np.isnan(actual_mean)) else 1.0 scaled_lm = self.__SAM_Death.predict(df) return scaled_lm.apply(lambda row: row * scaled_intercept) def get_age_grps_odds(self): - """ Return odds determined by age groups. This will be applied in - wasting prevalence linear model """ + """ Return odds determined by age groups. This will be applied in wasting prevalence linear model """ for agegp in self.module.age_grps_dict.keys(): mean, stdev = self.params[f'prev_WHZ_distribution_age_{agegp}'] whz_normal_distribution = norm(loc=mean, scale=stdev) @@ -1700,16 +1356,14 @@ def get_age_grps_odds(self): probability_less_than_minus2sd = 1 - whz_normal_distribution.sf(-2) # convert probability to odds and update odds by age group # dictionary - self.module.wasting_prevalence_odds_by_age_grp[agegp] = \ - probability_less_than_minus2sd / ( - 1 - probability_less_than_minus2sd) + self.module.wasting_prevalence_odds_by_age_grp[agegp] =\ + probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) # get severe wasting zcores: WHZ <-3 probability_less_than_minus3sd = 1 - whz_normal_distribution.sf(-3) - # make WHZ <-2 as the 100% and get the adjusted probability of - # severe wasting within overall wasting - self.module.age_grps_sev_wasting_probs[ - agegp] = \ + # make WHZ <-2 as the 100% and get the adjusted probability of severe wasting within + # overall wasting + self.module.age_grps_sev_wasting_probs[agegp] = \ probability_less_than_minus3sd * probability_less_than_minus2sd def get_wasting_prevalence_scaling(self, df): @@ -1719,26 +1373,20 @@ def get_wasting_prevalence_scaling(self, df): wasting_prevalence = self.get_wasting_prevalence() # index the age groups dictionary for agegp in self.module.age_grps_dict.keys(): - target_mean = self.module.wasting_prevalence_odds_by_age_grp[ - '12_23mo'] - actual_mean = wasting_prevalence.predict( - df.loc[df.is_alive & (df.age_years == 1)], - agrp=agegp, agrp_scaling='None').mean() + target_mean = self.module.wasting_prevalence_odds_by_age_grp['12_23mo'] + actual_mean = wasting_prevalence.predict(df.loc[df.is_alive & (df.age_years == 1)], + agrp=agegp, agrp_scaling='None').mean() # update and return age groups dictionary - self.module.age_grps_dict[agegp] = \ - self.module.wasting_prevalence_odds_by_age_grp[agegp] * ( - target_mean / actual_mean) \ - if (target_mean != 0 and actual_mean != 0 and ~np.isnan( - actual_mean)) \ + self.module.age_grps_dict[agegp] =\ + self.module.wasting_prevalence_odds_by_age_grp[agegp] * (target_mean / actual_mean)\ + if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean))\ else self.module.wasting_prevalence_odds_by_age_grp[agegp] class WastingLoggingEvent(RegularEvent, PopulationScopeEventMixin): """ - This Event logs the number of incident cases that have occurred - since the previous logging event. - Analysis scripts expect that the frequency of this logging event - is once per year. + This Event logs the number of incident cases that have occurred since the previous logging event. + Analysis scripts expect that the frequency of this logging event is once per year. """ def __init__(self, module): @@ -1751,13 +1399,11 @@ def apply(self, population): df = self.sim.population.props # Convert the list of timestamps into a number of timestamps # and check that all the dates have occurred since self.date_last_run - inc_df = pd.DataFrame( - index=self.module.wasting_incident_case_tracker.keys(), - columns=self.module.wasting_states) + inc_df = pd.DataFrame(index=self.module.wasting_incident_case_tracker.keys(), + columns=self.module.wasting_states) for age_grp in self.module.wasting_incident_case_tracker.keys(): for state in self.module.wasting_states: - inc_df.loc[age_grp, state] = len( - self.module.wasting_incident_case_tracker[age_grp][state]) + inc_df.loc[age_grp, state] = len(self.module.wasting_incident_case_tracker[age_grp][state]) logger.info(key='wasting_incidence_count', data=inc_df.to_dict()) @@ -1767,29 +1413,23 @@ def apply(self, population): self.date_last_run = self.sim.date # Wasting totals (prevalence at logging time) - currently_wasted_age_0_5mo = ( - df.is_alive & (df.age_exact_years < 0.5) & - (df.un_WHZ_category != 'WHZ>=-2')).sum() - currently_wasted_age_6_11mo = ( - df.is_alive & ((df.age_exact_years >= 0.5) & ( - df.age_exact_years < 1)) & ( - df.un_WHZ_category != 'WHZ>=-2')).sum() - currently_wasted_age_12_23mo = ( - df.is_alive & ((df.age_exact_years >= 1) & ( - df.age_exact_years < 2)) & ( - df.un_WHZ_category != 'WHZ>=-2')).sum() - currently_wasted_age_24_35mo = ( - df.is_alive & ((df.age_exact_years >= 2) & ( - df.age_exact_years < 3)) & ( - df.un_WHZ_category != 'WHZ>=-2')).sum() - currently_wasted_age_36_47mo = ( - df.is_alive & ((df.age_exact_years >= 3) & ( - df.age_exact_years < 4)) & ( - df.un_WHZ_category != 'WHZ>=-2')).sum() - currently_wasted_age_48_59mo = ( - df.is_alive & ((df.age_exact_years >= 4) & ( - df.age_exact_years < 5)) & ( - df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_0_5mo = (df.is_alive & (df.age_exact_years < 0.5) & (df.un_WHZ_category + != 'WHZ>=-2')).sum() + currently_wasted_age_6_11mo = \ + (df.is_alive & ((df.age_exact_years >= 0.5) & (df.age_exact_years < 1)) + & (df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_12_23mo = \ + (df.is_alive & ((df.age_exact_years >= 1) & (df.age_exact_years < 2)) + & (df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_24_35mo = \ + (df.is_alive & ((df.age_exact_years >= 2) & (df.age_exact_years < 3)) & + (df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_36_47mo = \ + (df.is_alive & ((df.age_exact_years >= 3) & (df.age_exact_years < 4)) & ( + df.un_WHZ_category != 'WHZ>=-2')).sum() + currently_wasted_age_48_59mo = \ + (df.is_alive & ((df.age_exact_years >= 4) & (df.age_exact_years < 5)) & ( + df.un_WHZ_category != 'WHZ>=-2')).sum() currently_wasted = {'0_5mo': currently_wasted_age_0_5mo, '6_11mo': currently_wasted_age_6_11mo, From cd20c5cdf3273707f534da67862d65e2aaad1d5a Mon Sep 17 00:00:00 2001 From: mnjowe Date: Thu, 4 Jan 2024 16:31:58 +0200 Subject: [PATCH 028/755] removing unnecessary semicolon --- src/tlo/methods/wasting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index f020345547..809d9822b6 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -725,7 +725,8 @@ def apply(self, population): # # # INCIDENCE OF WASTING # # # # # # # # # # # # # # # # # # # # # # Determine who will be onset with wasting among those who are not currently wasted ------------- inc_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & ( - df.un_WHZ_category == 'WHZ>=-2')]; get_incidence_of_wasting = \ + df.un_WHZ_category == 'WHZ>=-2')] + get_incidence_of_wasting = \ self.module.wasting_models.get_wasting_incidence(inc_wasting) incidence_of_wasting = rng.random_sample(len(get_incidence_of_wasting)) < get_incidence_of_wasting From 308e4534435bde94afdcaf076fa4d6a2fb3f7dd3 Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Mon, 29 Jan 2024 15:54:19 +0200 Subject: [PATCH 029/755] General changes after review 1 --- src/tlo/methods/stunting.py | 2 +- src/tlo/methods/wasting.py | 34 +++++++++++----------------------- tests/test_wasting.py | 16 +++++++--------- 3 files changed, 19 insertions(+), 33 deletions(-) diff --git a/src/tlo/methods/stunting.py b/src/tlo/methods/stunting.py index b4122b423a..8908ed6afc 100644 --- a/src/tlo/methods/stunting.py +++ b/src/tlo/methods/stunting.py @@ -530,7 +530,7 @@ class HSI_Stunting_ComplementaryFeeding(HSI_Event, IndividualScopeEventMixin): def __init__(self, module, person_id): super().__init__(module, person_id=person_id) - self.TREATMENT_ID = 'Undernutrition_Feeding' + self.TREATMENT_ID = 'Undernutrition_Feeding_Outpatient' self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({'U5Malnutr': 1}) self.ACCEPTED_FACILITY_LEVEL = '1a' diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 809d9822b6..667281083f 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -44,13 +44,13 @@ class Wasting(Module): # Declare Causes of Death CAUSES_OF_DEATH = { - 'SAM': Cause(gbd_causes='Protein-energy malnutrition', + 'Severe Acute Malnutrition': Cause(gbd_causes='Protein-energy malnutrition', label='Childhood Wasting') } # Declare Causes of Death and Disability CAUSES_OF_DISABILITY = { - 'SAM': Cause(gbd_causes='Protein-energy malnutrition', + 'Severe Acute Malnutrition': Cause(gbd_causes='Protein-energy malnutrition', label='Childhood Wasting') } @@ -292,11 +292,11 @@ def initialise_population(self, population): wasting_prevalence = self.wasting_models.get_wasting_prevalence() # Assign wasting categories in young children at initiation - for agegp in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months - low_bound_age_in_years = agegp[0] / 12.0 - high_bound_age_in_years = (1 + agegp[1]) / 12.0 + for low_bound_mnts, high_bound_mnths in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months + low_bound_age_in_years = low_bound_mnts / 12.0 + high_bound_age_in_years = (1 + high_bound_mnths) / 12.0 # linear model external variables - lm_ext_var = f'{agegp[0]}_{agegp[1]}mo' + lm_ext_var = f'{low_bound_mnts}_{high_bound_mnths}mo' mask = (df.is_alive & df.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, inclusive='left')) prevalence_of_wasting = wasting_prevalence.predict(df.loc[mask], agrp='None', agrp_scaling=lm_ext_var) @@ -523,13 +523,6 @@ def population_poll_clinical_am(self, population): for person_id in index_under5: self.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) - def on_hsi_alert(self, person_id, treatment_id): - """ - This is called whenever there is an HSI event commissioned by one of the other disease modules. - """ - logger.debug(key='message', data=f'This is Wasting, being alerted about a health system interaction for ' - f'person {person_id} and treatment {treatment_id}') - def report_daly_values(self): """ This must send back a pd.Series or pd.DataFrame that reports on the average daly-weights that have been @@ -871,7 +864,7 @@ def apply(self, person_id): df.at[person_id, 'un_sam_death_date'] = self.sim.date self.sim.modules['Demography'].do_death( individual_id=person_id, - cause='SAM', + cause='Severe Acute Malnutrition', originating_module=self.module) @@ -1123,7 +1116,7 @@ def __init__(self, module, person_id): the_appt_footprint['U5Malnutr'] = 1 # Define the necessary information for an HSI - self.TREATMENT_ID = 'Inpatient_care_for_complicated_SAM' + self.TREATMENT_ID = 'Undernutrition_Feeding_Inpatient' self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint self.ACCEPTED_FACILITY_LEVEL = '2' self.ALERT_OTHER_DISEASES = [] @@ -1136,8 +1129,6 @@ def apply(self, person_id, squeeze_factor): if not df.at[person_id, 'is_alive']: return - # Do here whatever happens to an individual during this health system interaction event - # ~~~~~~~~~~~~~~~~~~~~~~ # Make request for some consumables consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] @@ -1314,20 +1305,17 @@ def get_wasting_prevalence(self): return wasting_prevalence def get_moderate_acute_malnutrition_recovery(self): - """ predict moderate acute malnutrition recovery amongst young children less than 5 years - :params df: population dataframe + """ get moderate acute malnutrition recovery amongst young children less than 5 years """ return self.__Acute_Malnutrition_Recovery_MAM def get_severe_acute_malnutrition_recovery(self): - """ predict severe acute malnutrition recovery amongst young children less than 5 years - :params df: population dataframe + """ get severe acute malnutrition recovery amongst young children less than 5 years """ return self.__Acute_Malnutrition_Recovery_SAM def get_wasting_progression(self): - """ predict wasting progression amongst young children less than 5 years - :params df: population dataframe + """ get wasting progression amongst young children less than 5 years """ return self.__Severe_Wasting_Progression diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 8779b3e0d0..c0b2c2fa56 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -173,8 +173,7 @@ def test_wasting_polling(tmpdir): # Make incidence of wasting very high : params = sim.modules['Wasting'].parameters params['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] - params['progression_severe_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, - 1.0] + params['progression_severe_wasting_by_agegp'] = [0, 0, 0, 0, 0, 0] # re-initialise wasting linear models to use the updated parameter sim.modules['Wasting'].pre_initialise_population() @@ -183,14 +182,14 @@ def test_wasting_polling(tmpdir): sim.simulate(end_date=start_date + dur) sim.event_queue.queue = [] # clear the queue - # Run polling event: check that a severe incident case is produced: + # Run polling event: check that an incident case is produced: polling = WastingPollingEvent(sim.modules['Wasting']) polling.apply(sim.population) - assert len([q for q in sim.event_queue.queue if - isinstance(q[3], ProgressionSevereWastingEvent)]) > 0 + # assert len([q for q in sim.event_queue.queue if + # isinstance(q[3], ProgressionSevereWastingEvent)]) > 0 - # Check properties of this individual: should now be moderately wasted + # Check properties of individuals: should now be moderately wasted df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] @@ -703,9 +702,8 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): 1.0] params['prob_mam_death_after_care'] = [0.0, 1.0] - # reduce to 100% recovery rate. This is to ensure death event is scheduled - # for the individual each time we run this - # test + # reduce to 0% recovery rate. This is to ensure death event is scheduled + # for the individual each time we run this test params['recovery_rate_with_standard_RUTF'] = 0.0 params['recovery_rate_with_inpatient_care'] = 0.0 From cea20e051ab2556e6a4372fb0555a62650170acf Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Wed, 31 Jan 2024 08:52:02 +0200 Subject: [PATCH 030/755] Updated Priority Ranking Policies resource file --- .../ResourceFile_PriorityRanking_ALLPOLICIES.xlsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx index 0443bd6fb1..87a27a5e82 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:d0fe5f27b48430519dc01264d36d150862510adb46fe07ce82363bbc254136d7 -size 41283 +oid sha256:3ce61f39019e07a43294c5d1e41a2f8c5b69f48e298e0277c005980eb60bf23d +size 41451 From b7f9e34f616e8bc649cbb7c6b7087184a8efc96d Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Wed, 31 Jan 2024 11:43:53 +0200 Subject: [PATCH 031/755] Stunting Rollback --- src/tlo/methods/stunting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/stunting.py b/src/tlo/methods/stunting.py index 8908ed6afc..b4122b423a 100644 --- a/src/tlo/methods/stunting.py +++ b/src/tlo/methods/stunting.py @@ -530,7 +530,7 @@ class HSI_Stunting_ComplementaryFeeding(HSI_Event, IndividualScopeEventMixin): def __init__(self, module, person_id): super().__init__(module, person_id=person_id) - self.TREATMENT_ID = 'Undernutrition_Feeding_Outpatient' + self.TREATMENT_ID = 'Undernutrition_Feeding' self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({'U5Malnutr': 1}) self.ACCEPTED_FACILITY_LEVEL = '1a' From ed1723f5825859e19a25d36a959c3f1cb98ec5a1 Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Wed, 31 Jan 2024 15:58:49 +0200 Subject: [PATCH 032/755] Treatment_ID update --- ...ourceFile_PriorityRanking_ALLPOLICIES.xlsx | 4 +-- src/tlo/methods/wasting.py | 30 ++++++++++++------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx index 87a27a5e82..8f8d529023 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:3ce61f39019e07a43294c5d1e41a2f8c5b69f48e298e0277c005980eb60bf23d -size 41451 +oid sha256:f6590c15e8f0650b9c8d8bd43b05c0e73bfbd7b8598e070a907e194ed590dcf4 +size 41403 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 667281083f..337ec1d367 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -232,6 +232,13 @@ def __init__(self, name=None, resourcefilepath=None): # store severe wasting by age groups probabilities self.age_grps_sev_wasting_probs: dict = dict() + def declare_symptoms(self): + for symptom_name in self.symptoms: + self.sim.modules['SymptomManager'].register_symptom( + Symptom(name=symptom_name) + # (give non-generic symptom 'average' healthcare seeking) + ) + def read_parameters(self, data_folder): """ :param data_folder: path of a folder supplied to the Simulation containing data files. Typically, @@ -245,13 +252,14 @@ def read_parameters(self, data_folder): # Declare symptoms that this module will cause and which are not # included in the generic symptoms: - generic_symptoms = self.sim.modules['SymptomManager'].generic_symptoms - for symptom_name in self.symptoms: - if symptom_name not in generic_symptoms: - self.sim.modules['SymptomManager'].register_symptom( - Symptom(name=symptom_name) - # (give non-generic symptom 'average' healthcare seeking) - ) + self.declare_symptoms() + # generic_symptoms = self.sim.modules['SymptomManager'].generic_symptoms + # for symptom_name in self.symptoms: + # if symptom_name not in generic_symptoms: + # self.sim.modules['SymptomManager'].register_symptom( + # Symptom(name=symptom_name) + # # (give non-generic symptom 'average' healthcare seeking) + # ) def pre_initialise_population(self): """Things to do before processing the population: @@ -1008,7 +1016,7 @@ def __init__(self, module, person_id): the_appt_footprint['Under5OPD'] = 1 # This requires one out patient # Define the necessary information for an HSI - self.TREATMENT_ID = 'Supplementary_feeding_programme_for_MAM' + self.TREATMENT_ID = 'Undernutrition_Feeding_Supplementary' self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint self.ACCEPTED_FACILITY_LEVEL = '1a' self.ALERT_OTHER_DISEASES = [] @@ -1042,7 +1050,7 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data="PkgCode1 is not available, so can't use it.") def did_not_run(self): - logger.debug("supplementary_feeding_programme_for_MAM: did not run") + logger.debug("Undernutrition_Feeding_Supplementary: did not run") pass @@ -1061,7 +1069,7 @@ def __init__(self, module, person_id): the_appt_footprint['U5Malnutr'] = 1 # Define the necessary information for an HSI - self.TREATMENT_ID = 'Outpatient_therapeutic_programme_for_SAM' + self.TREATMENT_ID = 'Undernutrition_Feeding_Outpatient' self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint self.ACCEPTED_FACILITY_LEVEL = '1a' self.ALERT_OTHER_DISEASES = [] @@ -1098,7 +1106,7 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data="consumables not available, so can't use it.") def did_not_run(self): - logger.debug("HSI_outpatient_therapeutic_programme_for_SAM: did not run") + logger.debug("HSI_Undernutrition_Feeding_Outpatient: did not run") pass From 760e092ac8f55f73f564ee8d9ab8379eb98c34ed Mon Sep 17 00:00:00 2001 From: Watipaso Mulwafu <39279950+thewati@users.noreply.github.com> Date: Thu, 1 Feb 2024 09:17:20 +0200 Subject: [PATCH 033/755] Update src/tlo/analysis/utils.py great! Co-authored-by: Tim Hallett <39991060+tbhallett@users.noreply.github.com> --- src/tlo/analysis/utils.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tlo/analysis/utils.py b/src/tlo/analysis/utils.py index d6b920f497..a8b742741b 100644 --- a/src/tlo/analysis/utils.py +++ b/src/tlo/analysis/utils.py @@ -734,8 +734,6 @@ def get_color_coarse_appt(coarse_appt_type: str) -> str: 'FirstAttendance*': 'darkgrey', 'Inpatient*': 'silver', - 'Outpatient*': 'grey', - 'Supplementary*': 'darkslategrey', 'Contraception*': 'darkseagreen', 'AntenatalCare*': 'green', From 73407ad008ca74bcbff47f7cfcd2fa119e1e1ad7 Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Fri, 2 Feb 2024 15:17:04 +0200 Subject: [PATCH 034/755] Added Dalys reported test, Treatment_ID naming and other fixes --- .../wasting_analyses/analysis_wasting.py | 147 +++++++------ src/tlo/analysis/utils.py | 8 +- src/tlo/methods/wasting.py | 193 +++++++++--------- tests/test_wasting.py | 101 ++++++++- 4 files changed, 267 insertions(+), 182 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index b2ec48d82c..b5d5206327 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -88,7 +88,7 @@ def plot_wasting_incidence(self): _col_counter = -1 _col_counter += 1 # increment column counter fig.tight_layout() - plt.show() + # plt.show() def plot_wasting_prevalence(self): w_prev_df = self.__logs_dict['wasting_prevalence_count'] @@ -100,7 +100,7 @@ def plot_wasting_prevalence(self): ylabel='proportions', xlabel='year' ) - plt.show() + # plt.show() def plot_modal_gbd_deaths_by_gender(self): """ compare modal and GBD deaths by gender """ @@ -126,77 +126,76 @@ def plot_modal_gbd_deaths_by_gender(self): outputs / ('modal_gbd_deaths_by_gender' + datestamp + ".pdf"), format="pdf" ) - - plt.show() - - -seed = 1 - -# Path to the resource files used by the disease and intervention methods -resources = Path("./resources") -outputs = Path("./outputs") - -# create a datestamp -datestamp = datetime.date.today().strftime("__%Y_%m_%d") + \ - datetime.datetime.now().strftime("%H_%M_%S") - -# configure logging -log_config = { - # output filename. A timestamp will be added to this. - "filename": "wasting", - "custom_levels": { # Customise the output of specific loggers - "tlo.methods.demography": logging.INFO, - "tlo.methods.population": logging.INFO, - "tlo.methods.wasting": logging.INFO, - '*': logging.WARNING + # plt.show() + +if __name__ == "__main__": + seed = 1 + + # Path to the resource files used by the disease and intervention methods + resources = Path("./resources") + outputs = Path("./outputs") + + # create a datestamp + datestamp = datetime.date.today().strftime("__%Y_%m_%d") + \ + datetime.datetime.now().strftime("%H_%M_%S") + + # configure logging + log_config = { + # output filename. A timestamp will be added to this. + "filename": "wasting", + "custom_levels": { # Customise the output of specific loggers + "tlo.methods.demography": logging.INFO, + "tlo.methods.population": logging.INFO, + "tlo.methods.wasting": logging.INFO, + '*': logging.WARNING + } } -} - -# Basic arguments required for the simulation -start_date = Date(2010, 1, 1) -end_date = Date(2030, 1, 2) -pop_size = 10000 - -# Create simulation instance for this run. -sim = Simulation(start_date=start_date, seed=seed, log_config=log_config) - -# Register modules for simulation -sim.register( - demography.Demography(resourcefilepath=resources), - healthsystem.HealthSystem(resourcefilepath=resources, - service_availability=['*'], - cons_availability='default'), - healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resources), - healthburden.HealthBurden(resourcefilepath=resources), - symptommanager.SymptomManager(resourcefilepath=resources), - enhanced_lifestyle.Lifestyle(resourcefilepath=resources), - labour.Labour(resourcefilepath=resources), - care_of_women_during_pregnancy.CareOfWomenDuringPregnancy( - resourcefilepath=resources), - contraception.Contraception(resourcefilepath=resources), - pregnancy_supervisor.PregnancySupervisor(resourcefilepath=resources), - postnatal_supervisor.PostnatalSupervisor(resourcefilepath=resources), - newborn_outcomes.NewbornOutcomes(resourcefilepath=resources), - hiv.Hiv(resourcefilepath=resources), - tb.Tb(resourcefilepath=resources), - epi.Epi(resourcefilepath=resources), - wasting.Wasting(resourcefilepath=resources), -) - -sim.make_initial_population(n=pop_size) -sim.simulate(end_date=end_date) - -# read the results -output_path = sim.log_filepath - -# initialise the wasting class -wasting_analyses = WastingAnalyses(output_path) - -# plot wasting incidence -wasting_analyses.plot_wasting_incidence() - -# plot wasting prevalence -wasting_analyses.plot_wasting_prevalence() -# plot wasting deaths by gender as compared to GBD deaths -wasting_analyses.plot_modal_gbd_deaths_by_gender() + # Basic arguments required for the simulation + start_date = Date(2010, 1, 1) + end_date = Date(2030, 1, 2) + pop_size = 30000 + + # Create simulation instance for this run. + sim = Simulation(start_date=start_date, seed=seed, log_config=log_config) + + # Register modules for simulation + sim.register( + demography.Demography(resourcefilepath=resources), + healthsystem.HealthSystem(resourcefilepath=resources, + service_availability=['*'], + cons_availability='default'), + healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resources), + healthburden.HealthBurden(resourcefilepath=resources), + symptommanager.SymptomManager(resourcefilepath=resources), + enhanced_lifestyle.Lifestyle(resourcefilepath=resources), + labour.Labour(resourcefilepath=resources), + care_of_women_during_pregnancy.CareOfWomenDuringPregnancy( + resourcefilepath=resources), + contraception.Contraception(resourcefilepath=resources), + pregnancy_supervisor.PregnancySupervisor(resourcefilepath=resources), + postnatal_supervisor.PostnatalSupervisor(resourcefilepath=resources), + newborn_outcomes.NewbornOutcomes(resourcefilepath=resources), + hiv.Hiv(resourcefilepath=resources), + tb.Tb(resourcefilepath=resources), + epi.Epi(resourcefilepath=resources), + wasting.Wasting(resourcefilepath=resources), + ) + + sim.make_initial_population(n=pop_size) + sim.simulate(end_date=end_date) + + # read the results + output_path = sim.log_filepath + + # initialise the wasting class + wasting_analyses = WastingAnalyses(output_path) + + # plot wasting incidence + wasting_analyses.plot_wasting_incidence() + + # plot wasting prevalence + wasting_analyses.plot_wasting_prevalence() + + # plot wasting deaths by gender as compared to GBD deaths + wasting_analyses.plot_modal_gbd_deaths_by_gender() diff --git a/src/tlo/analysis/utils.py b/src/tlo/analysis/utils.py index d6b920f497..0c2145cc3f 100644 --- a/src/tlo/analysis/utils.py +++ b/src/tlo/analysis/utils.py @@ -733,9 +733,9 @@ def get_color_coarse_appt(coarse_appt_type: str) -> str: '*': 'black', 'FirstAttendance*': 'darkgrey', - 'Inpatient*': 'silver', - 'Outpatient*': 'grey', - 'Supplementary*': 'darkslategrey', + 'UndernutritionFeedingInpatient*': 'silver', + 'UndernutritionFeedingOutpatient*': 'grey', + 'UndernutritionFeedingSupplementary*': 'darkslategrey', 'Contraception*': 'darkseagreen', 'AntenatalCare*': 'green', @@ -806,7 +806,7 @@ def get_color_short_treatment_id(short_treatment_id: str) -> str: 'Lower respiratory infections': 'darkorange', 'Childhood Diarrhoea': 'tan', - 'Childhood Wasting': 'darkslategrey', + 'Childhood Undernutrition': 'tomato', 'AIDS': 'deepskyblue', 'Malaria': 'lightsteelblue', diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 337ec1d367..f8487579f4 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -45,13 +45,13 @@ class Wasting(Module): # Declare Causes of Death CAUSES_OF_DEATH = { 'Severe Acute Malnutrition': Cause(gbd_causes='Protein-energy malnutrition', - label='Childhood Wasting') + label='Childhood Wasting') } # Declare Causes of Death and Disability CAUSES_OF_DISABILITY = { 'Severe Acute Malnutrition': Cause(gbd_causes='Protein-energy malnutrition', - label='Childhood Wasting') + label='Childhood Wasting') } PARAMETERS = { @@ -205,13 +205,7 @@ def __init__(self, name=None, resourcefilepath=None): self.resourcefilepath = resourcefilepath # Store the symptoms that this module will use: - self.symptoms = { - 'palmar_pallor', - 'weight_loss', - 'poor_appetite', - 'lethargic', - # 'dehydration' - } + self.symptoms = {'weight_loss'} # dict to hold counters for the number of episodes by wasting-type # and age-group @@ -313,8 +307,8 @@ def initialise_population(self, population): wasted = self.rng.random_sample(len(prevalence_of_wasting)) < prevalence_of_wasting for idx in prevalence_of_wasting.index[wasted]: probability_of_severe = self.age_grps_sev_wasting_probs[lm_ext_var] - wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], p=[probability_of_severe, - 1 - probability_of_severe]) + wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], p=[probability_of_severe, + 1 - probability_of_severe]) df.at[idx, 'un_WHZ_category'] = wasted_category df.at[idx, 'un_last_wasting_date_of_onset'] = self.sim.date df.at[idx, 'un_ever_wasted'] = True @@ -393,7 +387,7 @@ def muac_cutoff_by_WHZ(self, idx, whz): df.loc[idx[~low_muac_in_moderate_wasting][moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] \ = '115-<125mm' # other moderate wasting will have normal MUAC - df.loc[idx[~low_muac_in_moderate_wasting][~moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category']\ + df.loc[idx[~low_muac_in_moderate_wasting][~moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] \ = '>=125mm' if whz == 'WHZ>=-2': @@ -453,7 +447,7 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): # check if person is not wasted if ((df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2') & - (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & (~df.at[person_id, 'un_am_bilateral_oedema'])): + (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & (~df.at[person_id, 'un_am_bilateral_oedema'])): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' # severe acute malnutrition - MUAC<115mm and/or WHZ<-3 and/or @@ -538,31 +532,29 @@ def report_daly_values(self): series of columns is taken to be the label of the cause of this disability. It will be recorded by the healthburden module as _. """ - # dict to hold the DALY weights + # Dict to hold the DALY weights daly_wts = dict() - if 'HealthBurden' in self.sim.modules.keys(): - df = self.sim.population.props - # Get DALY weights - get_daly_weight = self.sim.modules['HealthBurden'].get_daly_weight - - daly_wts['MAM_with_oedema'] = get_daly_weight(sequlae_code=461) - daly_wts['SAM_w/o_oedema'] = get_daly_weight(sequlae_code=462) - daly_wts['SAM_with_oedema'] = get_daly_weight(sequlae_code=463) - - total_daly_values = pd.Series(data=0.0, - index=df.index[df.is_alive]) - total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & - df.un_am_bilateral_oedema] = daly_wts['SAM_with_oedema'] - total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & - (~df.un_am_bilateral_oedema)] = daly_wts['SAM_w/o_oedema'] - total_daly_values.loc[df.is_alive & ( - ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | ( - (df.un_WHZ_category != 'WHZ<-3') & ( - df.un_am_MUAC_category != "115-<125mm"))) & df.un_am_bilateral_oedema] = daly_wts[ - 'MAM_with_oedema'] - - return total_daly_values + df = self.sim.population.props + # Get DALY weights + get_daly_weight = self.sim.modules['HealthBurden'].get_daly_weight + + daly_wts['MAM_with_oedema'] = get_daly_weight(sequlae_code=461) + daly_wts['SAM_w/o_oedema'] = get_daly_weight(sequlae_code=462) + daly_wts['SAM_with_oedema'] = get_daly_weight(sequlae_code=463) + + total_daly_values = pd.Series(data=0.0, + index=df.index[df.is_alive]) + total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & + df.un_am_bilateral_oedema] = daly_wts['SAM_with_oedema'] + total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & + (~df.un_am_bilateral_oedema)] = daly_wts['SAM_w/o_oedema'] + total_daly_values.loc[df.is_alive & ( + ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | ( + (df.un_WHZ_category != 'WHZ<-3') & ( + df.un_am_MUAC_category != "115-<125mm"))) & df.un_am_bilateral_oedema] = daly_wts[ + 'MAM_with_oedema'] + return total_daly_values def wasting_clinical_symptoms(self, person_id): """ @@ -602,7 +594,9 @@ def do_when_acute_malnutrition_assessment(self, person_id): # Check for coverage of supplementary feeding if self.rng.random_sample() < p['coverage_supplementary_feeding_program']: # schedule HSI for supplementary feeding program for MAM - self.sim.modules['HealthSystem'].schedule_hsi_event(hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), priority=0, topen=self.sim.date) + self.sim.modules['HealthSystem'].schedule_hsi_event( + hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), + priority=0, topen=self.sim.date) else: return # Interventions for uncomplicated SAM @@ -673,7 +667,7 @@ def do_when_am_treatment(self, person_id, intervention): else: self.sim.schedule_event(event=UpdateToMAM(module=self, person_id=person_id), date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + - DateOffset(weeks=3)) + DateOffset(weeks=3)) if intervention == 'ITC': sam_recovery = self.wasting_models.get_severe_acute_malnutrition_recovery().predict( @@ -726,7 +720,7 @@ def apply(self, population): # # # INCIDENCE OF WASTING # # # # # # # # # # # # # # # # # # # # # # Determine who will be onset with wasting among those who are not currently wasted ------------- inc_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & ( - df.un_WHZ_category == 'WHZ>=-2')] + df.un_WHZ_category == 'WHZ>=-2')] get_incidence_of_wasting = \ self.module.wasting_models.get_wasting_incidence(inc_wasting) @@ -756,7 +750,7 @@ def apply(self, population): progression_sev_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == '-3<=WHZ<-2')] progression_severe_wasting = self.module.wasting_models.get_wasting_progression().predict( - progression_sev_wasting) + progression_sev_wasting) progression_severe_wasting = \ rng.random_sample(len(progression_sev_wasting)) < progression_severe_wasting @@ -823,7 +817,7 @@ def apply(self, person_id): # before progression to severe wasting, check those who started # supplementary feeding programme before today if df.at[person_id, 'un_last_wasting_date_of_onset'] < \ - df.at[person_id, 'un_acute_malnutrition_tx_start_date'] < self.sim.date: + df.at[person_id, 'un_acute_malnutrition_tx_start_date'] < self.sim.date: return # continue with progression to severe if not treated/recovered @@ -867,7 +861,7 @@ def apply(self, person_id): # # Check if this person should still die from SAM: if pd.isnull(df.at[person_id, 'un_am_recovery_date']) & \ - (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM'): + (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM'): # Cause the death to happen immediately df.at[person_id, 'un_sam_death_date'] = self.sim.date self.sim.modules['Demography'].do_death( @@ -1171,13 +1165,14 @@ def __init__(self, module): # linear model to predict the incidence of wasting self.__Wasting_Incidence = LinearModel.multiplicative( - Predictor('age_exact_years').when('<0.5', self.params['base_inc_rate_wasting_by_agegp'][0]) - .when('<1.0', self.params['base_inc_rate_wasting_by_agegp'][1]) - .when('.between(1,1.9999)', self.params['base_inc_rate_wasting_by_agegp'][2]) - .when('.between(2,2.9999)', self.params['base_inc_rate_wasting_by_agegp'][3]) - .when('.between(3,3.9999)', self.params['base_inc_rate_wasting_by_agegp'][4]) - .when('.between(4,4.9999)', self.params['base_inc_rate_wasting_by_agegp'][5]) - .otherwise(0.0), + Predictor('age_exact_years', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) + .when('<0.5', self.params['base_inc_rate_wasting_by_agegp'][0]) + .when('.between(0.5,1, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][1]) + .when('.between(1,2, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][2]) + .when('.between(2,3, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][3]) + .when('.between(3,4, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][4]) + .when('.between(4,5, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][5]) + .otherwise(0.0), Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") &' '(nb_late_preterm == False) & (nb_early_preterm == False)', self.params['rr_wasting_SGA_and_term']), @@ -1193,36 +1188,37 @@ def __init__(self, module): # a linear model to predict the probability of individual's recovery from moderate acute malnutrition self.__Acute_Malnutrition_Recovery_MAM = LinearModel.multiplicative( - Predictor('un_am_treatment_type').when('soy_RUSF', self.params['recovery_rate_with_soy_RUSF']) - .when('CSB++', self.params['recovery_rate_with_CSB++']) - .otherwise(0.0), + Predictor('un_am_treatment_type', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) + .when('soy_RUSF', self.params['recovery_rate_with_soy_RUSF']) + .when('CSB++', self.params['recovery_rate_with_CSB++']) + .otherwise(0.0), ) # a linear model to predict the probability of individual's recovery from severe acute malnutrition self.__Acute_Malnutrition_Recovery_SAM = LinearModel.multiplicative( - Predictor('un_am_treatment_type') - .when('standard_RUTF', self.params['recovery_rate_with_standard_RUTF']) - .when('inpatient_care', self.params['recovery_rate_with_inpatient_care']) - .otherwise(0.0), + Predictor('un_am_treatment_type', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) + .when('standard_RUTF', self.params['recovery_rate_with_standard_RUTF']) + .when('inpatient_care', self.params['recovery_rate_with_inpatient_care']) + .otherwise(0.0), ) # Linear model for the probability of progression to severe wasting (age-dependent only) # (natural history only, no interventions) self.__Severe_Wasting_Progression = LinearModel.multiplicative( - Predictor('age_exact_years') - .when('<0.5', self.params['progression_severe_wasting_by_agegp'][0]) - .when('.between(0.5,0.9999)', self.params['progression_severe_wasting_by_agegp'][1]) - .when('.between(1,1.9999)', self.params['progression_severe_wasting_by_agegp'][2]) - .when('.between(2,2.9999)', self.params['progression_severe_wasting_by_agegp'][3]) - .when('.between(3,3.9999)', self.params['progression_severe_wasting_by_agegp'][4]) - .when('.between(4,4.9999)', self.params['progression_severe_wasting_by_agegp'][5]) - .otherwise(0.0), + Predictor('age_exact_years', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) + .when('<0.5', self.params['progression_severe_wasting_by_agegp'][0]) + .when('.between(0.5,1, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][1]) + .when('.between(1,2, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][2]) + .when('.between(2,3, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][3]) + .when('.between(3,4, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][4]) + .when('.between(4,5, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][5]) + .otherwise(0.0), ) self.__SAM_Death = LinearModel.multiplicative( Predictor('un_am_treatment_type').when('none', self.params['base_death_rate_untreated_SAM']), Predictor('un_sam_with_complications') - .when(True, self.params['rr_SAM_death_with_complications']), + .when(True, self.params['rr_SAM_death_with_complications']), Predictor().when('(un_am_bilateral_oedema == False) & ' '(un_WHZ_category == "WHZ<-3") &' '(un_am_MUAC_category == "115-<125mm")', @@ -1272,29 +1268,32 @@ def get_wasting_prevalence(self): wasting_prevalence = LinearModel( LinearModelType.LOGISTIC, 1.0, - Predictor('agrp', external=True) - .when('0_5mo', self.module.wasting_prevalence_odds_by_age_grp['0_5mo']) - .when('6_11mo', self.module.wasting_prevalence_odds_by_age_grp['6_11mo']) - .when('12_23mo', self.module.wasting_prevalence_odds_by_age_grp['12_23mo']) - .when('24_35mo', self.module.wasting_prevalence_odds_by_age_grp['24_35mo']) - .when('36_47mo', self.module.wasting_prevalence_odds_by_age_grp['36_47mo']) - .when('48_59mo', self.module.wasting_prevalence_odds_by_age_grp['48_59mo']) - .otherwise(1.0), - - Predictor('agrp_scaling', external=True) - .when('0_5mo', self.module.age_grps_dict['0_5mo']) - .when('6_11mo', self.module.age_grps_dict['6_11mo']) - .when('12_23mo', self.module.age_grps_dict['12_23mo']) - .when('24_35mo', self.module.age_grps_dict['24_35mo']) - .when('36_47mo', self.module.age_grps_dict['36_47mo']) - .when('48_59mo', self.module.age_grps_dict['48_59mo']) - .otherwise(1.0), - - Predictor('li_wealth').when(2, self.params['or_wasting_hhwealth_Q2']) - .when(3, self.params['or_wasting_hhwealth_Q3']) - .when(4, self.params['or_wasting_hhwealth_Q4']) - .when(5, self.params['or_wasting_hhwealth_Q5']) - .otherwise(1.0), + Predictor('agrp', external=True, conditions_are_mutually_exclusive=True, + conditions_are_exhaustive=True) + .when('0_5mo', self.module.wasting_prevalence_odds_by_age_grp['0_5mo']) + .when('6_11mo', self.module.wasting_prevalence_odds_by_age_grp['6_11mo']) + .when('12_23mo', self.module.wasting_prevalence_odds_by_age_grp['12_23mo']) + .when('24_35mo', self.module.wasting_prevalence_odds_by_age_grp['24_35mo']) + .when('36_47mo', self.module.wasting_prevalence_odds_by_age_grp['36_47mo']) + .when('48_59mo', self.module.wasting_prevalence_odds_by_age_grp['48_59mo']) + .otherwise(1.0), + + Predictor('agrp_scaling', external=True, conditions_are_mutually_exclusive=True, + conditions_are_exhaustive=True) + .when('0_5mo', self.module.age_grps_dict['0_5mo']) + .when('6_11mo', self.module.age_grps_dict['6_11mo']) + .when('12_23mo', self.module.age_grps_dict['12_23mo']) + .when('24_35mo', self.module.age_grps_dict['24_35mo']) + .when('36_47mo', self.module.age_grps_dict['36_47mo']) + .when('48_59mo', self.module.age_grps_dict['48_59mo']) + .otherwise(1.0), + + Predictor('li_wealth', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) + .when(2, self.params['or_wasting_hhwealth_Q2']) + .when(3, self.params['or_wasting_hhwealth_Q3']) + .when(4, self.params['or_wasting_hhwealth_Q4']) + .when(5, self.params['or_wasting_hhwealth_Q5']) + .otherwise(1.0), Predictor().when( '(nb_size_for_gestational_age == "small_for_gestational_age") ' '& (nb_late_preterm == False) & (nb_early_preterm == False)', @@ -1313,12 +1312,12 @@ def get_wasting_prevalence(self): return wasting_prevalence def get_moderate_acute_malnutrition_recovery(self): - """ get moderate acute malnutrition recovery amongst young children less than 5 years + """ returns linear model of moderate acute malnutrition recovery amongst young children less than 5 years """ return self.__Acute_Malnutrition_Recovery_MAM def get_severe_acute_malnutrition_recovery(self): - """ get severe acute malnutrition recovery amongst young children less than 5 years + """ returns linear model of severe acute malnutrition recovery amongst young children less than 5 years """ return self.__Acute_Malnutrition_Recovery_SAM @@ -1353,7 +1352,7 @@ def get_age_grps_odds(self): probability_less_than_minus2sd = 1 - whz_normal_distribution.sf(-2) # convert probability to odds and update odds by age group # dictionary - self.module.wasting_prevalence_odds_by_age_grp[agegp] =\ + self.module.wasting_prevalence_odds_by_age_grp[agegp] = \ probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) # get severe wasting zcores: WHZ <-3 @@ -1374,10 +1373,10 @@ def get_wasting_prevalence_scaling(self, df): actual_mean = wasting_prevalence.predict(df.loc[df.is_alive & (df.age_years == 1)], agrp=agegp, agrp_scaling='None').mean() # update and return age groups dictionary - self.module.age_grps_dict[agegp] =\ - self.module.wasting_prevalence_odds_by_age_grp[agegp] * (target_mean / actual_mean)\ - if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean))\ - else self.module.wasting_prevalence_odds_by_age_grp[agegp] + self.module.age_grps_dict[agegp] = \ + self.module.wasting_prevalence_odds_by_age_grp[agegp] * (target_mean / actual_mean) \ + if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) \ + else self.module.wasting_prevalence_odds_by_age_grp[agegp] class WastingLoggingEvent(RegularEvent, PopulationScopeEventMixin): @@ -1423,10 +1422,10 @@ def apply(self, population): (df.un_WHZ_category != 'WHZ>=-2')).sum() currently_wasted_age_36_47mo = \ (df.is_alive & ((df.age_exact_years >= 3) & (df.age_exact_years < 4)) & ( - df.un_WHZ_category != 'WHZ>=-2')).sum() + df.un_WHZ_category != 'WHZ>=-2')).sum() currently_wasted_age_48_59mo = \ (df.is_alive & ((df.age_exact_years >= 4) & (df.age_exact_years < 5)) & ( - df.un_WHZ_category != 'WHZ>=-2')).sum() + df.un_WHZ_category != 'WHZ>=-2')).sum() currently_wasted = {'0_5mo': currently_wasted_age_0_5mo, '6_11mo': currently_wasted_age_6_11mo, diff --git a/tests/test_wasting.py b/tests/test_wasting.py index c0b2c2fa56..2fb367b0e1 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -86,15 +86,15 @@ def check_configuration_of_properties(sim): # Those that were never wasted, should have normal WHZ score: assert ( - df.loc[~df.un_ever_wasted & - ~df.date_of_birth.isna(), 'un_WHZ_category'] == 'WHZ>=-2' + df.loc[~df.un_ever_wasted & + ~df.date_of_birth.isna(), 'un_WHZ_category'] == 'WHZ>=-2' ).all() # Those for whom the death date has past should be dead assert not df.loc[df.un_ever_wasted & (df['un_sam_death_date'] < sim.date), 'is_alive'].any() assert not df.loc[(df.un_clinical_acute_malnutrition == 'SAM') & ( - df['un_sam_death_date'] < sim.date), 'is_alive'].any() + df['un_sam_death_date'] < sim.date), 'is_alive'].any() # Check that those in a current episode have symptoms of wasting # [caused by the wasting module] but not others (among those alive) @@ -127,8 +127,8 @@ def check_configuration_of_properties(sim): assert set() == \ set_of_person_id_in_current_episode_before_recovery.intersection( - set_of_person_id_in_current_episode_before_death - ) + set_of_person_id_in_current_episode_before_death + ) # WHZ standard deviation of -3, oedema, and MUAC <115mm should cause # severe acute malnutrition @@ -199,6 +199,93 @@ def test_wasting_polling(tmpdir): assert person['un_last_wasting_date_of_onset'] == sim.date +def test_report_daly_weights(tmpdir): + """Check if daly weights reporting is done as expected. Four checks are made: + 1. For an individual who is well (No weights are expected/must be 0.0) + 2. For an individual with MAM and Oedema (expected daly weight is 0.051) + 3. For an individual with SAM, Oedema and Weight for Height Z-score(WHZ<-3), expected daly weight is 0.172 + 4. For an individual with SAM but no Oedema (expected daly weight is 0.128)""" + + dur = pd.DateOffset(days=0) + popsize = 1 + sim = get_sim(tmpdir) + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + + # Dict to hold the DALY weights + daly_wts = dict() + + # Get person to use + df = sim.population.props + person_id = df.index[0] + + # Check when no daly weight is available and person is not undernourished + df.at[person_id, 'is_alive'] = True + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' + + # Report daly weight for this individual + daly_weights_reported = sim.modules["Wasting"].report_daly_values() + + # Verify that individual has no daly weight + assert daly_weights_reported.loc[person_id] == 0.0 + + # Check daly weight for person with MAM (MAM daly weight is 0.051) + get_daly_weights = sim.modules['HealthBurden'].get_daly_weight + + # Reset diagnosis and check correct daly weight is given for MAM + df.loc[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' + df.loc[person_id, 'un_am_bilateral_oedema'] = True + daly_wts['MAM_with_oedema'] = get_daly_weights(sequlae_code=461) + + # Verify diagnosis + assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'MAM' + assert df.loc[person_id, 'un_am_bilateral_oedema'] == True + + # Report daly weight for this individual + daly_weights_reported = sim.modules["Wasting"].report_daly_values() + + # Compare the daly weight of this individual with the daly weight obtained from HealthBurden module + assert daly_wts['MAM_with_oedema'] == daly_weights_reported.loc[person_id] + + # Check daly weight for person with SAM and oedema (SAM_oedema weight is 0.172) + # Reset diagnosis + df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' + df.loc[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' + df.loc[person_id, 'un_am_bilateral_oedema'] = True + + # Verify diagnosis - an individual should be SAM + assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ<-3' + assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' + assert df.loc[person_id, 'un_am_bilateral_oedema'] == True + + # Report daly weight for this individual + daly_weights_reported = sim.modules["Wasting"].report_daly_values() + + # Get daly weights of SAM with Oedema + daly_wts['SAM_with_oedema'] = get_daly_weights(sequlae_code=463) + + # Compare the daly weight of this individual with the daly weight obtained from HealthBurden module + assert daly_wts['SAM_with_oedema'] == daly_weights_reported.loc[person_id] + + # Check daly weight for person with SAM no Oedema (SAM no oedema weight is 0.128) + # Reset diagnosis + df.loc[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' + df.loc[person_id, 'un_am_bilateral_oedema'] = False + + # Get day weights of SAM without Oedema + daly_wts['SAM_w/o_oedema'] = get_daly_weights(sequlae_code=462) + + # Report daly weight for this individual + daly_weights_reported = sim.modules["Wasting"].report_daly_values() + + # Verify diagnosis + assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' + assert df.loc[person_id, 'un_am_bilateral_oedema'] == False + + # Compare the daly weight of this individual with the daly weight obtained from HealthBurden module + assert daly_wts['SAM_w/o_oedema'] == daly_weights_reported.loc[person_id] + + def test_recovery_moderate_wasting(tmpdir): """Check natural recovery of moderate wasting """ dur = pd.DateOffset(days=0) @@ -609,10 +696,10 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): sim.simulate(end_date=start_date + dur) sim.event_queue.queue = [] # clear the queue + wasting_module = sim.modules['Wasting'] # Make 0% death rate by replacing with empty linear model 0.0 - sim.modules['Wasting'].sam_death_equation = LinearModel( + wasting_module.sam_death_equation = LinearModel( LinearModelType.MULTIPLICATIVE, 0.0) - wasting_module = sim.modules['Wasting'] # increase wasting incidence rate to 100% and reduce rate of progress to # severe wasting to zero.We don't want individuals to progress to SAM as From 140641c38b6ece9edcaafe2a8890e3bf4b3ee7ef Mon Sep 17 00:00:00 2001 From: mnjowe Date: Mon, 5 Feb 2024 16:51:56 +0200 Subject: [PATCH 035/755] removing unused death parameters and linear model, restructuring linear models and wasting tests --- resources/ResourceFile_Wasting.xlsx | 4 +- src/tlo/methods/wasting.py | 450 +++++++------------- tests/test_wasting.py | 609 ++++++++++++---------------- 3 files changed, 413 insertions(+), 650 deletions(-) diff --git a/resources/ResourceFile_Wasting.xlsx b/resources/ResourceFile_Wasting.xlsx index 162099f180..60acc22d60 100644 --- a/resources/ResourceFile_Wasting.xlsx +++ b/resources/ResourceFile_Wasting.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8bb674c8313b23ab955828ece7805a4fa2dc7c37d0b9d39322327b73c5dc2989 -size 12512 +oid sha256:b79a5d92163f8b69a1125003b4154f892e924011a0f1ae359a5b3c632f836179 +size 12146 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index f8487579f4..745d7042d6 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1,6 +1,7 @@ """Childhood wasting module""" import copy from pathlib import Path +from typing import Union import numpy as np import pandas as pd @@ -141,28 +142,6 @@ class Wasting(Module): Types.REAL, 'prevalence of nutritional oedema in children under 5 in Malawi'), 'proportion_oedema_with_WHZ<-2': Parameter( Types.REAL, 'proportion of oedematous malnutrition with concurrent wasting'), - # death CFR, risk factors - 'base_death_rate_untreated_SAM': Parameter( - Types.REAL, 'baseline death rate of untreated SAM'), - 'rr_SAM_death_with_complications': Parameter( - Types.REAL, 'relative rate of death for complicated SAM'), - 'rr_SAM_death_WHZ<-3_only': Parameter( - Types.REAL, 'relative risk of death from SAM if indices of WHZ<-3, compared to MUAC<115mm'), - 'rr_SAM_death_both_WHZ<-3_&_MUAC<115mm': Parameter( - Types.REAL, 'relative risk of death from SAM if both indices WHZ<-3 & MUAC<115mm are present, ' - 'compared to MUAC<115mm alone'), - 'rr_SAM_death_kwashiorkor_only': Parameter( - Types.REAL, - 'relative risk of death from SAM if bilateral oedema present (kwashiorkor), compared to MUAC<115mm alone'), - 'rr_SAM_death_kwashiorkor_MUAC<115mm_only': Parameter( - Types.REAL, 'relative risk of death from SAM if bilateral oedema present and MUAC<115mm, compared to ' - 'MUAC<115mm alone'), - 'rr_SAM_death_kwashiorkor_WHZ<-3_only': Parameter( - Types.REAL, 'relative risk of death from SAM if bilateral oedema present and WHZ<-3, compared to ' - 'MUAC<115mm alone'), - 'rr_SAM_death_kwashiorkor_both_WHZ<-3_&_MUAC<115mm': Parameter( - Types.REAL, 'relative risk of death from SAM if bilateral oedema present, WHZ<-3 and MUAC<115mm, ' - 'compared to MUAC<115mm alone'), # treatment parameters 'coverage_supplementary_feeding_program': Parameter( Types.REAL, 'coverage of supplementary feeding program for MAM in health centres'), @@ -170,8 +149,10 @@ class Wasting(Module): Types.REAL, 'coverage of outpatient therapeutic care for SAM in health centres'), 'coverage_inpatient_care': Parameter( Types.REAL, 'coverage of inpatient care for complicated SAM in hospitals'), - 'prob_mam_death_after_care': Parameter( - Types.LIST, 'probability of dying or returning to MAM after seeking care'), + 'prob_mam_after_care': Parameter( + Types.REAL, 'probability of returning to MAM after seeking care'), + 'prob_death_after_care': Parameter( + Types.REAL, 'probability of dying after seeking care'), } PROPERTIES = { @@ -204,8 +185,8 @@ def __init__(self, name=None, resourcefilepath=None): self.wasting_models = None self.resourcefilepath = resourcefilepath - # Store the symptoms that this module will use: - self.symptoms = {'weight_loss'} + # wasting symptom + self.wasting_symptom = 'weight_loss' # dict to hold counters for the number of episodes by wasting-type # and age-group @@ -216,23 +197,6 @@ def __init__(self, name=None, resourcefilepath=None): self.wasting_incident_case_tracker = copy.deepcopy(self.wasting_incident_case_tracker_blank) - # wasting prevalence odds by age groups - self.wasting_prevalence_odds_by_age_grp: dict = dict() - - # wasting prevalence scaling by age group - self.age_grps_dict: dict = {_agrp: 1.0 for _agrp in ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', - '48_59mo']} - - # store severe wasting by age groups probabilities - self.age_grps_sev_wasting_probs: dict = dict() - - def declare_symptoms(self): - for symptom_name in self.symptoms: - self.sim.modules['SymptomManager'].register_symptom( - Symptom(name=symptom_name) - # (give non-generic symptom 'average' healthcare seeking) - ) - def read_parameters(self, data_folder): """ :param data_folder: path of a folder supplied to the Simulation containing data files. Typically, @@ -240,26 +204,12 @@ def read_parameters(self, data_folder): :return: """ # Update parameters from the resource dataframe - # Read parameters from the resourcefile + # Read parameters from the resource file self.load_parameters_from_dataframe( pd.read_excel(Path(self.resourcefilepath) / 'ResourceFile_Wasting.xlsx', sheet_name='Parameter_values_AM')) - # Declare symptoms that this module will cause and which are not - # included in the generic symptoms: - self.declare_symptoms() - # generic_symptoms = self.sim.modules['SymptomManager'].generic_symptoms - # for symptom_name in self.symptoms: - # if symptom_name not in generic_symptoms: - # self.sim.modules['SymptomManager'].register_symptom( - # Symptom(name=symptom_name) - # # (give non-generic symptom 'average' healthcare seeking) - # ) - - def pre_initialise_population(self): - """Things to do before processing the population: - * Generate wasting models - """ - self.wasting_models = WastingModels(self) + # Register wasting symptom(weight loss) in Symptoms Manager + self.sim.modules['SymptomManager'].register_symptom(Symptom(name=self.wasting_symptom)) def initialise_population(self, population): """ @@ -274,8 +224,7 @@ def initialise_population(self, population): # Set initial properties df.loc[df.is_alive, 'un_ever_wasted'] = False - df.loc[ - df.is_alive, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished + df.loc[df.is_alive, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' df.loc[df.is_alive, 'un_last_wasting_date_of_onset'] = pd.NaT df.loc[df.is_alive, 'un_acute_malnutrition_tx_start_date'] = pd.NaT @@ -284,29 +233,23 @@ def initialise_population(self, population): df.loc[df.is_alive, 'un_am_MUAC_category'] = '>=125mm' df.loc[df.is_alive, 'un_am_treatment_type'] = 'not_applicable' - # update wasting prevalence odds dictionary - self.wasting_models.get_age_grps_odds() - - # update wasting prevalence scaling dictionary - self.wasting_models.get_wasting_prevalence_scaling(df) - - # initialise wasting prevalence linear model - wasting_prevalence = self.wasting_models.get_wasting_prevalence() + # initialise wasting linear models. + self.wasting_models = WastingModels(self) # Assign wasting categories in young children at initiation for low_bound_mnts, high_bound_mnths in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months low_bound_age_in_years = low_bound_mnts / 12.0 high_bound_age_in_years = (1 + high_bound_mnths) / 12.0 # linear model external variables - lm_ext_var = f'{low_bound_mnts}_{high_bound_mnths}mo' + agegp = f'{low_bound_mnts}_{high_bound_mnths}mo' mask = (df.is_alive & df.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, inclusive='left')) - prevalence_of_wasting = wasting_prevalence.predict(df.loc[mask], agrp='None', agrp_scaling=lm_ext_var) + prevalence_of_wasting = self.wasting_models.get_wasting_prevalence(agegp=agegp).predict(df.loc[mask]) # categorize into moderate (-3<=WHZ<-2) or severe (WHZ<-3) wasting wasted = self.rng.random_sample(len(prevalence_of_wasting)) < prevalence_of_wasting for idx in prevalence_of_wasting.index[wasted]: - probability_of_severe = self.age_grps_sev_wasting_probs[lm_ext_var] + probability_of_severe = self.get_odds_probs_wasting(agegp=agegp) wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], p=[probability_of_severe, 1 - probability_of_severe]) df.at[idx, 'un_WHZ_category'] = wasted_category @@ -315,14 +258,17 @@ def initialise_population(self, population): # start without treatment df.at[idx, 'un_am_treatment_type'] = 'none' - # update clinical symptoms for severe wasting - self.wasting_clinical_symptoms(person_id=idx) - # ------------------------------------------------------------------ # # # # # # Give MUAC category, presence of oedema, and determine # acute malnutrition state # # # # # self.population_poll_clinical_am(df) + children_with_sam = df.loc[df.is_alive & (df.age_exact_years < 5) + & (df.un_clinical_acute_malnutrition == 'SAM')] + for person in children_with_sam.index: + # update clinical symptoms for severe wasting + self.wasting_clinical_symptoms(person_id=person) + def initialise_simulation(self, sim): """Prepares for simulation: * Schedules the main polling event @@ -354,6 +300,34 @@ def on_birth(self, mother_id, child_id): df.at[child_id, 'un_am_MUAC_category'] = '>=125mm' df.at[child_id, 'un_am_treatment_type'] = 'not_applicable' + def get_odds_probs_wasting(self, agegp: str, lm_scaling: bool = False) -> Union[float, int]: + """ + This function will calculate the WHZ scores by categories and return probability or odds of severe wasting + for those with wasting status + :param agegp: age grouped in months + :param lm_scaling: whether this function is used for scaling wasting prevalence linear model or not + :return: + """ + # generate random numbers from N(meean, sd) + mean, stdev = self.parameters[f'prev_WHZ_distribution_age_{agegp}'] + whz_normal_distribution = norm(loc=mean, scale=stdev) + + # get all wasting: WHZ <-2 + probability_less_than_minus2sd = 1 - whz_normal_distribution.sf(-2) + + if lm_scaling: + # convert probability to odds and return the odds + return probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) + + # get severe wasting zcores: WHZ <-3 + probability_less_than_minus3sd = 1 - whz_normal_distribution.sf(-3) + + # make WHZ <-2 as the 100% and get the adjusted probability of severe wasting within overall wasting + proportion_severe_in_overall_wasting = probability_less_than_minus3sd * probability_less_than_minus2sd + + # get the probability of severe wasting + return proportion_severe_in_overall_wasting + def muac_cutoff_by_WHZ(self, idx, whz): """ Proportion of MUAC<115mm in WHZ<-3 and -3<=WHZ<-2, and proportion of wasted children with oedematous @@ -401,10 +375,10 @@ def muac_cutoff_by_WHZ(self, idx, whz): prob_less_than_115 = 1 - probability_over_or_equal_115 pro_between_115_125 = probability_over_or_equal_115 - probability_over_or_equal_125 - for id in idx: + for pid in idx: muac_cat = self.rng.choice(['<115mm', '115-<125mm', '>=125mm'], p=[prob_less_than_115, pro_between_115_125, probability_over_or_equal_125]) - df.at[id, 'un_am_MUAC_category'] = muac_cat + df.at[pid, 'un_am_MUAC_category'] = muac_cat def nutritional_oedema_present(self, idx): """ @@ -447,7 +421,7 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): # check if person is not wasted if ((df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2') & - (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & (~df.at[person_id, 'un_am_bilateral_oedema'])): + (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & (~df.at[person_id, 'un_am_bilateral_oedema'])): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' # severe acute malnutrition - MUAC<115mm and/or WHZ<-3 and/or @@ -521,7 +495,6 @@ def population_poll_clinical_am(self, population): self.nutritional_oedema_present(idx=index_under5) # determine the clinical acute malnutrition state ----- - df = self.sim.population.props for person_id in index_under5: self.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) @@ -550,9 +523,9 @@ def report_daly_values(self): total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & (~df.un_am_bilateral_oedema)] = daly_wts['SAM_w/o_oedema'] total_daly_values.loc[df.is_alive & ( - ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | ( - (df.un_WHZ_category != 'WHZ<-3') & ( - df.un_am_MUAC_category != "115-<125mm"))) & df.un_am_bilateral_oedema] = daly_wts[ + ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | ( + (df.un_WHZ_category != 'WHZ<-3') & ( + df.un_am_MUAC_category != "115-<125mm"))) & df.un_am_bilateral_oedema] = daly_wts[ 'MAM_with_oedema'] return total_daly_values @@ -565,15 +538,13 @@ def wasting_clinical_symptoms(self, person_id): if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': return - # currently symptoms list is applied to all (who are SAM) - for symptom in self.symptoms: - self.sim.modules["SymptomManager"].change_symptom( - person_id=person_id, - symptom_string=symptom, - add_or_remove="+", - disease_module=self, - # duration_in_days=None, - ) + # apply wasting symptoms to all SAM cases + self.sim.modules["SymptomManager"].change_symptom( + person_id=person_id, + symptom_string=self.wasting_symptom, + add_or_remove="+", + disease_module=self + ) def do_when_acute_malnutrition_assessment(self, person_id): """ @@ -633,7 +604,7 @@ def do_when_am_treatment(self, person_id, intervention): df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date if intervention == 'SFP': - mam_recovery = self.wasting_models.get_moderate_acute_malnutrition_recovery().predict( + mam_recovery = self.wasting_models.acute_malnutrition_recovery_mam_lm.predict( df.loc[[person_id]], self.rng) if mam_recovery: @@ -647,7 +618,7 @@ def do_when_am_treatment(self, person_id, intervention): return if intervention == 'OTC': - sam_recovery = self.wasting_models.get_severe_acute_malnutrition_recovery().predict( + sam_recovery = self.wasting_models.acute_malnutrition_recovery_sam_lm.predict( df.loc[[person_id]], self.rng) if sam_recovery: # schedule recovery date @@ -657,8 +628,8 @@ def do_when_am_treatment(self, person_id, intervention): # cancel death date df.at[person_id, 'un_sam_death_date'] = pd.NaT else: - outcome = self.rng.choice(['remained_mam', 'death'], p=self.parameters[ - 'prob_mam_death_after_care']) + outcome = self.rng.choice(['remained_mam', 'death'], p=[self.parameters['prob_mam_after_care'], + self.parameters['prob_death_after_care']]) if outcome == 'death': self.sim.schedule_event(event=SevereAcuteMalnutritionDeathEvent( module=self, person_id=person_id), @@ -670,9 +641,8 @@ def do_when_am_treatment(self, person_id, intervention): DateOffset(weeks=3)) if intervention == 'ITC': - sam_recovery = self.wasting_models.get_severe_acute_malnutrition_recovery().predict( + sam_recovery = self.wasting_models.acute_malnutrition_recovery_sam_lm.predict( df.loc[[person_id]], self.rng) - if sam_recovery: # schedule recovery date self.sim.schedule_event(event=ClinicalAcuteMalnutritionRecoveryEvent( @@ -682,7 +652,8 @@ def do_when_am_treatment(self, person_id, intervention): df.at[person_id, 'un_sam_death_date'] = pd.NaT else: outcome = self.rng.choice(['remained_mam', 'death'], - p=self.parameters['prob_mam_death_after_care']) + p=[self.parameters['prob_mam_after_care'], self.parameters[ + 'prob_death_after_care']]) if outcome == 'death': self.sim.schedule_event(event=SevereAcuteMalnutritionDeathEvent( module=self, person_id=person_id), @@ -720,11 +691,10 @@ def apply(self, population): # # # INCIDENCE OF WASTING # # # # # # # # # # # # # # # # # # # # # # Determine who will be onset with wasting among those who are not currently wasted ------------- inc_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & ( - df.un_WHZ_category == 'WHZ>=-2')] - get_incidence_of_wasting = \ - self.module.wasting_models.get_wasting_incidence(inc_wasting) - - incidence_of_wasting = rng.random_sample(len(get_incidence_of_wasting)) < get_incidence_of_wasting + df.un_WHZ_category == 'WHZ>=-2')] + incidence_of_wasting = self.module.wasting_models.wasting_incidence_lm.predict(inc_wasting, + rng=self.module.rng + ) wasting_idx = inc_wasting.index # update the properties for wasted children df.loc[wasting_idx[incidence_of_wasting], 'un_ever_wasted'] = True @@ -749,7 +719,7 @@ def apply(self, population): # and schedule progression event --------- progression_sev_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == '-3<=WHZ<-2')] - progression_severe_wasting = self.module.wasting_models.get_wasting_progression().predict( + progression_severe_wasting = self.module.wasting_models.severe_wasting_progression_lm.predict( progression_sev_wasting) progression_severe_wasting = \ @@ -804,7 +774,7 @@ class ProgressionSevereWastingEvent(Event, IndividualScopeEventMixin): """ This Event is for the onset of severe wasting (WHZ <-3). * Refreshes all the properties so that they pertain to this current episode of wasting - * Imposes the symptoms + * Imposes wasting symptom """ def __init__(self, module, person_id): @@ -817,7 +787,7 @@ def apply(self, person_id): # before progression to severe wasting, check those who started # supplementary feeding programme before today if df.at[person_id, 'un_last_wasting_date_of_onset'] < \ - df.at[person_id, 'un_acute_malnutrition_tx_start_date'] < self.sim.date: + df.at[person_id, 'un_acute_malnutrition_tx_start_date'] < self.sim.date: return # continue with progression to severe if not treated/recovered @@ -861,7 +831,7 @@ def apply(self, person_id): # # Check if this person should still die from SAM: if pd.isnull(df.at[person_id, 'un_am_recovery_date']) & \ - (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM'): + (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM'): # Cause the death to happen immediately df.at[person_id, 'un_sam_death_date'] = self.sim.date self.sim.modules['Demography'].do_death( @@ -1163,220 +1133,114 @@ def __init__(self, module): self.params = module.parameters self.rng = module.rng - # linear model to predict the incidence of wasting - self.__Wasting_Incidence = LinearModel.multiplicative( - Predictor('age_exact_years', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) - .when('<0.5', self.params['base_inc_rate_wasting_by_agegp'][0]) - .when('.between(0.5,1, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][1]) - .when('.between(1,2, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][2]) - .when('.between(2,3, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][3]) - .when('.between(3,4, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][4]) - .when('.between(4,5, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][5]) - .otherwise(0.0), - Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") &' - '(nb_late_preterm == False) & (nb_early_preterm == False)', - self.params['rr_wasting_SGA_and_term']), - Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") & ' - '(nb_late_preterm == True) | (nb_early_preterm == True)', - self.params['rr_wasting_SGA_and_preterm']), - Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") &' - '(nb_late_preterm == True) | (nb_early_preterm == True)', - self.params['rr_wasting_preterm_and_AGA']), - Predictor('li_wealth').apply(lambda x: 1 if x == 1 else (x - 1) ** ( - self.params['rr_wasting_wealth_level'])), - ) - # a linear model to predict the probability of individual's recovery from moderate acute malnutrition - self.__Acute_Malnutrition_Recovery_MAM = LinearModel.multiplicative( + self.acute_malnutrition_recovery_mam_lm = LinearModel.multiplicative( Predictor('un_am_treatment_type', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) - .when('soy_RUSF', self.params['recovery_rate_with_soy_RUSF']) - .when('CSB++', self.params['recovery_rate_with_CSB++']) - .otherwise(0.0), + .when('soy_RUSF', self.params['recovery_rate_with_soy_RUSF']) + .when('CSB++', self.params['recovery_rate_with_CSB++']) + .otherwise(0.0), ) # a linear model to predict the probability of individual's recovery from severe acute malnutrition - self.__Acute_Malnutrition_Recovery_SAM = LinearModel.multiplicative( + self.acute_malnutrition_recovery_sam_lm = LinearModel.multiplicative( Predictor('un_am_treatment_type', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) - .when('standard_RUTF', self.params['recovery_rate_with_standard_RUTF']) - .when('inpatient_care', self.params['recovery_rate_with_inpatient_care']) - .otherwise(0.0), + .when('standard_RUTF', self.params['recovery_rate_with_standard_RUTF']) + .when('inpatient_care', self.params['recovery_rate_with_inpatient_care']) + .otherwise(0.0), ) # Linear model for the probability of progression to severe wasting (age-dependent only) # (natural history only, no interventions) - self.__Severe_Wasting_Progression = LinearModel.multiplicative( + self.severe_wasting_progression_lm = LinearModel.multiplicative( Predictor('age_exact_years', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) - .when('<0.5', self.params['progression_severe_wasting_by_agegp'][0]) - .when('.between(0.5,1, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][1]) - .when('.between(1,2, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][2]) - .when('.between(2,3, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][3]) - .when('.between(3,4, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][4]) - .when('.between(4,5, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][5]) - .otherwise(0.0), + .when('<0.5', self.params['progression_severe_wasting_by_agegp'][0]) + .when('.between(0.5,1, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][1]) + .when('.between(1,2, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][2]) + .when('.between(2,3, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][3]) + .when('.between(3,4, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][4]) + .when('.between(4,5, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][5]) + .otherwise(0.0), ) - self.__SAM_Death = LinearModel.multiplicative( - Predictor('un_am_treatment_type').when('none', self.params['base_death_rate_untreated_SAM']), - Predictor('un_sam_with_complications') - .when(True, self.params['rr_SAM_death_with_complications']), - Predictor().when('(un_am_bilateral_oedema == False) & ' - '(un_WHZ_category == "WHZ<-3") &' - '(un_am_MUAC_category == "115-<125mm")', - self.params['rr_SAM_death_WHZ<-3_only']), - Predictor().when('(un_am_bilateral_oedema == False) & ' - '(un_WHZ_category == "WHZ<-3") & ' - '(un_am_MUAC_category == "<115mm")', - self.params['rr_SAM_death_both_WHZ<-3_&_MUAC<115mm']), - Predictor().when('(un_am_bilateral_oedema == True) & ' - '(un_WHZ_category == "-3<=WHZ<-2") & ' - '(un_am_MUAC_category == "<115mm")', - self.params['rr_SAM_death_kwashiorkor_only']), - Predictor().when('(un_am_bilateral_oedema == True) & ' - '(un_WHZ_category == "WHZ<-3") & ' - '(un_am_MUAC_category == "115-<125mm")', - self.params['rr_SAM_death_kwashiorkor_WHZ<-3_only']), - Predictor().when( - '(un_am_bilateral_oedema == True) & ' - '(un_WHZ_category == "WHZ<-3") & ' - '(un_am_MUAC_category == "<115mm")', - self.params['rr_SAM_death_kwashiorkor_both_WHZ<-3_&_MUAC<115mm'] - ), - Predictor().when('(un_am_bilateral_oedema == True) & ' - '(un_WHZ_category == "-3<=WHZ<-2") & ' - '(un_am_MUAC_category == "<115mm")', - self.params['rr_SAM_death_kwashiorkor_MUAC<115mm_only']), - ) + # get wasting incidence linear model + self.wasting_incidence_lm = self.get_wasting_incidence() - def get_wasting_incidence(self, df) -> pd.Series: - """ predict the incidence of wasting amongst young children + def get_wasting_incidence(self) -> LinearModel: + """ return a scaled wasting incidence linear model amongst young children :params df: population dataframe """ - unscaled_lm = self.__Wasting_Incidence + df = self.module.sim.population.props + + def unscaled_wasting_lm(intercept: Union[float, int] = 1.0) -> LinearModel: + # linear model to predict the incidence of wasting + return LinearModel( + LinearModelType.MULTIPLICATIVE, + intercept, + Predictor('age_exact_years').when('<0.5', self.params['base_inc_rate_wasting_by_agegp'][0]) + .when('<1.0', self.params['base_inc_rate_wasting_by_agegp'][1]) + .when('.between(1,1.9999)', self.params['base_inc_rate_wasting_by_agegp'][2]) + .when('.between(2,2.9999)', self.params['base_inc_rate_wasting_by_agegp'][3]) + .when('.between(3,3.9999)', self.params['base_inc_rate_wasting_by_agegp'][4]) + .when('.between(4,4.9999)', self.params['base_inc_rate_wasting_by_agegp'][5]) + .otherwise(0.0), + Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == False) & (nb_early_preterm == False)', + self.params['rr_wasting_SGA_and_term']), + Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + self.params['rr_wasting_SGA_and_preterm']), + Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") ' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + self.params['rr_wasting_preterm_and_AGA']), + Predictor('li_wealth').apply( + lambda x: 1 if x == 1 else (x - 1) ** (self.params['rr_wasting_wealth_level'])), + ) + + unscaled_lm = unscaled_wasting_lm() target_mean = self.params['base_inc_rate_wasting_by_agegp'][2] actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1) & (df.un_WHZ_category == 'WHZ>=-2')]).mean() scaled_intercept = 1.0 * (target_mean / actual_mean) \ if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else 1.0 - scaled_lm = unscaled_lm.predict(df) - return scaled_lm.apply(lambda row: row * scaled_intercept) + scaled_wasting_incidence_lm = unscaled_wasting_lm(intercept=scaled_intercept) + return scaled_wasting_incidence_lm - def get_wasting_prevalence(self): - """ predict wasting prevalence amongst young children less than 5 years + def get_wasting_prevalence(self, agegp: str) -> LinearModel: + """ return a scaled wasting prevalence linear model amongst young children less than 5 years :params df: population dataframe + :param agegp: children's age group """ - # linear model to predict the prevalence of wasting - wasting_prevalence = LinearModel( - LinearModelType.LOGISTIC, - 1.0, - Predictor('agrp', external=True, conditions_are_mutually_exclusive=True, - conditions_are_exhaustive=True) - .when('0_5mo', self.module.wasting_prevalence_odds_by_age_grp['0_5mo']) - .when('6_11mo', self.module.wasting_prevalence_odds_by_age_grp['6_11mo']) - .when('12_23mo', self.module.wasting_prevalence_odds_by_age_grp['12_23mo']) - .when('24_35mo', self.module.wasting_prevalence_odds_by_age_grp['24_35mo']) - .when('36_47mo', self.module.wasting_prevalence_odds_by_age_grp['36_47mo']) - .when('48_59mo', self.module.wasting_prevalence_odds_by_age_grp['48_59mo']) - .otherwise(1.0), + df = self.module.sim.population.props - Predictor('agrp_scaling', external=True, conditions_are_mutually_exclusive=True, - conditions_are_exhaustive=True) - .when('0_5mo', self.module.age_grps_dict['0_5mo']) - .when('6_11mo', self.module.age_grps_dict['6_11mo']) - .when('12_23mo', self.module.age_grps_dict['12_23mo']) - .when('24_35mo', self.module.age_grps_dict['24_35mo']) - .when('36_47mo', self.module.age_grps_dict['36_47mo']) - .when('48_59mo', self.module.age_grps_dict['48_59mo']) - .otherwise(1.0), - - Predictor('li_wealth', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) - .when(2, self.params['or_wasting_hhwealth_Q2']) + def make_linear_model_wasting(intercept: Union[float, int]) -> LinearModel: + return LinearModel( + LinearModelType.LOGISTIC, + intercept, # baseline odds: get_odds_wasting(agegp=agegp) + Predictor('li_wealth').when(2, self.params['or_wasting_hhwealth_Q2']) .when(3, self.params['or_wasting_hhwealth_Q3']) .when(4, self.params['or_wasting_hhwealth_Q4']) .when(5, self.params['or_wasting_hhwealth_Q5']) .otherwise(1.0), - Predictor().when( - '(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& (nb_late_preterm == False) & (nb_early_preterm == False)', - self.params['or_wasting_SGA_and_term']), - Predictor().when( - '(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', - self.params['or_wasting_SGA_and_preterm']), - Predictor().when( - '(nb_size_for_gestational_age == ' - '"average_for_gestational_age") ' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', - self.params['or_wasting_preterm_and_AGA']) - ) + Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == False) & (nb_early_preterm == False)', + self.params['or_wasting_SGA_and_term']), + Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + self.params['or_wasting_SGA_and_preterm']), + Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") ' + '& (nb_late_preterm == True) | (nb_early_preterm == True)', + self.params['or_wasting_preterm_and_AGA']) + ) - return wasting_prevalence + get_odds_wasting = self.module.get_odds_probs_wasting(agegp=agegp, lm_scaling=True) + unscaled_lm = make_linear_model_wasting(intercept=get_odds_wasting) + target_mean = self.module.get_odds_probs_wasting(agegp='12_23mo', lm_scaling=True) + actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1)]).mean() + scaled_intercept = get_odds_wasting * (target_mean / actual_mean) if \ + (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else get_odds_wasting + scaled_lm = make_linear_model_wasting(intercept=scaled_intercept) - def get_moderate_acute_malnutrition_recovery(self): - """ returns linear model of moderate acute malnutrition recovery amongst young children less than 5 years - """ - return self.__Acute_Malnutrition_Recovery_MAM - - def get_severe_acute_malnutrition_recovery(self): - """ returns linear model of severe acute malnutrition recovery amongst young children less than 5 years - """ - return self.__Acute_Malnutrition_Recovery_SAM - - def get_wasting_progression(self): - """ get wasting progression amongst young children less than 5 years - """ - return self.__Severe_Wasting_Progression - - def get_sam_deaths(self, df) -> pd.Series: - """ predict severe acute malnutrition deaths amongst young children less than 5 years - :params df: population dataframe - """ - pop = self.module.sim.population.props - pop_wanted = pop.loc[pop.is_alive & pop.age_exact_years.between(0.5, 5, inclusive='neither') & - (pop.un_clinical_acute_malnutrition == 'SAM')] - - unscaled_lm = self.__SAM_Death - target_mean = self.params['base_death_rate_untreated_SAM'] - actual_mean = unscaled_lm.predict(pop_wanted).mean() - scaled_intercept = 1.0 * (target_mean / actual_mean) if (target_mean != 0 and actual_mean != 0 and - ~np.isnan(actual_mean)) else 1.0 - scaled_lm = self.__SAM_Death.predict(df) - - return scaled_lm.apply(lambda row: row * scaled_intercept) - - def get_age_grps_odds(self): - """ Return odds determined by age groups. This will be applied in wasting prevalence linear model """ - for agegp in self.module.age_grps_dict.keys(): - mean, stdev = self.params[f'prev_WHZ_distribution_age_{agegp}'] - whz_normal_distribution = norm(loc=mean, scale=stdev) - # get all wasting: WHZ <-2 - probability_less_than_minus2sd = 1 - whz_normal_distribution.sf(-2) - # convert probability to odds and update odds by age group - # dictionary - self.module.wasting_prevalence_odds_by_age_grp[agegp] = \ - probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) - - # get severe wasting zcores: WHZ <-3 - probability_less_than_minus3sd = 1 - whz_normal_distribution.sf(-3) - # make WHZ <-2 as the 100% and get the adjusted probability of severe wasting within - # overall wasting - self.module.age_grps_sev_wasting_probs[agegp] = \ - probability_less_than_minus3sd * probability_less_than_minus2sd - - def get_wasting_prevalence_scaling(self, df): - """ get values for scaling wasting prevalence linear model - :params df: population dataframe """ - # initialise wasting prevalence linear model - wasting_prevalence = self.get_wasting_prevalence() - # index the age groups dictionary - for agegp in self.module.age_grps_dict.keys(): - target_mean = self.module.wasting_prevalence_odds_by_age_grp['12_23mo'] - actual_mean = wasting_prevalence.predict(df.loc[df.is_alive & (df.age_years == 1)], - agrp=agegp, agrp_scaling='None').mean() - # update and return age groups dictionary - self.module.age_grps_dict[agegp] = \ - self.module.wasting_prevalence_odds_by_age_grp[agegp] * (target_mean / actual_mean) \ - if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) \ - else self.module.wasting_prevalence_odds_by_age_grp[agegp] + return scaled_lm class WastingLoggingEvent(RegularEvent, PopulationScopeEventMixin): @@ -1422,10 +1286,10 @@ def apply(self, population): (df.un_WHZ_category != 'WHZ>=-2')).sum() currently_wasted_age_36_47mo = \ (df.is_alive & ((df.age_exact_years >= 3) & (df.age_exact_years < 4)) & ( - df.un_WHZ_category != 'WHZ>=-2')).sum() + df.un_WHZ_category != 'WHZ>=-2')).sum() currently_wasted_age_48_59mo = \ (df.is_alive & ((df.age_exact_years >= 4) & (df.age_exact_years < 5)) & ( - df.un_WHZ_category != 'WHZ>=-2')).sum() + df.un_WHZ_category != 'WHZ>=-2')).sum() currently_wasted = {'0_5mo': currently_wasted_age_0_5mo, '6_11mo': currently_wasted_age_6_11mo, diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 2fb367b0e1..10758809b4 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -6,10 +6,13 @@ import pandas as pd import pytest +from pandas import DateOffset -from tlo import Date, Simulation, logging +from tlo import Date, Module, Simulation, logging +from tlo.events import PopulationScopeEventMixin, RegularEvent from tlo.lm import LinearModel, LinearModelType from tlo.methods import ( + Metadata, demography, enhanced_lifestyle, healthburden, @@ -55,148 +58,148 @@ def get_sim(tmpdir): }) sim.register(demography.Demography(resourcefilepath=resourcefilepath), - enhanced_lifestyle.Lifestyle( - resourcefilepath=resourcefilepath), + enhanced_lifestyle.Lifestyle(resourcefilepath=resourcefilepath), healthsystem.HealthSystem(resourcefilepath=resourcefilepath, disable=False, cons_availability='all'), - symptommanager.SymptomManager( - resourcefilepath=resourcefilepath), - healthseekingbehaviour.HealthSeekingBehaviour( - resourcefilepath=resourcefilepath), - healthburden.HealthBurden( - resourcefilepath=resourcefilepath), - simplified_births.SimplifiedBirths( - resourcefilepath=resourcefilepath), + symptommanager.SymptomManager(resourcefilepath=resourcefilepath), + healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resourcefilepath), + healthburden.HealthBurden(resourcefilepath=resourcefilepath), + simplified_births.SimplifiedBirths(resourcefilepath=resourcefilepath), wasting.Wasting(resourcefilepath=resourcefilepath) ) return sim -def check_dtypes(sim): - # Check types of columns - df = sim.population.props - orig = sim.population.new_row - assert (df.dtypes == orig.dtypes).all() - - -def check_configuration_of_properties(sim): - # check that the properties are ok: - df = sim.population.props - - # Those that were never wasted, should have normal WHZ score: - assert ( - df.loc[~df.un_ever_wasted & - ~df.date_of_birth.isna(), 'un_WHZ_category'] == 'WHZ>=-2' - ).all() - - # Those for whom the death date has past should be dead - assert not df.loc[df.un_ever_wasted & - (df['un_sam_death_date'] < sim.date), 'is_alive'].any() - assert not df.loc[(df.un_clinical_acute_malnutrition == 'SAM') & ( - df['un_sam_death_date'] < sim.date), 'is_alive'].any() - - # Check that those in a current episode have symptoms of wasting - # [caused by the wasting module] but not others (among those alive) - has_symptoms_of_wasting = \ - set(sim.modules['SymptomManager'].who_has('weight_loss')) - has_symptoms = set([p for p in has_symptoms_of_wasting if - 'Wasting' in - sim.modules['SymptomManager'].causes_of(p, - 'weight_loss') - ]) - - in_current_episode_before_recovery = \ - df.is_alive & \ - df.un_ever_wasted & \ - (df.un_last_wasting_date_of_onset <= sim.date) & \ - (sim.date <= df.un_am_recovery_date) - set_of_person_id_in_current_episode_before_recovery = set( - in_current_episode_before_recovery[ - in_current_episode_before_recovery].index - ) - - in_current_episode_before_death = \ - df.is_alive & \ - df.un_ever_wasted & \ - (df.un_last_wasting_date_of_onset <= sim.date) & \ - (sim.date <= df.un_sam_death_date) - set_of_person_id_in_current_episode_before_death = set( - in_current_episode_before_death[in_current_episode_before_death].index - ) - - assert set() == \ - set_of_person_id_in_current_episode_before_recovery.intersection( - set_of_person_id_in_current_episode_before_death - ) - - # WHZ standard deviation of -3, oedema, and MUAC <115mm should cause - # severe acute malnutrition - whz_index = df.index[df['un_WHZ_category'] == 'WHZ<-3'] - oedema_index = df.index[df['un_am_bilateral_oedema']] - muac_index = df.index[df['un_am_MUAC_category'] == '<115mm'] - assert (df.loc[whz_index, 'un_clinical_acute_malnutrition'] == "SAM").all() - assert (df.loc[ - oedema_index, 'un_clinical_acute_malnutrition'] == "SAM").all() - assert (df.loc[ - muac_index, 'un_clinical_acute_malnutrition'] == "SAM").all() - - # all SAM individuals should have symptoms of wasting - assert set(df.index[df.is_alive & (df.age_exact_years < 5) & - (df.un_clinical_acute_malnutrition == 'SAM')] - ).issubset(has_symptoms) - - # All MAM individuals should have no symptoms of wasting - assert set(df.index[df.is_alive & (df.age_exact_years < 5) & - (df.un_clinical_acute_malnutrition == 'MAM')]) \ - not in has_symptoms - - @pytest.mark.slow def test_basic_run(tmpdir): """Short run of the module using default parameters with check on dtypes""" + class DummyModule(Module): + """ A Dummy module that ensure wasting properties are as expected on a daily basis """ + METADATA = {Metadata.DISEASE_MODULE} + + def read_parameters(self, data_folder): + pass + + def initialise_population(self, population): + pass + + def initialise_simulation(self, sim): + # schedule check property integrity event + sim.schedule_event(CheckPropertyIntegrityEvent(self), sim.date) + + def on_birth(self, mother_id, child_id): + pass + + class CheckPropertyIntegrityEvent(RegularEvent, PopulationScopeEventMixin): + def __init__(self, module): + """schedule to run every day + :param module: the module that created this event + """ + self.repeat_days = 1 + super().__init__(module, frequency=DateOffset(days=self.repeat_days)) + assert isinstance(module, DummyModule) + + def apply(self, population): + """ Apply this event to the population. + :param population: the current population + """ + # check datatypes + self.check_dtypes(population) + + # check properties are as expected + self.check_configuration_of_properties(population) + + def check_dtypes(self, population): + # Check types of columns + df = population.props + orig = population.new_row + assert (df.dtypes == orig.dtypes).all() + + def check_configuration_of_properties(self, population): + """ check wasting properties on a daily basis to ensure integrity """ + df = population.props + under5_sam = df.index[df.is_alive & (df.age_exact_years < 5) & + (df.un_clinical_acute_malnutrition == 'SAM')] + + # Those that were never wasted, should have normal WHZ score: + assert (df.loc[~df.un_ever_wasted & ~df.date_of_birth.isna(), 'un_WHZ_category'] == 'WHZ>=-2').all() + + # Those for whom the death date has past should be dead + assert not df.loc[df.un_ever_wasted & (df['un_sam_death_date'] < self.sim.date), 'is_alive'].any() + assert not df.loc[ + (df.un_clinical_acute_malnutrition == 'SAM') & (df['un_sam_death_date'] < self.sim.date), + 'is_alive'].any() + + # Check that those in a current episode have symptoms of wasting + # [caused by the wasting module] but not others (among those alive) + has_symptoms_of_wasting = set(self.sim.modules['SymptomManager'].who_has('weight_loss')) + + has_symptoms = set([p for p in has_symptoms_of_wasting if + 'Wasting' in sim.modules['SymptomManager'].causes_of(p, 'weight_loss')]) + + in_current_episode_before_recovery = df.is_alive & df.un_ever_wasted & (df.un_last_wasting_date_of_onset <= + self.sim.date) & (self.sim.date <= + df.un_am_recovery_date) + set_of_person_id_in_current_episode_before_recovery = set(in_current_episode_before_recovery[ + in_current_episode_before_recovery].index) + + in_current_episode_before_death = df.is_alive & df.un_ever_wasted & (df.un_last_wasting_date_of_onset <= + self.sim.date) & ( + self.sim.date <= df.un_sam_death_date) + set_of_person_id_in_current_episode_before_death = set(in_current_episode_before_death[ + in_current_episode_before_death].index) + + assert set() == set_of_person_id_in_current_episode_before_recovery.intersection( + set_of_person_id_in_current_episode_before_death) + + # WHZ standard deviation of -3, oedema, and MUAC <115mm should cause severe acute malnutrition + whz_index = df.index[df['un_WHZ_category'] == 'WHZ<-3'] + oedema_index = df.index[df['un_am_bilateral_oedema']] + muac_index = df.index[df['un_am_MUAC_category'] == '<115mm'] + assert (df.loc[whz_index, 'un_clinical_acute_malnutrition'] == "SAM").all() + assert (df.loc[oedema_index, 'un_clinical_acute_malnutrition'] == "SAM").all() + assert (df.loc[muac_index, 'un_clinical_acute_malnutrition'] == "SAM").all() + + # all SAM individuals should have symptoms of wasting + assert set(under5_sam).issubset(has_symptoms) + + # All MAM individuals should have no symptoms of wasting + assert set(df.index[df.is_alive & (df.age_exact_years < 5) & + (df.un_clinical_acute_malnutrition == 'MAM')]) not in has_symptoms + popsize = 10_000 sim = get_sim(tmpdir) + sim.register(DummyModule()) sim.make_initial_population(n=popsize) sim.simulate(end_date=end_date) - check_dtypes(sim) - check_configuration_of_properties(sim) -def test_wasting_polling(tmpdir): - """Check polling events leads to incident cases""" +def test_wasting_incidence(tmpdir): + """Check Incidence of wasting is happening as expected """ # get simulation object: dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) - # Make incidence of wasting very high : - params = sim.modules['Wasting'].parameters - params['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] - params['progression_severe_wasting_by_agegp'] = [0, 0, 0, 0, 0, 0] - - # re-initialise wasting linear models to use the updated parameter - sim.modules['Wasting'].pre_initialise_population() - sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - # Run polling event: check that an incident case is produced: + # Set incidence of wasting at 100% + sim.modules['Wasting'].wasting_models.wasting_incidence_lm = LinearModel.multiplicative() + + # Run polling event: check that all children should now have moderate wasting: polling = WastingPollingEvent(sim.modules['Wasting']) polling.apply(sim.population) - # assert len([q for q in sim.event_queue.queue if - # isinstance(q[3], ProgressionSevereWastingEvent)]) > 0 - # Check properties of individuals: should now be moderately wasted df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date + assert all(under5s['un_ever_wasted']) + assert all(under5s['un_WHZ_category'] == '-3<=WHZ<-2') + assert all(under5s['un_last_wasting_date_of_onset'] == sim.date) def test_report_daly_weights(tmpdir): @@ -256,7 +259,7 @@ def test_report_daly_weights(tmpdir): # Verify diagnosis - an individual should be SAM assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ<-3' assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' - assert df.loc[person_id, 'un_am_bilateral_oedema'] == True + assert df.loc[person_id, 'un_am_bilateral_oedema'] # Report daly weight for this individual daly_weights_reported = sim.modules["Wasting"].report_daly_values() @@ -280,7 +283,7 @@ def test_report_daly_weights(tmpdir): # Verify diagnosis assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' - assert df.loc[person_id, 'un_am_bilateral_oedema'] == False + assert not df.loc[person_id, 'un_am_bilateral_oedema'] # Compare the daly weight of this individual with the daly weight obtained from HealthBurden module assert daly_wts['SAM_w/o_oedema'] == daly_weights_reported.loc[person_id] @@ -300,21 +303,15 @@ def test_recovery_moderate_wasting(tmpdir): df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] + # make this individual have no wasting + df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' + # confirm wasting property is reset. This individual should have no wasting assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' - # get wasting module - wmodule = sim.modules['Wasting'] - # increase wasting incidence rate to 100% for all - # age groups(less than 5 years) - wmodule.parameters['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, - 1.0, 1.0] - wmodule.parameters['progression_severe_wasting_by_agegp'] = [0.0, 0.0, 0.0, - 0.0, 0.0, 0.0] + # Set incidence of wasting at 100% + sim.modules['Wasting'].wasting_models.wasting_incidence_lm = LinearModel.multiplicative() - # re-initialise wasting linear models to use the updated parameter - wmodule.pre_initialise_population() - - # Run Wasting Polling event to get new incident cases: + # Run Wasting Polling event: This event should cause all young children to be moderate wasting polling = WastingPollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) @@ -329,9 +326,8 @@ def test_recovery_moderate_wasting(tmpdir): # Check that there is a WastingNaturalRecoveryEvent scheduled # for this person - recov_event_tuple = \ - [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], WastingNaturalRecoveryEvent)][0] + recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], WastingNaturalRecoveryEvent)][0] date_of_scheduled_recov = recov_event_tuple[0] recov_event = recov_event_tuple[1] assert date_of_scheduled_recov > sim.date @@ -348,9 +344,8 @@ def test_recovery_moderate_wasting(tmpdir): def test_recovery_severe_wasting_without_complications(tmpdir): - """ Check natural recovery to MAM by removing death rate for those with - severe wasting, and check the onset of symptoms with SAM and revolving - of symptoms when recovered to MAM """ + """ Check natural recovery to MAM by removing death rate for those with severe wasting, and check the onset of + symptoms with SAM and revolving of symptoms when recovered to MAM """ dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) @@ -363,19 +358,19 @@ def test_recovery_severe_wasting_without_complications(tmpdir): df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] + # make this individual have no wasting + df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' + # confirm wasting property is reset. This individual should have no wasting assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' # get wasting module wmodule = sim.modules['Wasting'] - # increase wasting incidence rate to 100% for all - # age groups(less than 5 years) - wmodule.parameters['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, - 1.0, 1.0] - wmodule.parameters['progression_severe_wasting_by_agegp'] = [1.0, 1.0, 1.0, - 1.0, 1.0, 1.0] - # re-initialise wasting linear models to use the updated parameter - wmodule.pre_initialise_population() + # Set incidence of wasting at 100% + wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() + + # set progress to severe wasting at 100% as well + wmodule.wasting_models.severe_wasting_progression_lm = LinearModel.multiplicative() # Run Wasting Polling event to get new incident cases: polling = WastingPollingEvent(module=sim.modules['Wasting']) @@ -390,11 +385,9 @@ def test_recovery_severe_wasting_without_complications(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Check that there is a ProgressionSevereWastingEvent scheduled - # for this person: - progression_event_tuple = \ - [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], ProgressionSevereWastingEvent)][0] + # Check that there is a ProgressionSevereWastingEvent scheduled for this person: + progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], ProgressionSevereWastingEvent)][0] date_of_scheduled_progression = progression_event_tuple[0] progression_event = progression_event_tuple[1] assert date_of_scheduled_progression > sim.date @@ -404,12 +397,9 @@ def test_recovery_severe_wasting_without_complications(tmpdir): progression_event.apply(person_id=person_id) # Check individuals have symptoms caused by Wasting (SAM only) - assert 0 < len(sim.modules['SymptomManager'].has_what(person_id, - sim.modules[ - 'Wasting'])) + assert 0 < len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) - # Check properties of this individual: (should now be severely wasted and - # without a scheduled death date) + # Check properties of this individual: (should now be severely wasted and without a scheduled death date) person = df.loc[person_id] assert person['un_ever_wasted'] assert person['un_WHZ_category'] == 'WHZ<-3' @@ -422,41 +412,29 @@ def test_recovery_severe_wasting_without_complications(tmpdir): hsp.run() # check non-emergency care event is scheduled - assert isinstance( - sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - - # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and - # check care was sought - ge = [ev[1] for ev in - sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - ][0] + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + + # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought + ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) # check HSI event is scheduled - assert isinstance( - sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - HSI_Wasting_OutpatientTherapeuticProgramme_SAM) - - # Run the created instance of - # HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought - sam_ev = [ev[1] for ev in - sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], - HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + + # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] sam_ev.run(squeeze_factor=0.0) # check recovery event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[1][1], - ClinicalAcuteMalnutritionRecoveryEvent) + assert isinstance(sim.find_events_for_person(person_id)[1][1], ClinicalAcuteMalnutritionRecoveryEvent) # Run the recovery event and check the individual has recovered from SAM: - sam_recovery_event_tuple = \ - [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent) - ][0] + sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] date_of_scheduled_recovery_to_mam = sam_recovery_event_tuple[0] sam_recovery_event = sam_recovery_event_tuple[1] @@ -473,14 +451,12 @@ def test_recovery_severe_wasting_without_complications(tmpdir): assert pd.isnull(person['un_sam_death_date']) # check they have no symptoms: - assert 0 == len(sim.modules['SymptomManager'].has_what(person_id, - sim.modules[ - 'Wasting'])) + assert 0 == len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) def test_recovery_severe_wasting_with_complications(tmpdir): """ test individual's recovery from wasting with complications """ - dur = pd.DateOffset(days=3) + dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) @@ -513,61 +489,43 @@ def test_recovery_severe_wasting_with_complications(tmpdir): assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' # symptoms should be applied - assert person_id in set( - sim.modules['SymptomManager'].who_has('weight_loss')) + assert person_id in set(sim.modules['SymptomManager'].who_has('weight_loss')) # should have complications assert df.at[person_id, 'un_sam_with_complications'] # make recovery rate to 100% and death rate to zero so that # this individual should recover - wasting_module = sim.modules['Wasting'] - wasting_module.parameters['recovery_rate_with_inpatient_care'] = 1.0 - wasting_module.parameters['base_death_rate_untreated_SAM'] = 0.0 - - # re-initialise wasting models - wasting_module.pre_initialise_population() + wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel.multiplicative() - # run care seeking event and ensure HSI for complicated SAM is scheduled + # run care seeking event and ensure HSI for complicated SAM is scheduled hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) hsp.run() # check non-emergency care event is scheduled - assert isinstance( - sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - - # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and - # check care was sought - ge = [ev[1] for ev in - sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - ][0] + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + + # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought + ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) # check HSI event for complicated SAM is scheduled - assert isinstance( - sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - HSI_Wasting_InpatientCareForComplicated_SAM) - - # Run the created instance of - # HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought - sam_ev = [ev[1] for ev in - sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], HSI_Wasting_InpatientCareForComplicated_SAM)][ - 0] + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + HSI_Wasting_InpatientCareForComplicated_SAM) + + # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], HSI_Wasting_InpatientCareForComplicated_SAM)][0] sam_ev.run(squeeze_factor=0.0) # check recovery event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[0][1], - ClinicalAcuteMalnutritionRecoveryEvent) + assert isinstance(sim.find_events_for_person(person_id)[0][1], ClinicalAcuteMalnutritionRecoveryEvent) # Run the recovery event and check the individual has recovered from SAM: - sam_recovery_event_tuple = \ - [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], - ClinicalAcuteMalnutritionRecoveryEvent)][0] + sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] date_of_scheduled_recovery_to_mam = sam_recovery_event_tuple[0] sam_recovery_event = sam_recovery_event_tuple[1] @@ -584,13 +542,11 @@ def test_recovery_severe_wasting_with_complications(tmpdir): assert pd.isnull(person['un_sam_death_date']) # check they have no symptoms: - assert 0 == len(sim.modules['SymptomManager'].has_what(person_id, - sim.modules[ - 'Wasting'])) + assert 0 == len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) def test_nat_hist_death(tmpdir): - """Check: Wasting onset --> death""" + """ Check: Wasting onset --> death """ """ Check if the risk of death is 100% does everyone with SAM die? """ dur = pd.DateOffset(days=0) popsize = 1000 @@ -601,24 +557,20 @@ def test_nat_hist_death(tmpdir): sim.event_queue.queue = [] # clear the queue # get wasting module - wasting_module = sim.modules['Wasting'] - # Make 100% death rate by replacing with empty linear model 1.0 - wasting_module.sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 1.0) + wmodule = sim.modules['Wasting'] + + # Set death rate at 100% + wmodule.parameters['prob_death_after_care'] = 1.0 + wmodule.parameters['prob_mam_after_care'] = 0.0 + + # make zero recovery rate. reset recovery linear model + wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) # Get the children to use: df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] - # re-set parameter values to make zero recovery rate and 100% death rate - wasting_module.parameters['recovery_rate_with_standard_RUTF'] = 0.0 - wasting_module.parameters['recovery_rate_with_inpatient_care'] = 0.0 - wasting_module.parameters['base_death_rate_untreated_SAM'] = 1.0 - - # re-initialise wasting models - wasting_module.pre_initialise_population() - # make an individual diagnosed as SAM by WHZ category. # We want to make this individual qualify for death df.loc[person_id, 'un_ever_wasted'] = True @@ -626,51 +578,39 @@ def test_nat_hist_death(tmpdir): df.loc[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' # apply wasting symptoms to this individual - wasting_module.wasting_clinical_symptoms(person_id) + wmodule.wasting_clinical_symptoms(person_id) # check symptoms are applied - assert person_id in set( - sim.modules['SymptomManager'].who_has('weight_loss')) + assert person_id in set(sim.modules['SymptomManager'].who_has('weight_loss')) # run health seeking behavior and ensure non-emergency event is scheduled hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) hsp.run() # check non-emergency care event is scheduled - assert isinstance( - sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - - # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 - # and check care was sought - ge = [ev[1] for ev in - sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - ][0] + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + + # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought + ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) + if isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) # check inpatient care event is scheduled - assert isinstance( - sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - HSI_Wasting_OutpatientTherapeuticProgramme_SAM) - - # Run the created instance of - # HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought - sam_ev = [ev[1] for ev in - sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], - HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + + # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) + if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] sam_ev.run(squeeze_factor=0.0) # since there is zero recovery rate, check death event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[0][1], - SevereAcuteMalnutritionDeathEvent) + assert isinstance(sim.find_events_for_person(person_id)[0][1], SevereAcuteMalnutritionDeathEvent) # # Run the acute death event and ensure the person is now dead: - death_event_tuple = \ - [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent)][0] + death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent)][0] date_of_scheduled_death = death_event_tuple[0] death_event = death_event_tuple[1] assert date_of_scheduled_death > sim.date @@ -685,8 +625,8 @@ def test_nat_hist_death(tmpdir): def test_nat_hist_cure_if_recovery_scheduled(tmpdir): - """ Show that if a cure event is run before when a person was going to - recover naturally, it causes the episode to end earlier. """ + """ Show that if a cure event is run before when a person was going to recover naturally, it causes the episode + to end earlier. """ dur = pd.DateOffset(days=0) popsize = 1000 @@ -696,24 +636,15 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): sim.simulate(end_date=start_date + dur) sim.event_queue.queue = [] # clear the queue - wasting_module = sim.modules['Wasting'] + wmodule = sim.modules['Wasting'] # Make 0% death rate by replacing with empty linear model 0.0 - wasting_module.sam_death_equation = LinearModel( - LinearModelType.MULTIPLICATIVE, 0.0) - - # increase wasting incidence rate to 100% and reduce rate of progress to - # severe wasting to zero.We don't want individuals to progress to SAM as - # we are testing for MAM natural recovery - wasting_module.parameters['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, - 1.0, 1.0, - 1.0, 1.0] - wasting_module.parameters['progression_severe_wasting_by_agegp'] = [0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0] - wasting_module.pre_initialise_population() + wmodule.parameters['prob_death_after_care'] = 0.0 + wmodule.parameters['prob_mam_after_care'] = 1.0 + + # increase wasting incidence rate to 100% and reduce rate of progress to severe wasting to zero.We don't want + # individuals to progress to SAM as we are testing for MAM natural recovery + wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() + wmodule.wasting_models.severe_wasting_progression_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) # Get person to use: df = sim.population.props @@ -725,8 +656,7 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): polling = WastingPollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) - # Check properties of this individual: (should now be moderately wasted - # without progression to severe) + # Check properties of this individual: (should now be moderately wasted without progression to severe) person = df.loc[person_id] assert person['un_ever_wasted'] assert person['un_WHZ_category'] == '-3<=WHZ<-2' @@ -735,19 +665,15 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Check that there is a WastingNaturalRecoveryEvent scheduled for - # this person: - recov_event_tuple = \ - [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], WastingNaturalRecoveryEvent)][0] + # Check that there is a WastingNaturalRecoveryEvent scheduled for this person: + recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], WastingNaturalRecoveryEvent)][0] date_of_scheduled_recov = recov_event_tuple[0] recov_event = recov_event_tuple[1] assert date_of_scheduled_recov > sim.date # Run a Cure Event - cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, - module=sim.modules[ - 'Wasting']) + cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) cure_event.apply(person_id=person_id) # Check that the person is not wasted and is alive still: @@ -757,8 +683,7 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): assert not pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Run the recovery event that was originally scheduled - - # this should have no effect + # Run the recovery event that was originally scheduled - this should have no effect sim.date = date_of_scheduled_recov recov_event.apply(person_id=person_id) person = df.loc[person_id] @@ -769,8 +694,8 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): def test_nat_hist_cure_if_death_scheduled(tmpdir): - """Show that if a cure event is run before when a person was going to die, - it causes the episode to end without the person dying.""" + """Show that if a cure event is run before when a person was going to die, it causes the episode to end without + the person dying.""" dur = pd.DateOffset(days=0) popsize = 1000 @@ -781,29 +706,21 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): sim.event_queue.queue = [] # clear the queue # get wasting module parameters - params = sim.modules['Wasting'].parameters + wmodule = sim.modules['Wasting'] + # increase to 100% death rate, incidence and progress to severe wasting - params['base_death_rate_untreated_SAM'] = 1.0 - params['base_inc_rate_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] - params['progression_severe_wasting_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, - 1.0] - params['prob_mam_death_after_care'] = [0.0, 1.0] - - # reduce to 0% recovery rate. This is to ensure death event is scheduled - # for the individual each time we run this test - params['recovery_rate_with_standard_RUTF'] = 0.0 - params['recovery_rate_with_inpatient_care'] = 0.0 - - # increase parameters in moderate wasting for clinical SAM - # (MUAC and oedema) to be polled for death - params['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = [ - 5 * params['proportion_-3<=WHZ<-2_with_MUAC<115mm']] - params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] = [ - params['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] / 5] - params['proportion_oedema_with_WHZ<-2'] = 0.9 - - # re-initialise wasting models - sim.modules['Wasting'].pre_initialise_population() + wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() + wmodule.wasting_models.severe_wasting_progression_lm = LinearModel.multiplicative() + wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) + wmodule.parameters['prob_mam_after_care'] = 0.0 + wmodule.parameters['prob_death_after_care'] = 1.0 + + # increase parameters in moderate wasting for clinical SAM (MUAC and oedema) to be polled for death + wmodule.parameters['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = \ + [5 * wmodule.parameters['proportion_-3<=WHZ<-2_with_MUAC<115mm']] + wmodule.parameters['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] = \ + [wmodule.parameters['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] / 5] + wmodule.parameters['proportion_oedema_with_WHZ<-2'] = 0.9 # Get person to use: df = sim.population.props @@ -815,8 +732,7 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): polling = WastingPollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) - # Check properties of this individual: (should now be moderately wasted - # with a scheduled progression to severe date) + # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) person = df.loc[person_id] assert person['un_ever_wasted'] assert person['un_WHZ_category'] == '-3<=WHZ<-2' @@ -825,11 +741,9 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Check that there is a ProgressionSevereWastingEvent scheduled for this - # person: - progression_event_tuple = \ - [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], ProgressionSevereWastingEvent)][0] + # Check that there is a ProgressionSevereWastingEvent scheduled for this person: + progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], ProgressionSevereWastingEvent)][0] date_of_scheduled_progression = progression_event_tuple[0] progression_event = progression_event_tuple[1] assert date_of_scheduled_progression > sim.date @@ -838,8 +752,7 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): sim.date = date_of_scheduled_progression progression_event.apply(person_id=person_id) - # Check properties of this individual: (should now be severely wasted and - # without a scheduled death date) + # Check properties of this individual: (should now be severely wasted and without a scheduled death date) person = df.loc[person_id] assert person['un_ever_wasted'] assert person['un_WHZ_category'] == 'WHZ<-3' @@ -853,48 +766,35 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): hsp.run() # check non-emergency care event is scheduled - assert isinstance( - sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - - # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and - # check care was sought - ge = [ev[1] for ev in - sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - ][0] + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + + # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought + ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) # check inpatient care event is scheduled - assert isinstance( - sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - HSI_Wasting_OutpatientTherapeuticProgramme_SAM) - - # Run the created instance of - # HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought - sam_ev = [ev[1] for ev in - sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], - HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + + # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] sam_ev.run(squeeze_factor=0.0) # since there is zero recovery rate, check death event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[1][1], - SevereAcuteMalnutritionDeathEvent) + assert isinstance(sim.find_events_for_person(person_id)[1][1], SevereAcuteMalnutritionDeathEvent) # Run Severe Acute Malnutrition Death Event scheduled for this person: - death_event_tuple = \ - [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent)][0] + death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent)][0] date_of_scheduled_death = death_event_tuple[0] death_event = death_event_tuple[1] assert date_of_scheduled_death > sim.date # Run a Cure Event now - cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, - module=sim.modules[ - 'Wasting']) + cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) cure_event.apply(person_id=person_id) # Check that the person is not wasted and is alive still: @@ -904,8 +804,7 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): assert not pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Run the death event that was originally scheduled - this should have no - # effect and the person should not die + # Run the death event that was originally scheduled - this should have no effect and the person should not die sim.date = date_of_scheduled_death death_event.apply(person_id=person_id) person = df.loc[person_id] From e1ab6f1dbc0572813a0208078b40a0e9ec2b7c2b Mon Sep 17 00:00:00 2001 From: mnjowe Date: Mon, 5 Feb 2024 20:42:47 +0200 Subject: [PATCH 036/755] addressing failing tests --- src/tlo/methods/wasting.py | 4 ++-- tests/test_wasting.py | 40 +++++++++++++++++++------------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 745d7042d6..60a19e73e9 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -46,13 +46,13 @@ class Wasting(Module): # Declare Causes of Death CAUSES_OF_DEATH = { 'Severe Acute Malnutrition': Cause(gbd_causes='Protein-energy malnutrition', - label='Childhood Wasting') + label='Childhood Undernutrition') } # Declare Causes of Death and Disability CAUSES_OF_DISABILITY = { 'Severe Acute Malnutrition': Cause(gbd_causes='Protein-energy malnutrition', - label='Childhood Wasting') + label='Childhood Undernutrition') } PARAMETERS = { diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 10758809b4..3ff5579a5d 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -31,7 +31,7 @@ ProgressionSevereWastingEvent, SevereAcuteMalnutritionDeathEvent, WastingNaturalRecoveryEvent, - WastingPollingEvent, + WastingPollingEvent, UpdateToMAM, ) # Path to the resource files used by the disease and intervention methods @@ -196,7 +196,6 @@ def test_wasting_incidence(tmpdir): df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] - person = df.loc[person_id] assert all(under5s['un_ever_wasted']) assert all(under5s['un_WHZ_category'] == '-3<=WHZ<-2') assert all(under5s['un_last_wasting_date_of_onset'] == sim.date) @@ -242,7 +241,7 @@ def test_report_daly_weights(tmpdir): # Verify diagnosis assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'MAM' - assert df.loc[person_id, 'un_am_bilateral_oedema'] == True + assert df.loc[person_id, 'un_am_bilateral_oedema'] # Report daly weight for this individual daly_weights_reported = sim.modules["Wasting"].report_daly_values() @@ -344,7 +343,7 @@ def test_recovery_moderate_wasting(tmpdir): def test_recovery_severe_wasting_without_complications(tmpdir): - """ Check natural recovery to MAM by removing death rate for those with severe wasting, and check the onset of + """ Check recovery to MAM by removing death rate for those with severe wasting, and check the onset of symptoms with SAM and revolving of symptoms when recovered to MAM """ dur = pd.DateOffset(days=0) popsize = 1000 @@ -372,18 +371,20 @@ def test_recovery_severe_wasting_without_complications(tmpdir): # set progress to severe wasting at 100% as well wmodule.wasting_models.severe_wasting_progression_lm = LinearModel.multiplicative() + # set complete recovery from wasting to zero. We want those with SAM to recover to MAM + wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) + + # Set death rate at 0% and recovery to MAM at 100% + wmodule.parameters['prob_death_after_care'] = 0.0 + wmodule.parameters['prob_mam_after_care'] = 1.0 + # Run Wasting Polling event to get new incident cases: polling = WastingPollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) # Check properties of this individual: should now be moderately wasted person = df.loc[person_id] - assert person['un_ever_wasted'] assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) # Check that there is a ProgressionSevereWastingEvent scheduled for this person: progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) @@ -396,16 +397,14 @@ def test_recovery_severe_wasting_without_complications(tmpdir): sim.date = date_of_scheduled_progression progression_event.apply(person_id=person_id) - # Check individuals have symptoms caused by Wasting (SAM only) - assert 0 < len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) + # Check this individual has symptom(weight loss) caused by Wasting (SAM only) + assert 'weight_loss' in sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting']) - # Check properties of this individual: (should now be severely wasted and without a scheduled death date) + # Check properties of this individual: (should now be severely wasted, diagnosed as SAM and without a scheduled + # death date) person = df.loc[person_id] - assert person['un_ever_wasted'] assert person['un_WHZ_category'] == 'WHZ<-3' assert person['un_clinical_acute_malnutrition'] == 'SAM' - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) @@ -430,11 +429,11 @@ def test_recovery_severe_wasting_without_complications(tmpdir): sam_ev.run(squeeze_factor=0.0) # check recovery event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[1][1], ClinicalAcuteMalnutritionRecoveryEvent) + assert isinstance(sim.find_events_for_person(person_id)[1][1], UpdateToMAM) # Run the recovery event and check the individual has recovered from SAM: sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] + isinstance(event_tuple[1], UpdateToMAM)][0] date_of_scheduled_recovery_to_mam = sam_recovery_event_tuple[0] sam_recovery_event = sam_recovery_event_tuple[1] @@ -446,8 +445,7 @@ def test_recovery_severe_wasting_without_complications(tmpdir): # Check properties of this individual person = df.loc[person_id] - assert person['un_WHZ_category'] == 'WHZ>=-2' - assert (person['un_am_MUAC_category'] == '>=125mm') + assert person['un_clinical_acute_malnutrition'] == 'MAM' assert pd.isnull(person['un_sam_death_date']) # check they have no symptoms: @@ -535,7 +533,7 @@ def test_recovery_severe_wasting_with_complications(tmpdir): sim.date = date_of_scheduled_recovery_to_mam sam_recovery_event.apply(person_id=person_id) - # Check properties of this individual + # Check properties of this individual. Should now be well person = df.loc[person_id] assert person['un_WHZ_category'] == 'WHZ>=-2' assert (person['un_am_MUAC_category'] == '>=125mm') @@ -726,6 +724,8 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] + # Let this person have severe wasting + df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' # Run Wasting Polling event to get new incident cases: From e4b2df8fdbecc29e3a9332e2edd7a4649f82a89e Mon Sep 17 00:00:00 2001 From: mnjowe Date: Mon, 5 Feb 2024 21:07:44 +0200 Subject: [PATCH 037/755] resolving checks error --- tests/test_wasting.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 3ff5579a5d..9abbeb8d5e 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -195,7 +195,6 @@ def test_wasting_incidence(tmpdir): # Check properties of individuals: should now be moderately wasted df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] assert all(under5s['un_ever_wasted']) assert all(under5s['un_WHZ_category'] == '-3<=WHZ<-2') assert all(under5s['un_last_wasting_date_of_onset'] == sim.date) From 8f22e8e61f2c536ca0b1de598bf69e066550c141 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Mon, 5 Feb 2024 21:39:47 +0200 Subject: [PATCH 038/755] isort error --- tests/test_wasting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 9abbeb8d5e..f253fad361 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -30,8 +30,9 @@ HSI_Wasting_OutpatientTherapeuticProgramme_SAM, ProgressionSevereWastingEvent, SevereAcuteMalnutritionDeathEvent, + UpdateToMAM, WastingNaturalRecoveryEvent, - WastingPollingEvent, UpdateToMAM, + WastingPollingEvent, ) # Path to the resource files used by the disease and intervention methods From 6c5d875b63797b43a7938a37aeee56df61b1d5b1 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Tue, 6 Feb 2024 09:44:59 +0200 Subject: [PATCH 039/755] small fixes in wasting analyses, test and main module --- .../wasting_analyses/analysis_wasting.py | 6 ++--- src/tlo/methods/wasting.py | 25 ++++++++----------- tests/test_wasting.py | 9 +------ 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index b5d5206327..464417522b 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -88,7 +88,6 @@ def plot_wasting_incidence(self): _col_counter = -1 _col_counter += 1 # increment column counter fig.tight_layout() - # plt.show() def plot_wasting_prevalence(self): w_prev_df = self.__logs_dict['wasting_prevalence_count'] @@ -100,7 +99,6 @@ def plot_wasting_prevalence(self): ylabel='proportions', xlabel='year' ) - # plt.show() def plot_modal_gbd_deaths_by_gender(self): """ compare modal and GBD deaths by gender """ @@ -109,7 +107,7 @@ def plot_modal_gbd_deaths_by_gender(self): fig, axs = plt.subplots(nrows=1, ncols=2, sharey=True, sharex=True) for _col, sex in enumerate(('M', 'F')): plot_df = death_compare.loc[(['2010-2014', '2015-2019'], - sex, slice(None), 'Childhood Wasting' + sex, slice(None), 'Childhood Undernutrition' )].groupby('period').sum() plotting = plot_df.loc[['2010-2014', '2015-2019']] ax = plotting['model'].plot.bar(label='Model', ax=axs[_col], rot=0) @@ -126,7 +124,7 @@ def plot_modal_gbd_deaths_by_gender(self): outputs / ('modal_gbd_deaths_by_gender' + datestamp + ".pdf"), format="pdf" ) - # plt.show() + if __name__ == "__main__": seed = 1 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 60a19e73e9..236608927b 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1138,7 +1138,6 @@ def __init__(self, module): Predictor('un_am_treatment_type', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) .when('soy_RUSF', self.params['recovery_rate_with_soy_RUSF']) .when('CSB++', self.params['recovery_rate_with_CSB++']) - .otherwise(0.0), ) # a linear model to predict the probability of individual's recovery from severe acute malnutrition @@ -1146,20 +1145,18 @@ def __init__(self, module): Predictor('un_am_treatment_type', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) .when('standard_RUTF', self.params['recovery_rate_with_standard_RUTF']) .when('inpatient_care', self.params['recovery_rate_with_inpatient_care']) - .otherwise(0.0), ) # Linear model for the probability of progression to severe wasting (age-dependent only) # (natural history only, no interventions) self.severe_wasting_progression_lm = LinearModel.multiplicative( - Predictor('age_exact_years', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) + Predictor('age_exact_years', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=False) .when('<0.5', self.params['progression_severe_wasting_by_agegp'][0]) .when('.between(0.5,1, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][1]) .when('.between(1,2, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][2]) .when('.between(2,3, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][3]) .when('.between(3,4, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][4]) .when('.between(4,5, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][5]) - .otherwise(0.0), ) # get wasting incidence linear model @@ -1175,13 +1172,13 @@ def unscaled_wasting_lm(intercept: Union[float, int] = 1.0) -> LinearModel: return LinearModel( LinearModelType.MULTIPLICATIVE, intercept, - Predictor('age_exact_years').when('<0.5', self.params['base_inc_rate_wasting_by_agegp'][0]) - .when('<1.0', self.params['base_inc_rate_wasting_by_agegp'][1]) - .when('.between(1,1.9999)', self.params['base_inc_rate_wasting_by_agegp'][2]) - .when('.between(2,2.9999)', self.params['base_inc_rate_wasting_by_agegp'][3]) - .when('.between(3,3.9999)', self.params['base_inc_rate_wasting_by_agegp'][4]) - .when('.between(4,4.9999)', self.params['base_inc_rate_wasting_by_agegp'][5]) - .otherwise(0.0), + Predictor('age_exact_years', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=False) + .when('<0.5', self.params['base_inc_rate_wasting_by_agegp'][0]) + .when('.between(0.5,1, inclusive=left)', self.params['base_inc_rate_wasting_by_agegp'][1]) + .when('.between(1,2, inclusive=left)', self.params['base_inc_rate_wasting_by_agegp'][2]) + .when('.between(2,3, inclusive=left)', self.params['base_inc_rate_wasting_by_agegp'][3]) + .when('.between(3,4, inclusive=left)', self.params['base_inc_rate_wasting_by_agegp'][4]) + .when('.between(4,5, inclusive=left)', self.params['base_inc_rate_wasting_by_agegp'][5]), Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' '& (nb_late_preterm == False) & (nb_early_preterm == False)', self.params['rr_wasting_SGA_and_term']), @@ -1216,11 +1213,11 @@ def make_linear_model_wasting(intercept: Union[float, int]) -> LinearModel: return LinearModel( LinearModelType.LOGISTIC, intercept, # baseline odds: get_odds_wasting(agegp=agegp) - Predictor('li_wealth').when(2, self.params['or_wasting_hhwealth_Q2']) + Predictor('li_wealth', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=False) + .when(2, self.params['or_wasting_hhwealth_Q2']) .when(3, self.params['or_wasting_hhwealth_Q3']) .when(4, self.params['or_wasting_hhwealth_Q4']) - .when(5, self.params['or_wasting_hhwealth_Q5']) - .otherwise(1.0), + .when(5, self.params['or_wasting_hhwealth_Q5']), Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' '& (nb_late_preterm == False) & (nb_early_preterm == False)', self.params['or_wasting_SGA_and_term']), diff --git a/tests/test_wasting.py b/tests/test_wasting.py index f253fad361..ce3e7f7cd9 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -74,7 +74,7 @@ def get_sim(tmpdir): @pytest.mark.slow def test_basic_run(tmpdir): - """Short run of the module using default parameters with check on dtypes""" + """Run the simulation and do some daily checks on dtypes and properties integrity """ class DummyModule(Module): """ A Dummy module that ensure wasting properties are as expected on a daily basis """ METADATA = {Metadata.DISEASE_MODULE} @@ -713,13 +713,6 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): wmodule.parameters['prob_mam_after_care'] = 0.0 wmodule.parameters['prob_death_after_care'] = 1.0 - # increase parameters in moderate wasting for clinical SAM (MUAC and oedema) to be polled for death - wmodule.parameters['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = \ - [5 * wmodule.parameters['proportion_-3<=WHZ<-2_with_MUAC<115mm']] - wmodule.parameters['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] = \ - [wmodule.parameters['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] / 5] - wmodule.parameters['proportion_oedema_with_WHZ<-2'] = 0.9 - # Get person to use: df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] From a038a8a975e9c3460638aad3f30c0665cca54313 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Tue, 6 Feb 2024 10:06:45 +0200 Subject: [PATCH 040/755] use "left" not left when assigning inclusive value in linear models --- src/tlo/methods/wasting.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 236608927b..cce7760f75 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1174,11 +1174,11 @@ def unscaled_wasting_lm(intercept: Union[float, int] = 1.0) -> LinearModel: intercept, Predictor('age_exact_years', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=False) .when('<0.5', self.params['base_inc_rate_wasting_by_agegp'][0]) - .when('.between(0.5,1, inclusive=left)', self.params['base_inc_rate_wasting_by_agegp'][1]) - .when('.between(1,2, inclusive=left)', self.params['base_inc_rate_wasting_by_agegp'][2]) - .when('.between(2,3, inclusive=left)', self.params['base_inc_rate_wasting_by_agegp'][3]) - .when('.between(3,4, inclusive=left)', self.params['base_inc_rate_wasting_by_agegp'][4]) - .when('.between(4,5, inclusive=left)', self.params['base_inc_rate_wasting_by_agegp'][5]), + .when('.between(0.5,1, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][1]) + .when('.between(1,2, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][2]) + .when('.between(2,3, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][3]) + .when('.between(3,4, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][4]) + .when('.between(4,5, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][5]), Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' '& (nb_late_preterm == False) & (nb_early_preterm == False)', self.params['rr_wasting_SGA_and_term']), From b6b7306a90ae20402aded799e8fe6d15115eac3d Mon Sep 17 00:00:00 2001 From: mnjowe Date: Tue, 6 Feb 2024 10:39:15 +0200 Subject: [PATCH 041/755] remove misleading comment --- tests/test_wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index ce3e7f7cd9..6a37a184fd 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -779,7 +779,7 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): # since there is zero recovery rate, check death event is scheduled assert isinstance(sim.find_events_for_person(person_id)[1][1], SevereAcuteMalnutritionDeathEvent) - # Run Severe Acute Malnutrition Death Event scheduled for this person: + # Check a date of death is scheduled. it should be any date in the future: death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent)][0] date_of_scheduled_death = death_event_tuple[0] From 83d3ec49f4657774dc668adb8f048a788d4bf7f4 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Tue, 13 Feb 2024 11:01:47 +0200 Subject: [PATCH 042/755] addressing eva's comments and suggestions --- src/tlo/methods/wasting.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index cce7760f75..851d009441 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -178,13 +178,12 @@ class Wasting(Module): 'none', 'not_applicable']), } - wasting_states = ['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2'] - def __init__(self, name=None, resourcefilepath=None): super().__init__(name) self.wasting_models = None self.resourcefilepath = resourcefilepath - + # wasting states + self.wasting_states = self.PROPERTIES["un_WHZ_category"].categories # wasting symptom self.wasting_symptom = 'weight_loss' @@ -237,11 +236,11 @@ def initialise_population(self, population): self.wasting_models = WastingModels(self) # Assign wasting categories in young children at initiation - for low_bound_mnts, high_bound_mnths in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months - low_bound_age_in_years = low_bound_mnts / 12.0 - high_bound_age_in_years = (1 + high_bound_mnths) / 12.0 + for low_bound_mos, high_bound_mos in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months + low_bound_age_in_years = low_bound_mos / 12.0 + high_bound_age_in_years = (1 + high_bound_mos) / 12.0 # linear model external variables - agegp = f'{low_bound_mnts}_{high_bound_mnths}mo' + agegp = f'{low_bound_mos}_{high_bound_mos}mo' mask = (df.is_alive & df.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, inclusive='left')) prevalence_of_wasting = self.wasting_models.get_wasting_prevalence(agegp=agegp).predict(df.loc[mask]) @@ -249,7 +248,7 @@ def initialise_population(self, population): # categorize into moderate (-3<=WHZ<-2) or severe (WHZ<-3) wasting wasted = self.rng.random_sample(len(prevalence_of_wasting)) < prevalence_of_wasting for idx in prevalence_of_wasting.index[wasted]: - probability_of_severe = self.get_odds_probs_wasting(agegp=agegp) + probability_of_severe = self.get_probs_or_odds_wasting(agegp=agegp) wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], p=[probability_of_severe, 1 - probability_of_severe]) df.at[idx, 'un_WHZ_category'] = wasted_category @@ -300,12 +299,13 @@ def on_birth(self, mother_id, child_id): df.at[child_id, 'un_am_MUAC_category'] = '>=125mm' df.at[child_id, 'un_am_treatment_type'] = 'not_applicable' - def get_odds_probs_wasting(self, agegp: str, lm_scaling: bool = False) -> Union[float, int]: + def get_probs_or_odds_wasting(self, agegp: str, get_odds: bool = False) -> Union[float, int]: """ This function will calculate the WHZ scores by categories and return probability or odds of severe wasting for those with wasting status :param agegp: age grouped in months - :param lm_scaling: whether this function is used for scaling wasting prevalence linear model or not + :param get_odds: when set to True, this argument will cause this method return the odds of severe wasting to be + used for scaling wasting prevalence linear model :return: """ # generate random numbers from N(meean, sd) @@ -315,7 +315,7 @@ def get_odds_probs_wasting(self, agegp: str, lm_scaling: bool = False) -> Union[ # get all wasting: WHZ <-2 probability_less_than_minus2sd = 1 - whz_normal_distribution.sf(-2) - if lm_scaling: + if get_odds: # convert probability to odds and return the odds return probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) @@ -1229,9 +1229,9 @@ def make_linear_model_wasting(intercept: Union[float, int]) -> LinearModel: self.params['or_wasting_preterm_and_AGA']) ) - get_odds_wasting = self.module.get_odds_probs_wasting(agegp=agegp, lm_scaling=True) + get_odds_wasting = self.module.get_probs_or_odds_wasting(agegp=agegp, get_odds=True) unscaled_lm = make_linear_model_wasting(intercept=get_odds_wasting) - target_mean = self.module.get_odds_probs_wasting(agegp='12_23mo', lm_scaling=True) + target_mean = self.module.get_probs_or_odds_wasting(agegp='12_23mo', get_odds=True) actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1)]).mean() scaled_intercept = get_odds_wasting * (target_mean / actual_mean) if \ (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else get_odds_wasting From bcb9bec6a2ecd8150726e010e9cff1b22f2a31c5 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Thu, 15 Feb 2024 15:37:29 +0200 Subject: [PATCH 043/755] resolving conflicts --- .../ResourceFile_PriorityRanking_ALLPOLICIES.xlsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx index 8f8d529023..6bf85df2db 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:f6590c15e8f0650b9c8d8bd43b05c0e73bfbd7b8598e070a907e194ed590dcf4 -size 41403 +oid sha256:20fb355b93941651d041f8b109f5f0f1d188653cad73192a0d36e1eae8533e8c +size 41564 From f522fed93635f6886a2af4ddf52b3424fc11e2cc Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 11 Feb 2024 22:13:57 +0000 Subject: [PATCH 044/755] RF_Wasting: CSV instead of XLSX --- resources/ResourceFile_Wasting.csv | 3 +++ resources/ResourceFile_Wasting.xlsx | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 resources/ResourceFile_Wasting.csv delete mode 100644 resources/ResourceFile_Wasting.xlsx diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv new file mode 100644 index 0000000000..57c37aa84e --- /dev/null +++ b/resources/ResourceFile_Wasting.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:99d94106317fbec0bee8231a9190acce5e4e586b36b9ced9b0053fe52b94bfd1 +size 2480 diff --git a/resources/ResourceFile_Wasting.xlsx b/resources/ResourceFile_Wasting.xlsx deleted file mode 100644 index 60acc22d60..0000000000 --- a/resources/ResourceFile_Wasting.xlsx +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b79a5d92163f8b69a1125003b4154f892e924011a0f1ae359a5b3c632f836179 -size 12146 From a6281a54e4e7a863f6155f401c9487d4375d6392 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 11 Feb 2024 22:18:15 +0000 Subject: [PATCH 045/755] RF_Wasting: comments added --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 57c37aa84e..647472b8f8 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:99d94106317fbec0bee8231a9190acce5e4e586b36b9ced9b0053fe52b94bfd1 -size 2480 +oid sha256:3439870b193b766bdf7abfe7efb36e4fb029923d78864f8ea33c2b1696fde52a +size 2458 From a348b883382dab9c8633e0019d18f89b4afe2fd3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 11 Feb 2024 22:39:34 +0000 Subject: [PATCH 046/755] wast: parameters re-ordered, comments adjusted --- src/tlo/methods/wasting.py | 41 +++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 851d009441..a7f08633c3 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -84,7 +84,7 @@ class Wasting(Module): Types.REAL, 'odds ratio of wasting if born term and small for gestational age'), 'or_wasting_SGA_and_preterm': Parameter( Types.REAL, 'odds ratio of wasting if born preterm and small for gestational age'), - # incidence parameters + # incidence 'base_inc_rate_wasting_by_agegp': Parameter( Types.LIST, 'List with baseline incidence of wasting by age group'), 'rr_wasting_preterm_and_AGA': Parameter( @@ -97,24 +97,15 @@ class Wasting(Module): Types.REAL, 'relative risk of wasting per 1 unit decrease in wealth level'), 'min_days_duration_of_wasting': Parameter( Types.REAL, 'minimum duration in days of wasting (MAM and SAM)'), + # progression 'average_duration_of_untreated_MAM': Parameter( Types.REAL, 'average duration of untreated MAM'), - # progression to severe parameters - 'progression_severe_wasting_by_agegp': Parameter( - Types.LIST, 'List with progression rates to severe wasting by age group'), 'average_duration_of_untreated_SAM': Parameter( Types.REAL, 'average duration of untreated SAM'), + 'progression_severe_wasting_by_agegp': Parameter( + Types.LIST, 'List with progression rates to severe wasting by age group'), 'prob_complications_in_SAM': Parameter( Types.REAL, 'probability of medical complications in SAM '), - # recovery parameters - 'recovery_rate_with_standard_RUTF': Parameter( - Types.REAL, 'probability of recovery from wasting following treatment with standard RUTF'), - 'recovery_rate_with_soy_RUSF': Parameter( - Types.REAL, 'probability of recovery from wasting following treatment with soy RUSF'), - 'recovery_rate_with_CSB++': Parameter( - Types.REAL, 'probability of recovery from wasting following treatment with CSB++'), - 'recovery_rate_with_inpatient_care': Parameter( - Types.REAL, 'probability of recovery from wasting following treatment with inpatient care'), # MUAC distributions 'MUAC_distribution_WHZ<-3': Parameter( Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ<-3'), @@ -123,26 +114,25 @@ class Wasting(Module): 'MUAC_distribution_WHZ>=-2': Parameter( Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ>=-2'), 'proportion_WHZ<-3_with_MUAC<115mm': Parameter( - Types.REAL, 'proportion of severe weight-for-height Z-score with MUAC<115mm'), + Types.REAL, 'proportion of severe wasting with MUAC<115mm'), 'proportion_-3<=WHZ<-2_with_MUAC<115mm': Parameter( - Types.REAL, 'proportion of moderate weight-for-height Z-score with MUAC<115mm'), + Types.REAL, 'proportion of moderate wasting with MUAC<115mm'), 'proportion_-3<=WHZ<-2_with_MUAC_115-<125mm': Parameter( - Types.REAL, 'proportion of moderate weight-for-height Z-score with MUAC between 115mm and 125mm'), + Types.REAL, 'proportion of moderate wasting with 115mm≤MUAC<125mm'), 'proportion_mam_with_MUAC_115-<125mm_and_normal_whz': Parameter( - Types.REAL, 'proportion of mam cases with MUAC between 115mm and 125mm and normal/mild WHZ'), + Types.REAL, 'proportion of MAM cases with 115mm≤MUAC<125mm and normal/mild WHZ'), 'proportion_mam_with_MUAC_115-<125mm_and_-3<=WHZ<-2': Parameter( Types.REAL, - 'proportion of mam cases with both MUAC between 115mm and ' - '125mm and moderate wasting'), + 'proportion of MAM cases with both 115mm≤MUAC<125mm and moderate wasting'), 'proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC': Parameter( Types.REAL, - 'proportion of mam cases with moderate wasting and normal MUAC'), + 'proportion of MAM cases with moderate wasting and normal MUAC'), # bilateral oedema 'prevalence_nutritional_oedema': Parameter( Types.REAL, 'prevalence of nutritional oedema in children under 5 in Malawi'), 'proportion_oedema_with_WHZ<-2': Parameter( Types.REAL, 'proportion of oedematous malnutrition with concurrent wasting'), - # treatment parameters + # treatment 'coverage_supplementary_feeding_program': Parameter( Types.REAL, 'coverage of supplementary feeding program for MAM in health centres'), 'coverage_outpatient_therapeutic_care': Parameter( @@ -153,6 +143,15 @@ class Wasting(Module): Types.REAL, 'probability of returning to MAM after seeking care'), 'prob_death_after_care': Parameter( Types.REAL, 'probability of dying after seeking care'), + # recovery + 'recovery_rate_with_standard_RUTF': Parameter( + Types.REAL, 'probability of recovery from wasting following treatment with standard RUTF'), + 'recovery_rate_with_soy_RUSF': Parameter( + Types.REAL, 'probability of recovery from wasting following treatment with soy RUSF'), + 'recovery_rate_with_CSB++': Parameter( + Types.REAL, 'probability of recovery from wasting following treatment with CSB++'), + 'recovery_rate_with_inpatient_care': Parameter( + Types.REAL, 'probability of recovery from wasting following treatment with inpatient care'), } PROPERTIES = { From 2776254f6dc4a23fb84c3256f664c9bee68bced8 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 11 Feb 2024 22:41:04 +0000 Subject: [PATCH 047/755] wast & test_wast: property renamed un_acute_malnutrition_tx_start_date -> un_am_tx_start_date --- src/tlo/methods/wasting.py | 34 +++++++++++++++++----------------- tests/test_wasting.py | 8 ++++---- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index a7f08633c3..8664c7e78c 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -171,7 +171,7 @@ class Wasting(Module): 'un_sam_death_date': Property(Types.DATE, 'death date from severe acute malnutrition'), 'un_am_recovery_date': Property(Types.DATE, 'recovery date from acute malnutrition'), 'un_am_discharge_date': Property(Types.DATE, 'discharge date from treatment of MAM/ SAM'), - 'un_acute_malnutrition_tx_start_date': Property(Types.DATE, 'intervention start date'), + 'un_am_tx_start_date': Property(Types.DATE, 'intervention start date'), 'un_am_treatment_type': Property(Types.CATEGORICAL, 'treatment types for acute malnutrition', categories=['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care'] + [ 'none', 'not_applicable']), @@ -225,7 +225,7 @@ def initialise_population(self, population): df.loc[df.is_alive, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' df.loc[df.is_alive, 'un_last_wasting_date_of_onset'] = pd.NaT - df.loc[df.is_alive, 'un_acute_malnutrition_tx_start_date'] = pd.NaT + df.loc[df.is_alive, 'un_am_tx_start_date'] = pd.NaT df.loc[df.is_alive, 'un_sam_death_date'] = pd.NaT df.loc[df.is_alive, 'un_am_bilateral_oedema'] = False df.loc[df.is_alive, 'un_am_MUAC_category'] = '>=125mm' @@ -292,7 +292,7 @@ def on_birth(self, mother_id, child_id): df.at[child_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished df.at[child_id, 'un_clinical_acute_malnutrition'] = 'well' df.at[child_id, 'un_last_wasting_date_of_onset'] = pd.NaT - df.at[child_id, 'un_acute_malnutrition_tx_start_date'] = pd.NaT + df.at[child_id, 'un_am_tx_start_date'] = pd.NaT df.at[child_id, 'un_sam_death_date'] = pd.NaT df.at[child_id, 'un_am_bilateral_oedema'] = False df.at[child_id, 'un_am_MUAC_category'] = '>=125mm' @@ -600,7 +600,7 @@ def do_when_am_treatment(self, person_id, intervention): """ df = self.sim.population.props # Log that the treatment is provided: - df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date + df.at[person_id, 'un_am_tx_start_date'] = self.sim.date if intervention == 'SFP': mam_recovery = self.wasting_models.acute_malnutrition_recovery_mam_lm.predict( @@ -610,7 +610,7 @@ def do_when_am_treatment(self, person_id, intervention): # schedule recovery date self.sim.schedule_event(event=ClinicalAcuteMalnutritionRecoveryEvent( module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) + date=df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=3)) # cancel progression date (in ProgressionEvent) else: # remained MAM @@ -623,7 +623,7 @@ def do_when_am_treatment(self, person_id, intervention): # schedule recovery date self.sim.schedule_event(event=ClinicalAcuteMalnutritionRecoveryEvent( module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) + date=df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=3)) # cancel death date df.at[person_id, 'un_sam_death_date'] = pd.NaT else: @@ -632,11 +632,11 @@ def do_when_am_treatment(self, person_id, intervention): if outcome == 'death': self.sim.schedule_event(event=SevereAcuteMalnutritionDeathEvent( module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=3)) + date=df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=3)) else: self.sim.schedule_event(event=UpdateToMAM(module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + + date=df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=3)) if intervention == 'ITC': @@ -646,7 +646,7 @@ def do_when_am_treatment(self, person_id, intervention): # schedule recovery date self.sim.schedule_event(event=ClinicalAcuteMalnutritionRecoveryEvent( module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=4)) + date=df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=4)) # cancel death date df.at[person_id, 'un_sam_death_date'] = pd.NaT else: @@ -656,11 +656,11 @@ def do_when_am_treatment(self, person_id, intervention): if outcome == 'death': self.sim.schedule_event(event=SevereAcuteMalnutritionDeathEvent( module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=4)) + date=df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=4)) else: self.sim.schedule_event( event=UpdateToMAM(module=self, person_id=person_id), - date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + DateOffset(weeks=4)) + date=df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=4)) class WastingPollingEvent(RegularEvent, PopulationScopeEventMixin): @@ -786,7 +786,7 @@ def apply(self, person_id): # before progression to severe wasting, check those who started # supplementary feeding programme before today if df.at[person_id, 'un_last_wasting_date_of_onset'] < \ - df.at[person_id, 'un_acute_malnutrition_tx_start_date'] < self.sim.date: + df.at[person_id, 'un_am_tx_start_date'] < self.sim.date: return # continue with progression to severe if not treated/recovered @@ -895,7 +895,7 @@ def apply(self, person_id): df.at[person_id, 'un_am_bilateral_oedema'] = False df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' df.at[person_id, 'un_sam_with_complications'] = False - df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = pd.NaT + df.at[person_id, 'un_am_tx_start_date'] = pd.NaT df.at[person_id, 'un_am_treatment_type'] = 'not_applicable' # this will clear all wasting symptoms @@ -952,7 +952,7 @@ def apply(self, person_id): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' df.at[person_id, 'un_am_bilateral_oedema'] = False df.at[person_id, 'un_sam_with_complications'] = False - df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = pd.NaT + df.at[person_id, 'un_am_tx_start_date'] = pd.NaT df.at[person_id, 'un_am_recovery_date'] = pd.NaT df.at[person_id, 'un_am_discharge_date'] = pd.NaT # will start the process again @@ -1005,7 +1005,7 @@ def apply(self, person_id, squeeze_factor): if self.get_consumables([item_code1]): logger.debug(key='debug', data='consumables are available') # Log that the treatment is provided: - df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date + df.at[person_id, 'un_am_tx_start_date'] = self.sim.date df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=3) df.at[person_id, 'un_am_treatment_type'] = 'CSB++' self.module.do_when_am_treatment(person_id, intervention='SFP') @@ -1061,7 +1061,7 @@ def apply(self, person_id, squeeze_factor): if self.get_consumables(item_code1) and self.get_consumables(item_code2): logger.debug(key='debug', data='consumables are available.') # Log that the treatment is provided: - df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date + df.at[person_id, 'un_am_tx_start_date'] = self.sim.date df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=3) df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' self.module.do_when_am_treatment(person_id, intervention='OTC') @@ -1112,7 +1112,7 @@ def apply(self, person_id, squeeze_factor): if self.get_consumables(item_code1) and self.get_consumables(item_code2): logger.debug(key='debug', data='consumables available, so use it.') # Log that the treatment is provided: - df.at[person_id, 'un_acute_malnutrition_tx_start_date'] = self.sim.date + df.at[person_id, 'un_am_tx_start_date'] = self.sim.date df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=4) df.at[person_id, 'un_am_treatment_type'] = 'inpatient_care' self.module.do_when_am_treatment(person_id, intervention='ITC') diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 6a37a184fd..f6e960bbb0 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -319,7 +319,7 @@ def test_recovery_moderate_wasting(tmpdir): assert person['un_ever_wasted'] assert person['un_WHZ_category'] == '-3<=WHZ<-2' assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_tx_start_date']) assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) @@ -659,7 +659,7 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): assert person['un_ever_wasted'] assert person['un_WHZ_category'] == '-3<=WHZ<-2' assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_tx_start_date']) assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) @@ -730,7 +730,7 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): assert person['un_ever_wasted'] assert person['un_WHZ_category'] == '-3<=WHZ<-2' assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_tx_start_date']) assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) @@ -750,7 +750,7 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): assert person['un_ever_wasted'] assert person['un_WHZ_category'] == 'WHZ<-3' assert person['un_clinical_acute_malnutrition'] == 'SAM' - assert pd.isnull(person['un_acute_malnutrition_tx_start_date']) + assert pd.isnull(person['un_am_tx_start_date']) assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) From be848bb39c99daee4677c595e4922f9c8a6735b4 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 12 Feb 2024 17:10:20 +0000 Subject: [PATCH 048/755] wast: read parameters from CSV --- src/tlo/methods/wasting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 8664c7e78c..676cfaa9d6 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -204,7 +204,8 @@ def read_parameters(self, data_folder): # Update parameters from the resource dataframe # Read parameters from the resource file self.load_parameters_from_dataframe( - pd.read_excel(Path(self.resourcefilepath) / 'ResourceFile_Wasting.xlsx', sheet_name='Parameter_values_AM')) + pd.read_csv(Path(self.resourcefilepath) / 'ResourceFile_Wasting.csv') + ) # Register wasting symptom(weight loss) in Symptoms Manager self.sim.modules['SymptomManager'].register_symptom(Symptom(name=self.wasting_symptom)) From 2c67007e89e48a8c8510e5778c9ea9eb5dba6860 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 12 Feb 2024 17:12:17 +0000 Subject: [PATCH 049/755] wast: properties descriptions adjusted --- src/tlo/methods/wasting.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 676cfaa9d6..f901c066de 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -156,21 +156,23 @@ class Wasting(Module): PROPERTIES = { # Properties related to wasting - 'un_ever_wasted': Property(Types.BOOL, 'had wasting before WHZ <-2'), - 'un_WHZ_category': Property(Types.CATEGORICAL, 'weight-for-height z-score group', + 'un_ever_wasted': Property(Types.BOOL, 'ever had an episode of wasting (WHZ<-2)'), + 'un_WHZ_category': Property(Types.CATEGORICAL, 'weight-for-height z-score category', categories=['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2']), - 'un_last_wasting_date_of_onset': Property(Types.DATE, 'date of onset of latest wasting episode'), + 'un_last_wasting_date_of_onset': Property(Types.DATE, 'date of onset of last episode of wasting'), # Properties related to clinical acute malnutrition - 'un_clinical_acute_malnutrition': Property(Types.CATEGORICAL, 'clinical acute malnutrition state based on WHZ', + 'un_clinical_acute_malnutrition': Property(Types.CATEGORICAL, 'clinical acute malnutrition state base' + ' on WHZ and/or MUAC and/or oedema', categories=['MAM', 'SAM'] + ['well']), - 'un_am_bilateral_oedema': Property(Types.BOOL, 'bilateral oedema present in wasting'), - 'un_am_MUAC_category': Property(Types.CATEGORICAL, 'MUAC measurement categories', + 'un_am_bilateral_oedema': Property(Types.BOOL, 'bilateral pitting oedema present in wasting episode'), + 'un_am_MUAC_category': Property(Types.CATEGORICAL, 'MUAC measurement categories, based on WHO ' + 'cut-offs', categories=['<115mm', '115-<125mm', '>=125mm']), - 'un_sam_with_complications': Property(Types.BOOL, 'medical complications in SAM'), + 'un_sam_with_complications': Property(Types.BOOL, 'medical complications in SAM episode'), 'un_sam_death_date': Property(Types.DATE, 'death date from severe acute malnutrition'), 'un_am_recovery_date': Property(Types.DATE, 'recovery date from acute malnutrition'), - 'un_am_discharge_date': Property(Types.DATE, 'discharge date from treatment of MAM/ SAM'), + 'un_am_discharge_date': Property(Types.DATE, 'discharge date from treatment of MAM/SAM'), 'un_am_tx_start_date': Property(Types.DATE, 'intervention start date'), 'un_am_treatment_type': Property(Types.CATEGORICAL, 'treatment types for acute malnutrition', categories=['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care'] + [ From 255e84181e4fbbbb70a64dd4908ba59f5d12152a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 12 Feb 2024 17:35:49 +0000 Subject: [PATCH 050/755] RF_Wast: note updated --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 647472b8f8..00314c7de8 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3439870b193b766bdf7abfe7efb36e4fb029923d78864f8ea33c2b1696fde52a -size 2458 +oid sha256:85487c4538b5991a362172b4832cf39f58ed0231d86e28c3744ac7128e318862 +size 2512 From 645acc18e17a18fa9f44edcc54e8da6cb9def3d3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 12 Feb 2024 21:55:30 +0000 Subject: [PATCH 051/755] wast: minor changes (param moved; comment added) --- src/tlo/methods/wasting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index f901c066de..e280bfb0d7 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -95,9 +95,9 @@ class Wasting(Module): Types.REAL, 'relative risk of wasting if born preterm and small for gestational age'), 'rr_wasting_wealth_level': Parameter( Types.REAL, 'relative risk of wasting per 1 unit decrease in wealth level'), + # progression 'min_days_duration_of_wasting': Parameter( Types.REAL, 'minimum duration in days of wasting (MAM and SAM)'), - # progression 'average_duration_of_untreated_MAM': Parameter( Types.REAL, 'average duration of untreated MAM'), 'average_duration_of_untreated_SAM': Parameter( @@ -1195,7 +1195,7 @@ def unscaled_wasting_lm(intercept: Union[float, int] = 1.0) -> LinearModel: ) unscaled_lm = unscaled_wasting_lm() - target_mean = self.params['base_inc_rate_wasting_by_agegp'][2] + target_mean = self.params['base_inc_rate_wasting_by_agegp'][2] # base inc rate for 12-23mo old actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1) & (df.un_WHZ_category == 'WHZ>=-2')]).mean() From 177d8b0d15a8d81e048c0e1407648763ed933267 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 12 Feb 2024 21:59:29 +0000 Subject: [PATCH 052/755] RF_Wast: rename col 'more notes' to 'old values'; avoid multiple rows in a cell --- resources/ResourceFile_Wasting.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 00314c7de8..2a2a8e6a44 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:85487c4538b5991a362172b4832cf39f58ed0231d86e28c3744ac7128e318862 +oid sha256:19b21154ec4f8324dd7e08caca16e5bb3f74ee07c67dbbfc34b0eaf48a7e632a size 2512 From e70b39e36a48f916cd60a583abf274ed02b63679 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 19 Feb 2024 17:46:04 +0000 Subject: [PATCH 053/755] RF_Wast: added REF to some old values --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 2a2a8e6a44..56b5234430 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:19b21154ec4f8324dd7e08caca16e5bb3f74ee07c67dbbfc34b0eaf48a7e632a -size 2512 +oid sha256:de685722d74f6031de731fe519f859628cd0a397b193fd1d1932ec4efb47e8b4 +size 2685 From d983393fcaf7e2573f65ca3fd875c2e8a3e1d536 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 19 Feb 2024 22:15:57 +0000 Subject: [PATCH 054/755] wast: comments adjusted --- src/tlo/methods/wasting.py | 49 +++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index e280bfb0d7..72170c5d9c 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -203,7 +203,6 @@ def read_parameters(self, data_folder): modules would read a particular file within here. :return: """ - # Update parameters from the resource dataframe # Read parameters from the resource file self.load_parameters_from_dataframe( pd.read_csv(Path(self.resourcefilepath) / 'ResourceFile_Wasting.csv') @@ -247,7 +246,7 @@ def initialise_population(self, population): inclusive='left')) prevalence_of_wasting = self.wasting_models.get_wasting_prevalence(agegp=agegp).predict(df.loc[mask]) - # categorize into moderate (-3<=WHZ<-2) or severe (WHZ<-3) wasting + # categorize into moderate (-3 <= WHZ <- 2) or severe (WHZ <- 3) wasting wasted = self.rng.random_sample(len(prevalence_of_wasting)) < prevalence_of_wasting for idx in prevalence_of_wasting.index[wasted]: probability_of_severe = self.get_probs_or_odds_wasting(agegp=agegp) @@ -332,8 +331,8 @@ def get_probs_or_odds_wasting(self, agegp: str, get_odds: bool = False) -> Union def muac_cutoff_by_WHZ(self, idx, whz): """ - Proportion of MUAC<115mm in WHZ<-3 and -3<=WHZ<-2, and proportion of wasted children with oedematous - malnutrition ( Kwashiokor, marasmic-kwashiorkor) + Proportion of MUAC < 115 mm in WHZ < -3 and -3 <= WHZ < -2, + and proportion of wasted children with oedematous malnutrition (kwashiokor, marasmic kwashiorkor) :param idx: index of children ages 6-59 months or person_id :param whz: weight for height category @@ -341,36 +340,37 @@ def muac_cutoff_by_WHZ(self, idx, whz): df = self.sim.population.props p = self.parameters - # -- MUAC <115mm in severe wasting (WHZ<-3) and moderate (-3<=WHZ<-2)-- + # ----- MUAC < 115 mm in severe wasting (WHZ < -3) and moderate (-3 <= WHZ < -2) ------ if whz == 'WHZ<-3': - # apply probability of MUAC<115mm in severe wasting + # apply probability of MUAC < 115 mm in severe wasting low_muac_in_severe_wasting = self.rng.random_sample(size=len(idx)) < p['proportion_WHZ<-3_with_MUAC<115mm'] df.loc[idx[low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '<115mm' - # other severe wasting will have MUAC between 115-<125mm + # other with severe wasting will have MUAC between 115-<125mm df.loc[idx[~low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '115-<125mm' if whz == '-3<=WHZ<-2': - # apply probability of MUAC<115mm in moderate wasting + # apply probability of MUAC < 115 mm in moderate wasting low_muac_in_moderate_wasting = self.rng.random_sample(size=len(idx)) < \ p['proportion_-3<=WHZ<-2_with_MUAC<115mm'] df.loc[idx[low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = '<115mm' - # apply probability of MUAC between 115-<125mm in moderate wasting + # apply probability of MUAC within [115 mm; 125 mm) in moderate wasting moderate_low_muac_in_moderate_wasting = \ self.rng.random_sample(size=len(idx[~low_muac_in_moderate_wasting])) < \ p['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] df.loc[idx[~low_muac_in_moderate_wasting][moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] \ = '115-<125mm' - # other moderate wasting will have normal MUAC + # other with moderate wasting will have normal MUAC df.loc[idx[~low_muac_in_moderate_wasting][~moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] \ = '>=125mm' + # ----- MUAC distribution for WHZ >= -2 ----- if whz == 'WHZ>=-2': - # Give MUAC distribution for WHZ>=-2 ('well' group) --------- + muac_distribution_in_well_group = norm(loc=p['MUAC_distribution_WHZ>=-2'][0], scale=p['MUAC_distribution_WHZ>=-2'][1]) - # get probability of MUAC <115mm + # get probability of MUAC < 115 mm probability_over_or_equal_115 = muac_distribution_in_well_group.sf(11.5) probability_over_or_equal_125 = muac_distribution_in_well_group.sf(12.5) @@ -426,8 +426,7 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & (~df.at[person_id, 'un_am_bilateral_oedema'])): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' - # severe acute malnutrition - MUAC<115mm and/or WHZ<-3 and/or - # bilateral oedema + # severe acute malnutrition -- MUAC < 115 mm and/or WHZ < -3 and/or bilateral oedema elif ((df.at[person_id, 'un_am_MUAC_category'] == '<115mm') | (df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3') | (df.at[person_id, 'un_am_bilateral_oedema'])): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' @@ -449,7 +448,7 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): def date_of_outcome_for_untreated_am(self, person_id, duration_am): """ - helper funtion to get the duration and the wasting episode and date of outcome (recovery, progression, or death) + helper function to get duration and wasting episode and date of outcome (recovery, progression, or death) :param person_id: :param duration_am: :return: @@ -457,8 +456,7 @@ def date_of_outcome_for_untreated_am(self, person_id, duration_am): df = self.sim.population.props p = self.parameters - # moderate wasting (for progression to severe, or recovery from - # MAM) ----- + # moderate wasting (for progression to severe, or recovery from MAM) ----- if duration_am == 'MAM': # Allocate the duration of the moderate wasting episode duration_mam = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'])) @@ -668,9 +666,9 @@ def do_when_am_treatment(self, person_id, intervention): class WastingPollingEvent(RegularEvent, PopulationScopeEventMixin): """ - Regular event that determines new cases of wasting (WHZ<-2) to the under-5 population, and schedules + Regular event that determines new cases of wasting (WHZ < -2) to the under-5 population, and schedules individual incident cases to represent onset. It determines those who will progress to severe wasting - (WHZ<-3) and schedules the event to update on properties. These are events occurring without the input + (WHZ < -3) and schedules the event to update on properties. These are events occurring without the input of interventions, these events reflect the natural history only. """ AGE_GROUPS = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} @@ -706,7 +704,7 @@ def apply(self, population): # start without treatment df.loc[wasting_idx[incidence_of_wasting], 'un_am_treatment_type'] = 'none' # -------------------------------------------------------------------- - # Add this incident case to the tracker + # Add these incident cases to the tracker for person in wasting_idx: wasting_severity = df.at[person, 'un_WHZ_category'] age_group = WastingPollingEvent.AGE_GROUPS.get(df.loc[person].age_years, '5+y') @@ -715,10 +713,8 @@ def apply(self, population): # --------------------------------------------------------------------- - # # # # # # # #PROGRESS TO SEVERE WASTING # # # # # # # # # # # # # # # - - # Determine those that will progress to severe wasting ( WHZ<-3) - # and schedule progression event --------- + # # # PROGRESS TO SEVERE WASTING # # # # # # # # # # # # # # # # # # + # Determine those that will progress to severe wasting (WHZ < -3) and schedule progression event --------- progression_sev_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == '-3<=WHZ<-2')] progression_severe_wasting = self.module.wasting_models.severe_wasting_progression_lm.predict( @@ -740,9 +736,8 @@ def apply(self, population): event=ProgressionSevereWastingEvent( module=self.module, person_id=person), date=outcome_date) - # # # # # # #MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # - - # moderate wasting not progressed to severe, schedule recovery + # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # + # Schedule recovery from moderate wasting for those not progressing to severe wasting --------- for person in progression_sev_wasting.index[~progression_severe_wasting]: outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') if outcome_date <= self.sim.date: From b0d0b91a2f72cb86ec3213d3f42c10ac6d18a5a6 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 19 Feb 2024 22:37:26 +0000 Subject: [PATCH 055/755] wast: setting properties in the order they are defined --- src/tlo/methods/wasting.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 72170c5d9c..68d3371b60 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -225,12 +225,12 @@ def initialise_population(self, population): # Set initial properties df.loc[df.is_alive, 'un_ever_wasted'] = False df.loc[df.is_alive, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished - df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' df.loc[df.is_alive, 'un_last_wasting_date_of_onset'] = pd.NaT - df.loc[df.is_alive, 'un_am_tx_start_date'] = pd.NaT - df.loc[df.is_alive, 'un_sam_death_date'] = pd.NaT + df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' df.loc[df.is_alive, 'un_am_bilateral_oedema'] = False df.loc[df.is_alive, 'un_am_MUAC_category'] = '>=125mm' + df.loc[df.is_alive, 'un_sam_death_date'] = pd.NaT + df.loc[df.is_alive, 'un_am_tx_start_date'] = pd.NaT df.loc[df.is_alive, 'un_am_treatment_type'] = 'not_applicable' # initialise wasting linear models. From a4d15e027cc89edfaa0b98c7d437ec61b5c3c036 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 19 Feb 2024 22:37:35 +0000 Subject: [PATCH 056/755] wast: TODO --- src/tlo/methods/wasting.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 68d3371b60..73a8ccc786 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -232,6 +232,7 @@ def initialise_population(self, population): df.loc[df.is_alive, 'un_sam_death_date'] = pd.NaT df.loc[df.is_alive, 'un_am_tx_start_date'] = pd.NaT df.loc[df.is_alive, 'un_am_treatment_type'] = 'not_applicable' + # TODO: What about 'un_sam_with_complications'? There are no such cases when population is initialised? # initialise wasting linear models. self.wasting_models = WastingModels(self) From 11bfe6c8f734d7a3ab985e8fe8e9837277119086 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 20 Feb 2024 00:13:43 +0000 Subject: [PATCH 057/755] wast: tidy up the get_prob_severe_wasting_or_odds_wasting fnc; TODO incl. --- src/tlo/methods/wasting.py | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 73a8ccc786..3be20d3f8d 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -247,10 +247,10 @@ def initialise_population(self, population): inclusive='left')) prevalence_of_wasting = self.wasting_models.get_wasting_prevalence(agegp=agegp).predict(df.loc[mask]) - # categorize into moderate (-3 <= WHZ <- 2) or severe (WHZ <- 3) wasting + # apply prevalence of wasting and categorise into moderate (-3 <= WHZ < -2) or severe (WHZ < -3) wasting wasted = self.rng.random_sample(len(prevalence_of_wasting)) < prevalence_of_wasting for idx in prevalence_of_wasting.index[wasted]: - probability_of_severe = self.get_probs_or_odds_wasting(agegp=agegp) + probability_of_severe = self.get_prob_severe_wasting_or_odds_wasting(agegp=agegp) wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], p=[probability_of_severe, 1 - probability_of_severe]) df.at[idx, 'un_WHZ_category'] = wasted_category @@ -301,33 +301,36 @@ def on_birth(self, mother_id, child_id): df.at[child_id, 'un_am_MUAC_category'] = '>=125mm' df.at[child_id, 'un_am_treatment_type'] = 'not_applicable' - def get_probs_or_odds_wasting(self, agegp: str, get_odds: bool = False) -> Union[float, int]: + def get_prob_severe_wasting_or_odds_wasting(self, agegp: str, get_odds: bool = False) -> Union[float, int]: """ - This function will calculate the WHZ scores by categories and return probability or odds of severe wasting - for those with wasting status + This function will calculate the WHZ scores by categories and return probability of severe wasting + for those with wasting status, or odds of wasting :param agegp: age grouped in months - :param get_odds: when set to True, this argument will cause this method return the odds of severe wasting to be - used for scaling wasting prevalence linear model - :return: + :param get_odds: when set to True, this argument will cause this method return the odds of wasting to be used + for scaling wasting prevalence linear model + :return: probability of severe wasting among all wasting cases (if 'get_odds' == False), + or odds of wasting among all children under 5 (if 'get_odds' == True) """ - # generate random numbers from N(meean, sd) + # generate random numbers from N(mean, sd) mean, stdev = self.parameters[f'prev_WHZ_distribution_age_{agegp}'] whz_normal_distribution = norm(loc=mean, scale=stdev) - # get all wasting: WHZ <-2 + # get probability of any wasting: WHZ < -2 probability_less_than_minus2sd = 1 - whz_normal_distribution.sf(-2) if get_odds: - # convert probability to odds and return the odds + # convert probability of wasting to odds and return the odds of wasting return probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) - # get severe wasting zcores: WHZ <-3 + # get probability of severe wasting: WHZ < -3 probability_less_than_minus3sd = 1 - whz_normal_distribution.sf(-3) - # make WHZ <-2 as the 100% and get the adjusted probability of severe wasting within overall wasting + # make WHZ < -2 as the 100% and get the adjusted probability of severe wasting within overall wasting proportion_severe_in_overall_wasting = probability_less_than_minus3sd * probability_less_than_minus2sd + # TODO: this doesn't seem right, shouldn't be this + # proportion_severe_in_overall_wasting = probability_less_than_minus3sd / probability_less_than_minus2sd ? - # get the probability of severe wasting + # return the probability of severe wasting among all wasting cases return proportion_severe_in_overall_wasting def muac_cutoff_by_WHZ(self, idx, whz): @@ -1227,9 +1230,9 @@ def make_linear_model_wasting(intercept: Union[float, int]) -> LinearModel: self.params['or_wasting_preterm_and_AGA']) ) - get_odds_wasting = self.module.get_probs_or_odds_wasting(agegp=agegp, get_odds=True) + get_odds_wasting = self.module.get_prob_severe_wasting_or_odds_wasting(agegp=agegp, get_odds=True) unscaled_lm = make_linear_model_wasting(intercept=get_odds_wasting) - target_mean = self.module.get_probs_or_odds_wasting(agegp='12_23mo', get_odds=True) + target_mean = self.module.get_prob_severe_wasting_or_odds_wasting(agegp='12_23mo', get_odds=True) actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1)]).mean() scaled_intercept = get_odds_wasting * (target_mean / actual_mean) if \ (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else get_odds_wasting From bee7e6942d40d50d81524e3db056b62dc0842cd8 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 20 Feb 2024 00:15:33 +0000 Subject: [PATCH 058/755] wast: descriptions and comments adjusted --- src/tlo/methods/wasting.py | 45 +++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 3be20d3f8d..3c06820605 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -29,8 +29,8 @@ class Wasting(Module): """ This module applies the prevalence of wasting at the population-level, based on the Malawi DHS Survey 2015-2016. The definitions: - - moderate wasting: weight_for_height Z-score (WHZ) <-2 SD from the reference mean - - severe wasting: weight_for_height Z-score (WHZ) <-3 SD from the reference mean + - moderate wasting: weight_for_height Z-score (WHZ) < -2 SD from the reference mean + - severe wasting: weight_for_height Z-score (WHZ) < -3 SD from the reference mean """ @@ -90,7 +90,7 @@ class Wasting(Module): 'rr_wasting_preterm_and_AGA': Parameter( Types.REAL, 'relative risk of wasting if born preterm and adequate for gestational age'), 'rr_wasting_SGA_and_term': Parameter( - Types.REAL, 'relative risk of wasting if born term and small for geatational age'), + Types.REAL, 'relative risk of wasting if born term and small for gestational age'), 'rr_wasting_SGA_and_preterm': Parameter( Types.REAL, 'relative risk of wasting if born preterm and small for gestational age'), 'rr_wasting_wealth_level': Parameter( @@ -108,25 +108,26 @@ class Wasting(Module): Types.REAL, 'probability of medical complications in SAM '), # MUAC distributions 'MUAC_distribution_WHZ<-3': Parameter( - Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ<-3'), + Types.LIST, + 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ < -3'), 'MUAC_distribution_-3<=WHZ<-2': Parameter( - Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for -3<=WHZ<-2'), + Types.LIST, + 'mean and standard deviation of a normal distribution of MUAC measurements for -3 <= WHZ < -2'), 'MUAC_distribution_WHZ>=-2': Parameter( - Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ>=-2'), + Types.LIST, + 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ >= -2'), 'proportion_WHZ<-3_with_MUAC<115mm': Parameter( - Types.REAL, 'proportion of severe wasting with MUAC<115mm'), + Types.REAL, 'proportion of severe wasting with MUAC < 115mm'), 'proportion_-3<=WHZ<-2_with_MUAC<115mm': Parameter( - Types.REAL, 'proportion of moderate wasting with MUAC<115mm'), + Types.REAL, 'proportion of moderate wasting with MUAC < 115mm'), 'proportion_-3<=WHZ<-2_with_MUAC_115-<125mm': Parameter( - Types.REAL, 'proportion of moderate wasting with 115mm≤MUAC<125mm'), + Types.REAL, 'proportion of moderate wasting with 115 mm ≤ MUAC < 125mm'), 'proportion_mam_with_MUAC_115-<125mm_and_normal_whz': Parameter( - Types.REAL, 'proportion of MAM cases with 115mm≤MUAC<125mm and normal/mild WHZ'), + Types.REAL, 'proportion of MAM cases with 115 mm ≤ MUAC < 125 mm and normal/mild WHZ'), 'proportion_mam_with_MUAC_115-<125mm_and_-3<=WHZ<-2': Parameter( - Types.REAL, - 'proportion of MAM cases with both 115mm≤MUAC<125mm and moderate wasting'), + Types.REAL, 'proportion of MAM cases with both 115 mm ≤ MUAC < 125 mm and moderate wasting'), 'proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC': Parameter( - Types.REAL, - 'proportion of MAM cases with moderate wasting and normal MUAC'), + Types.REAL, 'proportion of MAM cases with moderate wasting and normal MUAC'), # bilateral oedema 'prevalence_nutritional_oedema': Parameter( Types.REAL, 'prevalence of nutritional oedema in children under 5 in Malawi'), @@ -156,8 +157,8 @@ class Wasting(Module): PROPERTIES = { # Properties related to wasting - 'un_ever_wasted': Property(Types.BOOL, 'ever had an episode of wasting (WHZ<-2)'), - 'un_WHZ_category': Property(Types.CATEGORICAL, 'weight-for-height z-score category', + 'un_ever_wasted': Property(Types.BOOL, 'ever had an episode of wasting (WHZ < -2)'), + 'un_WHZ_category': Property(Types.CATEGORICAL, 'weight-for-height Z-score category', categories=['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2']), 'un_last_wasting_date_of_onset': Property(Types.DATE, 'date of onset of last episode of wasting'), @@ -396,7 +397,7 @@ def nutritional_oedema_present(self, idx): p = self.parameters # Knowing the prevalence of nutritional oedema in under 5 - # population, apply the probability of oedema in WHZ<-2 + # population, apply the probability of oedema in WHZ < -2 # get those children with wasting children_with_wasting = idx.intersection(df.index[df.un_WHZ_category != 'WHZ>=-2']) children_without_wasting = idx.intersection(df.index[df.un_WHZ_category == 'WHZ>=-2']) @@ -729,13 +730,13 @@ def apply(self, population): # determine those individuals who will progress to severe wasting and time of progression for person in progression_sev_wasting.index[progression_severe_wasting]: outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') - # schedule severe wasting WHZ<-3 onset + # schedule severe wasting WHZ < -3 onset if outcome_date <= self.sim.date: - # schedule severe wasting WHZ<-3 onset today + # schedule severe wasting (WHZ < -3) onset today self.sim.schedule_event(event=ProgressionSevereWastingEvent( module=self.module, person_id=person), date=self.sim.date) else: - # schedule severe wasting WHZ<-3 onset according to duration + # schedule severe wasting WHZ < -3 onset according to duration self.sim.schedule_event( event=ProgressionSevereWastingEvent( module=self.module, person_id=person), date=outcome_date) @@ -773,7 +774,7 @@ def apply(self, population): class ProgressionSevereWastingEvent(Event, IndividualScopeEventMixin): """ - This Event is for the onset of severe wasting (WHZ <-3). + This Event is for the onset of severe wasting (WHZ < -3). * Refreshes all the properties so that they pertain to this current episode of wasting * Imposes wasting symptom """ @@ -796,7 +797,7 @@ def apply(self, person_id): # update properties df.at[person_id, 'un_WHZ_category'] = 'WHZ<-3' - # Give MUAC measurement category for WHZ<-3 + # Give MUAC measurement category for WHZ < -3 if df.at[person_id, 'age_exact_years'] > 0.5: m.muac_cutoff_by_WHZ(idx=df.loc[[person_id]].index, whz='WHZ<-3') From e6e581ea245427d2de22dca9fc6700cfdd4e3520 Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Thu, 22 Feb 2024 09:13:30 +0200 Subject: [PATCH 059/755] Updated proportion, prob/odds function_name, rng --- src/tlo/methods/wasting.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index cce7760f75..24072edcfd 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -249,7 +249,7 @@ def initialise_population(self, population): # categorize into moderate (-3<=WHZ<-2) or severe (WHZ<-3) wasting wasted = self.rng.random_sample(len(prevalence_of_wasting)) < prevalence_of_wasting for idx in prevalence_of_wasting.index[wasted]: - probability_of_severe = self.get_odds_probs_wasting(agegp=agegp) + probability_of_severe = self.get_prob_severe_wasting_or_odds_wasting(agegp=agegp) wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], p=[probability_of_severe, 1 - probability_of_severe]) df.at[idx, 'un_WHZ_category'] = wasted_category @@ -300,7 +300,7 @@ def on_birth(self, mother_id, child_id): df.at[child_id, 'un_am_MUAC_category'] = '>=125mm' df.at[child_id, 'un_am_treatment_type'] = 'not_applicable' - def get_odds_probs_wasting(self, agegp: str, lm_scaling: bool = False) -> Union[float, int]: + def get_prob_severe_wasting_or_odds_wasting(self, agegp: str, lm_scaling: bool = False) -> Union[float, int]: """ This function will calculate the WHZ scores by categories and return probability or odds of severe wasting for those with wasting status @@ -323,7 +323,7 @@ def get_odds_probs_wasting(self, agegp: str, lm_scaling: bool = False) -> Union[ probability_less_than_minus3sd = 1 - whz_normal_distribution.sf(-3) # make WHZ <-2 as the 100% and get the adjusted probability of severe wasting within overall wasting - proportion_severe_in_overall_wasting = probability_less_than_minus3sd * probability_less_than_minus2sd + proportion_severe_in_overall_wasting = probability_less_than_minus3sd / probability_less_than_minus2sd # get the probability of severe wasting return proportion_severe_in_overall_wasting @@ -693,7 +693,7 @@ def apply(self, population): inc_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & ( df.un_WHZ_category == 'WHZ>=-2')] incidence_of_wasting = self.module.wasting_models.wasting_incidence_lm.predict(inc_wasting, - rng=self.module.rng + rng=rng ) wasting_idx = inc_wasting.index # update the properties for wasted children @@ -1229,9 +1229,9 @@ def make_linear_model_wasting(intercept: Union[float, int]) -> LinearModel: self.params['or_wasting_preterm_and_AGA']) ) - get_odds_wasting = self.module.get_odds_probs_wasting(agegp=agegp, lm_scaling=True) + get_odds_wasting = self.module.get_prob_severe_wasting_or_odds_wasting(agegp=agegp, lm_scaling=True) unscaled_lm = make_linear_model_wasting(intercept=get_odds_wasting) - target_mean = self.module.get_odds_probs_wasting(agegp='12_23mo', lm_scaling=True) + target_mean = self.module.get_prob_severe_wasting_or_odds_wasting(agegp='12_23mo', lm_scaling=True) actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1)]).mean() scaled_intercept = get_odds_wasting * (target_mean / actual_mean) if \ (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else get_odds_wasting From 20b5cb50463fddd1faa41df3f8efc35cbe1d07f4 Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Thu, 22 Feb 2024 09:49:46 +0200 Subject: [PATCH 060/755] Updated proportion, prob/odds function_name, rng --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index d83ab40370..d4a26b04c5 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -299,7 +299,7 @@ def on_birth(self, mother_id, child_id): df.at[child_id, 'un_am_MUAC_category'] = '>=125mm' df.at[child_id, 'un_am_treatment_type'] = 'not_applicable' - def get_prob_severe_wasting_or_odds_wasting(self, agegp: str, lm_scaling: bool = False) -> Union[float, int]: + def get_prob_severe_wasting_or_odds_wasting(self, agegp: str, get_odds: bool = False) -> Union[float, int]: """ This function will calculate the WHZ scores by categories and return probability or odds of severe wasting for those with wasting status From 268bebe7c772fc3d95ea0eb61ef71c7421bf7557 Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Fri, 1 Mar 2024 09:43:21 +0200 Subject: [PATCH 061/755] Fix prob_odds function_name, rng --- src/tlo/methods/wasting.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index d4a26b04c5..6db00c0c57 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -323,7 +323,7 @@ def get_prob_severe_wasting_or_odds_wasting(self, agegp: str, get_odds: bool = F probability_less_than_minus3sd = 1 - whz_normal_distribution.sf(-3) # make WHZ <-2 as the 100% and get the adjusted probability of severe wasting within overall wasting - proportion_severe_in_overall_wasting = probability_less_than_minus3sd / probability_less_than_minus2sd + proportion_severe_in_overall_wasting = probability_less_than_minus3sd * probability_less_than_minus2sd # get the probability of severe wasting return proportion_severe_in_overall_wasting @@ -1229,9 +1229,9 @@ def make_linear_model_wasting(intercept: Union[float, int]) -> LinearModel: self.params['or_wasting_preterm_and_AGA']) ) - get_odds_wasting = self.module.get_odds_probs_wasting(agegp=agegp, lm_scaling=True) + get_odds_wasting = self.module.get_prob_severe_wasting_or_odds_wasting(agegp=agegp, get_odds=True) unscaled_lm = make_linear_model_wasting(intercept=get_odds_wasting) - target_mean = self.module.get_odds_probs_wasting(agegp='12_23mo', lm_scaling=True) + target_mean = self.module.get_prob_severe_wasting_or_odds_wasting(agegp='12_23mo', get_odds=True) actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1)]).mean() scaled_intercept = get_odds_wasting * (target_mean / actual_mean) if \ (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else get_odds_wasting From a6eb7b854f7efaa250521efc5f83d982b7aa59d9 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 1 Mar 2024 18:24:17 +0000 Subject: [PATCH 062/755] wast: fix a bug; rm TODOs --- src/tlo/methods/wasting.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 3c06820605..ca0f78f496 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -233,7 +233,6 @@ def initialise_population(self, population): df.loc[df.is_alive, 'un_sam_death_date'] = pd.NaT df.loc[df.is_alive, 'un_am_tx_start_date'] = pd.NaT df.loc[df.is_alive, 'un_am_treatment_type'] = 'not_applicable' - # TODO: What about 'un_sam_with_complications'? There are no such cases when population is initialised? # initialise wasting linear models. self.wasting_models = WastingModels(self) @@ -327,9 +326,7 @@ def get_prob_severe_wasting_or_odds_wasting(self, agegp: str, get_odds: bool = F probability_less_than_minus3sd = 1 - whz_normal_distribution.sf(-3) # make WHZ < -2 as the 100% and get the adjusted probability of severe wasting within overall wasting - proportion_severe_in_overall_wasting = probability_less_than_minus3sd * probability_less_than_minus2sd - # TODO: this doesn't seem right, shouldn't be this - # proportion_severe_in_overall_wasting = probability_less_than_minus3sd / probability_less_than_minus2sd ? + proportion_severe_in_overall_wasting = probability_less_than_minus3sd / probability_less_than_minus2sd # return the probability of severe wasting among all wasting cases return proportion_severe_in_overall_wasting From 89e54adb18f585986c6d9a5e8207a100ecf3d3cf Mon Sep 17 00:00:00 2001 From: thewati <39279950+thewati@users.noreply.github.com> Date: Tue, 5 Mar 2024 09:00:31 +0200 Subject: [PATCH 063/755] Standardize progression to sev wasting --- src/tlo/methods/wasting.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 6db00c0c57..86cf44372a 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -324,6 +324,9 @@ def get_prob_severe_wasting_or_odds_wasting(self, agegp: str, get_odds: bool = F # make WHZ <-2 as the 100% and get the adjusted probability of severe wasting within overall wasting proportion_severe_in_overall_wasting = probability_less_than_minus3sd * probability_less_than_minus2sd + prop_new = probability_less_than_minus3sd / probability_less_than_minus2sd + print(f'prop sev in wasting {proportion_severe_in_overall_wasting}') + print(f'prop new {prop_new}') # get the probability of severe wasting return proportion_severe_in_overall_wasting @@ -720,10 +723,8 @@ def apply(self, population): progression_sev_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == '-3<=WHZ<-2')] progression_severe_wasting = self.module.wasting_models.severe_wasting_progression_lm.predict( - progression_sev_wasting) + progression_sev_wasting, rng=rng) - progression_severe_wasting = \ - rng.random_sample(len(progression_sev_wasting)) < progression_severe_wasting # determine those individuals who will progress to severe wasting and time of progression for person in progression_sev_wasting.index[progression_severe_wasting]: outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') From 0a8c3ce8afcc9e60e4bea421d8f46bb3dcd1d7a2 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Tue, 5 Mar 2024 13:00:43 +0200 Subject: [PATCH 064/755] fixing the bug. return proportion not product --- src/tlo/methods/wasting.py | 24 ++++-------------------- tests/test_wasting.py | 19 +++++++++++-------- 2 files changed, 15 insertions(+), 28 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 6db00c0c57..49badfeffc 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -262,12 +262,6 @@ def initialise_population(self, population): # acute malnutrition state # # # # # self.population_poll_clinical_am(df) - children_with_sam = df.loc[df.is_alive & (df.age_exact_years < 5) - & (df.un_clinical_acute_malnutrition == 'SAM')] - for person in children_with_sam.index: - # update clinical symptoms for severe wasting - self.wasting_clinical_symptoms(person_id=person) - def initialise_simulation(self, sim): """Prepares for simulation: * Schedules the main polling event @@ -323,10 +317,8 @@ def get_prob_severe_wasting_or_odds_wasting(self, agegp: str, get_odds: bool = F probability_less_than_minus3sd = 1 - whz_normal_distribution.sf(-3) # make WHZ <-2 as the 100% and get the adjusted probability of severe wasting within overall wasting - proportion_severe_in_overall_wasting = probability_less_than_minus3sd * probability_less_than_minus2sd - - # get the probability of severe wasting - return proportion_severe_in_overall_wasting + # return the probability of severe wasting + return probability_less_than_minus3sd / probability_less_than_minus2sd def muac_cutoff_by_WHZ(self, idx, whz): """ @@ -429,6 +421,8 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): elif ((df.at[person_id, 'un_am_MUAC_category'] == '<115mm') | (df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3') | (df.at[person_id, 'un_am_bilateral_oedema'])): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' + # apply symptoms to all SAM cases + self.wasting_clinical_symptoms(person_id=person_id) else: df.at[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' @@ -762,13 +756,6 @@ def apply(self, population): # determine the clinical state of acute malnutrition, and check complications if SAM self.module.population_poll_clinical_am(df) - # then, update clinical symptoms for those with severe acute - # malnutrition - children_with_sam = df.loc[df.is_alive & (df.age_exact_years < 5) - & (df.un_clinical_acute_malnutrition == 'SAM')] - for person in children_with_sam.index: - self.module.wasting_clinical_symptoms(person_id=person) - class ProgressionSevereWastingEvent(Event, IndividualScopeEventMixin): """ @@ -803,9 +790,6 @@ def apply(self, person_id): # complications if SAM m.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) - # update clinical symptoms for severe wasting - m.wasting_clinical_symptoms(person_id=person_id) - # ------------------------------------------------------------------------------------------- # Add this incident case to the tracker wasting_severity = df.at[person_id, 'un_WHZ_category'] diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 6a37a184fd..e48d1adf86 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -186,6 +186,12 @@ def test_wasting_incidence(tmpdir): sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) + # reset properties of all individuals so that they are don't have wasting + df = sim.population.props + df.loc[df.is_alive, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished + df.loc[df.is_alive, 'un_ever_wasted'] = False + df.loc[df.is_alive, 'un_last_wasting_date_of_onset'] = pd.NaT + # Set incidence of wasting at 100% sim.modules['Wasting'].wasting_models.wasting_incidence_lm = LinearModel.multiplicative() @@ -194,7 +200,6 @@ def test_wasting_incidence(tmpdir): polling.apply(sim.population) # Check properties of individuals: should now be moderately wasted - df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] assert all(under5s['un_ever_wasted']) assert all(under5s['un_WHZ_category'] == '-3<=WHZ<-2') @@ -420,7 +425,7 @@ def test_recovery_severe_wasting_without_complications(tmpdir): ge.run(squeeze_factor=0.0) # check HSI event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[1][1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM) # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought @@ -480,9 +485,6 @@ def test_recovery_severe_wasting_with_complications(tmpdir): # assign diagnosis wmodule.clinical_acute_malnutrition_state(person_id, df) - # apply symptoms - wmodule.wasting_clinical_symptoms(person_id) - # by having severe wasting, this individual should be diagnosed as SAM assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' @@ -571,9 +573,10 @@ def test_nat_hist_death(tmpdir): # make an individual diagnosed as SAM by WHZ category. # We want to make this individual qualify for death - df.loc[person_id, 'un_ever_wasted'] = True df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' - df.loc[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' + + # assign diagnosis + wmodule.clinical_acute_malnutrition_state(person_id, df) # apply wasting symptoms to this individual wmodule.wasting_clinical_symptoms(person_id) @@ -768,7 +771,7 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): ge.run(squeeze_factor=0.0) # check inpatient care event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], + assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[1][1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM) # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought From 0228ad2a682876b44216a5d395064283ee4226c1 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Tue, 5 Mar 2024 13:15:44 +0200 Subject: [PATCH 065/755] changing all appearance of '115-<125mm' to '[115,125)mm' --- resources/ResourceFile_Wasting.xlsx | 4 ++-- src/tlo/methods/wasting.py | 32 ++++++++++++++--------------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/resources/ResourceFile_Wasting.xlsx b/resources/ResourceFile_Wasting.xlsx index 60acc22d60..ba9dbdfdaa 100644 --- a/resources/ResourceFile_Wasting.xlsx +++ b/resources/ResourceFile_Wasting.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b79a5d92163f8b69a1125003b4154f892e924011a0f1ae359a5b3c632f836179 -size 12146 +oid sha256:4c48a15d0fcbcd71c7170ad87e7b32d8413866b6283ef8cc96212e5d26b7efaf +size 12127 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 49badfeffc..3dd108fc05 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -126,11 +126,11 @@ class Wasting(Module): Types.REAL, 'proportion of severe weight-for-height Z-score with MUAC<115mm'), 'proportion_-3<=WHZ<-2_with_MUAC<115mm': Parameter( Types.REAL, 'proportion of moderate weight-for-height Z-score with MUAC<115mm'), - 'proportion_-3<=WHZ<-2_with_MUAC_115-<125mm': Parameter( + 'proportion_-3<=WHZ<-2_with_MUAC_[115,125)mm': Parameter( Types.REAL, 'proportion of moderate weight-for-height Z-score with MUAC between 115mm and 125mm'), - 'proportion_mam_with_MUAC_115-<125mm_and_normal_whz': Parameter( + 'proportion_mam_with_MUAC_[115,125)mm_and_normal_whz': Parameter( Types.REAL, 'proportion of mam cases with MUAC between 115mm and 125mm and normal/mild WHZ'), - 'proportion_mam_with_MUAC_115-<125mm_and_-3<=WHZ<-2': Parameter( + 'proportion_mam_with_MUAC_[115,125)mm_and_-3<=WHZ<-2': Parameter( Types.REAL, 'proportion of mam cases with both MUAC between 115mm and ' '125mm and moderate wasting'), @@ -167,7 +167,7 @@ class Wasting(Module): categories=['MAM', 'SAM'] + ['well']), 'un_am_bilateral_oedema': Property(Types.BOOL, 'bilateral oedema present in wasting'), 'un_am_MUAC_category': Property(Types.CATEGORICAL, 'MUAC measurement categories', - categories=['<115mm', '115-<125mm', '>=125mm']), + categories=['<115mm', '[115,125)mm', '>=125mm']), 'un_sam_with_complications': Property(Types.BOOL, 'medical complications in SAM'), 'un_sam_death_date': Property(Types.DATE, 'death date from severe acute malnutrition'), 'un_am_recovery_date': Property(Types.DATE, 'recovery date from acute malnutrition'), @@ -337,8 +337,8 @@ def muac_cutoff_by_WHZ(self, idx, whz): low_muac_in_severe_wasting = self.rng.random_sample(size=len(idx)) < p['proportion_WHZ<-3_with_MUAC<115mm'] df.loc[idx[low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '<115mm' - # other severe wasting will have MUAC between 115-<125mm - df.loc[idx[~low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '115-<125mm' + # other severe wasting will have MUAC between [115,125)mm + df.loc[idx[~low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '[115,125)mm' if whz == '-3<=WHZ<-2': # apply probability of MUAC<115mm in moderate wasting @@ -346,12 +346,12 @@ def muac_cutoff_by_WHZ(self, idx, whz): p['proportion_-3<=WHZ<-2_with_MUAC<115mm'] df.loc[idx[low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = '<115mm' - # apply probability of MUAC between 115-<125mm in moderate wasting + # apply probability of MUAC between [115,125)mm in moderate wasting moderate_low_muac_in_moderate_wasting = \ self.rng.random_sample(size=len(idx[~low_muac_in_moderate_wasting])) < \ - p['proportion_-3<=WHZ<-2_with_MUAC_115-<125mm'] + p['proportion_-3<=WHZ<-2_with_MUAC_[115,125)mm'] df.loc[idx[~low_muac_in_moderate_wasting][moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] \ - = '115-<125mm' + = '[115,125)mm' # other moderate wasting will have normal MUAC df.loc[idx[~low_muac_in_moderate_wasting][~moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] \ = '>=125mm' @@ -368,7 +368,7 @@ def muac_cutoff_by_WHZ(self, idx, whz): pro_between_115_125 = probability_over_or_equal_115 - probability_over_or_equal_125 for pid in idx: - muac_cat = self.rng.choice(['<115mm', '115-<125mm', '>=125mm'], + muac_cat = self.rng.choice(['<115mm', '[115,125)mm', '>=125mm'], p=[prob_less_than_115, pro_between_115_125, probability_over_or_equal_125]) df.at[pid, 'un_am_MUAC_category'] = muac_cat @@ -519,7 +519,7 @@ def report_daly_values(self): total_daly_values.loc[df.is_alive & ( ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | ( (df.un_WHZ_category != 'WHZ<-3') & ( - df.un_am_MUAC_category != "115-<125mm"))) & df.un_am_bilateral_oedema] = daly_wts[ + df.un_am_MUAC_category != "[115,125)mm"))) & df.un_am_bilateral_oedema] = daly_wts[ 'MAM_with_oedema'] return total_daly_values @@ -911,23 +911,23 @@ def apply(self, person_id): # oedema, or low muac - do not change the WHZ if df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2': # mam by muac only - df.at[person_id, 'un_am_MUAC_category'] = '115-<125mm' + df.at[person_id, 'un_am_MUAC_category'] = '[115,125)mm' else: # using the probability of mam classification by anthropometric # indices mam_classification = rng.choice(['mam_by_muac_only', 'mam_by_muac_and_whz', 'mam_by_whz_only'], - p=[p['proportion_mam_with_MUAC_115-<125mm_and_normal_whz'], - p['proportion_mam_with_MUAC_115-<125mm_and_-3<=WHZ<-2'], + p=[p['proportion_mam_with_MUAC_[115,125)mm_and_normal_whz'], + p['proportion_mam_with_MUAC_[115,125)mm_and_-3<=WHZ<-2'], p['proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC']]) if mam_classification == 'mam_by_muac_only': df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' - df.at[person_id, 'un_am_MUAC_category'] = '115-<125mm' + df.at[person_id, 'un_am_MUAC_category'] = '[115,125)mm' if mam_classification == 'mam_by_muac_and_whz': df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' - df.at[person_id, 'un_am_MUAC_category'] = '115-<125mm' + df.at[person_id, 'un_am_MUAC_category'] = '[115,125)mm' if mam_classification == 'mam_by_whz_only': df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' From 7e5b471c0db57c1bcc0a77e895bc3acd03fe2a8d Mon Sep 17 00:00:00 2001 From: mnjowe Date: Tue, 5 Mar 2024 13:37:50 +0200 Subject: [PATCH 066/755] adding random number generator to linear model --- src/tlo/methods/wasting.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 3dd108fc05..074ce791bd 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -714,10 +714,8 @@ def apply(self, population): progression_sev_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == '-3<=WHZ<-2')] progression_severe_wasting = self.module.wasting_models.severe_wasting_progression_lm.predict( - progression_sev_wasting) + progression_sev_wasting, rng=rng) - progression_severe_wasting = \ - rng.random_sample(len(progression_sev_wasting)) < progression_severe_wasting # determine those individuals who will progress to severe wasting and time of progression for person in progression_sev_wasting.index[progression_severe_wasting]: outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') From f1eb95c1d01da5178c22917eaf1388d029d19d93 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Wed, 6 Mar 2024 13:03:08 +0200 Subject: [PATCH 067/755] squeeze single row output --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 074ce791bd..34676eb289 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -714,7 +714,7 @@ def apply(self, population): progression_sev_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == '-3<=WHZ<-2')] progression_severe_wasting = self.module.wasting_models.severe_wasting_progression_lm.predict( - progression_sev_wasting, rng=rng) + progression_sev_wasting, rng=rng, squeeze_single_row_output=False) # determine those individuals who will progress to severe wasting and time of progression for person in progression_sev_wasting.index[progression_severe_wasting]: From ada21ed41ae313acdc1989190f2825f453551deb Mon Sep 17 00:00:00 2001 From: mnjowe Date: Sat, 16 Mar 2024 21:06:13 +0200 Subject: [PATCH 068/755] plotting wasting prevalence by age group and year --- .../wasting_analyses/analysis_wasting.py | 60 +++++++++++++++---- src/tlo/methods/wasting.py | 45 ++++++-------- 2 files changed, 68 insertions(+), 37 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 464417522b..aa9f248955 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -9,7 +9,7 @@ from matplotlib import pyplot as plt from tlo import Date, Simulation, logging -from tlo.analysis.utils import compare_number_of_deaths, parse_log_file +from tlo.analysis.utils import compare_number_of_deaths, parse_log_file, unflatten_flattened_multi_index_in_logging from tlo.methods import ( care_of_women_during_pregnancy, contraception, @@ -88,17 +88,51 @@ def plot_wasting_incidence(self): _col_counter = -1 _col_counter += 1 # increment column counter fig.tight_layout() + fig.savefig( + outputs / ('wasting incidence' + datestamp + ".pdf"), + format="pdf" + ) + plt.show() + + def construct_dfs(self) -> dict: + """ Create dict of pd.DataFrames containing counts of different lifestyle properties by date, sex and + age-group """ + return { + k: unflatten_flattened_multi_index_in_logging(v.set_index('date')) + for k, v in self.__logs_dict.items() if k in ['wasting_prevalence_count'] + } - def plot_wasting_prevalence(self): - w_prev_df = self.__logs_dict['wasting_prevalence_count'] + def plot_wasting_prevalence_per_year(self): + """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of + children wasted divide by the total number of children less than 5 years""" + w_prev_df = self.__logs_dict["wasting_prevalence_count"] + w_prev_df = w_prev_df[['date', 'total_under5_prop']] w_prev_df.set_index(w_prev_df.date.dt.year, inplace=True) w_prev_df.drop(columns='date', inplace=True) - w_prev_df = w_prev_df.apply(lambda _row: _row / _row.sum(), axis=1) - w_prev_df.plot(kind='bar', stacked=True, - title="Wasting prevalence in children 0-59 months", - ylabel='proportions', - xlabel='year' - ) + w_prev_df["total_under5_prop"].plot(kind='bar', stacked=True, + title="Wasting prevalence in children 0-59 months per year", + ylabel='proportions', + xlabel='year', + ylim=[0, 0.05]) + + plt.show() + + def plot_wasting_prevalence_by_age_group(self): + """ plot wasting prevalence per each age group. Proportions are obtained by getting a total number of + children wasted in a particular age group divide by the total number of children per that age group""" + w_prev_df = self.__logs_dict["wasting_prevalence_count"] + w_prev_df.drop(columns={'total_under5_prop'}, inplace=True) + w_prev_df.set_index(w_prev_df.date.dt.year, inplace=True) + w_prev_df = w_prev_df.loc[w_prev_df.index == 2023] + w_prev_df.drop(columns='date', inplace=True) + # plot wasting prevalence + w_prev_df.squeeze().plot(kind='bar', stacked=False, + title="Wasting prevalence in children 0-59 months per age group", + ylabel='proportions', + xlabel='year', + ylim=[0, 0.1]) + + plt.show() def plot_modal_gbd_deaths_by_gender(self): """ compare modal and GBD deaths by gender """ @@ -124,6 +158,7 @@ def plot_modal_gbd_deaths_by_gender(self): outputs / ('modal_gbd_deaths_by_gender' + datestamp + ".pdf"), format="pdf" ) + plt.show() if __name__ == "__main__": @@ -152,7 +187,7 @@ def plot_modal_gbd_deaths_by_gender(self): # Basic arguments required for the simulation start_date = Date(2010, 1, 1) end_date = Date(2030, 1, 2) - pop_size = 30000 + pop_size = 20000 # Create simulation instance for this run. sim = Simulation(start_date=start_date, seed=seed, log_config=log_config) @@ -193,7 +228,10 @@ def plot_modal_gbd_deaths_by_gender(self): wasting_analyses.plot_wasting_incidence() # plot wasting prevalence - wasting_analyses.plot_wasting_prevalence() + wasting_analyses.plot_wasting_prevalence_per_year() + + # plot wasting prevalence by age group + wasting_analyses.plot_wasting_prevalence_by_age_group() # plot wasting deaths by gender as compared to GBD deaths wasting_analyses.plot_modal_gbd_deaths_by_gender() diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 34676eb289..cfc32bdbeb 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1,7 +1,7 @@ """Childhood wasting module""" import copy from pathlib import Path -from typing import Union +from typing import Union, Dict, Any import numpy as np import pandas as pd @@ -1252,29 +1252,22 @@ def apply(self, population): self.date_last_run = self.sim.date # Wasting totals (prevalence at logging time) - currently_wasted_age_0_5mo = (df.is_alive & (df.age_exact_years < 0.5) & (df.un_WHZ_category + under5s = df.loc[df.is_alive & df.age_exact_years < 5] + # declare a dictionary that will hold proportions of wasting prevalence per each age group + wasting_prev_dict: Dict[str, Any] = dict() + # loop through different age groups and get proportions of wasting prevalence per each age group + for low_bound_mos, high_bound_mos in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months + low_bound_age_in_years = low_bound_mos / 12.0 + high_bound_age_in_years = (1 + high_bound_mos) / 12.0 + # get those children who are wasted + wasted_agegrp = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, + inclusive='left') & (under5s.un_WHZ_category != 'WHZ>=-2')).sum() - currently_wasted_age_6_11mo = \ - (df.is_alive & ((df.age_exact_years >= 0.5) & (df.age_exact_years < 1)) - & (df.un_WHZ_category != 'WHZ>=-2')).sum() - currently_wasted_age_12_23mo = \ - (df.is_alive & ((df.age_exact_years >= 1) & (df.age_exact_years < 2)) - & (df.un_WHZ_category != 'WHZ>=-2')).sum() - currently_wasted_age_24_35mo = \ - (df.is_alive & ((df.age_exact_years >= 2) & (df.age_exact_years < 3)) & - (df.un_WHZ_category != 'WHZ>=-2')).sum() - currently_wasted_age_36_47mo = \ - (df.is_alive & ((df.age_exact_years >= 3) & (df.age_exact_years < 4)) & ( - df.un_WHZ_category != 'WHZ>=-2')).sum() - currently_wasted_age_48_59mo = \ - (df.is_alive & ((df.age_exact_years >= 4) & (df.age_exact_years < 5)) & ( - df.un_WHZ_category != 'WHZ>=-2')).sum() - - currently_wasted = {'0_5mo': currently_wasted_age_0_5mo, - '6_11mo': currently_wasted_age_6_11mo, - '12_23mo': currently_wasted_age_12_23mo, - '24_35mo': currently_wasted_age_24_35mo, - '36_47mo': currently_wasted_age_36_47mo, - '48_59mo': currently_wasted_age_48_59mo} - - logger.info(key='wasting_prevalence_count', data=currently_wasted) + total_per_agegrp = (under5s.age_exact_years < high_bound_age_in_years).sum() + # add proportions to the dictionary + wasting_prev_dict[f'{low_bound_mos}_{high_bound_mos}mo'] = wasted_agegrp / total_per_agegrp + + # add to dictionary proportion of all wasted children under 5 years + wasting_prev_dict['total_under5_prop'] = (under5s.un_WHZ_category != 'WHZ>=-2').sum() / len(under5s) + # log wasting prevalence + logger.info(key='wasting_prevalence_count', data=wasting_prev_dict) From 30f480de04479140d49767d34a0ab0520d5f0ab9 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Sun, 17 Mar 2024 09:46:25 +0200 Subject: [PATCH 069/755] added footnote, fixed isort error --- .../wasting_analyses/analysis_wasting.py | 41 +++++++++++++------ src/tlo/methods/wasting.py | 2 +- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index aa9f248955..8c72c501fe 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -9,7 +9,7 @@ from matplotlib import pyplot as plt from tlo import Date, Simulation, logging -from tlo.analysis.utils import compare_number_of_deaths, parse_log_file, unflatten_flattened_multi_index_in_logging +from tlo.analysis.utils import compare_number_of_deaths, parse_log_file from tlo.methods import ( care_of_women_during_pregnancy, contraception, @@ -30,6 +30,13 @@ ) +def add_footnote(fig: plt.Figure, footnote: str): + """ A function that adds a footnote below each plot. Here we are explaining what a denominator for every + graph is """ + fig.figure.text(0.5, 0.01, footnote, ha="center", fontsize=10, + bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) + + class WastingAnalyses: """ This class looks at plotting all important outputs from the wasting module @@ -94,14 +101,6 @@ def plot_wasting_incidence(self): ) plt.show() - def construct_dfs(self) -> dict: - """ Create dict of pd.DataFrames containing counts of different lifestyle properties by date, sex and - age-group """ - return { - k: unflatten_flattened_multi_index_in_logging(v.set_index('date')) - for k, v in self.__logs_dict.items() if k in ['wasting_prevalence_count'] - } - def plot_wasting_prevalence_per_year(self): """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of children wasted divide by the total number of children less than 5 years""" @@ -109,29 +108,44 @@ def plot_wasting_prevalence_per_year(self): w_prev_df = w_prev_df[['date', 'total_under5_prop']] w_prev_df.set_index(w_prev_df.date.dt.year, inplace=True) w_prev_df.drop(columns='date', inplace=True) + fig, ax = plt.subplots() w_prev_df["total_under5_prop"].plot(kind='bar', stacked=True, + ax=ax, title="Wasting prevalence in children 0-59 months per year", ylabel='proportions', xlabel='year', ylim=[0, 0.05]) - + add_footnote(fig, "Proportion = total number of wasted children < 5 years / total number of children < 5 years") + plt.tight_layout() + fig.savefig( + outputs / ('wasting_prevalence_per_year' + datestamp + ".pdf"), + format="pdf" + ) plt.show() def plot_wasting_prevalence_by_age_group(self): """ plot wasting prevalence per each age group. Proportions are obtained by getting a total number of - children wasted in a particular age group divide by the total number of children per that age group""" + children wasted in a particular age-group divide by the total number of children per that age-group""" w_prev_df = self.__logs_dict["wasting_prevalence_count"] w_prev_df.drop(columns={'total_under5_prop'}, inplace=True) w_prev_df.set_index(w_prev_df.date.dt.year, inplace=True) w_prev_df = w_prev_df.loc[w_prev_df.index == 2023] w_prev_df.drop(columns='date', inplace=True) + fig, ax = plt.subplots() # plot wasting prevalence w_prev_df.squeeze().plot(kind='bar', stacked=False, - title="Wasting prevalence in children 0-59 months per age group", + ax=ax, + title="Wasting prevalence in children 0-59 months per each age group in 2023", ylabel='proportions', xlabel='year', ylim=[0, 0.1]) - + add_footnote(fig, "Proportion = total number of wasted children < 5 years per each age-group / total number of " + "children < 5 years per each age-group") + plt.tight_layout() + fig.savefig( + outputs / ('wasting_prevalence_per_each_age_group' + datestamp + ".pdf"), + format="pdf" + ) plt.show() def plot_modal_gbd_deaths_by_gender(self): @@ -154,6 +168,7 @@ def plot_modal_gbd_deaths_by_gender(self): ax.set_ylabel("Number of deaths") ax.legend(loc=2) fig.tight_layout() + add_footnote(fig, "Model output against Global Burden of Diseases(GDB) study data") fig.savefig( outputs / ('modal_gbd_deaths_by_gender' + datestamp + ".pdf"), format="pdf" diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index cfc32bdbeb..48f6668cc2 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1,7 +1,7 @@ """Childhood wasting module""" import copy from pathlib import Path -from typing import Union, Dict, Any +from typing import Any, Dict, Union import numpy as np import pandas as pd From 70302028cd3acfcb91ad6bd0b06ac09ba7a06249 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 11 Feb 2024 22:13:57 +0000 Subject: [PATCH 070/755] RF_Wast, wast: CSV instead of XLSX --- resources/ResourceFile_Wasting.csv | 3 +++ resources/ResourceFile_Wasting.xlsx | 3 --- src/tlo/methods/wasting.py | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 resources/ResourceFile_Wasting.csv delete mode 100644 resources/ResourceFile_Wasting.xlsx diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv new file mode 100644 index 0000000000..102e5d8b6f --- /dev/null +++ b/resources/ResourceFile_Wasting.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b333eeea428a6485db08f9cf908153f01584c9ce3db0d5454160fead11ac289a +size 2489 diff --git a/resources/ResourceFile_Wasting.xlsx b/resources/ResourceFile_Wasting.xlsx deleted file mode 100644 index ba9dbdfdaa..0000000000 --- a/resources/ResourceFile_Wasting.xlsx +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4c48a15d0fcbcd71c7170ad87e7b32d8413866b6283ef8cc96212e5d26b7efaf -size 12127 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 48f6668cc2..aad8457ceb 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -205,7 +205,8 @@ def read_parameters(self, data_folder): # Update parameters from the resource dataframe # Read parameters from the resource file self.load_parameters_from_dataframe( - pd.read_excel(Path(self.resourcefilepath) / 'ResourceFile_Wasting.xlsx', sheet_name='Parameter_values_AM')) + pd.read_csv(Path(self.resourcefilepath) / 'ResourceFile_Wasting.csv') + ) # Register wasting symptom(weight loss) in Symptoms Manager self.sim.modules['SymptomManager'].register_symptom(Symptom(name=self.wasting_symptom)) From 6f398bbcca6d759df95d5c1f0e76c80d81372d24 Mon Sep 17 00:00:00 2001 From: mnjowe Date: Fri, 19 Jul 2024 10:27:06 +0200 Subject: [PATCH 071/755] added wasting scenario run file for azure --- .../wasting_analyses/scenario_wasting.py | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/scripts/wasting_analyses/scenario_wasting.py diff --git a/src/scripts/wasting_analyses/scenario_wasting.py b/src/scripts/wasting_analyses/scenario_wasting.py new file mode 100644 index 0000000000..65832556c6 --- /dev/null +++ b/src/scripts/wasting_analyses/scenario_wasting.py @@ -0,0 +1,76 @@ +""" +This file defines a scenario for wasting analysis. + +It can be submitted on Azure Batch by running: + + tlo batch-submit src/scripts/wasting_analyses/scenario_wasting.py + +or locally using: + + tlo scenario-run src/scripts/wasting_analyses/scenario_wasting.py +""" +import warnings + +from tlo import Date, logging +from tlo.methods import demography, healthsystem, healthseekingbehaviour, healthburden, symptommanager, \ + enhanced_lifestyle, labour, care_of_women_during_pregnancy, contraception, pregnancy_supervisor, \ + postnatal_supervisor, newborn_outcomes, hiv, tb, epi, wasting +from tlo.scenario import BaseScenario + +# capture warnings during simulation run +warnings.simplefilter('default', (UserWarning, RuntimeWarning)) + + +class WastingAnalysis(BaseScenario): + + def __init__(self): + super().__init__( + seed=0, + start_date=Date(2010, 1, 1), + end_date=Date(2030, 1, 1), + initial_population_size=20_000, + number_of_draws=1, + runs_per_draw=1, + ) + + def log_configuration(self): + return { + 'filename': 'wasting_analysis', + 'directory': './outputs', + "custom_levels": { # Customise the output of specific loggers + "tlo.methods.demography": logging.INFO, + "tlo.methods.population": logging.INFO, + "tlo.methods.wasting": logging.INFO, + '*': logging.WARNING + } + } + + def modules(self): + return [demography.Demography(resourcefilepath=self.resources), + healthsystem.HealthSystem(resourcefilepath=self.resources, + service_availability=['*'], + cons_availability='default'), + healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=self.resources), + healthburden.HealthBurden(resourcefilepath=self.resources), + symptommanager.SymptomManager(resourcefilepath=self.resources), + enhanced_lifestyle.Lifestyle(resourcefilepath=self.resources), + labour.Labour(resourcefilepath=self.resources), + care_of_women_during_pregnancy.CareOfWomenDuringPregnancy( + resourcefilepath=self.resources), + contraception.Contraception(resourcefilepath=self.resources), + pregnancy_supervisor.PregnancySupervisor(resourcefilepath=self.resources), + postnatal_supervisor.PostnatalSupervisor(resourcefilepath=self.resources), + newborn_outcomes.NewbornOutcomes(resourcefilepath=self.resources), + hiv.Hiv(resourcefilepath=self.resources), + tb.Tb(resourcefilepath=self.resources), + epi.Epi(resourcefilepath=self.resources), + wasting.Wasting(resourcefilepath=self.resources)] + + def draw_parameters(self, draw_number, rng): + return {} + + +if __name__ == '__main__': + from tlo.cli import scenario_run + + scenario_run([__file__]) From b0b882776befa83b128118d9e8779da367b4209c Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 23 Jul 2024 22:09:16 +0100 Subject: [PATCH 072/755] Merge branch 'master' into hallett/wasting_module # Conflicts: # resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx # src/tlo/methods/hsi_generic_first_appts.py --- .github/workflows/run-profiling.yaml | 42 +- README.md | 60 ++ deploy/Dockerfile | 2 +- deploy/deploy.sh | 2 +- README.rst => docs/getting_started.rst | 6 +- docs/index.rst | 2 +- docs/publications.rst | 2 +- docs/readme.rst | 1 - docs/write-ups/Depression.docx | 4 +- docs/write-ups/OesophagealCancer.docx | 4 +- docs/write-ups/OtherAdultCancer.docx | 4 +- pyproject.toml | 4 +- requirements/dev.txt | 2 + resources/ResourceFile_Bladder_Cancer.xlsx | 2 +- resources/ResourceFile_Depression.xlsx | 4 +- resources/ResourceFile_HIV.xlsx | 4 +- ...d_Healthsystem_And_Healthcare_Seeking.xlsx | 4 +- .../ResourceFile_Other_Adult_Cancers.xlsx | 4 +- resources/ResourceFile_RTI.xlsx | 4 +- resources/ResourceFile_TB.xlsx | 4 +- .../cmd/ResourceFile_cmd_condition_death.xlsx | 4 +- .../cmd/ResourceFile_cmd_condition_onset.xlsx | 4 +- .../ResourceFile_cmd_condition_removal.xlsx | 4 +- .../ResourceFile_cmd_condition_testing.xlsx | 4 +- resources/cmd/ResourceFile_cmd_events.xlsx | 4 +- .../cmd/ResourceFile_cmd_events_death.xlsx | 4 +- resources/costing/ResourceFile_Costing.xlsx | 3 + .../ResourceFile_HealthSystem_parameters.csv | 4 +- ...urceFile_Consumables_Item_Designations.csv | 3 + ...rceFile_Consumables_Items_and_Packages.csv | 4 +- ...rceFile_Consumables_availability_small.csv | 4 +- .../ResourceFile_consumables_matched.csv | 4 +- .../ResourceFile_const_HR_scaling.xlsx | 3 - .../ResourceFile_HR_scaling_by_district.xlsx | 3 + ..._HR_scaling_by_level_and_officer_type.xlsx | 3 + .../ResourceFile_dynamic_HR_scaling.xlsx | 3 + .../ResourceFile_EquipmentCatalogue.csv | 3 + ...eFile_Equipment_Availability_Estimates.csv | 3 + ...ourceFile_PriorityRanking_ALLPOLICIES.xlsx | 4 +- resources/malaria/ResourceFile_malaria.xlsx | 4 +- .../breast_cancer_analyses.py | 12 +- .../calc_5y_survival_following_treatment.py | 21 +- .../consumables_availability_estimation.py | 8 +- ...ate_consumables_item_codes_and_packages.py | 53 +- .../equipment_availability_estimation.py | 356 +++++++ ...pact_of_capabilities_expansion_combined.py | 265 +++++ ...mpact_of_capabilities_expansion_scaling.py | 336 +++++++ ..._of_capabilities_expansion_test_scaling.py | 152 +++ ..._impact_of_const_capabilities_expansion.py | 183 ++++ .../scenario_impact_of_policy.py | 3 +- .../analysis_full_model.py | 4 +- .../analysis_logged_deviance.py | 4 +- .../analysis_htm_scaleup.py | 112 +++ .../htm_scenario_analyses/scenario_plots.py | 139 +++ src/scripts/malaria/analysis_malaria.py | 15 +- .../calc_5y_survival_following_treatment.py | 19 +- .../oesophagealcancer_analyses.py | 11 +- .../calc_5y_survival_following_treatment.py | 25 +- .../other_adult_cancers_analyses.py | 11 +- .../scenario_impact_of_healthsystem.py | 20 +- src/scripts/profiling/run_profiling.py | 62 +- src/scripts/profiling/scale_run.py | 7 + .../calc_5y_survival_following_treatment.py | 36 +- .../prostate_cancer_analyses.py | 13 +- .../schistosomiasis/schisto_analysis.py | 25 +- src/tlo/analysis/hsi_events.py | 5 +- src/tlo/analysis/utils.py | 52 +- src/tlo/cli.py | 50 +- src/tlo/core.py | 23 +- src/tlo/methods/alri.py | 225 ++--- src/tlo/methods/bed_days.py | 38 +- src/tlo/methods/bladder_cancer.py | 340 ++++--- src/tlo/methods/breast_cancer.py | 197 ++-- src/tlo/methods/cancer_consumables.py | 77 ++ src/tlo/methods/cardio_metabolic_disorders.py | 219 +++-- .../methods/care_of_women_during_pregnancy.py | 364 ++++--- src/tlo/methods/chronicsyndrome.py | 26 +- src/tlo/methods/consumables.py | 127 ++- src/tlo/methods/contraception.py | 84 +- src/tlo/methods/copd.py | 116 ++- src/tlo/methods/demography.py | 63 +- src/tlo/methods/depression.py | 249 +++-- src/tlo/methods/diarrhoea.py | 104 +- src/tlo/methods/dxmanager.py | 14 +- src/tlo/methods/epi.py | 2 +- src/tlo/methods/epilepsy.py | 52 +- src/tlo/methods/equipment.py | 289 ++++++ src/tlo/methods/healthseekingbehaviour.py | 23 +- src/tlo/methods/healthsystem.py | 921 +++++++++--------- src/tlo/methods/hiv.py | 558 ++++++++--- src/tlo/methods/hsi_event.py | 465 +++++++++ src/tlo/methods/hsi_generic_first_appts.py | 595 +++++------ src/tlo/methods/labour.py | 371 ++++--- src/tlo/methods/malaria.py | 366 ++++--- src/tlo/methods/measles.py | 27 +- src/tlo/methods/mockitis.py | 25 +- src/tlo/methods/newborn_outcomes.py | 70 +- src/tlo/methods/oesophagealcancer.py | 193 ++-- src/tlo/methods/other_adult_cancers.py | 208 ++-- src/tlo/methods/postnatal_supervisor.py | 36 +- src/tlo/methods/pregnancy_helper_functions.py | 17 +- src/tlo/methods/pregnancy_supervisor.py | 49 +- src/tlo/methods/prostate_cancer.py | 233 +++-- src/tlo/methods/rti.py | 306 ++++-- src/tlo/methods/scenario_switcher.py | 83 +- src/tlo/methods/schisto.py | 49 +- src/tlo/methods/skeleton.py | 2 +- src/tlo/methods/stunting.py | 67 +- src/tlo/methods/symptommanager.py | 98 +- src/tlo/methods/tb.py | 691 +++++++------ src/tlo/methods/wasting.py | 48 +- src/tlo/population.py | 167 +++- src/tlo/scenario.py | 51 +- src/tlo/simulation.py | 13 +- src/tlo/test/random_birth.py | 2 +- src/tlo/util.py | 27 +- tests/resources/scenario.py | 35 + tests/test_alri.py | 81 +- tests/test_analysis.py | 597 +++++++----- tests/test_basic_sims.py | 2 +- tests/test_beddays.py | 83 +- tests/test_bitset.py | 16 +- tests/test_cardiometabolicdisorders.py | 2 +- tests/test_consumables.py | 117 ++- tests/test_copd.py | 16 +- tests/test_core.py | 4 +- tests/test_demography.py | 28 + tests/test_diarrhoea.py | 76 +- tests/test_dxmanager.py | 4 +- tests/test_equipment.py | 480 +++++++++ tests/test_healthsystem.py | 228 ++++- tests/test_hiv.py | 27 +- tests/test_hiv_tb_scenarios.py | 270 ----- tests/test_htm_scaleup.py | 210 ++++ tests/test_labour.py | 2 +- tests/test_logging.py | 2 +- tests/test_malaria.py | 177 ++-- ...al_health_helper_and_analysis_functions.py | 12 +- tests/test_module_dependencies.py | 6 +- tests/test_population.py | 216 ++++ tests/test_rti.py | 8 +- tests/test_scenario.py | 68 ++ tests/test_stunting.py | 82 +- tests/test_symptommanager.py | 145 ++- tests/test_tb.py | 67 +- 145 files changed, 9966 insertions(+), 3697 deletions(-) create mode 100644 README.md rename README.rst => docs/getting_started.rst (92%) delete mode 100644 docs/readme.rst create mode 100644 resources/costing/ResourceFile_Costing.xlsx create mode 100644 resources/healthsystem/consumables/ResourceFile_Consumables_Item_Designations.csv delete mode 100644 resources/healthsystem/human_resources/const_HR_scaling/ResourceFile_const_HR_scaling.xlsx create mode 100644 resources/healthsystem/human_resources/scaling_capabilities/ResourceFile_HR_scaling_by_district.xlsx create mode 100644 resources/healthsystem/human_resources/scaling_capabilities/ResourceFile_HR_scaling_by_level_and_officer_type.xlsx create mode 100644 resources/healthsystem/human_resources/scaling_capabilities/ResourceFile_dynamic_HR_scaling.xlsx create mode 100644 resources/healthsystem/infrastructure_and_equipment/ResourceFile_EquipmentCatalogue.csv create mode 100644 resources/healthsystem/infrastructure_and_equipment/ResourceFile_Equipment_Availability_Estimates.csv create mode 100644 src/scripts/data_file_processing/healthsystem/equipment/equipment_availability_estimation.py create mode 100644 src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_capabilities_expansion_combined.py create mode 100644 src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_capabilities_expansion_scaling.py create mode 100644 src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_capabilities_expansion_test_scaling.py create mode 100644 src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_const_capabilities_expansion.py create mode 100644 src/scripts/htm_scenario_analyses/analysis_htm_scaleup.py create mode 100644 src/scripts/htm_scenario_analyses/scenario_plots.py create mode 100644 src/tlo/methods/cancer_consumables.py create mode 100644 src/tlo/methods/equipment.py create mode 100644 src/tlo/methods/hsi_event.py create mode 100644 tests/resources/scenario.py create mode 100644 tests/test_equipment.py delete mode 100644 tests/test_hiv_tb_scenarios.py create mode 100644 tests/test_htm_scaleup.py create mode 100644 tests/test_population.py create mode 100644 tests/test_scenario.py diff --git a/.github/workflows/run-profiling.yaml b/.github/workflows/run-profiling.yaml index 10b05f4748..a28acda1b0 100644 --- a/.github/workflows/run-profiling.yaml +++ b/.github/workflows/run-profiling.yaml @@ -31,17 +31,39 @@ jobs: set-variables: name: Create unique output file identifier and artifact name runs-on: ubuntu-latest + if: (github.event_name != 'issue_comment') || ((github.event_name == 'issue_comment') && (github.event.comment.body == '/run profiling')) outputs: profiling-output-dir: profiling_results/ profiling-filename: ${{ steps.set-profiling-filename.outputs.name }} artifact-name: ${{ steps.set-artifact-name.outputs.name }} - profiling-on-sha: ${{ steps.set-github-info.outputs.sha }} + profiling-on-sha: ${{ steps.determine-correct-sha.outputs.result }} profiling-event-trigger: ${{ steps.set-github-info.outputs.event }} steps: + - id: determine-if-pr-comment + name: Determine if this is a PR comment + run: | + if ! [ -z "${{ github.event.issue.pull_request }}" ]; then echo "is-pr=true" >> "${GITHUB_OUTPUT}"; else echo "is-pr=false" >> "${GITHUB_OUTPUT}"; fi + + - id: determine-correct-sha + name: Determine the SHA to run profiling on + uses: actions/github-script@v7 + with: + result-encoding: string + script: | + if ("${{ steps.determine-if-pr-comment.outputs.is-pr }}" === "true") { + const { data: pr } = await github.rest.pulls.get({ + owner: context.issue.owner, + repo: context.issue.repo, + pull_number: context.issue.number, + }); + return pr.head.sha; + }; + return context.sha; + - id: set-profiling-filename name: Set profiling output file name run: | - echo "name=${GITHUB_EVENT_NAME}_${GITHUB_RUN_NUMBER}_${GITHUB_SHA}" >> "${GITHUB_OUTPUT}" + echo "name=${GITHUB_EVENT_NAME}_${GITHUB_RUN_NUMBER}_${{ steps.determine-correct-sha.outputs.result }}" >> "${GITHUB_OUTPUT}" - id: set-artifact-name name: Set artifact name @@ -51,7 +73,7 @@ jobs: - id: set-github-info name: Fix Git and GitHub information when passing between workflows run: | - echo "sha=${GITHUB_SHA}" >> "${GITHUB_OUTPUT}" + echo "sha=${{ steps.determine-correct-sha.outputs.result }}" >> "${GITHUB_OUTPUT}" echo "event=${GITHUB_EVENT_NAME}" >> "${GITHUB_OUTPUT}" profile-on-comment: @@ -60,16 +82,18 @@ jobs: needs: set-variables uses: ./.github/workflows/run-on-comment.yml with: - runs-on: '["self-hosted", "test"]' + runs-on: '["self-hosted", "profiling"]' keyword: profiling commands: | tox -vv -e profile -- \ --html \ + --flat-html \ --root-output-dir ${{ needs.set-variables.outputs.profiling-output-dir }} \ --output-name ${{ needs.set-variables.outputs.profiling-filename }} \ --additional-stats \ sha=${{ needs.set-variables.outputs.profiling-on-sha }} \ - trigger=${{ needs.set-variables.outputs.profiling-event-trigger }} + trigger=${{ needs.set-variables.outputs.profiling-event-trigger }} \ + --disable-log-output-to-stdout description: Profiled run of the model timeout-minutes: 8640 application-organization: UCL @@ -84,7 +108,7 @@ jobs: name: Scheduled / dispatch triggered profiling if: ${{ github.event_name != 'issue_comment' }} needs: set-variables - runs-on: [self-hosted, test] + runs-on: [self-hosted, profiling] timeout-minutes: 8640 steps: - name: Checkout repository @@ -98,11 +122,13 @@ jobs: run: | tox -vv -e profile -- \ --html \ + --flat-html \ --root-output-dir ${{ needs.set-variables.outputs.profiling-output-dir }} \ --output-name ${{ needs.set-variables.outputs.profiling-filename }} \ --additional-stats \ sha=${{ needs.set-variables.outputs.profiling-on-sha }} \ - trigger=${{ needs.set-variables.outputs.profiling-event-trigger }} + trigger=${{ needs.set-variables.outputs.profiling-event-trigger }} \ + --disable-log-output-to-stdout ## Upload the output as an artifact so we can push it to the profiling repository - name: Save results as artifact @@ -137,7 +163,7 @@ jobs: ## The token provided needs contents and pages access to the target repo ## Token can be (re)generated by a member of the UCL organisation, ## the current member is the rc-softdev-admin. - ## [10-07-2023] The current token will expire 10-07-2024 + ## [17-07-2024] New token generated, will expire 10-07-2025 - name: Push results to profiling repository uses: dmnemec/copy_file_to_another_repo_action@v1.1.1 env: diff --git a/README.md b/README.md new file mode 100644 index 0000000000..eadcbd2c60 --- /dev/null +++ b/README.md @@ -0,0 +1,60 @@ +
+Thanzi La Onze +
+

Thanzi la Onse model

+
+ +[![License][license-badge]](./LICENSE.txt) +[![DOI][doi-badge]][doi-link] +[![Tests status][tests-badge]][tests-link] +[![Checks status][checks-badge]][checks-link] +[![Documentation status][documentation-badge]][documentation-link] + +The __Thanzi la Onse model (TLOmodel)__ is a part of the [Thanzi la Onse][thanzi-link] +(Health for All) Collaboration. Our fundamental aim is to develop the use of epidemiological and economic science to effect a step-change in the way that health priorities are addressed through policy interventions in low-income countries. We are doing this by developing a model that represents explicitly the generation of health gains in a population, which can be used to examine the effect of resource allocation, management and clinical practice, in order to contribute to informing decision-making. + +- __Documentation__: +- __Getting started__: +- __Contributing__: +- __Bug reports__: +- __Wiki__: + +## Project team + +TLOmodel is developed in a collaboration between: + +- [Kamuzu University of Health Sciences][kuhes-link] +- [MRC Centre for Global Infectioous Disease Analysis][mrc-gida-link], [Imperial College London][imperial-link] +- [Institute for Global Health][igh-link], [University College London][ucl-link] +- [Centre for Advanced Research Computing][arc-link], [University College London][ucl-link] +- [Centre for Health Economics][che-link], [University of York][york-link] + +It benefits from a close partnership between this team and the Ministry of Health, Malawi. + +A [full list of contributors][contributors-link] is available +in the documentation. + +## Acknowledgements + +This work has been funded by grants from [Wellcome](https://wellcome.org/), +[GCRF](https://www.newton-gcrf.org/) and [UKRI](https://www.ukri.org/). + +[tests-badge]: https://github.com/UCL/TLOmodel/actions/workflows/tests.yml/badge.svg +[tests-link]: https://github.com/UCL/TLOmodel/actions/workflows/tests.yml +[checks-badge]: https://github.com/UCL/TLOmodel/actions/workflows/checks.yml/badge.svg +[checks-link]: https://github.com/UCL/TLOmodel/actions/workflows/checks.yml +[documentation-badge]: https://github.com/UCL/TLOmodel/actions/workflows/docs.yml/badge.svg +[documentation-link]: https://github.com/UCL/TLOmodel/actions/workflows/docs.yml +[license-badge]: https://img.shields.io/badge/License-MIT-blue.svg +[doi-badge]: https://zenodo.org/badge/DOI/10.5281/zenodo.10144015.svg +[doi-link]: https://doi.org/10.5281/zenodo.10144015 +[thanzi-link]: https://thanzi.org +[kuhes-link]: https://www.kuhes.ac.mw/ +[imperial-link]: https://www.imperial.ac.uk +[mrc-gida-link]: https://www.imperial.ac.uk/mrc-global-infectious-disease-analysis +[ucl-link]: https://www.ucl.ac.uk +[igh-link]: https://www.ucl.ac.uk/global-health/ +[arc-link]: https://www.ucl.ac.uk/arc +[york-link]: https://www.york.ac.uk/ +[che-link]: https://www.york.ac.uk/che/ +[contributors-link]: https://www.tlomodel.org/contributors.html diff --git a/deploy/Dockerfile b/deploy/Dockerfile index 00bd10b483..23b460ebd1 100644 --- a/deploy/Dockerfile +++ b/deploy/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.8-slim-buster +FROM python:3.11-slim-bookworm # Setup SSH RUN mkdir /root/.ssh diff --git a/deploy/deploy.sh b/deploy/deploy.sh index 14b749bf75..3e1ccfefb4 100755 --- a/deploy/deploy.sh +++ b/deploy/deploy.sh @@ -5,7 +5,7 @@ set -e REGISTRY_NAME="tlob1acr" REGISTRY_URL="${REGISTRY_NAME}.azurecr.io" IMAGE_NAME="tlo" -IMAGE_TAG="1.2" +IMAGE_TAG="1.3" IMAGE_FULL_NAME="${IMAGE_NAME}:${IMAGE_TAG}" # Documentation at diff --git a/README.rst b/docs/getting_started.rst similarity index 92% rename from README.rst rename to docs/getting_started.rst index ec6d079815..7dd9e56254 100644 --- a/README.rst +++ b/docs/getting_started.rst @@ -1,6 +1,3 @@ -.. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.10144015.svg - :target: https://zenodo.org/doi/10.5281/zenodo.10144015 - ===================== Getting Started ===================== @@ -22,7 +19,8 @@ you prefer, you can carry out the setup using the command line: :: - conda create -n tlo python=3.8 + cd TLOmodel + conda create -n tlo python=3.11 conda activate tlo pip install -r requirements/dev.txt pip install -e . diff --git a/docs/index.rst b/docs/index.rst index 18362b728c..9de9d148d1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -48,7 +48,7 @@ Contents aims writeups data_sources - readme + getting_started azure_batch reference/index resources/index diff --git a/docs/publications.rst b/docs/publications.rst index 0c87c6eb7a..77ae7ef93a 100644 --- a/docs/publications.rst +++ b/docs/publications.rst @@ -19,7 +19,7 @@ Analyses Using The Model * `Modeling Contraception and Pregnancy in Malawi: A Thanzi La Onse Mathematical Modeling Study `_ -* `Factors Associated with Consumable Stock-Outs in Malawi: Evidence from a Facility Census `_ +* `Factors Associated with Consumable Stock-Outs in Malawi: Evidence from a Facility Census `_ * `The Effects of Health System Frailties on the Projected Impact of the HIV and TB Programmes in Malawi `_ diff --git a/docs/readme.rst b/docs/readme.rst deleted file mode 100644 index 72a3355815..0000000000 --- a/docs/readme.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../README.rst diff --git a/docs/write-ups/Depression.docx b/docs/write-ups/Depression.docx index 0d03c044b6..b2af7525c6 100644 --- a/docs/write-ups/Depression.docx +++ b/docs/write-ups/Depression.docx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:74cc9af2d9e114bee5f695cddcab49c92d79b6fa5abd7c8bb59b1c2a284b8ead -size 233268 +oid sha256:947d9954ead452370841b3e8bec8b6bf17fcea40e240ea342dcf169e6c6bb68d +size 235099 diff --git a/docs/write-ups/OesophagealCancer.docx b/docs/write-ups/OesophagealCancer.docx index 80654e9cb9..c52e9e261a 100644 --- a/docs/write-ups/OesophagealCancer.docx +++ b/docs/write-ups/OesophagealCancer.docx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ae9f447c5ab5d296f4d5d766a0675865998e386c5b17c97095e36799435f9277 -size 180430 +oid sha256:ef6ac87512767a2c70dc67d22f5c409c425bf26736624ba039285a1d906750ca +size 185471 diff --git a/docs/write-ups/OtherAdultCancer.docx b/docs/write-ups/OtherAdultCancer.docx index 99c7c562e1..42bf5f2b09 100644 --- a/docs/write-ups/OtherAdultCancer.docx +++ b/docs/write-ups/OtherAdultCancer.docx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:299b9025a1fe1fad73a42ed321061e655e638a9c3ce8ab67e3ee691815ae6d98 -size 71556 +oid sha256:1f3ff79a3f4e2ad48981cffd95eb6d96d7aa3dc8777015e2b71e63995bf336c9 +size 76152 diff --git a/pyproject.toml b/pyproject.toml index 25aae73d33..f18a736844 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,7 @@ dependencies = [ description = "Thanzi la Onse Epidemiology Model" dynamic = ["version"] license = {file = "LICENSE.txt"} -readme = "README.rst" +readme = "README.md" requires-python = ">=3.8" [project.optional-dependencies] @@ -56,6 +56,7 @@ dev = [ "pylint", "ruff", # Profiling + "ansi2html", "psutil", "pyinstrument>=4.3", # Building requirements files @@ -94,6 +95,7 @@ disable = [ "R", "C", "W", + "E0606", # possibly-used-before-assignment - gives a lot of false positives ] diff --git a/requirements/dev.txt b/requirements/dev.txt index d34d5cead1..efd4f0e3e8 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -6,6 +6,8 @@ # adal==1.2.7 # via msrestazure +ansi2html==1.9.1 + # via tlo (pyproject.toml) astroid==3.0.0 # via pylint azure-batch==14.0.0 diff --git a/resources/ResourceFile_Bladder_Cancer.xlsx b/resources/ResourceFile_Bladder_Cancer.xlsx index f6b7290213..74e26b31a8 100644 --- a/resources/ResourceFile_Bladder_Cancer.xlsx +++ b/resources/ResourceFile_Bladder_Cancer.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0801d6c43263854111fa13779db68c2c426bd99f517860cad73bbbee2e4b3334 +oid sha256:7ae80b76d054f9223f15e5a592189bd732a397810192990bfa63fb3dec393fb5 size 10954 diff --git a/resources/ResourceFile_Depression.xlsx b/resources/ResourceFile_Depression.xlsx index c4feb268fa..b6daab2002 100644 --- a/resources/ResourceFile_Depression.xlsx +++ b/resources/ResourceFile_Depression.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0bb3ed875059fa60e8708db0c19da56942d46297c07185849b1ff604f9c67ca8 -size 12357 +oid sha256:d7016feb63786ef5e87ed199dd79f8b6b4a8b8ead227196a4fb578bf33bc1a2f +size 12432 diff --git a/resources/ResourceFile_HIV.xlsx b/resources/ResourceFile_HIV.xlsx index 6e73cf07fe..f76169e701 100644 --- a/resources/ResourceFile_HIV.xlsx +++ b/resources/ResourceFile_HIV.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d20e316c9b00816da27cc8c104b70cec214787f0d96c80a437f8690806c5e2fb -size 158196 +oid sha256:913d736db7717519270d61824a8855cbfd4d6e61a73b7ce51e2c3b7915b011ff +size 161597 diff --git a/resources/ResourceFile_Improved_Healthsystem_And_Healthcare_Seeking.xlsx b/resources/ResourceFile_Improved_Healthsystem_And_Healthcare_Seeking.xlsx index 5b2d55972e..8fc0a24ae9 100644 --- a/resources/ResourceFile_Improved_Healthsystem_And_Healthcare_Seeking.xlsx +++ b/resources/ResourceFile_Improved_Healthsystem_And_Healthcare_Seeking.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f18f5a91e48fc846c332b55f1742d148816b1fee08ee34383c9995ea36dafdb3 -size 48167 +oid sha256:1b462c20ca6cbf0ca1f98936416e015fa248289e5bf4f66838e1b9920874f651 +size 48142 diff --git a/resources/ResourceFile_Other_Adult_Cancers.xlsx b/resources/ResourceFile_Other_Adult_Cancers.xlsx index bf6997cb24..160247c80d 100644 --- a/resources/ResourceFile_Other_Adult_Cancers.xlsx +++ b/resources/ResourceFile_Other_Adult_Cancers.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:be37486adb1684f56f4a03a490b7a952d5ddd4e0a19b5aa146d5aaee8dc5e680 -size 10830 +oid sha256:3d7a8daecbf8a3a6fb7efdcefffb5ece5e91c6abc811da5a038e4fc1fbb44774 +size 10865 diff --git a/resources/ResourceFile_RTI.xlsx b/resources/ResourceFile_RTI.xlsx index 68cdd18422..553d6febb0 100644 --- a/resources/ResourceFile_RTI.xlsx +++ b/resources/ResourceFile_RTI.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2c11ada2e8b77675950b61fc8e0efd1c4fa35dffaecaf1029eafd61892a7cefb -size 13949 +oid sha256:d950c5d769848fb226db8c1a7d7796c8e43cc2590806f846b98a4bbef6840948 +size 13776 diff --git a/resources/ResourceFile_TB.xlsx b/resources/ResourceFile_TB.xlsx index 494e6b31fd..3dfc69cd81 100644 --- a/resources/ResourceFile_TB.xlsx +++ b/resources/ResourceFile_TB.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6760fe2b529eb1538bbbfbd6d5e7350f9dbc2272ab997b363771c8b901739bb3 -size 54894 +oid sha256:120d687122772909c267db41c933664ccc6247c8aef59d49532547c0c3791121 +size 55634 diff --git a/resources/cmd/ResourceFile_cmd_condition_death.xlsx b/resources/cmd/ResourceFile_cmd_condition_death.xlsx index 725996cd2c..536c8ebbc9 100644 --- a/resources/cmd/ResourceFile_cmd_condition_death.xlsx +++ b/resources/cmd/ResourceFile_cmd_condition_death.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bedbf3304e4078e2d495a136eb838757fa06d0e5c7cad13714ba469f1c9a63ae -size 19087 +oid sha256:b13090d0ecf6d95c6001133bed733a1642f5e698cc0f048d7526357506088862 +size 19200 diff --git a/resources/cmd/ResourceFile_cmd_condition_onset.xlsx b/resources/cmd/ResourceFile_cmd_condition_onset.xlsx index d53e29356f..292f9b0f7b 100644 --- a/resources/cmd/ResourceFile_cmd_condition_onset.xlsx +++ b/resources/cmd/ResourceFile_cmd_condition_onset.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:154eb80d1676dd56bd832b77bcd40965ab9c69ee9dc6c146d1a3613cac2848a6 -size 30573 +oid sha256:b7db0f7a4aca08cdb1852bde35262295c294354a1838b72d65fb14b5cc257364 +size 30669 diff --git a/resources/cmd/ResourceFile_cmd_condition_removal.xlsx b/resources/cmd/ResourceFile_cmd_condition_removal.xlsx index 801b4b69f9..49a7ea79ee 100644 --- a/resources/cmd/ResourceFile_cmd_condition_removal.xlsx +++ b/resources/cmd/ResourceFile_cmd_condition_removal.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b66ae1f6017e1c506970092b975bd6d002dacce13e5c325e59b17cee984eec2f -size 18556 +oid sha256:b0d42326a048511264bedf856bb757d0a609ac01361ea1da2b0ed89c066dfa8b +size 18625 diff --git a/resources/cmd/ResourceFile_cmd_condition_testing.xlsx b/resources/cmd/ResourceFile_cmd_condition_testing.xlsx index 63b6baf08f..ead6ce011e 100644 --- a/resources/cmd/ResourceFile_cmd_condition_testing.xlsx +++ b/resources/cmd/ResourceFile_cmd_condition_testing.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3fbe4450eb795d3f3c42f71e459f1e703ec4e9aa41c75ed738a6f9c098c5db53 -size 11437 +oid sha256:82ad9558d816133b020e942c7962b1c783469fa3ba322db164a7305c60caf698 +size 11491 diff --git a/resources/cmd/ResourceFile_cmd_events.xlsx b/resources/cmd/ResourceFile_cmd_events.xlsx index cce09206ec..a7d2cb9bae 100644 --- a/resources/cmd/ResourceFile_cmd_events.xlsx +++ b/resources/cmd/ResourceFile_cmd_events.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1a34707bd325d919b8e94cb7135e5a3f17da4bca67d8cc2023418f7b1099e070 -size 14047 +oid sha256:1419799a637737654950aa137f2f7fd131a934deea6fa2e48ee5b37e531e4517 +size 14104 diff --git a/resources/cmd/ResourceFile_cmd_events_death.xlsx b/resources/cmd/ResourceFile_cmd_events_death.xlsx index 1dc7d3d67a..1983a2f88e 100644 --- a/resources/cmd/ResourceFile_cmd_events_death.xlsx +++ b/resources/cmd/ResourceFile_cmd_events_death.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a9f6e0e87f17ac90e074eb9434c90f67ec6207f3475c11e4340ba38fe2e94e13 -size 13343 +oid sha256:328f3c2a624dbbf9072712f573213c744dee7f962f854475b08ffb2a306392c0 +size 13425 diff --git a/resources/costing/ResourceFile_Costing.xlsx b/resources/costing/ResourceFile_Costing.xlsx new file mode 100644 index 0000000000..9f06132aaa --- /dev/null +++ b/resources/costing/ResourceFile_Costing.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2afa3649672e10c9741b26dc70fa0f4496af4fccfafbf8b7b70f3b90b291a4fb +size 1007463 diff --git a/resources/healthsystem/ResourceFile_HealthSystem_parameters.csv b/resources/healthsystem/ResourceFile_HealthSystem_parameters.csv index 2828a9376c..8c670a914d 100644 --- a/resources/healthsystem/ResourceFile_HealthSystem_parameters.csv +++ b/resources/healthsystem/ResourceFile_HealthSystem_parameters.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e36cbd225191f893f2de5f0f34adc251046af5ec58daaf7c86b09a6c83c1e31d -size 379 +oid sha256:f1cb38ba76c5673855e2e17e28ad1d36b5cec07d5d7872a7d6bc8aafde0f7009 +size 828 diff --git a/resources/healthsystem/consumables/ResourceFile_Consumables_Item_Designations.csv b/resources/healthsystem/consumables/ResourceFile_Consumables_Item_Designations.csv new file mode 100644 index 0000000000..ace9042583 --- /dev/null +++ b/resources/healthsystem/consumables/ResourceFile_Consumables_Item_Designations.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c953a6136e61fe55181e477e6c1425ec010ac55b180351f0f466da2c2eb0d379 +size 67854 diff --git a/resources/healthsystem/consumables/ResourceFile_Consumables_Items_and_Packages.csv b/resources/healthsystem/consumables/ResourceFile_Consumables_Items_and_Packages.csv index 8af8f070b2..0ee403abb0 100644 --- a/resources/healthsystem/consumables/ResourceFile_Consumables_Items_and_Packages.csv +++ b/resources/healthsystem/consumables/ResourceFile_Consumables_Items_and_Packages.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:85e2c3ba8037e74490751fbb8384709dff1907c785c856f0394f40b4fc024da3 -size 253400 +oid sha256:4106c2e3ae068d40b115857885b673bec3e1114be5183c0a4ae0366560e2a5c9 +size 249391 diff --git a/resources/healthsystem/consumables/ResourceFile_Consumables_availability_small.csv b/resources/healthsystem/consumables/ResourceFile_Consumables_availability_small.csv index 54453cbc2f..25249531b2 100644 --- a/resources/healthsystem/consumables/ResourceFile_Consumables_availability_small.csv +++ b/resources/healthsystem/consumables/ResourceFile_Consumables_availability_small.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:69a5143c0b7307c7bb48726aa73d6c2f61de2a69aeb445eec87494cf9d4a1041 -size 6087331 +oid sha256:c358a643e4def0e574b75f89f83d77f9c3366f668422e005150f4d69ebe8d7a7 +size 6169152 diff --git a/resources/healthsystem/consumables/ResourceFile_consumables_matched.csv b/resources/healthsystem/consumables/ResourceFile_consumables_matched.csv index 7754d65118..7ab675ecba 100644 --- a/resources/healthsystem/consumables/ResourceFile_consumables_matched.csv +++ b/resources/healthsystem/consumables/ResourceFile_consumables_matched.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fbfe91222d3a2a32ed44a4be711b30c5323276a71df802f6c9249eb4c21f8d43 -size 90158 +oid sha256:b5b0f417681cbdd2489e2f9c6634b2825c32beb9637dc045b56e308c910a102c +size 90569 diff --git a/resources/healthsystem/human_resources/const_HR_scaling/ResourceFile_const_HR_scaling.xlsx b/resources/healthsystem/human_resources/const_HR_scaling/ResourceFile_const_HR_scaling.xlsx deleted file mode 100644 index 2b15c3dc39..0000000000 --- a/resources/healthsystem/human_resources/const_HR_scaling/ResourceFile_const_HR_scaling.xlsx +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e9415f5249a5c4ddd2b5ccc3fbf1a64b33132b4b9e379ad079a9539cb109b24e -size 8515 diff --git a/resources/healthsystem/human_resources/scaling_capabilities/ResourceFile_HR_scaling_by_district.xlsx b/resources/healthsystem/human_resources/scaling_capabilities/ResourceFile_HR_scaling_by_district.xlsx new file mode 100644 index 0000000000..a5779ded7b --- /dev/null +++ b/resources/healthsystem/human_resources/scaling_capabilities/ResourceFile_HR_scaling_by_district.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3c091d5870440f2ec30d6592902bdf443b98c069355ca1f78f5671468e7e4e5b +size 9824 diff --git a/resources/healthsystem/human_resources/scaling_capabilities/ResourceFile_HR_scaling_by_level_and_officer_type.xlsx b/resources/healthsystem/human_resources/scaling_capabilities/ResourceFile_HR_scaling_by_level_and_officer_type.xlsx new file mode 100644 index 0000000000..3d804bbc77 --- /dev/null +++ b/resources/healthsystem/human_resources/scaling_capabilities/ResourceFile_HR_scaling_by_level_and_officer_type.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:af86c2c2af5c291c18c5d481681d6d316526b81806c8c8e898517e850160e6fd +size 12465 diff --git a/resources/healthsystem/human_resources/scaling_capabilities/ResourceFile_dynamic_HR_scaling.xlsx b/resources/healthsystem/human_resources/scaling_capabilities/ResourceFile_dynamic_HR_scaling.xlsx new file mode 100644 index 0000000000..a633e6fc92 --- /dev/null +++ b/resources/healthsystem/human_resources/scaling_capabilities/ResourceFile_dynamic_HR_scaling.xlsx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d2d74390498e497ee0bf68773327868f6b199c1c9569337b173fa330c0f2f926 +size 24593 diff --git a/resources/healthsystem/infrastructure_and_equipment/ResourceFile_EquipmentCatalogue.csv b/resources/healthsystem/infrastructure_and_equipment/ResourceFile_EquipmentCatalogue.csv new file mode 100644 index 0000000000..45f801f0c8 --- /dev/null +++ b/resources/healthsystem/infrastructure_and_equipment/ResourceFile_EquipmentCatalogue.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ec5f619816df6150ae92839152607296a5f2289024c92ce6b5ba621d38db20b7 +size 33517 diff --git a/resources/healthsystem/infrastructure_and_equipment/ResourceFile_Equipment_Availability_Estimates.csv b/resources/healthsystem/infrastructure_and_equipment/ResourceFile_Equipment_Availability_Estimates.csv new file mode 100644 index 0000000000..706297da67 --- /dev/null +++ b/resources/healthsystem/infrastructure_and_equipment/ResourceFile_Equipment_Availability_Estimates.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2785365d20a4da4c147ba6a5df9e0259c9076df0fec556086aea0f2a068c9c53 +size 1313098 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx index 6bf85df2db..646c8cfd80 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:20fb355b93941651d041f8b109f5f0f1d188653cad73192a0d36e1eae8533e8c -size 41564 +oid sha256:8a78bd1a7521c5df441f806e28780b55262d0ed1c9f83e834bcf2defba2d6c1d +size 40633 diff --git a/resources/malaria/ResourceFile_malaria.xlsx b/resources/malaria/ResourceFile_malaria.xlsx index 12d3014efb..a6487e80ae 100644 --- a/resources/malaria/ResourceFile_malaria.xlsx +++ b/resources/malaria/ResourceFile_malaria.xlsx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2b703bd5ee7979d349f5dfa825929d36c174a43381ab6fdf08f1b9264814a802 -size 67624 +oid sha256:e8157368754dae9ce692fbd10fecf1e598f37fb258292085c93e1c881dd47aa9 +size 69590 diff --git a/src/scripts/breast_cancer_analyses/breast_cancer_analyses.py b/src/scripts/breast_cancer_analyses/breast_cancer_analyses.py index e4456a9856..0e185d12bf 100644 --- a/src/scripts/breast_cancer_analyses/breast_cancer_analyses.py +++ b/src/scripts/breast_cancer_analyses/breast_cancer_analyses.py @@ -50,8 +50,13 @@ def run_sim(service_availability): + # configure logging + log_config = { + 'filename': 'LogFile', + 'directory': outputpath, + } # Establish the simulation object and set the seed - sim = Simulation(start_date=start_date, seed=0) + sim = Simulation(start_date=start_date, seed=0, log_config=log_config) # Register the appropriate modules sim.register(demography.Demography(resourcefilepath=resourcefilepath), @@ -71,14 +76,11 @@ def run_sim(service_availability): breast_cancer.BreastCancer(resourcefilepath=resourcefilepath) ) - # Establish the logger - logfile = sim.configure_logging(filename="LogFile") - # Run the simulation sim.make_initial_population(n=popsize) sim.simulate(end_date=end_date) - return logfile + return sim.log_filepath def get_summary_stats(logfile): diff --git a/src/scripts/breast_cancer_analyses/calc_5y_survival_following_treatment.py b/src/scripts/breast_cancer_analyses/calc_5y_survival_following_treatment.py index 3a18b9e451..5d2d34daeb 100644 --- a/src/scripts/breast_cancer_analyses/calc_5y_survival_following_treatment.py +++ b/src/scripts/breast_cancer_analyses/calc_5y_survival_following_treatment.py @@ -41,8 +41,18 @@ end_date = Date(2025, 1, 1) popsize = 10000 + +# Establish the logger and look at only demography +log_config = { + 'filename': 'LogFile', + 'custom_levels': { + '*': logging.WARNING, # <-- + 'tlo.methods.demography': logging.INFO + } + } + # Establish the simulation object and set the seed -sim = Simulation(start_date=start_date, seed=0) +sim = Simulation(start_date=start_date, seed=0, log_config=log_config) # Register the appropriate modules sim.register(demography.Demography(resourcefilepath=resourcefilepath), @@ -68,19 +78,12 @@ bc_parameters["init_prop_treatment_status_breast_cancer"] = [0.0] * 4 bc_parameters["init_prob_palliative_care"] = 0.0 -# Establish the logger and look at only demography -custom_levels = {"*": logging.WARNING, # <-- - "tlo.methods.demography": logging.INFO - } -logfile = sim.configure_logging(filename="LogFile", custom_levels=custom_levels) - - # Run the simulation sim.make_initial_population(n=popsize) sim.simulate(end_date=end_date) # Read the output: -output = parse_log_file(logfile) +output = parse_log_file(sim.log_filepath) # %% Analyse the output: diff --git a/src/scripts/data_file_processing/healthsystem/consumables/consumable_resource_analyses_with_lmis/consumables_availability_estimation.py b/src/scripts/data_file_processing/healthsystem/consumables/consumable_resource_analyses_with_lmis/consumables_availability_estimation.py index ccef5c219d..3615afd400 100644 --- a/src/scripts/data_file_processing/healthsystem/consumables/consumable_resource_analyses_with_lmis/consumables_availability_estimation.py +++ b/src/scripts/data_file_processing/healthsystem/consumables/consumable_resource_analyses_with_lmis/consumables_availability_estimation.py @@ -277,14 +277,16 @@ def custom_agg(x): return _collapsed_df # Hold out the dataframe with no naming inconsistencies -list_of_items_with_inconsistent_names_zipped = list(zip(inconsistent_item_names_mapping.keys(), inconsistent_item_names_mapping.values())) +list_of_items_with_inconsistent_names_zipped = set(zip(inconsistent_item_names_mapping.keys(), inconsistent_item_names_mapping.values())) list_of_items_with_inconsistent_names = [item for sublist in list_of_items_with_inconsistent_names_zipped for item in sublist] df_with_consistent_item_names = lmis_df_wide_flat[~lmis_df_wide_flat[('item',)].isin(list_of_items_with_inconsistent_names)] df_without_consistent_item_names = lmis_df_wide_flat[lmis_df_wide_flat[('item',)].isin(list_of_items_with_inconsistent_names)] # Make inconsistently named drugs uniform across the dataframe -df_without_consistent_item_names_corrected = rename_items_to_address_inconsistentencies(df_without_consistent_item_names, inconsistent_item_names_mapping) +df_without_consistent_item_names_corrected = rename_items_to_address_inconsistentencies( + df_without_consistent_item_names, inconsistent_item_names_mapping) # Append holdout and corrected dataframes -lmis_df_wide_flat = pd.concat([df_without_consistent_item_names_corrected, df_with_consistent_item_names], ignore_index=True) +lmis_df_wide_flat = pd.concat([df_without_consistent_item_names_corrected, df_with_consistent_item_names], + ignore_index=True) # --- 3.1 RULE: 1.If i) stockout is missing, ii) closing_bal, amc and received are not missing , and iii) amc !=0 and, # then stkout_days[m] = (amc[m] - closing_bal[m-1] - received)/amc * number of days in the month --- diff --git a/src/scripts/data_file_processing/healthsystem/consumables/processing_data_from_one_health/generate_consumables_item_codes_and_packages.py b/src/scripts/data_file_processing/healthsystem/consumables/processing_data_from_one_health/generate_consumables_item_codes_and_packages.py index 3fcbccf9e2..7ca04f763f 100644 --- a/src/scripts/data_file_processing/healthsystem/consumables/processing_data_from_one_health/generate_consumables_item_codes_and_packages.py +++ b/src/scripts/data_file_processing/healthsystem/consumables/processing_data_from_one_health/generate_consumables_item_codes_and_packages.py @@ -21,7 +21,8 @@ # Set local Dropbox source path_to_dropbox = Path( # <-- point to the TLO dropbox locally - '/Users/tbh03/Dropbox (SPH Imperial College)/Thanzi la Onse Theme 1 SHARE') + # '/Users/tbh03/Dropbox (SPH Imperial College)/Thanzi la Onse Theme 1 SHARE' + '/Users/sm2511/Dropbox/Thanzi La Onse') resourcefilepath = Path("./resources") path_for_new_resourcefiles = resourcefilepath / "healthsystem/consumables" @@ -245,7 +246,7 @@ def add_record(df: pd.DataFrame, record: Dict): """Add a row to the bottom of the dataframe, where the row is specified by a dict keyed by the target columns.""" - assert list(df.columns) == list(record.keys()) + assert set(df.columns) == set(record.keys()) return pd.concat([df, pd.DataFrame.from_records([record])], ignore_index=True) @@ -328,6 +329,54 @@ def add_record(df: pd.DataFrame, record: Dict): }, ) +cons = add_record( + cons, + { + 'Intervention_Cat': "Added by SM (Recommended by TM)", + 'Intervention_Pkg': "Isoniazid preventative therapy for HIV+ no TB", + 'Intervention_Pkg_Code': 82, + 'Items': "Isoniazid/Rifapentine", + 'Item_Code': 2678, + 'Expected_Units_Per_Case': 1.0, + 'Unit_Cost': 1.0 + }, +) + +cons = add_record( + cons, + { + 'Intervention_Cat': "Added by SM (Recommended by EJ)", + 'Intervention_Pkg': "Misc", + 'Intervention_Pkg_Code': -99, + 'Items': "Cystoscope", + 'Item_Code': 285, + 'Expected_Units_Per_Case': 1.0, + 'Unit_Cost': np.nan}, +) + +cons = add_record( + cons,{ + 'Intervention_Cat': "Added by SM (Recommended by EJ)", + 'Intervention_Pkg': "Misc", + 'Intervention_Pkg_Code': -99, + 'Items': "Endoscope", + 'Item_Code': 280, + 'Expected_Units_Per_Case': 1.0, + 'Unit_Cost': np.nan}, +) + +cons = add_record( + cons,{ + 'Intervention_Cat': "Added by SM (Recommended by EJ)", + 'Intervention_Pkg': "Misc", + 'Intervention_Pkg_Code': -99, + 'Items': "Prostate specific antigen test", + 'Item_Code': 281, + 'Expected_Units_Per_Case': 1.0, + 'Unit_Cost': np.nan}, +) + + # -------------- # -------------- # -------------- diff --git a/src/scripts/data_file_processing/healthsystem/equipment/equipment_availability_estimation.py b/src/scripts/data_file_processing/healthsystem/equipment/equipment_availability_estimation.py new file mode 100644 index 0000000000..12ba3c7f9d --- /dev/null +++ b/src/scripts/data_file_processing/healthsystem/equipment/equipment_availability_estimation.py @@ -0,0 +1,356 @@ +""" +This script generates estimates of availability of equipment used by disease modules. The output is: +* ResourceFile_Equipment_availability.csv + +N.B. The file uses `equipment_and_other_non_consumable_avaibility_hhfa.xlsx` [sic] in Dropbox as an input. + +It creates one row for each equipment code for whether equipment is available and + whether equipment is functional at a specific facility level and district. + +Equipment availability is measured as probability of each equipment being available within each District at each +Facility_level (as recorded by HHFA). +""" + +import datetime +from pathlib import Path + +import numpy as np +import pandas as pd + +# Set local Dropbox source +path_to_dropbox = Path( # <-- point to the TLO dropbox locally + '/Users/tbh03/SPH Imperial College Dropbox/Tim Hallett/Thanzi la Onse Theme 1 SHARE' + # '/Users/sm2511/Dropbox/Thanzi La Onse' +) + +path_to_files_in_the_tlo_dropbox = path_to_dropbox / "05 - Resources/Module-healthsystem/equipment/" + +# define a timestamp for script outputs +timestamp = datetime.datetime.now().strftime("_%Y_%m_%d_%H_%M") + +# print the start time of the script +print('Script Start', datetime.datetime.now().strftime('%H:%M')) + +# define a pathway to the data folder (note: currently outside the TLO model directory) +# remember to set working directory to TLOmodel/ +outputfilepath = Path("./outputs") +resourcefilepath = Path("./resources") +path_for_new_resourcefiles = resourcefilepath / "healthsystem/infrastructure_and_equipment/" + +# Import Raw data +hhfa_equipment_wide = pd.read_excel( + (path_to_dropbox / '07 - Data/HHFA_2018-19/2 clean/equipment_and_other_non_consumable_avaibility_hhfa.xlsx'), + sheet_name="hhfa_data") +hhfa_equipment_wide = hhfa_equipment_wide.drop(hhfa_equipment_wide.columns[0], axis=1) +# Reshape data +hhfa_equipment = pd.melt(hhfa_equipment_wide, id_vars=['fac_code'], var_name='equipment_availability_var', + value_name='response') +hhfa_equipment['equipment'] = hhfa_equipment['equipment_availability_var'].str.split('_').str[0] +hhfa_equipment['availability_var'] = hhfa_equipment['equipment_availability_var'].str.split('_').str[1] + +# Preserve only relevant datapoints +relevant_varlist = ['functional', 'today', 'today-functional', 'calibrated', 'date-last-calibrated', 'prepared', + 'previous-prep'] +hhfa_equipment_df_for_model = hhfa_equipment[hhfa_equipment['availability_var'].isin(relevant_varlist)] + +# Create a dataframe with 6 columns of HHFA data on availability: +# 'available', 'functional', 'calibrated', 'date_last_calibrated' , 'prepared', 'date_last_prepared' +# Reshape data +unique_equipment_df_for_model = hhfa_equipment_df_for_model.pivot(index=['fac_code', 'equipment'], + columns='availability_var', values='response') +unique_equipment_df_for_model = unique_equipment_df_for_model.reset_index() + +# Rename data columns +new_column_names = {'date-last-calibrated': 'date_last_calibrated', 'previous-prep': 'date_last_prepared', + 'today': 'available', 'today-functional': 'functional_today'} +unique_equipment_df_for_model = unique_equipment_df_for_model.rename(columns=new_column_names) + +# Extrapolate values from other variables +available_missing_before_extrapolation = len( + unique_equipment_df_for_model[unique_equipment_df_for_model.available.isna()]) +unique_equipment_df_for_model.loc[unique_equipment_df_for_model['functional'].isin( + ["Yes", "No"]), 'available'] = "Yes" # if there is a valid response to "functional" the equipment must be available +unique_equipment_df_for_model.loc[unique_equipment_df_for_model['functional_today'].isin( + ['AVAILABLE AND FUNCTIONAL', 'AVAILABLE NOT FUNCTIONAL', "AVAILABLE DON'T KNOW IF FUNCTIONAL", + 'Yes']), 'available'] = "Yes" # if equipment is functional then it is available +unique_equipment_df_for_model.loc[unique_equipment_df_for_model['functional_today'].isin( + ['NOT AVAILABLE', 'No']), 'available'] = "No" # if equipment is functional then it is available +available_missing_after_extrapolation = len( + unique_equipment_df_for_model[unique_equipment_df_for_model.available.isna()]) +print((available_missing_before_extrapolation - available_missing_after_extrapolation) / len( + unique_equipment_df_for_model) * 100, "% values for 'available' extrapolated from other survey questions") + +functional_missing_before_extrapolation = len( + unique_equipment_df_for_model[unique_equipment_df_for_model.functional.isna()]) +unique_equipment_df_for_model.loc[( + unique_equipment_df_for_model['functional_today'].isin(['AVAILABLE AND FUNCTIONAL', 'Yes']) & + unique_equipment_df_for_model[ + 'functional'].isna()), 'functional'] = "Yes" +# separate question asking whether equipment was available today +unique_equipment_df_for_model.loc[( + unique_equipment_df_for_model['functional_today'].isin(['AVAILABLE NOT FUNCTIONAL', 'No', 'NOT AVAILABLE']) & + unique_equipment_df_for_model[ + 'functional'].isna()), 'functional'] = "No" +# seperate question asking whether equipment was available today +unique_equipment_df_for_model.loc[unique_equipment_df_for_model['available'].isin( + ['AT LEAST ONE VALID', 'Available and functional']), 'functional'] = "Yes" # information under the available +# question captures whether equipment is functional +unique_equipment_df_for_model.loc[unique_equipment_df_for_model['available'].isin( + ['AVAILABLE NON VALID', 'Available not functional']), 'functional'] = "No" # information under the available +# question captures whether equipment is functional +functional_missing_after_extrapolation = len( + unique_equipment_df_for_model[unique_equipment_df_for_model.functional.isna()]) +print((functional_missing_before_extrapolation - functional_missing_after_extrapolation) / len( + unique_equipment_df_for_model) * 100, "% values for 'functional' extrapolated from other survey questions") + +# Sense check values - if equipment is calibrated or prepared, then it must be functional +unique_equipment_df_for_model.loc[unique_equipment_df_for_model['prepared'] == "Yes", 'functional'] = "Yes" +unique_equipment_df_for_model.loc[unique_equipment_df_for_model['calibrated'] == "Yes", 'functional'] = "Yes" + +# Convert to binary values +unique_equipment_df_for_model.loc[unique_equipment_df_for_model['available'].isin( + ['AT LEAST ONE VALID', 'Available and functional', 'AVAILABLE NON VALID', 'Available not functional', + "REPORTED AVAILABLE BUT NOT SEEN", "Yes"]), 'available'] = 1 +unique_equipment_df_for_model.loc[unique_equipment_df_for_model['available'].isin( + ['NOT AVAILABLE TODAY', 'Not available', 'NEVER AVAILABLE', "Not observed", "No"]), 'available'] = 0 +unique_equipment_df_for_model.loc[ + unique_equipment_df_for_model['functional'] == 3, 'functional'] = np.nan # 3 implies "Don't know" +unique_equipment_df_for_model.loc[unique_equipment_df_for_model['functional'] == 'Yes', 'functional'] = 1 +unique_equipment_df_for_model.loc[(unique_equipment_df_for_model['functional'] == 'No') | ( + unique_equipment_df_for_model['available'] == 0), 'functional'] = 0 + +# Merge with equipment names and item codes from TLO model +equipment_crosswalk = pd.read_excel( + (path_to_dropbox / '07 - Data/HHFA_2018-19/2 clean/equipment_and_other_non_consumable_avaibility_hhfa.xlsx'), + sheet_name="equipment_crosswalk") +equipment_crosswalk_only_matched_items = equipment_crosswalk[equipment_crosswalk.Equipment_name_HHFA.notna() & + equipment_crosswalk.Equipment_name.notna()] +tlo_equipment_availability = pd.merge( + equipment_crosswalk_only_matched_items[['Item_code', 'Equipment_name', 'Equipment_name_HHFA']], + unique_equipment_df_for_model[['fac_code', 'equipment', 'available', 'functional']], + left_on='Equipment_name_HHFA', right_on='equipment') + +tlo_equipment_availability_duplicates_collapsed = \ + tlo_equipment_availability.groupby(['Item_code', 'Equipment_name', 'fac_code'])[['available', 'functional']].agg( + max).reset_index() + +# Merge with facility information +# Load cleaned HHFA data prepared by script - `prepare_hhfa_consumables_data_for_inferential_analysis.py` +hhfa_facility_data = pd.read_csv(path_to_dropbox / '07 - Data/HHFA_2018-19/2 clean/cleaned_hhfa_2019.csv', + usecols=['fac_code', 'fac_type', 'district']) +hhfa_facility_data['Facility_level'] = hhfa_facility_data['fac_type'].str.replace('Facility_level_', '') +final_equipment_availability_df = pd.merge(tlo_equipment_availability_duplicates_collapsed, + hhfa_facility_data[['fac_code', 'Facility_level', 'district']], + on='fac_code') + +# Clean district names to match TLO model +final_equipment_availability_df['District'] = final_equipment_availability_df['district'] +# Define the mapping of districts to their corresponding city names +district_mapping = {'Lilongwe': 'Lilongwe City', 'Blantyre': 'Blantyre City', 'Mzimba North': 'Mzuzu City', + 'Zomba': 'Zomba City'} +# Iterate over each district in the mapping +for district, city in district_mapping.items(): + # Filter rows where 'district' is equal to the current district + district_rows = final_equipment_availability_df[final_equipment_availability_df['District'] == district] + + # Duplicate the filtered rows + duplicated_district_rows = district_rows.copy() + + # Change the value of 'district' column to the corresponding city name + duplicated_district_rows['District'] = city + + # Concatenate the original DataFrame with the duplicated and modified rows + final_equipment_availability_df = pd.concat([final_equipment_availability_df, duplicated_district_rows], + ignore_index=True) + +# For the districts above, drop level 3 for districts because this lies within the city, drop level 4 from Zomba +final_equipment_availability_df = final_equipment_availability_df.reset_index() +for district, city in district_mapping.items(): + final_equipment_availability_df = ( + final_equipment_availability_df.drop( + final_equipment_availability_df[ + (final_equipment_availability_df['District'] == district) + & (final_equipment_availability_df['Facility_level'] == '3') + ].index) + ) + +final_equipment_availability_df = final_equipment_availability_df.drop( + final_equipment_availability_df[ + (final_equipment_availability_df['District'] == 'Zomba') + & (final_equipment_availability_df['Facility_level'] == '4') + ].index +) + +# Combine Mzimba North and Mzimba South +final_equipment_availability_df.loc[(final_equipment_availability_df.District == 'Mzimba North') | ( + final_equipment_availability_df.District == 'Mzimba South'), 'District'] = 'Mzimba' +equipment_data_district_list = final_equipment_availability_df.District.unique() +model_district_list = pd.read_csv(resourcefilepath / 'demography/ResourceFile_PopulationSize_2018Census.csv')[ + 'District'].unique() # Check that the new list of district matches with the model +assert (set(equipment_data_district_list) == set(model_district_list)) + +# Collapse data by facility level and district +final_equipment_availability = \ + final_equipment_availability_df.groupby(['Facility_level', 'District', 'Item_code', 'Equipment_name'])[ + ['available', 'functional']].mean().reset_index() + +# ------------------------------------------------------------------------------------------------------------------- +# ------------------------------------------------------------------------------------------------------------------- +# Final formatting for compatability with the `Equipment` class + +final_equipment_availability_export = final_equipment_availability.copy() + +# - Drop any rows with missing data +final_equipment_availability_export = final_equipment_availability_export.dropna() + +# - 'Item_Code' is the name expected in the Equipment class, and this should have type `int` +final_equipment_availability_export['Item_Code'] = final_equipment_availability_export['Item_code'].astype(int) + +# Rename 'facility_level' +final_equipment_availability_export = final_equipment_availability_export.rename( + columns={'Facility_level': 'Facility_Level'}) + +# Check that every row specifies a facility_level +assert final_equipment_availability_export['Facility_Level'].isin([ + '0', '1a', '1b', '2', '3', '4', '5' +]).all() +assert final_equipment_availability_export['Facility_Level'].notnull().all() + +# - 'Pr_Available' is the name expected in the Equipment class, and is taken to be the probability that an item of +# equipment is available for use +# which is taken to be equivalent to it to being "functional" +final_equipment_availability_export['Pr_Available'] = final_equipment_availability['functional'].astype(float) +assert final_equipment_availability_export['Pr_Available'].notnull().any() + +# - Specify region (needed for merging in facility_ids) +region_lookup = \ + pd.read_csv(resourcefilepath / 'demography/ResourceFile_PopulationSize_2018Census.csv').set_index('District')[ + 'Region'].to_dict() +final_equipment_availability_export['Region'] = final_equipment_availability_export['District'].map(region_lookup) + +# -- Drop not needed columns +final_equipment_availability_export = final_equipment_availability_export[[ + 'Facility_Level', 'Region', 'District', 'Item_Code', 'Pr_Available' +]] + +# - Merge in 'Facility_ID' (which specifies the level and the district of the facilities) +mfl = pd.read_csv( + resourcefilepath / 'healthsystem' / 'organisation' / 'ResourceFile_Master_Facilities_List.csv' +) + +# Merge in district-specific facilities (matching on level and district) +final_equipment_availability_export = final_equipment_availability_export.merge( + mfl[['Facility_ID', 'Facility_Level', 'District']], + left_on=['Facility_Level', 'District'], + right_on=['Facility_Level', 'District'], + how='left', +) + +# Merge in region-level facilities (level 3) (matching on region only) + +# - First, ensure that there is only one set of facility_level 3 entries for each region. (In the current dataframe +# entries for level 3 of Blantyre City and Zomba City could both inform on level 3 in the Southern region.) +# Do this by taking the mean of Pr_Available across those rows that are facility_level 3 in the same region. +# Create a 'reconciled' set of data facility level 3. +mask_to_level_3 = final_equipment_availability_export['Facility_Level'] == '3' +reconciled_level_3_data = final_equipment_availability_export.loc[mask_to_level_3].groupby( + ['Region', 'Facility_Level', 'Item_Code'] +)['Pr_Available'].mean().reset_index() +reconciled_level_3_data['District'] = float('nan') # District is not used for region-level facilities +level_3_lookup = mfl.loc[mfl['Facility_Level'] == '3'].set_index('Region')['Facility_ID'].to_dict() +reconciled_level_3_data['Facility_ID'] = reconciled_level_3_data['Region'].map(level_3_lookup) + +# - Update dataset with the reconciled data for facility level 3 +final_equipment_availability_export = final_equipment_availability_export.drop( + final_equipment_availability_export.index[mask_to_level_3] +) +final_equipment_availability_export = pd.concat( + [final_equipment_availability_export, reconciled_level_3_data], + ignore_index=True +) + +# Set national-level facility_ids (levels 4/5) (depends on only on facility_level) +levels_4_and_5_lookup = mfl.loc[mfl['Facility_Level'].isin(['4', '5'])].set_index('Facility_Level')[ + 'Facility_ID'].to_dict() +mask_to_levels_4_and_5 = final_equipment_availability_export['Facility_Level'].isin(['4', '5']) +final_equipment_availability_export.loc[mask_to_levels_4_and_5, 'Facility_ID'] = \ + final_equipment_availability_export.loc[mask_to_levels_4_and_5, 'Facility_Level'].map(levels_4_and_5_lookup) + +assert final_equipment_availability_export['Facility_ID'].notnull().all() +final_equipment_availability_export['Facility_ID'] = final_equipment_availability_export['Facility_ID'].astype(int) + +# - Format as a pd.Series with multi-index (Facility_ID, Item_Code) +final_equipment_availability_export = final_equipment_availability_export.set_index(['Facility_ID', 'Item_Code'])[ + 'Pr_Available'] + +# Extrapolate so that there is an estimated availability for every item at every level +# - Create "full" dataset, where we force that there is probability of availability for every item_code at every +# observed facility +_all_fac_ids = mfl.Facility_ID.unique() +_all_item_codes = pd.read_csv( + resourcefilepath / 'healthsystem/infrastructure_and_equipment/ResourceFile_EquipmentCatalogue.csv' +)['Item_Code'].unique() +final_equipment_availability_export_full = pd.Series( + index=pd.MultiIndex.from_product( + [_all_fac_ids, _all_item_codes], + names=["Facility_ID", "Item_Code"] + ), + data=float("nan"), + name='Pr_Available' +).combine_first(final_equipment_availability_export) + +# Check no duplicates +assert not final_equipment_availability_export_full.index.has_duplicates + +pc_missing_data = (final_equipment_availability_export_full.isnull().sum() + / len(final_equipment_availability_export_full)) +print(f'Fraction of missing data when requiring data for all items at all facilities = ' + f'{round(100 * pc_missing_data)} %.') + +# Impute availability of missing item_codes in a facility_id... from the mean availability of the same items in other +# facilities of the same level +facility_levels = final_equipment_availability_export_full.index.get_level_values('Facility_ID').map( + mfl.set_index('Facility_ID')['Facility_Level'].to_dict() +) +final_equipment_availability_export_full = final_equipment_availability_export_full.groupby( + ['Item_Code', facility_levels]).transform(lambda x: x.fillna(x.mean())) + +# Remaining missing data include those item_codes that are never seen anywhere: interpolate these from the average +# availability of all other items, stratified by level and category of equipment +equipment_price_category_mapper = \ + equipment_crosswalk[['Item_code', 'Category']].dropna() \ + .drop_duplicates() \ + .pipe(lambda x: x.set_index(x['Item_code'].astype(int)))['Category'] \ + .to_dict() +# Manually declare the price category for equipment items added manually +# 402: Endoscope: 'Cost >= $1000' +equipment_price_category_mapper[402] = 'Cost >= $1000' +# 403: Electrocardiogram: 'Cost >= $1000' +equipment_price_category_mapper[403] = 'Cost >= $1000' + +equipment_price_category = final_equipment_availability_export_full.index.get_level_values('Item_Code') \ + .map(equipment_price_category_mapper) +final_equipment_availability_export_full = final_equipment_availability_export_full.groupby( + [equipment_price_category, facility_levels]).transform(lambda x: x.fillna(x.mean())) + +# Force availability to be 0 for level 5, where no service delivery occurs +level_5_lookup = mfl.loc[mfl['Facility_Level'].isin(['5'])].set_index('Facility_Level')['Facility_ID'].to_dict() +final_equipment_availability_export_full[ + final_equipment_availability_export_full.index.get_level_values(level=0) == list(level_5_lookup.values())[0]] = 0 + +# - Check no missing values +assert final_equipment_availability_export_full.notnull().all() + +# - Check that we've preserved the right estimates where there is data +pd.testing.assert_series_equal( + final_equipment_availability_export, + # <-- the data before any extrapolations + final_equipment_availability_export_full[final_equipment_availability_export.index] + # <-- the full data limited to those facilities/item for which there was data originally +) + +# Save final availability data to ResourceFile +final_equipment_availability_export_full.reset_index().to_csv( + resourcefilepath / 'healthsystem/infrastructure_and_equipment/ResourceFile_Equipment_Availability_Estimates.csv', + index=False +) diff --git a/src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_capabilities_expansion_combined.py b/src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_capabilities_expansion_combined.py new file mode 100644 index 0000000000..a46dfa75fe --- /dev/null +++ b/src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_capabilities_expansion_combined.py @@ -0,0 +1,265 @@ +"""This Scenario file run the model under different assumptions for HR capabilities expansion in order to estimate the +impact that is achieved under each. + +Run on the batch system using: +``` +tlo batch-submit src/scripts/healthsystem/impact_of_policy/scenario_impact_of_const_capabilities_expansion.py +``` + +or locally using: +``` +tlo scenario-run src/scripts/healthsystem/impact_of_policy/scenario_impact_of_const_capabilities_expansion.py +``` + +""" +from pathlib import Path +from typing import Dict + +import pandas as pd + +from tlo import Date, logging +from tlo.analysis.utils import get_parameters_for_status_quo, mix_scenarios +from tlo.methods.fullmodel import fullmodel +from tlo.methods.scenario_switcher import ScenarioSwitcher +from tlo.scenario import BaseScenario + + +class ImpactOfHealthSystemMode(BaseScenario): + def __init__(self): + super().__init__() + self.seed = 0 + self.start_date = Date(2010, 1, 1) + self.end_date = self.start_date + pd.DateOffset(years=31) + self.pop_size = 100_000 + self._scenarios = self._get_scenarios() + self.number_of_draws = len(self._scenarios) + self.runs_per_draw = 2 + + def log_configuration(self): + return { + 'filename': 'effect_of_policy', + 'directory': Path('./outputs'), # <- (specified only for local running) + 'custom_levels': { + '*': logging.WARNING, + 'tlo.methods.demography': logging.INFO, + 'tlo.methods.demography.detail': logging.WARNING, + 'tlo.methods.healthburden': logging.INFO, + 'tlo.methods.healthsystem.summary': logging.INFO, + } + } + + def modules(self): + return fullmodel(resourcefilepath=self.resources) + [ScenarioSwitcher(resourcefilepath=self.resources)] + + def draw_parameters(self, draw_number, rng): + if draw_number < self.number_of_draws: + return list(self._scenarios.values())[draw_number] + else: + return + + # case 1: gfHE = -0.030, factor = 1.01074 + # case 2: gfHE = -0.020, factor = 1.02116 + # case 3: gfHE = -0.015, factor = 1.02637 + # case 4: gfHE = 0.015, factor = 1.05763 + # case 5: gfHE = 0.020, factor = 1.06284 + # case 6: gfHE = 0.030, factor = 1.07326 + + def _get_scenarios(self) -> Dict[str, Dict]: + """Return the Dict with values for the parameters that are changed, keyed by a name for the scenario. + """ + return { + "No growth": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "no_scaling", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "scale_to_effective_capabilities": True, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "scale_to_effective_capabilities": True, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 1": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case1", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "scale_to_effective_capabilities": True, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 3": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case3", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "scale_to_effective_capabilities": True, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 4": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case4", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "scale_to_effective_capabilities": True, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 6": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case6", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "scale_to_effective_capabilities": True, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth FL case 1 const i": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_FL_case1_const_tot_i", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "scale_to_effective_capabilities": True, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth FL case 2 const i": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_FL_case2_const_tot_i", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "scale_to_effective_capabilities": True, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth FL case 1 vary i": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_FL_case1_vary_tot_i", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "scale_to_effective_capabilities": True, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth FL case 2 vary i": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_FL_case2_vary_tot_i", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "scale_to_effective_capabilities": True, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + } + +if __name__ == '__main__': + from tlo.cli import scenario_run + + scenario_run([__file__]) diff --git a/src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_capabilities_expansion_scaling.py b/src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_capabilities_expansion_scaling.py new file mode 100644 index 0000000000..28cd7ff171 --- /dev/null +++ b/src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_capabilities_expansion_scaling.py @@ -0,0 +1,336 @@ +"""This Scenario file run the model under different assumptions for HR capabilities expansion in order to estimate the +impact that is achieved under each. + +Run on the batch system using: +``` +tlo batch-submit src/scripts/healthsystem/impact_of_policy/scenario_impact_of_const_capabilities_expansion.py +``` + +or locally using: +``` +tlo scenario-run src/scripts/healthsystem/impact_of_policy/scenario_impact_of_const_capabilities_expansion.py +``` + +""" +from pathlib import Path +from typing import Dict + +import pandas as pd + +from tlo import Date, logging +from tlo.analysis.utils import get_parameters_for_status_quo, mix_scenarios +from tlo.methods.fullmodel import fullmodel +from tlo.methods.scenario_switcher import ImprovedHealthSystemAndCareSeekingScenarioSwitcher +from tlo.scenario import BaseScenario + + +class ImpactOfHealthSystemMode(BaseScenario): + def __init__(self): + super().__init__() + self.seed = 0 + self.start_date = Date(2010, 1, 1) + self.end_date = self.start_date + pd.DateOffset(years=31) + self.pop_size = 100_000 + self._scenarios = self._get_scenarios() + self.number_of_draws = len(self._scenarios) + self.runs_per_draw = 10 + + def log_configuration(self): + return { + 'filename': 'effect_of_capabilities_scaling', + 'directory': Path('./outputs'), # <- (specified only for local running) + 'custom_levels': { + '*': logging.WARNING, + 'tlo.methods.demography': logging.INFO, + 'tlo.methods.demography.detail': logging.WARNING, + 'tlo.methods.healthburden': logging.INFO, + 'tlo.methods.healthsystem.summary': logging.INFO, + } + } + + def modules(self): + return ( + fullmodel(resourcefilepath=self.resources) + + [ImprovedHealthSystemAndCareSeekingScenarioSwitcher(resourcefilepath=self.resources)] + ) + + def draw_parameters(self, draw_number, rng): + if draw_number < self.number_of_draws: + return list(self._scenarios.values())[draw_number] + else: + return + + # case 1: gfHE = -0.030, factor = 1.01074 + # case 2: gfHE = -0.020, factor = 1.02116 + # case 3: gfHE = -0.015, factor = 1.02637 + # case 4: gfHE = 0.015, factor = 1.05763 + # case 5: gfHE = 0.020, factor = 1.06284 + # case 6: gfHE = 0.030, factor = 1.07326 + + def _get_scenarios(self) -> Dict[str, Dict]: + """Return the Dict with values for the parameters that are changed, keyed by a name for the scenario. + """ + + self.YEAR_OF_CHANGE = 2019 + + return { + + # =========== STATUS QUO ============ + "No growth status quo": + mix_scenarios( + self._baseline(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "no_scaling", + }, + } + ), + + "GDP growth status quo": + mix_scenarios( + self._baseline(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth", + }, + } + ), + + "GDP growth fHE growth case 1 status quo": + mix_scenarios( + self._baseline(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case1", + }, + } + ), + + "GDP growth fHE growth case 3 status quo": + mix_scenarios( + self._baseline(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case3", + }, + } + ), + + + "GDP growth fHE growth case 4 status quo": + mix_scenarios( + self._baseline(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case4", + }, + } + ), + + "GDP growth fHE growth case 6 status quo": + mix_scenarios( + self._baseline(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case6", + }, + } + ), + + # =========== PERFECT CONSUMABLES AVAILABILITY ============ + "No growth perfect consumables": + mix_scenarios( + self._baseline(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "no_scaling", + "year_cons_availability_switch": self.YEAR_OF_CHANGE, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth perfect consumables": + mix_scenarios( + self._baseline(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth", + "year_cons_availability_switch": self.YEAR_OF_CHANGE, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 1 perfect consumables": + mix_scenarios( + self._baseline(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case1", + "year_cons_availability_switch": self.YEAR_OF_CHANGE, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 3 perfect consumables": + mix_scenarios( + self._baseline(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case3", + "year_cons_availability_switch": self.YEAR_OF_CHANGE, + "cons_availability_postSwitch": "all", + }, + } + ), + + + "GDP growth fHE growth case 4 perfect consumables": + mix_scenarios( + self._baseline(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case4", + "year_cons_availability_switch": self.YEAR_OF_CHANGE, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 6 perfect consumables": + mix_scenarios( + self._baseline(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case6", + "year_cons_availability_switch": self.YEAR_OF_CHANGE, + "cons_availability_postSwitch": "all", + }, + } + ), + + # =========== PERFECT HEALTHSYSTEM ============ + "No growth perfect healthsystem": + mix_scenarios( + self._baseline(), + { + 'ImprovedHealthSystemAndCareSeekingScenarioSwitcher': { + 'max_healthsystem_function': [False, True], # <-- switch from False to True mid-way + 'year_of_switch': self.YEAR_OF_CHANGE, + }, + "HealthSystem": { + "yearly_HR_scaling_mode": "no_scaling", + "year_cons_availability_switch": self.YEAR_OF_CHANGE, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth perfect healthsystem": + mix_scenarios( + self._baseline(), + { + 'ImprovedHealthSystemAndCareSeekingScenarioSwitcher': { + 'max_healthsystem_function': [False, True], # <-- switch from False to True mid-way + 'year_of_switch': self.YEAR_OF_CHANGE, + }, + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth", + "year_cons_availability_switch": self.YEAR_OF_CHANGE, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 1 perfect healthsystem": + mix_scenarios( + self._baseline(), + { + 'ImprovedHealthSystemAndCareSeekingScenarioSwitcher': { + 'max_healthsystem_function': [False, True], # <-- switch from False to True mid-way + 'year_of_switch': self.YEAR_OF_CHANGE, + }, + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case1", + "year_cons_availability_switch": self.YEAR_OF_CHANGE, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 3 perfect healthsystem": + mix_scenarios( + self._baseline(), + { + 'ImprovedHealthSystemAndCareSeekingScenarioSwitcher': { + 'max_healthsystem_function': [False, True], # <-- switch from False to True mid-way + 'year_of_switch': self.YEAR_OF_CHANGE, + }, + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case3", + "year_cons_availability_switch": self.YEAR_OF_CHANGE, + "cons_availability_postSwitch": "all", + }, + } + ), + + + "GDP growth fHE growth case 4 perfect healthsystem": + mix_scenarios( + self._baseline(), + { + 'ImprovedHealthSystemAndCareSeekingScenarioSwitcher': { + 'max_healthsystem_function': [False, True], # <-- switch from False to True mid-way + 'year_of_switch': self.YEAR_OF_CHANGE, + }, + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case4", + "year_cons_availability_switch": self.YEAR_OF_CHANGE, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 6 perfect healthsystem": + mix_scenarios( + self._baseline(), + { + 'ImprovedHealthSystemAndCareSeekingScenarioSwitcher': { + 'max_healthsystem_function': [False, True], # <-- switch from False to True mid-way + 'year_of_switch': self.YEAR_OF_CHANGE, + }, + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case6", + "year_cons_availability_switch": self.YEAR_OF_CHANGE, + "cons_availability_postSwitch": "all", + }, + } + ), + + } + + def _baseline(self) -> Dict: + """Return the Dict with values for the parameter changes that define the baseline scenario. """ + return mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "mode_appt_constraints": 1, # <-- Mode 1 prior to change to preserve calibration + "mode_appt_constraints_postSwitch": 2, # <-- Mode 2 post-change to show effects of HRH + "year_mode_switch": self.YEAR_OF_CHANGE, + "scale_to_effective_capabilities": True, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "cons_availability": "default", + } + }, + ) + +if __name__ == '__main__': + from tlo.cli import scenario_run + + scenario_run([__file__]) diff --git a/src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_capabilities_expansion_test_scaling.py b/src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_capabilities_expansion_test_scaling.py new file mode 100644 index 0000000000..5d29102e8b --- /dev/null +++ b/src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_capabilities_expansion_test_scaling.py @@ -0,0 +1,152 @@ +"""This Scenario file run the model under different assumptions for HR capabilities expansion in order to estimate the +impact that is achieved under each. + +Run on the batch system using: +``` +tlo batch-submit src/scripts/healthsystem/impact_of_policy/scenario_impact_of_const_capabilities_expansion.py +``` + +or locally using: +``` +tlo scenario-run src/scripts/healthsystem/impact_of_policy/scenario_impact_of_const_capabilities_expansion.py +``` + +""" +from pathlib import Path +from typing import Dict + +import pandas as pd + +from tlo import Date, logging +from tlo.analysis.utils import get_parameters_for_status_quo, mix_scenarios +from tlo.methods.fullmodel import fullmodel +from tlo.methods.scenario_switcher import ScenarioSwitcher +from tlo.scenario import BaseScenario + + +class ImpactOfHealthSystemMode(BaseScenario): + def __init__(self): + super().__init__() + self.seed = 0 + self.start_date = Date(2010, 1, 1) + self.end_date = self.start_date + pd.DateOffset(years=31) + self.pop_size = 100_000 + self._scenarios = self._get_scenarios() + self.number_of_draws = len(self._scenarios) + self.runs_per_draw = 2 + + def log_configuration(self): + return { + 'filename': 'effect_of_policy', + 'directory': Path('./outputs'), # <- (specified only for local running) + 'custom_levels': { + '*': logging.WARNING, + 'tlo.methods.demography': logging.INFO, + 'tlo.methods.demography.detail': logging.WARNING, + 'tlo.methods.healthburden': logging.INFO, + 'tlo.methods.healthsystem.summary': logging.INFO, + } + } + + def modules(self): + return fullmodel(resourcefilepath=self.resources) + [ScenarioSwitcher(resourcefilepath=self.resources)] + + def draw_parameters(self, draw_number, rng): + if draw_number < self.number_of_draws: + return list(self._scenarios.values())[draw_number] + else: + return + + # case 1: gfHE = -0.030, factor = 1.01074 + # case 2: gfHE = -0.020, factor = 1.02116 + # case 3: gfHE = -0.015, factor = 1.02637 + # case 4: gfHE = 0.015, factor = 1.05763 + # case 5: gfHE = 0.020, factor = 1.06284 + # case 6: gfHE = 0.030, factor = 1.07326 + + def _get_scenarios(self) -> Dict[str, Dict]: + """Return the Dict with values for the parameters that are changed, keyed by a name for the scenario. + """ + return { + "No growth": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "no_scaling", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "scale_to_effective_capabilities": True, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "scale_to_effective_capabilities": True, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 1": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case1", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "scale_to_effective_capabilities": True, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 6": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case6", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "scale_to_effective_capabilities": True, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + } + +if __name__ == '__main__': + from tlo.cli import scenario_run + + scenario_run([__file__]) diff --git a/src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_const_capabilities_expansion.py b/src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_const_capabilities_expansion.py new file mode 100644 index 0000000000..be0a641504 --- /dev/null +++ b/src/scripts/healthsystem/impact_of_const_capabilities_expansion/scenario_impact_of_const_capabilities_expansion.py @@ -0,0 +1,183 @@ +"""This Scenario file run the model under different assumptions for the HealthSystem Mode in order to estimate the +impact that is achieved under each (relative to there being no health system). + +Run on the batch system using: +``` +tlo batch-submit src/scripts/healthsystem/impact_of_policy/scenario_impact_of_policy.py +``` + +or locally using: +``` +tlo scenario-run src/scripts/healthsystem/impact_of_policy/scenario_impact_of_policy.py +``` + +""" +from pathlib import Path +from typing import Dict + +import pandas as pd + +from tlo import Date, logging +from tlo.analysis.utils import get_parameters_for_status_quo, mix_scenarios +from tlo.methods.fullmodel import fullmodel +from tlo.scenario import BaseScenario + + +class ImpactOfHealthSystemMode(BaseScenario): + def __init__(self): + super().__init__() + self.seed = 0 + self.start_date = Date(2010, 1, 1) + self.end_date = self.start_date + pd.DateOffset(years=31) #CHECK + self.pop_size = 100_000 + self._scenarios = self._get_scenarios() + self.number_of_draws = len(self._scenarios) + self.runs_per_draw = 2 + + def log_configuration(self): + return { + 'filename': 'effect_of_policy', + 'directory': Path('./outputs'), # <- (specified only for local running) + 'custom_levels': { + '*': logging.WARNING, + 'tlo.methods.demography': logging.INFO, + 'tlo.methods.demography.detail': logging.WARNING, + 'tlo.methods.healthburden': logging.INFO, + 'tlo.methods.healthsystem.summary': logging.INFO, + } + } + + def modules(self): + return fullmodel(resourcefilepath=self.resources) + + def draw_parameters(self, draw_number, rng): + if draw_number < self.number_of_draws: + return list(self._scenarios.values())[draw_number] + else: + return + + # case 1: gfHE = -0.030, factor = 1.01074 + # case 2: gfHE = -0.020, factor = 1.02116 + # case 3: gfHE = -0.015, factor = 1.02637 + # case 4: gfHE = 0.015, factor = 1.05763 + # case 5: gfHE = 0.020, factor = 1.06284 + # case 6: gfHE = 0.030, factor = 1.07326 + + def _get_scenarios(self) -> Dict[str, Dict]: + """Return the Dict with values for the parameters that are changed, keyed by a name for the scenario. + """ + return { + "No growth": + mix_scenarios( + get_parameters_for_status_quo(), + { + # MUST ADD SWITCH TO PERFECT CONSUMABLE AVAILABILITY IN 2018 + "HealthSystem": { + "yearly_HR_scaling_mode": "no_scaling", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 1": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case1", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 3": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case3", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 4": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case4", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + + "GDP growth fHE growth case 6": + mix_scenarios( + get_parameters_for_status_quo(), + { + "HealthSystem": { + "yearly_HR_scaling_mode": "GDP_growth_fHE_case6", + "year_mode_switch": 2019, + "mode_appt_constraints_postSwitch": 2, + "policy_name": "Naive", + "tclose_overwrite": 1, + "tclose_days_offset_overwrite": 7, + "use_funded_or_actual_staffing": "actual", + "year_cons_availability_switch": 2019, + "cons_availability_postSwitch": "all", + }, + } + ), + } + +if __name__ == '__main__': + from tlo.cli import scenario_run + + scenario_run([__file__]) diff --git a/src/scripts/healthsystem/impact_of_policy/scenario_impact_of_policy.py b/src/scripts/healthsystem/impact_of_policy/scenario_impact_of_policy.py index 43d0176622..2554d78583 100644 --- a/src/scripts/healthsystem/impact_of_policy/scenario_impact_of_policy.py +++ b/src/scripts/healthsystem/impact_of_policy/scenario_impact_of_policy.py @@ -20,7 +20,6 @@ from tlo import Date, logging from tlo.analysis.utils import get_parameters_for_status_quo, mix_scenarios from tlo.methods.fullmodel import fullmodel -from tlo.methods.scenario_switcher import ScenarioSwitcher from tlo.scenario import BaseScenario @@ -49,7 +48,7 @@ def log_configuration(self): } def modules(self): - return fullmodel(resourcefilepath=self.resources) + [ScenarioSwitcher(resourcefilepath=self.resources)] + return fullmodel(resourcefilepath=self.resources) def draw_parameters(self, draw_number, rng): if draw_number < self.number_of_draws: diff --git a/src/scripts/hiv/projections_jan2023/analysis_full_model.py b/src/scripts/hiv/projections_jan2023/analysis_full_model.py index e1213cd28e..2386ea56c6 100644 --- a/src/scripts/hiv/projections_jan2023/analysis_full_model.py +++ b/src/scripts/hiv/projections_jan2023/analysis_full_model.py @@ -23,8 +23,8 @@ # %% Run the simulation start_date = Date(2010, 1, 1) -end_date = Date(2020, 1, 1) -popsize = 5000 +end_date = Date(2012, 1, 1) +popsize = 500 # scenario = 0 # set up the log config diff --git a/src/scripts/hiv/projections_jan2023/analysis_logged_deviance.py b/src/scripts/hiv/projections_jan2023/analysis_logged_deviance.py index c004748ad4..eca9f999bc 100644 --- a/src/scripts/hiv/projections_jan2023/analysis_logged_deviance.py +++ b/src/scripts/hiv/projections_jan2023/analysis_logged_deviance.py @@ -34,8 +34,8 @@ # %% Run the simulation start_date = Date(2010, 1, 1) -end_date = Date(2015, 1, 1) -popsize = 5000 +end_date = Date(2014, 1, 1) +popsize = 1000 # scenario = 1 diff --git a/src/scripts/htm_scenario_analyses/analysis_htm_scaleup.py b/src/scripts/htm_scenario_analyses/analysis_htm_scaleup.py new file mode 100644 index 0000000000..a89231f670 --- /dev/null +++ b/src/scripts/htm_scenario_analyses/analysis_htm_scaleup.py @@ -0,0 +1,112 @@ + +""" +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/htm_scenario_analyses/analysis_htm_scaleup.py + +Run on the batch system using: +tlo batch-submit src/scripts/htm_scenario_analyses/analysis_htm_scaleup.py + +or locally using: +tlo scenario-run src/scripts/htm_scenario_analyses/analysis_htm_scaleup.py + +or execute a single run: +tlo scenario-run src/scripts/htm_scenario_analyses/analysis_htm_scaleup.py --draw 1 0 + +""" + +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 + + +class EffectOfProgrammes(BaseScenario): + def __init__(self): + super().__init__() + self.seed = 0 + self.start_date = Date(2010, 1, 1) + self.end_date = Date(2020, 1, 1) + self.pop_size = 75_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): + scaleup_start_year = 2012 + + return { + 'Hiv': { + 'do_scaleup': [False, True, False, False, True][draw_number], + 'scaleup_start_year': scaleup_start_year + }, + 'Tb': { + 'do_scaleup': [False, False, True, False, True][draw_number], + 'scaleup_start_year': scaleup_start_year + }, + 'Malaria': { + 'do_scaleup': [False, False, False, True, True][draw_number], + 'scaleup_start_year': scaleup_start_year + }, + } + + +if __name__ == '__main__': + from tlo.cli import scenario_run + + scenario_run([__file__]) + + diff --git a/src/scripts/htm_scenario_analyses/scenario_plots.py b/src/scripts/htm_scenario_analyses/scenario_plots.py new file mode 100644 index 0000000000..d14454ae13 --- /dev/null +++ b/src/scripts/htm_scenario_analyses/scenario_plots.py @@ -0,0 +1,139 @@ +""" this reads in the outputs generates through analysis_htm_scaleup.py +and produces plots for HIV, TB and malaria incidence +""" + + +import datetime +from pathlib import Path + +import matplotlib.pyplot as plt +import pandas as pd +import seaborn as sns + +from tlo import Date +from tlo.analysis.utils import ( + extract_params, + extract_results, + get_scenario_info, + get_scenario_outputs, + load_pickled_dataframes, +) + +resourcefilepath = Path("./resources") +datestamp = datetime.date.today().strftime("__%Y_%m_%d") + +outputspath = Path("./outputs") + + +# 0) Find results_folder associated with a given batch_file (and get most recent [-1]) +results_folder = get_scenario_outputs("scaleup_tests", outputspath)[-1] + +# Declare path for output graphs from this script +make_graph_file_name = lambda stub: results_folder / f"{stub}.png" # noqa: E731 + +# look at one log (so can decide what to extract) +log = load_pickled_dataframes(results_folder) + +# 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(2015, 1, 1), Date(2020, 1, 1)) + +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'] + +colors = sns.color_palette("Set1", 4) # Blue, Orange, Green, Red + + +# Create subplots +fig, axs = plt.subplots(3, 1, figsize=(6, 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=colors[i]) +axs[0].set_title('HIV/AIDS') +axs[0].legend() +axs[0].axvline(x=2015, color='gray', linestyle='--') + +# Plot for df2 +for i, col in enumerate(tb_deaths.columns): + axs[1].plot(tb_deaths.index, tb_deaths[col], color=colors[i]) +axs[1].set_title('TB') +axs[1].axvline(x=2015, color='gray', linestyle='--') + +# Plot for df3 +for i, col in enumerate(malaria_deaths.columns): + axs[2].plot(malaria_deaths.index, malaria_deaths[col], color=colors[i]) +axs[2].set_title('Malaria') +axs[2].axvline(x=2015, color='gray', linestyle='--') + +for ax in axs: + ax.set_xlabel('Years') + ax.set_ylabel('Number deaths') + +plt.tight_layout() +plt.show() + diff --git a/src/scripts/malaria/analysis_malaria.py b/src/scripts/malaria/analysis_malaria.py index 56d05cf3ae..b2b4217dc6 100644 --- a/src/scripts/malaria/analysis_malaria.py +++ b/src/scripts/malaria/analysis_malaria.py @@ -34,8 +34,8 @@ resourcefilepath = Path("./resources") start_date = Date(2010, 1, 1) -end_date = Date(2016, 1, 1) -popsize = 300 +end_date = Date(2014, 1, 1) +popsize = 100 # set up the log config @@ -84,6 +84,15 @@ ) ) +# update parameters +sim.modules["Hiv"].parameters["do_scaleup"] = True +sim.modules["Tb"].parameters["do_scaleup"] = True +sim.modules["Malaria"].parameters["do_scaleup"] = True +sim.modules["Hiv"].parameters["scaleup_start"] = 2 +sim.modules["Tb"].parameters["scaleup_start"] = 2 +sim.modules["Malaria"].parameters["scaleup_start"] = 2 + + # Run the simulation and flush the logger sim.make_initial_population(n=popsize) sim.simulate(end_date=end_date) @@ -97,5 +106,5 @@ pickle.dump(dict(output), f, pickle.HIGHEST_PROTOCOL) # load the results -with open(outputpath / "default_run.pickle", "rb") as f: +with open(outputpath / "malaria_run.pickle", "rb") as f: output = pickle.load(f) diff --git a/src/scripts/oesophagealcancer_analyses/calc_5y_survival_following_treatment.py b/src/scripts/oesophagealcancer_analyses/calc_5y_survival_following_treatment.py index 192b6d9fa8..e54451d516 100644 --- a/src/scripts/oesophagealcancer_analyses/calc_5y_survival_following_treatment.py +++ b/src/scripts/oesophagealcancer_analyses/calc_5y_survival_following_treatment.py @@ -40,8 +40,17 @@ end_date = Date(2080, 1, 1) popsize = 1000 +# Establish the logger and look at only demography +log_config = { + 'filename': 'LogFile', + 'custom_levels': { + '*': logging.WARNING, # <-- + 'tlo.methods.demography': logging.INFO + } +} + # Establish the simulation object and set the seed -sim = Simulation(start_date=start_date, seed=0) +sim = Simulation(start_date=start_date, seed=0, log_config=log_config) # Register the appropriate modules sim.register(demography.Demography(resourcefilepath=resourcefilepath), @@ -66,19 +75,13 @@ sim.modules['OesophagealCancer'].parameters["init_prop_treatment_status_oes_cancer"] = [0.0] * 6 sim.modules['OesophagealCancer'].parameters["init_prob_palliative_care"] = 0.0 -# Establish the logger and look at only demography -custom_levels = {"*": logging.WARNING, # <-- - "tlo.methods.demography": logging.INFO - } -logfile = sim.configure_logging(filename="LogFile", custom_levels=custom_levels) - # Run the simulation sim.make_initial_population(n=popsize) sim.simulate(end_date=end_date) # Read the output: -output = parse_log_file(logfile) +output = parse_log_file(sim.log_filepath) # %% Analyse the output: diff --git a/src/scripts/oesophagealcancer_analyses/oesophagealcancer_analyses.py b/src/scripts/oesophagealcancer_analyses/oesophagealcancer_analyses.py index 23e6c183ed..eb66364737 100644 --- a/src/scripts/oesophagealcancer_analyses/oesophagealcancer_analyses.py +++ b/src/scripts/oesophagealcancer_analyses/oesophagealcancer_analyses.py @@ -48,8 +48,12 @@ def run_sim(service_availability): + log_config = { + 'filename': 'LogFile', + 'directory': outputpath + } # Establish the simulation object and set the seed - sim = Simulation(start_date=start_date, seed=0) + sim = Simulation(start_date=start_date, seed=0, log_config=log_config) # Register the appropriate modules sim.register(demography.Demography(resourcefilepath=resourcefilepath), @@ -68,14 +72,11 @@ def run_sim(service_availability): postnatal_supervisor.PostnatalSupervisor(resourcefilepath=resourcefilepath) ) - # Establish the logger - logfile = sim.configure_logging(filename="LogFile") - # Run the simulation sim.make_initial_population(n=popsize) sim.simulate(end_date=end_date) - return logfile + return sim.log_filepath def get_summary_stats(logfile): diff --git a/src/scripts/other_adult_cancers_analyses/calc_5y_survival_following_treatment.py b/src/scripts/other_adult_cancers_analyses/calc_5y_survival_following_treatment.py index 99631447c9..a50ec7f9a6 100644 --- a/src/scripts/other_adult_cancers_analyses/calc_5y_survival_following_treatment.py +++ b/src/scripts/other_adult_cancers_analyses/calc_5y_survival_following_treatment.py @@ -41,8 +41,20 @@ end_date = Date(2080, 1, 1) popsize = 1000 +# Establish the logger and look at only demography +log_config = { + 'filename': 'LogFile', + 'directory': outputpath, + 'custom_levels': { + '*': logging.WARNING, # <-- + 'tlo.methods.demography': logging.INFO, + 'tlo.methods.other_adult_cancers': logging.INFO, + 'tlo.methods.healthsystem': logging.INFO, + } +} + # Establish the simulation object and set the seed -sim = Simulation(start_date=start_date, seed=0) +sim = Simulation(start_date=start_date, seed=0, log_config=log_config) # Register the appropriate modules sim.register(demography.Demography(resourcefilepath=resourcefilepath), @@ -66,21 +78,12 @@ # sim.modules['OtherAdultCancer'].parameters["init_prop_treatment_status_other_adult_cancer"] = [0.0] * 3 # sim.modules['OtherAdultCancer'].parameters["init_prob_palliative_care"] = 0.0 -# Establish the logger and look at only demography -custom_levels = {"*": logging.WARNING, # <-- - "tlo.methods.demography": logging.INFO, - "tlo.methods.other_adult_cancers": logging.INFO, - 'tlo.methods.healthsystem': logging.INFO, - } -logfile = sim.configure_logging(filename="LogFile", custom_levels=custom_levels) - - # Run the simulation sim.make_initial_population(n=popsize) sim.simulate(end_date=end_date) # Read the output: -output = parse_log_file(logfile) +output = parse_log_file(sim.log_filepath) # %% Analyse the output: diff --git a/src/scripts/other_adult_cancers_analyses/other_adult_cancers_analyses.py b/src/scripts/other_adult_cancers_analyses/other_adult_cancers_analyses.py index ff17364713..310541dc71 100644 --- a/src/scripts/other_adult_cancers_analyses/other_adult_cancers_analyses.py +++ b/src/scripts/other_adult_cancers_analyses/other_adult_cancers_analyses.py @@ -44,8 +44,12 @@ def run_sim(allow_hsi): + log_config = { + 'filename': 'LogFile', + 'directory': outputpath + } # Establish the simulation object and set the seed - sim = Simulation(start_date=start_date, seed=0) + sim = Simulation(start_date=start_date, seed=0, log_config=log_config) # Register the appropriate modules sim.register(demography.Demography(resourcefilepath=resourcefilepath), @@ -60,14 +64,11 @@ def run_sim(allow_hsi): other_adult_cancers.OtherAdultCancer(resourcefilepath=resourcefilepath), ) - # Establish the logger - logfile = sim.configure_logging(filename="LogFile") - # Run the simulation sim.make_initial_population(n=popsize) sim.simulate(end_date=end_date) - return logfile + return sim.log_filepath def get_summary_stats(logfile): diff --git a/src/scripts/overview_paper/C_impact_of_healthsystem_assumptions/scenario_impact_of_healthsystem.py b/src/scripts/overview_paper/C_impact_of_healthsystem_assumptions/scenario_impact_of_healthsystem.py index a8df16deda..058f026537 100644 --- a/src/scripts/overview_paper/C_impact_of_healthsystem_assumptions/scenario_impact_of_healthsystem.py +++ b/src/scripts/overview_paper/C_impact_of_healthsystem_assumptions/scenario_impact_of_healthsystem.py @@ -19,7 +19,7 @@ from tlo import Date, logging from tlo.analysis.utils import get_parameters_for_status_quo, mix_scenarios from tlo.methods.fullmodel import fullmodel -from tlo.methods.scenario_switcher import ScenarioSwitcher +from tlo.methods.scenario_switcher import ImprovedHealthSystemAndCareSeekingScenarioSwitcher from tlo.scenario import BaseScenario @@ -48,7 +48,8 @@ def log_configuration(self): } def modules(self): - return fullmodel(resourcefilepath=self.resources) + [ScenarioSwitcher(resourcefilepath=self.resources)] + return fullmodel(resourcefilepath=self.resources) + [ + ImprovedHealthSystemAndCareSeekingScenarioSwitcher(resourcefilepath=self.resources)] def draw_parameters(self, draw_number, rng): if draw_number < len(self._scenarios): @@ -89,19 +90,28 @@ def _get_scenarios(self) -> Dict[str, Dict]: "Perfect Healthcare Seeking": mix_scenarios( get_parameters_for_status_quo(), - {'ScenarioSwitcher': {'max_healthsystem_function': False, 'max_healthcare_seeking': True}}, + {'ScenarioSwitcher': { + 'max_healthsystem_function': [False] * 2, + 'max_healthcare_seeking': [True] * 2 + }}, + # (These changes start immediately and last for the full length of the simulation.) ), "+ Perfect Clinical Practice": mix_scenarios( get_parameters_for_status_quo(), - {'ScenarioSwitcher': {'max_healthsystem_function': True, 'max_healthcare_seeking': True}}, + {'ScenarioSwitcher': { + 'max_healthsystem_function': [True] * 2, + 'max_healthcare_seeking': [True] * 2 + }}, ), "+ Perfect Consumables Availability": mix_scenarios( get_parameters_for_status_quo(), - {'ScenarioSwitcher': {'max_healthsystem_function': False, 'max_healthcare_seeking': True}}, + {'ScenarioSwitcher': { + 'max_healthsystem_function': [False] * 2, + 'max_healthcare_seeking': [True] * 2}}, {'HealthSystem': {'cons_availability': 'all'}} ), } diff --git a/src/scripts/profiling/run_profiling.py b/src/scripts/profiling/run_profiling.py index d6ec96655c..882894d6af 100644 --- a/src/scripts/profiling/run_profiling.py +++ b/src/scripts/profiling/run_profiling.py @@ -9,10 +9,16 @@ import numpy as np from psutil import disk_io_counters from pyinstrument import Profiler -from pyinstrument.renderers import HTMLRenderer +from pyinstrument.renderers import ConsoleRenderer, HTMLRenderer from pyinstrument.session import Session from scale_run import save_arguments_to_json, scale_run +try: + from ansi2html import Ansi2HTMLConverter + ANSI2HTML_AVAILABLE = True +except ImportError: + ANSI2HTML_AVAILABLE = False + from tlo import Simulation _PROFILING_RESULTS: Path = (Path(__file__).parents[3] / "profiling_results").resolve() @@ -176,17 +182,26 @@ def run_profiling( output_name: str = "profiling", write_html: bool = False, write_pyisession: bool = False, + write_flat_html: bool = True, interval: float = 2e-1, initial_population: int = 50000, simulation_years: int = 5, simulation_months: int = 0, mode_appt_constraints: Literal[0, 1, 2] = 2, additional_stats: Optional[List[Tuple[str, str]]] = None, + show_progress_bar: bool = False, + disable_log_output_to_stdout: bool = False, ) -> None: """ Uses pyinstrument to profile the scale_run simulation, writing the output in the requested formats. """ + if write_flat_html and not ANSI2HTML_AVAILABLE: + # Check if flat HTML output requested but ansi2html module not available at + # _start_ of function to avoid erroring after a potentially long profiling run + msg = "ansi2html required for flat HTML output." + raise ValueError(msg) + additional_stats = dict(() if additional_stats is None else additional_stats) # Create the profiler to record the stack @@ -208,7 +223,7 @@ def run_profiling( "log_filename": "scale_run_profiling", "log_level": "WARNING", "parse_log_file": False, - "show_progress_bar": True, + "show_progress_bar": show_progress_bar, "seed": 0, "disable_health_system": False, "disable_spurious_symptoms": False, @@ -218,6 +233,7 @@ def run_profiling( "record_hsi_event_details": False, "ignore_warnings": True, "log_final_population_checksum": False, + "disable_log_output_to_stdout": disable_log_output_to_stdout, } output_arg_file = output_dir / f"{output_name}.args.json" @@ -253,7 +269,11 @@ def run_profiling( # Renderer initialisation options: # show_all: removes library calls where identifiable # timeline: if true, samples are left in chronological order rather than total time - html_renderer = HTMLRenderer(show_all=False, timeline=False) + html_renderer = HTMLRenderer( + show_all=False, + timeline=False, + processor_options={"show_regex": ".*/tlo/.*", "hide_regex": ".*/pandas/.*"} + ) print(f"Writing {output_html_file}", end="...", flush=True) with open(output_html_file, "w") as f: f.write(html_renderer.render(scale_run_session)) @@ -268,13 +288,29 @@ def run_profiling( f"\tWas : {additional_stats['html_output']}" f"\tReplaced by: {output_html_file}" ) - additional_stats["html_output"] = str(output_html_file) + additional_stats["html_output"] = str(output_html_file.name) if write_pyisession: output_ipysession_file = output_dir / f"{output_name}.pyisession" print(f"Writing {output_ipysession_file}", end="...", flush=True) scale_run_session.save(output_ipysession_file) print("done") + + if write_flat_html: + output_html_file = output_dir / f"{output_name}.flat.html" + console_renderer = ConsoleRenderer( + show_all=False, + timeline=False, + color=True, + flat=True, + processor_options={"show_regex": ".*/tlo/.*", "hide_regex": ".*/pandas/.*"} + ) + converter = Ansi2HTMLConverter(title=output_name) + print(f"Writing {output_html_file}", end="...", flush=True) + with open(output_html_file, "w") as f: + f.write(converter.convert(console_renderer.render(scale_run_session))) + print("done") + additional_stats["flat_html_output"] = str(output_html_file.name) # Write the statistics file, main output output_stat_file = output_dir / f"{output_name}.stats.json" @@ -304,7 +340,7 @@ def run_profiling( "Root directory to write profiling outputs to. Results will be written to " "a subdirectory within this directory based on the date-time at which the " "profiling run was started, specifically using the format codes from " - "strftime, within a directory corresponding to '%Y/%m/%d/%H%M'." + "strftime, within a directory corresponding to 'YY/mm/dd/HHMM'." ), default=_PROFILING_RESULTS, ) @@ -329,6 +365,12 @@ def run_profiling( action="store_true", dest="write_pyisession", ) + parser.add_argument( + "--flat-html", + action="store_true", + help="Write flat HTML output in addition to statistics output.", + dest="write_flat_html", + ) parser.add_argument( "-i", "--interval-seconds", @@ -382,6 +424,16 @@ def run_profiling( "as strings." ), ) + parser.add_argument( + "--show-progress-bar", + help="Show simulation progress bar during simulation rather than log output", + action="store_true", + ) + parser.add_argument( + "--disable-log-output-to-stdout", + help="Disable simulation log output being displayed in stdout stream", + action="store_true", + ) args = parser.parse_args() diff --git a/src/scripts/profiling/scale_run.py b/src/scripts/profiling/scale_run.py index a96e7999ec..735d1e7ba3 100644 --- a/src/scripts/profiling/scale_run.py +++ b/src/scripts/profiling/scale_run.py @@ -44,6 +44,7 @@ def scale_run( log_level: Literal["CRITICAL", "DEBUG", "FATAL", "WARNING", "INFO"] = "WARNING", parse_log_file: bool = False, show_progress_bar: bool = False, + disable_log_output_to_stdout: bool = False, seed: int = 0, disable_health_system: bool = False, disable_spurious_symptoms: bool = False, @@ -70,6 +71,7 @@ def scale_run( "filename": log_filename, "directory": output_dir, "custom_levels": {"*": getattr(logging, log_level)}, + "suppress_stdout": disable_log_output_to_stdout, } sim = Simulation( @@ -192,6 +194,11 @@ def scale_run( help="Show progress bar during simulation rather than log output", action="store_true", ) + parser.add_argument( + "--disable-log-output-to-stdout", + help="Disable log output being displayed in stdout stream", + action="store_true", + ) parser.add_argument( "--seed", help="Seed for base pseudo-random number generator", diff --git a/src/scripts/prostate_cancer_analyses/calc_5y_survival_following_treatment.py b/src/scripts/prostate_cancer_analyses/calc_5y_survival_following_treatment.py index 026650fc43..2e56e132c0 100644 --- a/src/scripts/prostate_cancer_analyses/calc_5y_survival_following_treatment.py +++ b/src/scripts/prostate_cancer_analyses/calc_5y_survival_following_treatment.py @@ -41,8 +41,17 @@ end_date = Date(2030, 1, 1) popsize = 10000 +# Establish the logger and look at only demography +log_config = { + 'filename': 'LogFile', + 'directory': outputpath, + 'custom_levels': {"*": logging.WARNING, # <-- + "tlo.methods.demography": logging.INFO + } + } + # Establish the simulation object and set the seed -sim = Simulation(start_date=start_date, seed=0) +sim = Simulation(start_date=start_date, seed=0, log_config=log_config) # Register the appropriate modules sim.register(demography.Demography(resourcefilepath=resourcefilepath), @@ -69,19 +78,13 @@ # sim.modules['ProstateCancer'].parameters["init_prop_treatment_status_prostate_cancer"] = [0.0] * 3 # sim.modules['ProstateCancer'].parameters["init_prob_palliative_care"] = 0.0 -# Establish the logger and look at only demography -custom_levels = {"*": logging.WARNING, # <-- - "tlo.methods.demography": logging.INFO - } -logfile = sim.configure_logging(filename="LogFile", custom_levels=custom_levels) - # Run the simulation sim.make_initial_population(n=popsize) sim.simulate(end_date=end_date) # Read the output: -output = parse_log_file(logfile) +output = parse_log_file(sim.log_filepath) # %% Analyse the output: @@ -106,16 +109,17 @@ # calc % of those that were alive 5 years after starting treatment (not died of any cause): 1 - ( - len(cohort_treated.loc[cohort_treated['days_treatment_to_death'] < (5*365.25)]) / - len(cohort_treated) + len(cohort_treated.loc[cohort_treated['days_treatment_to_death'] < (5 * 365.25)]) / + len(cohort_treated) ) # 0.77 # calc % of those that had not died of prostate cancer 5 years after starting treatment (could have died of another # cause): 1 - ( - len( - cohort_treated.loc[ - (cohort_treated['cause'] == 'ProstateCancer') & (cohort_treated['days_treatment_to_death'] < (5*365.25)) - ] - ) / len(cohort_treated) -) # 0.87 + len( + cohort_treated.loc[ + (cohort_treated['cause'] == 'ProstateCancer') & ( + cohort_treated['days_treatment_to_death'] < (5 * 365.25)) + ] + ) / len(cohort_treated) +) # 0.87 diff --git a/src/scripts/prostate_cancer_analyses/prostate_cancer_analyses.py b/src/scripts/prostate_cancer_analyses/prostate_cancer_analyses.py index b4b525b0f8..0d04a93fd1 100644 --- a/src/scripts/prostate_cancer_analyses/prostate_cancer_analyses.py +++ b/src/scripts/prostate_cancer_analyses/prostate_cancer_analyses.py @@ -50,8 +50,12 @@ def run_sim(service_availability): + log_config = { + 'filename': 'LogFile', + 'directory': outputpath + } # Establish the simulation object and set the seed - sim = Simulation(start_date=start_date, seed=0) + sim = Simulation(start_date=start_date, seed=0, log_config=log_config) # Register the appropriate modules sim.register(care_of_women_during_pregnancy.CareOfWomenDuringPregnancy(resourcefilepath=resourcefilepath), @@ -71,14 +75,11 @@ def run_sim(service_availability): postnatal_supervisor.PostnatalSupervisor(resourcefilepath=resourcefilepath) ) - # Establish the logger - logfile = sim.configure_logging(filename="LogFile") - # Run the simulation sim.make_initial_population(n=popsize) sim.simulate(end_date=end_date) - return logfile + return sim.log_filepath def get_summary_stats(logfile): @@ -248,4 +249,4 @@ def get_cols_excl_none(allcols, stub): # ** 5-year survival following treatment -# See sepaerate file +# See separate file diff --git a/src/scripts/schistosomiasis/schisto_analysis.py b/src/scripts/schistosomiasis/schisto_analysis.py index d33890c34e..cfed7b3528 100644 --- a/src/scripts/schistosomiasis/schisto_analysis.py +++ b/src/scripts/schistosomiasis/schisto_analysis.py @@ -16,14 +16,24 @@ def run_simulation(popsize=10000, haem=True, mansoni=True, mda_execute=True): + outputpath = Path("./outputs") # folder for convenience of storing outputs # The resource files resourcefilepath = Path("./resources") start_date = Date(2010, 1, 1) end_date = Date(2011, 2, 1) popsize = popsize + # Sets all modules to WARNING threshold, then alters schisto to INFO + log_config = { + 'filename': 'LogFile', + 'directory': outputpath, + 'custom_levels ': {"*": logging.WARNING, + "tlo.methods.schisto": logging.INFO, + } + } + # Establish the simulation object - sim = Simulation(start_date=start_date) + sim = Simulation(start_date=start_date, log_config=log_config) # Register the appropriate modules sim.register(demography.Demography(resourcefilepath=resourcefilepath)) @@ -36,13 +46,6 @@ def run_simulation(popsize=10000, haem=True, mansoni=True, mda_execute=True): if mansoni: sim.register(schisto.Schisto_Mansoni(resourcefilepath=resourcefilepath, symptoms_and_HSI=False)) - # Sets all modules to WARNING threshold, then alters schisto to INFO - custom_levels = {"*": logging.WARNING, - "tlo.methods.schisto": logging.INFO, - } - # configure logging after registering modules with custom levels - logfile = sim.configure_logging(filename="LogFile", custom_levels=custom_levels) - # Run the simulation sim.seed_rngs(int(np.random.uniform(0, 1) * 0 + 1000)) # initialise the population @@ -51,12 +54,13 @@ def run_simulation(popsize=10000, haem=True, mansoni=True, mda_execute=True): # # start the simulation sim.simulate(end_date=end_date) # fh.flush() - output = parse_log_file(logfile) + output = parse_log_file(sim.log_filepath) return sim, output sim, output = run_simulation(popsize=10000, haem=True, mansoni=False, mda_execute=False) + # --------------------------------------------------------------------------------------------------------- # Saving the results - prevalence, mwb, dalys and parameters used # --------------------------------------------------------------------------------------------------------- @@ -286,6 +290,8 @@ def plot_prev_high_infection_per_district(infection, high_inf_distr): districts_prevalence, districts_mwb, districts_high_inf_prev = get_values_per_district('Haematobium') expected_district_prevalence = get_expected_prevalence('Haematobium') plot_prevalence_per_district('Haematobium', districts_prevalence, expected_district_prevalence) + + # plot_mwb_per_district('Haematobium', districts_mwb) # plot_prev_high_infection_per_district('Haematobium', districts_high_inf_prev) @@ -427,7 +433,6 @@ def plot_high_inf_years(): plot_prevalent_years() plot_high_inf_years() - # DALYS loger_daly = output['tlo.methods.healthburden']["DALYS"] loger_daly.drop(columns=['sex', 'YLL_Demography_Other'], inplace=True) diff --git a/src/tlo/analysis/hsi_events.py b/src/tlo/analysis/hsi_events.py index 6176488630..9bc973f67c 100644 --- a/src/tlo/analysis/hsi_events.py +++ b/src/tlo/analysis/hsi_events.py @@ -47,7 +47,7 @@ def get_hsi_event_classes_per_module( module = importlib.import_module(f'tlo.methods.{module_name}') tlo_module_classes = [ obj for _, obj in inspect.getmembers(module) - if is_valid_tlo_module_subclass(obj, excluded_modules) + if is_valid_tlo_module_subclass(obj, {}) ] hsi_event_classes = [ obj for _, obj in inspect.getmembers(module) @@ -465,6 +465,9 @@ def main(): """Entry point to do the inspection of HSI events when running as script.""" args = _parse_command_line_args() warnings.simplefilter('ignore') + if args.json_file is None and args.merge_json_details: + msg = "Cannot merge details if JSON file not specified" + raise ValueError(msg) if args.json_file is not None: with open(args.json_file, 'r') as f: hsi_event_details = json.load(f) diff --git a/src/tlo/analysis/utils.py b/src/tlo/analysis/utils.py index 48f8b63709..075aadec06 100644 --- a/src/tlo/analysis/utils.py +++ b/src/tlo/analysis/utils.py @@ -254,13 +254,11 @@ def extract_results(results_folder: Path, """ def get_multiplier(_draw, _run): - """Helper function to get the multiplier from the simulation, if do_scaling=True. + """Helper function to get the multiplier from the simulation. Note that if the scaling factor cannot be found a `KeyError` is thrown.""" - if not do_scaling: - return 1.0 - else: - return load_pickled_dataframes(results_folder, _draw, _run, 'tlo.methods.population' - )['tlo.methods.population']['scaling_factor']['scaling_factor'].values[0] + return load_pickled_dataframes( + results_folder, _draw, _run, 'tlo.methods.population' + )['tlo.methods.population']['scaling_factor']['scaling_factor'].values[0] if custom_generate_series is None: # If there is no `custom_generate_series` provided, it implies that function required selects the specified @@ -293,7 +291,10 @@ def generate_series(dataframe: pd.DataFrame) -> pd.Series: df: pd.DataFrame = load_pickled_dataframes(results_folder, draw, run, module)[module][key] output_from_eval: pd.Series = generate_series(df) assert pd.Series == type(output_from_eval), 'Custom command does not generate a pd.Series' - res[draw_run] = output_from_eval * get_multiplier(draw, run) + if do_scaling: + res[draw_run] = output_from_eval * get_multiplier(draw, run) + else: + res[draw_run] = output_from_eval except KeyError: # Some logs could not be found - probably because this run failed. @@ -610,6 +611,7 @@ def filter_treatments(_treatments: Iterable[str], depth: int = 1) -> List[str]: [ "".join(f"{x}_" for i, x in enumerate(t.split('_')) if i < depth).rstrip('_') + '_*' for t in set(_treatments) + if t # In the event an abstract base class is detected, that does not set TREATMENT_ID by default ] ))) @@ -1124,6 +1126,42 @@ def get_parameters_for_status_quo() -> Dict: "mode_appt_constraints": 1, "cons_availability": "default", "beds_availability": "default", + "equip_availability": "all", # <--- NB. Existing calibration is assuming all equipment is available + }, + } + +def get_parameters_for_standard_mode2_runs() -> Dict: + """ + Returns a dictionary of parameters and their updated values to indicate + the "standard mode 2" scenario. + + The return dict is in the form: + e.g. { + 'Depression': { + 'pr_assessed_for_depression_for_perinatal_female': 1.0, + 'pr_assessed_for_depression_in_generic_appt_level1': 1.0, + }, + 'Hiv': { + 'prob_start_art_or_vs': 1.0, + } + } + """ + + return { + "SymptomManager": { + "spurious_symptoms": True, + }, + "HealthSystem": { + 'Service_Availability': ['*'], + "use_funded_or_actual_staffing": "actual", + "mode_appt_constraints": 1, + "mode_appt_constraints_postSwitch": 2, # <-- Include a transition to mode 2, to pick up any issues with this + "year_mode_switch": 2012, # <-- Could make this quite soon, but I'd say >1 year + "tclose_overwrite": 1, # <-- In most of our runs in mode 2, we chose to overwrite tclose + "tclose_days_offset_overwrite": 7, # <-- and usually set it to 7. + "cons_availability": "default", + "beds_availability": "default", + "equip_availability": "all", # <--- NB. Existing calibration is assuming all equipment is available }, } diff --git a/src/tlo/cli.py b/src/tlo/cli.py index 5d4f0b8e26..c5b0c3f86d 100644 --- a/src/tlo/cli.py +++ b/src/tlo/cli.py @@ -44,17 +44,23 @@ def cli(ctx, config_file, verbose): ctx.obj["verbose"] = verbose -@cli.command() +@cli.command(context_settings=dict(ignore_unknown_options=True)) @click.argument("scenario_file", type=click.Path(exists=True)) @click.option("--draw-only", is_flag=True, help="Only generate draws; do not run the simulation") @click.option("--draw", "-d", nargs=2, type=int) @click.option("--output-dir", type=str) -def scenario_run(scenario_file, draw_only, draw: tuple, output_dir=None): +@click.argument('scenario_args', nargs=-1, type=click.UNPROCESSED) +def scenario_run(scenario_file, draw_only, draw: tuple, output_dir=None, scenario_args=None): """Run the specified scenario locally. SCENARIO_FILE is path to file containing a scenario class """ scenario = load_scenario(scenario_file) + + # if we have other scenario arguments, parse them + if scenario_args is not None: + scenario.parse_arguments(scenario_args) + config = scenario.save_draws(return_config=True) json_string = json.dumps(config, indent=2) @@ -88,9 +94,10 @@ def scenario_run(scenario_file, draw_only, draw: tuple, output_dir=None): @click.option("--asserts-on", type=bool, default=False, is_flag=True, help="Enable assertions in simulation run.") @click.option("--more-memory", type=bool, default=False, is_flag=True, help="Request machine wth more memory (for larger population sizes).") +@click.option("--image-tag", type=str, help="Tag of the Docker image to use.") @click.option("--keep-pool-alive", type=bool, default=False, is_flag=True, hidden=True) @click.pass_context -def batch_submit(ctx, scenario_file, asserts_on, more_memory, keep_pool_alive): +def batch_submit(ctx, scenario_file, asserts_on, more_memory, keep_pool_alive, image_tag=None): """Submit a scenario to the batch system. SCENARIO_FILE is path to file containing scenario class. @@ -180,8 +187,14 @@ def batch_submit(ctx, scenario_file, asserts_on, more_memory, keep_pool_alive): password=config["REGISTRY"]["KEY"], ) - # Name of the image in the registry - image_name = config["REGISTRY"]["SERVER"] + "/" + config["REGISTRY"]["IMAGE_NAME"] + # url of the docker image to run the tasks + image_name = f"{config['REGISTRY']['SERVER']}/{config['REGISTRY']['IMAGE']}" + + # use the supplied image tag if provided, otherwise use the default + if image_tag is None: + image_name = f"{image_name}:{config['REGISTRY']['DEFAULT_TAG']}" + else: + image_name = f"{image_name}:{image_tag}" # Create container configuration, prefetching Docker images from the container registry container_conf = batch_models.ContainerConfiguration( @@ -469,11 +482,11 @@ def print_basic_job_details(job: dict): @cli.command() -@click.argument("job_id", type=str) +@click.argument("job_ids", type=str, nargs=-1) @click.option("--username", type=str, hidden=True) @click.option("--verbose", default=False, is_flag=True, hidden=True) @click.pass_context -def batch_download(ctx, job_id, username, verbose): +def batch_download(ctx, job_ids, username, verbose): """Download output files for a job.""" config = load_config(ctx.obj["config_file"]) @@ -518,17 +531,18 @@ def walk_fileshare(dir_name): share_client = ShareClient.from_connection_string(config['STORAGE']['CONNECTION_STRING'], config['STORAGE']['FILESHARE']) - # if the job directory exist, exit with error - top_level = f"{username}/{job_id}" - destination = Path(".", "outputs", top_level) - if os.path.exists(destination): - print("ERROR: Local directory already exists. Please move or delete.") - print("Directory:", destination) - return - - print(f"Downloading {top_level}") - walk_fileshare(top_level) - print("\rDownload complete. ") + for job_id in job_ids: + # if the job directory exist, print error and continue to next job_id + top_level = f"{username}/{job_id}" + destination = Path(".", "outputs", top_level) + if os.path.exists(destination): + print("ERROR: Local directory already exists. Please move or delete.") + print("Directory:", destination) + continue + + print(f"Downloading {top_level}") + walk_fileshare(top_level) + print("\rDownload complete. ") def load_config(config_file): diff --git a/src/tlo/core.py b/src/tlo/core.py index 8fe3291392..3d3fd3c171 100644 --- a/src/tlo/core.py +++ b/src/tlo/core.py @@ -4,13 +4,19 @@ specification for parameters and properties, and the base Module class for disease modules. """ +from __future__ import annotations + import json -import typing from enum import Enum, auto +from typing import TYPE_CHECKING import numpy as np import pandas as pd +if TYPE_CHECKING: + from typing import Optional + + from tlo.simulation import Simulation class Types(Enum): """Possible types for parameters and properties. @@ -32,6 +38,7 @@ class Types(Enum): DATA_FRAME = auto() STRING = auto() DICT = auto() + BITSET = auto() class Specifiable: @@ -49,7 +56,8 @@ class Specifiable: Types.SERIES: object, Types.DATA_FRAME: object, Types.STRING: object, - Types.DICT: object + Types.DICT: object, + Types.BITSET: np.uint32, } # Map our Types to Python types @@ -64,7 +72,8 @@ class Specifiable: Types.SERIES: pd.Series, Types.DATA_FRAME: pd.DataFrame, Types.STRING: object, - Types.DICT: dict + Types.DICT: dict, + Types.BITSET: int, } def __init__(self, type_, description, categories=None): @@ -120,6 +129,7 @@ class Property(Specifiable): float: float("nan"), "category": float("nan"), object: float("nan"), + np.uint32: 0, } def __init__(self, type_, description, categories=None, *, ordered=False): @@ -231,6 +241,7 @@ class attribute on a subclass. # parameters created from the PARAMETERS specification. __slots__ = ('name', 'parameters', 'rng', 'sim') + def __init__(self, name=None): """Construct a new disease module ready to be included in a simulation. @@ -240,9 +251,9 @@ def __init__(self, name=None): :param name: the name to use for this module. Defaults to the concrete subclass' name. """ self.parameters = {} - self.rng: typing.Optional[np.random.RandomState] = None + self.rng: Optional[np.random.RandomState] = None self.name = name or self.__class__.__name__ - self.sim = None + self.sim: Optional[Simulation] = None def load_parameters_from_dataframe(self, resource: pd.DataFrame): """Automatically load parameters from resource dataframe, updating the class parameter dictionary @@ -277,7 +288,7 @@ def load_parameters_from_dataframe(self, resource: pd.DataFrame): f"The value of '{parameter_value}' for parameter '{parameter_name}' " f"could not be parsed as a {parameter_definition.type_.name} data type" ) - if parameter_definition.python_type == list: + if parameter_definition.python_type is list: try: # chose json.loads instead of save_eval # because it raises error instead of joining two strings without a comma diff --git a/src/tlo/methods/alri.py b/src/tlo/methods/alri.py index e4b0b46d17..70ac14fe2d 100644 --- a/src/tlo/methods/alri.py +++ b/src/tlo/methods/alri.py @@ -19,12 +19,12 @@ Health care seeking is prompted by the onset of the symptom. The individual can be treated; if successful the risk of death is lowered and the person is "cured" (symptom resolved) some days later. """ +from __future__ import annotations -import types from collections import defaultdict from itertools import chain from pathlib import Path -from typing import Dict, List, Tuple, Union +from typing import TYPE_CHECKING, Dict, List, Tuple, Union import numpy as np import pandas as pd @@ -34,10 +34,15 @@ from tlo.lm import LinearModel, LinearModelType, Predictor from tlo.methods import Metadata from tlo.methods.causes import Cause -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom from tlo.util import random_date, sample_outcome +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + from tlo.population import IndividualProperties + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -50,7 +55,7 @@ # --------------------------------------------------------------------------------------------------------- -class Alri(Module): +class Alri(Module, GenericFirstAppointmentsMixin): """This is the disease module for Acute Lower Respiratory Infections.""" INIT_DEPENDENCIES = { @@ -1009,139 +1014,85 @@ def look_up_consumables(self): get_item_code = self.sim.modules['HealthSystem'].get_item_code_from_item_name - def get_dosage_for_age_in_months(age_in_whole_months: float, doses_by_age_in_months: Dict[int, float]): - """Returns the dose corresponding to age, using the lookup provided in `doses`. The format of `doses` is: - {: }.""" - - for upper_age_bound_in_months, _dose in sorted(doses_by_age_in_months.items()): - if age_in_whole_months < upper_age_bound_in_months: - return _dose - return _dose - - # # # # # # Dosages by age # # # # # # + # # # # # # Dosages by weight # # # # # # + # Assuming average weight of 0-5 is 12kg (abstraction). Doses sourced for WHO Pocket book of hospital care for + # children: Second edition 2014 # Antibiotic therapy ------------------- - # Antibiotics for non-severe pneumonia - oral amoxicillin for 5 days + # Antibiotics for non-severe pneumonia - oral amoxicillin for 5 days (40mg/kg BD - ((12*40)*2)*5 =4800mg) self.consumables_used_in_hsi['Amoxicillin_tablet_or_suspension_5days'] = { - get_item_code(item='Amoxycillin 250mg_1000_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {2: 0, 12: 0.006, 36: 0.012, np.inf: 0.018} - ), - get_item_code(item='Amoxycillin 125mg/5ml suspension, PFR_0.025_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {2: 0, 12: 1, 36: 2, np.inf: 3} - ), - } + get_item_code(item='Amoxycillin 250mg_1000_CMST'): 4800, + get_item_code(item='Amoxycillin 125mg/5ml suspension, PFR_0.025_CMST'): 192} # 25mg/ml - 4800/25 - # Antibiotics for non-severe pneumonia - oral amoxicillin for 3 days + # Antibiotics for non-severe pneumonia - oral amoxicillin for 3 days (40mg/kg BD - ((12*40)*2)*3 =2880mg) self.consumables_used_in_hsi['Amoxicillin_tablet_or_suspension_3days'] = { - get_item_code(item='Amoxycillin 250mg_1000_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {2: 0, 12: 0.01, 36: 0.02, np.inf: 0.03} - ), - get_item_code(item='Amoxycillin 125mg/5ml suspension, PFR_0.025_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {2: 0, 12: 1, 36: 2, np.inf: 3} - ), - } + get_item_code(item='Amoxycillin 250mg_1000_CMST'): 2880, + get_item_code(item='Amoxycillin 125mg/5ml suspension, PFR_0.025_CMST'): 115} # 25mg/ml - 2880/25 - # Antibiotics for non-severe pneumonia - oral amoxicillin for 7 days for young infants only + # Antibiotics for non-severe pneumonia - oral amoxicillin for 7 days for young infants only (40mg/kg BD - + # ((12*40)*2)*7 =6720mg) self.consumables_used_in_hsi['Amoxicillin_tablet_or_suspension_7days'] = { - get_item_code(item='Amoxycillin 250mg_1000_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {1: 0.004, 2: 0.006, np.inf: 0.01} - ), - get_item_code(item='Amoxycillin 125mg/5ml suspension, PFR_0.025_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {1: 0.4, 2: 0.5, np.inf: 1} - ), - } + get_item_code(item='Amoxycillin 250mg_1000_CMST'): 6720, + get_item_code(item='Amoxycillin 125mg/5ml suspension, PFR_0.025_CMST'): 269} # 25mg/ml - 6720/25 # Antibiotic therapy for severe pneumonia - ampicillin package + # Amp. dose - 50mg/KG QDS 5 days = (50*12)*4)*5 = 12_000mg + # Gent. dose -7.5mg/kg per day 5 days = (7.5*12)*5 = 450mg self.consumables_used_in_hsi['1st_line_IV_antibiotics'] = { - get_item_code(item='Ampicillin injection 500mg, PFR_each_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {1: 3.73, 2: 5.6, 4: 8, 12: 16, 36: 24, np.inf: 40} - ), - get_item_code(item='Gentamicin Sulphate 40mg/ml, 2ml_each_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {1: 0.7, 2: 1.4, 4: 2.81, 12: 4.69, 36: 7.03, np.inf: 9.37} - ), + get_item_code(item='Ampicillin injection 500mg, PFR_each_CMST'): 24, # 500mg vial -12_000/500 + get_item_code(item='Gentamicin Sulphate 40mg/ml, 2ml_each_CMST'): 6, # 80mg/2ml = 450/8 get_item_code(item='Cannula iv (winged with injection pot) 16_each_CMST'): 1, get_item_code(item='Syringe, Autodisable SoloShot IX '): 1 } # # Antibiotic therapy for severe pneumonia - benzylpenicillin package when ampicillin is not available + # Benpen dose - 50_000IU/KG QDS 5 days = (50_000*12)*4)*5 = 12_000_000IU = 8g (approx) + # Gent. dose -7.5mg/kg per day 5 days = (7.5*12)*5 = 450mg self.consumables_used_in_hsi['Benzylpenicillin_gentamicin_therapy_for_severe_pneumonia'] = { - get_item_code(item='Benzylpenicillin 3g (5MU), PFR_each_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {1: 2, 2: 5, 4: 8, 12: 15, 36: 24, np.inf: 34} - ), - get_item_code(item='Gentamicin Sulphate 40mg/ml, 2ml_each_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {1: 0.7, 2: 1.4, 4: 2.81, 12: 4.69, 36: 7.03, np.inf: 9.37} - ), + get_item_code(item='Benzylpenicillin 3g (5MU), PFR_each_CMST'): 8, + get_item_code(item='Gentamicin Sulphate 40mg/ml, 2ml_each_CMST'): 6, # 80mg/2ml = 450/8 get_item_code(item='Cannula iv (winged with injection pot) 16_each_CMST'): 1, get_item_code(item='Syringe, Autodisable SoloShot IX '): 1 } # Second line of antibiotics for severe pneumonia, if Staph not suspected + # Ceft. dose = 80mg/kg per day 5 days = (80*12)*5 = 4800mg self.consumables_used_in_hsi['Ceftriaxone_therapy_for_severe_pneumonia'] = { - get_item_code(item='Ceftriaxone 1g, PFR_each_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {4: 1.5, 12: 3, 36: 5, np.inf: 7} - ), + get_item_code(item='Ceftriaxone 1g, PFR_each_CMST'): 1, # smallest unit is 1g get_item_code(item='Cannula iv (winged with injection pot) 16_each_CMST'): 1, get_item_code(item='Syringe, Autodisable SoloShot IX '): 1 } # Second line of antibiotics for severe pneumonia, if Staph is suspected + # Flucox. dose = 50mg/kg QDS 7 days = ((50*12)*4)*7 = 16_800mg + # Oral flucox dose. = same self.consumables_used_in_hsi['2nd_line_Antibiotic_therapy_for_severe_staph_pneumonia'] = { - get_item_code(item='Flucloxacillin 250mg, vial, PFR_each_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {2: 21, 4: 22.4, 12: 37.3, 36: 67.2, 60: 93.3, np.inf: 140} - ), - get_item_code(item='Gentamicin Sulphate 40mg/ml, 2ml_each_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {4: 2.81, 12: 4.69, 36: 7.03, 60: 9.37, np.inf: 13.6} - ), + get_item_code(item='Flucloxacillin 250mg, vial, PFR_each_CMST'): 16_800, + get_item_code(item='Gentamicin Sulphate 40mg/ml, 2ml_each_CMST'): 6, # 80mg/2ml = 450/8 get_item_code(item='Cannula iv (winged with injection pot) 16_each_CMST'): 1, get_item_code(item='Syringe, Autodisable SoloShot IX '): 1, - get_item_code(item='Flucloxacillin 250mg_100_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {4: 0.42, 36: 0.84, 60: 1.68, np.inf: 1.68} - ), - } + get_item_code(item='Flucloxacillin 250mg_100_CMST'): 16_800} # First dose of antibiotic before referral ------------------- - + # single dose of 7.5mg gent and 50mg/g amp. given # Referral process in iCCM for severe pneumonia, and at health centres for HIV exposed/infected self.consumables_used_in_hsi['First_dose_oral_amoxicillin_for_referral'] = { - get_item_code(item='Amoxycillin 250mg_1000_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {12: 0.001, 36: 0.002, np.inf: 0.003} - ), + get_item_code(item='Amoxycillin 250mg_1000_CMST'): 250, } # Referral process at health centres for severe cases self.consumables_used_in_hsi['First_dose_IM_antibiotics_for_referral'] = { - get_item_code(item='Ampicillin injection 500mg, PFR_each_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {4: 0.4, 12: 0.8, 36: 1.4, np.inf: 2} - ), - get_item_code(item='Gentamicin Sulphate 40mg/ml, 2ml_each_CMST'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {4: 0.56, 12: 0.94, 36: 1.41, np.inf: 1.87} - ), + get_item_code(item='Ampicillin injection 500mg, PFR_each_CMST'): 2, # 2 x 500mg vial + get_item_code(item='Gentamicin Sulphate 40mg/ml, 2ml_each_CMST'): 2, # assuming single dose at referral get_item_code(item='Cannula iv (winged with injection pot) 16_each_CMST'): 1, get_item_code(item='Syringe, Autodisable SoloShot IX '): 1 } # Oxygen, pulse oximetry and x-ray ------------------- - # Oxygen for hypoxaemia + # Oxygen for hypoxaemia - 5/l per min (Approx) for 3 days ((24*60)*5)*3 self.consumables_used_in_hsi['Oxygen_Therapy'] = { - get_item_code(item='Oxygen, 1000 liters, primarily with oxygen cylinders'): 1, + get_item_code(item='Oxygen, 1000 liters, primarily with oxygen cylinders'): 21_600, } # Pulse oximetry @@ -1157,10 +1108,7 @@ def get_dosage_for_age_in_months(age_in_whole_months: float, doses_by_age_in_mon # Optional consumables ------------------- # Paracetamol self.consumables_used_in_hsi['Paracetamol_tablet'] = { - get_item_code(item='Paracetamol, tablet, 100 mg'): - lambda _age: get_dosage_for_age_in_months(int(_age * 12.0), - {36: 12, np.inf: 18} - ), + get_item_code(item='Paracetamol, tablet, 100 mg'): 240, # 20mg/kg } # Maintenance of fluids via nasograstric tube @@ -1173,11 +1121,6 @@ def get_dosage_for_age_in_months(age_in_whole_months: float, doses_by_age_in_mon get_item_code(item='Salbutamol sulphate 1mg/ml, 5ml_each_CMST'): 2 } - # Bronchodilator - oral - self.consumables_used_in_hsi['Oral_Brochodilator'] = { - get_item_code(item='Salbutamol, syrup, 2 mg/5 ml'): 1, - get_item_code(item='Salbutamol, tablet, 4 mg'): 1 - } def end_episode(self, person_id): """End the episode infection for a person (i.e. reset all properties to show no current infection or @@ -1310,7 +1253,7 @@ def do_effects_of_treatment_and_return_outcome(self, person_id, antibiotic_provi # Gather underlying properties that will affect success of treatment SpO2_level = person.ri_SpO2_level - symptoms = self.sim.modules['SymptomManager'].has_what(person_id) + symptoms = self.sim.modules['SymptomManager'].has_what(person_id=person_id) imci_symptom_based_classification = self.get_imci_classification_based_on_symptoms( child_is_younger_than_2_months=person.age_exact_years < (2.0 / 12.0), symptoms=symptoms, @@ -1341,21 +1284,6 @@ def do_effects_of_treatment_and_return_outcome(self, person_id, antibiotic_provi else: return 'failure' - def on_presentation(self, person_id, hsi_event): - """Action taken when a child (under 5 years old) presents at a generic appointment (emergency or non-emergency) - with symptoms of `cough` or `difficult_breathing`.""" - - self.record_sought_care_for_alri() - - # All persons have an initial out-patient appointment at the current facility level. - self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=HSI_Alri_Treatment(person_id=person_id, module=self, - facility_level=hsi_event.ACCEPTED_FACILITY_LEVEL), - topen=self.sim.date, - tclose=self.sim.date + pd.DateOffset(days=1), - priority=1 - ) - def record_sought_care_for_alri(self): """Count that the person is seeking care""" self.logging_event.new_seeking_care() @@ -1433,6 +1361,38 @@ def _ultimate_treatment_indicated_for_patient(classification_for_treatment_decis else: raise ValueError(f'Classification not recognised: {classification_for_treatment_decision}') + def do_at_generic_first_appt( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + facility_level: str, + **kwargs, + ) -> None: + # Action taken when a child (under 5 years old) presents at a + # generic appointment (emergency or non-emergency) with symptoms + # of `cough` or `difficult_breathing`. + if individual_properties["age_years"] <= 5 and ( + ("cough" in symptoms) or ("difficult_breathing" in symptoms) + ): + self.record_sought_care_for_alri() + + # All persons have an initial out-patient appointment at the current facility level. + event = HSI_Alri_Treatment( + person_id=person_id, module=self, facility_level=facility_level + ) + schedule_hsi_event( + event, + topen=self.sim.date, + tclose=self.sim.date + pd.DateOffset(days=1), + priority=1, + ) + + def do_at_generic_first_appt_emergency(self, **kwargs) -> None: + # Emergency and non-emergency treatment is identical for alri + self.do_at_generic_first_appt(**kwargs) + class Models: """Helper-class to store all the models that specify the natural history of the Alri disease""" @@ -2394,11 +2354,7 @@ def _get_cons(self, _arg: Union[str, Tuple[str]]) -> bool: def _get_cons_group(self, item_group_str: str) -> bool: """True if _all_ of a group of consumables (identified by a string) is available.""" if item_group_str is not None: - return self.get_consumables( - item_codes={ - k: v(self._age_exact_years) if isinstance(v, types.LambdaType) else v - for k, v in self.module.consumables_used_in_hsi[item_group_str].items() - }) + return self.get_consumables(self.module.consumables_used_in_hsi[item_group_str]) else: raise ValueError('String for the group of consumables not provided') @@ -2595,6 +2551,8 @@ def _get_disease_classification_for_treatment_decision(self, 'chest_indrawing_pneumonia', (symptoms-based assessment) 'cough_or_cold' (symptoms-based assessment) }.""" + if use_oximeter: + self.add_equipment({'Pulse oximeter'}) child_is_younger_than_2_months = age_exact_years < (2.0 / 12.0) @@ -2650,6 +2608,15 @@ def _try_treatment(antibiotic_indicated: Tuple[str], oxygen_indicated: bool) -> oxygen_available = self._get_cons('Oxygen_Therapy') oxygen_provided = (oxygen_available and oxygen_indicated) + # If individual is provided with oxygen, add used equipment + if oxygen_provided: + self.add_equipment({'Oxygen cylinder, with regulator', 'Nasal Prongs'}) + + # If individual is provided with intravenous antibiotics, add used equipment + if antibiotic_provided in ('1st_line_IV_antibiotics', + 'Benzylpenicillin_gentamicin_therapy_for_severe_pneumonia'): + self.add_equipment({'Infusion pump', 'Drip stand'}) + all_things_needed_available = antibiotic_available and ( (oxygen_available and oxygen_indicated) or (not oxygen_indicated) ) @@ -2731,6 +2698,7 @@ def _provide_bronchodilator_if_wheeze(self, facility_level, symptoms): if facility_level == '1a': _ = self._get_cons('Inhaled_Brochodilator') else: + # n.b. this is never called, see issue 1172 _ = self._get_cons('Brochodilator_and_Steroids') def do_on_follow_up_following_treatment_failure(self): @@ -2738,9 +2706,12 @@ def do_on_follow_up_following_treatment_failure(self): A further drug will be used but this will have no effect on the chance of the person dying.""" if self._has_staph_aureus(): - _ = self._get_cons('2nd_line_Antibiotic_therapy_for_severe_staph_pneumonia') + cons_avail = self._get_cons('2nd_line_Antibiotic_therapy_for_severe_staph_pneumonia') else: - _ = self._get_cons('Ceftriaxone_therapy_for_severe_pneumonia') + cons_avail = self._get_cons('Ceftriaxone_therapy_for_severe_pneumonia') + + if cons_avail: + self.add_equipment({'Infusion pump', 'Drip stand'}) def apply(self, person_id, squeeze_factor): """Assess and attempt to treat the person.""" @@ -2755,7 +2726,7 @@ def apply(self, person_id, squeeze_factor): return # Do nothing if the persons does not have indicating symptoms - symptoms = self.sim.modules['SymptomManager'].has_what(person_id) + symptoms = self.sim.modules['SymptomManager'].has_what(person_id=person_id) if not {'cough', 'difficult_breathing'}.intersection(symptoms): return self.make_appt_footprint({}) @@ -3038,7 +3009,7 @@ def apply(self, person_id): assert 'danger_signs_pneumonia' == self.module.get_imci_classification_based_on_symptoms( child_is_younger_than_2_months=df.at[person_id, 'age_exact_years'] < (2.0 / 12.0), - symptoms=self.sim.modules['SymptomManager'].has_what(person_id) + symptoms=self.sim.modules['SymptomManager'].has_what(person_id=person_id) ) @@ -3069,7 +3040,7 @@ def apply(self, person_id): assert 'fast_breathing_pneumonia' == \ self.module.get_imci_classification_based_on_symptoms( - child_is_younger_than_2_months=False, symptoms=self.sim.modules['SymptomManager'].has_what(person_id) + child_is_younger_than_2_months=False, symptoms=self.sim.modules['SymptomManager'].has_what(person_id=person_id) ) diff --git a/src/tlo/methods/bed_days.py b/src/tlo/methods/bed_days.py index ef501f3b2e..7adb6de60c 100644 --- a/src/tlo/methods/bed_days.py +++ b/src/tlo/methods/bed_days.py @@ -5,12 +5,12 @@ """ from collections import defaultdict -from typing import Dict, Tuple +from typing import Dict, Literal, Tuple import numpy as np import pandas as pd -from tlo import Property, Types, logging +from tlo import Date, Property, Types, logging # --------------------------------------------------------------------------------------------------------- # CLASS DEFINITIONS @@ -145,6 +145,40 @@ def initialise_beddays_tracker(self, model_to_data_popsize_ratio=1.0): assert not df.isna().any().any() self.bed_tracker[bed_type] = df + def switch_beddays_availability( + self, + new_availability: Literal["all", "none", "default"], + effective_on_and_from: Date, + model_to_data_popsize_ratio: float = 1.0, + ) -> None: + """ + Action to be taken if the beddays availability changes in the middle + of the simulation. + + If bed capacities are reduced below the currently scheduled occupancy, + inpatients are not evicted from beds and are allowed to remain in the + bed until they are scheduled to leave. Obviously, no new patients will + be admitted if there is no room in the new capacities. + + :param new_availability: The new bed availability. See __init__ for details. + :param effective_on_and_from: First day from which the new capacities will be imposed. + :param model_to_data_popsize_ratio: As in initialise_population. + """ + # Store new bed availability + self.availability = new_availability + # Before we update the bed capacity, we need to store its old values + # This is because we will need to update the trackers to reflect the new# + # maximum capacities for each bed type. + old_max_capacities: pd.DataFrame = self._scaled_capacity.copy() + # Set the new capacity for beds + self.set_scaled_capacity(model_to_data_popsize_ratio) + # Compute the difference between the new max capacities and the old max capacities + difference_in_max = self._scaled_capacity - old_max_capacities + # For each tracker, after the effective date, impose the difference on the max + # number of beds + for bed_type, tracker in self.bed_tracker.items(): + tracker.loc[effective_on_and_from:] += difference_in_max[bed_type] + def on_start_of_day(self): """Things to do at the start of each new day: * Refresh inpatient status diff --git a/src/tlo/methods/bladder_cancer.py b/src/tlo/methods/bladder_cancer.py index 7231125519..52271f6f16 100644 --- a/src/tlo/methods/bladder_cancer.py +++ b/src/tlo/methods/bladder_cancer.py @@ -2,11 +2,13 @@ Bladder Cancer Disease Module Limitations to note: -* Needs to represent the the DxTest 'cytoscopy_blood_urine_bladder_cancer' requires use of a cytoscope +* Needs to represent the DxTest 'cystoscopy_blood_urine_bladder_cancer' requires use of a cystoscope * Footprints of HSI -- pending input from expert on resources required. """ +from __future__ import annotations from pathlib import Path +from typing import TYPE_CHECKING, List import pandas as pd @@ -14,17 +16,23 @@ from tlo.events import IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.lm import LinearModel, LinearModelType, Predictor from tlo.methods import Metadata +from tlo.methods.cancer_consumables import get_consumable_item_codes_cancers from tlo.methods.causes import Cause from tlo.methods.demography import InstantaneousDeath from tlo.methods.dxmanager import DxTest -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + from tlo.population import IndividualProperties + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -class BladderCancer(Module): +class BladderCancer(Module, GenericFirstAppointmentsMixin): """Bladder Cancer Disease Module""" def __init__(self, name=None, resourcefilepath=None): @@ -34,10 +42,11 @@ def __init__(self, name=None, resourcefilepath=None): self.lm_onset_blood_urine = None self.lm_onset_pelvic_pain = None self.daly_wts = dict() + self.item_codes_bladder_can = dict() INIT_DEPENDENCIES = {'Demography', 'Lifestyle', 'HealthSystem', 'SymptomManager'} - OPTIONAL_INIT_DEPENDENCIES = {'HealthBurden'} + OPTIONAL_INIT_DEPENDENCIES = {'HealthBurden', 'Schisto'} METADATA = { Metadata.DISEASE_MODULE, @@ -156,11 +165,11 @@ def __init__(self, name=None, resourcefilepath=None): "rp_bladder_cancer_schisto_h": Parameter( Types.REAL, "relative prevalence at baseline of bladder cancer if schisto_h" ), - "sensitivity_of_cytoscopy_for_bladder_cancer_blood_urine": Parameter( - Types.REAL, "sensitivity of cytoscopy_for diagnosis of bladder cancer given blood urine" + "sensitivity_of_cystoscopy_for_bladder_cancer_blood_urine": Parameter( + Types.REAL, "sensitivity of cystoscopy_for diagnosis of bladder cancer given blood urine" ), - "sensitivity_of_cytoscopy_for_bladder_cancer_pelvic_pain": Parameter( - Types.REAL, "sensitivity of cytoscopy_for diagnosis of bladder cancer given pelvic pain" + "sensitivity_of_cystoscopy_for_bladder_cancer_pelvic_pain": Parameter( + Types.REAL, "sensitivity of cystoscopy_for diagnosis of bladder cancer given pelvic pain" ) } @@ -234,17 +243,23 @@ def initialise_population(self, population): # check parameters are sensible: probability of having any cancer stage cannot exceed 1.0 assert sum(p['init_prop_bladder_cancer_stage']) <= 1.0 - lm_init_bc_status_any_stage = LinearModel( - LinearModelType.MULTIPLICATIVE, - sum(p['init_prop_bladder_cancer_stage']), + predictors = [ Predictor('li_tob').when(True, p['rp_bladder_cancer_tobacco']), - # todo: add line when schisto is merged - # Predictor('sh_infection_status').when('High-infection', p['rp_bladder_cancer_schisto_h']), Predictor('age_years', conditions_are_mutually_exclusive=True) .when('.between(30,49)', p['rp_bladder_cancer_age3049']) .when('.between(50,69)', p['rp_bladder_cancer_age5069']) .when('.between(70,120)', p['rp_bladder_cancer_agege70']) .when('.between(0,14)', 0.0) + ] + + conditional_predictors = [ + Predictor('ss_sh_infection_status').when('High-infection', p['rp_bladder_cancer_schisto_h']), + ] if "Schisto" in self.sim.modules else [] + + lm_init_bc_status_any_stage = LinearModel( + LinearModelType.MULTIPLICATIVE, + sum(p['init_prop_bladder_cancer_stage']), + *(predictors + conditional_predictors) ) bc_status_any_stage = lm_init_bc_status_any_stage.predict(df.loc[df.is_alive], self.rng) @@ -368,6 +383,9 @@ def initialise_simulation(self, sim): * Define the Disability-weights * Schedule the palliative care appointments for those that are on palliative care at initiation """ + # We call the following function to store the required consumables for the simulation run within the appropriate + # dictionary + self.item_codes_bladder_can = get_consumable_item_codes_cancers(self) # ----- SCHEDULE LOGGING EVENTS ----- # Schedule logging event to happen immediately @@ -386,20 +404,26 @@ def initialise_simulation(self, sim): p = self.parameters lm = self.linear_models_for_progession_of_bc_status - lm['tis_t1'] = LinearModel( - LinearModelType.MULTIPLICATIVE, - p['r_tis_t1_bladder_cancer_none'], - # todo: add in when schisto is in - # Predictor('sh_infection_status').when('High-infection', p['rp_bladder_cancer_schisto_h']), + predictors = [ Predictor('age_years', conditions_are_mutually_exclusive=True) .when('.between(30,49)', p['rp_bladder_cancer_age3049']) .when('.between(50,69)', p['rp_bladder_cancer_age5069']) .when('.between(70,120)', p['rp_bladder_cancer_agege70']) .when('.between(0,14)', 0.0), Predictor('li_tob').when(True, p['rr_tis_t1_bladder_cancer_none_tobacco']), - # todo: add in when schisto module in master - # Predictor('sh_').when(True, p['rr_tis_t1_bladder_cancer_none_ex_alc']), - Predictor('bc_status').when('none', 1.0).otherwise(0.0) + # todo: + # Predictor('tmp_').when(True, p['rr_tis_t1_bladder_cancer_none_ex_alc']), + Predictor('bc_status').when('none', 1.0).otherwise(0.0), + ] + + conditional_predictors = [ + Predictor('ss_sh_infection_status').when('High-infection', p['rp_bladder_cancer_schisto_h']), + ] if "Schisto" in self.sim.modules else [] + + lm["tis_t1"] = LinearModel( + LinearModelType.MULTIPLICATIVE, + p['r_tis_t1_bladder_cancer_none'], + *(predictors + conditional_predictors) ) lm['t2p'] = LinearModel( @@ -458,17 +482,17 @@ def initialise_simulation(self, sim): # This properties of conditional on the test being done only to persons with the Symptom, 'blood_urine'. self.sim.modules['HealthSystem'].dx_manager.register_dx_test( - cytoscopy_for_bladder_cancer_given_blood_urine=DxTest( + cystoscopy_for_bladder_cancer_given_blood_urine=DxTest( property='bc_status', - sensitivity=self.parameters['sensitivity_of_cytoscopy_for_bladder_cancer_blood_urine'], + sensitivity=self.parameters['sensitivity_of_cystoscopy_for_bladder_cancer_blood_urine'], target_categories=["tis_t1", "t2p", "metastatic"] ) ) self.sim.modules['HealthSystem'].dx_manager.register_dx_test( - cytoscopy_for_bladder_cancer_given_pelvic_pain=DxTest( + cystoscopy_for_bladder_cancer_given_pelvic_pain=DxTest( property='bc_status', - sensitivity=self.parameters['sensitivity_of_cytoscopy_for_bladder_cancer_pelvic_pain'], + sensitivity=self.parameters['sensitivity_of_cystoscopy_for_bladder_cancer_pelvic_pain'], target_categories=["tis_t1", "t2p", "metastatic"] ) ) @@ -570,6 +594,33 @@ def report_daly_values(self): return disability_series_for_alive_persons + def do_at_generic_first_appt( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs, + ) -> None: + # Only investigate if the patient is not a child + if individual_properties["age_years"] > 5: + # Begin investigation if symptoms are present. + if "blood_urine" in symptoms: + event = HSI_BladderCancer_Investigation_Following_Blood_Urine( + person_id=person_id, module=self + ) + schedule_hsi_event( + event, topen=self.sim.date, priority=0 + ) + + if "pelvic_pain" in symptoms: + event = HSI_BladderCancer_Investigation_Following_pelvic_pain( + person_id=person_id, module=self + ) + schedule_hsi_event( + event, topen=self.sim.date, priority=0 + ) + # --------------------------------------------------------------------------------------------------------- # DISEASE MODULE EVENTS @@ -667,49 +718,59 @@ def apply(self, person_id, squeeze_factor): return hs.get_blank_appt_footprint() # Check that this event has been called for someone with the symptom blood_urine - assert 'blood_urine' in self.sim.modules['SymptomManager'].has_what(person_id) + assert 'blood_urine' in self.sim.modules['SymptomManager'].has_what(person_id=person_id) # If the person is already diagnosed, then take no action: if not pd.isnull(df.at[person_id, "bc_date_diagnosis"]): return hs.get_blank_appt_footprint() - # Use a cytoscope to diagnose whether the person has bladder Cancer: - dx_result = hs.dx_manager.run_dx_test( - dx_tests_to_run='cytoscopy_for_bladder_cancer_given_blood_urine', - hsi_event=self - ) + # Check consumables are available + cons_avail = self.get_consumables(item_codes=self.module.item_codes_bladder_can['screening_cystoscopy_core'], + optional_item_codes=self.module.item_codes_bladder_can[ + 'screening_biopsy_endoscopy_cystoscopy_optional']) - if dx_result: - # record date of diagnosis: - df.at[person_id, 'bc_date_diagnosis'] = self.sim.date - - # Check if is in metastatic: - in_metastatic = df.at[person_id, 'bc_status'] == 'metastatic' - - # If diagnosis detects cancer, we assume classification as metastatic is accurate - if not in_metastatic: - # start treatment: - hs.schedule_hsi_event( - hsi_event=HSI_BladderCancer_StartTreatment( - module=self.module, - person_id=person_id - ), - priority=0, - topen=self.sim.date, - tclose=None - ) + if cons_avail: + # Use a biopsy to diagnose whether the person has bladder Cancer + # If consumables are available update the use of equipment and run the dx_test representing the biopsy + self.add_equipment({'Cystoscope', 'Ordinary Microscope', 'Ultrasound scanning machine'}) - else: - # start palliative care: - hs.schedule_hsi_event( - hsi_event=HSI_BladderCancer_PalliativeCare( - module=self.module, - person_id=person_id - ), - priority=0, - topen=self.sim.date, - tclose=None - ) + # Use a cystoscope to diagnose whether the person has bladder Cancer: + dx_result = hs.dx_manager.run_dx_test( + dx_tests_to_run='cystoscopy_for_bladder_cancer_given_blood_urine', + hsi_event=self + ) + + if dx_result: + # record date of diagnosis: + df.at[person_id, 'bc_date_diagnosis'] = self.sim.date + + # Check if is in metastatic: + in_metastatic = df.at[person_id, 'bc_status'] == 'metastatic' + + # If diagnosis detects cancer, we assume classification as metastatic is accurate + if not in_metastatic: + # start treatment: + hs.schedule_hsi_event( + hsi_event=HSI_BladderCancer_StartTreatment( + module=self.module, + person_id=person_id + ), + priority=0, + topen=self.sim.date, + tclose=None + ) + + else: + # start palliative care: + hs.schedule_hsi_event( + hsi_event=HSI_BladderCancer_PalliativeCare( + module=self.module, + person_id=person_id + ), + priority=0, + topen=self.sim.date, + tclose=None + ) class HSI_BladderCancer_Investigation_Following_pelvic_pain(HSI_Event, IndividualScopeEventMixin): @@ -730,55 +791,65 @@ def apply(self, person_id, squeeze_factor): return hs.get_blank_appt_footprint() # Check that this event has been called for someone with the symptom pelvic_pain - assert 'pelvic_pain' in self.sim.modules['SymptomManager'].has_what(person_id) + assert 'pelvic_pain' in self.sim.modules['SymptomManager'].has_what(person_id=person_id) # If the person is already diagnosed, then take no action: if not pd.isnull(df.at[person_id, "bc_date_diagnosis"]): return hs.get_blank_appt_footprint() - # Use a cytoscope to diagnose whether the person has bladder Cancer: - dx_result = hs.dx_manager.run_dx_test( - dx_tests_to_run='cytoscopy_for_bladder_cancer_given_pelvic_pain', - hsi_event=self - ) + # Check consumables are available + cons_avail = self.get_consumables(item_codes=self.module.item_codes_bladder_can['screening_cystoscopy_core'], + optional_item_codes=self.module.item_codes_bladder_can[ + 'screening_biopsy_endoscopy_cystoscopy_optional']) - if dx_result: - # record date of diagnosis: - df.at[person_id, 'bc_date_diagnosis'] = self.sim.date - - # Check if is in metastatic: - in_metastatic = df.at[person_id, 'bc_status'] == 'metastatic' - - # If diagnosis detects cancer, we assume classification as metastatic is accurate - if not in_metastatic: - # start treatment: - hs.schedule_hsi_event( - hsi_event=HSI_BladderCancer_StartTreatment( - module=self.module, - person_id=person_id - ), - priority=0, - topen=self.sim.date, - tclose=None - ) + if cons_avail: + # Use a biopsy to diagnose whether the person has bladder Cancer + # If consumables are available log the use of equipment and run the dx_test representing the biopsy + self.add_equipment({'Cystoscope', 'Ordinary Microscope', 'Ultrasound scanning machine'}) - else: - # start palliative care: - hs.schedule_hsi_event( - hsi_event=HSI_BladderCancer_PalliativeCare( - module=self.module, - person_id=person_id - ), - priority=0, - topen=self.sim.date, - tclose=None - ) + # Use a cystoscope to diagnose whether the person has bladder Cancer: + dx_result = hs.dx_manager.run_dx_test( + dx_tests_to_run='cystoscopy_for_bladder_cancer_given_pelvic_pain', + hsi_event=self + ) + + if dx_result: + # record date of diagnosis: + df.at[person_id, 'bc_date_diagnosis'] = self.sim.date + + # Check if is in metastatic: + in_metastatic = df.at[person_id, 'bc_status'] == 'metastatic' + + # If diagnosis detects cancer, we assume classification as metastatic is accurate + if not in_metastatic: + # start treatment: + hs.schedule_hsi_event( + hsi_event=HSI_BladderCancer_StartTreatment( + module=self.module, + person_id=person_id + ), + priority=0, + topen=self.sim.date, + tclose=None + ) + + else: + # start palliative care: + hs.schedule_hsi_event( + hsi_event=HSI_BladderCancer_PalliativeCare( + module=self.module, + person_id=person_id + ), + priority=0, + topen=self.sim.date, + tclose=None + ) class HSI_BladderCancer_StartTreatment(HSI_Event, IndividualScopeEventMixin): """ Scheduled by HSI_bladderCancer_Investigation_Following_blood_urine or pelvic pain following a - diagnosis of bladder Cancer using cytoscopy. It initiates the treatment of bladder Cancer. + diagnosis of bladder Cancer using cystoscopy. It initiates the treatment of bladder Cancer. It is only for persons with a cancer that is not in metastatic and who have been diagnosed. """ def __init__(self, module, person_id): @@ -817,20 +888,29 @@ def apply(self, person_id, squeeze_factor): assert not pd.isnull(df.at[person_id, "bc_date_diagnosis"]) assert pd.isnull(df.at[person_id, "bc_date_treatment"]) - # Record date and stage of starting treatment - df.at[person_id, "bc_date_treatment"] = self.sim.date - df.at[person_id, "bc_stage_at_which_treatment_given"] = df.at[person_id, "bc_status"] - - # Schedule a post-treatment check for 12 months: - hs.schedule_hsi_event( - hsi_event=HSI_BladderCancer_PostTreatmentCheck( - module=self.module, - person_id=person_id, - ), - topen=self.sim.date + DateOffset(years=12), - tclose=None, - priority=0 - ) + # Check consumables are available + cons_avail = self.get_consumables(item_codes=self.module.item_codes_bladder_can['treatment_surgery_core'], + optional_item_codes= + self.module.item_codes_bladder_can['treatment_surgery_optional']) + + if cons_avail: + # If consumables are available and the treatment will go ahead - update the equipment + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('Major Surgery')) + + # Record date and stage of starting treatment + df.at[person_id, "bc_date_treatment"] = self.sim.date + df.at[person_id, "bc_stage_at_which_treatment_given"] = df.at[person_id, "bc_status"] + + # Schedule a post-treatment check for 12 months: + hs.schedule_hsi_event( + hsi_event=HSI_BladderCancer_PostTreatmentCheck( + module=self.module, + person_id=person_id, + ), + topen=self.sim.date + DateOffset(years=12), + tclose=None, + priority=0 + ) class HSI_BladderCancer_PostTreatmentCheck(HSI_Event, IndividualScopeEventMixin): @@ -914,20 +994,28 @@ def apply(self, person_id, squeeze_factor): # Check that the person is in metastatic assert df.at[person_id, "bc_status"] == 'metastatic' - # Record the start of palliative care if this is first appointment - if pd.isnull(df.at[person_id, "bc_date_palliative_care"]): - df.at[person_id, "bc_date_palliative_care"] = self.sim.date - - # Schedule another instance of the event for one month - hs.schedule_hsi_event( - hsi_event=HSI_BladderCancer_PalliativeCare( - module=self.module, - person_id=person_id - ), - topen=self.sim.date + DateOffset(months=1), - tclose=None, - priority=0 - ) + # Check consumables are available + cons_available = self.get_consumables( + item_codes=self.module.item_codes_bladder_can['palliation']) + + if cons_available: + # If consumables are available and the treatment will go ahead - update the equipment + self.add_equipment({'Infusion pump', 'Drip stand'}) + + # Record the start of palliative care if this is first appointment + if pd.isnull(df.at[person_id, "bc_date_palliative_care"]): + df.at[person_id, "bc_date_palliative_care"] = self.sim.date + + # Schedule another instance of the event for one month + hs.schedule_hsi_event( + hsi_event=HSI_BladderCancer_PalliativeCare( + module=self.module, + person_id=person_id + ), + topen=self.sim.date + DateOffset(months=1), + tclose=None, + priority=0 + ) # --------------------------------------------------------------------------------------------------------- diff --git a/src/tlo/methods/breast_cancer.py b/src/tlo/methods/breast_cancer.py index 1ce9ad2bf6..a55c6f4930 100644 --- a/src/tlo/methods/breast_cancer.py +++ b/src/tlo/methods/breast_cancer.py @@ -4,8 +4,10 @@ Limitations to note: * Footprints of HSI -- pending input from expert on resources required. """ +from __future__ import annotations from pathlib import Path +from typing import TYPE_CHECKING, List import pandas as pd @@ -13,17 +15,23 @@ from tlo.events import IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.lm import LinearModel, LinearModelType, Predictor from tlo.methods import Metadata +from tlo.methods.cancer_consumables import get_consumable_item_codes_cancers from tlo.methods.causes import Cause from tlo.methods.demography import InstantaneousDeath from tlo.methods.dxmanager import DxTest -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + from tlo.population import IndividualProperties + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -class BreastCancer(Module): +class BreastCancer(Module, GenericFirstAppointmentsMixin): """Breast Cancer Disease Module""" def __init__(self, name=None, resourcefilepath=None): @@ -32,6 +40,7 @@ def __init__(self, name=None, resourcefilepath=None): self.linear_models_for_progession_of_brc_status = dict() self.lm_onset_breast_lump_discernible = None self.daly_wts = dict() + self.item_codes_breast_can = dict() INIT_DEPENDENCIES = {'Demography', 'HealthSystem', 'SymptomManager'} @@ -340,6 +349,9 @@ def initialise_simulation(self, sim): * Define the Disability-weights * Schedule the palliative care appointments for those that are on palliative care at initiation """ + # We call the following function to store the required consumables for the simulation run within the appropriate + # dictionary + self.item_codes_breast_can = get_consumable_item_codes_cancers(self) # ----- SCHEDULE LOGGING EVENTS ----- # Schedule logging event to happen immediately @@ -559,6 +571,23 @@ def report_daly_values(self): return disability_series_for_alive_persons + def do_at_generic_first_appt( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs, + ) -> None: + # If the patient is not a child and symptoms include breast + # lump discernible + if individual_properties["age_years"] > 5 and "breast_lump_discernible" in symptoms: + event = HSI_BreastCancer_Investigation_Following_breast_lump_discernible( + person_id=person_id, + module=self, + ) + schedule_hsi_event(event, topen=self.sim.date, priority=0) + # --------------------------------------------------------------------------------------------------------- # DISEASE MODULE EVENTS @@ -656,53 +685,62 @@ def apply(self, person_id, squeeze_factor): return hs.get_blank_appt_footprint() # Check that this event has been called for someone with the symptom breast_lump_discernible - assert 'breast_lump_discernible' in self.sim.modules['SymptomManager'].has_what(person_id) + assert 'breast_lump_discernible' in self.sim.modules['SymptomManager'].has_what(person_id=person_id) # If the person is already diagnosed, then take no action: if not pd.isnull(df.at[person_id, "brc_date_diagnosis"]): return hs.get_blank_appt_footprint() - df.brc_breast_lump_discernible_investigated = True + df.at[person_id, 'brc_breast_lump_discernible_investigated'] = True - # Use a biopsy to diagnose whether the person has breast Cancer: - # todo: request consumables needed for this + # Check consumables to undertake biopsy are available + cons_avail = self.get_consumables(item_codes=self.module.item_codes_breast_can['screening_biopsy_core'], + optional_item_codes= + self.module.item_codes_breast_can[ + 'screening_biopsy_endoscopy_cystoscopy_optional']) - dx_result = hs.dx_manager.run_dx_test( - dx_tests_to_run='biopsy_for_breast_cancer_given_breast_lump_discernible', - hsi_event=self - ) + if cons_avail: + # Use a biopsy to diagnose whether the person has breast Cancer + # If consumables are available, add the used equipment and run the dx_test representing the biopsy + self.add_equipment({'Ultrasound scanning machine', 'Ordinary Microscope'}) - if dx_result: - # record date of diagnosis: - df.at[person_id, 'brc_date_diagnosis'] = self.sim.date - - # Check if is in stage4: - in_stage4 = df.at[person_id, 'brc_status'] == 'stage4' - # If the diagnosis does detect cancer, it is assumed that the classification as stage4 is made accurately. - - if not in_stage4: - # start treatment: - hs.schedule_hsi_event( - hsi_event=HSI_BreastCancer_StartTreatment( - module=self.module, - person_id=person_id - ), - priority=0, - topen=self.sim.date, - tclose=None - ) + dx_result = hs.dx_manager.run_dx_test( + dx_tests_to_run='biopsy_for_breast_cancer_given_breast_lump_discernible', + hsi_event=self + ) - else: - # start palliative care: - hs.schedule_hsi_event( - hsi_event=HSI_BreastCancer_PalliativeCare( - module=self.module, - person_id=person_id - ), - priority=0, - topen=self.sim.date, - tclose=None - ) + if dx_result: + # record date of diagnosis: + df.at[person_id, 'brc_date_diagnosis'] = self.sim.date + + # Check if is in stage4: + in_stage4 = df.at[person_id, 'brc_status'] == 'stage4' + # If the diagnosis does detect cancer, it is assumed that the classification as stage4 is + # made accurately. + + if not in_stage4: + # start treatment: + hs.schedule_hsi_event( + hsi_event=HSI_BreastCancer_StartTreatment( + module=self.module, + person_id=person_id + ), + priority=0, + topen=self.sim.date, + tclose=None + ) + + else: + # start palliative care: + hs.schedule_hsi_event( + hsi_event=HSI_BreastCancer_PalliativeCare( + module=self.module, + person_id=person_id + ), + priority=0, + topen=self.sim.date, + tclose=None + ) # todo: we would like to note that the symptom has been investigated in a diagnostic test and the diagnosis was # todo: was missed, so the same test will not likely be repeated, at least not in the short term, so we even @@ -728,8 +766,6 @@ def apply(self, person_id, squeeze_factor): df = self.sim.population.props hs = self.sim.modules["HealthSystem"] - # todo: request consumables needed for this - if not df.at[person_id, 'is_alive']: return hs.get_blank_appt_footprint() @@ -755,19 +791,34 @@ def apply(self, person_id, squeeze_factor): assert not pd.isnull(df.at[person_id, "brc_date_diagnosis"]) assert pd.isnull(df.at[person_id, "brc_date_treatment"]) - # Record date and stage of starting treatment - df.at[person_id, "brc_date_treatment"] = self.sim.date - df.at[person_id, "brc_stage_at_which_treatment_given"] = df.at[person_id, "brc_status"] + # Check that consumables are available + cons_available = self.get_consumables( + item_codes=self.module.item_codes_breast_can['treatment_surgery_core'], + optional_item_codes=self.module.item_codes_breast_can['treatment_surgery_optional'], + ) - # Schedule a post-treatment check for 12 months: - hs.schedule_hsi_event( - hsi_event=HSI_BreastCancer_PostTreatmentCheck( - module=self.module, - person_id=person_id, - ), - topen=self.sim.date + DateOffset(months=12), - tclose=None, - priority=0 + if cons_available: + # If consumables are available and the treatment will go ahead - add the used equipment + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('Major Surgery')) + + # Log the use of adjuvant chemotherapy + self.get_consumables( + item_codes=self.module.item_codes_breast_can['treatment_chemotherapy'], + optional_item_codes=self.module.item_codes_breast_can['iv_drug_cons']) + + # Record date and stage of starting treatment + df.at[person_id, "brc_date_treatment"] = self.sim.date + df.at[person_id, "brc_stage_at_which_treatment_given"] = df.at[person_id, "brc_status"] + + # Schedule a post-treatment check for 12 months: + hs.schedule_hsi_event( + hsi_event=HSI_BreastCancer_PostTreatmentCheck( + module=self.module, + person_id=person_id, + ), + topen=self.sim.date + DateOffset(months=12), + tclose=None, + priority=0 ) @@ -846,28 +897,34 @@ def apply(self, person_id, squeeze_factor): df = self.sim.population.props hs = self.sim.modules["HealthSystem"] - # todo: request consumables needed for this - if not df.at[person_id, 'is_alive']: return hs.get_blank_appt_footprint() # Check that the person is in stage4 assert df.at[person_id, "brc_status"] == 'stage4' - # Record the start of palliative care if this is first appointment - if pd.isnull(df.at[person_id, "brc_date_palliative_care"]): - df.at[person_id, "brc_date_palliative_care"] = self.sim.date - - # Schedule another instance of the event for one month - hs.schedule_hsi_event( - hsi_event=HSI_BreastCancer_PalliativeCare( - module=self.module, - person_id=person_id - ), - topen=self.sim.date + DateOffset(months=3), - tclose=None, - priority=0 - ) + # Check consumables are available + cons_available = self.get_consumables( + item_codes=self.module.item_codes_breast_can['palliation']) + + if cons_available: + # If consumables are available and the treatment will go ahead - add the used equipment + self.add_equipment({'Infusion pump', 'Drip stand'}) + + # Record the start of palliative care if this is first appointment + if pd.isnull(df.at[person_id, "brc_date_palliative_care"]): + df.at[person_id, "brc_date_palliative_care"] = self.sim.date + + # Schedule another instance of the event for one month + hs.schedule_hsi_event( + hsi_event=HSI_BreastCancer_PalliativeCare( + module=self.module, + person_id=person_id + ), + topen=self.sim.date + DateOffset(months=3), + tclose=None, + priority=0 + ) # --------------------------------------------------------------------------------------------------------- diff --git a/src/tlo/methods/cancer_consumables.py b/src/tlo/methods/cancer_consumables.py new file mode 100644 index 0000000000..e26d577242 --- /dev/null +++ b/src/tlo/methods/cancer_consumables.py @@ -0,0 +1,77 @@ +""" +This file stores defines the consumables required within the cancer modules +""" +from typing import Dict + + +def get_consumable_item_codes_cancers(self) -> Dict[str, int]: + """ + Returns dict the relevant item_codes for the consumables across the five cancer modules. This is intended to prevent + repetition within module code. + """ + + get_item_code = self.sim.modules['HealthSystem'].get_item_code_from_item_name + + cons_dict = dict() + + # Add items that are needed for all cancer modules + cons_dict['screening_biopsy_endoscopy_cystoscopy_optional'] = \ + {get_item_code("Specimen container"): 1, + get_item_code("Lidocaine HCl (in dextrose 7.5%), ampoule 2 ml"): 1, + get_item_code("Gauze, absorbent 90cm x 40m_each_CMST"): 30, + get_item_code("Disposables gloves, powder free, 100 pieces per box"): 1, + get_item_code("Syringe, needle + swab"): 1} + + cons_dict['screening_biopsy_core'] = \ + {get_item_code("Biopsy needle"): 1} + + cons_dict['treatment_surgery_core'] = \ + {get_item_code("Halothane (fluothane)_250ml_CMST"): 100, + get_item_code("Scalpel blade size 22 (individually wrapped)_100_CMST"): 1} + + cons_dict['treatment_surgery_optional'] = \ + {get_item_code("Sodium chloride, injectable solution, 0,9 %, 500 ml"): 2000, + get_item_code("Paracetamol, tablet, 500 mg"): 8000, + get_item_code("Pethidine, 50 mg/ml, 2 ml ampoule"): 6, + get_item_code("Suture pack"): 1, + get_item_code("Gauze, absorbent 90cm x 40m_each_CMST"): 30, + get_item_code("Cannula iv (winged with injection pot) 18_each_CMST"): 1} + + cons_dict['palliation'] = \ + {get_item_code("morphine sulphate 10 mg/ml, 1 ml, injection (nt)_10_IDA"): 1, + get_item_code("Diazepam, injection, 5 mg/ml, in 2 ml ampoule"): 3, + get_item_code("Syringe, needle + swab"): 4} + # N.B. This is not an exhaustive list of drugs required for palliation + + cons_dict['treatment_chemotherapy'] = \ + {get_item_code("Cyclophosphamide, 1 g"): 16800} + + cons_dict['iv_drug_cons'] = \ + {get_item_code("Cannula iv (winged with injection pot) 18_each_CMST"): 1, + get_item_code("Giving set iv administration + needle 15 drops/ml_each_CMST"): 1, + get_item_code("Disposables gloves, powder free, 100 pieces per box"): 1, + get_item_code("Gauze, swabs 8-ply 10cm x 10cm_100_CMST"): 84} + + # Add items that are specific to a particular cancer module + if 'ProstateCancer' == self.name: + + cons_dict['screening_psa_test_core'] = \ + {get_item_code("Prostate specific antigen test"): 1} + + cons_dict['screening_psa_test_optional'] = \ + {get_item_code("Blood collecting tube, 5 ml"): 1, + get_item_code("Disposables gloves, powder free, 100 pieces per box"): 1, + get_item_code("Gauze, swabs 8-ply 10cm x 10cm_100_CMST"): 1} + + elif 'BladderCancer' == self.name: + # Note: bladder cancer is not in the malawi STG 2023 therefore no details on chemotherapy + + cons_dict['screening_cystoscopy_core'] = \ + {get_item_code("Cystoscope"): 1} + + elif 'OesophagealCancer' == self.name: + + cons_dict['screening_endoscopy_core'] = \ + {get_item_code("Endoscope"): 1} + + return cons_dict diff --git a/src/tlo/methods/cardio_metabolic_disorders.py b/src/tlo/methods/cardio_metabolic_disorders.py index 760289ae44..d90688adb0 100644 --- a/src/tlo/methods/cardio_metabolic_disorders.py +++ b/src/tlo/methods/cardio_metabolic_disorders.py @@ -10,11 +10,12 @@ And: * Chronic Lower Back Pain """ +from __future__ import annotations import math from itertools import combinations from pathlib import Path -from typing import List +from typing import TYPE_CHECKING, List import numpy as np import pandas as pd @@ -26,10 +27,15 @@ from tlo.methods import demography as de from tlo.methods.causes import Cause from tlo.methods.dxmanager import DxTest -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom from tlo.util import random_date +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + from tlo.population import IndividualProperties + # --------------------------------------------------------------------------------------------------------- # MODULE DEFINITIONS # --------------------------------------------------------------------------------------------------------- @@ -37,8 +43,7 @@ logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) - -class CardioMetabolicDisorders(Module): +class CardioMetabolicDisorders(Module, GenericFirstAppointmentsMixin): """ CardioMetabolicDisorders module covers a subset of cardio-metabolic conditions and events. Conditions are binary and individuals experience a risk of acquiring or losing a condition based on annual probability and @@ -57,7 +62,7 @@ class CardioMetabolicDisorders(Module): INIT_DEPENDENCIES = {'Demography', 'Lifestyle', 'HealthSystem', 'SymptomManager'} - OPTIONAL_INIT_DEPENDENCIES = {'HealthBurden'} + OPTIONAL_INIT_DEPENDENCIES = {'HealthBurden', 'Hiv'} ADDITIONAL_DEPENDENCIES = {'Depression'} @@ -594,9 +599,7 @@ def build_linear_model(self, condition, interval_between_polls, lm_type): # LinearModel expects native python types - if it's numpy type, convert it baseline_annual_probability = float(baseline_annual_probability) - linearmodel = LinearModel( - LinearModelType.MULTIPLICATIVE, - baseline_annual_probability, + predictors = [ Predictor('sex').when('M', p['rr_male']), Predictor( 'age_years', @@ -689,6 +692,17 @@ def build_linear_model(self, condition, interval_between_polls, lm_type): 'rr_chronic_ischemic_heart_disease_on_medication']), Predictor('nc_ever_stroke_on_medication').when(True, p['rr_stroke_on_medication']), Predictor('nc_ever_heart_attack_on_medication').when(True, p['rr_heart_attack_on_medication']) + ] + + conditional_predictors = [ + Predictor().when('hv_inf & ' + '(hv_art != "on_VL_suppressed")', p['rr_hiv']), + ] if "Hiv" in self.sim.modules else [] + + linearmodel = LinearModel( + LinearModelType.MULTIPLICATIVE, + baseline_annual_probability, + *(predictors + conditional_predictors) ) return linearmodel @@ -799,37 +813,52 @@ def on_hsi_alert(self, person_id, treatment_id): """ pass - def determine_if_will_be_investigated(self, person_id): - """ - This is called by the HSI generic first appts module whenever a person attends an appointment and determines - if the person will be tested for one or more conditions. - A maximum of one instance of `HSI_CardioMetabolicDisorders_Investigations` is created for the person, during - which multiple conditions can be investigated. - """ - - def is_next_test_due(current_date, date_of_last_test): - return pd.isnull(date_of_last_test) or (current_date - date_of_last_test).days > DAYS_IN_YEAR / 2 - - df = self.sim.population.props - person = df.loc[person_id, df.columns[df.columns.str.startswith('nc_')]] - symptoms = self.sim.modules['SymptomManager'].has_what(person_id=person_id) + def do_at_generic_first_appt( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs + ) -> None: + # This is called by the HSI generic first appts module whenever a + # person attends an appointment and determines if the person will + # be tested for one or more conditions. + # A maximum of one instance of `HSI_CardioMetabolicDisorders_Investigations` + # is created for the person, during which multiple conditions can + # be investigated. + if individual_properties["age_years"] <= 5: + return - conditions_to_investigate = [] # The list of conditions that will be investigated in follow-up HSI - has_any_cmd_symptom = False # Marker for whether the person has any symptoms of interest + # The list of conditions that will be investigated in follow-up HSI + conditions_to_investigate = [] + # Marker for whether the person has any symptoms of interest + has_any_cmd_symptom = False # Determine if there are any conditions that should be investigated: for condition in self.conditions: - is_already_diagnosed = person[f'nc_{condition}_ever_diagnosed'] - has_symptom = f'{condition}_symptoms' in symptoms - next_test_due = is_next_test_due( - current_date=self.sim.date, date_of_last_test=df.at[person_id, f'nc_{condition}_date_last_test'] + is_already_diagnosed = individual_properties[ + f"nc_{condition}_ever_diagnosed" + ] + has_symptom = f"{condition}_symptoms" in symptoms + date_of_last_test = individual_properties[f"nc_{condition}_date_last_test"] + next_test_due = ( + pd.isnull(date_of_last_test) + or (self.sim.date - date_of_last_test).days > DAYS_IN_YEAR / 2 + ) + p_assess_if_no_symptom = self.parameters[f"{condition}_hsi"].get( + "pr_assessed_other_symptoms" ) - p_assess_if_no_symptom = self.parameters[f'{condition}_hsi'].get('pr_assessed_other_symptoms') if (not is_already_diagnosed) and ( - has_symptom or (next_test_due and (self.rng.random_sample() < p_assess_if_no_symptom)) + has_symptom + or ( + next_test_due + and (self.rng.random_sample() < p_assess_if_no_symptom) + ) ): - # If the person is not already diagnosed and either has the symptom or is due a routine check... + # If the person is not already diagnosed, and either + # has the symptom or is due a routine check, # ... add this condition to be investigated in the appointment. conditions_to_investigate.append(condition) @@ -838,46 +867,46 @@ def is_next_test_due(current_date, date_of_last_test): # Schedule follow-up HSI *if* there are any conditions to investigate: if conditions_to_investigate: - self.sim.modules['HealthSystem'].schedule_hsi_event( - HSI_CardioMetabolicDisorders_Investigations( - module=self, - person_id=person_id, - conditions_to_investigate=conditions_to_investigate, - has_any_cmd_symptom=has_any_cmd_symptom, - ), - priority=0, - topen=self.sim.date, - tclose=None - ) - - def determine_if_will_be_investigated_events(self, person_id): - """ - This is called by the HSI generic first appts module whenever a person attends an emergency appointment and - determines if they will receive emergency care based on the duration of time since symptoms have appeared. - A maximum of one instance of `HSI_CardioMetabolicDisorders_SeeksEmergencyCareAndGetsTreatment` is created - for the person, during which multiple events can be investigated. - """ - - health_system = self.sim.modules["HealthSystem"] - symptoms = self.sim.modules['SymptomManager'].has_what(person_id=person_id) - + event = HSI_CardioMetabolicDisorders_Investigations( + module=self, + person_id=person_id, + conditions_to_investigate=conditions_to_investigate, + has_any_cmd_symptom=has_any_cmd_symptom, + ) + schedule_hsi_event(event, topen=self.sim.date, priority=0) + + def do_at_generic_first_appt_emergency( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs, + ) -> None: + # This is called by the HSI generic first appts module whenever a person attends + # an emergency appointment and determines if they will receive emergency care + # based on the duration of time since symptoms have appeared. A maximum of one + # instance of `HSI_CardioMetabolicDisorders_SeeksEmergencyCareAndGetsTreatment` + # is created for the person, during which multiple events can be investigated. ev_to_investigate = [] for ev in self.events: - # If the person has symptoms of damage from within the last 3 days, schedule them for emergency care - if f'{ev}_damage' in symptoms and \ - ((self.sim.date - self.sim.population.props.at[person_id, f'nc_{ev}_date_last_event']).days <= 3): + # If the person has symptoms of damage from within the last 3 days, schedule + # them for emergency care + if f"{ev}_damage" in symptoms and ( + ( + self.sim.date - individual_properties[f"nc_{ev}_date_last_event"] + ).days + <= 3 + ): ev_to_investigate.append(ev) if ev_to_investigate: - health_system.schedule_hsi_event( - HSI_CardioMetabolicDisorders_SeeksEmergencyCareAndGetsTreatment( - module=self, - person_id=person_id, - events_to_investigate=ev_to_investigate, - ), - priority=1, - topen=self.sim.date + event = HSI_CardioMetabolicDisorders_SeeksEmergencyCareAndGetsTreatment( + module=self, + person_id=person_id, + events_to_investigate=ev_to_investigate, ) + schedule_hsi_event(event, topen=self.sim.date, priority=1) class Tracker: @@ -1406,6 +1435,7 @@ def apply(self, person_id, squeeze_factor): return hs.get_blank_appt_footprint() # Run a test to diagnose whether the person has condition: + self.add_equipment({'Blood pressure machine'}) dx_result = hs.dx_manager.run_dx_test( dx_tests_to_run='assess_hypertension', hsi_event=self @@ -1458,6 +1488,9 @@ def do_for_each_condition(self, _c) -> bool: if df.at[person_id, f'nc_{_c}_ever_diagnosed']: return + if _c == 'chronic_ischemic_heart_disease': + self.add_equipment({'Electrocardiogram', 'Stethoscope'}) + # Run a test to diagnose whether the person has condition: dx_result = hs.dx_manager.run_dx_test( dx_tests_to_run=f'assess_{_c}', @@ -1490,6 +1523,11 @@ def apply(self, person_id, squeeze_factor): return hs.get_blank_appt_footprint() # Do test and trigger treatment (if necessary) for each condition: + if set(self.conditions_to_investigate).intersection( + ['diabetes', 'chronic_kidney_disease', 'chronic_ischemic_hd'] + ): + self.add_equipment({'Analyser, Haematology', 'Analyser, Combined Chemistry and Electrolytes'}) + hsi_scheduled = [self.do_for_each_condition(_c) for _c in self.conditions_to_investigate] # If no follow-up treatment scheduled but the person has at least 2 risk factors, start weight loss treatment @@ -1513,6 +1551,7 @@ def apply(self, person_id, squeeze_factor): and (self.module.rng.rand() < self.module.parameters['hypertension_hsi']['pr_assessed_other_symptoms']) ): # Run a test to diagnose whether the person has condition: + self.add_equipment({'Blood pressure machine'}) dx_result = hs.dx_manager.run_dx_test( dx_tests_to_run='assess_hypertension', hsi_event=self @@ -1560,6 +1599,8 @@ def apply(self, person_id, squeeze_factor): # Don't advise those with CKD to lose weight, but do so for all other conditions if BMI is higher than normal if self.condition != 'chronic_kidney_disease' and (df.at[person_id, 'li_bmi'] > 2): + self.add_equipment({'Weighing scale'}) + self.sim.population.props.at[person_id, 'nc_ever_weight_loss_treatment'] = True # Schedule a post-weight loss event for individual to potentially lose weight in next 6-12 months: self.sim.schedule_event(CardioMetabolicDisordersWeightLossEvent(m, person_id), @@ -1571,10 +1612,23 @@ def apply(self, person_id, squeeze_factor): return self.sim.modules['HealthSystem'].get_blank_appt_footprint() assert person[f'nc_{self.condition}_ever_diagnosed'], "The person is not diagnosed and so should not be " \ "receiving an HSI." + + # Monthly doses of medications as follows. Diabetes - 1000mg metformin daily (1000*30.5), + # hypertension - 25mg hydrochlorothiazide daily (25*30.5), CKD 1 dialysis bag (estimate), + # lower back pain - 2400mg aspirin daily (2400*30.5), CIHD - 75mg aspirin daily (75*30.5) + dose = {'diabetes': 30_500, + 'hypertension': 610, + 'chronic_kidney_disease': 1, + 'chronic_lower_back_pain': 73_200, + 'chronic_ischemic_hd': 2288, + 'ever_stroke': 2288, + 'ever_heart_attack': 2288} + # Check availability of medication for condition - if self.get_consumables( - item_codes=self.module.parameters[f'{self.condition}_hsi'].get('medication_item_code').astype(int) - ): + if self.get_consumables(item_codes= + {self.module.parameters[f'{self.condition}_hsi'].get( + 'medication_item_code').astype(int): dose[self.condition]}): + # If medication is available, flag as being on medication df.at[person_id, f'nc_{self.condition}_on_medication'] = True # Determine if the medication will work to prevent death @@ -1640,10 +1694,21 @@ def apply(self, person_id, squeeze_factor): # Return the blank_appt_footprint() so that this HSI does not occupy any time resources return self.sim.modules['HealthSystem'].get_blank_appt_footprint() + # Monthly doses of medications as follows. Diabetes - 1000mg metformin daily (1000*30.5), + # hypertension - 25mg hydrochlorothiazide daily (25*30.5), CKD 1 dialysis bag (estimate), + # lower back pain - 2400mg aspirin daily (2400*30.5), CIHD - 75mg aspirin daily (75*30.5) + dose = {'diabetes': 30_500, + 'hypertension': 610, + 'chronic_kidney_disease': 1, + 'chronic_lower_back_pain': 73_200, + 'chronic_ischemic_hd': 2288, + 'ever_stroke': 2288, + 'ever_heart_attack': 2288} + # Check availability of medication for condition if self.get_consumables( - item_codes=self.module.parameters[f'{self.condition}_hsi'].get('medication_item_code').astype(int) - ): + item_codes={self.module.parameters[f'{self.condition}_hsi'].get('medication_item_code').astype(int) + : dose[self.condition]}): # Schedule their next HSI for a refill of medication, one month from now self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=self, @@ -1696,6 +1761,12 @@ def do_for_each_event_to_be_investigated(self, _ev): df = self.sim.population.props # Run a test to diagnose whether the person has condition: + if _ev == 'ever_stroke': + self.add_equipment({'Computed Tomography (CT machine)', 'CT scanner accessories'}) + + if _ev == 'ever_heart_attack': + self.add_equipment({'Electrocardiogram'}) + dx_result = self.sim.modules['HealthSystem'].dx_manager.run_dx_test( dx_tests_to_run=f'assess_{_ev}', hsi_event=self @@ -1705,10 +1776,13 @@ def do_for_each_event_to_be_investigated(self, _ev): df.at[person_id, f'nc_{_ev}_date_diagnosis'] = self.sim.date df.at[person_id, f'nc_{_ev}_ever_diagnosed'] = True if self.module.parameters['prob_care_provided_given_seek_emergency_care'] > self.module.rng.random_sample(): + # If care is provided.... + dose = 20 if _ev == 'ever_stroke' else 40 + if self.get_consumables( - item_codes=self.module.parameters[f'{_ev}_hsi'].get( - 'emergency_medication_item_code').astype(int) + item_codes={self.module.parameters[f'{_ev}_hsi'].get( + 'emergency_medication_item_code').astype(int): dose} ): logger.debug(key='debug', data='Treatment will be provided.') df.at[person_id, f'nc_{_ev}_on_medication'] = True @@ -1752,6 +1826,7 @@ def apply(self, person_id, squeeze_factor): data=('This is HSI_CardioMetabolicDisorders_SeeksEmergencyCareAndGetsTreatment: ' f'The squeeze-factor is {squeeze_factor}.'), ) + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('ICU')) for _ev in self.events_to_investigate: self.do_for_each_event_to_be_investigated(_ev) diff --git a/src/tlo/methods/care_of_women_during_pregnancy.py b/src/tlo/methods/care_of_women_during_pregnancy.py index 42e026478c..dba3bcda8e 100644 --- a/src/tlo/methods/care_of_women_during_pregnancy.py +++ b/src/tlo/methods/care_of_women_during_pregnancy.py @@ -1,5 +1,6 @@ from pathlib import Path +import numpy as np import pandas as pd from tlo import DateOffset, Module, Parameter, Property, Types, logging @@ -7,7 +8,7 @@ from tlo.methods import Metadata, pregnancy_helper_functions from tlo.methods.dxmanager import DxTest from tlo.methods.epi import HSI_TdVaccine -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event from tlo.methods.labour import LabourOnsetEvent from tlo.methods.malaria import HSI_MalariaIPTp from tlo.methods.tb import HSI_Tb_ScreeningAndRefer @@ -202,157 +203,160 @@ def get_and_store_pregnancy_item_codes(self): This function defines the required consumables for each intervention delivered during this module and stores them in a module level dictionary called within HSIs """ - get_list_of_items = pregnancy_helper_functions.get_list_of_items + ic = self.sim.modules['HealthSystem'].get_item_code_from_item_name + # First we store the item codes for the consumables for which their quantity varies for individuals based on + # length of pregnancy # ---------------------------------- BLOOD TEST EQUIPMENT --------------------------------------------------- self.item_codes_preg_consumables['blood_test_equipment'] = \ - get_list_of_items(self, ['Blood collecting tube, 5 ml', - 'Cannula iv (winged with injection pot) 18_each_CMST', - 'Disposables gloves, powder free, 100 pieces per box']) - + {ic('Blood collecting tube, 5 ml'): 1, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1 + } # ---------------------------------- IV DRUG ADMIN EQUIPMENT ------------------------------------------------- self.item_codes_preg_consumables['iv_drug_equipment'] = \ - get_list_of_items(self, ['Cannula iv (winged with injection pot) 18_each_CMST', - 'Giving set iv administration + needle 15 drops/ml_each_CMST', - 'Disposables gloves, powder free, 100 pieces per box']) + {ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1 + } # -------------------------------------------- ECTOPIC PREGNANCY --------------------------------------------- self.item_codes_preg_consumables['ectopic_pregnancy_core'] = \ - get_list_of_items(self, ['Halothane (fluothane)_250ml_CMST']) + {ic('Halothane (fluothane)_250ml_CMST'): 100} self.item_codes_preg_consumables['ectopic_pregnancy_optional'] = \ - get_list_of_items(self, ['Scalpel blade size 22 (individually wrapped)_100_CMST', - 'Sodium chloride, injectable solution, 0,9 %, 500 ml', - 'Paracetamol, tablet, 500 mg', - 'Pethidine, 50 mg/ml, 2 ml ampoule', - 'Suture pack', - 'Gauze, absorbent 90cm x 40m_each_CMST', - 'Cannula iv (winged with injection pot) 18_each_CMST', - 'Giving set iv administration + needle 15 drops/ml_each_CMST', - 'Disposables gloves, powder free, 100 pieces per box' - ]) + {ic('Scalpel blade size 22 (individually wrapped)_100_CMST'): 1, + ic('Sodium chloride, injectable solution, 0,9 %, 500 ml'): 2000, + ic('Paracetamol, tablet, 500 mg'): 8000, + ic('Pethidine, 50 mg/ml, 2 ml ampoule'): 6, + ic('Suture pack'): 1, + ic('Gauze, absorbent 90cm x 40m_each_CMST'): 30, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1, + } # ------------------------------------------- POST ABORTION CARE - GENERAL ----------------------------------- self.item_codes_preg_consumables['post_abortion_care_core'] = \ - get_list_of_items(self, ['Misoprostol, tablet, 200 mcg']) + {ic('Misoprostol, tablet, 200 mcg'): 600} self.item_codes_preg_consumables['post_abortion_care_optional'] = \ - get_list_of_items(self, ['Complete blood count', - 'Blood collecting tube, 5 ml', - 'Paracetamol, tablet, 500 mg', - 'Pethidine, 50 mg/ml, 2 ml ampoule', - 'Cannula iv (winged with injection pot) 18_each_CMST', - 'Giving set iv administration + needle 15 drops/ml_each_CMST', - 'Disposables gloves, powder free, 100 pieces per box' - ]) + {ic('Complete blood count'): 1, + ic('Blood collecting tube, 5 ml'): 1, + ic('Paracetamol, tablet, 500 mg'): 8000, + ic('Gauze, absorbent 90cm x 40m_each_CMST'): 30, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1, + } # ------------------------------------------- POST ABORTION CARE - SEPSIS ------------------------------------- self.item_codes_preg_consumables['post_abortion_care_sepsis_core'] = \ - get_list_of_items(self, ['Benzylpenicillin 3g (5MU), PFR_each_CMST', - 'Gentamycin, injection, 40 mg/ml in 2 ml vial']) + {ic('Benzathine benzylpenicillin, powder for injection, 2.4 million IU'): 8, + ic('Gentamycin, injection, 40 mg/ml in 2 ml vial'): 6, + } self.item_codes_preg_consumables['post_abortion_care_sepsis_optional'] = \ - get_list_of_items(self, ['Sodium chloride, injectable solution, 0,9 %, 500 ml', - 'Cannula iv (winged with injection pot) 18_each_CMST', - 'Disposables gloves, powder free, 100 pieces per box', - 'Giving set iv administration + needle 15 drops/ml_each_CMST', - 'Oxygen, 1000 liters, primarily with oxygen cylinders']) - - # ------------------------------------------- POST ABORTION CARE - SHOCK ------------------------------------- + {ic('Sodium chloride, injectable solution, 0,9 %, 500 ml'): 2000, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1, + ic('Oxygen, 1000 liters, primarily with oxygen cylinders'): 23_040, + } + + # ------------------------------------------- POST ABORTION CARE - SHOCK ------------------------------------ self.item_codes_preg_consumables['post_abortion_care_shock'] = \ - get_list_of_items(self, ['Sodium chloride, injectable solution, 0,9 %, 500 ml', - 'Oxygen, 1000 liters, primarily with oxygen cylinders']) + {ic('Sodium chloride, injectable solution, 0,9 %, 500 ml'): 2000, + ic('Oxygen, 1000 liters, primarily with oxygen cylinders'): 23_040, + } self.item_codes_preg_consumables['post_abortion_care_shock_optional'] = \ - get_list_of_items(self, ['Cannula iv (winged with injection pot) 18_each_CMST', - 'Disposables gloves, powder free, 100 pieces per box', - 'Giving set iv administration + needle 15 drops/ml_each_CMST']) - + {ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1, + } # ---------------------------------- URINE DIPSTICK ---------------------------------------------------------- - self.item_codes_preg_consumables['urine_dipstick'] = get_list_of_items(self, ['Urine analysis']) + self.item_codes_preg_consumables['urine_dipstick'] = {ic('Urine analysis'): 1} # ---------------------------------- IRON AND FOLIC ACID ------------------------------------------------------ - self.item_codes_preg_consumables['iron_folic_acid'] = get_list_of_items( - self, ['Ferrous Salt + Folic Acid, tablet, 200 + 0.25 mg']) + # Dose changes at run time + self.item_codes_preg_consumables['iron_folic_acid'] = \ + {ic('Ferrous Salt + Folic Acid, tablet, 200 + 0.25 mg'): 1} # TODO: update con requested here # --------------------------------- BALANCED ENERGY AND PROTEIN ---------------------------------------------- - self.item_codes_preg_consumables['balanced_energy_protein'] = get_list_of_items( - self, ['Dietary supplements (country-specific)']) + # Dose changes at run time + self.item_codes_preg_consumables['balanced_energy_protein'] = \ + {ic('Dietary supplements (country-specific)'): 1} # --------------------------------- INSECTICIDE TREATED NETS ------------------------------------------------ - self.item_codes_preg_consumables['itn'] = get_list_of_items(self, ['Insecticide-treated net']) + self.item_codes_preg_consumables['itn'] = {ic('Insecticide-treated net'): 1} # --------------------------------- CALCIUM SUPPLEMENTS ----------------------------------------------------- - self.item_codes_preg_consumables['calcium'] = get_list_of_items(self, ['Calcium, tablet, 600 mg']) + self.item_codes_preg_consumables['calcium'] = {ic('Calcium, tablet, 600 mg'): 1} # -------------------------------- HAEMOGLOBIN TESTING ------------------------------------------------------- - self.item_codes_preg_consumables['hb_test'] = get_list_of_items(self, ['Haemoglobin test (HB)']) + self.item_codes_preg_consumables['hb_test'] = {ic('Haemoglobin test (HB)'): 1} # ------------------------------------------- ALBENDAZOLE ----------------------------------------------------- - self.item_codes_preg_consumables['albendazole'] = get_list_of_items(self, ['Albendazole 200mg_1000_CMST']) + self.item_codes_preg_consumables['albendazole'] = {ic('Albendazole 200mg_1000_CMST'): 400} # ------------------------------------------- HEP B TESTING --------------------------------------------------- - self.item_codes_preg_consumables['hep_b_test'] = get_list_of_items( - self, ['Hepatitis B test kit-Dertemine_100 tests_CMST']) + self.item_codes_preg_consumables['hep_b_test'] = {ic('Hepatitis B test kit-Dertemine_100 tests_CMST'): 1} # ------------------------------------------- SYPHILIS TESTING ------------------------------------------------ - self.item_codes_preg_consumables['syphilis_test'] = get_list_of_items( - self, ['Test, Rapid plasma reagin (RPR)']) + self.item_codes_preg_consumables['syphilis_test'] = {ic('Test, Rapid plasma reagin (RPR)'): 1} # ------------------------------------------- SYPHILIS TREATMENT ---------------------------------------------- - self.item_codes_preg_consumables['syphilis_treatment'] = get_list_of_items( - self, ['Benzathine benzylpenicillin, powder for injection, 2.4 million IU']) - - # ----------------------------------------------- IPTP -------------------------------------------------------- - self.item_codes_preg_consumables['iptp'] = get_list_of_items( - self, ['Sulfamethoxazole + trimethropin, tablet 400 mg + 80 mg']) + self.item_codes_preg_consumables['syphilis_treatment'] =\ + {ic('Benzathine benzylpenicillin, powder for injection, 2.4 million IU'): 1} # ----------------------------------------------- GDM TEST ---------------------------------------------------- - self.item_codes_preg_consumables['gdm_test'] = get_list_of_items(self, ['Blood glucose level test']) + self.item_codes_preg_consumables['gdm_test'] = {ic('Blood glucose level test'): 1} # ------------------------------------------ FULL BLOOD COUNT ------------------------------------------------- - self.item_codes_preg_consumables['full_blood_count'] = get_list_of_items(self, ['Complete blood count']) + self.item_codes_preg_consumables['full_blood_count'] = {ic('Complete blood count'): 1} # ---------------------------------------- BLOOD TRANSFUSION ------------------------------------------------- - self.item_codes_preg_consumables['blood_transfusion'] = get_list_of_items(self, ['Blood, one unit']) + self.item_codes_preg_consumables['blood_transfusion'] = {ic('Blood, one unit'): 2} # --------------------------------------- ORAL ANTIHYPERTENSIVES --------------------------------------------- - self.item_codes_preg_consumables['oral_antihypertensives'] = get_list_of_items( - self, ['Methyldopa 250mg_1000_CMST']) + # Dose changes at run time + self.item_codes_preg_consumables['oral_antihypertensives'] = {ic('Methyldopa 250mg_1000_CMST'): 1} # ------------------------------------- INTRAVENOUS ANTIHYPERTENSIVES --------------------------------------- - self.item_codes_preg_consumables['iv_antihypertensives'] = get_list_of_items( - self, ['Hydralazine, powder for injection, 20 mg ampoule']) + self.item_codes_preg_consumables['iv_antihypertensives'] = \ + {ic('Hydralazine, powder for injection, 20 mg ampoule'): 1} # ---------------------------------------- MAGNESIUM SULPHATE ------------------------------------------------ - self.item_codes_preg_consumables['magnesium_sulfate'] = get_list_of_items( - self, ['Magnesium sulfate, injection, 500 mg/ml in 10-ml ampoule']) + self.item_codes_preg_consumables['magnesium_sulfate'] = \ + {ic('Magnesium sulfate, injection, 500 mg/ml in 10-ml ampoule'): 2} # ---------------------------------------- MANAGEMENT OF ECLAMPSIA -------------------------------------------- - self.item_codes_preg_consumables['eclampsia_management_optional'] = get_list_of_items( - self, ['Misoprostol, tablet, 200 mcg', - 'Oxytocin, injection, 10 IU in 1 ml ampoule', - 'Sodium chloride, injectable solution, 0,9 %, 500 ml', - 'Cannula iv (winged with injection pot) 18_each_CMST', - 'Giving set iv administration + needle 15 drops/ml_each_CMST', - 'Disposables gloves, powder free, 100 pieces per box', - 'Oxygen, 1000 liters, primarily with oxygen cylinders', - 'Complete blood count', - 'Blood collecting tube, 5 ml', - 'Foley catheter', - 'Bag, urine, collecting, 2000 ml']) + self.item_codes_preg_consumables['eclampsia_management_optional'] = \ + {ic('Sodium chloride, injectable solution, 0,9 %, 500 ml'): 2000, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1, + ic('Oxygen, 1000 liters, primarily with oxygen cylinders'): 23_040, + ic('Complete blood count'): 1, + ic('Blood collecting tube, 5 ml'): 1, + ic('Foley catheter'): 1, + ic('Bag, urine, collecting, 2000 ml'): 1, + } # -------------------------------------- ANTIBIOTICS FOR PROM ------------------------------------------------ - self.item_codes_preg_consumables['abx_for_prom'] = get_list_of_items( - self, ['Benzathine benzylpenicillin, powder for injection, 2.4 million IU']) + self.item_codes_preg_consumables['abx_for_prom'] = \ + {ic('Benzathine benzylpenicillin, powder for injection, 2.4 million IU'): 8} # ----------------------------------- ORAL DIABETIC MANAGEMENT ----------------------------------------------- - self.item_codes_preg_consumables['oral_diabetic_treatment'] = get_list_of_items( - self, ['Glibenclamide 5mg_1000_CMST']) + # Dose changes at run time + self.item_codes_preg_consumables['oral_diabetic_treatment'] = \ + {ic('Glibenclamide 5mg_1000_CMST'): 1} # ---------------------------------------- INSULIN ---------------------------------------------------------- - self.item_codes_preg_consumables['insulin_treatment'] = get_list_of_items( - self, ['Insulin soluble 100 IU/ml, 10ml_each_CMST']) + # Dose changes at run time + self.item_codes_preg_consumables['insulin_treatment'] = \ + {ic('Insulin soluble 100 IU/ml, 10ml_each_CMST'): 1} def initialise_simulation(self, sim): @@ -730,7 +734,7 @@ def screening_interventions_delivered_at_every_contact(self, hsi_event): # check consumables avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_preg_consumables, core='urine_dipstick') + self, hsi_event, cons=self.item_codes_preg_consumables['urine_dipstick'], opt_cons=None) # If the intervention will be delivered the dx_manager runs, returning True if the consumables are # available and the test detects protein in the urine @@ -743,6 +747,7 @@ def screening_interventions_delivered_at_every_contact(self, hsi_event): # The process is repeated for blood pressure monitoring if self.rng.random_sample() < params['prob_intervention_delivered_bp']: + hsi_event.add_equipment({'Sphygmomanometer'}) if self.sim.modules['HealthSystem'].dx_manager.run_dx_test(dx_tests_to_run='blood_pressure_measurement', hsi_event=hsi_event): @@ -788,8 +793,10 @@ def iron_and_folic_acid_supplementation(self, hsi_event): # check consumable availability - dose is total days of pregnancy x 2 tablets days = self.get_approx_days_of_pregnancy(person_id) + updated_cons = {k: v*(days*2) for (k, v) in self.item_codes_preg_consumables['iron_folic_acid'].items()} + avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_preg_consumables, core='iron_folic_acid', number=days*3) + self, hsi_event, cons=updated_cons, opt_cons=None) if avail: logger.info(key='anc_interventions', data={'mother': person_id, 'intervention': 'iron_folic_acid'}) @@ -822,8 +829,11 @@ def balance_energy_and_protein_supplementation(self, hsi_event): # If the consumables are available... days = self.get_approx_days_of_pregnancy(person_id) + updated_cons = {k: v*days for (k, v) in + self.item_codes_preg_consumables['balanced_energy_protein'].items()} + avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_preg_consumables, core='balanced_energy_protein', number=days) + self, hsi_event, cons=updated_cons, opt_cons=None) # And she is deemed to be at risk (i.e. BMI < 18) she is started on supplements if avail and (df.at[person_id, 'li_bmi'] == 1): @@ -885,8 +895,11 @@ def calcium_supplementation(self, hsi_event): or (df.at[person_id, 'la_parity'] > 4)): days = self.get_approx_days_of_pregnancy(person_id) * 3 + updated_cons = {k: v * days for (k, v) in + self.item_codes_preg_consumables['calcium'].items()} + avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_preg_consumables, core='calcium', number=days) + self, hsi_event, cons=updated_cons, opt_cons=None) if avail: df.at[person_id, 'ac_receiving_calcium_supplements'] = True @@ -909,7 +922,9 @@ def point_of_care_hb_testing(self, hsi_event): # Run check against probability of testing being delivered avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_preg_consumables, core='hb_test', optional='blood_test_equipment') + self, hsi_event, + cons=self.item_codes_preg_consumables['hb_test'], + opt_cons=self.item_codes_preg_consumables['blood_test_equipment']) # We run the test through the dx_manager and if a woman has anaemia and its detected she will be admitted # for further care @@ -983,8 +998,9 @@ def syphilis_screening_and_treatment(self, hsi_event): logger.info(key='anc_interventions', data={'mother': person_id, 'intervention': 'syphilis_test'}) avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_preg_consumables, core='syphilis_test', - optional='blood_test_equipment') + self, hsi_event, + cons=self.item_codes_preg_consumables['syphilis_test'], + opt_cons=self.item_codes_preg_consumables['blood_test_equipment']) test = self.sim.modules['HealthSystem'].dx_manager.run_dx_test( dx_tests_to_run='blood_test_syphilis', hsi_event=hsi_event) @@ -993,8 +1009,9 @@ def syphilis_screening_and_treatment(self, hsi_event): if avail and test: avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_preg_consumables, core='syphilis_treatment', - optional='blood_test_equipment') + self, hsi_event, + cons=self.item_codes_preg_consumables['syphilis_treatment'], + opt_cons=self.item_codes_preg_consumables['blood_test_equipment']) if avail: # We assume that treatment is 100% effective at curing infection @@ -1059,24 +1076,30 @@ def gdm_screening(self, hsi_event): if self.rng.random_sample() < params['prob_intervention_delivered_gdm_test']: avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_preg_consumables, core='gdm_test', optional='blood_test_equipment') + self, hsi_event, + cons=self.item_codes_preg_consumables['gdm_test'], + opt_cons=self.item_codes_preg_consumables['blood_test_equipment']) # If the test accurately detects a woman has gestational diabetes the consumables are recorded and # she is referred for treatment - if avail and self.sim.modules['HealthSystem'].dx_manager.run_dx_test( - dx_tests_to_run='blood_test_glucose', hsi_event=hsi_event): + if avail: + hsi_event.add_equipment({'Glucometer'}) - logger.info(key='anc_interventions', data={'mother': person_id, 'intervention': 'gdm_screen'}) - mni[person_id]['anc_ints'].append('gdm_screen') + if ( + self.sim.modules['HealthSystem'].dx_manager.run_dx_test( + dx_tests_to_run='blood_test_glucose', hsi_event=hsi_event) + ): + logger.info(key='anc_interventions', data={'mother': person_id, 'intervention': 'gdm_screen'}) + mni[person_id]['anc_ints'].append('gdm_screen') - # We assume women with a positive GDM screen will be admitted (if they are not already receiving - # outpatient care) - if df.at[person_id, 'ac_gest_diab_on_treatment'] == 'none': + # We assume women with a positive GDM screen will be admitted (if they are not already receiving + # outpatient care) + if df.at[person_id, 'ac_gest_diab_on_treatment'] == 'none': - # Store onset after diagnosis as daly weight is tied to diagnosis - pregnancy_helper_functions.store_dalys_in_mni(person_id, mni, 'gest_diab_onset', - self.sim.date) - df.at[person_id, 'ac_to_be_admitted'] = True + # Store onset after diagnosis as daly weight is tied to diagnosis + pregnancy_helper_functions.store_dalys_in_mni(person_id, mni, 'gest_diab_onset', + self.sim.date) + df.at[person_id, 'ac_to_be_admitted'] = True def interventions_delivered_each_visit_from_anc2(self, hsi_event): """This function contains a collection of interventions that are delivered to women every time they attend ANC @@ -1195,6 +1218,7 @@ def full_blood_count_testing(self, hsi_event): # If a woman is not truly anaemic but the FBC returns a result of anaemia, due to tests specificity, we # assume the reported anaemia is mild hsi_event.get_consumables(item_codes=self.item_codes_preg_consumables['blood_test_equipment']) + hsi_event.add_equipment({'Analyser, Haematology'}) test_result = self.sim.modules['HealthSystem'].dx_manager.run_dx_test( dx_tests_to_run='full_blood_count_hb', hsi_event=hsi_event) @@ -1225,8 +1249,9 @@ def antenatal_blood_transfusion(self, individual_id, hsi_event): # Check for consumables avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_preg_consumables, core='blood_transfusion', number=2, - optional='iv_drug_equipment') + self, hsi_event, + cons=self.item_codes_preg_consumables['blood_transfusion'], + opt_cons=self.item_codes_preg_consumables['iv_drug_equipment']) sf_check = pregnancy_helper_functions.check_emonc_signal_function_will_run(self.sim.modules['Labour'], sf='blood_tran', @@ -1236,6 +1261,8 @@ def antenatal_blood_transfusion(self, individual_id, hsi_event): if avail and sf_check: pregnancy_helper_functions.log_met_need(self, 'blood_tran', hsi_event) + hsi_event.add_equipment({'Drip stand', 'Infusion pump'}) + # If the woman is receiving blood due to anaemia we apply a probability that a transfusion of 2 units # RBCs will correct this woman's severe anaemia if params['treatment_effect_blood_transfusion_anaemia'] > self.rng.random_sample(): @@ -1253,9 +1280,12 @@ def initiate_maintenance_anti_hypertensive_treatment(self, individual_id, hsi_ev df = self.sim.population.props # Calculate the approximate dose for the remainder of pregnancy and check availability + days = self.get_approx_days_of_pregnancy(individual_id) * 4 + updated_cons = {k: v * days for (k, v) in + self.item_codes_preg_consumables['oral_antihypertensives'].items()} + avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_preg_consumables, core='oral_antihypertensives', - number=(self.get_approx_days_of_pregnancy(individual_id) * 4)) + self, hsi_event, cons=updated_cons, opt_cons=None) # If the consumables are available then the woman is started on treatment if avail: @@ -1274,12 +1304,14 @@ def initiate_treatment_for_severe_hypertension(self, individual_id, hsi_event): # Define the consumables and check their availability avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_preg_consumables, core='iv_antihypertensives', - optional='iv_drug_equipment') + self, hsi_event, + cons=self.item_codes_preg_consumables['iv_antihypertensives'], + opt_cons=self.item_codes_preg_consumables['iv_drug_equipment']) # If they are available then the woman is started on treatment if avail: pregnancy_helper_functions.log_met_need(self, 'iv_htns', hsi_event) + hsi_event.add_equipment({'Drip stand', 'Infusion pump'}) # We assume women treated with antihypertensives would no longer be severely hypertensive- meaning they # are not at risk of death from severe gestational hypertension in the PregnancySupervisor event @@ -1305,8 +1337,9 @@ def treatment_for_severe_pre_eclampsia_or_eclampsia(self, individual_id, hsi_eve df = self.sim.population.props avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_preg_consumables, core='magnesium_sulfate', - optional='eclampsia_management_optional') + self, hsi_event, + cons=self.item_codes_preg_consumables['magnesium_sulfate'], + opt_cons=self.item_codes_preg_consumables['eclampsia_management_optional']) # check HCW will deliver intervention sf_check = pregnancy_helper_functions.check_emonc_signal_function_will_run(self.sim.modules['Labour'], @@ -1317,6 +1350,7 @@ def treatment_for_severe_pre_eclampsia_or_eclampsia(self, individual_id, hsi_eve if avail and sf_check: df.at[individual_id, 'ac_mag_sulph_treatment'] = True pregnancy_helper_functions.log_met_need(self, 'mag_sulph', hsi_event) + hsi_event.add_equipment({'Drip stand', 'Infusion pump'}) def antibiotics_for_prom(self, individual_id, hsi_event): """ @@ -1329,8 +1363,9 @@ def antibiotics_for_prom(self, individual_id, hsi_event): # check consumables and whether HCW are available to deliver the intervention avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_preg_consumables, core='abx_for_prom', - optional='iv_drug_equipment') + self, hsi_event, + cons=self.item_codes_preg_consumables['abx_for_prom'], + opt_cons=self.item_codes_preg_consumables['iv_drug_equipment']) sf_check = pregnancy_helper_functions.check_emonc_signal_function_will_run(self.sim.modules['Labour'], sf='iv_abx', @@ -1338,6 +1373,7 @@ def antibiotics_for_prom(self, individual_id, hsi_event): if avail and sf_check: df.at[individual_id, 'ac_received_abx_for_prom'] = True + hsi_event.add_equipment({'Drip stand', 'Infusion pump'}) def ectopic_pregnancy_treatment_doesnt_run(self, hsi_event): """ @@ -1427,6 +1463,12 @@ def apply(self, person_id, squeeze_factor): df.at[person_id, 'ac_total_anc_visits_current_pregnancy'] += 1 # =================================== INTERVENTIONS ==================================================== + # Add equipment used during first ANC visit not directly related to interventions + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('ANC')) + self.add_equipment( + {'Height Pole (Stadiometer)', 'MUAC tape', + 'Ultrasound, combined 2/4 pole interferential with vacuum and dual frequency 1-3MHZ'}) + # First all women, regardless of ANC contact or gestation, undergo urine and blood pressure measurement # and depression screening self.module.screening_interventions_delivered_at_every_contact(hsi_event=self) @@ -1445,6 +1487,7 @@ def apply(self, person_id, squeeze_factor): # If the woman presents after 20 weeks she is provided interventions she has missed by presenting late if mother.ps_gestational_age_in_weeks > 19: + self.add_equipment({'Stethoscope, foetal, monaural, Pinard, plastic'}) self.module.point_of_care_hb_testing(hsi_event=self) self.module.albendazole_administration(hsi_event=self) self.module.iptp_administration(hsi_event=self) @@ -1509,7 +1552,12 @@ def apply(self, person_id, squeeze_factor): df.at[person_id, 'ac_total_anc_visits_current_pregnancy'] += 1 # =================================== INTERVENTIONS ==================================================== - # First we administer the administer the interventions all women will receive at this contact regardless of + # Add equipment used during ANC visit not directly related to interventions + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('ANC')) + self.add_equipment( + {'Ultrasound, combined 2/4 pole interferential with vacuum and dual frequency 1-3MHZ'}) + + # First we administer the interventions all women will receive at this contact regardless of # gestational age self.module.interventions_delivered_each_visit_from_anc2(hsi_event=self) self.module.tetanus_vaccination(hsi_event=self) @@ -1593,6 +1641,8 @@ def apply(self, person_id, squeeze_factor): df.at[person_id, 'ac_total_anc_visits_current_pregnancy'] += 1 # =================================== INTERVENTIONS ==================================================== + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('ANC')) + gest_age_next_contact = self.module.determine_gestational_age_for_next_contact(person_id) self.module.interventions_delivered_each_visit_from_anc2(hsi_event=self) @@ -1665,6 +1715,8 @@ def apply(self, person_id, squeeze_factor): df.at[person_id, 'ac_total_anc_visits_current_pregnancy'] += 1 # =================================== INTERVENTIONS ==================================================== + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('ANC')) + gest_age_next_contact = self.module.determine_gestational_age_for_next_contact(person_id) self.module.interventions_delivered_each_visit_from_anc2(hsi_event=self) @@ -1732,7 +1784,11 @@ def apply(self, person_id, squeeze_factor): self.module.anc_counter[5] += 1 df.at[person_id, 'ac_total_anc_visits_current_pregnancy'] += 1 - # =================================== INTERVENTIONS ==================================================== + # =================================== INTERVENTIONS =================================================== + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('ANC')) + self.add_equipment( + {'Ultrasound, combined 2/4 pole interferential with vacuum and dual frequency 1-3MHZ'}) + gest_age_next_contact = self.module.determine_gestational_age_for_next_contact(person_id) self.module.interventions_delivered_each_visit_from_anc2(hsi_event=self) @@ -1800,6 +1856,9 @@ def apply(self, person_id, squeeze_factor): gest_age_next_contact = self.module.determine_gestational_age_for_next_contact(person_id) # =================================== INTERVENTIONS ==================================================== + self.add_equipment({'Weighing scale', 'Measuring tapes', + 'Stethoscope, foetal, monaural, Pinard, plastic'}) + self.module.interventions_delivered_each_visit_from_anc2(hsi_event=self) if mother.ps_gestational_age_in_weeks < 40: @@ -1859,6 +1918,8 @@ def apply(self, person_id, squeeze_factor): df.at[person_id, 'ac_total_anc_visits_current_pregnancy'] += 1 # =================================== INTERVENTIONS ==================================================== + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('ANC')) + gest_age_next_contact = self.module.determine_gestational_age_for_next_contact(person_id) self.module.interventions_delivered_each_visit_from_anc2(hsi_event=self) @@ -1912,6 +1973,8 @@ def apply(self, person_id, squeeze_factor): self.module.anc_counter[8] += 1 df.at[person_id, 'ac_total_anc_visits_current_pregnancy'] += 1 + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('ANC')) + self.module.interventions_delivered_each_visit_from_anc2(hsi_event=self) if df.at[person_id, 'ac_to_be_admitted']: @@ -2426,6 +2489,8 @@ def apply(self, person_id, squeeze_factor): if not mother.la_currently_in_labour and not mother.hs_is_inpatient and mother.ps_gest_diab != 'none' \ and (mother.ac_gest_diab_on_treatment != 'none') and (mother.ps_gestational_age_in_weeks > 21): + est_length_preg = self.module.get_approx_days_of_pregnancy(person_id) + def schedule_gdm_event_and_checkup(): # Schedule GestationalDiabetesGlycaemicControlEvent which determines if this new treatment will # effectively control blood glucose prior to next follow up @@ -2450,9 +2515,12 @@ def schedule_gdm_event_and_checkup(): # meds if mother.ac_gest_diab_on_treatment == 'diet_exercise': + days = est_length_preg * 10 + updated_cons = {k: v * days for (k, v) in + self.module.item_codes_preg_consumables['oral_diabetic_treatment'].items()} + avail = pregnancy_helper_functions.return_cons_avail( - self.module, self, self.module.item_codes_preg_consumables, core='oral_diabetic_treatment', - number=(self.module.get_approx_days_of_pregnancy(person_id) * 2)) + self.module, self, cons=updated_cons, opt_cons=None) # If the meds are available women are started on that treatment if avail: @@ -2468,9 +2536,15 @@ def schedule_gdm_event_and_checkup(): # blood sugar- they are started on insulin if mother.ac_gest_diab_on_treatment == 'orals': + # Dose is (avg.) 0.8 units per KG per day. Average weight is an appoximation + required_units_per_preg = 65 * (0.8 * est_length_preg) + required_vials = np.ceil(required_units_per_preg/1000) + + updated_cons = {k: v * required_vials for (k, v) in + self.module.item_codes_preg_consumables['insulin_treatment'].items()} + avail = pregnancy_helper_functions.return_cons_avail( - self.module, self, self.module.item_codes_preg_consumables, core='insulin_treatment', - number=5) + self.module, self, cons=updated_cons, opt_cons=None) if avail: df.at[person_id, 'ac_gest_diab_on_treatment'] = 'insulin' @@ -2514,43 +2588,51 @@ def apply(self, person_id, squeeze_factor): # Request baseline PAC consumables baseline_cons = pregnancy_helper_functions.return_cons_avail( - self.module, self, self.module.item_codes_preg_consumables, core='post_abortion_care_core', - optional='post_abortion_care_optional') + self.module, self, + cons=self.module.item_codes_preg_consumables['post_abortion_care_core'], + opt_cons=self.module.item_codes_preg_consumables['post_abortion_care_optional']) # Check HCW availability to deliver surgical removal of retained products sf_check = pregnancy_helper_functions.check_emonc_signal_function_will_run(self.sim.modules['Labour'], sf='retained_prod', hsi_event=self) + # Add used equipment if intervention can happen + if baseline_cons and sf_check: + self.add_equipment({'D&C set', 'Suction Curettage machine', 'Drip stand', 'Infusion pump'}) + # Then we determine if a woman gets treatment for her complication depending on availability of the baseline # consumables (misoprostol) or a HCW who can conduct MVA/DC (we dont model equipment) and additional # consumables for management of her specific complication if abortion_complications.has_any([person_id], 'sepsis', first=True): cons_for_sepsis_pac = pregnancy_helper_functions.return_cons_avail( - self.module, self, self.module.item_codes_preg_consumables, core='post_abortion_care_sepsis_core', - optional='post_abortion_care_sepsis_optional') + self.module, self, + cons=self.module.item_codes_preg_consumables['post_abortion_care_sepsis_core'], + opt_cons=self.module.item_codes_preg_consumables['post_abortion_care_sepsis_optional']) if cons_for_sepsis_pac and (baseline_cons or sf_check): df.at[person_id, 'ac_received_post_abortion_care'] = True elif abortion_complications.has_any([person_id], 'haemorrhage', first=True): - cons_for_haemorrhage = pregnancy_helper_functions.return_cons_avail( - self.module, self, self.module.item_codes_preg_consumables, core='blood_transfusion', number=2, - optional='iv_drug_equipment') + self.module, self, + cons=self.module.item_codes_preg_consumables['blood_transfusion'], + opt_cons=self.module.item_codes_preg_consumables['iv_drug_equipment']) cons_for_shock = pregnancy_helper_functions.return_cons_avail( - self.module, self, self.module.item_codes_preg_consumables, core='post_abortion_care_shock', - optional='post_abortion_care_shock_optional') + self.module, self, + cons=self.module.item_codes_preg_consumables['post_abortion_care_shock'], + opt_cons=self.module.item_codes_preg_consumables['post_abortion_care_shock_optional']) if cons_for_haemorrhage and cons_for_shock and (baseline_cons or sf_check): df.at[person_id, 'ac_received_post_abortion_care'] = True elif abortion_complications.has_any([person_id], 'injury', first=True): cons_for_shock = pregnancy_helper_functions.return_cons_avail( - self.module, self, self.module.item_codes_preg_consumables, core='post_abortion_care_shock', - optional='post_abortion_care_shock_optional') + self.module, self, + cons=self.module.item_codes_preg_consumables['post_abortion_care_shock'], + opt_cons=self.module.item_codes_preg_consumables['post_abortion_care_shock_optional']) if cons_for_shock and (baseline_cons or sf_check): df.at[person_id, 'ac_received_post_abortion_care'] = True @@ -2595,13 +2677,15 @@ def apply(self, person_id, squeeze_factor): # We define the required consumables and check their availability avail = pregnancy_helper_functions.return_cons_avail( - self.module, self, self.module.item_codes_preg_consumables, core='ectopic_pregnancy_core', - optional='ectopic_pregnancy_optional') + self.module, self, + cons=self.module.item_codes_preg_consumables['ectopic_pregnancy_core'], + opt_cons=self.module.item_codes_preg_consumables['ectopic_pregnancy_optional']) # If they are available then treatment can go ahead if avail: self.sim.modules['PregnancySupervisor'].mother_and_newborn_info[person_id]['delete_mni'] = True pregnancy_helper_functions.log_met_need(self.module, 'ep_case_mang', self) + self.add_equipment({'Laparotomy Set'}) # For women who have sought care after they have experienced rupture we use this treatment variable to # reduce risk of death (women who present prior to rupture do not pass through the death event as we assume diff --git a/src/tlo/methods/chronicsyndrome.py b/src/tlo/methods/chronicsyndrome.py index 08fc8c41ae..0ae6599939 100644 --- a/src/tlo/methods/chronicsyndrome.py +++ b/src/tlo/methods/chronicsyndrome.py @@ -1,3 +1,7 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, List + import numpy as np import pandas as pd @@ -6,14 +10,18 @@ from tlo.methods import Metadata from tlo.methods.causes import Cause from tlo.methods.demography import InstantaneousDeath -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -class ChronicSyndrome(Module): +class ChronicSyndrome(Module, GenericFirstAppointmentsMixin): """ This is a dummy chronic disease It demonstrates the following behaviours in respect of the healthsystem module: @@ -275,6 +283,20 @@ def report_daly_values(self): return health_values + def do_at_generic_first_appt_emergency( + self, + person_id: int, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs, + ) -> None: + """Example for CHRONIC SYNDROME""" + if "craving_sandwiches" in symptoms: + event = HSI_ChronicSyndrome_SeeksEmergencyCareAndGetsTreatment( + module=self, + person_id=person_id, + ) + schedule_hsi_event(event, topen=self.sim.date, priority=1) class ChronicSyndromeEvent(RegularEvent, PopulationScopeEventMixin): diff --git a/src/tlo/methods/consumables.py b/src/tlo/methods/consumables.py index bf5a00c7ed..9a96ae93cd 100644 --- a/src/tlo/methods/consumables.py +++ b/src/tlo/methods/consumables.py @@ -2,7 +2,7 @@ import warnings from collections import defaultdict from itertools import repeat -from typing import Dict, List, Optional +from typing import Dict, List, Optional, Tuple import numpy as np import pandas as pd @@ -24,51 +24,126 @@ class Consumables: :param: `availability`: Determines the availability of consumables. If 'default' then use the availability specified in the ResourceFile; if 'none', then let no consumable be ever be available; if 'all', then all - consumables are always available. When using 'all' or 'none', requests for consumables are not logged. + consumables are always available. Other options are also available: see `self._options_for_availability`. If an item_code is requested that is not recognised (not included in `data`), a `UserWarning` is issued, and the result returned is on the basis of the average availability of other consumables in that facility in that month. """ - def __init__(self, data: pd.DataFrame = None, rng: np.random = None, availability: str = 'default') -> None: - - assert availability in ('none', 'default', 'all'), "Argument `availability` is not recognised." - self.cons_availability = availability # Governs availability - none/default/all - self.item_codes = set() # All item_codes that are recognised. + def __init__(self, + availability_data: pd.DataFrame = None, + item_code_designations: pd.DataFrame = None, + rng: np.random = None, + availability: str = 'default' + ) -> None: + + self._options_for_availability = { + 'none', + 'default', + 'all', + 'all_diagnostics_available', + 'all_medicines_available', + 'all_medicines_and_other_available', + 'all_vital_available', + 'all_drug_or_vaccine_available', + } + # Create internal items: self._rng = rng + self._availability = None # Internal storage of availability assumption (only accessed through getter/setter) self._prob_item_codes_available = None # Data on the probability of each item_code being available - self._cons_available_today = None # Index for the item_codes available self._is_available = None # Dict of sets giving the set of item_codes available, by facility_id self._is_unknown_item_available = None # Whether an unknown item is available, by facility_id self._not_recognised_item_codes = set() # The item codes requested but which are not recognised. - self._process_consumables_df(data) + # Save designations + self._item_code_designations = item_code_designations + + # Save all item_codes that are defined and pd.Series with probs of availability from ResourceFile + self.item_codes, self._processed_consumables_data = \ + self._process_consumables_data(availability_data=availability_data) - # Create pointer to the `HealthSystemSummaryCounter` helper class + # Set the availability based on the argument provided (this can be updated later after the class is initialised) + self.availability = availability + + # Create (and save pointer to) the `ConsumablesSummaryCounter` helper class self._summary_counter = ConsumablesSummaryCounter() + @property + def availability(self): + """Returns the internally stored value for the assumption of availability of consumables.""" + return self._availability + + @availability.setter + def availability(self, value: str): + """Changes the effective availability of consumables and updates the internally stored value for that + assumption. + Note that this overrides any changes effected by `override_availability()`. + """ + assert value in self._options_for_availability, f"Argument `cons_availability` is not recognised: {value}." + self._availability = value + self._update_prob_item_codes_available(self._availability) + def on_start_of_day(self, date: datetime.datetime) -> None: """Do the jobs at the start of each new day. * Update the availability of the consumables """ self._refresh_availability_of_consumables(date) - def _process_consumables_df(self, df: pd.DataFrame) -> None: - """Helper function for processing the consumables data, passed in here as pd.DataFrame that has been read-in by - the HealthSystem. - * Saves the data as `self._prob_item_codes_available` - * Saves the set of all recognised item_codes to `self.item_codes` - * Over-rides the availability of all items to be always or never available according the specification of the - argument `cons_availability`. - """ - self.item_codes = set(df.item_code) # Record all consumables identified - self._prob_item_codes_available = df.set_index(['month', 'Facility_ID', 'item_code'])['available_prop'] + def _update_prob_item_codes_available(self, availability: str): + """Saves (or re-saves) the values for `self._prob_item_codes_available` that use the processed consumables + data (read-in from the ResourceFile) and enforces the assumption for the availability of the consumables by + overriding the availability of specific consumables.""" + + # Load the original read-in data (create copy so that edits do change the original) + self._prob_item_codes_available = self._processed_consumables_data.copy() + + # Load designations of the consumables + item_code_designations = self._item_code_designations - if self.cons_availability == 'all': + # Over-ride the data according to option for `availability` + if availability == 'default': + pass + elif availability == 'all': self.override_availability(dict(zip(self.item_codes, repeat(1.0)))) - elif self.cons_availability == 'none': + elif availability == 'none': self.override_availability(dict(zip(self.item_codes, repeat(0.0)))) + elif availability == 'all_diagnostics_available': + item_codes_dx = set( + item_code_designations.index[item_code_designations['is_diagnostic']]).intersection(self.item_codes) + self.override_availability(dict(zip(item_codes_dx, repeat(1.0)))) + elif availability == 'all_medicines_available': + item_codes_medicines = set( + item_code_designations.index[item_code_designations['is_medicine']]).intersection(self.item_codes) + self.override_availability(dict(zip(item_codes_medicines, repeat(1.0)))) + elif availability == 'all_medicines_and_other_available': + item_codes_medicines_and_other = set( + item_code_designations.index[item_code_designations['is_medicine'] | item_code_designations['is_other']] + ).intersection(self.item_codes) + self.override_availability(dict(zip(item_codes_medicines_and_other, repeat(1.0)))) + elif availability == 'all_vital_available': + item_codes_vital = set( + item_code_designations.index[item_code_designations['is_vital']] + ).intersection(self.item_codes) + self.override_availability(dict(zip(item_codes_vital, repeat(1.0)))) + elif availability == 'all_drug_or_vaccine_available': + item_codes_drug_or_vaccine = set( + item_code_designations.index[item_code_designations['is_drug_or_vaccine']] + ).intersection(self.item_codes) + self.override_availability(dict(zip(item_codes_drug_or_vaccine, repeat(1.0)))) + else: + raise ValueError + + def _process_consumables_data(self, availability_data: pd.DataFrame) -> Tuple[set, pd.Series]: + """Helper function for processing the consumables data, passed in here as pd.DataFrame that has been read-in by + the HealthSystem. + Returns: (i) the set of all recognised item_codes; (ii) pd.Series of the availability of + each consumable at each facility_id during each month. + """ + return ( + set(availability_data.item_code), + availability_data.set_index(['month', 'Facility_ID', 'item_code'])['available_prop'] + ) def _refresh_availability_of_consumables(self, date: datetime.datetime): """Update the availability of all items based on the data for the probability of availability, given the current @@ -96,6 +171,8 @@ def override_availability(self, item_codes: dict = None) -> None: Over-ride the availability (for all months and all facilities) of certain item_codes. Note this should not be called directly: Disease modules should call `override_availability_of_consumables` in `HealthSystem`. + Note that these changes will *not* persist following a change of the overall modulator of consumables + availability, `Consumables.availability`. :param item_codes: Dictionary of the form {: probability_that_item_is_available} :return: None """ @@ -173,9 +250,9 @@ def _lookup_availability_of_consumables(self, if facility_info is None: # If `facility_info` is None, it implies that the HSI has not been initialised because the HealthSystem - # is running with `disable=True`. Therefore, accept the default behaviour indicated by the argument saved - # in `self.cons_availability`. If the behaviour is `default`, then let the consumable be available. - if self.cons_availability in ('all', 'default'): + # is running with `disable=True`. Therefore, assume the consumable is available if the overall + # availability assumption is 'all' or 'default', and not otherwise. + if self.availability in ('all', 'default'): return {_i: True for _i in item_codes} else: return {_i: False for _i in item_codes} diff --git a/src/tlo/methods/contraception.py b/src/tlo/methods/contraception.py index 9ddbc6aac9..ab6c633f4c 100644 --- a/src/tlo/methods/contraception.py +++ b/src/tlo/methods/contraception.py @@ -7,7 +7,7 @@ from tlo import Date, DateOffset, Module, Parameter, Property, Types, logging from tlo.analysis.utils import flatten_multi_index_series_into_dict_for_logging from tlo.events import Event, IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event from tlo.util import random_date, sample_outcome, transition_states logger = logging.getLogger(__name__) @@ -646,23 +646,60 @@ def select_contraceptive_following_birth(self, mother_id, mother_age): def get_item_code_for_each_contraceptive(self): """Get the item_code for each contraceptive and for contraceptive initiation.""" - # TODO: update with optional items (currently all considered essential) - get_items_from_pkg = self.sim.modules['HealthSystem'].get_item_codes_from_package_name + # ### Get item codes from item names and define number of units per case here + get_item_code = self.sim.modules['HealthSystem'].get_item_code_from_item_name _cons_codes = dict() - # items for each method that requires an HSI to switch to - _cons_codes['pill'] = get_items_from_pkg('Pill') - _cons_codes['male_condom'] = get_items_from_pkg('Male condom') - _cons_codes['other_modern'] = get_items_from_pkg('Female Condom') - # NB. The consumable female condom is used for the contraceptive state of "other_modern method" - _cons_codes['IUD'] = get_items_from_pkg('IUD') - _cons_codes['injections'] = get_items_from_pkg('Injectable') - _cons_codes['implant'] = get_items_from_pkg('Implant') - _cons_codes['female_sterilization'] = get_items_from_pkg('Female sterilization') + # # items for each method that requires an HSI to switch to + # in 80% cases combined pills administrated + # in other 20% cases same amount of progesterone-only pills ("Levonorgestrel 0.0375 mg, cycle") administrated + # (omitted in here) + _cons_codes['pill'] = \ + {get_item_code("Levonorgestrel 0.15 mg + Ethinyl estradiol 30 mcg (Microgynon), cycle"): 21 * 3.75} + _cons_codes['male_condom'] =\ + {get_item_code("Condom, male"): 30} + _cons_codes['other_modern'] =\ + {get_item_code("Female Condom_Each_CMST"): 30} + _cons_codes['IUD'] =\ + {get_item_code("Glove disposable powdered latex medium_100_CMST"): 2, + get_item_code("IUD, Copper T-380A"): 1} + _cons_codes['injections'] = \ + {get_item_code("Depot-Medroxyprogesterone Acetate 150 mg - 3 monthly"): 1, + get_item_code("Glove disposable powdered latex medium_100_CMST"): 1, + get_item_code("Water for injection, 10ml_Each_CMST"): 1, + get_item_code("Povidone iodine, solution, 10 %, 5 ml per injection"): 5, + get_item_code("Gauze, swabs 8-ply 10cm x 10cm_100_CMST"): 1} + _cons_codes['implant'] =\ + {get_item_code("Glove disposable powdered latex medium_100_CMST"): 3, + get_item_code("Lidocaine HCl (in dextrose 7.5%), ampoule 2 ml"): 2, + get_item_code("Povidone iodine, solution, 10 %, 5 ml per injection"): 1*5, # unit: 1 ml + get_item_code("Syringe, needle + swab"): 2, + get_item_code("Trocar"): 1, + get_item_code("Needle suture intestinal round bodied ½ circle trocar_6_CMST"): 1, + # in 50% cases Jadelle administrated + # in other 50% cases other type of implant ("Implanon (Etonogestrel 68 mg)") administrated + # (omitted in here) + get_item_code("Jadelle (implant), box of 2_CMST"): 1, + get_item_code("Gauze, swabs 8-ply 10cm x 10cm_100_CMST"): 1} + _cons_codes['female_sterilization'] =\ + {get_item_code("Lidocaine HCl (in dextrose 7.5%), ampoule 2 ml"): 1, + get_item_code("Atropine sulphate 600 micrograms/ml, 1ml_each_CMST"): 0.5, # 1 unit used only in 50% cases + # approximated by 0.5 unit each time + get_item_code("Diazepam, injection, 5 mg/ml, in 2 ml ampoule"): 1, + get_item_code("Syringe, autodestruct, 5ml, disposable, hypoluer with 21g needle_each_CMST"): 3, + get_item_code("Gauze, swabs 8-ply 10cm x 10cm_100_CMST"): 2, + get_item_code("Needle, suture, assorted sizes, round body"): 3, + get_item_code("Suture, catgut, chromic, 0, 150 cm"): 3, + get_item_code("Tape, adhesive, 2.5 cm wide, zinc oxide, 5 m roll"): 125, # unit: 1 cm long (2.5 cm wide) + get_item_code("Glove surgeon's size 7 sterile_2_CMST"): 2, + get_item_code("Paracetamol, tablet, 500 mg"): 8*500, # unit: 1 mg + get_item_code("Povidone iodine, solution, 10 %, 5 ml per injection"): 2*5, # unit: 1 ml + get_item_code("Cotton wool, 500g_1_CMST"): 100} # unit: 1 g + assert set(_cons_codes.keys()) == set(self.states_that_may_require_HSI_to_switch_to) # items used when initiating a modern reliable method after not using or switching from non-reliable method - _cons_codes['co_initiation'] = get_items_from_pkg('Contraception initiation') + _cons_codes['co_initiation'] = {get_item_code('Pregnancy slide test kit_100_CMST'): 1} return _cons_codes @@ -1144,8 +1181,12 @@ def apply(self, person_id, squeeze_factor): # Record the date that Family Planning Appointment happened for this person self.sim.population.props.at[person_id, "co_date_of_last_fp_appt"] = self.sim.date + # Measure weight, height and BP even if contraception not administrated + self.add_equipment({ + 'Weighing scale', 'Height Pole (Stadiometer)', 'Blood pressure machine' + }) + # Determine essential and optional items - # TODO: we don't distinguish essential X optional for contraception methods yet, will need to update once we do items_essential = self.module.cons_codes[self.new_contraceptive] items_optional = {} # Record use of consumables and default the person to "not_using" if the consumable is not available. @@ -1170,7 +1211,8 @@ def apply(self, person_id, squeeze_factor): items_all = {**items_essential, **items_optional} # Determine whether the contraception is administrated (ie all essential items are available), - # if so do log the availability of all items, if not set the contraception to "not_using": + # if so do log the availability of all items and update used equipment if any, if not set the contraception to + # "not_using": co_administrated = all(v for k, v in cons_available.items() if k in items_essential) if co_administrated: @@ -1194,6 +1236,18 @@ def apply(self, person_id, squeeze_factor): ) _new_contraceptive = self.new_contraceptive + + # Add used equipment + if _new_contraceptive == 'female_sterilization': + self.add_equipment({ + 'Cusco’s/ bivalved Speculum (small, medium, large)', 'Lamp, Anglepoise' + }) + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('Minor Surgery')) + elif _new_contraceptive == 'IUD': + self.add_equipment({ + 'Cusco’s/ bivalved Speculum (small, medium, large)', 'Sponge Holding Forceps' + }) + else: _new_contraceptive = "not_using" diff --git a/src/tlo/methods/copd.py b/src/tlo/methods/copd.py index 2fd27e13a2..53602505ae 100644 --- a/src/tlo/methods/copd.py +++ b/src/tlo/methods/copd.py @@ -1,5 +1,7 @@ +from __future__ import annotations + from pathlib import Path -from typing import Dict, List +from typing import TYPE_CHECKING, Dict, List import pandas as pd @@ -9,10 +11,15 @@ from tlo.lm import LinearModel, LinearModelType, Predictor from tlo.methods import Metadata from tlo.methods.causes import Cause -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom from tlo.util import random_date +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import ConsumablesChecker, HSIEventScheduler + from tlo.population import IndividualProperties + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -23,11 +30,11 @@ } -class Copd(Module): +class Copd(Module, GenericFirstAppointmentsMixin): """The module responsible for determining Chronic Obstructive Pulmonary Diseases (COPD) status and outcomes. and initialises parameters and properties associated with COPD plus functions and events related to COPD.""" - INIT_DEPENDENCIES = {'SymptomManager', 'Lifestyle'} + INIT_DEPENDENCIES = {'SymptomManager', 'Lifestyle', 'HealthSystem'} ADDITIONAL_DEPENDENCIES = set() METADATA = { @@ -184,14 +191,14 @@ def define_symptoms(self): def lookup_item_codes(self): """Look-up the item-codes for the consumables needed in the HSI Events for this module.""" - # todo: Need to look-up these item-codes. + ic = self.sim.modules['HealthSystem'].get_item_code_from_item_name + self.item_codes = { - 'bronchodilater_inhaler': 293, - 'steroid_inhaler': 294, - 'oxygen': 127, - 'aminophylline': 292, - 'amoxycillin': 125, - 'prednisolone': 291 + 'bronchodilater_inhaler': ic('Salbutamol Inhaler 100mcg/dose - 200 doses '), + 'oxygen': ic('Oxygen, 1000 liters, primarily with oxygen cylinders'), + 'aminophylline': ic('Aminophylline 100mg, tablets'), + 'amoxycillin': ic('Amoxycillin 250mg_1000_CMST'), + 'prednisolone': ic('Prednisolone 5mg_100_CMST'), } def do_logging(self): @@ -204,30 +211,70 @@ def do_logging(self): data=flatten_multi_index_series_into_dict_for_logging(counts) ) - def give_inhaler(self, person_id: int, hsi_event: HSI_Event): - """Give inhaler if person does not already have one""" - df = self.sim.population.props - has_inhaler = df.at[person_id, 'ch_has_inhaler'] - if not has_inhaler: - if hsi_event.get_consumables(self.item_codes['bronchodilater_inhaler']): - df.at[person_id, 'ch_has_inhaler'] = True - - def do_when_present_with_breathless(self, person_id: int, hsi_event: HSI_Event): - """What to do when a person presents at the generic first appt HSI with a symptom of `breathless_severe` or - `breathless_moderate`. + def _common_first_appt( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + consumables_checker: ConsumablesChecker, + ): + """What to do when a person presents at the generic first appt HSI + with a symptom of `breathless_severe` or `breathless_moderate`. * If severe --> give the inhaler and schedule the HSI for Treatment * Otherwise --> just give inhaler. """ - self.give_inhaler(hsi_event=hsi_event, person_id=person_id) - - if 'breathless_severe' in self.sim.modules['SymptomManager'].has_what(person_id): - self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=HSI_Copd_TreatmentOnSevereExacerbation(module=self, person_id=person_id), - priority=0, - topen=self.sim.date, - tclose=None, + if ('breathless_moderate' in symptoms) or ('breathless_severe' in symptoms): + # Give inhaler if patient does not already have one + if not individual_properties["ch_has_inhaler"] and consumables_checker( + {self.item_codes["bronchodilater_inhaler"]: 1} + ): + individual_properties["ch_has_inhaler"] = True + if "breathless_severe" in symptoms: + event = HSI_Copd_TreatmentOnSevereExacerbation( + module=self, person_id=person_id + ) + schedule_hsi_event( + event, topen=self.sim.date, priority=0 + ) + + def do_at_generic_first_appt( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + consumables_checker: ConsumablesChecker, + **kwargs, + ) -> None: + # Non-emergency appointments are only forwarded if + # the patient is over 5 years old + if individual_properties["age_years"] > 5: + return self._common_first_appt( + person_id=person_id, + individual_properties=individual_properties, + symptoms=symptoms, + schedule_hsi_event=schedule_hsi_event, + consumables_checker=consumables_checker, ) + def do_at_generic_first_appt_emergency( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + consumables_checker: ConsumablesChecker, + **kwargs, + ) -> None: + return self._common_first_appt( + person_id=person_id, + individual_properties=individual_properties, + symptoms=symptoms, + schedule_hsi_event=schedule_hsi_event, + consumables_checker=consumables_checker, + ) + class CopdModels: """Helper class containing the models needed for the Copd module.""" @@ -527,7 +574,8 @@ def apply(self, person_id, squeeze_factor): * Provide treatment: whatever is available at this facility at this time (no referral). """ df = self.sim.population.props - if not self.get_consumables(self.module.item_codes['oxygen']): + # Assume average 8L O2 for 2 days inpatient care + if not self.get_consumables({self.module.item_codes['oxygen']: 23_040}): # refer to the next higher facility if the current facility has no oxygen self.facility_levels_index += 1 if self.facility_levels_index >= len(self.all_facility_levels): @@ -537,11 +585,13 @@ def apply(self, person_id, squeeze_factor): else: # Give oxygen and AminoPhylline, if possible, ... and cancel death if the treatment is successful. + # Aminophylline dose = 100mg 8hrly, assuming 600mg in 48 hours prob_treatment_success = self.module.models.prob_livesaved_given_treatment( df=df.iloc[[person_id]], - oxygen=self.get_consumables(self.module.item_codes['oxygen']), - aminophylline=self.get_consumables(self.module.item_codes['aminophylline']) + oxygen=self.get_consumables({self.module.item_codes['oxygen']: 23_040}), + aminophylline=self.get_consumables({self.module.item_codes['aminophylline']: 600}) ) + self.add_equipment({'Oxygen cylinder, with regulator', 'Nasal Prongs', 'Drip stand', 'Infusion pump'}) if prob_treatment_success: df.at[person_id, 'ch_will_die_this_episode'] = False diff --git a/src/tlo/methods/demography.py b/src/tlo/methods/demography.py index c3863a66af..8d510f29ae 100644 --- a/src/tlo/methods/demography.py +++ b/src/tlo/methods/demography.py @@ -73,9 +73,10 @@ class Demography(Module): The core demography module. """ - def __init__(self, name=None, resourcefilepath=None): + def __init__(self, name=None, resourcefilepath=None, equal_allocation_by_district: bool = False): super().__init__(name) self.resourcefilepath = resourcefilepath + self.equal_allocation_by_district = equal_allocation_by_district self.initial_model_to_data_popsize_ratio = None # will store scaling factor self.popsize_by_year = dict() # will store total population size each year self.causes_of_death = dict() # will store all the causes of death that are possible in the simulation @@ -85,8 +86,8 @@ def __init__(self, name=None, resourcefilepath=None): self.other_death_poll = None # will hold pointer to the OtherDeathPoll object self.districts = None # will store all the districts in a list - OPTIONAL_INIT_DEPENDENCIES = {'ScenarioSwitcher'} # <-- Forces the 'ScenarioSwitcher' to be the first registered - # module, if it's registered. + OPTIONAL_INIT_DEPENDENCIES = {'ImprovedHealthSystemAndCareSeekingScenarioSwitcher'} + # <-- this forces that module to be the first registered module, if it's registered. AGE_RANGE_CATEGORIES, AGE_RANGE_LOOKUP = create_age_range_lookup( min_age=MIN_AGE_FOR_RANGE, @@ -245,6 +246,8 @@ def initialise_population(self, population): init_pop, max_age=self.parameters['max_age_initial'] ) + if self.equal_allocation_by_district: + init_pop = self._edit_init_pop_so_that_equal_number_in_each_district(init_pop) # randomly pick from the init_pop sheet, to allocate characteristic to each person in the df demog_char_to_assign = init_pop.iloc[self.rng.choice(init_pop.index.values, @@ -381,6 +384,56 @@ def _edit_init_pop_to_prevent_persons_greater_than_max_age(self, df, max_age: in _df.prob = _df.prob / _df.prob.sum() # Rescale `prob` so that it sums to 1.0 return _df.reset_index(drop=True) + @staticmethod + def _edit_init_pop_so_that_equal_number_in_each_district(df) -> pd.DataFrame: + """Return an edited version of the `pd.DataFrame` describing the probability of persons in the population being + created with certain characteristics to reflect the constraint of there being an equal number of persons + in each district.""" + + # Get breakdown of Sex/Age within each district + district_nums = df['District_Num'].unique() + + # Target size of each district + target_size_for_district = df['Count'].sum() / len(district_nums) + + # Make new version (a copy) of the dataframe + df_new = df.copy() + + for district_num in district_nums: + mask_for_district = df['District_Num'] == district_num + # For each district, compute the age/sex breakdown, and use this with target_size to create updated `Count` + # values + df_new.loc[mask_for_district, 'Count'] = target_size_for_district * ( + df.loc[mask_for_district, 'Count'] / df.loc[mask_for_district, 'Count'].sum() + ) + + # Recompute "prob" column (i.e. the probability of being in that category) + df_new["prob"] = df_new['Count'] / df_new['Count'].sum() + + # Check that the resulting dataframe is of the same size/shape as the original; that Count and prob make + # sense; and that we have preserved the age/sex breakdown within each district + def all_elements_identical(x): + return np.allclose(x, x[0]) + + assert df['Count'].sum() == df_new['Count'].sum() + assert 1.0 == df['prob'].sum() == df_new['prob'].sum() + assert all_elements_identical(df_new.groupby('District_Num')['prob'].sum().values) + + def get_age_sex_breakdown_in_district(dat, district_num): + return ( + dat.loc[df['District_Num'] == district_num].groupby(['Age', 'Sex'])['prob'].sum() + / dat.loc[df['District_Num'] == district_num, 'prob'].sum() + ) + + for _d in district_nums: + pd.testing.assert_series_equal( + get_age_sex_breakdown_in_district(df, _d), + get_age_sex_breakdown_in_district(df_new, _d) + ) + + # Return the new dataframe + return df_new + def process_causes_of_death(self): """ 1) Register all causes of deaths defined by Module @@ -581,11 +634,11 @@ def apply(self, population): df = population.props dates_of_birth = df.loc[df.is_alive, 'date_of_birth'] df.loc[df.is_alive, 'age_exact_years'] = age_at_date( - population.sim.date, dates_of_birth + self.module.sim.date, dates_of_birth ) df.loc[df.is_alive, 'age_years'] = df.loc[df.is_alive, 'age_exact_years'].astype('int64') df.loc[df.is_alive, 'age_range'] = df.loc[df.is_alive, 'age_years'].map(self.age_range_lookup) - df.loc[df.is_alive, 'age_days'] = (population.sim.date - dates_of_birth).dt.days + df.loc[df.is_alive, 'age_days'] = (self.module.sim.date - dates_of_birth).dt.days class OtherDeathPoll(RegularEvent, PopulationScopeEventMixin): diff --git a/src/tlo/methods/depression.py b/src/tlo/methods/depression.py index 8f5fd9661c..4e6825cbc5 100644 --- a/src/tlo/methods/depression.py +++ b/src/tlo/methods/depression.py @@ -1,7 +1,10 @@ """ This is the Depression Module. """ +from __future__ import annotations + from pathlib import Path +from typing import TYPE_CHECKING, List, Optional, Union import numpy as np import pandas as pd @@ -12,9 +15,14 @@ from tlo.methods import Metadata from tlo.methods.causes import Cause from tlo.methods.dxmanager import DxTest -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import DiagnosisFunction, HSIEventScheduler + from tlo.population import IndividualProperties + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -23,7 +31,7 @@ # MODULE DEFINITIONS # --------------------------------------------------------------------------------------------------------- -class Depression(Module): +class Depression(Module, GenericFirstAppointmentsMixin): def __init__(self, name=None, resourcefilepath=None): super().__init__(name) self.resourcefilepath = resourcefilepath @@ -32,7 +40,7 @@ def __init__(self, name=None, resourcefilepath=None): 'Demography', 'Contraception', 'HealthSystem', 'Lifestyle', 'SymptomManager' } - OPTIONAL_INIT_DEPENDENCIES = {'HealthBurden'} + OPTIONAL_INIT_DEPENDENCIES = {'HealthBurden', 'Hiv'} # Declare Metadata METADATA = { @@ -138,6 +146,8 @@ def __init__(self, name=None, resourcefilepath=None): 'rr_depr_agege60': Parameter(Types.REAL, 'Relative rate of depression associated with age > 60'), + 'rr_depr_hiv': Parameter(Types.REAL, 'Relative rate of depression associated with HIV infection'), + 'depr_resolution_rates': Parameter( Types.LIST, 'Risk of depression resolving in 3 months if no chronic conditions and no treatments.' @@ -220,11 +230,13 @@ def read_parameters(self, data_folder): ) p = self.parameters - # Build the Linear Models: + # Build the Linear Models + + # ----- Initialisation of population ----- self.linearModels = dict() - self.linearModels['Depression_At_Population_Initialisation'] = LinearModel( - LinearModelType.MULTIPLICATIVE, - self.parameters['init_pr_depr_m_age1519_no_cc_wealth123'], + + # risk of depression in initial population + predictors = [ Predictor('de_cc').when(True, p['init_rp_depr_cc']), Predictor('li_wealth').when('.isin([4,5])', p['init_rp_depr_wealth45']), Predictor().when('(sex=="F") & de_recently_pregnant', p['init_rp_depr_f_rec_preg']), @@ -237,44 +249,63 @@ def read_parameters(self, data_folder): .when('.between(0, 14)', 0) .when('.between(15, 19)', 1.0) .when('.between(20, 59)', p['init_rp_depr_age2059']) - .when('>= 60', p['init_rp_depr_agege60']) + .when('>= 60', p['init_rp_depr_agege60']), + ] + + conditional_predictors = [ + Predictor().when( + 'hv_inf & hv_diagnosed', + p["rr_depr_hiv"]), + ] if "Hiv" in self.sim.modules else [] + + self.linearModels["Depression_At_Population_Initialisation"] = LinearModel( + LinearModelType.MULTIPLICATIVE, + p['init_pr_depr_m_age1519_no_cc_wealth123'], + *(predictors + conditional_predictors) ) + # risk of ever having depression in initial population self.linearModels['Depression_Ever_At_Population_Initialisation_Males'] = LinearModel.multiplicative( Predictor('age_years').apply( lambda x: (x if x > 15 else 0) * self.parameters['init_rp_ever_depr_per_year_older_m'] ) ) + # risk of ever having depression in initial population (female) self.linearModels['Depression_Ever_At_Population_Initialisation_Females'] = LinearModel.multiplicative( Predictor('age_years').apply(lambda x: (x if x > 15 else 0) * p['init_rp_ever_depr_per_year_older_f']) ) + # risk of ever having diagnosed depression in initial population self.linearModels['Depression_Ever_Diagnosed_At_Population_Initialisation'] = LinearModel.multiplicative( Predictor('de_ever_depr').when(True, p['init_pr_ever_diagnosed_depression']) .otherwise(0.0) ) + # risk of currently using anti-depressants in initial population self.linearModels['Using_AntiDepressants_Initialisation'] = LinearModel.multiplicative( Predictor('de_depr').when(True, p['init_pr_antidepr_curr_depr']), Predictor().when('~de_depr & de_ever_diagnosed_depression', p['init_rp_antidepr_ever_depr_not_curr']) ) + # risk of ever having talking therapy in initial population self.linearModels['Ever_Talking_Therapy_Initialisation'] = LinearModel( LinearModelType.MULTIPLICATIVE, p['init_pr_ever_talking_therapy_if_diagnosed'], Predictor('de_ever_diagnosed_depression').when(False, 0) ) + # risk of ever having self-harmed in initial population self.linearModels['Ever_Self_Harmed_Initialisation'] = LinearModel( LinearModelType.MULTIPLICATIVE, p['init_pr_ever_self_harmed_if_ever_depr'], Predictor('de_ever_depr').when(False, 0) ) - self.linearModels['Risk_of_Depression_Onset_per3mo'] = LinearModel( - LinearModelType.MULTIPLICATIVE, - p['base_3m_prob_depr'], + # ----- Recurring events ----- + + # risk of depression every 3 months + predictors = [ Predictor('de_cc').when(True, p['rr_depr_cc']), Predictor('age_years', conditions_are_mutually_exclusive=True) .when('.between(0, 14)', 0) @@ -284,9 +315,22 @@ def read_parameters(self, data_folder): Predictor('sex').when('F', p['rr_depr_female']), Predictor('de_recently_pregnant').when(True, p['rr_depr_pregnancy']), Predictor('de_ever_depr').when(True, p['rr_depr_prev_epis']), - Predictor('de_on_antidepr').when(True, p['rr_depr_on_antidepr']) + Predictor('de_on_antidepr').when(True, p['rr_depr_on_antidepr']), + ] + + conditional_predictors = [ + Predictor().when( + 'hv_inf & hv_diagnosed', + p["rr_depr_hiv"]), + ] if "Hiv" in self.sim.modules else [] + + self.linearModels["Risk_of_Depression_Onset_per3mo"] = LinearModel( + LinearModelType.MULTIPLICATIVE, + p['base_3m_prob_depr'], + *(predictors + conditional_predictors) ) + # risk of depression resolution every 3 months self.linearModels['Risk_of_Depression_Resolution_per3mo'] = LinearModel.multiplicative( Predictor('de_intrinsic_3mo_risk_of_depr_resolution').apply(lambda x: x), Predictor('de_cc').when(True, p['rr_resol_depr_cc']), @@ -294,16 +338,19 @@ def read_parameters(self, data_folder): Predictor('de_ever_talk_ther').when(True, p['rr_resol_depr_current_talk_ther']) ) + # risk of stopping anti-depressants every 3 months self.linearModels['Risk_of_Stopping_Antidepressants_per3mo'] = LinearModel.multiplicative( Predictor('de_depr').when(True, p['prob_3m_default_antidepr']) .when(False, p['prob_3m_stop_antidepr']) ) + # risk of self-harm every 3 months self.linearModels['Risk_of_SelfHarm_per3mo'] = LinearModel( LinearModelType.MULTIPLICATIVE, p['prob_3m_selfharm_depr'] ) + # risk of suicide every 3 months self.linearModels['Risk_of_Suicide_per3mo'] = LinearModel( LinearModelType.MULTIPLICATIVE, p['prob_3m_suicide_depr_m'], @@ -507,62 +554,146 @@ def right_censor(obs, window_close): return av_daly_wt_last_month - def do_on_presentation_to_care(self, person_id, hsi_event): - """This member function is called when a person is in an HSI, and there may need to be screening for depression. + def _check_for_suspected_depression( + self, symptoms: List[str], treatment_id: str, has_even_been_diagnosed: bool + ): """ - df = self.sim.population.props - if hsi_event.TREATMENT_ID == "FirstAttendance_NonEmergency": - if self.rng.rand() < self.parameters['pr_assessed_for_depression_in_generic_appt_level1']: - self.do_when_suspected_depression(person_id=person_id, hsi_event=hsi_event) - - elif hsi_event.TREATMENT_ID == "FirstAttendance_Emergency": - symptoms = self.sim.modules['SymptomManager'].has_what(person_id) - if 'Injuries_From_Self_Harm' in symptoms: - self.do_when_suspected_depression(person_id=person_id, hsi_event=hsi_event) - # TODO: Trigger surgical care for injuries. - - elif hsi_event.TREATMENT_ID == "AntenatalCare_Outpatient": # module care_of_women_during_pregnancy - if (not df.at[person_id, 'de_ever_diagnosed_depression']) and ( - self.rng.rand() < self.parameters['pr_assessed_for_depression_for_perinatal_female'] - ): - self.do_when_suspected_depression(person_id, hsi_event) + Returns True if any signs of depression are present, otherwise False. - elif hsi_event.TREATMENT_ID == "PostnatalCare_Maternal": # module labour - if (not df.at[person_id, 'de_ever_diagnosed_depression']) and ( - self.rng.rand() < self.parameters['pr_assessed_for_depression_for_perinatal_female'] + Raises an error if the treatment type cannot be identified. + """ + if treatment_id == "FirstAttendance_NonEmergency": + if ( + self.rng.rand() + < self.parameters["pr_assessed_for_depression_in_generic_appt_level1"] ): - self.do_when_suspected_depression(person_id=person_id, hsi_event=hsi_event) - + return True + elif treatment_id == "FirstAttendance_Emergency": + if "Injuries_From_Self_Harm" in symptoms: + return True + # TODO: Trigger surgical care for injuries. + elif treatment_id == "AntenatalCare_Outpatient": + if (not has_even_been_diagnosed) and ( + self.rng.rand() + < self.parameters["pr_assessed_for_depression_for_perinatal_female"] + ): # module care_of_women_during_pregnancy + return True + elif treatment_id == "PostnatalCare_Maternal": + if (not has_even_been_diagnosed) and self.rng.rand() < self.parameters[ + "pr_assessed_for_depression_for_perinatal_female" + ]: # module labour + return True else: raise NotImplementedError + return False - def do_when_suspected_depression(self, person_id, hsi_event): + def do_on_presentation_to_care(self, person_id: int, hsi_event: HSI_Event): + """ + This member function is called when a person is in an HSI, + and there may need to be screening for depression. + """ + if self._check_for_suspected_depression( + self.sim.modules["SymptomManager"].has_what(person_id=person_id), + hsi_event.TREATMENT_ID, + self.sim.population.props.at[person_id, "de_ever_diagnosed_depression"], + ): + individual_properties = {} + self.do_when_suspected_depression( + person_id=person_id, + individual_properties=individual_properties, + schedule_hsi_event=self.sim.modules["HealthSystem"].schedule_hsi_event, + hsi_event=hsi_event + ) + self.sim.population.props.loc[person_id, individual_properties.keys()] = ( + individual_properties.values() + ) + return + + def do_when_suspected_depression( + self, + person_id: int, + individual_properties: Union[dict, IndividualProperties], + schedule_hsi_event: HSIEventScheduler, + diagnosis_function: Optional[DiagnosisFunction] = None, + hsi_event: Optional[HSI_Event] = None, + ) -> None: """ - This is called by the a generic HSI event when depression is suspected or otherwise investigated. - :param person_id: - :param hsi_event: The HSI event that has called this event - :return: + This is called by any HSI event when depression is suspected or otherwise investigated. + + At least one of the diagnosis_function or hsi_event arguments must be provided; if both + are provided, the hsi_event argument is ignored. + - If the hsi_event argument is provided, that event is used to access the diagnosis + manager and run diagnosis tests. + - If the diagnosis_function is passed in directly, it is assumed to be a Callable method that + runs diagnosis tests. + + :param person_id: Patient's row index in the population DataFrame. + :param individual_properties: Indexable object to write individual property updates to. + :param schedule_hsi_event: Function to schedule subsequent HSI events. + :param diagnosis_function: A function capable of running diagnosis checks on the population. + :param hsi_event: The HSI_Event that triggered this call. """ + if diagnosis_function is None: + assert isinstance( + hsi_event, HSI_Event + ), "No diagnosis test function, nor HSI_Event instance, supplied." + + def diagnosis_function(tests, use_dict: bool = False, report_tried: bool = False): + return hsi_event.healthcare_system.dx_manager.run_dx_test( + tests, + hsi_event=hsi_event, + use_dict_for_single=use_dict, + report_dxtest_tried=report_tried, + ) # Assess for depression and initiate treatments for depression if positive diagnosis - if self.sim.modules['HealthSystem'].dx_manager.run_dx_test(dx_tests_to_run='assess_depression', - hsi_event=hsi_event - ): + if diagnosis_function('assess_depression'): # If depressed: diagnose the person with depression - self.sim.population.props.at[person_id, 'de_ever_diagnosed_depression'] = True + individual_properties['de_ever_diagnosed_depression'] = True + + scheduling_options = {"priority": 0, "topen": self.sim.date} + # Provide talking therapy + # (this can occur even if the person has already had talking therapy before) + schedule_hsi_event( + HSI_Depression_TalkingTherapy(module=self, person_id=person_id), + **scheduling_options, + ) + # Initiate person on anti-depressants + # (at the same facility level as the HSI event that is calling) + schedule_hsi_event( + HSI_Depression_Start_Antidepressant(module=self, person_id=person_id), + **scheduling_options, + ) - # Provide talking therapy (This can occur even if the person has already had talking therapy before) - self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=HSI_Depression_TalkingTherapy(module=self, person_id=person_id), - priority=0, - topen=self.sim.date + def do_at_generic_first_appt( + self, individual_properties: IndividualProperties, **kwargs + ) -> None: + if individual_properties["age_years"] > 5: + self.do_at_generic_first_appt_emergency( + individual_properties=individual_properties, + **kwargs, ) - # Initiate person on anti-depressants (at the same facility level as the HSI event that is calling) - self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=HSI_Depression_Start_Antidepressant(module=self, person_id=person_id), - priority=0, - topen=self.sim.date + def do_at_generic_first_appt_emergency( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + diagnosis_function: DiagnosisFunction, + treatment_id: str, + **kwargs, + ) -> None: + if self._check_for_suspected_depression( + symptoms, + treatment_id, + individual_properties["de_ever_diagnosed_depression"], + ): + self.do_when_suspected_depression( + person_id=person_id, + individual_properties=individual_properties, + diagnosis_function=diagnosis_function, + schedule_hsi_event=schedule_hsi_event, ) @@ -830,9 +961,10 @@ def apply(self, person_id, squeeze_factor): "receiving an HSI. " # Check availability of antidepressant medication - item_code = self.module.parameters['anti_depressant_medication_item_code'] + # Dose is 25mg daily, patient provided with month supply - 25mg x 30.437 (days) = 761mg per month + item_code_with_dose = {self.module.parameters['anti_depressant_medication_item_code']: 761} - if self.get_consumables(item_codes=item_code): + if self.get_consumables(item_codes=item_code_with_dose): # If medication is available, flag as being on antidepressants df.at[person_id, 'de_on_antidepr'] = True @@ -873,7 +1005,10 @@ def apply(self, person_id, squeeze_factor): return self.sim.modules['HealthSystem'].get_blank_appt_footprint() # Check availability of antidepressant medication - if self.get_consumables(self.module.parameters['anti_depressant_medication_item_code']): + # Dose is 25mg daily, patient provided with month supply - 25mg x 30.437 (days) = 761mg per month + item_code_with_dose = {self.module.parameters['anti_depressant_medication_item_code']: 761} + + if self.get_consumables(item_codes=item_code_with_dose): # Schedule their next HSI for a refill of medication, one month from now self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Depression_Refill_Antidepressant(person_id=person_id, module=self.module), diff --git a/src/tlo/methods/diarrhoea.py b/src/tlo/methods/diarrhoea.py index 242ecb2cc1..06c8a37b18 100644 --- a/src/tlo/methods/diarrhoea.py +++ b/src/tlo/methods/diarrhoea.py @@ -13,11 +13,13 @@ Outstanding Issues * To include rotavirus vaccine - * See todo """ +from __future__ import annotations + from collections.abc import Iterable from pathlib import Path +from typing import TYPE_CHECKING, List import numpy as np import pandas as pd @@ -28,9 +30,14 @@ from tlo.methods import Metadata from tlo.methods.causes import Cause from tlo.methods.dxmanager import DxTest -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.util import random_date, sample_outcome +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import DiagnosisFunction, HSIEventScheduler + from tlo.population import IndividualProperties + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -39,7 +46,7 @@ # MODULE DEFINITIONS # --------------------------------------------------------------------------------------------------------- -class Diarrhoea(Module): +class Diarrhoea(Module, GenericFirstAppointmentsMixin): # Declare the pathogens that this module will simulate: pathogens = [ 'rotavirus', @@ -644,47 +651,23 @@ def report_daly_values(self): def look_up_consumables(self): """Look up and store the consumables item codes used in each of the HSI.""" - get_item_codes_from_package_name = self.sim.modules['HealthSystem'].get_item_codes_from_package_name - - self.consumables_used_in_hsi['ORS'] = get_item_codes_from_package_name( - package='ORS') - self.consumables_used_in_hsi['Treatment_Severe_Dehydration'] = get_item_codes_from_package_name( - package='Treatment of severe diarrhea') - self.consumables_used_in_hsi['Zinc_Under6mo'] = get_item_codes_from_package_name( - package='Zinc for Children 0-6 months') - self.consumables_used_in_hsi['Zinc_Over6mo'] = get_item_codes_from_package_name( - package='Zinc for Children 6-59 months') - self.consumables_used_in_hsi['Antibiotics_for_Dysentery'] = get_item_codes_from_package_name( - package='Antibiotics for treatment of dysentery') - - def do_when_presentation_with_diarrhoea(self, person_id, hsi_event): - """This routine is called when Diarrhoea is a symptom for a child attending a Generic HSI Appointment. It - checks for danger signs and schedules HSI Events appropriately.""" + ic = self.sim.modules['HealthSystem'].get_item_code_from_item_name - # 1) Assessment of danger signs - danger_signs = self.sim.modules['HealthSystem'].dx_manager.run_dx_test( - dx_tests_to_run="imci_severe_dehydration_visual_inspection", hsi_event=hsi_event) + self.consumables_used_in_hsi['ORS'] = {ic('ORS, sachet'): 2} - # 2) Determine which HSI to use: - if danger_signs and (self.rng.rand() < self.parameters['prob_hospitalization_on_danger_signs']): - # Danger signs and hospitalized --> In-patient - self.sim.modules['HealthSystem'].schedule_hsi_event( - HSI_Diarrhoea_Treatment_Inpatient( - person_id=person_id, - module=self), - priority=0, - topen=self.sim.date, - tclose=None) + self.consumables_used_in_hsi['Treatment_Severe_Dehydration'] = \ + {ic('ORS, sachet'): 2, + ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic("ringer's lactate (Hartmann's solution), 1000 ml_12_IDA"): 1000} - else: - # No danger signs or otherwise not hospitalized --> Out-patient - self.sim.modules['HealthSystem'].schedule_hsi_event( - HSI_Diarrhoea_Treatment_Outpatient( - person_id=person_id, - module=self), - priority=0, - topen=self.sim.date, - tclose=None) + self.consumables_used_in_hsi['Zinc'] = ic('Zinc, tablet, 20 mg') + + # For weight based treatment for children under five, we've averaged the median weight for each for years + # 0-5 as 12kg. + # So for cipro/para - 10mg/kg 12 hrly for 7 days = ((10*12)*2) * 7 (same dose in mg reccomended) + self.consumables_used_in_hsi['Antibiotics_for_Dysentery'] = \ + {ic('Ciprofloxacin 250mg_100_CMST'): 1680, + ic("Paracetamol syrup 120mg/5ml_0.0119047619047619_CMST"): 70} # 24mg/ml so 1680/24 = 70ml per dose def do_treatment(self, person_id, hsi_event): """Method called by the HSI that enacts decisions about a treatment and its effect for diarrhoea caused by a @@ -728,9 +711,10 @@ def do_treatment(self, person_id, hsi_event): # ** Implement the procedure for treatment ** # STEP ZERO: Get the Zinc consumable (happens irrespective of whether child will die or not) + # Dose is 10mg 24hrly for 10 days <6months or 20m for >6mnths + dose = 100 if person.age_exact_years < 0.5 else 200 gets_zinc = hsi_event.get_consumables( - item_codes=self.consumables_used_in_hsi[ - 'Zinc_Under6mo' if person.age_exact_years < 0.5 else 'Zinc_Over6mo'] + item_codes={self.consumables_used_in_hsi['Zinc']: dose} ) # STEP ONE: Aim to alleviate dehydration: @@ -962,6 +946,38 @@ def check_properties(self): ) assert set_of_person_id_in_current_episode == has_symptoms + def do_at_generic_first_appt( + self, + person_id: int, + individual_properties: IndividualProperties, + schedule_hsi_event: HSIEventScheduler, + symptoms: List[str], + diagnosis_function: DiagnosisFunction, + **kwargs, + ) -> None: + # This routine is called when Diarrhoea is a symptom for a child + # attending a Generic HSI Appointment. It checks for danger signs + # and schedules HSI Events appropriately. + if individual_properties["age_years"] > 5 or "diarrhoea" not in symptoms: + return + + # 1) Assessment of danger signs + danger_signs = diagnosis_function( + "imci_severe_dehydration_visual_inspection" + ) + + # 2) Determine which HSI to use: + is_inpatient = ( # Danger signs and hospitalized --> In-patient + danger_signs and + self.rng.rand() < self.parameters["prob_hospitalization_on_danger_signs"] + ) + hsi_event_class = ( + HSI_Diarrhoea_Treatment_Inpatient if is_inpatient else + HSI_Diarrhoea_Treatment_Outpatient + ) + event = hsi_event_class(person_id=person_id, module=self) + schedule_hsi_event(event, priority=0, topen=self.sim.date) + class Models: """Helper-class to store all the models that specify the natural history of the Alri disease""" @@ -1555,6 +1571,8 @@ def apply(self, person_id, squeeze_factor): if not df.at[person_id, 'is_alive']: return + self.add_equipment({'Infusion pump', 'Drip stand'}) + self.module.do_treatment(person_id=person_id, hsi_event=self) diff --git a/src/tlo/methods/dxmanager.py b/src/tlo/methods/dxmanager.py index dbf0b71683..b46dd58f87 100644 --- a/src/tlo/methods/dxmanager.py +++ b/src/tlo/methods/dxmanager.py @@ -3,7 +3,7 @@ See https://github.com/UCL/TLOmodel/wiki/Diagnostic-Tests-(DxTest)-and-the-Diagnostic-Tests-Manager-(DxManager) """ import json -from typing import Dict, List, Tuple, Union +from typing import Any, Dict, List, Tuple, TypeAlias, Union import numpy as np import pandas as pd @@ -12,6 +12,8 @@ from tlo import logging from tlo.events import IndividualScopeEventMixin +DiagnosisTestReturnType: TypeAlias = Tuple[Union[Any, Dict[str, Any]]] + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -89,8 +91,14 @@ def print_info_about_all_dx_tests(self): for dx_test in self.dx_tests: self.print_info_about_dx_test(dx_test) - def run_dx_test(self, dx_tests_to_run, hsi_event, use_dict_for_single=False, report_dxtest_tried=False): - from tlo.methods.healthsystem import HSI_Event + def run_dx_test( + self, + dx_tests_to_run, + hsi_event, + use_dict_for_single=False, + report_dxtest_tried=False, + ) -> DiagnosisTestReturnType: + from tlo.methods.hsi_event import HSI_Event # Check that the thing passed to hsi_event is usable as an hsi_event assert isinstance(hsi_event, HSI_Event) diff --git a/src/tlo/methods/epi.py b/src/tlo/methods/epi.py index 912edbf459..1cdf8a1612 100644 --- a/src/tlo/methods/epi.py +++ b/src/tlo/methods/epi.py @@ -6,7 +6,7 @@ from tlo import Date, DateOffset, Module, Parameter, Property, Types, logging from tlo.events import IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.methods import Metadata -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) diff --git a/src/tlo/methods/epilepsy.py b/src/tlo/methods/epilepsy.py index f06c62d098..a1650a3889 100644 --- a/src/tlo/methods/epilepsy.py +++ b/src/tlo/methods/epilepsy.py @@ -1,5 +1,7 @@ +from __future__ import annotations + from pathlib import Path -from typing import Union +from typing import TYPE_CHECKING, List, Union import numpy as np import pandas as pd @@ -9,14 +11,18 @@ from tlo.methods import Metadata from tlo.methods.causes import Cause from tlo.methods.demography import InstantaneousDeath -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -class Epilepsy(Module): +class Epilepsy(Module, GenericFirstAppointmentsMixin): def __init__(self, name=None, resourcefilepath=None): super().__init__(name) self.resourcefilepath = resourcefilepath @@ -392,6 +398,17 @@ def get_best_available_medicine(self, hsi_event) -> Union[None, str]: # None of the treatment is available: return None return None + def do_at_generic_first_appt_emergency( + self, + person_id: int, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs, + ) -> None: + if "seizures" in symptoms: + event = HSI_Epilepsy_Start_Anti_Epileptic(person_id=person_id, module=self) + schedule_hsi_event(event, priority=0, topen=self.sim.date) + class EpilepsyEvent(RegularEvent, PopulationScopeEventMixin): """The regular event that actually changes individuals' epilepsy status @@ -600,7 +617,14 @@ def apply(self, person_id, squeeze_factor): if best_available_medicine is not None: # Request the medicine from the health system - self.get_consumables(self.module.item_codes[best_available_medicine]) + + dose = {'phenobarbitone': 9131, # 100mg per day - 3 months + 'carbamazepine': 91_311, # 1000mg per day - 3 months + 'phenytoin': 27_393} # 300mg per day - 3 months + + self.get_consumables({self.module.item_codes[best_available_medicine]: + dose[best_available_medicine]}) + # Update this person's properties to show that they are currently on medication df.at[person_id, 'ep_antiep'] = True @@ -651,18 +675,30 @@ def apply(self, person_id, squeeze_factor): # Request the medicine best_available_medicine = self.module.get_best_available_medicine(self) if best_available_medicine is not None: + + # Schedule a reoccurrence of this follow-up in 3 months if ep_seiz_stat == '3', + # else, schedule this reoccurrence of it in 1 year (i.e., if ep_seiz_stat == '2' + if df.at[person_id, 'ep_seiz_stat'] == '3': + fu_mnths = 3 + else: + fu_mnths = 12 + # The medicine is available, so request it - self.get_consumables(self.module.item_codes[best_available_medicine]) + dose = {'phenobarbitone_3_mnths': 9131, 'phenobarbitone_12_mnths': 36_525, # 100mg per day - 3/12 months + 'carbamazepine_3_mnths': 91_311, 'carbamazepine_12_mnths': 365_250, # 1000mg per day - 3/12 months + 'phenytoin_3_mnths': 27_393, 'phenytoin_12_mnths': 109_575} # 300mg per day - 3/12 months + + self.get_consumables({self.module.item_codes[best_available_medicine]: + dose[f'{best_available_medicine}_{fu_mnths}_mnths']}) # Reset counter of "failed attempts" and put the appointment for the next occurrence to the usual self._counter_of_failed_attempts_due_to_unavailable_medicines = 0 self.EXPECTED_APPT_FOOTPRINT = self._DEFAULT_APPT_FOOTPRINT - # Schedule a reoccurrence of this follow-up in 3 months if ep_seiz_stat == '3', - # else, schedule this reoccurrence of it in 1 year (i.e., if ep_seiz_stat == '2') + # Schedule follow-up hs.schedule_hsi_event( hsi_event=self, - topen=self.sim.date + DateOffset(months=3 if df.at[person_id, 'ep_seiz_stat'] == '3' else 12), + topen=self.sim.date + DateOffset(months=fu_mnths), tclose=None, priority=0 ) diff --git a/src/tlo/methods/equipment.py b/src/tlo/methods/equipment.py new file mode 100644 index 0000000000..e00bf030fd --- /dev/null +++ b/src/tlo/methods/equipment.py @@ -0,0 +1,289 @@ +import warnings +from collections import defaultdict +from typing import Counter, Dict, Iterable, Literal, Set, Union + +import numpy as np +import pandas as pd + +from tlo import logging + +logger_summary = logging.getLogger("tlo.methods.healthsystem.summary") + + +class Equipment: + """This is the equipment class. It maintains a current record of the availability of equipment in the + health system. It is expected that this is instantiated by the :py:class:`~.HealthSystem` module. + + The basic paradigm is that an :py:class:`~.HSI_Event` can declare equipment that is required for delivering the healthcare + service that the ``HSI_Event`` represents. The ``HSI_Event`` uses :py:meth:`HSI_event.add_equipment` to make these declarations, + with reference to the items of equipment that are defined in ``ResourceFile_EquipmentCatalogue.csv``. (These + declaration can be in the form of the descriptor or the equipment item code). These declarations can be used when + the ``HSI_Event`` is created but before it is run (in ``__init__``), or during execution of the ``HSI_Event`` (in :py:meth:`.HSI_Event.apply`). + + As the ``HSI_Event`` can declare equipment that is required before it is run, the HealthSystem *can* use this to + prevent an ``HSI_Event`` running if the equipment declared is not available. Note that for equipment that is declared + whilst the ``HSI_Event`` is running, there are no checks on availability, and the ``HSI_Event`` is allowed to continue + running even if equipment is declared is not available. For this reason, the ``HSI_Event`` should declare equipment + that is *essential* for the healthcare service in its ``__init__`` method. If the logic inside the ``apply`` method + of the ``HSI_Event`` depends on the availability of equipment, then it can find the probability with which + item(s) will be available using :py:meth:`.HSI_Event.probability_equipment_available`. + + The data on the availability of equipment data refers to the proportion of facilities in a district of a + particular level (i.e., the ``Facility_ID``) that do have that piece of equipment. In the model, we do not know + which actual facility the person is attending (there are many actual facilities grouped together into one + ``Facility_ID`` in the model). Therefore, the determination of whether equipment is available is made + probabilistically for the ``HSI_Event`` (i.e., the probability that the actual facility being attended by the + person has the equipment is represented by the proportion of such facilities that do have that equipment). It is + assumed that the probabilities of each item being available are independent of one other (so that the + probability of all items being available is the product of the probabilities for each item). This probabilistic + determination of availability is only done _once_ for the ``HSI_Event``: i.e., if the equipment is determined to + not be available for the instance of the ``HSI_Event``, then it will remain not available if the same event is + re-scheduled / re-entered into the ``HealthSystem`` queue. This represents that if the facility that a particular + person attends for the ``HSI_Event`` does not have the equipment available, then it will still not be available on + another day. + + Where data on availability is not provided for an item, the probability of availability is inferred from the + average availability of other items in that facility ID. Likewise, the probability of an item being available + at a facility ID is inferred from the average availability of that item at other facilities. If an item code is + referred in ``add_equipment`` that is not recognised (not included in :py:attr:`catalogue`), a :py:exc:`UserWarning` is issued, but + that item is then silently ignored. If a facility ID is ever referred that is not recognised (not included in + :py:attr:`master_facilities_list`), an :py:exc:`AssertionError` is raised. + + :param catalogue: The database of all recognised item_codes. + :param data_availability: Specifies the probability with which each equipment (identified by an ``item_code``) is + available at a facility level. Note that information must be provided for every item in the :py:attr`catalogue` + and every facility ID in the :py:attr`master_facilities_list`. + :param: rng: The random number generator object to use for random numbers. + :param availability: Determines the mode availability of the equipment. If 'default' then use the availability + specified in :py:attr:`data_availability`; if 'none', then let no equipment be ever be available; if 'all', then all + equipment is always available. + :param master_facilities_list: The :py:class:`~pandas.DataFrame` with the line-list of all the facilities in the health system. + """ + + def __init__( + self, + catalogue: pd.DataFrame, + data_availability: pd.DataFrame, + rng: np.random.RandomState, + master_facilities_list: pd.DataFrame, + availability: Literal["all", "default", "none"] = "default", + ) -> None: + # - Store arguments + self.catalogue = catalogue + self.rng = rng + self.data_availability = data_availability + self.availability = availability + self.master_facilities_list = master_facilities_list + + # - Data structures for quick look-ups for items and descriptors + self._item_code_lookup = self.catalogue.set_index('Item_Description')['Item_Code'].to_dict() + self._pkg_lookup = self._create_pkg_lookup() + self._all_item_descriptors = set(self._item_code_lookup.keys()) + self._all_item_codes = set(self._item_code_lookup.values()) + self._all_fac_ids = self.master_facilities_list['Facility_ID'].unique() + + # - Probabilities of items being available at each facility_id + self._probabilities_of_items_available = self._get_equipment_availability_probabilities() + + # - Internal store of which items have been used at each facility_id This is of the form + # {facility_id: {item_code: count}}. + self._record_of_equipment_used_by_facility_id = defaultdict(Counter) + + + def on_simulation_end(self): + """Things to do when the simulation ends: + * Log (to the summary logger) the equipment that has been used. + """ + self.write_to_log() + + @property + def availability(self): + return self._availability + + @availability.setter + def availability(self, value: Literal["all", "default", "none"]): + assert value in {"all", "none", "default"}, f"New availability value {value} not recognised." + self._availability = value + + def _get_equipment_availability_probabilities(self) -> pd.Series: + """ + Extract the probabilities that each equipment item is available (at a given + facility), for use when the equipment availability is set to "default". + + The probabilities extracted in this method are constant throughout the simulation, + however they will not be used when the equipment availability is "all" or "none". + Extracting them once and storing the result allows us to avoid repeating this + calculation if the equipment availability change event occurs during the simulation. + """ + dat = self.data_availability.set_index( + [self.data_availability["Facility_ID"].astype(np.int64), self.data_availability["Item_Code"].astype(np.int64)] + )["Pr_Available"] + + # Confirm that there is an estimate for every item_code at every facility_id + full_index = pd.MultiIndex.from_product( + [self._all_fac_ids, self._all_item_codes], names=["Facility_ID", "Item_Code"] + ) + pd.testing.assert_index_equal(full_index, dat.index, check_order=False) + assert not dat.isnull().any() + + return dat + + def parse_items(self, items: Union[int, str, Iterable[int], Iterable[str]]) -> Set[int]: + """Parse equipment items specified as an item_code (integer), an item descriptor (string), or an iterable of + item_codes or descriptors (but not a mix of the two), and return as a set of item_code (integers). For any + item_code/descriptor not recognised, a ``UserWarning`` is issued.""" + + def check_item_codes_recognised(item_codes: set[int]): + if not item_codes.issubset(self._all_item_codes): + warnings.warn(f'At least one item code was unrecognised: "{item_codes}".') + + def check_item_descriptors_recognised(item_descriptors: set[str]): + if not item_descriptors.issubset(self._all_item_descriptors): + warnings.warn(f'At least one item descriptor was unrecognised "{item_descriptors}".') + + # Make into a set if it is not one already + if isinstance(items, (str, int)): + items = set([items]) + else: + items = set(items) + + items_are_ints = all(isinstance(element, int) for element in items) + + if items_are_ints: + check_item_codes_recognised(items) + # In the return, any unrecognised item_codes are silently ignored. + return items.intersection(self._all_item_codes) + else: + check_item_descriptors_recognised(items) # Warn for any unrecognised descriptors + # In the return, any unrecognised descriptors are silently ignored. + return set(self._item_code_lookup[i] for i in items if i in self._item_code_lookup) + + def probability_all_equipment_available( + self, facility_id: int, item_codes: Set[int] + ) -> float: + """ + Returns the probability that all the equipment item_codes are available + at the given facility. + + It does so by looking at the probabilities of each equipment item being + available and multiplying these together to find the probability that *all* + are available. + + NOTE: This will error if the facility ID or any of the item codes is not recognised. + + :param facility_id: Facility at which to check for the equipment. + :param item_codes: Integer item codes corresponding to the equipment to check. + """ + + assert facility_id in self._all_fac_ids, f"Unrecognised facility ID: {facility_id=}" + assert item_codes.issubset(self._all_item_codes), f"At least one item code was unrecognised: {item_codes=}" + + if self.availability == "all": + return 1.0 + elif self.availability == "none": + return 0.0 + return self._probabilities_of_items_available.loc[ + (facility_id, list(item_codes)) + ].prod() + + def is_all_items_available( + self, item_codes: Set[int], facility_id: int + ) -> bool: + """ + Determine if all equipment items are available at the given facility_id. + Returns True only if all items are available at the facility_id, + otherwise returns False. + """ + if item_codes: + return self.rng.random_sample() < self.probability_all_equipment_available( + facility_id=facility_id, + item_codes=item_codes, + ) + else: + # In the case of an empty set, default to True without doing anything else ('no equipment' is always + # "available"). This is the most common case, so optimising for speed. + return True + + def record_use_of_equipment( + self, item_codes: Set[int], facility_id: int + ) -> None: + """Update internal record of the usage of items at equipment at the specified facility_id.""" + self._record_of_equipment_used_by_facility_id[facility_id].update(item_codes) + + def write_to_log(self) -> None: + """Write to the log: + * Summary of the equipment that was _ever_ used at each district/facility level. + Note that the info-level health system logger (key: `hsi_event_counts`) contains logging of the equipment used + in each HSI event (if finer splits are needed). Alternatively, different aggregations could be created here for + the summary logger, using the same pattern as used here. + """ + + mfl = self.master_facilities_list + + def set_of_keys_or_empty_set(x: Union[set, dict]): + if isinstance(x, set): + return x + elif isinstance(x, dict): + return set(x.keys()) + else: + return set() + + set_of_equipment_ever_used_at_each_facility_id = pd.Series({ + fac_id: set_of_keys_or_empty_set(self._record_of_equipment_used_by_facility_id.get(fac_id, set())) + for fac_id in mfl['Facility_ID'] + }, name='EquipmentEverUsed').astype(str) + + output = mfl.merge( + set_of_equipment_ever_used_at_each_facility_id, + left_on='Facility_ID', + right_index=True, + how='left', + ).drop(columns=['Facility_ID', 'Facility_Name']) + + # Log multi-row data-frame + for _, row in output.iterrows(): + logger_summary.info( + key='EquipmentEverUsed_ByFacilityID', + description='For each facility_id (the set of facilities of the same level in a district), the set of' + 'equipment items that are ever used.', + data=row.to_dict(), + ) + + def from_pkg_names(self, pkg_names: Union[str, Iterable[str]]) -> Set[int]: + """Convenience function to find the set of item_codes that are grouped under requested package name(s) in the + catalogue.""" + # Make into a set if it is not one already + if isinstance(pkg_names, (str, int)): + pkg_names = set([pkg_names]) + else: + pkg_names = set(pkg_names) + + item_codes = set() + for pkg_name in pkg_names: + if pkg_name in self._pkg_lookup.keys(): + item_codes.update(self._pkg_lookup[pkg_name]) + else: + raise ValueError(f'That Pkg_Name is not in the catalogue: {pkg_name=}') + + return item_codes + + def _create_pkg_lookup(self) -> Dict[str, Set[int]]: + """Create a lookup from a Package Name to a set of Item_Codes that are contained with that package. + N.B. In the Catalogue, there is one row for each Item, and the Packages to which each Item belongs (if any) + is given in a column 'Pkg_Name': if an item belongs to multiple packages, these names are separated by commas, + and if it doesn't belong to any package, then there is a NULL value.""" + df = self.catalogue + + # Make dataframe with columns for each package, and bools showing whether each item_code is included + pkgs = df['Pkg_Name'].replace({float('nan'): None}) \ + .str.get_dummies(sep=',') \ + .set_index(df.Item_Code) \ + .astype(bool) + + # Make dict of the form: {'Pkg_Code': } + pkg_lookup_dict = { + pkg_name.strip(): set(pkgs[pkg_name].loc[pkgs[pkg_name]].index.to_list()) + for pkg_name in pkgs.columns + } + + return pkg_lookup_dict diff --git a/src/tlo/methods/healthseekingbehaviour.py b/src/tlo/methods/healthseekingbehaviour.py index 505c78a373..22e628d166 100644 --- a/src/tlo/methods/healthseekingbehaviour.py +++ b/src/tlo/methods/healthseekingbehaviour.py @@ -5,7 +5,10 @@ The write-up of these estimates is: Health-seeking behaviour estimates for adults and children.docx """ +from __future__ import annotations + from pathlib import Path +from typing import TYPE_CHECKING, List import numpy as np import pandas as pd @@ -15,10 +18,15 @@ from tlo.lm import LinearModel from tlo.methods import Metadata from tlo.methods.hsi_generic_first_appts import ( + GenericFirstAppointmentsMixin, + HSI_EmergencyCare_SpuriousSymptom, HSI_GenericEmergencyFirstAppt, HSI_GenericNonEmergencyFirstAppt, ) +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + # --------------------------------------------------------------------------------------------------------- # MODULE DEFINITIONS # --------------------------------------------------------------------------------------------------------- @@ -26,7 +34,7 @@ HIGH_ODDS_RATIO = 1e5 -class HealthSeekingBehaviour(Module): +class HealthSeekingBehaviour(Module, GenericFirstAppointmentsMixin): """ This modules determines if the onset of symptoms will lead to that person presenting at the health facility for a HSI_GenericFirstAppointment. @@ -250,6 +258,19 @@ def force_any_symptom_to_lead_to_healthcareseeking(self): else: return self.arg_force_any_symptom_to_lead_to_healthcareseeking + def do_at_generic_first_appt_emergency( + self, + person_id: int, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs, + ) -> None: + if "spurious_emergency_symptom" in symptoms: + event = HSI_EmergencyCare_SpuriousSymptom( + module=self.sim.modules["HealthSeekingBehaviour"], + person_id=person_id, + ) + schedule_hsi_event(event, priority=0, topen=self.sim.date) # --------------------------------------------------------------------------------------------------------- # REGULAR POLLING EVENT diff --git a/src/tlo/methods/healthsystem.py b/src/tlo/methods/healthsystem.py index 6838f56705..db9173d15b 100644 --- a/src/tlo/methods/healthsystem.py +++ b/src/tlo/methods/healthsystem.py @@ -1,6 +1,7 @@ import datetime import heapq as hp import itertools +import re import warnings from collections import Counter, defaultdict from collections.abc import Iterable @@ -26,6 +27,15 @@ get_item_codes_from_package_name, ) from tlo.methods.dxmanager import DxManager +from tlo.methods.equipment import Equipment +from tlo.methods.hsi_event import ( + LABEL_FOR_MERGED_FACILITY_LEVELS_1B_AND_2, + FacilityInfo, + HSI_Event, + HSIEventDetails, + HSIEventQueueItem, + HSIEventWrapper, +) logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -33,9 +43,6 @@ logger_summary = logging.getLogger(f"{__name__}.summary") logger_summary.setLevel(logging.INFO) -# Declare the level which will be used to represent the merging of levels '1b' and '2' -LABEL_FOR_MERGED_FACILITY_LEVELS_1B_AND_2 = '2' - # Declare the assumption for the availability of consumables at the merged levels '1b' and '2'. This can be a # list of facility_levels over which an average is taken (within a district): e.g. ['1b', '2']. AVAILABILITY_OF_CONSUMABLES_AT_MERGED_LEVELS_1B_AND_2 = ['1b'] # <-- Implies that availability at merged level '1b & 2' @@ -45,13 +52,6 @@ # probably account for the majority of the # interactions. - -def adjust_facility_level_to_merge_1b_and_2(level: str) -> str: - """Adjust the facility level of an HSI_Event so that HSI_Events scheduled at level '1b' and '2' are both directed - to level '2'""" - return level if level not in ('1b', '2') else LABEL_FOR_MERGED_FACILITY_LEVELS_1B_AND_2 - - def pool_capabilities_at_levels_1b_and_2(df_original: pd.DataFrame) -> pd.DataFrame: """Return a modified version of the imported capabilities DataFrame to reflect that the capabilities of level 1b are pooled with those of level 2, and all labelled as level 2.""" @@ -104,342 +104,12 @@ def pool_capabilities_at_levels_1b_and_2(df_original: pd.DataFrame) -> pd.DataFr return df_updated -class FacilityInfo(NamedTuple): - """Information about a specific health facility.""" - id: int - name: str - level: str - region: str - - class AppointmentSubunit(NamedTuple): """Component of an appointment relating to a specific officer type.""" officer_type: str time_taken: float -class HSIEventDetails(NamedTuple): - """Non-target specific details of a health system interaction event.""" - event_name: str - module_name: str - treatment_id: str - facility_level: Optional[str] - appt_footprint: Tuple[Tuple[str, int]] - beddays_footprint: Tuple[Tuple[str, int]] - - -class HSIEventQueueItem(NamedTuple): - """Properties of event added to health system queue. - - The order of the attributes in the tuple is important as the queue sorting is done - by the order of the items in the tuple, i.e. first by `priority`, then `topen` and - so on. - - Ensure priority is above topen in order for held-over events with low priority not - to jump ahead higher priority ones which were opened later. - """ - priority: int - topen: Date - rand_queue_counter: int # Ensure order of events with same topen & priority is not model-dependent - queue_counter: int # Include safety tie-breaker in unlikely event rand_queue_counter is equal - tclose: Date - # Define HSI_Event type as string to avoid NameError exception as HSI_Event defined - # later in module (see https://stackoverflow.com/a/36286947/4798943) - hsi_event: 'HSI_Event' - - -class HSI_Event: - """Base HSI event class, from which all others inherit. - - Concrete subclasses should also inherit from one of the EventMixin classes - defined below, and implement at least an `apply` and `did_not_run` method. - """ - - def __init__(self, module, *args, **kwargs): - """Create a new event. - - Note that just creating an event does not schedule it to happen; that - must be done by calling Simulation.schedule_event. - - :param module: the module that created this event. - All subclasses of Event take this as the first argument in their - constructor, but may also take further keyword arguments. - """ - self.module = module - self.sim = module.sim - self.target = None # Overwritten by the mixin - super().__init__(*args, **kwargs) # Call the mixin's constructors - - # Defaults for the HSI information: - self.TREATMENT_ID = '' - # self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({}) # HSI needs this property, but it is not defined - # in the Base class to allow overwriting with a - # property function. - self.ACCEPTED_FACILITY_LEVEL = None - self.BEDDAYS_FOOTPRINT = self.make_beddays_footprint({}) - - # Information received about this HSI: - self._received_info_about_bed_days = None - self.expected_time_requests = {} - self.facility_info = None - - @property - def bed_days_allocated_to_this_event(self): - if self._received_info_about_bed_days is None: - # default to the footprint if no information about bed-days is received - return self.BEDDAYS_FOOTPRINT - - return self._received_info_about_bed_days - - def apply(self, squeeze_factor=0.0, *args, **kwargs): - """Apply this event to the population. - - Must be implemented by subclasses. - - """ - raise NotImplementedError - - def did_not_run(self, *args, **kwargs): - """Called when this event is due but it is not run. Return False to prevent the event being rescheduled, or True - to allow the rescheduling. This is called each time that the event is tried to be run but it cannot be. - """ - logger.debug(key="message", data=f"{self.__class__.__name__}: did not run.") - return True - - def never_ran(self): - """Called when this event is was entered to the HSI Event Queue, but was never run. - """ - logger.debug(key="message", data=f"{self.__class__.__name__}: was never run.") - - def post_apply_hook(self): - """Impose the bed-days footprint (if target of the HSI is a person_id)""" - if isinstance(self.target, int): - self.module.sim.modules['HealthSystem'].bed_days.impose_beddays_footprint( - person_id=self.target, - footprint=self.bed_days_allocated_to_this_event - ) - - def run(self, squeeze_factor): - """Make the event happen.""" - updated_appt_footprint = self.apply(self.target, squeeze_factor) - self.post_apply_hook() - return updated_appt_footprint - - def get_consumables(self, - item_codes: Union[None, np.integer, int, list, set, dict] = None, - optional_item_codes: Union[None, np.integer, int, list, set, dict] = None, - to_log: Optional[bool] = True, - return_individual_results: Optional[bool] = False - ) -> Union[bool, dict]: - """Function to allow for getting and checking of entire set of consumables. All requests for consumables should - use this function. - :param item_codes: The item code(s) (and quantities) of the consumables that are requested and which determine - the summary result for availability/non-availability. This can be an `int` (the item_code needed [assume - quantity=1]), a `list` or `set` (the collection of item_codes [for each assuming quantity=1]), or a `dict` - (with key:value pairs `:`). - :param optional_item_codes: The item code(s) (and quantities) of the consumables that are requested and which do - not determine the summary result for availability/non-availability. (Same format as `item_codes`). This is - useful when a large set of items may be used, but the viability of a subsequent operation depends only on a - subset. - :param return_individual_results: If True returns a `dict` giving the availability of each item_code requested - (otherwise gives a `bool` indicating if all the item_codes requested are available). - :param to_log: If True, logs the request. - :returns A `bool` indicating whether every item is available, or a `dict` indicating the availability of each - item. - Note that disease module can use the `get_item_codes_from_package_name` and `get_item_code_from_item_name` - methods in the `HealthSystem` module to find item_codes. - """ - - def _return_item_codes_in_dict(item_codes: Union[None, np.integer, int, list, set, dict]) -> dict: - """Convert an argument for 'item_codes` (provided as int, list, set or dict) into the format - dict(:quantity).""" - - if item_codes is None: - return {} - - if isinstance(item_codes, (int, np.integer)): - return {int(item_codes): 1} - - elif isinstance(item_codes, list): - if not all([isinstance(i, (int, np.integer)) for i in item_codes]): - raise ValueError("item_codes must be integers") - return {int(i): 1 for i in item_codes} - - elif isinstance(item_codes, dict): - if not all( - [(isinstance(code, (int, np.integer)) and - isinstance(quantity, (float, np.floating, int, np.integer))) - for code, quantity in item_codes.items()] - ): - raise ValueError("item_codes must be integers and quantities must be integers or floats.") - return {int(i): float(q) for i, q in item_codes.items()} - - else: - raise ValueError("The item_codes are given in an unrecognised format") - - hs_module = self.sim.modules['HealthSystem'] - - _item_codes = _return_item_codes_in_dict(item_codes) - _optional_item_codes = _return_item_codes_in_dict(optional_item_codes) - - # Determine if the request should be logged (over-ride argument provided if HealthSystem is disabled). - _to_log = to_log if not hs_module.disable else False - - # Checking the availability and logging: - rtn = hs_module.consumables._request_consumables(item_codes={**_item_codes, **_optional_item_codes}, - to_log=_to_log, - facility_info=self.facility_info, - treatment_id=self.TREATMENT_ID) - - # Return result in expected format: - if not return_individual_results: - # Determine if all results for all the `item_codes` are True (discarding results from optional_item_codes). - return all(v for k, v in rtn.items() if k in _item_codes) - else: - return rtn - - def make_beddays_footprint(self, dict_of_beddays): - """Helper function to make a correctly-formed 'bed-days footprint'""" - - # get blank footprint - footprint = self.sim.modules['HealthSystem'].bed_days.get_blank_beddays_footprint() - - # do checks on the dict_of_beddays provided. - assert isinstance(dict_of_beddays, dict) - assert all((k in footprint.keys()) for k in dict_of_beddays.keys()) - assert all(isinstance(v, (float, int)) for v in dict_of_beddays.values()) - - # make footprint (defaulting to zero where a type of bed-days is not specified) - for k, v in dict_of_beddays.items(): - footprint[k] = v - - return footprint - - def is_all_beddays_allocated(self): - """Check if the entire footprint requested is allocated""" - return all( - self.bed_days_allocated_to_this_event[k] == self.BEDDAYS_FOOTPRINT[k] for k in self.BEDDAYS_FOOTPRINT - ) - - def make_appt_footprint(self, dict_of_appts): - """Helper function to make appointment footprint in format expected downstream. - - Should be passed a dictionary keyed by appointment type codes with non-negative - values. - """ - health_system = self.sim.modules['HealthSystem'] - if health_system.appt_footprint_is_valid(dict_of_appts): - return Counter(dict_of_appts) - - raise ValueError( - "Argument to make_appt_footprint should be a dictionary keyed by " - "appointment type code strings in Appt_Types_Table with non-negative " - "values" - ) - - def initialise(self): - """Initialise the HSI: - * Set the facility_info - * Compute appt-footprint time requirements - """ - health_system = self.sim.modules['HealthSystem'] - - # Over-write ACCEPTED_FACILITY_LEVEL to to redirect all '1b' appointments to '2' - self.ACCEPTED_FACILITY_LEVEL = adjust_facility_level_to_merge_1b_and_2(self.ACCEPTED_FACILITY_LEVEL) - - if not isinstance(self.target, tlo.population.Population): - self.facility_info = health_system.get_facility_info(self) - - # If there are bed-days specified, add (if needed) the in-patient admission and in-patient day Appointment - # Types. - # (HSI that require a bed for one or more days always need such appointments, but this may have been - # missed in the declaration of the `EXPECTED_APPT_FOOTPRINT` in the HSI.) - # NB. The in-patient day Appointment time is automatically applied on subsequent days. - if sum(self.BEDDAYS_FOOTPRINT.values()): - self.EXPECTED_APPT_FOOTPRINT = health_system.bed_days.add_first_day_inpatient_appts_to_footprint( - self.EXPECTED_APPT_FOOTPRINT) - - # Write the time requirements for staff of the appointments to the HSI: - self.expected_time_requests = health_system.get_appt_footprint_as_time_request( - facility_info=self.facility_info, - appt_footprint=self.EXPECTED_APPT_FOOTPRINT, - ) - - # Do checks - _ = self._check_if_appt_footprint_can_run() - - def _check_if_appt_footprint_can_run(self): - """Check that event (if individual level) is able to run with this configuration of officers (i.e. check that - this does not demand officers that are _never_ available), and issue warning if not.""" - health_system = self.sim.modules['HealthSystem'] - if not isinstance(self.target, tlo.population.Population): - if health_system._officers_with_availability.issuperset(self.expected_time_requests.keys()): - return True - else: - logger.warning( - key="message", - data=(f"The expected footprint of {self.TREATMENT_ID} is not possible with the configuration of " - f"officers.") - ) - return False - - def as_namedtuple( - self, actual_appt_footprint: Optional[dict] = None - ) -> HSIEventDetails: - appt_footprint = ( - getattr(self, 'EXPECTED_APPT_FOOTPRINT', {}) - if actual_appt_footprint is None else actual_appt_footprint - ) - return HSIEventDetails( - event_name=type(self).__name__, - module_name=type(self.module).__name__, - treatment_id=self.TREATMENT_ID, - facility_level=getattr(self, 'ACCEPTED_FACILITY_LEVEL', None), - appt_footprint=tuple(sorted(appt_footprint.items())), - beddays_footprint=tuple( - sorted((k, v) for k, v in self.BEDDAYS_FOOTPRINT.items() if v > 0) - ) - ) - - -class HSIEventWrapper(Event): - """This is wrapper that contains an HSI event. - - It is used: - 1) When the healthsystem is in mode 'disabled=True' such that HSI events sent to the health system scheduler are - passed to the main simulation scheduler for running on the date of `topen`. (Note, it is run with - squeeze_factor=0.0.) - 2) When the healthsytsem is in mode `diable_and_reject_all=True` such that HSI are not run but the `never_ran` - method is run on the date of `tclose`. - 3) When an HSI has been submitted to `schedule_hsi_event` but the service is not available. - """ - - def __init__(self, hsi_event, run_hsi=True, *args, **kwargs): - super().__init__(hsi_event.module, *args, **kwargs) - self.hsi_event = hsi_event - self.target = hsi_event.target - self.run_hsi = run_hsi # True to call the HSI's `run` method; False to call the HSI's `never_ran` method - - def run(self): - """Do the appropriate action on the HSI event""" - - # Check that the person is still alive (this check normally happens in the HealthSystemScheduler and silently - # do not run the HSI event) - - if isinstance(self.hsi_event.target, tlo.population.Population) or ( - self.hsi_event.module.sim.population.props.at[self.hsi_event.target, 'is_alive'] - ): - - if self.run_hsi: - # Run the event (with 0 squeeze_factor) and ignore the output - _ = self.hsi_event.run(squeeze_factor=0.0) - else: - self.hsi_event.module.sim.modules["HealthSystem"].call_and_record_never_ran_hsi_event( - hsi_event=self.hsi_event, - priority=-1 - ) - - def _accepts_argument(function: callable, argument: str) -> bool: """Helper to test if callable object accepts an argument with a given name. @@ -507,6 +177,9 @@ class HealthSystem(Module): # Consumables 'item_and_package_code_lookups': Parameter( Types.DATA_FRAME, 'Data imported from the OneHealth Tool on consumable items, packages and costs.'), + 'consumables_item_designations': Parameter( + Types.DATA_FRAME, 'Look-up table for the designations of consumables (whether diagnostic, medicine, or ' + 'other'), 'availability_estimates': Parameter( Types.DATA_FRAME, 'Estimated availability of consumables in the LMIS dataset.'), 'cons_availability': Parameter( @@ -514,7 +187,8 @@ class HealthSystem(Module): "Availability of consumables. If 'default' then use the availability specified in the ResourceFile; if " "'none', then let no consumable be ever be available; if 'all', then all consumables are always available." " When using 'all' or 'none', requests for consumables are not logged. NB. This parameter is over-ridden" - "if an argument is provided to the module initialiser."), + "if an argument is provided to the module initialiser." + "Note that other options are also available: see the `Consumables` class."), # Infrastructure and Equipment 'BedCapacity': Parameter( @@ -524,6 +198,27 @@ class HealthSystem(Module): "Availability of beds. If 'default' then use the availability specified in the ResourceFile; if " "'none', then let no beds be ever be available; if 'all', then all beds are always available. NB. This " "parameter is over-ridden if an argument is provided to the module initialiser."), + 'EquipmentCatalogue': Parameter( + Types.DATA_FRAME, "Data on equipment items and packages."), + 'equipment_availability_estimates': Parameter( + Types.DATA_FRAME, "Data on the availability of equipment items and packages." + ), + 'equip_availability': Parameter( + Types.STRING, + "What to assume about the availability of equipment. If 'default' then use the availability specified in " + "the ResourceFile; if 'none', then let no equipment ever be available; if 'all', then all equipment is " + "always available. NB. This parameter is over-ridden if an argument is provided to the module initialiser." + ), + 'equip_availability_postSwitch': Parameter( + Types.STRING, + "What to assume about the availability of equipment after the switch (see `year_equip_availability_switch`" + "). The options for this are the same as `equip_availability`." + ), + 'year_equip_availability_switch': Parameter( + Types.INT, + "Year in which the assumption for `equip_availability` changes (The change happens on 1st January of that " + "year.)" + ), # Service Availability 'Service_Availability': Parameter( @@ -533,35 +228,83 @@ class HealthSystem(Module): 'policy_name': Parameter( Types.STRING, "Name of priority policy adopted"), 'year_mode_switch': Parameter( - Types.INT, "Year in which mode switch in enforced"), - + Types.INT, "Year in which mode switch is enforced"), + 'scale_to_effective_capabilities': Parameter( + Types.BOOL, "In year in which mode switch takes place, will rescale available capabilities to match those" + "that were effectively used (on average) in the past year if this is set to True. This way," + "we can approximate overtime and rushing of appts even in mode 2."), + 'year_cons_availability_switch': Parameter( + Types.INT, "Year in which consumable availability switch is enforced. The change happens" + "on 1st January of that year.)"), + 'year_use_funded_or_actual_staffing_switch': Parameter( + Types.INT, "Year in which switch for `use_funded_or_actual_staffing` is enforced. (The change happens" + "on 1st January of that year.)"), 'priority_rank': Parameter( Types.DICT, "Data on the priority ranking of each of the Treatment_IDs to be adopted by " " the queueing system under different policies, where the lower the number the higher" " the priority, and on which categories of individuals classify for fast-tracking " " for specific treatments"), - 'const_HR_scaling_table': Parameter( - Types.DICT, "Factors by which capabilities of medical officer categories at different levels will be" - "scaled at the start of the simulation to simulate a number of effects (e.g. absenteeism," - "boosting of specific medical cadres, etc). This is the imported from an" - "Excel workbook: keys are the worksheet names and values are the worksheets in " - "the format of pd.DataFrames."), - - 'const_HR_scaling_mode': Parameter( - Types.STRING, "Mode of HR scaling considered at the start of the simulation. Options are default" - " (capabilities are scaled by a constaint factor of 1), data (factors informed by survey data)," - "and custom (user can freely set these factors as parameters in the analysis).", + 'HR_scaling_by_level_and_officer_type_table': Parameter( + Types.DICT, "Factors by which capabilities of medical officer types at different levels will be" + "scaled at the start of the year specified by `year_HR_scaling_by_level_and_officer_type`. This" + "serves to simulate a number of effects (e.g. absenteeism, boosting capabilities of specific " + "medical cadres, etc). This is the imported from an Excel workbook: keys are the worksheet " + "names and values are the worksheets in the format of pd.DataFrames. Additional scenarios can " + "be added by adding worksheets to this workbook: the value of " + "`HR_scaling_by_level_and_officer_type_mode` indicates which sheet is used." + ), + + 'year_HR_scaling_by_level_and_officer_type': Parameter( + Types.INT, "Year in which one-off constant HR scaling will take place. (The change happens" + "on 1st January of that year.)" + ), + + 'HR_scaling_by_level_and_officer_type_mode': Parameter( + Types.STRING, "Mode of HR scaling considered at the start of the simulation. This corresponds to the name" + "of the worksheet in `ResourceFile_HR_scaling_by_level_and_officer_type.xlsx` that should be" + " used. Options are: `default` (capabilities are scaled by a constaint factor of 1); `data` " + "(factors informed by survey data); and, `custom` (user can freely set these factors as " + "parameters in the analysis).", ), - 'dynamic_HR_scaling_factor': Parameter( - Types.REAL, "Factor by which HR capabilities are scaled at regular intervals of 1 year (in addition to the" - " [optional] scaling with population size (controlled by `scale_HR_by_popsize`" + 'HR_scaling_by_district_table': Parameter( + Types.DICT, "Factors by which daily capabilities in different districts will be" + "scaled at the start of the year specified by year_HR_scaling_by_district to simulate" + "(e.g., through catastrophic event disrupting delivery of services in particular district(s))." + "This is the import of an Excel workbook: keys are the worksheet names and values are the " + "worksheets in the format of pd.DataFrames. Additional scenarios can be added by adding " + "worksheets to this workbook: the value of `HR_scaling_by_district_mode` indicates which" + "sheet is used." ), - 'scale_HR_by_popsize': Parameter( - Types.BOOL, "Decide whether to scale HR capabilities by population size every year. Can be used as well as" - " the dynamic_HR_scaling_factor" + 'year_HR_scaling_by_district': Parameter( + Types.INT, "Year in which scaling of daily capabilities by district will take place. (The change happens" + "on 1st January of that year.)"), + + 'HR_scaling_by_district_mode': Parameter( + Types.STRING, "Mode of scaling of daily capabilities by district. This corresponds to the name of the " + "worksheet in the file `ResourceFile_HR_scaling_by_district.xlsx`." + ), + + 'yearly_HR_scaling': Parameter( + Types.DICT, "Factors by which HR capabilities are scaled. " + "Each sheet specifies a 'mode' for dynamic HR scaling. The mode to use is determined by the " + "parameter `yearly_HR_scaling_mode`. Each sheet must have the same format, including the same " + "column headers. On each sheet, the first row (for `2010`, when the simulation starts) " + "specifies the initial configuration: `dynamic_HR_scaling_factor` (float) is the factor by " + "which all human resoucres capabilities and multiplied; `scale_HR_by_popsize` (bool) specifies " + "whether the capabilities should (also) grow by the factor by which the population has grown in" + " the last year. Each subsequent row specifies a year where there should be a CHANGE in the " + "configuration. If there are no further rows, then there is no change. But, for example, an" + " additional row of the form ```2015, 1.05, TRUE``` would mean that on 1st January of 2015, " + "2016, 2017, ....(and the rest of the simulation), the capabilities would increase by the " + "product of 1.05 and by the ratio of the population size to that in the year previous." + ), + + 'yearly_HR_scaling_mode': Parameter( + Types.STRING, "Specifies which of the policies in yearly_HR_scaling should be adopted. This corresponds to" + "a worksheet of the file `ResourceFile_dynamic_HR_scaling.xlsx`." ), 'tclose_overwrite': Parameter( @@ -580,7 +323,13 @@ class HealthSystem(Module): ' to the module initialiser.', ), 'mode_appt_constraints_postSwitch': Parameter( - Types.INT, 'Mode considered after a mode switch in year_mode_switch.') + Types.INT, 'Mode considered after a mode switch in year_mode_switch.'), + 'cons_availability_postSwitch': Parameter( + Types.STRING, 'Consumables availability after switch in `year_cons_availability_switch`. Acceptable values' + 'are the same as those for Parameter `cons_availability`.'), + 'use_funded_or_actual_staffing_postSwitch': Parameter( + Types.STRING, 'Staffing availability after switch in `year_use_funded_or_actual_staffing_switch`. ' + 'Acceptable values are the same as those for Parameter `use_funded_or_actual_staffing`.'), } PROPERTIES = { @@ -597,6 +346,7 @@ def __init__( mode_appt_constraints: Optional[int] = None, cons_availability: Optional[str] = None, beds_availability: Optional[str] = None, + equip_availability: Optional[str] = None, randomise_queue: bool = True, ignore_priority: bool = False, policy_name: Optional[str] = None, @@ -621,6 +371,8 @@ def __init__( or 'none', requests for consumables are not logged. :param beds_availability: If 'default' then use the availability specified in the ResourceFile; if 'none', then let no beds be ever be available; if 'all', then all beds are always available. + :param equip_availability: If 'default' then use the availability specified in the ResourceFile; if 'none', then + let no equipment ever be available; if 'all', then all equipment is always available. :param randomise_queue ensure that the queue is not model-dependent, i.e. properly randomised for equal topen and priority :param ignore_priority: If ``True`` do not use the priority information in HSI @@ -701,10 +453,9 @@ def __init__( assert isinstance(capabilities_coefficient, float) self.capabilities_coefficient = capabilities_coefficient - # Find which set of assumptions to use - those for the actual staff available or the funded staff available - if use_funded_or_actual_staffing is not None: - assert use_funded_or_actual_staffing in ['actual', 'funded', 'funded_plus'] + # Save argument for assumptions to use for 'use_funded_or_actual_staffing` self.arg_use_funded_or_actual_staffing = use_funded_or_actual_staffing + self._use_funded_or_actual_staffing = None # <-- this is the private internal store of the value that is used. # Define (empty) list of registered disease modules (filled in at `initialise_simulation`) self.recognised_modules_names = [] @@ -713,13 +464,16 @@ def __init__( self.HSI_EVENT_QUEUE = [] self.hsi_event_queue_counter = 0 # Counter to help with the sorting in the heapq - # Store the argument provided for cons_availability + # Store the arguments provided for cons/beds/equip_availability assert cons_availability in (None, 'default', 'all', 'none') self.arg_cons_availability = cons_availability assert beds_availability in (None, 'default', 'all', 'none') self.arg_beds_availability = beds_availability + assert equip_availability in (None, 'default', 'all', 'none') + self.arg_equip_availability = equip_availability + # `compute_squeeze_factor_to_district_level` is a Boolean indicating whether the computation of squeeze_factors # should be specific to each district (when `True`), or if the computation of squeeze_factors should be on the # basis that resources from all districts can be effectively "pooled" (when `False). @@ -804,6 +558,10 @@ def read_parameters(self, data_folder): # Read in ResourceFile_Consumables self.parameters['item_and_package_code_lookups'] = pd.read_csv( path_to_resourcefiles_for_healthsystem / 'consumables' / 'ResourceFile_Consumables_Items_and_Packages.csv') + self.parameters['consumables_item_designations'] = pd.read_csv( + path_to_resourcefiles_for_healthsystem / "consumables" / "ResourceFile_Consumables_Item_Designations.csv", + dtype={'Item_Code': int, 'is_diagnostic': bool, 'is_medicine': bool, 'is_other': bool} + ).set_index('Item_Code') self.parameters['availability_estimates'] = pd.read_csv( path_to_resourcefiles_for_healthsystem / 'consumables' / 'ResourceFile_Consumables_availability_small.csv') @@ -811,32 +569,72 @@ def read_parameters(self, data_folder): self.parameters['BedCapacity'] = pd.read_csv( path_to_resourcefiles_for_healthsystem / 'infrastructure_and_equipment' / 'ResourceFile_Bed_Capacity.csv') + # Read in ResourceFile_Equipment + self.parameters['EquipmentCatalogue'] = pd.read_csv( + path_to_resourcefiles_for_healthsystem + / 'infrastructure_and_equipment' + / 'ResourceFile_EquipmentCatalogue.csv') + self.parameters['equipment_availability_estimates'] = pd.read_csv( + path_to_resourcefiles_for_healthsystem + / 'infrastructure_and_equipment' + / 'ResourceFile_Equipment_Availability_Estimates.csv') + # Data on the priority of each Treatment_ID that should be adopted in the queueing system according to different # priority policies. Load all policies at this stage, and decide later which one to adopt. self.parameters['priority_rank'] = pd.read_excel(path_to_resourcefiles_for_healthsystem / 'priority_policies' / 'ResourceFile_PriorityRanking_ALLPOLICIES.xlsx', sheet_name=None) - self.parameters['const_HR_scaling_table']: Dict = pd.read_excel( + self.parameters['HR_scaling_by_level_and_officer_type_table']: Dict = pd.read_excel( path_to_resourcefiles_for_healthsystem / "human_resources" / - "const_HR_scaling" / - "ResourceFile_const_HR_scaling.xlsx", + "scaling_capabilities" / + "ResourceFile_HR_scaling_by_level_and_officer_type.xlsx", sheet_name=None # all sheets read in ) + # Ensure the mode of HR scaling to be considered in included in the tables loaded + assert (self.parameters['HR_scaling_by_level_and_officer_type_mode'] in + self.parameters['HR_scaling_by_level_and_officer_type_table']), \ + (f"Value of `HR_scaling_by_level_and_officer_type_mode` not recognised: " + f"{self.parameters['HR_scaling_by_level_and_officer_type_mode']}") + self.parameters['HR_scaling_by_district_table']: Dict = pd.read_excel( + path_to_resourcefiles_for_healthsystem / + "human_resources" / + "scaling_capabilities" / + "ResourceFile_HR_scaling_by_district.xlsx", + sheet_name=None # all sheets read in + ) + # Ensure the mode of HR scaling by district to be considered in included in the tables loaded + assert self.parameters['HR_scaling_by_district_mode'] in self.parameters['HR_scaling_by_district_table'], \ + f"Value of `HR_scaling_by_district_mode` not recognised: {self.parameters['HR_scaling_by_district_mode']}" + + self.parameters['yearly_HR_scaling']: Dict = pd.read_excel( + path_to_resourcefiles_for_healthsystem / + "human_resources" / + "scaling_capabilities" / + "ResourceFile_dynamic_HR_scaling.xlsx", + sheet_name=None, # all sheets read in + dtype={ + 'year': int, + 'dynamic_HR_scaling_factor': float, + 'scale_HR_by_popsize': bool + } # Ensure that these column are read as the right type + ) + # Ensure the mode of yearly HR scaling to be considered in included in the tables loaded + assert self.parameters['yearly_HR_scaling_mode'] in self.parameters['yearly_HR_scaling'], \ + f"Value of `yearly_HR_scaling` not recognised: {self.parameters['yearly_HR_scaling_mode']}" + # Ensure that a value for the year at the start of the simulation is provided. + assert all(2010 in sheet['year'].values for sheet in self.parameters['yearly_HR_scaling'].values()) def pre_initialise_population(self): """Generate the accessory classes used by the HealthSystem and pass to them the data that has been read.""" - # Ensure the mode of HR scaling to be considered in included in the tables loaded - assert self.parameters['const_HR_scaling_mode'] in self.parameters['const_HR_scaling_table'], \ - f"Value of `const_HR_scaling_mode` not recognised: {self.parameters['const_HR_scaling_mode']}" - # Create dedicated RNGs for separate functions done by the HealthSystem module self.rng_for_hsi_queue = np.random.RandomState(self.rng.randint(2 ** 31 - 1)) self.rng_for_dx = np.random.RandomState(self.rng.randint(2 ** 31 - 1)) rng_for_consumables = np.random.RandomState(self.rng.randint(2 ** 31 - 1)) + rng_for_equipment = np.random.RandomState(self.rng.randint(2 ** 31 - 1)) # Determine mode_appt_constraints self.mode_appt_constraints = self.get_mode_appt_constraints() @@ -844,9 +642,15 @@ def pre_initialise_population(self): # Determine service_availability self.service_availability = self.get_service_availability() - self.process_human_resources_files( - use_funded_or_actual_staffing=self.get_use_funded_or_actual_staffing() - ) + # Process health system organisation files (Facilities, Appointment Types, Time Taken etc.) + self.process_healthsystem_organisation_files() + + # Set value for `use_funded_or_actual_staffing` and process Human Resources Files + # (Initially set value should be equal to what is specified by the parameter, but overwritten with what was + # provided in argument if an argument was specified -- provided for backward compatibility/debugging.) + self.use_funded_or_actual_staffing = self.parameters['use_funded_or_actual_staffing'] \ + if self.arg_use_funded_or_actual_staffing is None \ + else self.arg_use_funded_or_actual_staffing # Initialise the BedDays class self.bed_days = BedDays(hs_module=self, @@ -855,12 +659,22 @@ def pre_initialise_population(self): # Initialise the Consumables class self.consumables = Consumables( - data=self.update_consumables_availability_to_represent_merging_of_levels_1b_and_2( + availability_data=self.update_consumables_availability_to_represent_merging_of_levels_1b_and_2( self.parameters['availability_estimates']), + item_code_designations=self.parameters['consumables_item_designations'], rng=rng_for_consumables, availability=self.get_cons_availability() ) + # Determine equip_availability + self.equipment = Equipment( + catalogue=self.parameters['EquipmentCatalogue'], + data_availability=self.parameters['equipment_availability_estimates'], + rng=rng_for_equipment, + master_facilities_list=self.parameters['Master_Facilities_List'], + availability=self.get_equip_availability(), + ) + self.tclose_overwrite = self.parameters['tclose_overwrite'] self.tclose_days_offset_overwrite = self.parameters['tclose_days_offset_overwrite'] @@ -871,7 +685,6 @@ def pre_initialise_population(self): # Set up framework for considering a priority policy self.setup_priority_policy() - def initialise_population(self, population): self.bed_days.initialise_population(population.props) @@ -914,10 +727,53 @@ def initialise_simulation(self, sim): sim.schedule_event(HealthSystemChangeMode(self), Date(self.parameters["year_mode_switch"], 1, 1)) - # Schedule recurring event which will rescale daily capabilities at regular intervals. - # The first event scheduled will only be used to update self.last_year_pop_size parameter, - # actual scaling will only take effect from 2011 onwards - sim.schedule_event(DynamicRescalingHRCapabilities(self), Date(sim.date) + pd.DateOffset(years=1)) + # Schedule a consumables availability switch + sim.schedule_event( + HealthSystemChangeParameters( + self, + parameters={ + 'cons_availability': self.parameters['cons_availability_postSwitch'] + } + ), + Date(self.parameters["year_cons_availability_switch"], 1, 1) + ) + + # Schedule an equipment availability switch + sim.schedule_event( + HealthSystemChangeParameters( + self, + parameters={ + 'equip_availability': self.parameters['equip_availability_postSwitch'] + } + ), + Date(self.parameters["year_equip_availability_switch"], 1, 1) + ) + + # Schedule an equipment availability switch + sim.schedule_event( + HealthSystemChangeParameters( + self, + parameters={ + 'use_funded_or_actual_staffing': self.parameters['use_funded_or_actual_staffing_postSwitch'] + } + ), + Date(self.parameters["year_use_funded_or_actual_staffing_switch"], 1, 1) + ) + + # Schedule a one-off rescaling of _daily_capabilities broken down by officer type and level. + # This occurs on 1st January of the year specified in the parameters. + sim.schedule_event(ConstantRescalingHRCapabilities(self), + Date(self.parameters["year_HR_scaling_by_level_and_officer_type"], 1, 1)) + + # Schedule a one-off rescaling of _daily_capabilities broken down by district + # This occurs on 1st January of the year specified in the parameters. + sim.schedule_event(RescaleHRCapabilities_ByDistrict(self), + Date(self.parameters["year_HR_scaling_by_district"], 1, 1)) + + # Schedule recurring event which will rescale daily capabilities (at yearly intervals). + # The first event scheduled for the start of the simulation is only used to update self.last_year_pop_size, + # whilst the actual scaling will only take effect from 2011 onwards. + sim.schedule_event(DynamicRescalingHRCapabilities(self), Date(sim.date)) def on_birth(self, mother_id, child_id): self.bed_days.on_birth(self.sim.population.props, mother_id, child_id) @@ -926,6 +782,8 @@ def on_simulation_end(self): """Put out to the log the information from the tracker of the last day of the simulation""" self.bed_days.on_simulation_end() self.consumables.on_simulation_end() + self.equipment.on_simulation_end() + if self._hsi_event_count_log_period == "simulation": self._write_hsi_event_counts_to_log_and_reset() self._write_never_ran_hsi_event_counts_to_log_and_reset() @@ -972,10 +830,15 @@ def setup_priority_policy(self): if 'Tb' in self.sim.modules: self.list_fasttrack.append(('tb_diagnosed', 'FT_if_tbdiagnosed')) - def process_human_resources_files(self, use_funded_or_actual_staffing: str): - """Create the data-structures needed from the information read into the parameters.""" - - + def process_healthsystem_organisation_files(self): + """Create the data-structures needed from the information read into the parameters: + * self._facility_levels + * self._appointment_types + * self._appt_times + * self._appt_type_by_facLevel + * self._facility_by_facility_id + * self._facilities_for_each_district + """ # * Define Facility Levels self._facility_levels = set(self.parameters['Master_Facilities_List']['Facility_Level']) - {'5'} @@ -1068,6 +931,10 @@ def process_human_resources_files(self, use_funded_or_actual_staffing: str): self._facility_by_facility_id = facilities_by_facility_id self._facilities_for_each_district = facilities_per_level_and_district + def setup_daily_capabilities(self, use_funded_or_actual_staffing): + """Set up `self._daily_capabilities` and `self._officers_with_availability`. + This is called when the value for `use_funded_or_actual_staffing` is set - at the beginning of the simulation + and when the assumption when the underlying assumption for `use_funded_or_actual_staffing` is updated""" # * Store 'DailyCapabilities' in correct format and using the specified underlying assumptions self._daily_capabilities = self.format_daily_capabilities(use_funded_or_actual_staffing) @@ -1076,28 +943,6 @@ def process_human_resources_files(self, use_funded_or_actual_staffing: str): # never available.) self._officers_with_availability = set(self._daily_capabilities.index[self._daily_capabilities > 0]) - def adjust_for_const_HR_scaling(self, df: pd.DataFrame) -> pd.DataFrame: - """Adjust the Daily_Capabilities pd.DataFrame to account for assumptions about scaling of HR resources""" - - # Get the set of scaling_factors that are specified by the 'const_HR_scaling_mode' assumption - const_HR_scaling_factor = self.parameters['const_HR_scaling_table'][self.parameters['const_HR_scaling_mode']] - const_HR_scaling_factor = const_HR_scaling_factor.set_index('Officer_Category') - - level_conversion = {"1a": "L1a_Av_Mins_Per_Day", "1b": "L1b_Av_Mins_Per_Day", - "2": "L2_Av_Mins_Per_Day", "0": "L0_Av_Mins_Per_Day", "3": "L3_Av_Mins_Per_Day", - "4": "L4_Av_Mins_Per_Day", "5": "L5_Av_Mins_Per_Day"} - - scaler = df[['Officer_Category', 'Facility_Level']].apply( - lambda row: const_HR_scaling_factor.loc[row['Officer_Category'], level_conversion[row['Facility_Level']]], - axis=1 - ) - - # Apply scaling to 'Total_Mins_Per_Day' - df['Total_Mins_Per_Day'] *= scaler - - return df - - def format_daily_capabilities(self, use_funded_or_actual_staffing: str) -> pd.Series: """ This will updates the dataframe for the self.parameters['Daily_Capabilities'] so as to include @@ -1111,9 +956,7 @@ def format_daily_capabilities(self, use_funded_or_actual_staffing: str) -> pd.Se # Get the capabilities data imported (according to the specified underlying assumptions). capabilities = pool_capabilities_at_levels_1b_and_2( - self.adjust_for_const_HR_scaling( self.parameters[f'Daily_Capabilities_{use_funded_or_actual_staffing}'] - ) ) capabilities = capabilities.rename(columns={'Officer_Category': 'Officer_Type_Code'}) # neaten @@ -1167,6 +1010,27 @@ def format_daily_capabilities(self, use_funded_or_actual_staffing: str) -> pd.Se # return the pd.Series of `Total_Minutes_Per_Day' indexed for each type of officer at each facility return capabilities_ex['Total_Minutes_Per_Day'] + def _rescale_capabilities_to_capture_effective_capability(self): + # Notice that capabilities will only be expanded through this process + # (i.e. won't reduce available capabilities if these were under-used in the last year). + # Note: Currently relying on module variable rather than parameter for + # scale_to_effective_capabilities, in order to facilitate testing. However + # this may eventually come into conflict with the Switcher functions. + pattern = r"FacilityID_(\w+)_Officer_(\w+)" + for officer in self._daily_capabilities.keys(): + matches = re.match(pattern, officer) + # Extract ID and officer type from + facility_id = int(matches.group(1)) + officer_type = matches.group(2) + level = self._facility_by_facility_id[facility_id].level + # Only rescale if rescaling factor is greater than 1 (i.e. don't reduce + # available capabilities if these were under-used the previous year). + rescaling_factor = self._summary_counter.frac_time_used_by_officer_type_and_level( + officer_type=officer_type, level=level + ) + if rescaling_factor > 1 and rescaling_factor != float("inf"): + self._daily_capabilities[officer] *= rescaling_factor + def update_consumables_availability_to_represent_merging_of_levels_1b_and_2(self, df_original): """To represent that facility levels '1b' and '2' are merged together under the label '2', we replace the availability of consumables at level 2 with new values.""" @@ -1281,6 +1145,24 @@ def get_beds_availability(self) -> str: return _beds_availability + def get_equip_availability(self) -> str: + """Returns equipment availability. (Should be equal to what is specified by the parameter, but can be + overwritten with what was provided in argument if an argument was specified -- provided for backward + compatibility/debugging.)""" + + if self.arg_equip_availability is None: + _equip_availability = self.parameters['equip_availability'] + else: + _equip_availability = self.arg_equip_availability + + # Log the equip_availability + logger.info(key="message", + data=f"Running Health System With the Following Equipment Availability: " + f"{_equip_availability}" + ) + + return _equip_availability + def schedule_to_call_never_ran_on_date(self, hsi_event: 'HSI_Event', tdate: datetime.datetime): """Function to schedule never_ran being called on a given date""" self.sim.schedule_event(HSIEventWrapper(hsi_event=hsi_event, run_hsi=False), tdate) @@ -1292,13 +1174,17 @@ def get_mode_appt_constraints(self) -> int: if self.arg_mode_appt_constraints is None \ else self.arg_mode_appt_constraints - def get_use_funded_or_actual_staffing(self) -> str: - """Returns `use_funded_or_actual_staffing`. (Should be equal to what is specified by the parameter, but - overwrite with what was provided in argument if an argument was specified -- provided for backward - compatibility/debugging.)""" - return self.parameters['use_funded_or_actual_staffing'] \ - if self.arg_use_funded_or_actual_staffing is None \ - else self.arg_use_funded_or_actual_staffing + @property + def use_funded_or_actual_staffing(self) -> str: + """Returns value for `use_funded_or_actual_staffing`.""" + return self._use_funded_or_actual_staffing + + @use_funded_or_actual_staffing.setter + def use_funded_or_actual_staffing(self, use_funded_or_actual_staffing) -> str: + """Set value for `use_funded_or_actual_staffing` and update the daily_capabilities accordingly. """ + assert use_funded_or_actual_staffing in ['actual', 'funded', 'funded_plus'] + self._use_funded_or_actual_staffing = use_funded_or_actual_staffing + self.setup_daily_capabilities(self._use_funded_or_actual_staffing) def get_priority_policy_initial(self) -> str: """Returns `priority_policy`. (Should be equal to what is specified by the parameter, but @@ -1822,6 +1708,7 @@ def write_to_hsi_log( priority: int, ): """Write the log `HSI_Event` and add to the summary counter.""" + # Debug logger gives simple line-list for every HSI event logger.debug( key="HSI_Event", data={ @@ -1834,15 +1721,19 @@ def write_to_hsi_log( 'did_run': did_run, 'Facility_Level': event_details.facility_level if event_details.facility_level is not None else -99, 'Facility_ID': facility_id if facility_id is not None else -99, + 'Equipment': sorted(event_details.equipment), }, description="record of each HSI event" ) if did_run: if self._hsi_event_count_log_period is not None: + # Do logging for HSI Event using counts of each 'unique type' of HSI event (as defined by + # `HSIEventDetails`). event_details_key = self._hsi_event_details.setdefault( event_details, len(self._hsi_event_details) ) self._hsi_event_counts_log_period[event_details_key] += 1 + # Do logging for 'summary logger' self._summary_counter.record_hsi_event( treatment_id=event_details.treatment_id, hsi_event_name=event_details.event_name, @@ -1912,7 +1803,7 @@ def write_to_never_ran_hsi_log( def log_current_capabilities_and_usage(self): """ This will log the percentage of the current capabilities that is used at each Facility Type, according the - `runnning_total_footprint`. + `runnning_total_footprint`. This runs every day. """ current_capabilities = self.capabilities_today total_footprint = self.running_total_footprint @@ -1958,7 +1849,9 @@ def log_current_capabilities_and_usage(self): description='daily summary of utilisation and capacity of health system resources') self._summary_counter.record_hs_status( - fraction_time_used_across_all_facilities=fraction_time_used_overall) + fraction_time_used_across_all_facilities=fraction_time_used_overall, + fraction_time_used_by_officer_type_and_level=summary_by_officer["Fraction_Time_Used"].to_dict() + ) def remove_beddays_footprint(self, person_id): # removing bed_days from a particular individual if any @@ -1998,6 +1891,8 @@ def get_item_code_from_item_name(self, item: str) -> int: def override_availability_of_consumables(self, item_codes) -> None: """Over-ride the availability (for all months and all facilities) of certain consumables item_codes. + Note that these changes will *not* persist following a change of the overall modulator of consumables + availability, `Consumables.availability`. :param item_codes: Dictionary of the form {: probability_that_item_is_available} :return: None """ @@ -2044,6 +1939,14 @@ def on_end_of_month(self) -> None: def on_end_of_year(self) -> None: """Write to log the current states of the summary counters and reset them.""" + # If we are at the end of the year preceeding the mode switch, and if wanted + # to rescale capabilities to capture effective availability as was recorded, on + # average, in the past year, do so here. + if ( + (self.sim.date.year == self.parameters['year_mode_switch'] - 1) + and self.parameters['scale_to_effective_capabilities'] + ): + self._rescale_capabilities_to_capture_effective_capability() self._summary_counter.write_to_log_and_reset_counters() self.consumables.on_end_of_year() self.bed_days.on_end_of_year() @@ -2360,9 +2263,19 @@ def process_events_mode_0_and_1(self, hold_over: List[HSIEventQueueItem]) -> Non # Run the list of population-level HSI events self.module.run_population_level_events(list_of_population_hsi_event_tuples_due_today) - # Run the list of individual-level events + # For each individual level event, check whether the equipment it has already declared is available. If it + # is not, then call the HSI's never_run function, and do not take it forward for running; if it is then + # add it to the list of events to run. + list_of_individual_hsi_event_tuples_due_today_that_have_essential_equipment = list() + for item in list_of_individual_hsi_event_tuples_due_today: + if not item.hsi_event.is_all_declared_equipment_available: + self.module.call_and_record_never_ran_hsi_event(hsi_event=item.hsi_event, priority=item.priority) + else: + list_of_individual_hsi_event_tuples_due_today_that_have_essential_equipment.append(item) + + # Try to run the list of individual-level events that have their essential equipment _to_be_held_over = self.module.run_individual_level_events_in_mode_0_or_1( - list_of_individual_hsi_event_tuples_due_today, + list_of_individual_hsi_event_tuples_due_today_that_have_essential_equipment, ) hold_over.extend(_to_be_held_over) @@ -2498,6 +2411,15 @@ def process_events_mode_2(self, hold_over: List[HSIEventQueueItem]) -> None: assert event.facility_info is not None, \ f"Cannot run HSI {event.TREATMENT_ID} without facility_info being defined." + # Check if equipment declared is available. If not, call `never_ran` and do not run the + # event. (`continue` returns flow to beginning of the `while` loop) + if not event.is_all_declared_equipment_available: + self.module.call_and_record_never_ran_hsi_event( + hsi_event=event, + priority=next_event_tuple.priority + ) + continue + # Expected appt footprint before running event _appt_footprint_before_running = event.EXPECTED_APPT_FOOTPRINT # Run event & get actual footprint @@ -2539,8 +2461,7 @@ def process_events_mode_2(self, hold_over: List[HSIEventQueueItem]) -> None: ) # Update today's footprint based on actual call and squeeze factor - self.module.running_total_footprint -= original_call - self.module.running_total_footprint += updated_call + self.module.running_total_footprint.update(updated_call) # Write to the log self.module.record_hsi_event( @@ -2664,7 +2585,8 @@ def apply(self, population): treatment_id='Inpatient_Care', facility_level=self.module._facility_by_facility_id[_fac_id].level, appt_footprint=tuple(sorted(_inpatient_appts.items())), - beddays_footprint=() + beddays_footprint=(), + equipment=tuple(), # Equipment is normally a set, but this has to be hashable. ), person_id=-1, facility_id=_fac_id, @@ -2732,6 +2654,7 @@ def _reset_internal_stores(self) -> None: self._never_ran_appts_by_level = {_level: defaultdict(int) for _level in ('0', '1a', '1b', '2', '3', '4')} self._frac_time_used_overall = [] # Running record of the usage of the healthcare system + self._sum_of_daily_frac_time_used_by_officer_type_and_level = Counter() self._squeeze_factor_by_hsi_event_name = defaultdict(list) # Running record the squeeze-factor applying to each # treatment_id. Key is of the form: # ":" @@ -2774,14 +2697,19 @@ def record_never_ran_hsi_event(self, self._never_ran_appts[appt_type] += number self._never_ran_appts_by_level[level][appt_type] += number - def record_hs_status(self, fraction_time_used_across_all_facilities: float) -> None: + def record_hs_status( + self, + fraction_time_used_across_all_facilities: float, + fraction_time_used_by_officer_type_and_level: Dict[Tuple[str, int], float], + ) -> None: """Record a current status metric of the HealthSystem.""" - # The fraction of all healthcare worker time that is used: self._frac_time_used_overall.append(fraction_time_used_across_all_facilities) + for officer_type_facility_level, fraction_time in fraction_time_used_by_officer_type_and_level.items(): + self._sum_of_daily_frac_time_used_by_officer_type_and_level[officer_type_facility_level] += fraction_time def write_to_log_and_reset_counters(self): - """Log summary statistics reset the data structures.""" + """Log summary statistics reset the data structures. This usually occurs at the end of the year.""" logger_summary.info( key="HSI_Event", @@ -2820,8 +2748,47 @@ def write_to_log_and_reset_counters(self): }, ) + # Log mean of 'fraction time used by officer type and facility level' from daily entries from the previous + # year. + logger_summary.info( + key="Capacity_By_OfficerType_And_FacilityLevel", + description="The fraction of healthcare worker time that is used each day, averaged over this " + "calendar year, for each officer type at each facility level.", + data=flatten_multi_index_series_into_dict_for_logging( + self.frac_time_used_by_officer_type_and_level()), + ) + self._reset_internal_stores() + def frac_time_used_by_officer_type_and_level( + self, + officer_type: Optional[str]=None, + level: Optional[str]=None, + ) -> Union[float, pd.Series]: + """Average fraction of time used by officer type and level since last reset. + If `officer_type` and/or `level` is not provided (left to default to `None`) then a pd.Series with a multi-index + is returned giving the result for all officer_types/levels.""" + + if (officer_type is not None) and (level is not None): + return ( + self._sum_of_daily_frac_time_used_by_officer_type_and_level[officer_type, level] + / len(self._frac_time_used_overall) + # Use len(self._frac_time_used_overall) as proxy for number of days in past year. + ) + else: + # Return multiple in the form of a pd.Series with multiindex + mean_frac_time_used = { + (_officer_type, _level): v / len(self._frac_time_used_overall) + for (_officer_type, _level), v in self._sum_of_daily_frac_time_used_by_officer_type_and_level.items() + if (_officer_type == officer_type or officer_type is None) and (_level == level or level is None) + } + return pd.Series( + index=pd.MultiIndex.from_tuples( + mean_frac_time_used.keys(), + names=['OfficerType', 'FacilityLevel'] + ), + data=mean_frac_time_used.values() + ).sort_index() class HealthSystemChangeParameters(Event, PopulationScopeEventMixin): """Event that causes certain internal parameters of the HealthSystem to be changed; specifically: @@ -2830,6 +2797,8 @@ class HealthSystemChangeParameters(Event, PopulationScopeEventMixin): * `capabilities_coefficient` * `cons_availability` * `beds_availability` + * `equip_availability` + * `use_funded_or_actual_staffing` Note that no checking is done here on the suitability of values of each parameter.""" def __init__(self, module: HealthSystem, parameters: Dict): @@ -2848,21 +2817,32 @@ def apply(self, population): self.module.capabilities_coefficient = self._parameters['capabilities_coefficient'] if 'cons_availability' in self._parameters: - self.module.consumables = Consumables(data=self.module.parameters['availability_estimates'], - rng=self.module.rng, - availability=self._parameters['cons_availability']) - self.module.consumables.on_start_of_day(self.module.sim.date) + self.module.consumables.availability = self._parameters['cons_availability'] if 'beds_availability' in self._parameters: - self.module.bed_days.availability = self._parameters['beds_availability'] + self.module.bed_days.switch_beddays_availability( + new_availability=self._parameters["beds_availability"], + effective_on_and_from=self.sim.date, + model_to_data_popsize_ratio=self.sim.modules["Demography"].initial_model_to_data_popsize_ratio + ) + if 'equip_availability' in self._parameters: + self.module.equipment.availability = self._parameters['equip_availability'] + + if 'use_funded_or_actual_staffing' in self._parameters: + self.module.use_funded_or_actual_staffing = self._parameters['use_funded_or_actual_staffing'] class DynamicRescalingHRCapabilities(RegularEvent, PopulationScopeEventMixin): """ This event exists to scale the daily capabilities assumed at fixed time intervals""" def __init__(self, module): super().__init__(module, frequency=DateOffset(years=1)) - self.last_year_pop_size = self.current_pop_size # store population size at initiation (when this class is - # created) + self.last_year_pop_size = self.current_pop_size # will store population size at initiation (when this class is + # created, at the start of the simulation) + + # Store the sequence of updates as a dict of the form + # {: {`dynamic_HR_scaling_factor`: float, `scale_HR_by_popsize`: bool}} + self.scaling_values = self.module.parameters['yearly_HR_scaling'][ + self.module.parameters['yearly_HR_scaling_mode']].set_index("year").to_dict("index") @property def current_pop_size(self) -> float: @@ -2870,18 +2850,79 @@ def current_pop_size(self) -> float: df = self.sim.population.props return df.is_alive.sum() - def apply(self, population): + def _get_most_recent_year_specified_for_a_change_in_configuration(self) -> int: + """Get the most recent year (in the past), for which there is an entry in `parameters['yearly_HR_scaling']`.""" + years = np.array(list(self.scaling_values.keys())) + return years[years <= self.sim.date.year].max() + def apply(self, population): + """Do the scaling on the capabilities based on instruction that is in force at this time.""" + # Get current population size this_year_pop_size = self.current_pop_size - # Rescale by fixed amount - self.module._daily_capabilities *= self.module.parameters['dynamic_HR_scaling_factor'] + # Get the configuration to apply now (the latest entry in the `parameters['yearly_HR_scaling']`) + config = self.scaling_values.get(self._get_most_recent_year_specified_for_a_change_in_configuration()) + + # ... Do the rescaling specified for this year by the specified factor + self.module._daily_capabilities *= config['dynamic_HR_scaling_factor'] + + # ... If requested, also do the scaling for the population growth that has occurred since the last year + if config['scale_HR_by_popsize']: + self.module._daily_capabilities *= this_year_pop_size / self.last_year_pop_size + + # Save current population size as that for 'last year'. + self.last_year_pop_size = this_year_pop_size + + +class ConstantRescalingHRCapabilities(Event, PopulationScopeEventMixin): + """ This event exists to scale the daily capabilities, with a factor for each Officer Type at each Facility_Level. + """ + def __init__(self, module): + super().__init__(module) + + def apply(self, population): + + # Get the set of scaling_factors that are specified by the 'HR_scaling_by_level_and_officer_type_mode' + # assumption + HR_scaling_by_level_and_officer_type_factor = ( + self.module.parameters['HR_scaling_by_level_and_officer_type_table'][ + self.module.parameters['HR_scaling_by_level_and_officer_type_mode'] + ].set_index('Officer_Category') + ) + + pattern = r"FacilityID_(\w+)_Officer_(\w+)" + + for officer in self.module._daily_capabilities.keys(): + matches = re.match(pattern, officer) + # Extract ID and officer type from + facility_id = int(matches.group(1)) + officer_type = matches.group(2) + level = self.module._facility_by_facility_id[facility_id].level + self.module._daily_capabilities[officer] *= \ + HR_scaling_by_level_and_officer_type_factor.at[officer_type, f"L{level}_factor"] + + +class RescaleHRCapabilities_ByDistrict(Event, PopulationScopeEventMixin): + """ This event exists to scale the daily capabilities, with a factor for each district.""" + def __init__(self, module): + super().__init__(module) + + def apply(self, population): + + # Get the set of scaling_factors that are specified by 'HR_scaling_by_level_and_officer_type_mode' + HR_scaling_factor_by_district = self.module.parameters['HR_scaling_by_district_table'][ + self.module.parameters['HR_scaling_by_district_mode'] + ].set_index('District').to_dict() - # Rescale daily capabilities by population size, if this option is included - if self.module.parameters['scale_HR_by_popsize']: - self.module._daily_capabilities *= this_year_pop_size/self.last_year_pop_size + pattern = r"FacilityID_(\w+)_Officer_(\w+)" - self.last_year_pop_size = this_year_pop_size # Save for next year + for officer in self.module._daily_capabilities.keys(): + matches = re.match(pattern, officer) + # Extract ID and officer type from + facility_id = int(matches.group(1)) + district = self.module._facility_by_facility_id[facility_id].district + if district in HR_scaling_factor_by_district: + self.module._daily_capabilities[officer] *= HR_scaling_factor_by_district[district] class HealthSystemChangeMode(RegularEvent, PopulationScopeEventMixin): diff --git a/src/tlo/methods/hiv.py b/src/tlo/methods/hiv.py index 6a1e7f0245..1ddafe4c47 100644 --- a/src/tlo/methods/hiv.py +++ b/src/tlo/methods/hiv.py @@ -9,7 +9,7 @@ - with viral suppression: when the person with not develop AIDS, or if they have already, it is relieved and they will not die of AIDS; and the person is not infectious - without viral suppression: when there is no benefit in avoiding AIDS and infectiousness is unchanged. -Maintenance on ART and PrEP is re-assessed at periodic 'Decision Events', at which is it is determined if the person +Maintenance on ART and PrEP is re-assessed at periodic 'Decision Events', at which it is determined if the person will attend the "next" HSI for continuation of the service; and if not, they are removed from that service and "stop treatment". If a stock-out or non-availability of health system resources prevent treatment continuation, the person "stops treatment". Stopping treatment leads to a new AIDS Event being scheduled. Persons can restart treatment. If a @@ -23,27 +23,33 @@ * Cotrimoxazole is not included - either in effect of consumption of the drug (because the effect is not known). * Calibration has not been done: most things look OK - except HIV-AIDS deaths """ +from __future__ import annotations import os +from typing import TYPE_CHECKING, List import numpy as np import pandas as pd -from tlo import DAYS_IN_YEAR, DateOffset, Module, Parameter, Property, Types, logging +from tlo import DAYS_IN_YEAR, Date, DateOffset, Module, Parameter, Property, Types, logging from tlo.events import Event, IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.lm import LinearModel, LinearModelType, Predictor from tlo.methods import Metadata, demography, tb from tlo.methods.causes import Cause from tlo.methods.dxmanager import DxTest -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom from tlo.util import create_age_range_lookup +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -class Hiv(Module): +class Hiv(Module, GenericFirstAppointmentsMixin): """ The HIV Disease Module """ @@ -187,6 +193,9 @@ def __init__(self, name=None, resourcefilepath=None, run_with_checks=False): "rr_edlevel_higher": Parameter( Types.REAL, "Relative risk of HIV with higher education" ), + "rr_schisto": Parameter( + Types.REAL, "Relative risk of HIV with high intensity S. haematobium infection" + ), # Natural history - transmission - relative risk of HIV acquisition (interventions) "rr_behaviour_change": Parameter( Types.REAL, "Relative risk of HIV with behaviour modification" @@ -375,10 +384,32 @@ def __init__(self, name=None, resourcefilepath=None, run_with_checks=False): Types.REAL, "probability of death if aids and tb, person on treatment for tb", ), + "hiv_healthseekingbehaviour_cap": Parameter( + Types.INT, + "number of repeat visits assumed for healthcare services", + ), "dispensation_period_months": Parameter( Types.REAL, "length of prescription for ARVs in months, same for all PLHIV", ), + "length_of_inpatient_stay_if_terminal": Parameter( + Types.LIST, + "length in days of inpatient stay for end-of-life HIV patients: list has two elements [low-bound-inclusive," + " 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" + ), + "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, + "the parameters and values changed in scenario analysis" + ), } def read_parameters(self, data_folder): @@ -389,7 +420,7 @@ def read_parameters(self, data_folder): # 1) Read the ResourceFiles - # Short cut to parameters dict + # Shortcut to parameters dict p = self.parameters workbook = pd.read_excel( @@ -416,6 +447,9 @@ def read_parameters(self, data_folder): # Load spectrum estimates of treatment cascade 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() + # DALY weights # get the DALY weight that this module will use from the weight database (these codes are just random!) if "HealthBurden" in self.sim.modules.keys(): @@ -447,7 +481,7 @@ def pre_initialise_population(self): # ---- LINEAR MODELS ----- # LinearModel for the relative risk of becoming infected during the simulation # N.B. age assumed not to have an effect on incidence - self.lm["rr_of_infection"] = LinearModel.multiplicative( + predictors = [ Predictor("age_years").when("<15", 0.0).when("<49", 1.0).otherwise(0.0), Predictor("sex").when("F", p["rr_sex_f"]), Predictor("li_is_circ").when(True, p["rr_circumcision"]), @@ -462,17 +496,32 @@ def pre_initialise_population(self): Predictor("li_ed_lev", conditions_are_mutually_exclusive=True) .when(2, p["rr_edlevel_primary"]) .when(3, p["rr_edlevel_secondary"]), - Predictor("hv_behaviour_change").when(True, p["rr_behaviour_change"]), - ) + Predictor("hv_behaviour_change").when(True, p["rr_behaviour_change"]) + ] + + conditional_predictors = [ + Predictor().when( + '(ss_sh_infection_status == "High-infection") &' + '(sex == "F")', + p["rr_schisto"] + ), + ] if "Schisto" in self.sim.modules else [] + + self.lm["rr_of_infection"] = LinearModel.multiplicative( + *(predictors + conditional_predictors)) # LinearModels to give the shape and scale for the Weibull distribution describing time from infection to death self.lm["scale_parameter_for_infection_to_death"] = LinearModel.multiplicative( Predictor( "age_years", conditions_are_mutually_exclusive=True, - conditions_are_exhaustive=True) + conditions_are_exhaustive=True, + ) .when("==0", p["mean_survival_for_infants_infected_prior_to_birth"]) - .when(".between(1,4)", p["infection_to_death_infant_infection_after_birth_weibull_scale"]) + .when( + ".between(1,4)", + p["infection_to_death_infant_infection_after_birth_weibull_scale"], + ) .when(".between(5, 19)", p["infection_to_death_weibull_scale_1519"]) .when(".between(20, 24)", p["infection_to_death_weibull_scale_2024"]) .when(".between(25, 29)", p["infection_to_death_weibull_scale_2529"]) @@ -501,13 +550,16 @@ def pre_initialise_population(self): ) # -- Linear Model to give the mean months between aids and death depending on age - self.lm["offset_parameter_for_months_from_aids_to_death"] = LinearModel.multiplicative( - Predictor( - "age_years", - conditions_are_mutually_exclusive=True, - conditions_are_exhaustive=True) - .when("<5", p["mean_months_between_aids_and_death_infant"]) - .when(">=5", p["mean_months_between_aids_and_death"]) + self.lm["offset_parameter_for_months_from_aids_to_death"] = ( + LinearModel.multiplicative( + Predictor( + "age_years", + conditions_are_mutually_exclusive=True, + conditions_are_exhaustive=True, + ) + .when("<5", p["mean_months_between_aids_and_death_infant"]) + .when(">=5", p["mean_months_between_aids_and_death"]) + ) ) # -- Linear Models for the Uptake of Services @@ -565,7 +617,6 @@ def initialise_population(self, population): # --- Current status df.loc[df.is_alive, "hv_inf"] = False df.loc[df.is_alive, "hv_art"] = "not" - df.loc[df.is_alive, "hv_date_treated"] = pd.NaT df.loc[df.is_alive, "hv_is_on_prep"] = False df.loc[df.is_alive, "hv_behaviour_change"] = False df.loc[df.is_alive, "hv_diagnosed"] = False @@ -574,6 +625,8 @@ def initialise_population(self, population): # --- Dates on which things have happened df.loc[df.is_alive, "hv_date_inf"] = pd.NaT df.loc[df.is_alive, "hv_last_test_date"] = pd.NaT + df.loc[df.is_alive, "hv_date_treated"] = pd.NaT + df.loc[df.is_alive, "hv_date_last_ART"] = pd.NaT # Launch sub-routines for allocating the right number of people into each category self.initialise_baseline_prevalence(population) # allocate baseline prevalence @@ -606,16 +659,14 @@ def initialise_baseline_prevalence(self, population): Predictor("li_is_sexworker").when(True, params["rr_fsw"]), Predictor("li_is_circ").when(True, params["rr_circumcision"]), Predictor("li_urban").when(False, params["rr_rural"]), - Predictor( - "li_wealth", conditions_are_mutually_exclusive=True).when( - 2, params["rr_windex_poorer"]).when( - 3, params["rr_windex_middle"]).when( - 4, params["rr_windex_richer"]).when( - 5, params["rr_windex_richest"]), - Predictor( - "li_ed_lev", conditions_are_mutually_exclusive=True).when( - 2, params["rr_edlevel_primary"]).when( - 3, params["rr_edlevel_secondary"]) + Predictor("li_wealth", conditions_are_mutually_exclusive=True) + .when(2, params["rr_windex_poorer"]) + .when(3, params["rr_windex_middle"]) + .when(4, params["rr_windex_richer"]) + .when(5, params["rr_windex_richest"]), + Predictor("li_ed_lev", conditions_are_mutually_exclusive=True) + .when(2, params["rr_edlevel_primary"]) + .when(3, params["rr_edlevel_secondary"]), ).predict(df.loc[df.is_alive]) # Rescale relative probability of infection so that its average is 1.0 within each age/sex group @@ -756,6 +807,11 @@ def split_into_vl_and_notvl(all_idx, prob): # this window is 1-90 days (3-monthly prescribing) for person in art_idx: days = self.rng.randint(low=1, high=self.parameters['dispensation_period_months'] * 30.5, dtype=np.int64) + + date_treated = (params['dispensation_period_months'] * 30.5) - days + df.at[person, "hv_date_treated"] = self.sim.date - pd.to_timedelta(date_treated, unit="days") + df.at[person, "hv_date_last_ART"] = self.sim.date - pd.to_timedelta(date_treated, unit="days") + self.sim.schedule_event( Hiv_DecisionToContinueTreatment(person_id=person, module=self), self.sim.date + pd.to_timedelta(days, unit="days"), @@ -844,6 +900,7 @@ def initialise_simulation(self, sim): * 7) Look-up and save the codes for consumables """ df = sim.population.props + p = self.parameters # 1) Schedule the Main HIV Regular Polling Event sim.schedule_event( @@ -853,10 +910,16 @@ def initialise_simulation(self, sim): # 2) Schedule the Logging Event sim.schedule_event(HivLoggingEvent(self), sim.date + DateOffset(years=1)) + # Optional: Schedule the scale-up of programs + if self.parameters["do_scaleup"]: + 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) + # 3) Determine who has AIDS and impose the Symptoms 'aids_symptoms' # Those on ART currently (will not get any further events scheduled): - on_art_idx = df.loc[df.is_alive & df.hv_inf & (df.hv_art != "not")].index + on_art_idx = df.loc[df.is_alive & df.hv_inf & (df.hv_art == "on_VL_suppressed")].index # Those that lived more than ten years and not currently on ART are assumed to currently have AIDS # (will have AIDS Death event scheduled) @@ -864,7 +927,7 @@ def initialise_simulation(self, sim): df.is_alive & df.hv_inf & ((self.sim.date - df.hv_date_inf).dt.days > 10 * 365) - & (df.hv_art == "not") + & (df.hv_art != "on_VL_suppressed") ].index # Those that are in neither category are "before AIDS" (will have AIDS Onset Event scheduled) @@ -918,7 +981,8 @@ def initialise_simulation(self, sim): ) date_aids_death = ( - self.sim.date + pd.DateOffset(months=self.rng.randint(low=0, high=18)) + self.sim.date + pd.DateOffset( + months=self.rng.randint(low=0, high=p['mean_months_between_aids_and_death'])) ) # 30% AIDS deaths have TB co-infection @@ -929,6 +993,23 @@ def initialise_simulation(self, sim): date=date_aids_death, ) + # schedule hospital stay for end of life care if untreated + beddays = self.rng.randint( + low=p['length_of_inpatient_stay_if_terminal'][0], + high=p['length_of_inpatient_stay_if_terminal'][1]) + date_admission = date_aids_death - pd.DateOffset(days=beddays) + self.sim.modules["HealthSystem"].schedule_hsi_event( + hsi_event=HSI_Hiv_EndOfLifeCare( + person_id=person_id, module=self, beddays=beddays + ), + priority=0, + topen=( + date_admission + if (date_admission >= self.sim.date) + else self.sim.date + ), + ) + # 5) (Optionally) Schedule the event to check the configuration of all properties if self.run_with_checks: sim.schedule_event( @@ -958,31 +1039,37 @@ def initialise_simulation(self, sim): self.item_codes_for_consumables_required['circ'] = \ hs.get_item_codes_from_package_name("Male circumcision ") - self.item_codes_for_consumables_required['prep'] = { - hs.get_item_code_from_item_name("Tenofovir (TDF)/Emtricitabine (FTC), tablet, 300/200 mg"): 1} + # adult prep: 1 tablet daily + self.item_codes_for_consumables_required['prep'] = \ + hs.get_item_code_from_item_name("Tenofovir (TDF)/Emtricitabine (FTC), tablet, 300/200 mg") - # infant NVP given in 3-monthly dosages - self.item_codes_for_consumables_required['infant_prep'] = { - hs.get_item_code_from_item_name("Nevirapine, oral solution, 10 mg/ml"): 1} + # infant NVP 1.5mg daily for birth weight 2500g or above, for 6 weeks + self.item_codes_for_consumables_required['infant_prep'] = \ + hs.get_item_code_from_item_name("Nevirapine, oral solution, 10 mg/ml") # First - line ART for adults(age > "ART_age_cutoff_older_child") - self.item_codes_for_consumables_required['First-line ART regimen: adult'] = { - hs.get_item_code_from_item_name("First-line ART regimen: adult"): 1} - self.item_codes_for_consumables_required['First-line ART regimen: adult: cotrimoxazole'] = { - hs.get_item_code_from_item_name("Cotrimoxizole, 960mg pppy"): 1} + # TDF/3TC/DTG 120/60/50mg, 1 tablet per day + # cotrim adult tablet, 1 tablet per day, units specified in mg * dispensation days + self.item_codes_for_consumables_required['First-line ART regimen: adult'] = \ + hs.get_item_code_from_item_name("First-line ART regimen: adult") + self.item_codes_for_consumables_required['First-line ART regimen: adult: cotrimoxazole'] = \ + hs.get_item_code_from_item_name("Cotrimoxizole, 960mg pppy") # ART for older children aged ("ART_age_cutoff_younger_child" < age <= "ART_age_cutoff_older_child"): - # cotrim is separate item - optional in get_cons call - self.item_codes_for_consumables_required['First line ART regimen: older child'] = { - hs.get_item_code_from_item_name("First line ART regimen: older child"): 1} - self.item_codes_for_consumables_required['First line ART regimen: older child: cotrimoxazole'] = { - hs.get_item_code_from_item_name("Sulfamethoxazole + trimethropin, tablet 400 mg + 80 mg"): 1} + # ABC/3TC/DTG 120/60/50mg, 3 tablets per day + # cotrim paediatric tablet, 4 tablets per day, units specified in mg * dispensation days + self.item_codes_for_consumables_required['First line ART regimen: older child'] = \ + hs.get_item_code_from_item_name("First line ART regimen: older child") + self.item_codes_for_consumables_required['First line ART regimen: older child: cotrimoxazole'] = \ + hs.get_item_code_from_item_name("Cotrimoxazole 120mg_1000_CMST") # ART for younger children aged (age < "ART_age_cutoff_younger_child"): - self.item_codes_for_consumables_required['First line ART regimen: young child'] = { - hs.get_item_code_from_item_name("First line ART regimen: young child"): 1} - self.item_codes_for_consumables_required['First line ART regimen: young child: cotrimoxazole'] = { - hs.get_item_code_from_item_name("Sulfamethoxazole + trimethropin, oral suspension, 240 mg, 100 ml"): 1} + # ABC/3TC/DTG 120/60/10mg, 2 tablets per day + # cotrim paediatric tablet, 2 tablets per day, units specified in mg * dispensation days + self.item_codes_for_consumables_required['First line ART regimen: young child'] = \ + hs.get_item_code_from_item_name("First line ART regimen: young child") + self.item_codes_for_consumables_required['First line ART regimen: young child: cotrimoxazole'] = \ + hs.get_item_code_from_item_name("Cotrimoxazole 120mg_1000_CMST") # 7) Define the DxTests # HIV Rapid Diagnostic Test: @@ -1011,6 +1098,44 @@ def initialise_simulation(self, sim): ) ) + def update_parameters_for_program_scaleup(self): + + p = self.parameters + scaled_params = p["scaleup_parameters"] + + if p["do_scaleup"]: + + # scale-up HIV program + # reduce risk of HIV - applies to whole adult population + p["beta"] = p["beta"] * scaled_params["reduction_in_hiv_beta"] + + # increase PrEP coverage for FSW after HIV test + p["prob_prep_for_fsw_after_hiv_test"] = scaled_params["prob_prep_for_fsw_after_hiv_test"] + + # prep poll for AGYW - target to the highest risk + # increase retention to 75% for FSW and AGYW + p["prob_prep_for_agyw"] = scaled_params["prob_prep_for_agyw"] + p["probability_of_being_retained_on_prep_every_3_months"] = scaled_params["probability_of_being_retained_on_prep_every_3_months"] + + # increase probability of VMMC after hiv test + p["prob_circ_after_hiv_test"] = scaled_params["prob_circ_after_hiv_test"] + + # increase testing/diagnosis rates, default 2020 0.03/0.25 -> 93% dx + p["hiv_testing_rates"]["annual_testing_rate_children"] = scaled_params["annual_testing_rate_children"] + p["hiv_testing_rates"]["annual_testing_rate_adults"] = scaled_params["annual_testing_rate_adults"] + + # ANC testing - value for mothers and infants testing + p["prob_hiv_test_at_anc_or_delivery"] = scaled_params["prob_hiv_test_at_anc_or_delivery"] + p["prob_hiv_test_for_newborn_infant"] = scaled_params["prob_hiv_test_for_newborn_infant"] + + # prob ART start if dx, this is already 95% at 2020 + p["prob_start_art_after_hiv_test"] = scaled_params["prob_start_art_after_hiv_test"] + + # viral suppression rates + # adults already at 95% by 2020 + # change all column values + p["prob_start_art_or_vs"]["virally_suppressed_on_art"] = scaled_params["virally_suppressed_on_art"] + def on_birth(self, mother_id, child_id): """ * Initialise our properties for a newborn individual; @@ -1025,7 +1150,6 @@ def on_birth(self, mother_id, child_id): df.at[child_id, "hv_inf"] = False df.at[child_id, "hv_art"] = "not" df.at[child_id, "hv_on_cotrimoxazole"] = False - df.at[child_id, "hv_date_treated"] = pd.NaT df.at[child_id, "hv_is_on_prep"] = False df.at[child_id, "hv_behaviour_change"] = False df.at[child_id, "hv_diagnosed"] = False @@ -1034,6 +1158,8 @@ def on_birth(self, mother_id, child_id): # --- Dates on which things have happened df.at[child_id, "hv_date_inf"] = pd.NaT df.at[child_id, "hv_last_test_date"] = pd.NaT + df.at[child_id, "hv_date_treated"] = pd.NaT + df.at[child_id, "hv_date_last_ART"] = pd.NaT # ----------------------------------- MTCT - AT OR PRIOR TO BIRTH -------------------------- # DETERMINE IF THE CHILD IS INFECTED WITH HIV FROM THEIR MOTHER DURING PREGNANCY / DELIVERY @@ -1096,7 +1222,7 @@ def on_birth(self, mother_id, child_id): tclose=None, ) - # if mother known HIV+, schedule virological test for infant + # if mother known HIV+, schedule virological test for infant and give prep if mother.hv_diagnosed and df.at[child_id, "is_alive"]: self.sim.modules["HealthSystem"].schedule_hsi_event( hsi_event=HSI_Hiv_StartInfantProphylaxis( @@ -1264,10 +1390,10 @@ def get_time_from_aids_to_death(self): """ mean = self.parameters["mean_months_between_aids_and_death"] draw_number_of_months = int(np.round(self.rng.exponential(mean))) - return pd.DateOffset(months=draw_number_of_months) + return pd.DateOffset(months=(draw_number_of_months + 1)) def do_when_hiv_diagnosed(self, person_id): - """Things to do when a person has been tested and found (newly) be be HIV-positive:. + """Things to do when a person has been tested and found (newly) to be HIV-positive:. * Consider if ART should be initiated, and schedule HSI if so. The person should not yet be on ART. """ @@ -1335,7 +1461,8 @@ def prob_viral_suppression(self, year, age_of_person): def stops_treatment(self, person_id): """Helper function that is called when someone stops being on ART. - Sets the flag for ART status. If the person was already on ART, it schedules a new AIDSEvent""" + Sets the flag for ART status. If the person was already on ART, it schedules a new AIDSEvent + """ df = self.sim.population.props @@ -1427,11 +1554,13 @@ def decide_whether_hiv_test_for_infant(self, mother_id, child_id) -> None: mother_id = mother_id child_id = child_id - if not df.at[child_id, 'hv_diagnosed'] and \ - df.at[mother_id, 'hv_diagnosed'] and ( - df.at[child_id, 'nb_pnc_check'] == 1) and ( - self.rng.random_sample() < self.parameters['prob_hiv_test_for_newborn_infant']): - self.sim.modules['HealthSystem'].schedule_hsi_event( + if ( + not df.at[child_id, "hv_diagnosed"] + and df.at[mother_id, "hv_diagnosed"] + and (df.at[child_id, "nb_pnc_check"] == 1) + and (self.rng.random_sample() < self.parameters["prob_hiv_test_for_newborn_infant"]) + ): + self.sim.modules["HealthSystem"].schedule_hsi_event( HSI_Hiv_TestAndRefer( person_id=child_id, module=self, @@ -1501,6 +1630,25 @@ def is_subset(col_for_set, col_for_subset): ) ) + def do_at_generic_first_appt( + self, + person_id: int, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs, + ) -> None: + # 'Automatic' testing for HIV for everyone attending care with AIDS symptoms: + # - suppress the footprint (as it done as part of another appointment) + # - do not do referrals if the person is HIV negative (assumed not time for counselling etc). + if "aids_symptoms" in symptoms: + event = HSI_Hiv_TestAndRefer( + person_id=person_id, + module=self, + referred_from="hsi_generic_first_appt", + suppress_footprint=True, + do_not_refer_if_neg=True, + ) + schedule_hsi_event(event, priority=0, topen=self.sim.date) # --------------------------------------------------------------------------- # Main Polling Event @@ -1859,6 +2007,23 @@ def apply(self, person_id): ), date=date_of_aids_death, ) + # schedule hospital stay + beddays = self.sim.modules["Hiv"].rng.randint(low=14, high=20) + date_admission = date_of_aids_death - pd.DateOffset(days=beddays) + self.sim.modules["HealthSystem"].schedule_hsi_event( + hsi_event=HSI_Hiv_EndOfLifeCare( + person_id=person_id, + module=self.sim.modules["Hiv"], + beddays=beddays, + ), + priority=0, + topen=( + date_admission + if (date_admission > self.sim.date) + else self.sim.date + ), + tclose=date_of_aids_death, + ) else: # cause is active TB @@ -1868,6 +2033,23 @@ def apply(self, person_id): ), date=date_of_aids_death, ) + # schedule hospital stay + beddays = self.sim.modules["Hiv"].rng.randint(low=14, high=20) + date_admission = date_of_aids_death - pd.DateOffset(days=beddays) + self.sim.modules["HealthSystem"].schedule_hsi_event( + hsi_event=HSI_Hiv_EndOfLifeCare( + person_id=person_id, + module=self.sim.modules["Hiv"], + beddays=beddays, + ), + priority=0, + topen=( + date_admission + if (date_admission >= self.sim.date) + else self.sim.date + ), + tclose=date_of_aids_death, + ) class HivAidsDeathEvent(Event, IndividualScopeEventMixin): @@ -1934,16 +2116,22 @@ def __init__(self, module, person_id, cause): def apply(self, person_id): df = self.sim.population.props + p = self.sim.modules["Hiv"].parameters # Check person is_alive if not df.at[person_id, "is_alive"]: return if df.at[person_id, 'tb_on_treatment']: - prob = self.module.rng.rand() + + risk_of_death = p["aids_tb_treatment_adjustment"] + + if "CardioMetabolicDisorders" in self.sim.modules: + if df.at[person_id, "nc_diabetes"]: + risk_of_death *= self.sim.modules["Tb"].parameters["rr_death_diabetes"] # treatment adjustment reduces probability of death - if prob < self.sim.modules["Hiv"].parameters["aids_tb_treatment_adjustment"]: + if self.module.rng.rand() < risk_of_death: self.sim.modules["Demography"].do_death( individual_id=person_id, cause="AIDS_TB", @@ -1962,6 +2150,23 @@ def apply(self, person_id): ), date=date_of_aids_death, ) + # schedule hospital stay + beddays = self.module.rng.randint(low=14, high=20) + date_admission = date_of_aids_death - pd.DateOffset(days=beddays) + self.sim.modules["HealthSystem"].schedule_hsi_event( + hsi_event=HSI_Hiv_EndOfLifeCare( + person_id=person_id, + module=self.sim.modules["Hiv"], + beddays=beddays, + ), + priority=0, + topen=( + date_admission + if (date_admission >= self.sim.date) + else self.sim.date + ), + tclose=date_of_aids_death, + ) # aids-tb and not on tb treatment elif not df.at[person_id, 'tb_on_treatment']: @@ -2069,13 +2274,28 @@ def apply(self, person_id): ) +class HivScaleUpEvent(Event, PopulationScopeEventMixin): + """ This event exists to change parameters or functions + depending on the scenario for projections which has been set + It only occurs once on date: scaleup_start_date, + called by initialise_simulation + """ + + def __init__(self, module): + super().__init__(module) + + def apply(self, population): + self.module.update_parameters_for_program_scaleup() + + # --------------------------------------------------------------------------- # Health System Interactions (HSI) # --------------------------------------------------------------------------- + class HSI_Hiv_TestAndRefer(HSI_Event, IndividualScopeEventMixin): """ - The is the Test-and-Refer HSI. Individuals may seek an HIV test at any time. From this, they can be referred on to + This is the Test-and-Refer HSI. Individuals may seek an HIV test at any time. From this, they can be referred on to other services. This event is scheduled by: * the main event poll, @@ -2106,7 +2326,8 @@ def __init__( # Define the necessary information for an HSI self.TREATMENT_ID = "Hiv_Test" self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({"VCTNegative": 1}) - self.ACCEPTED_FACILITY_LEVEL = '1a' + self.ACCEPTED_FACILITY_LEVEL = "1a" + self.counter_for_test_not_available = 0 def apply(self, person_id, squeeze_factor): """Do the testing and referring to other services""" @@ -2221,13 +2442,21 @@ def apply(self, person_id, squeeze_factor): # Test was not possible, set blank footprint and schedule another test ACTUAL_APPT_FOOTPRINT = self.make_appt_footprint({"VCTNegative": 1}) - # repeat appt for HIV test - self.sim.modules["HealthSystem"].schedule_hsi_event( - HSI_Hiv_TestAndRefer(person_id=person_id, module=self.module, referred_from='HIV_test'), - topen=self.sim.date + pd.DateOffset(months=1), - tclose=None, - priority=0, - ) + # set cap for number of repeat tests + self.counter_for_test_not_available += 1 # The current appointment is included in the count. + + + if ( + self.counter_for_test_not_available + <= self.module.parameters["hiv_healthseekingbehaviour_cap"] + ): + # repeat appt for HIV test + self.sim.modules["HealthSystem"].schedule_hsi_event( + self, + topen=self.sim.date + pd.DateOffset(days=7), + tclose=None, + priority=0, + ) # Return the footprint. If it should be suppressed, return a blank footprint. if self.suppress_footprint: @@ -2242,7 +2471,7 @@ def __init__(self, module, person_id): self.TREATMENT_ID = "Hiv_Prevention_Circumcision" self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({"MaleCirc": 1}) - self.ACCEPTED_FACILITY_LEVEL = '1a' + self.ACCEPTED_FACILITY_LEVEL = '1b' self.number_of_occurrences = 0 def apply(self, person_id, squeeze_factor): @@ -2264,6 +2493,10 @@ def apply(self, person_id, squeeze_factor): # Update circumcision state df.at[person_id, "li_is_circ"] = True + # Add used equipment + self.add_equipment({'Drip stand', 'Stool, adjustable height', 'Autoclave', + 'Bipolar Diathermy Machine', 'Bed, adult', 'Trolley, patient'}) + # Schedule follow-up appts # schedule first follow-up appt, 3 days from procedure; self.sim.modules["HealthSystem"].schedule_hsi_event( @@ -2281,7 +2514,10 @@ def apply(self, person_id, squeeze_factor): ) else: # schedule repeating appt when consumables not available - if self.number_of_occurrences <= 3: + if ( + self.number_of_occurrences + <= self.module.parameters["hiv_healthseekingbehaviour_cap"] + ): self.sim.modules["HealthSystem"].schedule_hsi_event( self, topen=self.sim.date + DateOffset(weeks=1), @@ -2320,7 +2556,9 @@ def apply(self, person_id, squeeze_factor): return self.sim.modules["HealthSystem"].get_blank_appt_footprint() # Check that infant prophylaxis is available and if it is, initiate: - if self.get_consumables(item_codes=self.module.item_codes_for_consumables_required['infant_prep']): + if self.get_consumables( + item_codes={self.module.item_codes_for_consumables_required['infant_prep']: 63} + ): df.at[person_id, "hv_is_on_prep"] = True # Schedule follow-up visit for 3 months time @@ -2336,10 +2574,13 @@ def apply(self, person_id, squeeze_factor): ) else: - if self.repeat_visits <= 4: - # infant does not get NVP now but has repeat visit scheduled up to 5 times - df.at[person_id, "hv_is_on_prep"] = False + # infant does not get NVP now but has repeat visit scheduled up to 5 times + df.at[person_id, "hv_is_on_prep"] = False + if ( + self.repeat_visits + <= self.module.parameters["hiv_healthseekingbehaviour_cap"] + ): self.repeat_visits += 1 # Schedule repeat visit for one week's time @@ -2368,6 +2609,7 @@ def __init__(self, module, person_id): self.TREATMENT_ID = "Hiv_Prevention_Prep" self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({"PharmDispensing": 1, "VCTNegative": 1}) self.ACCEPTED_FACILITY_LEVEL = '1a' + self.counter_for_drugs_not_available = 0 def apply(self, person_id, squeeze_factor): """Start PrEP for this person; or continue them on PrEP for 3 more months""" @@ -2400,7 +2642,10 @@ def apply(self, person_id, squeeze_factor): return self.make_appt_footprint({"Over5OPD": 1, "VCTPositive": 1}) # Check that PrEP is available and if it is, initiate or continue PrEP: - if self.get_consumables(item_codes=self.module.item_codes_for_consumables_required['prep']): + quantity_required = self.module.parameters['dispensation_period_months'] * 30 + if self.get_consumables( + item_codes={self.module.item_codes_for_consumables_required['prep']: quantity_required} + ): df.at[person_id, "hv_is_on_prep"] = True # Schedule 'decision about whether to continue on PrEP' for 3 months time @@ -2413,6 +2658,22 @@ def apply(self, person_id, squeeze_factor): # If PrEP is not available, the person will default and not be on PrEP df.at[person_id, "hv_is_on_prep"] = False + self.counter_for_drugs_not_available += ( + 1 # The current appointment is included in the count. + ) + + if ( + self.counter_for_drugs_not_available + <= self.module.parameters["hiv_healthseekingbehaviour_cap"] + ): + # Schedule repeat visit for one week's time + self.sim.modules["HealthSystem"].schedule_hsi_event( + self, + priority=1, + topen=self.sim.date + pd.DateOffset(days=7), + tclose=None, + ) + def never_ran(self): """This is called if this HSI was never run. Default the person to being off PrEP""" @@ -2445,8 +2706,8 @@ def apply(self, person_id, squeeze_factor): # check whether person had Rx at least 3 months ago and is now due repeat prescription # alternate routes into testing/tx may mean person already has recent ARV dispensation - if person['hv_date_last_ART'] >= ( - self.sim.date - pd.DateOffset(months=self.module.parameters['dispensation_period_months'])): + if person['hv_date_last_ART'] > ( + self.sim.date - pd.DateOffset(months=self.module.parameters['dispensation_period_months'])): return self.sim.modules["HealthSystem"].get_blank_appt_footprint() if art_status_at_beginning_of_hsi == "not": @@ -2486,57 +2747,58 @@ def apply(self, person_id, squeeze_factor): } logger.info(key='hiv_arv_NA', data=person_details_for_tx) - # As drugs were not available, the person will default to being off ART (...if they were on ART at the - # beginning of the HSI.) - # NB. If the person was not on ART at the beginning of the HSI, then there is no need to stop them (which - # causes a new AIDSOnsetEvent to be scheduled.) - self.counter_for_drugs_not_available += 1 # The current appointment is included in the count. + # As drugs were not available, the person will default to being off ART (...if they were on ART at the + # beginning of the HSI.) + # NB. If the person was not on ART at the beginning of the HSI, then there is no need to stop them (which + # causes a new AIDSOnsetEvent to be scheduled.) + self.counter_for_drugs_not_available += 1 # The current appointment is included in the count. - if art_status_at_beginning_of_hsi != "not": - self.module.stops_treatment(person_id) + if art_status_at_beginning_of_hsi != "not": + self.module.stops_treatment(person_id) - p = self.module.parameters["probability_of_seeking_further_art_appointment_if_drug_not_available"] - - if self.module.rng.random_sample() >= p: + p = self.module.parameters[ + "probability_of_seeking_further_art_appointment_if_drug_not_available" + ] - # add in referral straight back to tx - # if defaulting, seek another treatment appointment in 6 months - self.sim.modules["HealthSystem"].schedule_hsi_event( - hsi_event=HSI_Hiv_StartOrContinueTreatment( - person_id=person_id, module=self.module, - facility_level_of_this_hsi="1a", - ), - topen=self.sim.date + pd.DateOffset(months=6), - priority=0, - ) + if self.module.rng.random_sample() >= p: - else: - # If person 'decides to' seek another treatment appointment, - # schedule a new HSI appointment for next month - # NB. With a probability of 1.0, this will keep occurring, - # if person has already tried unsuccessfully to get ART at level 1a 2 times - # then refer to level 1b - if self.counter_for_drugs_not_available <= 2: - # repeat attempt for ARVs at level 1a + # add in referral straight back to tx + # if defaulting, seek another treatment appointment in 6 months self.sim.modules["HealthSystem"].schedule_hsi_event( hsi_event=HSI_Hiv_StartOrContinueTreatment( - person_id=person_id, module=self.module, - facility_level_of_this_hsi="1a" + person_id=person_id, + module=self.module, + facility_level_of_this_hsi="1a", ), - topen=self.sim.date + pd.DateOffset(months=1), + topen=self.sim.date + pd.DateOffset(months=6), priority=0, ) else: - # refer to higher facility level - self.sim.modules["HealthSystem"].schedule_hsi_event( - hsi_event=HSI_Hiv_StartOrContinueTreatment( - person_id=person_id, module=self.module, - facility_level_of_this_hsi="2" - ), - topen=self.sim.date + pd.DateOffset(days=1), - priority=0, - ) + # If person 'decides to' seek another treatment appointment, + # schedule a new HSI appointment for next month + # NB. With a probability of 1.0, this will keep occurring, + # if person has already tried unsuccessfully to get ART at level 1a 2 times + # then refer to level 1b + if self.counter_for_drugs_not_available <= 2: + # repeat attempt for ARVs at level 1a + self.sim.modules["HealthSystem"].schedule_hsi_event( + self, + topen=self.sim.date + pd.DateOffset(months=1), + priority=0, + ) + + else: + # refer to higher facility level + self.sim.modules["HealthSystem"].schedule_hsi_event( + hsi_event=HSI_Hiv_StartOrContinueTreatment( + person_id=person_id, + module=self.module, + facility_level_of_this_hsi="2", + ), + topen=self.sim.date + pd.DateOffset(days=1), + priority=0, + ) # also screen for tb if "Tb" in self.sim.modules: @@ -2624,29 +2886,33 @@ def get_drugs(self, age_of_person): whether individual drugs were available""" p = self.module.parameters + dispensation_days = 30 * self.module.parameters['dispensation_period_months'] if age_of_person < p["ART_age_cutoff_young_child"]: # Formulation for young children drugs_available = self.get_consumables( - item_codes=self.module.item_codes_for_consumables_required['First line ART regimen: young child'], - optional_item_codes=self.module.item_codes_for_consumables_required[ - 'First line ART regimen: young child: cotrimoxazole'], + item_codes={self.module.item_codes_for_consumables_required[ + 'First line ART regimen: young child']: dispensation_days * 2}, + optional_item_codes={self.module.item_codes_for_consumables_required[ + 'First line ART regimen: young child: cotrimoxazole']: dispensation_days * 240}, return_individual_results=True) elif age_of_person <= p["ART_age_cutoff_older_child"]: # Formulation for older children drugs_available = self.get_consumables( - item_codes=self.module.item_codes_for_consumables_required['First line ART regimen: older child'], - optional_item_codes=self.module.item_codes_for_consumables_required[ - 'First line ART regimen: older child: cotrimoxazole'], + item_codes={self.module.item_codes_for_consumables_required[ + 'First line ART regimen: older child']: dispensation_days * 3}, + optional_item_codes={self.module.item_codes_for_consumables_required[ + 'First line ART regimen: older child: cotrimoxazole']: dispensation_days * 480}, return_individual_results=True) else: # Formulation for adults drugs_available = self.get_consumables( - item_codes=self.module.item_codes_for_consumables_required['First-line ART regimen: adult'], - optional_item_codes=self.module.item_codes_for_consumables_required[ - 'First-line ART regimen: adult: cotrimoxazole'], + item_codes={self.module.item_codes_for_consumables_required[ + 'First-line ART regimen: adult']: dispensation_days}, + optional_item_codes={self.module.item_codes_for_consumables_required[ + 'First-line ART regimen: adult: cotrimoxazole']: dispensation_days * 960}, return_individual_results=True) # add drug names to dict @@ -2712,6 +2978,42 @@ def EXPECTED_APPT_FOOTPRINT(self): return self.make_appt_footprint({"EstNonCom": 1}) # Adult already on treatment +class HSI_Hiv_EndOfLifeCare(HSI_Event, IndividualScopeEventMixin): + """ + this is a hospital stay for terminally-ill patients with AHD + it does not affect disability weight or probability of death + no consumables are logged but health system capacity (HR) is allocated + there are no consequences if hospital bed is not available as person has scheduled death + already within 2 weeks + """ + + def __init__(self, module, person_id, beddays=17): + super().__init__(module, person_id=person_id) + assert isinstance(module, Hiv) + + self.TREATMENT_ID = "Hiv_PalliativeCare" + self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({}) + self.ACCEPTED_FACILITY_LEVEL = "2" + + self.beddays = beddays + self.BEDDAYS_FOOTPRINT = self.make_beddays_footprint({"general_bed": self.beddays}) + + def apply(self, person_id, squeeze_factor): + df = self.sim.population.props + hs = self.sim.modules["HealthSystem"] + + if not df.at[person_id, "is_alive"]: + return hs.get_blank_appt_footprint() + + if df.at[person_id, "hv_art"] == "virally_suppressed": + return hs.get_blank_appt_footprint() + + logger.debug( + key="message", + data=f"HSI_Hiv_EndOfLifeCare: inpatient admission for {person_id}", + ) + + # --------------------------------------------------------------------------- # Logging # --------------------------------------------------------------------------- diff --git a/src/tlo/methods/hsi_event.py b/src/tlo/methods/hsi_event.py new file mode 100644 index 0000000000..85feb2b1b5 --- /dev/null +++ b/src/tlo/methods/hsi_event.py @@ -0,0 +1,465 @@ +from __future__ import annotations + +from collections import Counter +from typing import TYPE_CHECKING, Dict, Iterable, Literal, NamedTuple, Optional, Set, Tuple, Union + +import numpy as np + +from tlo import Date, logging +from tlo.events import Event +from tlo.population import Population + +if TYPE_CHECKING: + from tlo import Module, Simulation + from tlo.methods.healthsystem import HealthSystem + +logger = logging.getLogger(__name__) +logger.setLevel(logging.INFO) + +logger_summary = logging.getLogger(f"{__name__}.summary") +logger_summary.setLevel(logging.INFO) + +# Declare the level which will be used to represent the merging of levels '1b' and '2' +LABEL_FOR_MERGED_FACILITY_LEVELS_1B_AND_2 = "2" + + +class FacilityInfo(NamedTuple): + """Information about a specific health facility.""" + + id: int + name: str + level: str + region: str + + +class HSIEventDetails(NamedTuple): + """Non-target specific details of a health system interaction event.""" + + event_name: str + module_name: str + treatment_id: str + facility_level: Optional[str] + appt_footprint: Tuple[Tuple[str, int]] + beddays_footprint: Tuple[Tuple[str, int]] + equipment: Tuple[str] + + +class HSIEventQueueItem(NamedTuple): + """Properties of event added to health system queue. + + The order of the attributes in the tuple is important as the queue sorting is done + by the order of the items in the tuple, i.e. first by `priority`, then `topen` and + so on. + + Ensure priority is above topen in order for held-over events with low priority not + to jump ahead higher priority ones which were opened later. + """ + + priority: int + topen: Date + rand_queue_counter: ( + int # Ensure order of events with same topen & priority is not model-dependent + ) + queue_counter: ( + int # Include safety tie-breaker in unlikely event rand_queue_counter is equal + ) + tclose: Date + # Define HSI_Event type as string to avoid NameError exception as HSI_Event defined + # later in module (see https://stackoverflow.com/a/36286947/4798943) + hsi_event: "HSI_Event" + + +class HSI_Event: + """Base HSI event class, from which all others inherit. + + Concrete subclasses should also inherit from one of the EventMixin classes + defined in `src/tlo/events.py`, and implement at least an `apply` and + `did_not_run` method. + """ + + module: Module + target: int # Will be overwritten by the mixin on derived classes + + TREATMENT_ID: str + ACCEPTED_FACILITY_LEVEL: str + # These values need to be set at runtime as they depend on the modules + # which have been loaded. + BEDDAYS_FOOTPRINT: Dict[str, Union[float, int]] + + _received_info_about_bed_days: Dict[str, Union[float, int]] = None + expected_time_requests: Counter = {} + facility_info: FacilityInfo = None + + def __init__(self, module, *args, **kwargs): + """Create a new event. + + Note that just creating an event does not schedule it to happen; that + must be done by calling Simulation.schedule_event. + + :param module: the module that created this event. + All subclasses of Event take this as the first argument in their + constructor, but may also take further keyword arguments. + """ + self.module = module + super().__init__(*args, **kwargs) + + # Information that will later be received/computed about this HSI + self._received_info_about_bed_days = None + self.expected_time_requests = {} + self.facility_info = None + self._is_all_declared_equipment_available = None + + self.TREATMENT_ID = "" + self.ACCEPTED_FACILITY_LEVEL = None + # Set "dynamic" default value + self.BEDDAYS_FOOTPRINT = self.make_beddays_footprint({}) + self._EQUIPMENT: Set[int] = set() # The set of equipment that is used in the HSI. If any items in this set are + # not available at the point when the HSI will be run, then the HSI is not + # run, and the `never_ran` method is called instead. This is a declaration + # of resource needs, but is private because users are expected to use + # `add_equipment` to declare equipment needs. + + @property + def bed_days_allocated_to_this_event(self): + if self._received_info_about_bed_days is None: + # default to the footprint if no information about bed-days is received + return self.BEDDAYS_FOOTPRINT + + return self._received_info_about_bed_days + + @property + def sim(self) -> Simulation: + return self.module.sim + + @property + def healthcare_system(self) -> HealthSystem: + """The healthcare module being used by the Simulation.""" + return self.sim.modules["HealthSystem"] + + def _adjust_facility_level_to_merge_1b_and_2(self) -> str: + """Adjust the facility level of the HSI_Event, + so that HSI_Events scheduled at level '1b' and '2' are both directed to level '2' + """ + self.ACCEPTED_FACILITY_LEVEL = ( + self.ACCEPTED_FACILITY_LEVEL + if self.ACCEPTED_FACILITY_LEVEL not in ("1b", "2") + else LABEL_FOR_MERGED_FACILITY_LEVELS_1B_AND_2 + ) + + def apply(self, squeeze_factor=0.0, *args, **kwargs): + """Apply this event to the population. + + Must be implemented by subclasses. + """ + raise NotImplementedError + + def did_not_run(self, *args, **kwargs) -> Literal[True]: + """Called when this event is due but it is not run. Return False to prevent the event being rescheduled, or True + to allow the rescheduling. This is called each time that the event is tried to be run but it cannot be. + """ + logger.debug(key="message", data=f"{self.__class__.__name__}: did not run.") + return True + + def never_ran(self) -> None: + """Called when this event is was entered to the HSI Event Queue, but was never run.""" + logger.debug(key="message", data=f"{self.__class__.__name__}: was never run.") + + def post_apply_hook(self) -> None: + """Do any required processing after apply() completes.""" + + def _run_after_hsi_event(self) -> None: + """ + Do things following the event's `apply` and `post_apply_hook` functions running. + * Impose the bed-days footprint (if target of the HSI is a person_id) + * Record the equipment that has been added before and during the course of the HSI Event. + """ + if isinstance(self.target, int): + self.healthcare_system.bed_days.impose_beddays_footprint( + person_id=self.target, footprint=self.bed_days_allocated_to_this_event + ) + + if self.facility_info is not None: + # If there is a facility_info (e.g., healthsystem not running in disabled mode), then record equipment used + self.healthcare_system.equipment.record_use_of_equipment( + item_codes=self._EQUIPMENT, + facility_id=self.facility_info.id + ) + + def run(self, squeeze_factor): + """Make the event happen.""" + updated_appt_footprint = self.apply(self.target, squeeze_factor) + self.post_apply_hook() + self._run_after_hsi_event() + return updated_appt_footprint + + def get_consumables( + self, + item_codes: Union[None, np.integer, int, list, set, dict] = None, + optional_item_codes: Union[None, np.integer, int, list, set, dict] = None, + to_log: Optional[bool] = True, + return_individual_results: Optional[bool] = False, + ) -> Union[bool, dict]: + """Function to allow for getting and checking of entire set of consumables. All requests for consumables should + use this function. + :param item_codes: The item code(s) (and quantities) of the consumables that are requested and which determine + the summary result for availability/non-availability. This can be an `int` (the item_code needed [assume + quantity=1]), a `list` or `set` (the collection of item_codes [for each assuming quantity=1]), or a `dict` + (with key:value pairs `:`). + :param optional_item_codes: The item code(s) (and quantities) of the consumables that are requested and which do + not determine the summary result for availability/non-availability. (Same format as `item_codes`). This is + useful when a large set of items may be used, but the viability of a subsequent operation depends only on a + subset. + :param return_individual_results: If True returns a `dict` giving the availability of each item_code requested + (otherwise gives a `bool` indicating if all the item_codes requested are available). + :param to_log: If True, logs the request. + :returns A `bool` indicating whether every item is available, or a `dict` indicating the availability of each + item. + Note that disease module can use the `get_item_codes_from_package_name` and `get_item_code_from_item_name` + methods in the `HealthSystem` module to find item_codes. + """ + _item_codes = self._return_item_codes_in_dict(item_codes) + _optional_item_codes = self._return_item_codes_in_dict(optional_item_codes) + + # Determine if the request should be logged (over-ride argument provided if HealthSystem is disabled). + _to_log = to_log if not self.healthcare_system.disable else False + + # Checking the availability and logging: + rtn = self.healthcare_system.consumables._request_consumables( + item_codes={**_item_codes, **_optional_item_codes}, + to_log=_to_log, + facility_info=self.facility_info, + treatment_id=self.TREATMENT_ID, + ) + + # Return result in expected format: + if not return_individual_results: + # Determine if all results for all the `item_codes` are True (discarding results from optional_item_codes). + return all(v for k, v in rtn.items() if k in _item_codes) + else: + return rtn + + def make_beddays_footprint(self, dict_of_beddays) -> Dict[str, Union[float, int]]: + """Helper function to make a correctly-formed 'bed-days footprint'""" + + # get blank footprint + footprint = self.healthcare_system.bed_days.get_blank_beddays_footprint() + + # do checks on the dict_of_beddays provided. + assert isinstance(dict_of_beddays, dict) + assert all((k in footprint.keys()) for k in dict_of_beddays.keys()) + assert all(isinstance(v, (float, int)) for v in dict_of_beddays.values()) + + # make footprint (defaulting to zero where a type of bed-days is not specified) + for k, v in dict_of_beddays.items(): + footprint[k] = v + + return footprint + + def is_all_beddays_allocated(self) -> bool: + """Check if the entire footprint requested is allocated""" + return all( + self.bed_days_allocated_to_this_event[k] == self.BEDDAYS_FOOTPRINT[k] + for k in self.BEDDAYS_FOOTPRINT + ) + + def make_appt_footprint(self, dict_of_appts) -> Counter: + """Helper function to make appointment footprint in format expected downstream. + + Should be passed a dictionary keyed by appointment type codes with non-negative + values. + """ + if self.healthcare_system.appt_footprint_is_valid(dict_of_appts): + return Counter(dict_of_appts) + + raise ValueError( + "Argument to make_appt_footprint should be a dictionary keyed by " + "appointment type code strings in Appt_Types_Table with non-negative " + "values" + ) + + def add_equipment(self, item_codes: Union[int, str, Iterable[int], Iterable[str]]) -> None: + """Declare that piece(s) of equipment are used in this HSI_Event. Equipment items can be identified by their + item_codes (int) or descriptors (str); a singular item or an iterable of items (either codes or descriptors but + not a mix of both) can be defined at once. Checks are done on the validity of the item_codes/item + descriptions and a warning issued if any are not recognised.""" + self._EQUIPMENT.update(self.healthcare_system.equipment.parse_items(item_codes)) + + @property + def is_all_declared_equipment_available(self) -> bool: + """Returns ``True`` if all the (currently) declared items of equipment are available. This is called by the + ``HealthSystem`` module before the HSI is run and so is looking only at those items that are declared when this + instance was created. The evaluation of whether equipment is available is only done *once* for this instance of + the event: i.e., if the equipment is not available for the instance of this ``HSI_Event``, then it will remain not + available if the same event is re-scheduled/re-entered into the HealthSystem queue. This is representing that + if the facility that a particular person attends for the ``HSI_Event`` does not have the equipment available, then + it will also not be available on another day.""" + + if self._is_all_declared_equipment_available is None: + # Availability has not already been evaluated: determine availability + self._is_all_declared_equipment_available = self.healthcare_system.equipment.is_all_items_available( + item_codes=self._EQUIPMENT, + facility_id=self.facility_info.id, + ) + return self._is_all_declared_equipment_available + + def probability_all_equipment_available(self, item_codes: Union[int, str, Iterable[int], Iterable[str]]) -> float: + """Returns the probability that all the equipment item_codes are available. This does not imply that the + equipment is being used and no logging happens. It is provided as a convenience to disease module authors in + case the logic during an ``HSI_Event`` depends on the availability of a piece of equipment. This function + accepts the item codes/descriptions in a variety of formats, so the argument needs to be parsed.""" + return self.healthcare_system.equipment.probability_all_equipment_available( + item_codes=self.healthcare_system.equipment.parse_items(item_codes), + facility_id=self.facility_info.id, + ) + + def initialise(self) -> None: + """Initialise the HSI: + * Set the facility_info + * Compute appt-footprint time requirements + """ + health_system = self.healthcare_system + + # Over-write ACCEPTED_FACILITY_LEVEL to to redirect all '1b' appointments to '2' + self._adjust_facility_level_to_merge_1b_and_2() + + if not isinstance(self.target, Population): + self.facility_info = health_system.get_facility_info(self) + + # If there are bed-days specified, add (if needed) the in-patient admission and in-patient day Appointment + # Types. + # (HSI that require a bed for one or more days always need such appointments, but this may have been + # missed in the declaration of the `EXPECTED_APPT_FOOTPRINT` in the HSI.) + # NB. The in-patient day Appointment time is automatically applied on subsequent days. + if sum(self.BEDDAYS_FOOTPRINT.values()): + self.EXPECTED_APPT_FOOTPRINT = ( + health_system.bed_days.add_first_day_inpatient_appts_to_footprint( + self.EXPECTED_APPT_FOOTPRINT + ) + ) + + # Write the time requirements for staff of the appointments to the HSI: + self.expected_time_requests = ( + health_system.get_appt_footprint_as_time_request( + facility_info=self.facility_info, + appt_footprint=self.EXPECTED_APPT_FOOTPRINT, + ) + ) + + # Do checks + self._check_if_appt_footprint_can_run() + + def _check_if_appt_footprint_can_run(self) -> bool: + """Check that event (if individual level) is able to run with this configuration of officers (i.e. check that + this does not demand officers that are _never_ available), and issue warning if not. + """ + if not isinstance(self.target, Population): + if self.healthcare_system._officers_with_availability.issuperset( + self.expected_time_requests.keys() + ): + return True + else: + logger.warning( + key="message", + data=( + f"The expected footprint of {self.TREATMENT_ID} is not possible with the configuration of " + f"officers." + ), + ) + return False + + @staticmethod + def _return_item_codes_in_dict( + item_codes: Union[None, np.integer, int, list, set, dict] + ) -> dict: + """Convert an argument for 'item_codes` (provided as int, list, set or dict) into the format + dict(:quantity).""" + + if item_codes is None: + return {} + + if isinstance(item_codes, (int, np.integer)): + return {int(item_codes): 1} + + elif isinstance(item_codes, list): + if not all([isinstance(i, (int, np.integer)) for i in item_codes]): + raise ValueError("item_codes must be integers") + return {int(i): 1 for i in item_codes} + + elif isinstance(item_codes, dict): + if not all( + [ + ( + isinstance(code, (int, np.integer)) + and isinstance(quantity, (float, np.floating, int, np.integer)) + ) + for code, quantity in item_codes.items() + ] + ): + raise ValueError( + "item_codes must be integers and quantities must be integers or floats." + ) + return {int(i): float(q) for i, q in item_codes.items()} + + else: + raise ValueError("The item_codes are given in an unrecognised format") + + def as_namedtuple( + self, actual_appt_footprint: Optional[dict] = None + ) -> HSIEventDetails: + appt_footprint = ( + getattr(self, "EXPECTED_APPT_FOOTPRINT", {}) + if actual_appt_footprint is None + else actual_appt_footprint + ) + return HSIEventDetails( + event_name=type(self).__name__, + module_name=type(self.module).__name__, + treatment_id=self.TREATMENT_ID, + facility_level=getattr(self, "ACCEPTED_FACILITY_LEVEL", None), + appt_footprint=tuple(sorted(appt_footprint.items())), + beddays_footprint=tuple( + sorted((k, v) for k, v in self.BEDDAYS_FOOTPRINT.items() if v > 0) + ), + equipment=tuple(sorted(self._EQUIPMENT)), + ) + + +class HSIEventWrapper(Event): + """This is wrapper that contains an HSI event. + + It is used: + 1) When the healthsystem is in mode 'disabled=True' such that HSI events sent to the health system scheduler are + passed to the main simulation scheduler for running on the date of `topen`. (Note, it is run with + squeeze_factor=0.0.) + 2) When the healthsystem is in mode `disable_and_reject_all=True` such that HSI are not run but the `never_ran` + method is run on the date of `tclose`. + 3) When an HSI has been submitted to `schedule_hsi_event` but the service is not available. + """ + + def __init__(self, hsi_event, run_hsi=True, *args, **kwargs): + super().__init__(hsi_event.module, *args, **kwargs) + self.hsi_event = hsi_event + self.target = hsi_event.target + self.run_hsi = run_hsi # True to call the HSI's `run` method; False to call the HSI's `never_ran` method + + def run(self): + """Do the appropriate action on the HSI event""" + + # Check that the person is still alive (this check normally happens in the HealthSystemScheduler and silently + # do not run the HSI event) + + if isinstance(self.hsi_event.target, Population) or ( + self.hsi_event.module.sim.population.props.at[ + self.hsi_event.target, "is_alive" + ] + ): + + if self.run_hsi: + # Run the event (with 0 squeeze_factor) and ignore the output + _ = self.hsi_event.run(squeeze_factor=0.0) + else: + self.hsi_event.module.sim.modules[ + "HealthSystem" + ].call_and_record_never_ran_hsi_event( + hsi_event=self.hsi_event, priority=-1 + ) diff --git a/src/tlo/methods/hsi_generic_first_appts.py b/src/tlo/methods/hsi_generic_first_appts.py index b35a062acc..37f6c5e261 100644 --- a/src/tlo/methods/hsi_generic_first_appts.py +++ b/src/tlo/methods/hsi_generic_first_appts.py @@ -1,377 +1,288 @@ -""" -The file contains the event HSI_GenericFirstApptAtFacilityLevel1, which describes the first interaction with -the health system following the onset of acute generic symptoms. +"""Events which describes the first interaction with the health system. -This file contains the HSI events that represent the first contact with the Health System, which are triggered by -the onset of symptoms. Non-emergency symptoms lead to `HSI_GenericFirstApptAtFacilityLevel0` and emergency symptoms -lead to `HSI_GenericEmergencyFirstApptAtFacilityLevel1`. +This module contains the HSI events that represent the first contact with the health +system, which are triggered by the onset of symptoms. Non-emergency symptoms lead to +:py:class:`HSI_GenericNonEmergencyFirstAppt` and emergency symptoms lead to +:py:class:`HSI_GenericEmergencyFirstAppt`. """ -import pandas as pd -from tlo import logging +from __future__ import annotations + +from collections.abc import Callable +from typing import TYPE_CHECKING, Any, Dict, List, Protocol, Set, Union + +import numpy as np + +from tlo import Date, Module, logging from tlo.events import IndividualScopeEventMixin -from tlo.methods.bladder_cancer import ( - HSI_BladderCancer_Investigation_Following_Blood_Urine, - HSI_BladderCancer_Investigation_Following_pelvic_pain, -) -from tlo.methods.breast_cancer import ( - HSI_BreastCancer_Investigation_Following_breast_lump_discernible, -) -from tlo.methods.care_of_women_during_pregnancy import ( - HSI_CareOfWomenDuringPregnancy_PostAbortionCaseManagement, - HSI_CareOfWomenDuringPregnancy_TreatmentForEctopicPregnancy, -) -from tlo.methods.chronicsyndrome import HSI_ChronicSyndrome_SeeksEmergencyCareAndGetsTreatment -from tlo.methods.epilepsy import HSI_Epilepsy_Start_Anti_Epileptic -from tlo.methods.healthsystem import HSI_Event -from tlo.methods.hiv import HSI_Hiv_TestAndRefer -from tlo.methods.labour import HSI_Labour_ReceivesSkilledBirthAttendanceDuringLabour -from tlo.methods.measles import HSI_Measles_Treatment -from tlo.methods.mockitis import HSI_Mockitis_PresentsForCareWithSevereSymptoms -from tlo.methods.oesophagealcancer import HSI_OesophagealCancer_Investigation_Following_Dysphagia -from tlo.methods.other_adult_cancers import ( - HSI_OtherAdultCancer_Investigation_Following_early_other_adult_ca_symptom, -) -from tlo.methods.prostate_cancer import ( - HSI_ProstateCancer_Investigation_Following_Pelvic_Pain, - HSI_ProstateCancer_Investigation_Following_Urinary_Symptoms, -) +from tlo.methods.hsi_event import HSI_Event + +if TYPE_CHECKING: + from typing import Optional, TypeAlias + + from tlo.methods.dxmanager import DiagnosisTestReturnType + from tlo.population import IndividualProperties logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -class HSI_GenericNonEmergencyFirstAppt(HSI_Event, IndividualScopeEventMixin): - """This is a Health System Interaction Event that represents the first interaction with the health system following - the onset of non-emergency symptom(s). This is the HSI that is generated by the HealthSeekingBehaviour module. By - default, it occurs at level '0' but it could occur also at other levels.""" - - def __init__(self, module, person_id, facility_level='0'): - super().__init__(module, person_id=person_id, ) +DiagnosisFunction: TypeAlias = Callable[[str, bool, bool], Any] +ConsumablesChecker: TypeAlias = Callable[ + [ + Union[None, np.integer, int, List, Set, Dict], + Union[None, np.integer, int, List, Set, Dict], + ], + Union[bool, Dict], +] + + +class HSIEventScheduler(Protocol): + + def __call__( + self, + hsi_event: HSI_Event, + priority: int, + topen: Date, + tclose: Optional[Date] = None, + ) -> None: ... + + +class GenericFirstAppointmentsMixin: + """Mix-in for modules with actions to perform on generic first appointments.""" + + def do_at_generic_first_appt( + self, + *, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + diagnosis_function: DiagnosisFunction, + consumables_checker: ConsumablesChecker, + facility_level: str, + treatment_id: str, + ) -> None: + """ + Actions to take during a non-emergency generic health system interaction (HSI). + + Derived classes should overwrite this method so that they are compatible with + the :py:class:`~.HealthSystem` module, and can schedule HSI events when a + individual presents symptoms indicative of the corresponding illness or + condition. + + When overwriting, arguments that are not required can be left out of the + definition. If done so, the method **must** take a ``**kwargs`` input to avoid + errors when looping over all disease modules and running their generic HSI + methods. + + HSI events should be scheduled by the :py:class:`Module` subclass implementing + this method using the ``schedule_hsi_event`` argument. + + Implementations of this method should **not** make any updates to the population + dataframe directly - if the target individuals properties need to be updated + this should be performed by updating the ``individual_properties`` argument. + + :param person_id: Row index (ID) of the individual target of the HSI event in + the population dataframe. + :param individual_properties: Properties of individual target as provided in the + population dataframe. Updates to individual properties may be written to + this object. + :param symptoms: List of symptoms the patient is experiencing. + :param schedule_hsi_event: A function that can schedule subsequent HSI events. + :param diagnosis_function: A function that can run diagnosis tests based on the + patient's symptoms. + :param consumables_checker: A function that can query the health system to check + for available consumables. + :param facility_level: The level of the facility that the patient presented at. + :param treatment_id: The treatment id of the HSI event triggering the generic + appointment. + """ + + def do_at_generic_first_appt_emergency( + self, + *, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + diagnosis_function: DiagnosisFunction, + consumables_checker: ConsumablesChecker, + facility_level: str, + treatment_id: str, + ) -> None: + """ + Actions to take during an emergency generic health system interaction (HSI). + + Call signature is identical to the + :py:meth:`~GenericFirstAppointmentsMixin.do_at_generic_first_appt` method. + + Derived classes should overwrite this method so that they are compatible with + the :py:class`~.HealthSystem` module, and can schedule HSI events when a + individual presents symptoms indicative of the corresponding illness or + condition. + """ + + +class _BaseHSIGenericFirstAppt(HSI_Event, IndividualScopeEventMixin): + + def __init__(self, module, person_id) -> None: + super().__init__(module, person_id=person_id) + # No footprint, as this HSI (mostly just) determines which further HSI will be + # needed for this person. In some cases, small bits of care are provided (e.g. a + # diagnosis, or the provision of inhaler). + self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({}) + + def _diagnosis_function( + self, tests, use_dict: bool = False, report_tried: bool = False + ) -> DiagnosisTestReturnType: + """ + Passed to modules when determining HSI events to be scheduled based on + this generic appointment. Intended as the ``diagnosis_function`` argument to + :py:meth:`GenericFirstAppointmentsMixin.do_at_generic_first_appt` or + :py:meth:`GenericFirstAppointmentsMixin.do_at_generic_first_appt_emergency`. + + Class-level definition avoids the need to redefine this method each time + the :py:meth:`apply` method is called. + + :param tests: The name of the test(s) to run via the diagnosis manager. + :param use_dict_for_single: If ``True``, the return type will be a dictionary + even if only one test was requested. + :param report_dxtest_tried: Report if a test was attempted but could not + be carried out due to for example lack of consumables, etc. + :returns: Test results as dictionary key/value pairs. + """ + return self.sim.modules["HealthSystem"].dx_manager.run_dx_test( + tests, + hsi_event=self, + use_dict_for_single=use_dict, + report_dxtest_tried=report_tried, + ) - assert module is self.sim.modules['HealthSeekingBehaviour'] + @staticmethod + def _do_at_generic_first_appt_for_module(module: Module) -> Callable: + """Retrieves relevant do_at_generic_first_appt* method for a module. + + Must be implemented by concrete classes derived from this base class. + """ + raise NotImplementedError + + def apply(self, person_id: int, squeeze_factor: float = 0.0) -> None: + """ + Run the actions required during the health system interaction (HSI). + + TODO: person_id is not needed any more - but would have to go through the + whole codebase to manually identify instances of this class to change call + syntax, and leave other HSI_Event-derived classes alone. + """ + # Create a memoized view of target individuals' properties as a context manager + # that will automatically synchronize any updates back to the population + # dataframe on exit + with self.sim.population.individual_properties( + self.target, read_only=False + ) as individual_properties: + if not individual_properties["is_alive"]: + return + # Pre-evaluate symptoms for individual to avoid repeat accesses + # Use the individual_properties context here to save independent DF lookups + symptoms = self.sim.modules["SymptomManager"].has_what( + individual_details=individual_properties + ) + schedule_hsi_event = self.sim.modules["HealthSystem"].schedule_hsi_event + for module in self.sim.modules.values(): + if isinstance(module, GenericFirstAppointmentsMixin): + self._do_at_generic_first_appt_for_module(module)( + person_id=self.target, + individual_properties=individual_properties, + symptoms=symptoms, + schedule_hsi_event=schedule_hsi_event, + diagnosis_function=self._diagnosis_function, + consumables_checker=self.get_consumables, + facility_level=self.ACCEPTED_FACILITY_LEVEL, + treatment_id=self.TREATMENT_ID, + ) + + +class HSI_GenericNonEmergencyFirstAppt(_BaseHSIGenericFirstAppt): + """ + This is a health system interaction event that represents the first interaction with + the health system following the onset of non-emergency symptom(s). + + It is generated by the :py:class:`~HealthSeekingBehaviour` module. + + By default, it occurs at level '0' but it could occur also at other levels. + + It uses the non-emergency generic first appointment methods of the disease modules + to determine any follow-up events that need to be scheduled. + """ + + def __init__(self, module, person_id, facility_level="0"): + super().__init__( + module, + person_id=person_id, + ) - self.TREATMENT_ID = 'FirstAttendance_NonEmergency' + assert module is self.sim.modules["HealthSeekingBehaviour"] + self.TREATMENT_ID = "FirstAttendance_NonEmergency" self.ACCEPTED_FACILITY_LEVEL = facility_level - self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({}) # <-- No footprint, as this HSI (mostly just) - # determines which further HSI will be needed - # for this person. In some cases, small bits - # of care are provided (e.g. a diagnosis, or - # the provision of inhaler.). - - def apply(self, person_id, squeeze_factor): - """Run the actions required during the HSI.""" - df = self.sim.population.props - if not df.at[person_id, 'is_alive']: - return + @staticmethod + def _do_at_generic_first_appt_for_module( + module: GenericFirstAppointmentsMixin, + ) -> Callable: + return module.do_at_generic_first_appt - do_at_generic_first_appt_non_emergency(hsi_event=self, squeeze_factor=squeeze_factor) +class HSI_GenericEmergencyFirstAppt(_BaseHSIGenericFirstAppt): + """ + This is a health system interaction event that represents the generic appointment + which is the first interaction with the health system following the onset of + emergency symptom(s). -class HSI_GenericEmergencyFirstAppt(HSI_Event, IndividualScopeEventMixin): - """This is a Health System Interaction Event that represents the generic appointment which is the first interaction - with the health system following the onset of emergency symptom(s).""" + It uses the emergency generic first appointment methods of the disease modules to + determine any follow-up events that need to be scheduled. + """ def __init__(self, module, person_id): super().__init__(module, person_id=person_id) - assert module.name in ['HealthSeekingBehaviour', 'Labour', 'PregnancySupervisor', 'RTI'] + assert module.name in [ + "HealthSeekingBehaviour", + "Labour", + "PregnancySupervisor", + "RTI", + ] - self.TREATMENT_ID = 'FirstAttendance_Emergency' - self.ACCEPTED_FACILITY_LEVEL = '1b' - self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({}) # <-- No footprint, as this HSI (mostly just) - # determines which further HSI will be needed - # for this person. In some cases, small bits - # of care are provided (e.g. a diagnosis, or - # the provision of inhaler.). + self.TREATMENT_ID = "FirstAttendance_Emergency" + 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']: - return - - do_at_generic_first_appt_emergency(hsi_event=self, squeeze_factor=squeeze_factor) + @staticmethod + def _do_at_generic_first_appt_for_module( + module: GenericFirstAppointmentsMixin, + ) -> Callable: + return module.do_at_generic_first_appt_emergency class HSI_EmergencyCare_SpuriousSymptom(HSI_Event, IndividualScopeEventMixin): - """This is an HSI event that provides Accident & Emergency Care for a person that has spurious emergency symptom.""" + """HSI event providing accident & emergency care on spurious emergency symptoms.""" - def __init__(self, module, person_id, accepted_facility_level='1a'): + def __init__(self, module, person_id, accepted_facility_level="1a"): super().__init__(module, person_id=person_id) - assert module is self.sim.modules['HealthSeekingBehaviour'] + assert module is self.sim.modules["HealthSeekingBehaviour"] self.TREATMENT_ID = "FirstAttendance_SpuriousEmergencyCare" - self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({'AccidentsandEmerg': 1}) - self.ACCEPTED_FACILITY_LEVEL = accepted_facility_level # '1a' in default or '1b' as an alternative + self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint( + {"AccidentsandEmerg": 1} + ) + self.ACCEPTED_FACILITY_LEVEL = ( + accepted_facility_level # '1a' in default or '1b' as an alternative + ) def apply(self, person_id, squeeze_factor): df = self.sim.population.props - if not df.at[person_id, 'is_alive']: + if not df.at[person_id, "is_alive"]: return self.make_appt_footprint({}) else: - sm = self.sim.modules['SymptomManager'] - sm.change_symptom(person_id, "spurious_emergency_symptom", '-', sm) - - -def do_at_generic_first_appt_non_emergency(hsi_event, squeeze_factor): - """The actions are taken during the non-emergency generic HSI, HSI_GenericFirstApptAtFacilityLevel0.""" - - # Gather useful shortcuts - sim = hsi_event.sim - person_id = hsi_event.target - df = hsi_event.sim.population.props - symptoms = hsi_event.sim.modules['SymptomManager'].has_what(person_id=person_id) - age = df.at[person_id, 'age_years'] - schedule_hsi = hsi_event.sim.modules["HealthSystem"].schedule_hsi_event - - # ----------------------------------- ALL AGES ----------------------------------- - # Consider Measles if rash. - if 'Measles' in sim.modules: - if "rash" in symptoms: - schedule_hsi( - HSI_Measles_Treatment( - person_id=person_id, - module=hsi_event.sim.modules['Measles']), - priority=0, - topen=hsi_event.sim.date, - tclose=None) - - # 'Automatic' testing for HIV for everyone attending care with AIDS symptoms: - # - suppress the footprint (as it done as part of another appointment) - # - do not do referrals if the person is HIV negative (assumed not time for counselling etc). - if 'Hiv' in sim.modules: - if 'aids_symptoms' in symptoms: - schedule_hsi( - HSI_Hiv_TestAndRefer( - person_id=person_id, - module=hsi_event.sim.modules['Hiv'], - referred_from="hsi_generic_first_appt", - suppress_footprint=True, - do_not_refer_if_neg=True), - topen=hsi_event.sim.date, - tclose=None, - priority=0) - - if 'injury' in symptoms: - if 'RTI' in sim.modules: - sim.modules['RTI'].do_rti_diagnosis_and_treatment(person_id) - - if 'Schisto' in sim.modules: - sim.modules['Schisto'].do_on_presentation_with_symptoms(person_id=person_id, symptoms=symptoms) - - if "Malaria" in sim.modules: - malaria_associated_symptoms = {'fever', 'headache', 'stomachache', 'diarrhoea', 'vomiting'} - if bool(set(symptoms) & malaria_associated_symptoms): - sim.modules['Malaria'].do_for_suspected_malaria_case(person_id=person_id, hsi_event=hsi_event) - - if age <= 5: - # ----------------------------------- CHILD < 5 ----------------------------------- - if 'Diarrhoea' in sim.modules: - if 'diarrhoea' in symptoms: - sim.modules['Diarrhoea'].do_when_presentation_with_diarrhoea( - person_id=person_id, hsi_event=hsi_event) - - if 'Alri' in sim.modules: - if ('cough' in symptoms) or ('difficult_breathing' in symptoms): - sim.modules['Alri'].on_presentation(person_id=person_id, hsi_event=hsi_event) - - # Routine assessments - if 'Stunting' in sim.modules: - sim.modules['Stunting'].do_routine_assessment_for_chronic_undernutrition(person_id=person_id) - - if 'Wasting' in sim.modules: - sim.modules['Wasting'].do_when_acute_malnutrition_assessment(person_id) - - else: - # ----------------------------------- ADULT ----------------------------------- - if 'OesophagealCancer' in sim.modules: - # If the symptoms include dysphagia, then begin investigation for Oesophageal Cancer: - if 'dysphagia' in symptoms: - schedule_hsi( - HSI_OesophagealCancer_Investigation_Following_Dysphagia( - person_id=person_id, - module=sim.modules['OesophagealCancer']), - priority=0, - topen=sim.date, - tclose=None - ) - - if 'BladderCancer' in sim.modules: - # If the symptoms include blood_urine, then begin investigation for Bladder Cancer: - if 'blood_urine' in symptoms: - schedule_hsi( - HSI_BladderCancer_Investigation_Following_Blood_Urine( - person_id=person_id, - module=sim.modules['BladderCancer']), - priority=0, - topen=sim.date, - tclose=None - ) - - # If the symptoms include pelvic_pain, then begin investigation for Bladder Cancer: - if 'pelvic_pain' in symptoms: - schedule_hsi( - HSI_BladderCancer_Investigation_Following_pelvic_pain( - person_id=person_id, - module=sim.modules['BladderCancer']), - priority=0, - topen=sim.date, - tclose=None) - - if 'ProstateCancer' in sim.modules: - # If the symptoms include urinary, then begin investigation for prostate cancer: - if 'urinary' in symptoms: - schedule_hsi( - HSI_ProstateCancer_Investigation_Following_Urinary_Symptoms( - person_id=person_id, - module=sim.modules['ProstateCancer']), - priority=0, - topen=sim.date, - tclose=None) - - if 'pelvic_pain' in symptoms: - schedule_hsi( - HSI_ProstateCancer_Investigation_Following_Pelvic_Pain( - person_id=person_id, - module=sim.modules['ProstateCancer']), - priority=0, - topen=sim.date, - tclose=None) - - if 'OtherAdultCancer' in sim.modules: - if 'early_other_adult_ca_symptom' in symptoms: - schedule_hsi( - HSI_OtherAdultCancer_Investigation_Following_early_other_adult_ca_symptom( - person_id=person_id, - module=sim.modules['OtherAdultCancer'] - ), - priority=0, - topen=sim.date, - tclose=None) - - if 'BreastCancer' in sim.modules: - # If the symptoms include breast lump discernible: - if 'breast_lump_discernible' in symptoms: - schedule_hsi( - HSI_BreastCancer_Investigation_Following_breast_lump_discernible( - person_id=person_id, - module=sim.modules['BreastCancer'], - ), - priority=0, - topen=sim.date, - tclose=None) - - if 'Depression' in sim.modules: - sim.modules['Depression'].do_on_presentation_to_care(person_id=person_id, - hsi_event=hsi_event) - - if 'CardioMetabolicDisorders' in sim.modules: - sim.modules['CardioMetabolicDisorders'].determine_if_will_be_investigated(person_id=person_id) - - if 'Copd' in sim.modules: - if ('breathless_moderate' in symptoms) or ('breathless_severe' in symptoms): - sim.modules['Copd'].do_when_present_with_breathless(person_id=person_id, hsi_event=hsi_event) - - -def do_at_generic_first_appt_emergency(hsi_event, squeeze_factor): - """The actions are taken during the non-emergency generic HSI, HSI_GenericEmergencyFirstApptAtFacilityLevel1.""" - - # Gather useful shortcuts - sim = hsi_event.sim - rng = hsi_event.module.rng - person_id = hsi_event.target - df = hsi_event.sim.population.props - symptoms = hsi_event.sim.modules['SymptomManager'].has_what(person_id=person_id) - schedule_hsi = hsi_event.sim.modules["HealthSystem"].schedule_hsi_event - age = df.at[person_id, 'age_years'] - - if 'PregnancySupervisor' in sim.modules: - - # ----- ECTOPIC PREGNANCY ----- - if df.at[person_id, 'ps_ectopic_pregnancy'] != 'none': - event = HSI_CareOfWomenDuringPregnancy_TreatmentForEctopicPregnancy( - module=sim.modules['CareOfWomenDuringPregnancy'], person_id=person_id) - schedule_hsi(event, priority=0, topen=sim.date, tclose=sim.date + pd.DateOffset(days=1)) - - # ----- COMPLICATIONS OF ABORTION ----- - abortion_complications = sim.modules['PregnancySupervisor'].abortion_complications - if abortion_complications.has_any([person_id], 'sepsis', 'injury', 'haemorrhage', first=True): - event = HSI_CareOfWomenDuringPregnancy_PostAbortionCaseManagement( - module=sim.modules['CareOfWomenDuringPregnancy'], person_id=person_id) - schedule_hsi(event, priority=0, topen=sim.date, tclose=sim.date + pd.DateOffset(days=1)) - - if 'Labour' in sim.modules: - mni = sim.modules['PregnancySupervisor'].mother_and_newborn_info - labour_list = sim.modules['Labour'].women_in_labour - - if person_id in labour_list: - la_currently_in_labour = df.at[person_id, 'la_currently_in_labour'] - if ( - la_currently_in_labour & - mni[person_id]['sought_care_for_complication'] & - (mni[person_id]['sought_care_labour_phase'] == 'intrapartum') - ): - event = HSI_Labour_ReceivesSkilledBirthAttendanceDuringLabour( - module=sim.modules['Labour'], person_id=person_id, - facility_level_of_this_hsi=rng.choice(['1a', '1b'])) - schedule_hsi(event, priority=0, topen=sim.date, tclose=sim.date + pd.DateOffset(days=1)) - - if "Depression" in sim.modules: - sim.modules['Depression'].do_on_presentation_to_care(person_id=person_id, - hsi_event=hsi_event) - - if "Malaria" in sim.modules: - if 'severe_malaria' in symptoms: - sim.modules['Malaria'].do_on_emergency_presentation_with_severe_malaria(person_id=person_id, - hsi_event=hsi_event) - - # ------ CARDIO-METABOLIC DISORDERS ------ - if 'CardioMetabolicDisorders' in sim.modules: - sim.modules['CardioMetabolicDisorders'].determine_if_will_be_investigated_events(person_id=person_id) - - if "Epilepsy" in sim.modules: - if 'seizures' in symptoms: - schedule_hsi(HSI_Epilepsy_Start_Anti_Epileptic(person_id=person_id, - module=sim.modules['Epilepsy']), - priority=0, - topen=sim.date, - tclose=None) - - if 'severe_trauma' in symptoms: - if 'RTI' in sim.modules: - sim.modules['RTI'].do_rti_diagnosis_and_treatment(person_id=person_id) - - if 'Alri' in sim.modules: - if (age <= 5) and (('cough' in symptoms) or ('difficult_breathing' in symptoms)): - sim.modules['Alri'].on_presentation(person_id=person_id, hsi_event=hsi_event) - - # ----- spurious emergency symptom ----- - if 'spurious_emergency_symptom' in symptoms: - event = HSI_EmergencyCare_SpuriousSymptom( - module=sim.modules['HealthSeekingBehaviour'], - person_id=person_id - ) - schedule_hsi(event, priority=0, topen=sim.date) - - if 'Copd' in sim.modules: - if ('breathless_moderate' in symptoms) or ('breathless_severe' in symptoms): - sim.modules['Copd'].do_when_present_with_breathless(person_id=person_id, hsi_event=hsi_event) - - # ----- EXAMPLES FOR MOCKITIS AND CHRONIC SYNDROME ----- - if 'craving_sandwiches' in symptoms: - event = HSI_ChronicSyndrome_SeeksEmergencyCareAndGetsTreatment( - module=sim.modules['ChronicSyndrome'], - person_id=person_id - ) - schedule_hsi(event, priority=1, topen=sim.date) - - if 'extreme_pain_in_the_nose' in symptoms: - event = HSI_Mockitis_PresentsForCareWithSevereSymptoms( - module=sim.modules['Mockitis'], - person_id=person_id - ) - schedule_hsi(event, priority=1, topen=sim.date) + sm = self.sim.modules["SymptomManager"] + sm.change_symptom(person_id, "spurious_emergency_symptom", "-", sm) diff --git a/src/tlo/methods/labour.py b/src/tlo/methods/labour.py index 0f6d7d134e..695dbeb501 100644 --- a/src/tlo/methods/labour.py +++ b/src/tlo/methods/labour.py @@ -1,4 +1,7 @@ +from __future__ import annotations + from pathlib import Path +from typing import TYPE_CHECKING import numpy as np import pandas as pd @@ -10,10 +13,16 @@ from tlo.methods import Metadata, labour_lm, pregnancy_helper_functions from tlo.methods.causes import Cause from tlo.methods.dxmanager import DxTest -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.postnatal_supervisor import PostnatalWeekOneMaternalEvent from tlo.util import BitsetHandler +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + from tlo.population import IndividualProperties + + # Standard logger logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -27,7 +36,7 @@ logger_pn.setLevel(logging.INFO) -class Labour(Module): +class Labour(Module, GenericFirstAppointmentsMixin): """This is module is responsible for the process of labour, birth and the immediate postnatal period (up until 48hrs post birth). This model has a number of core functions including; initiating the onset of labour for women on their pre-determined due date (or prior to this for preterm labour/admission for delivery), applying the incidence @@ -597,8 +606,8 @@ def __init__(self, name=None, resourcefilepath=None): 'antihypertensives'), 'la_postpartum_haem': Property(Types.BOOL, 'whether the woman has experienced an postpartum haemorrhage in this' 'delivery'), - 'la_postpartum_haem_treatment': Property(Types.INT, ' Treatment for received for postpartum haemorrhage ' - '(bitset)'), + 'la_postpartum_haem_treatment': Property(Types.BITSET, ' Treatment for received for postpartum haemorrhage ' + '(bitset)'), 'la_has_had_hysterectomy': Property(Types.BOOL, 'whether this woman has had a hysterectomy as treatment for a ' 'complication of labour, and therefore is unable to conceive'), 'la_date_most_recent_delivery': Property(Types.DATE, 'date of on which this mother last delivered'), @@ -681,174 +690,180 @@ def get_and_store_labour_item_codes(self): This function defines the required consumables for each intervention delivered during this module and stores them in a module level dictionary called within HSIs """ - get_item_code_from_pkg = self.sim.modules['HealthSystem'].get_item_codes_from_package_name - - get_list_of_items = pregnancy_helper_functions.get_list_of_items - - # ---------------------------------- IV DRUG ADMIN EQUIPMENT ------------------------------------------------- - self.item_codes_lab_consumables['iv_drug_equipment'] = \ - get_list_of_items(self, ['Cannula iv (winged with injection pot) 18_each_CMST', - 'Giving set iv administration + needle 15 drops/ml_each_CMST', - 'Disposables gloves, powder free, 100 pieces per box']) + ic = self.sim.modules['HealthSystem'].get_item_code_from_item_name # ---------------------------------- BLOOD TEST EQUIPMENT --------------------------------------------------- self.item_codes_lab_consumables['blood_test_equipment'] = \ - get_list_of_items(self, ['Blood collecting tube, 5 ml', - 'Cannula iv (winged with injection pot) 18_each_CMST', - 'Disposables gloves, powder free, 100 pieces per box']) + {ic('Blood collecting tube, 5 ml'): 1, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1 + } + # ---------------------------------- IV DRUG ADMIN EQUIPMENT ------------------------------------------------- + self.item_codes_lab_consumables['iv_drug_equipment'] = \ + {ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1 + } # ------------------------------------------ FULL BLOOD COUNT ------------------------------------------------- - self.item_codes_lab_consumables['full_blood_count'] = get_list_of_items(self, ['Complete blood count']) + self.item_codes_lab_consumables['full_blood_count'] = {ic('Complete blood count'): 1} # -------------------------------------------- DELIVERY ------------------------------------------------------ # assuming CDK has blade, soap, cord tie self.item_codes_lab_consumables['delivery_core'] = \ - get_list_of_items(self, ['Clean delivery kit', - 'Chlorhexidine 1.5% solution_5_CMST']) + {ic('Clean delivery kit'): 1, + ic('Chlorhexidine 1.5% solution_5_CMST'): 20, + } self.item_codes_lab_consumables['delivery_optional'] = \ - get_list_of_items(self, ['Cannula iv (winged with injection pot) 18_each_CMST', - 'Disposables gloves, powder free, 100 pieces per box', - 'Gauze, absorbent 90cm x 40m_each_CMST', - 'Paracetamol, tablet, 500 mg']) + {ic('Gauze, absorbent 90cm x 40m_each_CMST'): 30, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1, + ic('Paracetamol, tablet, 500 mg'): 8000 + } # -------------------------------------------- CAESAREAN DELIVERY ------------------------------------------ self.item_codes_lab_consumables['caesarean_delivery_core'] = \ - get_list_of_items(self, ['Halothane (fluothane)_250ml_CMST', - 'Ceftriaxone 1g, PFR_each_CMST', - 'Metronidazole 200mg_1000_CMST']) + {ic('Halothane (fluothane)_250ml_CMST'): 100, + ic('Ceftriaxone 1g, PFR_each_CMST'): 2, + ic('Metronidazole 200mg_1000_CMST'): 1, # todo: replace + } self.item_codes_lab_consumables['caesarean_delivery_optional'] = \ - get_list_of_items(self, ['Scalpel blade size 22 (individually wrapped)_100_CMST', - 'Cannula iv (winged with injection pot) 18_each_CMST', - 'Paracetamol, tablet, 500 mg', - 'Declofenac injection_each_CMST', - 'Pethidine, 50 mg/ml, 2 ml ampoule', - 'Foley catheter', - 'Bag, urine, collecting, 2000 ml', - "ringer's lactate (Hartmann's solution), 1000 ml_12_IDA", - 'Sodium chloride, injectable solution, 0,9 %, 500 ml', - "Giving set iv administration + needle 15 drops/ml_each_CMST", - "Chlorhexidine 1.5% solution_5_CMST"]) + {ic('Scalpel blade size 22 (individually wrapped)_100_CMST'): 1, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Sodium chloride, injectable solution, 0,9 %, 500 ml'): 2000, + ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1, + ic('Foley catheter'): 1, + ic('Bag, urine, collecting, 2000 ml'): 1, + ic('Paracetamol, tablet, 500 mg'): 8000, + ic('Declofenac injection_each_CMST'): 2, + ic("ringer's lactate (Hartmann's solution), 1000 ml_12_IDA"): 2000, + } # -------------------------------------------- OBSTETRIC SURGERY ---------------------------------------------- self.item_codes_lab_consumables['obstetric_surgery_core'] = \ - get_list_of_items(self, ['Halothane (fluothane)_250ml_CMST', - 'Ceftriaxone 1g, PFR_each_CMST', - 'Metronidazole 200mg_1000_CMST']) + {ic('Halothane (fluothane)_250ml_CMST'): 100, + ic('Ceftriaxone 1g, PFR_each_CMST'): 2, + ic('Metronidazole 200mg_1000_CMST'): 1, # todo: replace + } self.item_codes_lab_consumables['obstetric_surgery_optional'] = \ - get_list_of_items(self, ['Scalpel blade size 22 (individually wrapped)_100_CMST', - 'Cannula iv (winged with injection pot) 18_each_CMST', - 'Paracetamol, tablet, 500 mg', - 'Declofenac injection_each_CMST', - 'Pethidine, 50 mg/ml, 2 ml ampoule', - 'Foley catheter', - 'Bag, urine, collecting, 2000 ml', - "ringer's lactate (Hartmann's solution), 1000 ml_12_IDA", - 'Sodium chloride, injectable solution, 0,9 %, 500 ml', - "Giving set iv administration + needle 15 drops/ml_each_CMST"]) + {ic('Scalpel blade size 22 (individually wrapped)_100_CMST'): 1, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Sodium chloride, injectable solution, 0,9 %, 500 ml'): 2000, + ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1, + ic('Foley catheter'): 1, + ic('Bag, urine, collecting, 2000 ml'): 1, + ic('Paracetamol, tablet, 500 mg'): 8000, + ic('Declofenac injection_each_CMST'): 2, + ic("ringer's lactate (Hartmann's solution), 1000 ml_12_IDA"): 2000, + } # -------------------------------------------- ABX FOR PROM ------------------------------------------------- self.item_codes_lab_consumables['abx_for_prom'] = \ - get_list_of_items(self, ['Benzathine benzylpenicillin, powder for injection, 2.4 million IU']) + {ic('Benzathine benzylpenicillin, powder for injection, 2.4 million IU'): 8} # -------------------------------------------- ANTENATAL STEROIDS --------------------------------------------- + self.item_codes_lab_consumables['antenatal_steroids'] = \ - get_list_of_items(self, ['Dexamethasone 5mg/ml, 5ml_each_CMST']) + {ic('Dexamethasone 5mg/ml, 5ml_each_CMST'): 12} # ------------------------------------- INTRAVENOUS ANTIHYPERTENSIVES --------------------------------------- self.item_codes_lab_consumables['iv_antihypertensives'] = \ - get_list_of_items(self, ['Hydralazine, powder for injection, 20 mg ampoule']) + {ic('Hydralazine, powder for injection, 20 mg ampoule'): 1} # --------------------------------------- ORAL ANTIHYPERTENSIVES --------------------------------------------- self.item_codes_lab_consumables['oral_antihypertensives'] = \ - get_list_of_items(self, ['Methyldopa 250mg_1000_CMST']) + {ic('Methyldopa 250mg_1000_CMST'): 1} # ---------------------------------- SEVERE PRE-ECLAMPSIA/ECLAMPSIA ----------------------------------------- self.item_codes_lab_consumables['magnesium_sulfate'] = \ - get_list_of_items(self, ['Magnesium sulfate, injection, 500 mg/ml in 10-ml ampoule']) + {ic('Magnesium sulfate, injection, 500 mg/ml in 10-ml ampoule'): 2} self.item_codes_lab_consumables['eclampsia_management_optional'] = \ - get_list_of_items(self, ['Misoprostol, tablet, 200 mcg', - 'Oxytocin, injection, 10 IU in 1 ml ampoule', - 'Sodium chloride, injectable solution, 0,9 %, 500 ml', - 'Cannula iv (winged with injection pot) 18_each_CMST', - 'Giving set iv administration + needle 15 drops/ml_each_CMST', - 'Disposables gloves, powder free, 100 pieces per box', - 'Oxygen, 1000 liters, primarily with oxygen cylinders', - 'Complete blood count', - 'Foley catheter', - 'Bag, urine, collecting, 2000 ml']) - + {ic('Sodium chloride, injectable solution, 0,9 %, 500 ml'): 2000, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1, + ic('Oxygen, 1000 liters, primarily with oxygen cylinders'): 23_040, + ic('Complete blood count'): 1, + ic('Blood collecting tube, 5 ml'): 1, + ic('Foley catheter'): 1, + ic('Bag, urine, collecting, 2000 ml'): 1, + } # ------------------------------------- OBSTRUCTED LABOUR --------------------------------------------------- self.item_codes_lab_consumables['obstructed_labour'] = \ - get_list_of_items(self, ['Lidocaine HCl (in dextrose 7.5%), ampoule 2 ml', - 'Benzylpenicillin 3g (5MU), PFR_each_CMST', - 'Gentamycin, injection, 40 mg/ml in 2 ml vial', - 'Sodium chloride, injectable solution, 0,9 %, 500 ml', - 'Cannula iv (winged with injection pot) 18_each_CMST', - 'Giving set iv administration + needle 15 drops/ml_each_CMST', - 'Disposables gloves, powder free, 100 pieces per box', - 'Complete blood count', - 'Foley catheter', - 'Bag, urine, collecting, 2000 ml', - 'Paracetamol, tablet, 500 mg', - 'Pethidine, 50 mg/ml, 2 ml ampoule', - 'Gauze, absorbent 90cm x 40m_each_CMST', - 'Suture pack']) - + {ic('Lidocaine HCl (in dextrose 7.5%), ampoule 2 ml'): 1, + ic('Benzathine benzylpenicillin, powder for injection, 2.4 million IU'): 8, + ic('Gentamycin, injection, 40 mg/ml in 2 ml vial'): 6, + ic('Sodium chloride, injectable solution, 0,9 %, 500 ml'): 2000, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1, + ic('Complete blood count'): 1, + ic('Blood collecting tube, 5 ml'): 1, + ic('Foley catheter'): 1, + ic('Bag, urine, collecting, 2000 ml'): 1, + ic('Paracetamol, tablet, 500 mg'): 8000, + ic('Pethidine, 50 mg/ml, 2 ml ampoule'): 6, + ic('Gauze, absorbent 90cm x 40m_each_CMST'): 30, + ic('Suture pack'): 1, + } # ------------------------------------- OBSTETRIC VACUUM --------------------------------------------------- - self.item_codes_lab_consumables['vacuum'] = get_list_of_items(self, ['Vacuum, obstetric']) + self.item_codes_lab_consumables['vacuum'] = {ic('Vacuum, obstetric'): 1} # ------------------------------------- MATERNAL SEPSIS ----------------------------------------------------- self.item_codes_lab_consumables['maternal_sepsis_core'] = \ - get_list_of_items(self, ['Benzylpenicillin 3g (5MU), PFR_each_CMST', - 'Gentamycin, injection, 40 mg/ml in 2 ml vial']) - # 'Metronidazole, injection, 500 mg in 100 ml vial']) + {ic('Benzylpenicillin 3g (5MU), PFR_each_CMST'): 8, + ic('Gentamycin, injection, 40 mg/ml in 2 ml vial'): 6, + } self.item_codes_lab_consumables['maternal_sepsis_optional'] = \ - get_list_of_items(self, ['Cannula iv (winged with injection pot) 18_each_CMST', - 'Oxygen, 1000 liters, primarily with oxygen cylinders', - 'Paracetamol, tablet, 500 mg', - 'Giving set iv administration + needle 15 drops/ml_each_CMST', - 'Foley catheter', - 'Bag, urine, collecting, 2000 ml', - 'Disposables gloves, powder free, 100 pieces per box', - 'Complete blood count']) - + {ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Oxygen, 1000 liters, primarily with oxygen cylinders'): 23_040, + ic('Paracetamol, tablet, 500 mg'): 8000, + ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Foley catheter'): 1, + ic('Bag, urine, collecting, 2000 ml'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1, + ic('Complete blood count'): 1, + } # ------------------------------------- ACTIVE MANAGEMENT THIRD STAGE --------------------------------------- - self.item_codes_lab_consumables['amtsl'] = \ - get_list_of_items(self, ['Oxytocin, injection, 10 IU in 1 ml ampoule']) + self.item_codes_lab_consumables['amtsl'] = {ic('Oxytocin, injection, 10 IU in 1 ml ampoule'): 1} # ------------------------------------- POSTPARTUM HAEMORRHAGE --------------------------------------- self.item_codes_lab_consumables['pph_core'] = \ - get_list_of_items(self, ['Oxytocin, injection, 10 IU in 1 ml ampoule']) + {ic('Oxytocin, injection, 10 IU in 1 ml ampoule'): 5} self.item_codes_lab_consumables['pph_optional'] = \ - get_list_of_items(self, ['Misoprostol, tablet, 200 mcg', - 'Pethidine, 50 mg/ml, 2 ml ampoule', - 'Oxygen, 1000 liters, primarily with oxygen cylinders', - 'Cannula iv (winged with injection pot) 18_each_CMST', - 'Bag, urine, collecting, 2000 ml', - 'Foley catheter', - 'Giving set iv administration + needle 15 drops/ml_each_CMST', - 'Disposables gloves, powder free, 100 pieces per box', - 'Complete blood count']) + {ic('Misoprostol, tablet, 200 mcg'): 600, + ic('Pethidine, 50 mg/ml, 2 ml ampoule'): 6, + ic('Oxygen, 1000 liters, primarily with oxygen cylinders'): 23_040, + ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Foley catheter'): 1, + ic('Bag, urine, collecting, 2000 ml'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1, + ic('Complete blood count'): 1, + } # ------------------------------------- BLOOD TRANSFUSION --------------------------------------- - self.item_codes_lab_consumables['blood_transfusion'] = get_list_of_items(self, ['Blood, one unit']) + self.item_codes_lab_consumables['blood_transfusion'] = {ic('Blood, one unit'): 2} # ------------------------------------------ FULL BLOOD COUNT ------------------------------------------------- - self.item_codes_lab_consumables['hb_test'] = get_list_of_items(self, ['Haemoglobin test (HB)']) + self.item_codes_lab_consumables['hb_test'] = {ic('Haemoglobin test (HB)'): 1} # ---------------------------------- IRON AND FOLIC ACID ------------------------------------------------------ + # Dose changes at run time self.item_codes_lab_consumables['iron_folic_acid'] = \ - get_item_code_from_pkg('Ferrous Salt + Folic Acid, tablet, 200 + 0.25 mg') + {ic('Ferrous Salt + Folic Acid, tablet, 200 + 0.25 mg'): 1} # -------------------------------------------- RESUSCITATION ------------------------------------------ - self.item_codes_lab_consumables['resuscitation'] = \ - get_list_of_items(self, ['Infant resuscitator, clear plastic + mask + bag_each_CMST']) + self.item_codes_lab_consumables['resuscitation'] =\ + {ic('Infant resuscitator, clear plastic + mask + bag_each_CMST'): 1} def initialise_simulation(self, sim): # Update self.current_parameters @@ -1658,7 +1673,9 @@ def prophylactic_labour_interventions(self, hsi_event): # If she has not already receive antibiotics, we check for consumables avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_lab_consumables, core='abx_for_prom', optional='iv_drug_equipment') + self, hsi_event, + cons=self.item_codes_lab_consumables['abx_for_prom'], + opt_cons=self.item_codes_lab_consumables['iv_drug_equipment']) # Then query if these consumables are available during this HSI And provide if available. # Antibiotics for from reduce risk of newborn sepsis within the first @@ -1672,8 +1689,9 @@ def prophylactic_labour_interventions(self, hsi_event): mni[person_id]['labour_state'] == 'late_preterm_labour': avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_lab_consumables, core='antenatal_steroids', - optional='iv_drug_equipment') + self, hsi_event, + cons=self.item_codes_lab_consumables['antenatal_steroids'], + opt_cons=self.item_codes_lab_consumables['iv_drug_equipment']) # If available they are given. Antenatal steroids reduce a preterm newborns chance of developing # respiratory distress syndrome and of death associated with prematurity @@ -1735,8 +1753,9 @@ def assessment_and_treatment_of_severe_pre_eclampsia_mgso4(self, hsi_event, labo # Define and check for the required consumables avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_lab_consumables, core='magnesium_sulfate', - optional='eclampsia_management_optional') + self, hsi_event, + cons=self.item_codes_lab_consumables['magnesium_sulfate'], + opt_cons=self.item_codes_lab_consumables['eclampsia_management_optional']) # If the consumables are available - the intervention is delivered. IV magnesium reduces the # probability that a woman with severe pre-eclampsia will experience eclampsia in labour @@ -1764,8 +1783,9 @@ def assessment_and_treatment_of_hypertension(self, hsi_event, labour_stage): # Then query if these consumables are available during this HSI avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_lab_consumables, core='iv_antihypertensives', - optional='iv_drug_equipment') + self, hsi_event, + cons=self.item_codes_lab_consumables['iv_antihypertensives'], + opt_cons=self.item_codes_lab_consumables['iv_drug_equipment']) # If they are available then the woman is started on treatment. Intravenous antihypertensive reduce a # womans risk of progression from mild to severe gestational hypertension ANd reduce risk of death for @@ -1779,8 +1799,9 @@ def assessment_and_treatment_of_hypertension(self, hsi_event, labour_stage): elif (labour_stage == 'pp') and (df.at[person_id, 'pn_htn_disorders'] == 'severe_gest_htn'): df.at[person_id, 'pn_htn_disorders'] = 'gest_htn' - avail = hsi_event.get_consumables( - item_codes=self.item_codes_lab_consumables['oral_antihypertensives']) + dose = (7 * 4) * 6 # approximating 4 tablets a day, for 6 weeks + cons = {_i: dose for _i in self.item_codes_lab_consumables['oral_antihypertensives']} + avail = hsi_event.get_consumables(item_codes=cons) if avail: df.at[person_id, 'la_gest_htn_on_treatment'] = True @@ -1811,8 +1832,9 @@ def assessment_and_treatment_of_eclampsia(self, hsi_event, labour_stage): # define and check required consumables avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_lab_consumables, core='magnesium_sulfate', - optional='eclampsia_management_optional') + self, hsi_event, + cons=self.item_codes_lab_consumables['magnesium_sulfate'], + opt_cons=self.item_codes_lab_consumables['eclampsia_management_optional']) if (labour_stage == 'ip') and (df.at[person_id, 'ac_admitted_for_immediate_delivery'] == 'none'): self.determine_delivery_mode_in_spe_or_ec(person_id, hsi_event, 'ec') @@ -1858,14 +1880,18 @@ def refer_for_cs(): # If the general package is available AND the facility has the correct tools to carry out the # delivery then it can occur avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_lab_consumables, core='vacuum', - optional='obstructed_labour') + self, hsi_event, + cons=self.item_codes_lab_consumables['vacuum'], + opt_cons=self.item_codes_lab_consumables['obstructed_labour']) # run HCW check sf_check = pregnancy_helper_functions.check_emonc_signal_function_will_run(self, sf='avd', hsi_event=hsi_event) if avail and sf_check: + # Add used equipment + hsi_event.add_equipment({'Delivery Forceps', 'Vacuum extractor'}) + pregnancy_helper_functions.log_met_need(self, f'avd_{indication}', hsi_event) # If AVD was successful then we record the mode of delivery. We use this variable to reduce @@ -1911,8 +1937,9 @@ def assessment_and_treatment_of_maternal_sepsis(self, hsi_event, labour_stage): # Define and check available consumables avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_lab_consumables, core='maternal_sepsis_core', - optional='maternal_sepsis_optional') + self, hsi_event, + cons=self.item_codes_lab_consumables['maternal_sepsis_core'], + opt_cons=self.item_codes_lab_consumables['maternal_sepsis_optional']) # If delivered this intervention reduces a womans risk of dying from sepsis if avail and sf_check: @@ -1990,7 +2017,9 @@ def active_management_of_the_third_stage_of_labour(self, hsi_event): # Define and check available consumables avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_lab_consumables, core='amtsl', optional='iv_drug_equipment') + self, hsi_event, + cons=self.item_codes_lab_consumables['amtsl'], + opt_cons=self.item_codes_lab_consumables['iv_drug_equipment']) # run HCW check sf_check = pregnancy_helper_functions.check_emonc_signal_function_will_run(self, sf='uterotonic', @@ -2021,7 +2050,9 @@ def assessment_and_treatment_of_pph_uterine_atony(self, hsi_event): # Define and check available consumables avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_lab_consumables, core='pph_core', optional='pph_optional') + self, hsi_event, + cons=self.item_codes_lab_consumables['pph_core'], + opt_cons=self.item_codes_lab_consumables['pph_optional']) # run HCW check sf_check = pregnancy_helper_functions.check_emonc_signal_function_will_run(self, sf='uterotonic', @@ -2104,23 +2135,28 @@ def surgical_management_of_pph(self, hsi_event): # We log the required consumables and condition the surgery happening on the availability of the # first consumable in this package, the anaesthetic required for the surgery avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_lab_consumables, core='obstetric_surgery_core', - optional='obstetric_surgery_optional') + self, hsi_event, + cons=self.item_codes_lab_consumables['obstetric_surgery_core'], + opt_cons=self.item_codes_lab_consumables['obstetric_surgery_optional']) # run HCW check sf_check = pregnancy_helper_functions.check_emonc_signal_function_will_run(self, sf='surg', hsi_event=hsi_event) - # determine if uterine preserving surgery will be successful - treatment_success_pph = params['success_rate_pph_surgery'] > self.rng.random_sample() + if avail and sf_check: + # Add used equipment + hsi_event.add_equipment(hsi_event.healthcare_system.equipment.from_pkg_names('Major Surgery')) - # If resources are available and the surgery is a success then a hysterectomy does not occur - if treatment_success_pph and avail and sf_check: - self.pph_treatment.set(person_id, 'surgery') + # determine if uterine preserving surgery will be successful + treatment_success_pph = params['success_rate_pph_surgery'] > self.rng.random_sample() - elif not treatment_success_pph and avail and sf_check: - self.pph_treatment.set(person_id, 'hysterectomy') - df.at[person_id, 'la_has_had_hysterectomy'] = True + if treatment_success_pph: + self.pph_treatment.set(person_id, 'surgery') + else: + # If the treatment is unsuccessful then women will require a hysterectomy to stop the bleeding + hsi_event.add_equipment({'Hysterectomy set'}) + self.pph_treatment.set(person_id, 'hysterectomy') + df.at[person_id, 'la_has_had_hysterectomy'] = True # log intervention delivery if self.pph_treatment.has_all(person_id, 'surgery') or df.at[person_id, 'la_has_had_hysterectomy']: @@ -2140,14 +2176,17 @@ def blood_transfusion(self, hsi_event): # Check consumables avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_lab_consumables, core='blood_transfusion', number=2, - optional='iv_drug_equipment') + self, hsi_event, + cons=self.item_codes_lab_consumables['blood_transfusion'], + opt_cons=self.item_codes_lab_consumables['iv_drug_equipment']) # check HCW sf_check = pregnancy_helper_functions.check_emonc_signal_function_will_run(self, sf='blood_tran', hsi_event=hsi_event) if avail and sf_check: + hsi_event.add_equipment({'Drip stand', 'Infusion pump'}) + mni[person_id]['received_blood_transfusion'] = True pregnancy_helper_functions.log_met_need(self, 'blood_tran', hsi_event) @@ -2171,6 +2210,9 @@ def assessment_and_treatment_of_anaemia(self, hsi_event): mother = df.loc[person_id] mni = self.sim.modules['PregnancySupervisor'].mother_and_newborn_info + # Add used equipment + hsi_event.add_equipment({'Analyser, Haematology'}) + # Use dx_test function to assess anaemia status test_result = self.sim.modules['HealthSystem'].dx_manager.run_dx_test( dx_tests_to_run='full_blood_count_hb_pn', hsi_event=hsi_event) @@ -2290,6 +2332,34 @@ def run_if_receives_comprehensive_emergency_obstetric_care_cant_run(self, hsi_ev if hsi_event.timing == 'postpartum': self.apply_risk_of_early_postpartum_death(person_id) + def do_at_generic_first_appt_emergency( + self, + person_id: int, + individual_properties: IndividualProperties, + schedule_hsi_event: HSIEventScheduler, + **kwargs, + ) -> None: + mni = self.sim.modules["PregnancySupervisor"].mother_and_newborn_info + labour_list = self.sim.modules["Labour"].women_in_labour + + if person_id in labour_list: + la_currently_in_labour = individual_properties["la_currently_in_labour"] + if ( + la_currently_in_labour + & mni[person_id]["sought_care_for_complication"] + & (mni[person_id]["sought_care_labour_phase"] == "intrapartum") + ): + event = HSI_Labour_ReceivesSkilledBirthAttendanceDuringLabour( + module=self, + person_id=person_id, + facility_level_of_this_hsi=self.rng.choice(["1a", "1b"]), + ) + schedule_hsi_event( + event, + priority=0, + topen=self.sim.date, + tclose=self.sim.date + pd.DateOffset(days=1), + ) class LabourOnsetEvent(Event, IndividualScopeEventMixin): """ @@ -2865,8 +2935,14 @@ def apply(self, person_id, squeeze_factor): # LOG CONSUMABLES FOR DELIVERY... # We assume all deliveries require this basic package of consumables avail = pregnancy_helper_functions.return_cons_avail( - self.module, self, self.module.item_codes_lab_consumables, core='delivery_core', - optional='delivery_optional') + self.module, self, + cons=self.module.item_codes_lab_consumables['delivery_core'], + opt_cons=self.module.item_codes_lab_consumables['delivery_optional']) + + # Add used equipment + self.add_equipment({'Delivery set', 'Weighing scale', 'Stethoscope, foetal, monaural, Pinard, plastic', + 'Resuscitaire', 'Sphygmomanometer', 'Tray, emergency', 'Suction machine', + 'Thermometer', 'Drip stand', 'Infusion pump'}) # If the clean delivery kit consumable is available, we assume women benefit from clean delivery if avail: @@ -2942,7 +3018,7 @@ def apply(self, person_id, squeeze_factor): # TODO: potential issue is that this consumable is being logged now for every birth as opposed to # for each birth where resuscitation of the newborn is required avail = pregnancy_helper_functions.return_cons_avail( - self.module, self, self.module.item_codes_lab_consumables, core='resuscitation') + self.module, self, cons=self.module.item_codes_lab_consumables['resuscitation'], opt_cons=None) # Run HCW check sf_check = pregnancy_helper_functions.check_emonc_signal_function_will_run(self.module, @@ -3161,8 +3237,9 @@ def apply(self, person_id, squeeze_factor): # We log the required consumables and condition the caesarean happening on the availability of the # first consumable in this package, the anaesthetic required for the surgery avail = pregnancy_helper_functions.return_cons_avail( - self.module, self, self.module.item_codes_lab_consumables, core='caesarean_delivery_core', - optional='caesarean_delivery_optional') + self.module, self, + cons=self.module.item_codes_lab_consumables['caesarean_delivery_core'], + opt_cons=self.module.item_codes_lab_consumables['caesarean_delivery_optional']) # We check that the HCW will deliver the intervention sf_check = pregnancy_helper_functions.check_emonc_signal_function_will_run(self.module, sf='surg', @@ -3173,6 +3250,9 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='message', data="cs delivery blocked for this analysis") elif (avail and sf_check) or (mni[person_id]['cs_indication'] == 'other'): + # If intervention is delivered - add used equipment + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('Major Surgery')) + person = df.loc[person_id] logger.info(key='caesarean_delivery', data=person.to_dict()) logger.info(key='cs_indications', data={'id': person_id, @@ -3206,6 +3286,7 @@ def apply(self, person_id, squeeze_factor): # Unsuccessful repair will lead to this woman requiring a hysterectomy. Hysterectomy will also reduce # risk of death from uterine rupture but leads to permanent infertility in the simulation else: + self.add_equipment({'Hysterectomy set'}) df.at[person_id, 'la_has_had_hysterectomy'] = True # ============================= SURGICAL MANAGEMENT OF POSTPARTUM HAEMORRHAGE================================== diff --git a/src/tlo/methods/malaria.py b/src/tlo/methods/malaria.py index b660d102c5..3e273245eb 100644 --- a/src/tlo/methods/malaria.py +++ b/src/tlo/methods/malaria.py @@ -4,26 +4,33 @@ including the malaria RDT using DxTest """ +from __future__ import annotations from pathlib import Path +from typing import TYPE_CHECKING, List, Literal, Optional, Union import pandas as pd -from tlo import DateOffset, Module, Parameter, Property, Types, logging +from tlo import Date, DateOffset, Module, Parameter, Property, Types, logging from tlo.events import Event, IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.lm import LinearModel, Predictor from tlo.methods import Metadata from tlo.methods.causes import Cause from tlo.methods.dxmanager import DxTest -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom from tlo.util import random_date +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import DiagnosisFunction, HSIEventScheduler + from tlo.population import IndividualProperties + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -class Malaria(Module): +class Malaria(Module, GenericFirstAppointmentsMixin): def __init__(self, name=None, resourcefilepath=None): """Create instance of Malaria module @@ -43,9 +50,7 @@ def __init__(self, name=None, resourcefilepath=None): 'Contraception', 'Demography', 'HealthSystem', 'SymptomManager' } - OPTIONAL_INIT_DEPENDENCIES = {'HealthBurden'} - - ADDITIONAL_DEPENDENCIES = {'Hiv', 'Tb'} + OPTIONAL_INIT_DEPENDENCIES = {'HealthBurden', 'Hiv'} METADATA = { Metadata.DISEASE_MODULE, @@ -183,12 +188,26 @@ def __init__(self, name=None, resourcefilepath=None): 'prob_of_treatment_success': Parameter( 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" + ), + "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, + "the parameters and values changed in scenario analysis" ) - } PROPERTIES = { - 'ma_is_infected': Property(Types.BOOL, 'Current status of malaria'), + 'ma_is_infected': Property( + Types.BOOL, 'Current status of malaria, infected with malaria parasitaemia' + ), 'ma_date_infected': Property(Types.DATE, 'Date of latest infection'), 'ma_date_symptoms': Property( Types.DATE, 'Date of symptom start for clinical infection' @@ -235,11 +254,15 @@ def read_parameters(self, data_folder): p['sev_symp_prob'] = workbook['severe_symptoms'] p['rdt_testing_rates'] = workbook['WHO_TestData2023'] + p['highrisk_districts'] = workbook['highrisk_districts'] p['inf_inc'] = pd.read_csv(self.resourcefilepath / 'malaria' / 'ResourceFile_malaria_InfInc_expanded.csv') p['clin_inc'] = pd.read_csv(self.resourcefilepath / 'malaria' / 'ResourceFile_malaria_ClinInc_expanded.csv') 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() + # check itn projected values are <=0.7 and rounded to 1dp for matching to incidence tables p['itn'] = round(p['itn'], 1) assert (p['itn'] <= 0.7) @@ -349,7 +372,7 @@ def pre_initialise_population(self): p['rr_severe_malaria_hiv_over5']), Predictor().when('(hv_inf == True) & (is_pregnant == True)', p['rr_severe_malaria_hiv_pregnant']), - ] if "hiv" in self.sim.modules else [] + ] if "Hiv" in self.sim.modules else [] self.lm["rr_of_severe_malaria"] = LinearModel.multiplicative( *(predictors + conditional_predictors)) @@ -405,9 +428,11 @@ def malaria_poll2(self, population): def _draw_incidence_for(_col, _where): """a helper function to perform random draw for selected individuals on column of probabilities""" # create an index from the individuals to lookup entries in the current incidence table - district_age_subset = df.loc[_where, ['district_num_of_residence', 'ma_age_edited']] - district_age_subset.set_index(district_age_subset.columns.to_list(), inplace=True) - district_age_lookup = district_age_subset.index + district_age_lookup = ( + df[_where] + .set_index(['district_num_of_residence', 'ma_age_edited']) + .index + ) # get the monthly incidence probabilities for these individuals monthly_prob = curr_inc.loc[district_age_lookup, _col] # update the index so it's the same as the original population dataframe for these individuals @@ -427,7 +452,7 @@ def _draw_incidence_for(_col, _where): df.loc[_where] ) - random_draw = rng.random_sample(_where.sum()) < monthly_prob * individual_risk + random_draw = rng.random_sample(_where.sum()) < (monthly_prob * individual_risk) selected = _where & random_draw @@ -442,7 +467,8 @@ def _draw_incidence_for(_col, _where): df.loc[alive_over_one, 'ma_age_edited'] = df.loc[alive_over_one, 'age_years'].astype(float) # select new infections - alive_uninfected = alive & ~df.ma_is_infected + # eligible: uninfected or asym + alive_uninfected = alive & df.ma_inf_type.isin(['none', 'asym']) now_infected = _draw_incidence_for('monthly_prob_inf', alive_uninfected) df.loc[now_infected, 'ma_inf_type'] = 'asym' @@ -524,8 +550,12 @@ def general_population_rdt_scheduler(self, population): # extract annual testing rates from NMCP reports # this is the # rdts issued divided by population size - test_rates = p['rdt_testing_rates'].set_index('Year')['Rate_rdt_testing'].dropna() - rdt_rate = test_rates.loc[min(test_rates.index.max(), self.sim.date.year)] / 12 + year = self.sim.date.year if self.sim.date.year <= 2024 else 2024 + + test_rates = ( + p['rdt_testing_rates'].set_index('Year')['Rate_rdt_testing'].dropna() + ) + rdt_rate = test_rates.loc[min(test_rates.index.max(), year)] / 12 # adjust rdt usage reported rate to reflect consumables availability rdt_rate = rdt_rate * p['scaling_factor_for_rdt_availability'] @@ -568,6 +598,12 @@ def initialise_simulation(self, sim): sim.schedule_event(MalariaTxLoggingEvent(self), sim.date + DateOffset(years=1)) sim.schedule_event(MalariaPrevDistrictLoggingEvent(self), sim.date + DateOffset(months=1)) + # Optional: Schedule the scale-up of programs + if self.parameters["do_scaleup"]: + 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) + # 2) ----------------------------------- DIAGNOSTIC TESTS ----------------------------------- # Create the diagnostic test representing the use of RDT for malaria diagnosis # and registers it with the Diagnostic Test Manager @@ -616,7 +652,56 @@ def initialise_simulation(self, sim): # malaria IPTp for pregnant women self.item_codes_for_consumables_required['malaria_iptp'] = get_item_code( - 'Sulfamethoxazole + trimethropin, tablet 400 mg + 80 mg') + 'Sulfamethoxazole + trimethropin, tablet 400 mg + 80 mg' + ) + + def update_parameters_for_program_scaleup(self): + + p = self.parameters + scaled_params = p["scaleup_parameters"] + + if p["do_scaleup"]: + + # scale-up malaria program + # increase testing + # prob_malaria_case_tests=0.4 default + p["prob_malaria_case_tests"] = scaled_params["prob_malaria_case_tests"] + + # gen pop testing rates + # annual Rate_rdt_testing=0.64 at 2023 + p["rdt_testing_rates"]["Rate_rdt_testing"] = scaled_params["rdt_testing_rates"] + + # treatment reaches XX + # no default between testing and treatment, governed by tx availability + + # coverage IPTp reaches XX + # given during ANC visits and MalariaIPTp Event which selects ALL eligible women + + # treatment success reaches 1 - default is currently 1 also + p["prob_of_treatment_success"] = scaled_params["prob_of_treatment_success"] + + # bednet and ITN coverage + # set IRS for 4 high-risk districts + # lookup table created in malaria read_parameters + # produces self.itn_irs called by malaria poll to draw incidence + # need to overwrite this + highrisk_distr_num = p["highrisk_districts"]["district_num"] + + # Find indices where District_Num is in highrisk_distr_num + mask = self.itn_irs['irs_rate'].index.get_level_values('District_Num').isin( + highrisk_distr_num) + + # IRS values can be 0 or 0.8 - no other value in lookup table + self.itn_irs['irs_rate'].loc[mask] = scaled_params["irs_district"] + + # set ITN for all districts + # Set these values to 0.7 - this is the max value possible in lookup table + # equivalent to 0.7 of all pop sleeping under bednet + # household coverage could be 100%, but not everyone in household sleeping under bednet + self.itn_irs['itn_rate'] = scaled_params["itn_district"] + + # itn rates for 2019 onwards + p["itn"] = scaled_params["itn"] def on_birth(self, mother_id, child_id): df = self.sim.population.props @@ -662,100 +747,133 @@ def report_daly_values(self): return health_values.loc[df.is_alive] # returns the series - def check_if_fever_is_caused_by_malaria(self, person_id, hsi_event): - """Run by an HSI when an adult presents with fever""" + def check_if_fever_is_caused_by_malaria( + self, + true_malaria_infection_type: str, + diagnosis_function: DiagnosisFunction, + person_id: Optional[int] = None, + fever_is_a_symptom: Optional[bool] = True, + patient_age: Optional[Union[int, float]] = None, + facility_level: Optional[str] = None, + treatment_id: Optional[str] = None, + ) -> Literal["severe_malaria", "clinical_malaria", "negative_malaria_test"]: + """ + Run by an HSI when an adult presents with fever. + Determine if the cause is malaria. + Optional arguments are used by the logger, + and are not needed in the diagnosis. + """ # Call the DxTest RDT to diagnose malaria - dx_result = self.sim.modules['HealthSystem'].dx_manager.run_dx_test( - dx_tests_to_run='malaria_rdt', - hsi_event=hsi_event - ) + dx_result = diagnosis_function('malaria_rdt') # Log the test: line-list of summary information about each test - fever_present = 'fever' in self.sim.modules["SymptomManager"].has_what(person_id) - person_details_for_test = { - 'person_id': person_id, - 'age': self.sim.population.props.at[person_id, 'age_years'], - 'fever_present': fever_present, - 'rdt_result': dx_result, - 'facility_level': hsi_event.ACCEPTED_FACILITY_LEVEL, - 'called_by': hsi_event.TREATMENT_ID - } - logger.info(key='rdt_log', data=person_details_for_test) - - # get facility level from hsi_event - - true_malaria_infection_type = self.sim.population.props.at[person_id, 'ma_inf_type'] + logger.info( + key="rdt_log", + data={ + "person_id": person_id, + "age": patient_age, + "fever_present": fever_is_a_symptom, + "rdt_result": dx_result, + "facility_level": facility_level, + "called_by": treatment_id, + }, + ) - # severe malaria infection always returns positive RDT + # Severe malaria infection always returns positive RDT if true_malaria_infection_type == 'severe': return 'severe_malaria' - elif dx_result and true_malaria_infection_type in ('clinical', 'asym'): return 'clinical_malaria' - else: return 'negative_malaria_test' - def do_for_suspected_malaria_case(self, person_id, hsi_event): - """ - :param person_id: - :param hsi_event: - :return: - - This is called for a person (of any age) that attends non-emergency generic HSI and has - any symptoms suggestive of malaria """ - - df = self.sim.population.props - - if df.at[person_id, 'ma_tx'] == 'none': - malaria_test_result = self.check_if_fever_is_caused_by_malaria(person_id=person_id, hsi_event=hsi_event) - + def do_at_generic_first_appt( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + diagnosis_function: DiagnosisFunction, + facility_level: str, + treatment_id: str, + **kwargs, + ) -> None: + malaria_associated_symptoms = { + "fever", + "headache", + "stomachache", + "diarrhoea", + "vomiting", + } + if ( + bool(set(symptoms) & malaria_associated_symptoms) + and individual_properties["ma_tx"] == "none" + ): + malaria_test_result = self.check_if_fever_is_caused_by_malaria( + true_malaria_infection_type=individual_properties["ma_inf_type"], + diagnosis_function=diagnosis_function, + person_id=person_id, + fever_is_a_symptom="fever" in symptoms, + patient_age=individual_properties["age_years"], + facility_level=facility_level, + treatment_id=treatment_id, + ) # Treat / refer based on diagnosis - if malaria_test_result == 'severe_malaria': - df.at[person_id, 'ma_dx_counter'] += 1 - self.sim.modules['HealthSystem'].schedule_hsi_event( - HSI_Malaria_Treatment_Complicated( - person_id=person_id, - module=self), - priority=0, - topen=self.sim.date, - tclose=None) + if malaria_test_result == "severe_malaria": + individual_properties["ma_dx_counter"] += 1 + event = HSI_Malaria_Treatment_Complicated(person_id=person_id, module=self) + schedule_hsi_event( + event, priority=0, topen=self.sim.date + ) # return type 'clinical_malaria' includes asymptomatic infection - elif malaria_test_result == 'clinical_malaria': - df.at[person_id, 'ma_dx_counter'] += 1 - self.sim.modules['HealthSystem'].schedule_hsi_event( - HSI_Malaria_Treatment( - person_id=person_id, - module=self), - priority=1, - topen=self.sim.date, - tclose=None) - - def do_on_emergency_presentation_with_severe_malaria(self, person_id, hsi_event): - """This is called for a person (of any age) that attends an emergency generic HSI and has a fever. - (Quick diagnosis algorithm - just perfectly recognises the symptoms of severe malaria.) - """ - df = self.sim.population.props - - if df.at[person_id, 'ma_tx'] == 'none': - # Check if malaria parasitaemia: - malaria_test_result = self.check_if_fever_is_caused_by_malaria(person_id=person_id, hsi_event=hsi_event) - - # if any symptoms indicative of malaria and they have parasitaemia (would return a positive rdt) - if malaria_test_result in ('severe_malaria', 'clinical_malaria'): - df.at[person_id, 'ma_dx_counter'] += 1 + elif malaria_test_result == "clinical_malaria": + individual_properties["ma_dx_counter"] += 1 + event = HSI_Malaria_Treatment(person_id=person_id, module=self) + schedule_hsi_event( + event, priority=1, topen=self.sim.date + ) - # Launch the HSI for treatment for Malaria, HSI_Malaria_Treatment will determine correct treatment - self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=HSI_Malaria_Treatment_Complicated( - person_id=person_id, - module=self), - priority=0, - topen=self.sim.date, + def do_at_generic_first_appt_emergency( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + diagnosis_function: DiagnosisFunction, + facility_level: str, + treatment_id: str, + **kwargs, + ) -> None: + # This is called for a person (of any age) that attends an + # emergency generic HSI and has a fever. + # (Quick diagnosis algorithm - just perfectly recognises the + # symptoms of severe malaria.) + if 'severe_malaria' in symptoms: + if individual_properties["ma_tx"] == 'none': + # Check if malaria parasitaemia: + malaria_test_result = self.check_if_fever_is_caused_by_malaria( + true_malaria_infection_type=individual_properties["ma_inf_type"], + diagnosis_function=diagnosis_function, + person_id=person_id, + fever_is_a_symptom="fever" in symptoms, + patient_age=individual_properties["age_years"], + facility_level=facility_level, + treatment_id=treatment_id, ) + # if any symptoms indicative of malaria and they have parasitaemia (would return a positive rdt) + if malaria_test_result in ('severe_malaria', 'clinical_malaria'): + individual_properties['ma_dx_counter'] += 1 + + # Launch the HSI for treatment for Malaria, HSI_Malaria_Treatment will determine correct treatment + event = HSI_Malaria_Treatment_Complicated( + person_id=person_id, module=self, + ) + schedule_hsi_event( + event, priority=0, topen=self.sim.date + ) class MalariaPollingEventDistrict(RegularEvent, PopulationScopeEventMixin): """ @@ -776,6 +894,21 @@ def apply(self, population): self.module.general_population_rdt_scheduler(population) +class MalariaScaleUpEvent(Event, PopulationScopeEventMixin): + """ This event exists to change parameters or functions + depending on the scenario for projections which has been set + It only occurs once on date: scaleup_start_date, + called by initialise_simulation + """ + + def __init__(self, module): + super().__init__(module) + + def apply(self, population): + + self.module.update_parameters_for_program_scaleup() + + class MalariaIPTp(RegularEvent, PopulationScopeEventMixin): """ malaria prophylaxis for pregnant women @@ -927,7 +1060,7 @@ def apply(self, person_id, squeeze_factor): ) # Log the test: line-list of summary information about each test - fever_present = 'fever' in self.sim.modules["SymptomManager"].has_what(person_id) + fever_present = 'fever' in self.sim.modules["SymptomManager"].has_what(person_id=person_id) person_details_for_test = { 'person_id': person_id, 'age': df.at[person_id, 'age_years'], @@ -1019,7 +1152,7 @@ def apply(self, person_id, squeeze_factor): ) # Log the test: line-list of summary information about each test - fever_present = 'fever' in self.sim.modules["SymptomManager"].has_what(person_id) + fever_present = 'fever' in self.sim.modules["SymptomManager"].has_what(person_id=person_id) person_details_for_test = { 'person_id': person_id, 'age': df.at[person_id, 'age_years'], @@ -1081,7 +1214,7 @@ def apply(self, person_id, squeeze_factor): # rdt is offered as part of the treatment package # Log the test: line-list of summary information about each test - fever_present = 'fever' in self.sim.modules["SymptomManager"].has_what(person_id) + fever_present = 'fever' in self.sim.modules["SymptomManager"].has_what(person_id=person_id) person_details_for_test = { 'person_id': person_id, 'age': df.at[person_id, 'age_years'], @@ -1172,9 +1305,13 @@ def apply(self, person_id, squeeze_factor): df.at[person_id, 'ma_date_tx'] = self.sim.date df.at[person_id, 'ma_tx_counter'] += 1 + # Add used equipment + self.add_equipment({'Drip stand', 'Haemoglobinometer', + 'Analyser, Combined Chemistry and Electrolytes'}) + # rdt is offered as part of the treatment package # Log the test: line-list of summary information about each test - fever_present = 'fever' in self.sim.modules["SymptomManager"].has_what(person_id) + fever_present = 'fever' in self.sim.modules["SymptomManager"].has_what(person_id=person_id) person_details_for_test = { 'person_id': person_id, 'age': df.at[person_id, 'age_years'], @@ -1262,7 +1399,7 @@ def apply(self, population): * assigns symptoms * schedules rdt * cures people currently on treatment for malaria - * clears symptoms for those not on treatment + * clears symptoms for those not on treatment but self-cured * clears parasites if treated """ @@ -1345,14 +1482,22 @@ def apply(self, population): # select people with clinical malaria and treatment for at least 5 days # if treated, will clear symptoms and parasitaemia # this will also clear parasitaemia for asymptomatic cases picked up by routine rdt - clinical_and_treated = df.index[df.is_alive & - (df.ma_date_tx < (self.sim.date - DateOffset(days=5))) & - (df.ma_inf_type == 'clinical')] + random_draw = self.module.rng.random_sample(size=len(df)) + + clinical_and_treated = df.index[ + df.is_alive + & (df.ma_date_tx < (self.sim.date - DateOffset(days=5))) + & (df.ma_inf_type == 'clinical') + & (random_draw < p['prob_of_treatment_success']) + ] # select people with severe malaria and treatment for at least 7 days - severe_and_treated = df.index[df.is_alive & - (df.ma_date_tx < (self.sim.date - DateOffset(days=7))) & - (df.ma_inf_type == 'severe')] + severe_and_treated = df.index[ + df.is_alive + & (df.ma_date_tx < (self.sim.date - DateOffset(days=7))) + & (df.ma_inf_type == 'severe') + & (random_draw < p['prob_of_treatment_success']) + ] # create list of all cases to be resolved through treatment infections_to_clear = sorted(set(clinical_and_treated).union(severe_and_treated)) @@ -1366,13 +1511,14 @@ def apply(self, population): df.loc[infections_to_clear, 'ma_is_infected'] = False df.loc[infections_to_clear, 'ma_inf_type'] = 'none' - # UNTREATED - # if not treated, self-cure occurs after 6 days of symptoms + # UNTREATED or TREATMENT FAILURE + # if not treated or treatment failed, self-cure occurs after 6 days of symptoms # but parasites remain in blood - clinical_not_treated = df.index[df.is_alive & - (df.ma_inf_type == 'clinical') & - (df.ma_date_symptoms < (self.sim.date - DateOffset(days=6))) & - (df.ma_tx == 'none')] + clinical_not_treated = df.index[ + df.is_alive + & (df.ma_inf_type == 'clinical') + & (df.ma_date_symptoms < (self.sim.date - DateOffset(days=6))) + ] self.sim.modules['SymptomManager'].clear_symptoms( person_id=clinical_not_treated, disease_module=self.module diff --git a/src/tlo/methods/measles.py b/src/tlo/methods/measles.py index a52cfd199a..5d2c6dcc53 100644 --- a/src/tlo/methods/measles.py +++ b/src/tlo/methods/measles.py @@ -1,5 +1,8 @@ +from __future__ import annotations + import math import os +from typing import TYPE_CHECKING, List import pandas as pd @@ -7,15 +10,19 @@ from tlo.events import Event, IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.methods import Metadata from tlo.methods.causes import Cause -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom from tlo.util import random_date +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -class Measles(Module): +class Measles(Module, GenericFirstAppointmentsMixin): """This module represents measles infections and disease.""" INIT_DEPENDENCIES = {'Demography', 'HealthSystem', 'SymptomManager'} @@ -203,6 +210,17 @@ def process_parameters(self): assert set(self.symptoms) == set(self.symptom_probs.get(_age).keys()) assert all([0.0 <= x <= 1.0 for x in self.symptom_probs.get(_age).values()]) + def do_at_generic_first_appt( + self, + person_id: int, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs, + ) -> None: + if "rash" in symptoms: + event = HSI_Measles_Treatment(person_id=person_id, module=self) + schedule_hsi_event(event, priority=0, topen=self.sim.date) + class MeaslesEvent(RegularEvent, PopulationScopeEventMixin): """ MeaslesEvent runs every month and creates a number of new infections which are scattered across the month. @@ -424,7 +442,7 @@ def apply(self, person_id, squeeze_factor): data=f"HSI_Measles_Treatment: treat person {person_id} for measles") df = self.sim.population.props - symptoms = self.sim.modules["SymptomManager"].has_what(person_id) + symptoms = self.sim.modules["SymptomManager"].has_what(person_id=person_id) # for non-complicated measles item_codes = [self.module.consumables['vit_A']] @@ -442,6 +460,9 @@ def apply(self, person_id, squeeze_factor): logger.debug(key="HSI_Measles_Treatment", data=f"HSI_Measles_Treatment: giving required measles treatment to person {person_id}") + if "respiratory_symptoms" in symptoms: + self.add_equipment({'Oxygen concentrator', 'Oxygen cylinder, with regulator'}) + # modify person property which is checked when scheduled death occurs (or shouldn't occur) df.at[person_id, "me_on_treatment"] = True diff --git a/src/tlo/methods/mockitis.py b/src/tlo/methods/mockitis.py index 74cb625997..6af33c5fc7 100644 --- a/src/tlo/methods/mockitis.py +++ b/src/tlo/methods/mockitis.py @@ -1,3 +1,6 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, List import pandas as pd @@ -6,14 +9,18 @@ from tlo.methods import Metadata from tlo.methods.causes import Cause from tlo.methods.demography import InstantaneousDeath -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -class Mockitis(Module): +class Mockitis(Module, GenericFirstAppointmentsMixin): """This is a dummy infectious disease. It demonstrates the following behaviours in respect of the healthsystem module: @@ -286,6 +293,20 @@ def report_daly_values(self): return health_values # returns the series + def do_at_generic_first_appt_emergency( + self, + person_id: int, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs, + ) -> None: + # Example for mockitis + if "extreme_pain_in_the_nose" in symptoms: + event = HSI_Mockitis_PresentsForCareWithSevereSymptoms( + module=self, + person_id=person_id, + ) + schedule_hsi_event(event, priority=1, topen=self.sim.date) class MockitisEvent(RegularEvent, PopulationScopeEventMixin): """ diff --git a/src/tlo/methods/newborn_outcomes.py b/src/tlo/methods/newborn_outcomes.py index 513b644746..433b21ca88 100644 --- a/src/tlo/methods/newborn_outcomes.py +++ b/src/tlo/methods/newborn_outcomes.py @@ -8,7 +8,7 @@ from tlo.lm import LinearModel from tlo.methods import Metadata, demography, newborn_outcomes_lm, pregnancy_helper_functions from tlo.methods.causes import Cause -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event from tlo.methods.postnatal_supervisor import PostnatalWeekOneNeonatalEvent from tlo.util import BitsetHandler @@ -265,7 +265,7 @@ def __init__(self, name=None, resourcefilepath=None): 'nb_preterm_birth_disab': Property(Types.CATEGORICAL, 'Disability associated with preterm delivery', categories=['none', 'mild_motor_and_cog', 'mild_motor', 'moderate_motor', 'severe_motor']), - 'nb_congenital_anomaly': Property(Types.INT, 'Types of congenital anomaly of the newborn stored as bitset'), + 'nb_congenital_anomaly': Property(Types.BITSET, 'Types of congenital anomaly of the newborn stored as bitset'), 'nb_early_onset_neonatal_sepsis': Property(Types.BOOL, 'whether this neonate has developed neonatal sepsis' ' following birth'), 'nb_inj_abx_neonatal_sepsis': Property(Types.BOOL, 'If this neonate has injectable antibiotics as treatment ' @@ -377,43 +377,53 @@ def get_and_store_newborn_item_codes(self): This function defines the required consumables for each intervention delivered during this module and stores them in a module level dictionary called within HSIs """ - get_list_of_items = pregnancy_helper_functions.get_list_of_items - - # ---------------------------------- IV DRUG ADMIN EQUIPMENT ------------------------------------------------- - self.item_codes_nb_consumables['iv_drug_equipment'] = \ - get_list_of_items(self, ['Cannula iv (winged with injection pot) 18_each_CMST', - 'Giving set iv administration + needle 15 drops/ml_each_CMST', - 'Disposables gloves, powder free, 100 pieces per box']) + ic = self.sim.modules['HealthSystem'].get_item_code_from_item_name + # First we store the item codes for the consumables for which their quantity varies for individuals based on + # length of pregnancy # ---------------------------------- BLOOD TEST EQUIPMENT --------------------------------------------------- self.item_codes_nb_consumables['blood_test_equipment'] = \ - get_list_of_items(self, ['Disposables gloves, powder free, 100 pieces per box']) + {ic('Blood collecting tube, 5 ml'): 1, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1 + } + # ---------------------------------- IV DRUG ADMIN EQUIPMENT ------------------------------------------------- + self.item_codes_nb_consumables['iv_drug_equipment'] = \ + {ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1 + } # -------------------------------------------- VITAMIN K ------------------------------------------ self.item_codes_nb_consumables['vitamin_k'] = \ - get_list_of_items(self, ['vitamin K1 (phytomenadione) 1 mg/ml, 1 ml, inj._100_IDA']) + {ic('vitamin K1 (phytomenadione) 1 mg/ml, 1 ml, inj._100_IDA'): 1} # -------------------------------------------- EYE CARE ------------------------------------------ - self.item_codes_nb_consumables['eye_care'] = get_list_of_items( - self, ['Tetracycline eye ointment, 1 %, tube 5 mg']) + self.item_codes_nb_consumables['eye_care'] = \ + {ic('Tetracycline eye ointment, 1 %, tube 5 mg'): 5} # ------------------------------------- SEPSIS - FULL SUPPORTIVE CARE --------------------------------------- + # Whilst abx for newborns are weight based the maximum dose does not exceed the minimum unit for the costing + # model self.item_codes_nb_consumables['sepsis_supportive_care_core'] = \ - get_list_of_items(self, ['Benzylpenicillin 1g (1MU), PFR_Each_CMST', - 'Gentamicin 40mg/ml, 2ml_each_CMST', - 'Oxygen, 1000 liters, primarily with oxygen cylinders']) + {ic('Benzylpenicillin 1g (1MU), PFR_Each_CMST'): 1, + ic('Gentamicin 40mg/ml, 2ml_each_CMST'): 1, + ic('Oxygen, 1000 liters, primarily with oxygen cylinders'): 5760 # + } self.item_codes_nb_consumables['sepsis_supportive_care_optional'] = \ - get_list_of_items(self, ['Dextrose (glucose) 5%, 1000ml_each_CMST', - 'Tube, feeding CH 8_each_CMST', - 'Cannula iv (winged with injection pot) 18_each_CMST', - 'Giving set iv administration + needle 15 drops/ml_each_CMST', - 'Disposables gloves, powder free, 100 pieces per box']) + {ic('Dextrose (glucose) 5%, 1000ml_each_CMST'): 500, + ic('Tube, feeding CH 8_each_CMST'): 1, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Disposables gloves, powder free, 100 pieces per box'): 1 + } # ---------------------------------------- SEPSIS - ANTIBIOTICS --------------------------------------------- - self.item_codes_nb_consumables['sepsis_abx'] =\ - get_list_of_items(self, ['Benzylpenicillin 1g (1MU), PFR_Each_CMST', - 'Gentamicin 40mg/ml, 2ml_each_CMST']) + self.item_codes_nb_consumables['sepsis_abx'] = \ + {ic('Benzylpenicillin 1g (1MU), PFR_Each_CMST'): 1, + ic('Gentamicin 40mg/ml, 2ml_each_CMST'): 1, + } def initialise_simulation(self, sim): # For the first period (2010-2015) we use the first value in each list as a parameter @@ -969,23 +979,27 @@ def assessment_and_treatment_newborn_sepsis(self, hsi_event, facility_type): # check consumables avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_nb_consumables, core='sepsis_supportive_care_core', - optional='sepsis_supportive_care_optional') + self, hsi_event, + cons=self.item_codes_nb_consumables['sepsis_supportive_care_core'], + opt_cons=self.item_codes_nb_consumables['sepsis_supportive_care_optional']) # Then, if the consumables are available, treatment for sepsis is delivered if avail and sf_check: df.at[person_id, 'nb_supp_care_neonatal_sepsis'] = True pregnancy_helper_functions.log_met_need(self, 'neo_sep_supportive_care', hsi_event) + hsi_event.add_equipment({'Drip stand', 'Infusion pump'}) # The same pattern is then followed for health centre care else: avail = pregnancy_helper_functions.return_cons_avail( - self, hsi_event, self.item_codes_nb_consumables, core='sepsis_abx', - optional='iv_drug_equipment') + self, hsi_event, + cons=self.item_codes_nb_consumables['sepsis_abx'], + opt_cons=self.item_codes_nb_consumables['iv_drug_equipment']) if avail and sf_check: df.at[person_id, 'nb_inj_abx_neonatal_sepsis'] = True pregnancy_helper_functions.log_met_need(self, 'neo_sep_abx', hsi_event) + hsi_event.add_equipment({'Drip stand', 'Infusion pump', 'Oxygen cylinder, with regulator'}) def link_twins(self, child_one, child_two, mother_id): """ diff --git a/src/tlo/methods/oesophagealcancer.py b/src/tlo/methods/oesophagealcancer.py index fb8e96116c..8adc0614e1 100644 --- a/src/tlo/methods/oesophagealcancer.py +++ b/src/tlo/methods/oesophagealcancer.py @@ -6,8 +6,10 @@ * Perhaps need to add (i) wood burning fire / indoor pollution (ii) white maize flour in diet (both risk factors) * Footprints of HSI -- pending input from expert on resources required. """ +from __future__ import annotations from pathlib import Path +from typing import TYPE_CHECKING, List import pandas as pd @@ -15,17 +17,23 @@ from tlo.events import IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.lm import LinearModel, LinearModelType, Predictor from tlo.methods import Metadata +from tlo.methods.cancer_consumables import get_consumable_item_codes_cancers from tlo.methods.causes import Cause from tlo.methods.demography import InstantaneousDeath from tlo.methods.dxmanager import DxTest -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + from tlo.population import IndividualProperties + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -class OesophagealCancer(Module): +class OesophagealCancer(Module, GenericFirstAppointmentsMixin): """Oesophageal Cancer Disease Module""" def __init__(self, name=None, resourcefilepath=None): @@ -34,6 +42,7 @@ def __init__(self, name=None, resourcefilepath=None): self.linear_models_for_progession_of_oc_status = dict() self.lm_onset_dysphagia = None self.daly_wts = dict() + self.item_codes_oesophageal_can = dict() INIT_DEPENDENCIES = {'Demography', 'HealthSystem', 'Lifestyle', 'SymptomManager'} @@ -355,6 +364,9 @@ def initialise_simulation(self, sim): * Define the Disability-weights * Schedule the palliative care appointments for those that are on palliative care at initiation """ + # We call the following function to store the required consumables for the simulation run within the appropriate + # dictionary + self.item_codes_oesophageal_can = get_consumable_item_codes_cancers(self) # ----- SCHEDULE LOGGING EVENTS ----- # Schedule logging event to happen immediately @@ -565,6 +577,22 @@ def report_daly_values(self): return disability_series_for_alive_persons + def do_at_generic_first_appt( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs, + ) -> None: + # If the symptoms include dysphagia, and the patient is not a child, + # begin investigation for Oesophageal Cancer: + if individual_properties["age_years"] > 5 and "dysphagia" in symptoms: + event = HSI_OesophagealCancer_Investigation_Following_Dysphagia( + person_id=person_id, module=self + ) + schedule_hsi_event(event, priority=0, topen=self.sim.date) + # --------------------------------------------------------------------------------------------------------- # DISEASE MODULE EVENTS @@ -653,49 +681,60 @@ def apply(self, person_id, squeeze_factor): return hs.get_blank_appt_footprint() # Check that this event has been called for someone with the symptom dysphagia - assert 'dysphagia' in self.sim.modules['SymptomManager'].has_what(person_id) + assert 'dysphagia' in self.sim.modules['SymptomManager'].has_what(person_id=person_id) # If the person is already diagnosed, then take no action: if not pd.isnull(df.at[person_id, "oc_date_diagnosis"]): return hs.get_blank_appt_footprint() - # Use an endoscope to diagnose whether the person has Oesophageal Cancer: - dx_result = hs.dx_manager.run_dx_test( - dx_tests_to_run='endoscopy_for_oes_cancer_given_dysphagia', - hsi_event=self - ) - - if dx_result: - # record date of diagnosis: - df.at[person_id, 'oc_date_diagnosis'] = self.sim.date - - # Check if is in stage4: - in_stage4 = df.at[person_id, 'oc_status'] == 'stage4' - # If the diagnosis does detect cancer, it is assumed that the classification as stage4 is made accurately. - - if not in_stage4: - # start treatment: - hs.schedule_hsi_event( - hsi_event=HSI_OesophagealCancer_StartTreatment( - module=self.module, - person_id=person_id - ), - priority=0, - topen=self.sim.date, - tclose=None - ) - - else: - # start palliative care: - hs.schedule_hsi_event( - hsi_event=HSI_OesophagealCancer_PalliativeCare( - module=self.module, - person_id=person_id - ), - priority=0, - topen=self.sim.date, - tclose=None - ) + # Check the consumables are available + cons_avail = self.get_consumables(item_codes=self.module.item_codes_oesophageal_can['screening_endoscopy_core'], + optional_item_codes= + self.module.item_codes_oesophageal_can[ + 'screening_biopsy_endoscopy_cystoscopy_optional']) + + if cons_avail: + # If consumables are available add used equipment and run the dx_test representing the biopsy + # n.b. endoscope not in equipment list + self.add_equipment({'Endoscope', 'Ordinary Microscope'}) + + # Use an endoscope to diagnose whether the person has Oesophageal Cancer: + dx_result = hs.dx_manager.run_dx_test( + dx_tests_to_run='endoscopy_for_oes_cancer_given_dysphagia', + hsi_event=self + ) + if dx_result: + # record date of diagnosis: + df.at[person_id, 'oc_date_diagnosis'] = self.sim.date + + # Check if is in stage4: + in_stage4 = df.at[person_id, 'oc_status'] == 'stage4' + # If the diagnosis does detect cancer, it is assumed that the classification as stage4 is made + # accurately. + + if not in_stage4: + # start treatment: + hs.schedule_hsi_event( + hsi_event=HSI_OesophagealCancer_StartTreatment( + module=self.module, + person_id=person_id + ), + priority=0, + topen=self.sim.date, + tclose=None + ) + + else: + # start palliative care: + hs.schedule_hsi_event( + hsi_event=HSI_OesophagealCancer_PalliativeCare( + module=self.module, + person_id=person_id + ), + priority=0, + topen=self.sim.date, + tclose=None + ) class HSI_OesophagealCancer_StartTreatment(HSI_Event, IndividualScopeEventMixin): @@ -740,20 +779,34 @@ def apply(self, person_id, squeeze_factor): assert not pd.isnull(df.at[person_id, "oc_date_diagnosis"]) assert pd.isnull(df.at[person_id, "oc_date_treatment"]) - # Record date and stage of starting treatment - df.at[person_id, "oc_date_treatment"] = self.sim.date - df.at[person_id, "oc_stage_at_which_treatment_applied"] = df.at[person_id, "oc_status"] + # Check consumables are available + cons_avail = self.get_consumables(item_codes=self.module.item_codes_oesophageal_can['treatment_surgery_core'], + optional_item_codes= + self.module.item_codes_oesophageal_can['treatment_surgery_optional']) - # Schedule a post-treatment check for 12 months: - hs.schedule_hsi_event( - hsi_event=HSI_OesophagealCancer_PostTreatmentCheck( - module=self.module, - person_id=person_id, - ), - topen=self.sim.date + DateOffset(years=12), - tclose=None, - priority=0 - ) + if cons_avail: + # If consumables are available and the treatment will go ahead - update the equipment + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('Major Surgery')) + + # Log chemotherapy consumables + self.get_consumables( + item_codes=self.module.item_codes_oesophageal_can['treatment_chemotherapy'], + optional_item_codes=self.module.item_codes_oesophageal_can['iv_drug_cons']) + + # Record date and stage of starting treatment + df.at[person_id, "oc_date_treatment"] = self.sim.date + df.at[person_id, "oc_stage_at_which_treatment_applied"] = df.at[person_id, "oc_status"] + + # Schedule a post-treatment check for 12 months: + hs.schedule_hsi_event( + hsi_event=HSI_OesophagealCancer_PostTreatmentCheck( + module=self.module, + person_id=person_id, + ), + topen=self.sim.date + DateOffset(years=12), + tclose=None, + priority=0 + ) class HSI_OesophagealCancer_PostTreatmentCheck(HSI_Event, IndividualScopeEventMixin): @@ -837,20 +890,28 @@ def apply(self, person_id, squeeze_factor): # Check that the person is in stage4 assert df.at[person_id, "oc_status"] == 'stage4' - # Record the start of palliative care if this is first appointment - if pd.isnull(df.at[person_id, "oc_date_palliative_care"]): - df.at[person_id, "oc_date_palliative_care"] = self.sim.date + # Check consumables are available + cons_available = self.get_consumables( + item_codes=self.module.item_codes_oesophageal_can['palliation']) - # Schedule another instance of the event for one month - hs.schedule_hsi_event( - hsi_event=HSI_OesophagealCancer_PalliativeCare( - module=self.module, - person_id=person_id - ), - topen=self.sim.date + DateOffset(months=1), - tclose=None, - priority=0 - ) + if cons_available: + # If consumables are available and the treatment will go ahead - update the equipment + self.add_equipment({'Infusion pump', 'Drip stand'}) + + # Record the start of palliative care if this is first appointment + if pd.isnull(df.at[person_id, "oc_date_palliative_care"]): + df.at[person_id, "oc_date_palliative_care"] = self.sim.date + + # Schedule another instance of the event for one month + hs.schedule_hsi_event( + hsi_event=HSI_OesophagealCancer_PalliativeCare( + module=self.module, + person_id=person_id + ), + topen=self.sim.date + DateOffset(months=1), + tclose=None, + priority=0 + ) # --------------------------------------------------------------------------------------------------------- diff --git a/src/tlo/methods/other_adult_cancers.py b/src/tlo/methods/other_adult_cancers.py index 508e96c12b..5aad8f971a 100644 --- a/src/tlo/methods/other_adult_cancers.py +++ b/src/tlo/methods/other_adult_cancers.py @@ -4,8 +4,10 @@ Limitations to note: * Footprints of HSI -- pending input from expert on resources required. """ +from __future__ import annotations from pathlib import Path +from typing import TYPE_CHECKING, List import pandas as pd @@ -13,17 +15,23 @@ from tlo.events import IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.lm import LinearModel, LinearModelType, Predictor from tlo.methods import Metadata +from tlo.methods.cancer_consumables import get_consumable_item_codes_cancers from tlo.methods.causes import Cause from tlo.methods.demography import InstantaneousDeath from tlo.methods.dxmanager import DxTest -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + from tlo.population import IndividualProperties + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -class OtherAdultCancer(Module): +class OtherAdultCancer(Module, GenericFirstAppointmentsMixin): """Other Adult Cancers Disease Module""" def __init__(self, name=None, resourcefilepath=None): @@ -32,10 +40,11 @@ def __init__(self, name=None, resourcefilepath=None): self.linear_models_for_progession_of_oac_status = dict() self.lm_onset_early_other_adult_ca_symptom = None self.daly_wts = dict() + self.item_codes_other_can = dict() INIT_DEPENDENCIES = {'Demography', 'HealthSystem', 'SymptomManager'} - OPTIONAL_INIT_DEPENDENCIES = {'HealthBurden'} + OPTIONAL_INIT_DEPENDENCIES = {'HealthBurden', 'Hiv'} METADATA = { Metadata.DISEASE_MODULE, @@ -113,6 +122,9 @@ def __init__(self, name=None, resourcefilepath=None): "rr_site_confined_agege70": Parameter( Types.REAL, "rate ratio for site-confined other_adult cancer for age ge 70" ), + "rr_site_confined_hiv": Parameter( + Types.REAL, "rate ratio for site-confined other_adult_cancer if infected with HIV" + ), "r_local_ln_site_confined_other_adult_ca": Parameter( Types.REAL, "probabilty per 3 months of local ln other_adult cancer amongst people with site confined", @@ -363,6 +375,9 @@ def initialise_simulation(self, sim): * Define the Disability-weights * Schedule the palliative care appointments for those that are on palliative care at initiation """ + # We call the following function to store the required consumables for the simulation run within the appropriate + # dictionary + self.item_codes_other_can = get_consumable_item_codes_cancers(self) # ----- SCHEDULE LOGGING EVENTS ----- # Schedule logging event to happen immediately @@ -381,15 +396,26 @@ def initialise_simulation(self, sim): p = self.parameters lm = self.linear_models_for_progession_of_oac_status - lm['site_confined'] = LinearModel( - LinearModelType.MULTIPLICATIVE, - p['r_site_confined_none'], + predictors = [ Predictor('age_years', conditions_are_mutually_exclusive=True) .when('.between(30,49)', p['rr_site_confined_age3049']) .when('.between(50,69)', p['rr_site_confined_age5069']) .when('.between(0,14)', 0.0) .when('.between(70,120)', p['rr_site_confined_agege70']), Predictor('oac_status').when('none', 1.0).otherwise(0.0) + ] + + conditional_predictors = [ + Predictor().when( + 'hv_inf & ' + '(hv_art != "on_VL_suppressed")', + p["rr_site_confined_hiv"]), + ] if "Hiv" in self.sim.modules else [] + + lm['site_confined'] = LinearModel( + LinearModelType.MULTIPLICATIVE, + p['r_site_confined_none'], + *(predictors + conditional_predictors) ) lm['local_ln'] = LinearModel( @@ -549,6 +575,21 @@ def report_daly_values(self): return disability_series_for_alive_persons + def do_at_generic_first_appt( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs + ) -> None: + if individual_properties["age_years"] > 5 and "early_other_adult_ca_symptom" in symptoms: + event = HSI_OtherAdultCancer_Investigation_Following_early_other_adult_ca_symptom( + person_id=person_id, + module=self, + ) + schedule_hsi_event(event, priority=0, topen=self.sim.date) + # --------------------------------------------------------------------------------------------------------- # DISEASE MODULE EVENTS @@ -644,50 +685,60 @@ def apply(self, person_id, squeeze_factor): return hs.get_blank_appt_footprint() # Check that this event has been called for someone with the symptom other_adult_ca_symptom - assert 'early_other_adult_ca_symptom' in self.sim.modules['SymptomManager'].has_what(person_id) + assert 'early_other_adult_ca_symptom' in self.sim.modules['SymptomManager'].has_what(person_id=person_id) # If the person is already diagnosed, then take no action: if not pd.isnull(df.at[person_id, "oac_date_diagnosis"]): return hs.get_blank_appt_footprint() - # Use a diagnostic_device to diagnose whether the person has other adult cancer: - dx_result = hs.dx_manager.run_dx_test( - dx_tests_to_run='diagnostic_device_for_other_adult_cancer_given_other_adult_ca_symptom', - hsi_event=self - ) + # Check consumables are available + cons_avail = self.get_consumables(item_codes=self.module.item_codes_other_can['screening_biopsy_core'], + optional_item_codes= + self.module.item_codes_other_can[ + 'screening_biopsy_endoscopy_cystoscopy_optional']) - if dx_result: - # record date of diagnosis: - df.at[person_id, 'oac_date_diagnosis'] = self.sim.date - - # Check if is in metastatic: - in_metastatic = df.at[person_id, 'oac_status'] == 'metastatic' - # If the diagnosis does detect cancer, it is assumed that the classification as metastatic is - # made accurately. - - if not in_metastatic: - # start treatment: - hs.schedule_hsi_event( - hsi_event=HSI_OtherAdultCancer_StartTreatment( - module=self.module, - person_id=person_id - ), - priority=0, - topen=self.sim.date, - tclose=None - ) + if cons_avail: + # If consumables are available add used equipment and run the dx_test representing the biopsy + self.add_equipment({'Ultrasound scanning machine', 'Ordinary Microscope'}) - else: - # start palliative care: - hs.schedule_hsi_event( - hsi_event=HSI_OtherAdultCancer_PalliativeCare( - module=self.module, - person_id=person_id - ), - priority=0, - topen=self.sim.date, - tclose=None - ) + # Use a diagnostic_device to diagnose whether the person has other adult cancer: + dx_result = hs.dx_manager.run_dx_test( + dx_tests_to_run='diagnostic_device_for_other_adult_cancer_given_other_adult_ca_symptom', + hsi_event=self + ) + + if dx_result: + # record date of diagnosis: + df.at[person_id, 'oac_date_diagnosis'] = self.sim.date + + # Check if is in metastatic: + in_metastatic = df.at[person_id, 'oac_status'] == 'metastatic' + # If the diagnosis does detect cancer, it is assumed that the classification as metastatic is + # made accurately. + + if not in_metastatic: + # start treatment: + hs.schedule_hsi_event( + hsi_event=HSI_OtherAdultCancer_StartTreatment( + module=self.module, + person_id=person_id + ), + priority=0, + topen=self.sim.date, + tclose=None + ) + + else: + # start palliative care: + hs.schedule_hsi_event( + hsi_event=HSI_OtherAdultCancer_PalliativeCare( + module=self.module, + person_id=person_id + ), + priority=0, + topen=self.sim.date, + tclose=None + ) class HSI_OtherAdultCancer_StartTreatment(HSI_Event, IndividualScopeEventMixin): @@ -731,21 +782,30 @@ def apply(self, person_id, squeeze_factor): assert not pd.isnull(df.at[person_id, "oac_date_diagnosis"]) assert pd.isnull(df.at[person_id, "oac_date_treatment"]) - # Record date and stage of starting treatment - df.at[person_id, "oac_date_treatment"] = self.sim.date - df.at[person_id, "oac_stage_at_which_treatment_given"] = df.at[person_id, "oac_status"] - - # Schedule a post-treatment check for 12 months: - hs.schedule_hsi_event( - hsi_event=HSI_OtherAdultCancer_PostTreatmentCheck( - module=self.module, - person_id=person_id, - ), - topen=self.sim.date + DateOffset(months=3), - tclose=None, - priority=0 + cons_available = self.get_consumables( + item_codes=self.module.item_codes_other_can['treatment_surgery_core'], + optional_item_codes=self.module.item_codes_other_can['treatment_surgery_optional'], ) + if cons_available: + # If consumables are available and the treatment will go ahead - update the equipment + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('Major Surgery')) + + # Record date and stage of starting treatment + df.at[person_id, "oac_date_treatment"] = self.sim.date + df.at[person_id, "oac_stage_at_which_treatment_given"] = df.at[person_id, "oac_status"] + + # Schedule a post-treatment check for 12 months: + hs.schedule_hsi_event( + hsi_event=HSI_OtherAdultCancer_PostTreatmentCheck( + module=self.module, + person_id=person_id, + ), + topen=self.sim.date + DateOffset(months=3), + tclose=None, + priority=0 + ) + def did_not_run(self): pass @@ -835,20 +895,28 @@ def apply(self, person_id, squeeze_factor): # Check that the person is in metastatic assert df.at[person_id, "oac_status"] == 'metastatic' - # Record the start of palliative care if this is first appointment - if pd.isnull(df.at[person_id, "oac_date_palliative_care"]): - df.at[person_id, "oac_date_palliative_care"] = self.sim.date - - # Schedule another instance of the event for one month - hs.schedule_hsi_event( - hsi_event=HSI_OtherAdultCancer_PalliativeCare( - module=self.module, - person_id=person_id - ), - topen=self.sim.date + DateOffset(months=1), - tclose=None, - priority=0 - ) + # Check consumables are available + cons_available = self.get_consumables( + item_codes=self.module.item_codes_other_can['palliation']) + + if cons_available: + # If consumables are available and the treatment will go ahead - update the equipment + self.add_equipment({'Infusion pump', 'Drip stand'}) + + # Record the start of palliative care if this is first appointment + if pd.isnull(df.at[person_id, "oac_date_palliative_care"]): + df.at[person_id, "oac_date_palliative_care"] = self.sim.date + + # Schedule another instance of the event for one month + hs.schedule_hsi_event( + hsi_event=HSI_OtherAdultCancer_PalliativeCare( + module=self.module, + person_id=person_id + ), + topen=self.sim.date + DateOffset(months=1), + tclose=None, + priority=0 + ) def did_not_run(self): pass diff --git a/src/tlo/methods/postnatal_supervisor.py b/src/tlo/methods/postnatal_supervisor.py index 0d16a2d7ac..25bce6013f 100644 --- a/src/tlo/methods/postnatal_supervisor.py +++ b/src/tlo/methods/postnatal_supervisor.py @@ -8,7 +8,7 @@ from tlo.lm import LinearModel from tlo.methods import Metadata, postnatal_supervisor_lm, pregnancy_helper_functions from tlo.methods.causes import Cause -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -1274,24 +1274,28 @@ def apply(self, person_id, squeeze_factor): return # Define the consumables - of_repair_cons = pregnancy_helper_functions.get_list_of_items( - self, ['Scalpel blade size 22 (individually wrapped)_100_CMST', - 'Halothane (fluothane)_250ml_CMST', - 'Ceftriaxone 1g, PFR_each_CMST', - 'Metronidazole 200mg_1000_CMST', - 'Cannula iv (winged with injection pot) 18_each_CMST', - 'Paracetamol, tablet, 500 mg', - 'Declofenac injection_each_CMST', - 'Pethidine, 50 mg/ml, 2 ml ampoule', - 'Foley catheter', - 'Bag, urine, collecting, 2000 ml', - "ringer's lactate (Hartmann's solution), 1000 ml_12_IDA", - 'Sodium chloride, injectable solution, 0,9 %, 500 ml', - "Giving set iv administration + needle 15 drops/ml_each_CMST", - "Chlorhexidine 1.5% solution_5_CMST"]) + ic = self.sim.modules['HealthSystem'].get_item_code_from_item_name + + of_repair_cons = \ + {ic('Scalpel blade size 22 (individually wrapped)_100_CMST'): 1, + ic('Halothane (fluothane)_250ml_CMST'): 100, + ic('Ceftriaxone 1g, PFR_each_CMST'): 2, + ic('Metronidazole 200mg_1000_CMST'): 6000, + ic('Cannula iv (winged with injection pot) 18_each_CMST'): 1, + ic('Paracetamol, tablet, 500 mg'): 8000, + ic('Declofenac injection_each_CMST'): 1, + ic('Foley catheter'): 1, + ic('Bag, urine, collecting, 2000 ml'): 1, + ic("ringer's lactate (Hartmann's solution), 1000 ml_12_IDA"): 2000, + ic('Sodium chloride, injectable solution, 0,9 %, 500 ml'): 2000, + ic('Giving set iv administration + needle 15 drops/ml_each_CMST'): 1, + ic('Chlorhexidine 1.5% solution_5_CMST'): 50, + } self.get_consumables(item_codes=of_repair_cons) + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('Major Surgery')) + # Log the end of disability in the MNI pregnancy_helper_functions.store_dalys_in_mni( person_id, self.sim.modules['PregnancySupervisor'].mother_and_newborn_info, diff --git a/src/tlo/methods/pregnancy_helper_functions.py b/src/tlo/methods/pregnancy_helper_functions.py index 20a712f134..8f7faa0503 100644 --- a/src/tlo/methods/pregnancy_helper_functions.py +++ b/src/tlo/methods/pregnancy_helper_functions.py @@ -21,7 +21,7 @@ def get_list_of_items(self, item_list): return codes -def return_cons_avail(self, hsi_event, cons_dict, **info): +def return_cons_avail(self, hsi_event, cons, opt_cons): """ This function is called by majority of interventions across maternal and neonatal modules to return whether a consumable or package of consumables are available. If analysis is not being conducted (as indicated by a series of @@ -38,21 +38,12 @@ def return_cons_avail(self, hsi_event, cons_dict, **info): ps_params = self.sim.modules['PregnancySupervisor'].current_parameters la_params = self.sim.modules['Labour'].current_parameters - # If 'number' is passed as an optional argument then a predetermined number of consumables will be requested - if 'number' in info.keys(): - core_cons = {cons_dict[info['core']][0]: info['number']} - else: - core_cons = cons_dict[info['core']] - - # If 'optional' is passed then the optional set of consumables is selected from the consumables dict - if 'optional' in info.keys(): - opt_cons = cons_dict[info['optional']] - else: + if opt_cons is None: opt_cons = [] # Check if analysis is currently running, if not then availability is determined normally if not ps_params['ps_analysis_in_progress'] and not la_params['la_analysis_in_progress']: - available = hsi_event.get_consumables(item_codes=core_cons, + available = hsi_event.get_consumables(item_codes=cons, optional_item_codes=opt_cons) if not available and (hsi_event.target in mni) and (hsi_event != 'AntenatalCare_Outpatient'): @@ -61,7 +52,7 @@ def return_cons_avail(self, hsi_event, cons_dict, **info): return available else: - available = hsi_event.get_consumables(item_codes=core_cons, optional_item_codes=opt_cons) + available = hsi_event.get_consumables(item_codes=cons, optional_item_codes=opt_cons) # Depending on HSI calling this function a different parameter set is used to determine if analysis is being # conducted diff --git a/src/tlo/methods/pregnancy_supervisor.py b/src/tlo/methods/pregnancy_supervisor.py index 41c6386021..7dd8819ab6 100644 --- a/src/tlo/methods/pregnancy_supervisor.py +++ b/src/tlo/methods/pregnancy_supervisor.py @@ -1,4 +1,7 @@ +from __future__ import annotations + from pathlib import Path +from typing import TYPE_CHECKING import numpy as np import pandas as pd @@ -18,14 +21,23 @@ from tlo.events import Event, IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.lm import LinearModel from tlo.methods import Metadata, labour, pregnancy_helper_functions, pregnancy_supervisor_lm +from tlo.methods.care_of_women_during_pregnancy import ( + HSI_CareOfWomenDuringPregnancy_PostAbortionCaseManagement, + HSI_CareOfWomenDuringPregnancy_TreatmentForEctopicPregnancy, +) from tlo.methods.causes import Cause +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.util import BitsetHandler +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + from tlo.population import IndividualProperties + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -class PregnancySupervisor(Module): +class PregnancySupervisor(Module, GenericFirstAppointmentsMixin): """This module is responsible for simulating the antenatal period of pregnancy (the period from conception until the termination of pregnancy). A number of outcomes are managed by this module including early pregnancy loss (induced/spontaneous abortion, ectopic pregnancy and antenatal stillbirth) and pregnancy complications of the @@ -392,7 +404,7 @@ def __init__(self, name=None, resourcefilepath=None): 'ps_anc4': Property(Types.BOOL, 'Whether this woman is predicted to attend 4 or more antenatal care visits ' 'during her pregnancy'), - 'ps_abortion_complications': Property(Types.INT, 'Bitset column holding types of abortion complication'), + 'ps_abortion_complications': Property(Types.BITSET, 'Bitset column holding types of abortion complication'), 'ps_prev_spont_abortion': Property(Types.BOOL, 'Whether this woman has had any previous pregnancies end in ' 'spontaneous abortion'), 'ps_prev_stillbirth': Property(Types.BOOL, 'Whether this woman has had any previous pregnancies end in ' @@ -1660,6 +1672,39 @@ def schedule_late_visit(df_slice): early_initiation_anc_below_4.loc[~early_initiation_anc_below_4]]: schedule_late_visit(s) + def do_at_generic_first_appt_emergency( + self, + person_id: int, + individual_properties: IndividualProperties, + schedule_hsi_event: HSIEventScheduler, + **kwargs, + ) -> None: + scheduling_options = { + "priority": 0, + "topen": self.sim.date, + "tclose": self.sim.date + pd.DateOffset(days=1), + } + + # ----- ECTOPIC PREGNANCY ----- + if individual_properties["ps_ectopic_pregnancy"] != 'none': + event = HSI_CareOfWomenDuringPregnancy_TreatmentForEctopicPregnancy( + module=self.sim.modules["CareOfWomenDuringPregnancy"], + person_id=person_id, + ) + schedule_hsi_event(event, **scheduling_options) + + # ----- COMPLICATIONS OF ABORTION ----- + abortion_complications = self.sim.modules[ + "PregnancySupervisor" + ].abortion_complications + if abortion_complications.has_any( + [person_id], "sepsis", "injury", "haemorrhage", first=True + ): + event = HSI_CareOfWomenDuringPregnancy_PostAbortionCaseManagement( + module=self.sim.modules["CareOfWomenDuringPregnancy"], + person_id=person_id, + ) + schedule_hsi_event(event, **scheduling_options) class PregnancySupervisorEvent(RegularEvent, PopulationScopeEventMixin): """ This is the PregnancySupervisorEvent, it is a weekly event which has four primary functions. diff --git a/src/tlo/methods/prostate_cancer.py b/src/tlo/methods/prostate_cancer.py index 255c03a525..dbbe2c427f 100644 --- a/src/tlo/methods/prostate_cancer.py +++ b/src/tlo/methods/prostate_cancer.py @@ -4,8 +4,10 @@ Limitations to note: * Footprints of HSI -- pending input from expert on resources required. """ +from __future__ import annotations from pathlib import Path +from typing import TYPE_CHECKING, List import pandas as pd @@ -13,17 +15,23 @@ from tlo.events import IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.lm import LinearModel, LinearModelType, Predictor from tlo.methods import Metadata +from tlo.methods.cancer_consumables import get_consumable_item_codes_cancers from tlo.methods.causes import Cause from tlo.methods.demography import InstantaneousDeath from tlo.methods.dxmanager import DxTest -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + from tlo.population import IndividualProperties + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -class ProstateCancer(Module): +class ProstateCancer(Module, GenericFirstAppointmentsMixin): """Prostate Cancer Disease Module""" def __init__(self, name=None, resourcefilepath=None): @@ -33,6 +41,7 @@ def __init__(self, name=None, resourcefilepath=None): self.lm_prostate_ca_onset_urinary_symptoms = None self.lm_onset_pelvic_pain = None self.daly_wts = dict() + self.item_codes_prostate_can = dict() INIT_DEPENDENCIES = {'Demography', 'HealthSystem', 'SymptomManager'} @@ -277,14 +286,14 @@ def initialise_population(self, population): disease_module=self ) -# above code replaced with below when running for n=1 - + # above code replaced with below when running for n=1 - -# self.sim.modules['SymptomManager'].change_symptom( -# person_id=1, -# symptom_string='pelvic_pain', -# add_or_remove='+', -# disease_module=self -# ) + # self.sim.modules['SymptomManager'].change_symptom( + # person_id=1, + # symptom_string='pelvic_pain', + # add_or_remove='+', + # disease_module=self + # ) # ----- Impose the symptom of random sample of those in each cancer stage to have urinary symptoms: lm_init_urinary = LinearModel.multiplicative( @@ -306,14 +315,14 @@ def initialise_population(self, population): disease_module=self ) -# above code replaced with below when running for n=1 - + # above code replaced with below when running for n=1 - -# self.sim.modules['SymptomManager'].change_symptom( -# person_id=1, -# symptom_string='pelvic_pain', -# add_or_remove='+', -# disease_module=self -# ) + # self.sim.modules['SymptomManager'].change_symptom( + # person_id=1, + # symptom_string='pelvic_pain', + # add_or_remove='+', + # disease_module=self + # ) # -------------------- pc_date_diagnosis ----------- # for those with symptoms set to initially diagnosed @@ -368,6 +377,9 @@ def initialise_simulation(self, sim): * Define the Disability-weights * Schedule the palliative care appointments for those that are on palliative care at initiation """ + # We call the following function to store the required consumables for the simulation run within the appropriate + # dictionary + self.item_codes_prostate_can = get_consumable_item_codes_cancers(self) # ----- SCHEDULE LOGGING EVENTS ----- # Schedule logging event to happen immediately @@ -577,6 +589,33 @@ def report_daly_values(self): return disability_series_for_alive_persons + def do_at_generic_first_appt( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs + ) -> None: + # If the patient is not a child, and symptoms are indicative, + # begin investigation for prostate cancer + scheduling_options = { + "priority": 0, + "topen": self.sim.date, + } + if individual_properties["age_years"] > 5: + if "urinary" in symptoms: + event = HSI_ProstateCancer_Investigation_Following_Urinary_Symptoms( + person_id=person_id, module=self + ) + schedule_hsi_event(event, **scheduling_options) + + if "pelvic_pain" in symptoms: + event = HSI_ProstateCancer_Investigation_Following_Pelvic_Pain( + person_id=person_id, module=self + ) + schedule_hsi_event(event, **scheduling_options) + # --------------------------------------------------------------------------------------------------------- # DISEASE MODULE EVENTS @@ -680,7 +719,7 @@ def apply(self, person_id, squeeze_factor): return hs.get_blank_appt_footprint() # Check that this event has been called for someone with the urinary symptoms - assert 'urinary' in self.sim.modules['SymptomManager'].has_what(person_id) + assert 'urinary' in self.sim.modules['SymptomManager'].has_what(person_id=person_id) # If the person is already diagnosed, then take no action: if not pd.isnull(df.at[person_id, "pc_date_diagnosis"]): @@ -695,7 +734,10 @@ def apply(self, person_id, squeeze_factor): hsi_event=self ) - if dx_result: + # Check consumable availability + cons_avail = self.get_consumables(item_codes=self.module.item_codes_prostate_can['screening_psa_test_optional']) + + if dx_result and cons_avail: # send for biopsy hs.schedule_hsi_event( hsi_event=HSI_ProstateCancer_Investigation_Following_psa_positive( @@ -725,7 +767,7 @@ def apply(self, person_id, squeeze_factor): return hs.get_blank_appt_footprint() # Check that this event has been called for someone with the pelvic pain - assert 'pelvic_pain' in self.sim.modules['SymptomManager'].has_what(person_id) + assert 'pelvic_pain' in self.sim.modules['SymptomManager'].has_what(person_id=person_id) # If the person is already diagnosed, then take no action: if not pd.isnull(df.at[person_id, "pc_date_diagnosis"]): @@ -740,7 +782,9 @@ def apply(self, person_id, squeeze_factor): hsi_event=self ) - if dx_result: + cons_avail = self.get_consumables(item_codes=self.module.item_codes_prostate_can['screening_psa_test_optional']) + + if dx_result and cons_avail: # send for biopsy hs.schedule_hsi_event( hsi_event=HSI_ProstateCancer_Investigation_Following_psa_positive( @@ -776,43 +820,52 @@ def apply(self, person_id, squeeze_factor): df.at[person_id, 'pc_date_biopsy'] = self.sim.date # todo: stratify by pc_status - # Use a psa test to assess whether the person has prostate cancer: - dx_result = hs.dx_manager.run_dx_test( - dx_tests_to_run='biopsy_for_prostate_cancer', - hsi_event=self - ) - if dx_result: - # record date of diagnosis: - df.at[person_id, 'pc_date_diagnosis'] = self.sim.date + cons_available = self.get_consumables(item_codes=self.module.item_codes_prostate_can['screening_biopsy_core'], + optional_item_codes=self.module.item_codes_prostate_can[ + 'screening_biopsy_endoscopy_cystoscopy_optional']) - # Check if is in metastatic stage: - in_metastatic = df.at[person_id, 'pc_status'] == 'metastatic' - # If the diagnosis does detect cancer, it is assumed that the classification as metastatic is made - # accurately. + if cons_available: + # If consumables are available update the use of equipment and run the dx_test representing the biopsy + self.add_equipment({'Ultrasound scanning machine', 'Ordinary Microscope'}) - if not in_metastatic: - # start treatment: - hs.schedule_hsi_event( - hsi_event=HSI_ProstateCancer_StartTreatment( - module=self.module, - person_id=person_id - ), - priority=0, - topen=self.sim.date, - tclose=None - ) - else: - # start palliative care: - hs.schedule_hsi_event( - hsi_event=HSI_ProstateCancer_PalliativeCare( - module=self.module, - person_id=person_id - ), - priority=0, - topen=self.sim.date, - tclose=None - ) + # Use a biopsy to assess whether the person has prostate cancer: + dx_result = hs.dx_manager.run_dx_test( + dx_tests_to_run='biopsy_for_prostate_cancer', + hsi_event=self + ) + + if dx_result: + # record date of diagnosis: + df.at[person_id, 'pc_date_diagnosis'] = self.sim.date + + # Check if is in metastatic stage: + in_metastatic = df.at[person_id, 'pc_status'] == 'metastatic' + # If the diagnosis does detect cancer, it is assumed that the classification as metastatic is made + # accurately. + + if not in_metastatic: + # start treatment: + hs.schedule_hsi_event( + hsi_event=HSI_ProstateCancer_StartTreatment( + module=self.module, + person_id=person_id + ), + priority=0, + topen=self.sim.date, + tclose=None + ) + else: + # start palliative care: + hs.schedule_hsi_event( + hsi_event=HSI_ProstateCancer_PalliativeCare( + module=self.module, + person_id=person_id + ), + priority=0, + topen=self.sim.date, + tclose=None + ) class HSI_ProstateCancer_StartTreatment(HSI_Event, IndividualScopeEventMixin): @@ -858,20 +911,28 @@ def apply(self, person_id, squeeze_factor): assert not pd.isnull(df.at[person_id, "pc_date_diagnosis"]) assert pd.isnull(df.at[person_id, "pc_date_treatment"]) - # Record date and stage of starting treatment - df.at[person_id, "pc_date_treatment"] = self.sim.date - df.at[person_id, "pc_stage_at_which_treatment_given"] = df.at[person_id, "pc_status"] - - # Schedule a post-treatment check for 12 months: - hs.schedule_hsi_event( - hsi_event=HSI_ProstateCancer_PostTreatmentCheck( - module=self.module, - person_id=person_id, - ), - topen=self.sim.date + DateOffset(months=12), - tclose=None, - priority=0 - ) + cons_available = self.get_consumables(item_codes=self.module.item_codes_prostate_can['treatment_surgery_core'], + optional_item_codes=self.module.item_codes_prostate_can[ + 'treatment_surgery_optional']) + + if cons_available: + # If consumables are available and the treatment will go ahead - update the equipment + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('Major Surgery')) + + # Record date and stage of starting treatment + df.at[person_id, "pc_date_treatment"] = self.sim.date + df.at[person_id, "pc_stage_at_which_treatment_given"] = df.at[person_id, "pc_status"] + + # Schedule a post-treatment check for 12 months: + hs.schedule_hsi_event( + hsi_event=HSI_ProstateCancer_PostTreatmentCheck( + module=self.module, + person_id=person_id, + ), + topen=self.sim.date + DateOffset(months=12), + tclose=None, + priority=0 + ) class HSI_ProstateCancer_PostTreatmentCheck(HSI_Event, IndividualScopeEventMixin): @@ -955,20 +1016,28 @@ def apply(self, person_id, squeeze_factor): # Check that the person is in metastatic assert df.at[person_id, "pc_status"] == 'metastatic' - # Record the start of palliative care if this is first appointment - if pd.isnull(df.at[person_id, "pc_date_palliative_care"]): - df.at[person_id, "pc_date_palliative_care"] = self.sim.date - - # Schedule another instance of the event for one month - hs.schedule_hsi_event( - hsi_event=HSI_ProstateCancer_PalliativeCare( - module=self.module, - person_id=person_id - ), - topen=self.sim.date + DateOffset(months=1), - tclose=None, - priority=0 - ) + # Check consumables are available + cons_available = self.get_consumables( + item_codes=self.module.item_codes_prostate_can['palliation']) + + if cons_available: + # If consumables are available and the treatment will go ahead - update the equipment + self.add_equipment({'Infusion pump', 'Drip stand'}) + + # Record the start of palliative care if this is first appointment + if pd.isnull(df.at[person_id, "pc_date_palliative_care"]): + df.at[person_id, "pc_date_palliative_care"] = self.sim.date + + # Schedule another instance of the event for one month + hs.schedule_hsi_event( + hsi_event=HSI_ProstateCancer_PalliativeCare( + module=self.module, + person_id=person_id + ), + topen=self.sim.date + DateOffset(months=1), + tclose=None, + priority=0 + ) # --------------------------------------------------------------------------------------------------------- diff --git a/src/tlo/methods/rti.py b/src/tlo/methods/rti.py index aac0129cf6..13ddee6a86 100644 --- a/src/tlo/methods/rti.py +++ b/src/tlo/methods/rti.py @@ -2,7 +2,10 @@ Road traffic injury module. """ +from __future__ import annotations + from pathlib import Path +from typing import TYPE_CHECKING, List import numpy as np import pandas as pd @@ -12,9 +15,14 @@ from tlo.lm import LinearModel, LinearModelType, Predictor from tlo.methods import Metadata from tlo.methods.causes import Cause -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + from tlo.population import IndividualProperties + # --------------------------------------------------------------------------------------------------------- # MODULE DEFINITIONS # --------------------------------------------------------------------------------------------------------- @@ -23,7 +31,7 @@ logger.setLevel(logging.DEBUG) -class RTI(Module): +class RTI(Module, GenericFirstAppointmentsMixin): """ The road traffic injuries module for the TLO model, handling all injuries related to road traffic accidents. """ @@ -1008,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" ) } @@ -1773,21 +1785,6 @@ def rti_ask_for_shock_treatment(self, person_id): tclose=self.sim.date + DateOffset(days=15) ) - def rti_ask_for_imaging(self, person_id): - """ - A function called by the generic emergency appointment to order imaging for diagnosis - :param person_id: - :return: - """ - df = self.sim.population.props - if df.at[person_id, 'is_alive']: - self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=HSI_RTI_Imaging_Event(module=self, person_id=person_id), - priority=0, - topen=self.sim.date + DateOffset(days=1), - tclose=self.sim.date + DateOffset(days=15) - ) - def rti_ask_for_burn_treatment(self, person_id): """ Function called by HSI_RTI_MedicalIntervention to centralise all burn treatment requests. This function @@ -2500,17 +2497,111 @@ def rti_assign_injuries(self, number): # Finally return the injury description information return inj_df - def do_rti_diagnosis_and_treatment(self, person_id): - """Things to do upon a person presenting at a Non-Emergency Generic HSI if they have an injury.""" - df = self.sim.population.props - persons_injuries = df.loc[person_id, RTI.INJURY_COLUMNS] - if pd.isnull(df.at[person_id, 'cause_of_death']) and not df.at[person_id, 'rt_diagnosed']: - if len(set(RTI.INJURIES_REQ_IMAGING).intersection(persons_injuries)) > 0: - self.rti_ask_for_imaging(person_id) - df.at[person_id, 'rt_diagnosed'] = True - self.rti_do_when_diagnosed(person_id=person_id) - if df.at[person_id, 'rt_in_shock']: - self.rti_ask_for_shock_treatment(person_id) + def _common_first_appt_steps( + self, + person_id: int, + individual_properties: IndividualProperties, + schedule_hsi_event: HSIEventScheduler, + ) -> None: + """ + Shared logic steps that are used by the RTI module when a generic HSI + event is to be scheduled. + """ + # Things to do upon a person presenting at a Non-Emergency Generic + # HSI if they have an injury. + persons_injuries = [ + individual_properties[injury] for injury in RTI.INJURY_COLUMNS + ] + if ( + pd.isnull(individual_properties["cause_of_death"]) + and not individual_properties["rt_diagnosed"] + ): + if set(RTI.INJURIES_REQ_IMAGING).intersection(set(persons_injuries)): + if individual_properties["is_alive"]: + event = HSI_RTI_Imaging_Event(module=self, person_id=person_id) + schedule_hsi_event( + event, + priority=0, + topen=self.sim.date + DateOffset(days=1), + tclose=self.sim.date + DateOffset(days=15), + ) + individual_properties["rt_diagnosed"] = True + + # The injured person has been diagnosed in A&E and needs to progress further + # through the health system. + # They will then me scheduled a generic "medical intervention" appointment, + # serving three purposes: + # 1. Determine which treatments they require for their injuries to and shedule them, + # 2. Contain them in the health care system with inpatient days, + # 3. The appointment treats injuries that heal over time without further need for + # resources in the health system. + + # Check this person is injured, search they have an injury code that isn't "none" + _, counts = RTI.rti_find_and_count_injuries( + pd.DataFrame(data=[persons_injuries], columns=RTI.INJURY_COLUMNS), + RTI.INJURY_CODES[1:], + ) + # also test whether the regular injury symptom has been given to the person via spurious symptoms + assert (counts > 0) or self.sim.modules[ + "SymptomManager" + ].spurious_symptoms, ( + "This person has asked for medical treatment despite not being injured" + ) + + # If they meet the requirements, send them to HSI_RTI_MedicalIntervention for further treatment + # Using counts condition to stop spurious symptoms progressing people through the model + if counts > 0: + event = HSI_RTI_Medical_Intervention(module=self, person_id=person_id) + schedule_hsi_event( + event, + priority=0, + topen=self.sim.date, + ) + + # We now check if they need shock treatment + if ( + individual_properties["rt_in_shock"] + and individual_properties["is_alive"] + ): + event = HSI_RTI_Shock_Treatment(module=self, person_id=person_id) + schedule_hsi_event( + event, + priority=0, + topen=self.sim.date + DateOffset(days=1), + tclose=self.sim.date + DateOffset(days=15), + ) + + def do_at_generic_first_appt( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs + ) -> None: + if "injury" in symptoms: + return self._common_first_appt_steps( + person_id=person_id, + individual_properties=individual_properties, + schedule_hsi_event=schedule_hsi_event, + ) + + def do_at_generic_first_appt_emergency( + self, + person_id: int, + individual_properties: IndividualProperties, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs + ) -> None: + # Same process is followed for emergency and non emergency appointments, except the + # initial symptom check + if "severe_trauma" in symptoms: + return self._common_first_appt_steps( + person_id=person_id, + individual_properties=individual_properties, + schedule_hsi_event=schedule_hsi_event, + ) # --------------------------------------------------------------------------------------------------------- @@ -3126,8 +3217,13 @@ def apply(self, person_id, squeeze_factor): self.sim.population.props.at[person_id, 'rt_diagnosed'] = True road_traffic_injuries = self.sim.modules['RTI'] road_traffic_injuries.rti_injury_diagnosis(person_id, self.EXPECTED_APPT_FOOTPRINT) - if 'Tomography' in list(self.EXPECTED_APPT_FOOTPRINT.keys()): + + if 'DiagRadio' in list(self.EXPECTED_APPT_FOOTPRINT.keys()): + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('X-ray')) + + elif 'Tomography' in list(self.EXPECTED_APPT_FOOTPRINT.keys()): self.ACCEPTED_FACILITY_LEVEL = '3' + self.add_equipment({'Computed Tomography (CT machine)', 'CT scanner accessories'}) def did_not_run(self, *args, **kwargs): pass @@ -3429,6 +3525,9 @@ def apply(self, person_id, squeeze_factor): # determine the number of ICU days used to treat patient if df.loc[person_id, 'rt_ISS_score'] > self.hdu_cut_off_iss_score: + + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('ICU')) + mean_icu_days = p['mean_icu_days'] sd_icu_days = p['sd_icu_days'] mean_tbi_icu_days = p['mean_tbi_icu_days'] @@ -3721,8 +3820,6 @@ class HSI_RTI_Shock_Treatment(HSI_Event, IndividualScopeEventMixin): """ This HSI event handles the process of treating hypovolemic shock, as recommended by the pediatric handbook for Malawi and (TODO: FIND ADULT REFERENCE) - Currently this HSI_Event is described only and not used, as I still need to work out how to model the occurrence - of shock """ def __init__(self, module, person_id): @@ -3732,9 +3829,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'] 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 @@ -3746,21 +3846,21 @@ def apply(self, person_id, squeeze_factor): # TODO: find a more complete list of required consumables for adults if is_child: self.module.item_codes_for_consumables_required['shock_treatment_child'] = { - get_item_code("ringer's lactate (Hartmann's solution), 1000 ml_12_IDA"): 1, - get_item_code("Dextrose (glucose) 5%, 1000ml_each_CMST"): 1, + get_item_code("ringer's lactate (Hartmann's solution), 1000 ml_12_IDA"): 500, + get_item_code("Dextrose (glucose) 5%, 1000ml_each_CMST"): 500, get_item_code('Cannula iv (winged with injection pot) 18_each_CMST'): 1, - get_item_code('Blood, one unit'): 1, - get_item_code("Oxygen, 1000 liters, primarily with oxygen cylinders"): 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_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"): 1, + 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'): 1, - get_item_code("Oxygen, 1000 liters, primarily with oxygen cylinders"): 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'] @@ -3770,8 +3870,10 @@ def apply(self, person_id, squeeze_factor): 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({}) def did_not_run(self): @@ -3824,11 +3926,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({}) @@ -3858,7 +3964,7 @@ def apply(self, person_id, squeeze_factor): # If they have a fracture that needs a cast, ask for plaster of paris self.module.item_codes_for_consumables_required['fracture_treatment'] = { get_item_code('Plaster of Paris (POP) 10cm x 7.5cm slab_12_CMST'): fracturecastcounts, - get_item_code('Bandage, crepe 7.5cm x 1.4m long , when stretched'): slingcounts, + get_item_code('Bandage, crepe 7.5cm x 1.4m long , when stretched'): 200, } is_cons_available = self.get_consumables( self.module.item_codes_for_consumables_required['fracture_treatment'] @@ -3869,6 +3975,9 @@ def apply(self, person_id, squeeze_factor): data=f"Fracture casts available for person %d's {fracturecastcounts + slingcounts} fractures, " f"{person_id}" ) + + self.add_equipment({'Casting platform', 'Casting chairs', 'Bucket, 10L'}) + # update the property rt_med_int to indicate they are recieving treatment df.at[person_id, 'rt_med_int'] = True # Find the persons injuries @@ -3920,7 +4029,8 @@ 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 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', @@ -3960,9 +4070,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'] @@ -3981,9 +4095,9 @@ def apply(self, person_id, squeeze_factor): # If they have an open fracture, ask for consumables to treat fracture if open_fracture_counts > 0: self.module.item_codes_for_consumables_required['open_fracture_treatment'] = { - get_item_code('Ceftriaxone 1g, PFR_each_CMST'): 1, - get_item_code('Cetrimide 15% + chlorhexidine 1.5% solution.for dilution _5_CMST'): 1, - get_item_code("Gauze, absorbent 90cm x 40m_each_CMST"): 1, + get_item_code('Ceftriaxone 1g, PFR_each_CMST'): 2000, + get_item_code('Cetrimide 15% + chlorhexidine 1.5% solution.for dilution _5_CMST'): 500, + get_item_code("Gauze, absorbent 90cm x 40m_each_CMST"): 100, get_item_code('Suture pack'): 1, } # If wound is "grossly contaminated" administer Metronidazole @@ -3991,9 +4105,10 @@ def apply(self, person_id, squeeze_factor): p = self.module.parameters prob_open_fracture_contaminated = p['prob_open_fracture_contaminated'] rand_for_contamination = self.module.rng.random_sample(size=1) + # NB: Dose used below from BNF is for surgical prophylaxsis if rand_for_contamination < prob_open_fracture_contaminated: self.module.item_codes_for_consumables_required['open_fracture_treatment'].update( - {get_item_code('Metronidazole, injection, 500 mg in 100 ml vial'): 1} + {get_item_code('Metronidazole, injection, 500 mg in 100 ml vial'): 1500} ) # Check that there are enough consumables to treat this person's fractures is_cons_available = self.get_consumables( @@ -4004,6 +4119,9 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='rti_general_message', data=f"Fracture casts available for person {person_id} {open_fracture_counts} open fractures" ) + + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('Major Surgery')) + person = df.loc[person_id] # update the dataframe to show this person is recieving treatment df.loc[person_id, 'rt_med_int'] = True @@ -4030,7 +4148,8 @@ 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 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', @@ -4073,10 +4192,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'] @@ -4092,7 +4216,7 @@ def apply(self, person_id, squeeze_factor): if lacerationcounts > 0: self.module.item_codes_for_consumables_required['laceration_treatment'] = { get_item_code('Suture pack'): lacerationcounts, - get_item_code('Cetrimide 15% + chlorhexidine 1.5% solution.for dilution _5_CMST'): lacerationcounts, + get_item_code('Cetrimide 15% + chlorhexidine 1.5% solution.for dilution _5_CMST'): 500, } # check the number of suture kits required and request them @@ -4121,7 +4245,8 @@ 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 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', @@ -4168,10 +4293,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'] @@ -4200,7 +4330,7 @@ def apply(self, person_id, squeeze_factor): # check if they have multiple burns, which implies a higher burned total body surface area (TBSA) which # will alter the treatment plan self.module.item_codes_for_consumables_required['burn_treatment'].update( - {get_item_code("ringer's lactate (Hartmann's solution), 1000 ml_12_IDA"): 1} + {get_item_code("ringer's lactate (Hartmann's solution), 1000 ml_12_IDA"): 4000} ) is_cons_available = self.get_consumables( @@ -4244,7 +4374,8 @@ 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 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', @@ -4271,9 +4402,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] @@ -4302,7 +4438,8 @@ 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) + 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") return self.make_appt_footprint({}) @@ -4332,9 +4469,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 @@ -4386,20 +4528,20 @@ def apply(self, person_id, squeeze_factor): description='Summary of the pain medicine requested by each person') if df.loc[person_id, 'age_years'] < 16: self.module.item_codes_for_consumables_required['pain_management'] = { - get_item_code("Paracetamol 500mg_1000_CMST"): 1 + get_item_code("Paracetamol 500mg_1000_CMST"): 8000 } cond = self.get_consumables( self.module.item_codes_for_consumables_required['pain_management'] ) else: self.module.item_codes_for_consumables_required['pain_management'] = { - get_item_code("diclofenac sodium 25 mg, enteric coated_1000_IDA"): 1 + get_item_code("diclofenac sodium 25 mg, enteric coated_1000_IDA"): 300 } cond1 = self.get_consumables( self.module.item_codes_for_consumables_required['pain_management'] ) self.module.item_codes_for_consumables_required['pain_management'] = { - get_item_code("Paracetamol 500mg_1000_CMST"): 1 + get_item_code("Paracetamol 500mg_1000_CMST"): 8000 } cond2 = self.get_consumables( self.module.item_codes_for_consumables_required['pain_management'] @@ -4443,7 +4585,8 @@ 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) + 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}.") @@ -4456,7 +4599,7 @@ def apply(self, person_id, squeeze_factor): data=dict_to_output, description='Summary of the pain medicine requested by each person') self.module.item_codes_for_consumables_required['pain_management'] = { - get_item_code("tramadol HCl 100 mg/2 ml, for injection_100_IDA"): 1 + get_item_code("tramadol HCl 100 mg/2 ml, for injection_100_IDA"): 300 } is_cons_available = self.get_consumables( self.module.item_codes_for_consumables_required['pain_management'] @@ -4474,7 +4617,8 @@ 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) + 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}.") @@ -4488,7 +4632,7 @@ def apply(self, person_id, squeeze_factor): description='Summary of the pain medicine requested by each person') # give morphine self.module.item_codes_for_consumables_required['pain_management'] = { - get_item_code("morphine sulphate 10 mg/ml, 1 ml, injection (nt)_10_IDA"): 1 + get_item_code("morphine sulphate 10 mg/ml, 1 ml, injection (nt)_10_IDA"): 120 } is_cons_available = self.get_consumables( self.module.item_codes_for_consumables_required['pain_management'] @@ -4506,7 +4650,8 @@ 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) + 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}.") @@ -4634,6 +4779,8 @@ def __init__(self, module, person_id): self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({'MajorSurg': 1}) self.ACCEPTED_FACILITY_LEVEL = '1b' self.BEDDAYS_FOOTPRINT = self.make_beddays_footprint({}) + 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'] p = self.module.parameters self.prob_perm_disability_with_treatment_severe_TBI = p['prob_perm_disability_with_treatment_severe_TBI'] @@ -4641,6 +4788,7 @@ def __init__(self, module, person_id): self.treated_code = 'none' 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 road_traffic_injuries = self.sim.modules['RTI'] @@ -4648,22 +4796,22 @@ def apply(self, person_id, squeeze_factor): # Request first draft of consumables used in major surgery self.module.item_codes_for_consumables_required['major_surgery'] = { # request a general anaesthetic - get_item_code("Halothane (fluothane)_250ml_CMST"): 1, + get_item_code("Halothane (fluothane)_250ml_CMST"): 100, # clean the site of the surgery - get_item_code("Chlorhexidine 1.5% solution_5_CMST"): 1, + get_item_code("Chlorhexidine 1.5% solution_5_CMST"): 500, # tools to begin surgery get_item_code("Scalpel blade size 22 (individually wrapped)_100_CMST"): 1, # administer an IV get_item_code('Cannula iv (winged with injection pot) 18_each_CMST'): 1, get_item_code("Giving set iv administration + needle 15 drops/ml_each_CMST"): 1, - get_item_code("ringer's lactate (Hartmann's solution), 1000 ml_12_IDA"): 1, + get_item_code("ringer's lactate (Hartmann's solution), 1000 ml_12_IDA"): 2000, # repair incision made get_item_code("Suture pack"): 1, - get_item_code("Gauze, absorbent 90cm x 40m_each_CMST"): 1, + get_item_code("Gauze, absorbent 90cm x 40m_each_CMST"): 100, # administer pain killer - get_item_code('Pethidine, 50 mg/ml, 2 ml ampoule'): 1, + get_item_code('Pethidine, 50 mg/ml, 2 ml ampoule'): 6, # administer antibiotic - get_item_code("Ampicillin injection 500mg, PFR_each_CMST"): 1, + get_item_code("Ampicillin injection 500mg, PFR_each_CMST"): 1000, # equipment used by surgeon, gloves and facemask get_item_code('Disposables gloves, powder free, 100 pieces per box'): 1, get_item_code('surgical face mask, disp., with metal nose piece_50_IDA'): 1, @@ -4722,6 +4870,9 @@ def apply(self, person_id, squeeze_factor): # RTI_Med assert df.loc[person_id, 'rt_diagnosed'], 'This person has not been through a and e' assert df.loc[person_id, 'rt_med_int'], 'This person has not been through rti med int' + + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('Major Surgery')) + # ------------------------ Track permanent disabilities with treatment ------------------------------------- # --------------------------------- Perm disability from TBI ----------------------------------------------- codes = ['133', '133a', '133b', '133c', '133d', '134', '134a', '134b', '135'] @@ -4910,7 +5061,8 @@ def apply(self, person_id, squeeze_factor): ['Treated injury code not removed', self.treated_code] df.loc[person_id, 'rt_date_death_no_med'] = pd.NaT 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) 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) return self.make_appt_footprint({}) @@ -4976,7 +5128,12 @@ def __init__(self, module, person_id): 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): + self._number_of_times_this_event_has_run += 1 df = self.sim.population.props if not df.at[person_id, 'is_alive']: return self.make_appt_footprint({}) @@ -4984,22 +5141,22 @@ def apply(self, person_id, squeeze_factor): # Request first draft of consumables used in major surgery self.module.item_codes_for_consumables_required['minor_surgery'] = { # request a local anaesthetic - get_item_code("Halothane (fluothane)_250ml_CMST"): 1, + get_item_code("Halothane (fluothane)_250ml_CMST"): 100, # clean the site of the surgery - get_item_code("Chlorhexidine 1.5% solution_5_CMST"): 1, + get_item_code("Chlorhexidine 1.5% solution_5_CMST"): 500, # tools to begin surgery get_item_code("Scalpel blade size 22 (individually wrapped)_100_CMST"): 1, # administer an IV get_item_code('Cannula iv (winged with injection pot) 18_each_CMST'): 1, get_item_code("Giving set iv administration + needle 15 drops/ml_each_CMST"): 1, - get_item_code("ringer's lactate (Hartmann's solution), 1000 ml_12_IDA"): 1, + get_item_code("ringer's lactate (Hartmann's solution), 1000 ml_12_IDA"): 2000, # repair incision made get_item_code("Suture pack"): 1, - get_item_code("Gauze, absorbent 90cm x 40m_each_CMST"): 1, + get_item_code("Gauze, absorbent 90cm x 40m_each_CMST"): 100, # administer pain killer - get_item_code('Pethidine, 50 mg/ml, 2 ml ampoule'): 1, + get_item_code('Pethidine, 50 mg/ml, 2 ml ampoule'): 6, # administer antibiotic - get_item_code("Ampicillin injection 500mg, PFR_each_CMST"): 1, + get_item_code("Ampicillin injection 500mg, PFR_each_CMST"): 1000, # equipment used by surgeon, gloves and facemask get_item_code('Disposables gloves, powder free, 100 pieces per box'): 1, get_item_code('surgical face mask, disp., with metal nose piece_50_IDA'): 1, @@ -5037,6 +5194,8 @@ def apply(self, person_id, squeeze_factor): # todo: think about consequences of certain consumables not being available for minor surgery and model health # outcomes if request_outcome: + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('Major Surgery')) + # create a dictionary to store the recovery times for each injury in days minor_surg_recov_time_days = { '322': 180, @@ -5095,7 +5254,8 @@ def apply(self, person_id, squeeze_factor): ['Injury treated not removed', treated_code] df.loc[person_id, 'rt_date_death_no_med'] = pd.NaT 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) 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', diff --git a/src/tlo/methods/scenario_switcher.py b/src/tlo/methods/scenario_switcher.py index 9d69d76663..615660daaa 100644 --- a/src/tlo/methods/scenario_switcher.py +++ b/src/tlo/methods/scenario_switcher.py @@ -1,18 +1,22 @@ import warnings -from tlo import Module, Parameter, Types +from tlo import Date, Module, Parameter, Types from tlo.analysis.utils import get_parameters_for_improved_healthsystem_and_healthcare_seeking +from tlo.events import Event, PopulationScopeEventMixin -class ScenarioSwitcher(Module): - """The ScenarioSwitcher module. - This is a utility module that can be used to make changes to parameters in registered simulation models, including - parameters of the form `pd.Series` and `pd.DataFrame` that cannot be changed via the `Scenario` class (see - https://github.com/UCL/TLOmodel/issues/988). It loads a ResourceFile that contains parameter value to be updated, +class ImprovedHealthSystemAndCareSeekingScenarioSwitcher(Module): + """This is the `ImprovedHealthSystemAndCareSeekingScenarioSwitcher` module. + It provides switches that can be used by the `Scenario` class to control the overall performance of the HealthSystem + and healthcare seeking, which are mediated by many parameters across many modules, and which are of the types + `pd.Series` and `pd.DataFrame`, which cannot be changed via the `Scenario` class (see + https://github.com/UCL/TLOmodel/issues/988). + It does this by loading a ResourceFile that contains parameter value to be updated, and makes these changes at the point `pre_initialise_population`. As this module is declared as an (Optional) dependency of the module that would be loaded first in the simulation (i.e. `Demography`), this module is registered first and so this module's `pre_initialise_population` method is called before any other. This provides - a close approximation to what would happen if the parameters were being changed by the `Scenario` class.""" + a close approximation to what would happen if the parameters were being changed by the `Scenario` class. + """ def __init__(self, name=None, resourcefilepath=None): super().__init__(name) @@ -25,32 +29,59 @@ def __init__(self, name=None, resourcefilepath=None): METADATA = set() PARAMETERS = { + # Each of these parameter is a list of two booleans -- [bool, bool] -- which represent (i) the state during the + # period before the date of a switch in state, (ii) the state at the date of switch and the period thereafter. + + # -- Health System Strengthening Switches "max_healthsystem_function": Parameter( - Types.BOOL, "If True, over-writes parameters that define maximal health system function." + Types.LIST, "If True, over-writes parameters that define maximal health system function." "Parameter passed through to `get_parameters_for_improved_healthsystem_and_healthcare_seeking`." ), "max_healthcare_seeking": Parameter( - Types.BOOL, "If True, over-writes parameters that define maximal healthcare-seeking behaviour. " + Types.LIST, "If True, over-writes parameters that define maximal healthcare-seeking behaviour. " "Parameter passed through to `get_parameters_for_improved_healthsystem_and_healthcare_seeking`." ), + + # This parameter specifies the year in which the state changes. The change occurs on 1st January of that year. + # If there should not be any switch, then this year can be set to a year that is beyond the end of the + # simulation. + "year_of_switch": Parameter( + Types.INT, "The year in which the state changes. The state changes on 1st January of that year." + ), } PROPERTIES = {} def read_parameters(self, data_folder): - """Default values for parameters. These are hard-coded.""" - self.parameters["max_healthsystem_function"] = False - self.parameters["max_healthcare_seeking"] = False + """Read-in parameters and process them into the internal storage structures required.""" - def initialise_population(self, population): - pass + # Parameters are hard-coded for this module to not make any changes. (The expectation is that some of these + # are over-written by the Scenario class.) + # The first value in the list is used before the year of change, and the second value is used after. + self.parameters["max_healthsystem_function"] = [False] * 2 # (No use of the "max" scenarios) + self.parameters["max_healthcare_seeking"] = [False] * 2 + self.parameters["year_of_switch"] = 2100 # (Any change occurs very far in the future) def pre_initialise_population(self): - """Retrieve parameters to be updated and update them in the other registered disease modules.""" + """Set the parameters for the first period of the simulation. + Note that this is happening here and not in initialise_simulation because we want to make sure that the + parameters are changed before other modules call `pre_initialise_population`. We ensure that this module's + method is the first to be called as this module is declared as an (Optional) dependency of the module that is + loaded first in the simulation (i.e. `Demography`). This provides a close approximation to what would happen if + the parameters were being changed by the `Scenario` class.""" + self.update_parameters() + + def update_parameters(self): + """Update the parameters in the simulation's modules.""" + + # Check whether we are currently in the first or second phase of the simulation (i.e., before or after the + # time of the change, which is at the beginning of the year `year_of_switch`.) + phase_of_simulation = 0 if self.sim.date.year < self.parameters["year_of_switch"] else 1 params_to_update = get_parameters_for_improved_healthsystem_and_healthcare_seeking( resourcefilepath=self.resourcefilepath, - **self.parameters + max_healthsystem_function=self.parameters['max_healthsystem_function'][phase_of_simulation], + max_healthcare_seeking=self.parameters['max_healthcare_seeking'][phase_of_simulation], ) for module, params in params_to_update.items(): @@ -63,8 +94,26 @@ def pre_initialise_population(self): f"module={module}, name={name}.", ) - def initialise_simulation(self, sim): + def initialise_population(self, population): pass + def initialise_simulation(self, sim): + """Schedule an event at which the parameters are changed.""" + + date_of_switch_event = Date(self.parameters["year_of_switch"], 1, 1) # 1st January of the year specified. + sim.schedule_event(ScenarioSwitchEvent(module=self), date_of_switch_event) + def on_birth(self, mother_id, child_id): pass + + +class ScenarioSwitchEvent(Event, PopulationScopeEventMixin): + + def __init__(self, module): + super().__init__(module) + + def apply(self, population): + """Run the function that updates the simulation parameters.""" + self.module.update_parameters() + + diff --git a/src/tlo/methods/schisto.py b/src/tlo/methods/schisto.py index 2a7c94eed1..0e9735286a 100644 --- a/src/tlo/methods/schisto.py +++ b/src/tlo/methods/schisto.py @@ -1,5 +1,7 @@ +from __future__ import annotations + from pathlib import Path -from typing import Optional, Sequence, Union +from typing import TYPE_CHECKING, List, Optional, Sequence, Union import numpy as np import pandas as pd @@ -9,10 +11,14 @@ from tlo.events import Event, IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.methods import Metadata from tlo.methods.causes import Cause -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom from tlo.util import random_date +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -25,7 +31,7 @@ _AGE_GROUPS = {'PSAC': (0, 4), 'SAC': (5, 14), 'Adults': (15, 120), 'All': (0, 120)} -class Schisto(Module): +class Schisto(Module, GenericFirstAppointmentsMixin): """Schistosomiasis module. Two species of worm that cause Schistosomiasis are modelled independently. Worms are acquired by persons via the environment. There is a delay between the acquisition of worms and the maturation to 'adults' worms; and a long @@ -208,22 +214,6 @@ def get_total_disability_weight(list_of_symptoms: list) -> float: return pd.Series(index=df.index[df.is_alive], data=0.0).add(disability_weights_for_each_person_with_symptoms, fill_value=0.0) - def do_on_presentation_with_symptoms(self, person_id: int, symptoms: Union[list, set, tuple]) -> None: - """Do when person presents to the GenericFirstAppt. If the person has certain set of symptoms, refer ta HSI for - testing.""" - - set_of_symptoms_indicative_of_schisto = {'anemia', 'haematuria', 'bladder_pathology'} - - if set_of_symptoms_indicative_of_schisto.issubset(symptoms): - self.sim.modules['HealthSystem'].schedule_hsi_event( - HSI_Schisto_TestingFollowingSymptoms( - module=self, - person_id=person_id), - topen=self.sim.date, - tclose=None, - priority=0 - ) - def do_effect_of_treatment(self, person_id: Union[int, Sequence[int]]) -> None: """Do the effects of a treatment administered to a person or persons. This can be called for a person who is infected and receiving treatment following a diagnosis, or for a person who is receiving treatment as part of a @@ -308,7 +298,7 @@ def _get_disability_weight(self) -> dict: def _get_item_code_for_praziquantel(self) -> int: """Look-up the item code for Praziquantel""" - return self.sim.modules['HealthSystem'].get_item_code_from_item_name("Praziquantel, 600 mg (donated)") + return self.sim.modules['HealthSystem'].get_item_code_from_item_name("Praziquantel 600mg_1000_CMST") def _schedule_mda_events(self) -> None: """Schedule MDA events, historical and prognosed.""" @@ -339,6 +329,23 @@ def _schedule_mda_events(self) -> None: Date(year=year_first_simulated_mda, month=7, day=1) ) + def do_at_generic_first_appt( + self, + person_id: int, + symptoms: List[str], + schedule_hsi_event: HSIEventScheduler, + **kwargs + ) -> None: + # Do when person presents to the GenericFirstAppt. + # If the person has certain set of symptoms, refer ta HSI for testing. + set_of_symptoms_indicative_of_schisto = {'anemia', 'haematuria', 'bladder_pathology'} + + if set_of_symptoms_indicative_of_schisto.issubset(symptoms): + event = HSI_Schisto_TestingFollowingSymptoms( + module=self, person_id=person_id + ) + schedule_hsi_event(event, priority=0, topen=self.sim.date) + class SchistoSpecies: """Helper Class to hold the information specific to a particular species (either S. mansoni or S. haematobium).""" @@ -916,6 +923,8 @@ def apply(self, person_id, squeeze_factor): ) if will_test: + self.add_equipment({'Ordinary Microscope'}) + # Determine if they truly are infected (with any of the species) is_infected = (person.loc[cols_of_infection_status] != 'Non-infected').any() diff --git a/src/tlo/methods/skeleton.py b/src/tlo/methods/skeleton.py index e4f8a9bd6a..3f21cc4fff 100644 --- a/src/tlo/methods/skeleton.py +++ b/src/tlo/methods/skeleton.py @@ -6,7 +6,7 @@ from tlo.events import IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.methods import Metadata from tlo.methods.causes import Cause -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event # --------------------------------------------------------------------------------------------------------- # MODULE DEFINITIONS diff --git a/src/tlo/methods/stunting.py b/src/tlo/methods/stunting.py index b4122b423a..002d24bc31 100644 --- a/src/tlo/methods/stunting.py +++ b/src/tlo/methods/stunting.py @@ -5,14 +5,14 @@ -------- The Stunting module determines the prevalence of stunting for children under 5 years old. A polling event runs every month and determines the risk of onset of non-severe stunting, progression to severe stunting or natural -recovery. The Generic HSI calls `do_routine_assessment_for_chronic_undernutrition` for any HSI with a child under -5 years old: if they have any stunting they are provided with an intervention - `HSI_Stunting_ComplementaryFeeding`. - +recovery. The Generic HSI calls do_at_generic_first_appt for any HSI with a child under 5 years old: +if they have any stunting they are provided with an intervention - `HSI_Stunting_ComplementaryFeeding`. """ +from __future__ import annotations from collections import namedtuple from pathlib import Path -from typing import Union +from typing import TYPE_CHECKING, Union import numpy as np import pandas as pd @@ -22,7 +22,12 @@ from tlo.events import IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.lm import LinearModel, LinearModelType, Predictor from tlo.methods import Metadata -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin + +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + from tlo.population import IndividualProperties logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -32,7 +37,7 @@ # MODULE DEFINITION # --------------------------------------------------------------------------------------------------------- -class Stunting(Module): +class Stunting(Module, GenericFirstAppointmentsMixin): """This is the disease module for Stunting""" INIT_DEPENDENCIES = {'Demography', 'Wasting', 'NewbornOutcomes', 'Diarrhoea', 'Hiv'} @@ -275,31 +280,43 @@ def do_recovery(self, idx: Union[list, pd.Index]): '-3<=HAZ<-2': 'HAZ>=-2' }) - def do_routine_assessment_for_chronic_undernutrition(self, person_id): - """This is called by the a generic HSI event for every child aged less than 5 years. It assesses stunting - and schedules an HSI as needed.""" - - df = self.sim.population.props - person = df.loc[person_id] - is_stunted = person.un_HAZ_category in ('HAZ<-3', '-3<=HAZ<-2') - p_stunting_diagnosed = self.parameters['prob_stunting_diagnosed_at_generic_appt'] - - if not is_stunted: - return - - # Schedule the HSI for provision of treatment based on the probability of stunting diagnosis - if p_stunting_diagnosed > self.rng.random_sample(): - self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=HSI_Stunting_ComplementaryFeeding(module=self, person_id=person_id), - priority=2, # <-- lower priority that for wasting and most other HSI - topen=self.sim.date) - def do_treatment(self, person_id, prob_success): """Represent the treatment with supplementary feeding. If treatment is successful, effect the recovery of the person immediately.""" if prob_success > self.rng.random_sample(): self.do_recovery([person_id]) + def do_at_generic_first_appt( + self, + person_id: int, + individual_properties: IndividualProperties, + schedule_hsi_event: HSIEventScheduler, + **kwargs, + ) -> None: + # This is called by the a generic HSI event for every child aged less than 5 + # years. It assesses stunting and schedules an HSI as needed. + is_stunted = individual_properties["un_HAZ_category"] in ( + "HAZ<-3", + "-3<=HAZ<-2", + ) + p_stunting_diagnosed = self.parameters[ + "prob_stunting_diagnosed_at_generic_appt" + ] + + # Schedule the HSI for provision of treatment based on the probability of + # stunting diagnosis, provided the necessary symptoms are there. + if individual_properties["age_years"] <= 5 and is_stunted: + # Schedule the HSI for provision of treatment based on the probability of + # stunting diagnosis + if p_stunting_diagnosed > self.rng.random_sample(): + event = HSI_Stunting_ComplementaryFeeding( + module=self, person_id=person_id + ) + schedule_hsi_event( + event, + priority=2, # <-- lower priority that for wasting and most other HSI + topen=self.sim.date, + ) class Models: def __init__(self, module): diff --git a/src/tlo/methods/symptommanager.py b/src/tlo/methods/symptommanager.py index 61ffaaf1ce..67389e283e 100644 --- a/src/tlo/methods/symptommanager.py +++ b/src/tlo/methods/symptommanager.py @@ -11,9 +11,11 @@ * The probability of spurious symptoms is not informed by data. """ +from __future__ import annotations + from collections import defaultdict from pathlib import Path -from typing import Sequence, Union +from typing import TYPE_CHECKING, List, Optional, Sequence, Union import numpy as np import pandas as pd @@ -23,6 +25,9 @@ from tlo.methods import Metadata from tlo.util import BitsetHandler +if TYPE_CHECKING: + from tlo.population import IndividualProperties + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -272,7 +277,8 @@ def pre_initialise_population(self): SymptomManager.PROPERTIES = dict() for symptom_name in sorted(self.symptom_names): symptom_column_name = self.get_column_name_for_symptom(symptom_name) - SymptomManager.PROPERTIES[symptom_column_name] = Property(Types.INT, f'Presence of symptom {symptom_name}') + SymptomManager.PROPERTIES[symptom_column_name] = Property(Types.BITSET, + f'Presence of symptom {symptom_name}') def initialise_population(self, population): """ @@ -459,33 +465,81 @@ def who_not_have(self, symptom_string: str) -> pd.Index: ) ] - def has_what(self, person_id, disease_module: Module = None): + def has_what( + self, + person_id: Optional[int] = None, + individual_details: Optional[IndividualProperties] = None, + disease_module: Optional[Module] = None, + ) -> List[str]: """ This is a helper function that will give a list of strings for the symptoms that a _single_ person is currently experiencing. - Optionally can specify disease_module_name to limit to the symptoms caused by that disease module - :param person_id: the person_of of interest - :param disease_module: (optional) disease module of interest - :return: list of strings for the symptoms that are currently being experienced - """ + If working in a `tlo.population.IndividualProperties` context, one can pass the context object + instead of supplying the person's DataFrame index. + Note that at least one of these inputs must be passed as a keyword argument however. + In the event that both arguments are passed, the individual_details argument takes precedence over the person_id. - assert isinstance(person_id, (int, np.integer)), 'person_id must be a single integer for one particular person' + Optionally can specify disease_module_name to limit to the symptoms caused by that disease module. - df = self.sim.population.props - assert df.at[person_id, 'is_alive'], "The person is not alive" - - if disease_module is not None: - assert disease_module.name in ([self.name] + self.recognised_module_names), \ - "Disease Module Name is not recognised" - sy_columns = [self.get_column_name_for_symptom(s) for s in self.symptom_names] - person_has = self.bsh.has( - [person_id], disease_module.name, first=True, columns=sy_columns - ) - return [s for s in self.symptom_names if person_has[f'sy_{s}']] + :param person_id: the person_of of interest. + :param individual_details: `tlo.population.IndividualProperties` object for the person of interest. + :param disease_module: (optional) disease module of interest. + :return: list of strings for the symptoms that are currently being experienced. + """ + assert ( + disease_module.name in ([self.name] + self.recognised_module_names) + if disease_module is not None + else True + ), "Disease Module Name is not recognised" + + if individual_details is not None: + # We are working in an IndividualDetails context, avoid lookups to the + # population DataFrame as we have this context stored already. + assert individual_details["is_alive"], "The person is not alive" + + if disease_module is not None: + int_repr = self.bsh._element_to_int_map[disease_module.name] + return [ + symptom + for symptom in self.symptom_names + if individual_details[ + self.bsh._get_columns(self.get_column_name_for_symptom(symptom)) + ] + & int_repr + != 0 + ] + else: + return [ + symptom + for symptom in self.symptom_names + if individual_details[self.get_column_name_for_symptom(symptom)] > 0 + ] else: - symptom_cols = df.loc[person_id, [f'sy_{s}' for s in self.symptom_names]] - return symptom_cols.index[symptom_cols > 0].str.removeprefix("sy_").to_list() + assert isinstance( + person_id, (int, np.integer) + ), "person_id must be a single integer for one particular person" + + df = self.sim.population.props + assert df.at[person_id, "is_alive"], "The person is not alive" + + if disease_module is not None: + sy_columns = [ + self.get_column_name_for_symptom(s) for s in self.symptom_names + ] + person_has = self.bsh.has( + [person_id], disease_module.name, first=True, columns=sy_columns + ) + return [s for s in self.symptom_names if person_has[f"sy_{s}"]] + else: + symptom_cols = df.loc[ + person_id, [f"sy_{s}" for s in self.symptom_names] + ] + return ( + symptom_cols.index[symptom_cols > 0] + .str.removeprefix("sy_") + .to_list() + ) def have_what(self, person_ids: Sequence[int]): """Find the set of symptoms for a list of person_ids. diff --git a/src/tlo/methods/tb.py b/src/tlo/methods/tb.py index 79afd6fa5f..8b7a061586 100644 --- a/src/tlo/methods/tb.py +++ b/src/tlo/methods/tb.py @@ -9,13 +9,13 @@ import pandas as pd -from tlo import DateOffset, Module, Parameter, Property, Types, logging +from tlo import Date, DateOffset, Module, Parameter, Property, Types, logging from tlo.events import Event, IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.lm import LinearModel, LinearModelType, Predictor from tlo.methods import Metadata, hiv from tlo.methods.causes import Cause from tlo.methods.dxmanager import DxTest -from tlo.methods.healthsystem import HealthSystemChangeParameters, HSI_Event +from tlo.methods.hsi_event import HSI_Event from tlo.methods.symptommanager import Symptom from tlo.util import random_date @@ -48,7 +48,13 @@ def __init__(self, name=None, resourcefilepath=None, run_with_checks=False): # initialise empty dict with set keys self.tb_outputs = {k: [] for k in keys} - INIT_DEPENDENCIES = {"Demography", "HealthSystem", "Lifestyle", "SymptomManager", "Epi"} + INIT_DEPENDENCIES = { + "Demography", + "HealthSystem", + "Lifestyle", + "SymptomManager", + "Epi", + } OPTIONAL_INIT_DEPENDENCIES = {"HealthBurden", "Hiv"} @@ -123,10 +129,9 @@ def __init__(self, name=None, resourcefilepath=None, run_with_checks=False): "none", "tb_tx_adult", "tb_tx_child", - "tb_tx_child_shorter", "tb_retx_adult", "tb_retx_child", - "tb_mdrtx" + "tb_mdrtx", ], description="current tb treatment regimen", ), @@ -164,9 +169,6 @@ def __init__(self, name=None, resourcefilepath=None, run_with_checks=False): "rr_tb_child": Parameter( Types.REAL, "relative risk of tb infection if under 16 years of age" ), - "rr_bcg_inf": Parameter( - Types.REAL, "relative risk of tb infection with bcg vaccination" - ), "monthly_prob_relapse_tx_complete": Parameter( Types.REAL, "monthly probability of relapse once treatment complete" ), @@ -180,6 +182,9 @@ def __init__(self, name=None, resourcefilepath=None, run_with_checks=False): "rr_relapse_hiv": Parameter( Types.REAL, "relative risk of relapse for HIV-positive people" ), + "rr_relapse_diabetes": Parameter( + Types.REAL, "relative risk of relapse for people with diabetes (treated/untreated)" + ), # ------------------ active disease ------------------ # "scaling_factor_WHO": Parameter( Types.REAL, @@ -215,6 +220,9 @@ def __init__(self, name=None, resourcefilepath=None, run_with_checks=False): "death_rate_adult_treated": Parameter( Types.REAL, "probability of death in adult aged >=15 years with treated tb" ), + "rr_death_diabetes": Parameter( + Types.REAL, "additional risk of death if person has diabetes (treated/untreated)" + ), # ------------------ progression to active disease ------------------ # "rr_tb_bcg": Parameter( Types.REAL, @@ -238,9 +246,9 @@ def __init__(self, name=None, resourcefilepath=None, run_with_checks=False): "rr_tb_obese": Parameter( Types.REAL, "relative risk of progression to active disease if obese" ), - "rr_tb_diabetes1": Parameter( + "rr_tb_diabetes": Parameter( Types.REAL, - "relative risk of progression to active disease with type 1 diabetes", + "relative risk of progression to active disease with any type diabetes", ), "rr_tb_alcohol": Parameter( Types.REAL, @@ -315,9 +323,6 @@ def __init__(self, name=None, resourcefilepath=None, run_with_checks=False): "prob_tx_success_5_14": Parameter( Types.REAL, "Probability of treatment success for children aged 5-14 years" ), - "prob_tx_success_shorter": Parameter( - Types.REAL, "Probability of treatment success for children aged <16 years on shorter regimen" - ), # ------------------ testing rates ------------------ # "rate_testing_general_pop": Parameter( Types.REAL, @@ -339,9 +344,6 @@ def __init__(self, name=None, resourcefilepath=None, run_with_checks=False): "mdr_treatment_length": Parameter( Types.REAL, "length of treatment for mdr-tb in months" ), - "child_shorter_treatment_length": Parameter( - Types.REAL, "length of treatment for shorter paediatric regimen in months" - ), "prob_retained_ipt_6_months": Parameter( Types.REAL, "probability of being retained on IPT every 6 months if still eligible", @@ -354,14 +356,6 @@ def __init__(self, name=None, resourcefilepath=None, run_with_checks=False): Types.INT, "year from which IPT is available for paediatric contacts of diagnosed active TB cases", ), - "scenario": Parameter( - Types.INT, - "integer value labelling the scenario to be run: default is 0" - ), - "scenario_start_date": Parameter( - Types.DATE, - "date from which different scenarios are run" - ), "first_line_test": Parameter( Types.STRING, "name of first test to be used for TB diagnosis" @@ -370,19 +364,31 @@ def __init__(self, name=None, resourcefilepath=None, run_with_checks=False): Types.STRING, "name of second test to be used for TB diagnosis" ), - "probability_access_to_xray": Parameter( - Types.REAL, - "probability a person will have access to chest x-ray" + "tb_healthseekingbehaviour_cap": Parameter( + Types.INT, + "number of repeat visits assumed for healthcare services", ), - "prob_tb_referral_in_generic_hsi": Parameter( - Types.REAL, - "probability of referral to TB screening HSI if presenting with TB-related symptoms" + "data_end": Parameter( + Types.INT, + "last year for which data are available", + ), + "length_of_inpatient_stay_if_terminal": Parameter( + Types.LIST, + "length of inpatient stay for end-of-life TB patients", ), # ------------------ scale-up parameters for scenario analysis ------------------ # - "scaleup_parameters": Parameter( - Types.DATA_FRAME, - "list of parameters and values changed in scenario analysis", + "do_scaleup": Parameter( + Types.BOOL, + "argument to determine whether scale-up of program will be implemented" + ), + "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, + "the parameters and values changed in scenario analysis" + ) } def read_parameters(self, data_folder): @@ -413,8 +419,6 @@ def read_parameters(self, data_folder): p["ipt_coverage"] = workbook["ipt_coverage"] - p["scaleup_parameters"] = workbook["scaleup_parameters"] - self.district_list = ( self.sim.modules["Demography"] .parameters["pop_2010"]["District"] @@ -422,6 +426,9 @@ def read_parameters(self, data_folder): .tolist() ) + # load parameters for scale-up projections + p["scaleup_parameters"] = workbook["scaleup_parameters"].set_index('parameter')['scaleup_value'].to_dict() + # 2) Get the DALY weights if "HealthBurden" in self.sim.modules.keys(): # HIV-negative @@ -540,16 +547,14 @@ def pre_initialise_population(self): ), ] conditional_predictors = [ - Predictor("nc_diabetes").when(True, p['rr_tb_diabetes1']), - ] if "cardio_metabolic_disorders" in self.sim.modules else [] + Predictor("nc_diabetes").when(True, p['rr_tb_diabetes']), + ] if "CardioMetabolicDisorders" in self.sim.modules else [] self.lm["active_tb"] = LinearModel.multiplicative( *(predictors + conditional_predictors)) # risk of relapse <2 years following treatment - self.lm["risk_relapse_2yrs"] = LinearModel( - LinearModelType.MULTIPLICATIVE, - p["monthly_prob_relapse_tx_complete"], + predictors = [ Predictor("hv_inf").when(True, p["rr_relapse_hiv"]), Predictor("tb_treatment_failure") .when(True, (p["monthly_prob_relapse_tx_incomplete"] / p["monthly_prob_relapse_tx_complete"])), @@ -561,7 +566,16 @@ def pre_initialise_population(self): 'tb_on_ipt & ' 'age_years > 15', p["rr_ipt_adult"]), - ) + ] + + conditional_predictors = [ + Predictor("nc_diabetes").when(True, p['rr_relapse_diabetes']), + ] if "CardioMetabolicDisorders" in self.sim.modules else [] + + self.lm["risk_relapse_2yrs"] = LinearModel( + LinearModelType.MULTIPLICATIVE, + p["monthly_prob_relapse_tx_complete"], + *(predictors + conditional_predictors)) # risk of relapse if >=2 years post treatment self.lm["risk_relapse_late"] = LinearModel( @@ -579,9 +593,7 @@ def pre_initialise_population(self): ) # probability of death - self.lm["death_rate"] = LinearModel( - LinearModelType.MULTIPLICATIVE, - 1, + predictors = [ Predictor().when( "(tb_on_treatment == True) & " "(age_years <=4)", @@ -607,7 +619,14 @@ def pre_initialise_population(self): "(tb_smear == False)", p["death_rate_smear_neg_untreated"], ), - ) + ] + + conditional_predictors = [ + Predictor("nc_diabetes").when(True, p['rr_death_diabetes']), + ] if "CardioMetabolicDisorders" in self.sim.modules else [] + + self.lm["death_rate"] = LinearModel.multiplicative( + *(predictors + conditional_predictors)) def send_for_screening_general(self, population): @@ -740,6 +759,7 @@ def get_consumables_for_dx_and_tx(self): ) # 4) -------- Define the treatment options -------- + # treatment supplied as full kits for duration of treatment # adult treatment - primary self.item_codes_for_consumables_required['tb_tx_adult'] = \ hs.get_item_code_from_item_name("Cat. I & III Patient Kit A") @@ -748,10 +768,6 @@ def get_consumables_for_dx_and_tx(self): self.item_codes_for_consumables_required['tb_tx_child'] = \ hs.get_item_code_from_item_name("Cat. I & III Patient Kit B") - # child treatment - primary, shorter regimen - self.item_codes_for_consumables_required['tb_tx_child_shorter'] = \ - hs.get_item_code_from_item_name("Cat. I & III Patient Kit B") - # adult treatment - secondary self.item_codes_for_consumables_required['tb_retx_adult'] = \ hs.get_item_code_from_item_name("Cat. II Patient Kit A1") @@ -761,12 +777,16 @@ def get_consumables_for_dx_and_tx(self): hs.get_item_code_from_item_name("Cat. II Patient Kit A2") # mdr treatment - self.item_codes_for_consumables_required['tb_mdrtx'] = { - hs.get_item_code_from_item_name("Treatment: second-line drugs"): 1} + self.item_codes_for_consumables_required['tb_mdrtx'] = \ + hs.get_item_code_from_item_name("Treatment: second-line drugs") # ipt - self.item_codes_for_consumables_required['tb_ipt'] = { - hs.get_item_code_from_item_name("Isoniazid/Pyridoxine, tablet 300 mg"): 1} + self.item_codes_for_consumables_required['tb_ipt'] = \ + hs.get_item_code_from_item_name("Isoniazid/Pyridoxine, tablet 300 mg") + + # 3hp + self.item_codes_for_consumables_required['tb_3HP'] = \ + hs.get_item_code_from_item_name("Isoniazid/Rifapentine") def initialise_population(self, population): @@ -835,21 +855,25 @@ def initialise_population(self, population): def initialise_simulation(self, sim): """ * 1) Schedule the regular TB events - * 2) Schedule the scenario change + * 2) schedule logging * 3) Define the DxTests and treatment options """ # 1) Regular events sim.schedule_event(TbActiveEvent(self), sim.date) - sim.schedule_event(TbTreatmentAndRelapseEvents(self), sim.date) + sim.schedule_event(TbRegularEvents(self), sim.date) sim.schedule_event(TbSelfCureEvent(self), sim.date) sim.schedule_event(TbActiveCasePoll(self), sim.date + DateOffset(years=1)) - # log at the end of the year - sim.schedule_event(TbLoggingEvent(self), sim.date + DateOffset(years=1)) + # 2) log at the end of the year + # Optional: Schedule the scale-up of programs + if self.parameters["do_scaleup"]: + 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(TbScaleUpEvent(self), scaleup_start_date) - # 2) Scenario change - sim.schedule_event(ScenarioSetupEvent(self), self.parameters["scenario_start_date"]) + # 2) log at the end of the year + sim.schedule_event(TbLoggingEvent(self), sim.date + DateOffset(years=1)) # 3) Define the DxTests and get the consumables required self.get_consumables_for_dx_and_tx() @@ -860,6 +884,31 @@ def initialise_simulation(self, sim): TbCheckPropertiesEvent(self), sim.date + pd.DateOffset(months=1) ) + def update_parameters_for_program_scaleup(self): + + p = self.parameters + scaled_params = p["scaleup_parameters"] + + if p["do_scaleup"]: + + # scale-up TB program + # use NTP treatment rates + p["rate_testing_active_tb"]["treatment_coverage"] = scaled_params["tb_treatment_coverage"] + + # increase tb treatment success rates + p["prob_tx_success_ds"] = scaled_params["tb_prob_tx_success_ds"] + p["prob_tx_success_mdr"] = scaled_params["tb_prob_tx_success_mdr"] + p["prob_tx_success_0_4"] = scaled_params["tb_prob_tx_success_0_4"] + p["prob_tx_success_5_14"] = scaled_params["tb_prob_tx_success_5_14"] + + # change first-line testing for TB to xpert + p["first_line_test"] = scaled_params["first_line_test"] + p["second_line_test"] = scaled_params["second_line_test"] + + # increase coverage of IPT + p["ipt_coverage"]["coverage_plhiv"] = scaled_params["ipt_coverage_plhiv"] + p["ipt_coverage"]["coverage_paediatric"] = scaled_params["ipt_coverage_paediatric"] + def on_birth(self, mother_id, child_id): """Initialise properties for a newborn individual allocate IPT for child if mother diagnosed with TB @@ -1163,22 +1212,9 @@ def end_treatment(self, population): ) ].index - # ---------------------- treatment end: shorter paediatric regimen ---------------------- # - # end treatment for paediatric cases on 4 month regimen - end_tx_shorter_idx = df.loc[ - df.is_alive - & df.tb_on_treatment - & (df.tb_treatment_regimen == "tb_tx_child_shorter") - & ( - now - > (df.tb_date_treated + pd.DateOffset(months=p["child_shorter_treatment_length"])) - ) - ].index - # join indices end_tx_idx = end_ds_tx_idx.union(end_ds_retx_idx) end_tx_idx = end_tx_idx.union(end_mdr_tx_idx) - end_tx_idx = end_tx_idx.union(end_tx_shorter_idx) # ---------------------- treatment failure ---------------------- # # sample some to have treatment failure @@ -1199,13 +1235,6 @@ def end_treatment(self, population): & (random_var < (1 - p["prob_tx_success_5_14"])) ].index - # children aged <16 and on shorter regimen - ds_tx_failure_shorter_idx = df.loc[ - (df.index.isin(end_tx_shorter_idx)) - & (df.age_years < 16) - & (random_var < (1 - p["prob_tx_success_shorter"])) - ].index - # adults ds-tb ds_tx_failure_adult_idx = df.loc[ (df.index.isin(end_ds_tx_idx)) @@ -1224,7 +1253,6 @@ def end_treatment(self, population): (df.index.isin(end_mdr_tx_idx)) & (df.tb_strain == "mdr") & (random_var < (1 - p["prob_tx_success_mdr"])) - ].index # join indices of failing cases together @@ -1233,7 +1261,6 @@ def end_treatment(self, population): ( ds_tx_failure0_4_idx, ds_tx_failure5_14_idx, - ds_tx_failure_shorter_idx, ds_tx_failure_adult_idx, failure_in_mdr_with_ds_tx_idx, failure_due_to_mdr_idx, @@ -1328,118 +1355,6 @@ def is_subset(col_for_set, col_for_subset): # # --------------------------------------------------------------------------- # # TB infection event # # --------------------------------------------------------------------------- -class ScenarioSetupEvent(RegularEvent, PopulationScopeEventMixin): - """ This event exists to change parameters or functions - depending on the scenario for projections which has been set - * scenario 0 is the default which uses baseline parameters - * scenario 1 achieves all program targets with consumables constraints - * scenario 2 achieves all program targets without consumables constraints - It only occurs once at param: scenario_start_date, - called by initialise_simulation - """ - - def __init__(self, module): - super().__init__(module, frequency=DateOffset(years=100)) - - def apply(self, population): - - p = self.module.parameters - scenario = p["scenario"] - scaled_params = p["scaleup_parameters"] - - logger.debug( - key="message", data=f"ScenarioSetupEvent: scenario {scenario}" - ) - - # baseline scenario 0: no change to parameters/functions - if scenario == 0: - return - - # scenario 1 or 2 scale-up all HIV/TB program activities - if scenario > 0: - # HIV - # reduce risk of HIV - applies to whole adult population - self.sim.modules["Hiv"].parameters["beta"] = self.sim.modules["Hiv"].parameters["beta"] * scaled_params.loc[ - scaled_params.parameter == "hiv_beta", "value"].values[0] - - # increase PrEP coverage for FSW after HIV test - self.sim.modules["Hiv"].parameters["prob_prep_for_fsw_after_hiv_test"] = scaled_params.loc[ - scaled_params.parameter == "prob_prep_for_fsw_after_hiv_test", "value"].values[0] - - # prep poll for AGYW - target to the highest risk - # increase retention to 75% for FSW and AGYW - self.sim.modules["Hiv"].parameters["prob_prep_for_agyw"] = scaled_params.loc[ - scaled_params.parameter == "prob_prep_for_agyw", "value"].values[0] - self.sim.modules["Hiv"].parameters[ - "probability_of_being_retained_on_prep_every_3_months"] = scaled_params.loc[ - scaled_params.parameter == "probability_of_being_retained_on_prep_every_3_months", "value"].values[0] - - # increase probability of VMMC after hiv test - self.sim.modules["Hiv"].parameters["prob_circ_after_hiv_test"] = scaled_params.loc[ - scaled_params.parameter == "prob_circ_after_hiv_test", "value"].values[0] - - # increase testing/diagnosis rates, default 2020 0.03/0.25 -> 93% dx - self.sim.modules["Hiv"].parameters["hiv_testing_rates"]["annual_testing_rate_children"] = scaled_params.loc[ - scaled_params.parameter == "annual_testing_rate_children", "value"].values[0] - self.sim.modules["Hiv"].parameters["hiv_testing_rates"]["annual_testing_rate_adults"] = scaled_params.loc[ - scaled_params.parameter == "annual_testing_rate_adults", "value"].values[0] - - # ANC testing - value for mothers and infants testing - self.sim.modules["Hiv"].parameters["prob_hiv_test_at_anc_or_delivery"] = scaled_params.loc[ - scaled_params.parameter == "prob_hiv_test_at_anc_or_delivery", "value"].values[0] - self.sim.modules["Hiv"].parameters["prob_hiv_test_for_newborn_infant"] = scaled_params.loc[ - scaled_params.parameter == "prob_hiv_test_for_newborn_infant", "value"].values[0] - - # prob ART start if dx, this is already 95% at 2020 - # self.sim.modules["Hiv"].parameters["prob_start_art_after_hiv_test"] = scaled_params.loc[ - # scaled_params.parameter == - # "prob_start_art_after_hiv_test", "value"].values[0] - - # viral suppression rates - # adults already at 95% by 2020 - # change all column values - self.sim.modules["Hiv"].parameters["prob_start_art_or_vs"]["virally_suppressed_on_art"] = scaled_params.loc[ - scaled_params.parameter == "virally_suppressed_on_art", "value"].values[0] - - # TB - # use NTP treatment rates - self.sim.modules["Tb"].parameters["rate_testing_active_tb"]["treatment_coverage"] = scaled_params.loc[ - scaled_params.parameter == "tb_treatment_coverage", "value"].values[0] - - # increase tb treatment success rates - self.sim.modules["Tb"].parameters["prob_tx_success_ds"] = scaled_params.loc[ - scaled_params.parameter == "tb_prob_tx_success_ds", "value"].values[0] - self.sim.modules["Tb"].parameters["prob_tx_success_mdr"] = scaled_params.loc[ - scaled_params.parameter == "tb_prob_tx_success_mdr", "value"].values[0] - self.sim.modules["Tb"].parameters["prob_tx_success_0_4"] = scaled_params.loc[ - scaled_params.parameter == "tb_prob_tx_success_0_4", "value"].values[0] - self.sim.modules["Tb"].parameters["prob_tx_success_5_14"] = scaled_params.loc[ - scaled_params.parameter == "tb_prob_tx_success_5_14", "value"].values[0] - self.sim.modules["Tb"].parameters["prob_tx_success_shorter"] = scaled_params.loc[ - scaled_params.parameter == "tb_prob_tx_success_shorter", "value"].values[0] - - # change first-line testing for TB to xpert - p["first_line_test"] = scaled_params.loc[ - scaled_params.parameter == "first_line_test", "value"].values[0] - p["second_line_test"] = scaled_params.loc[ - scaled_params.parameter == "second_line_test", "value"].values[0] - - # increase coverage of IPT - p["ipt_coverage"]["coverage_plhiv"] = scaled_params.loc[ - scaled_params.parameter == "ipt_coverage_plhiv", "value"].values[0] - p["ipt_coverage"]["coverage_paediatric"] = scaled_params.loc[ - scaled_params.parameter == "ipt_coverage_paediatric", "value"].values[0] - - # remove consumables constraints, all cons available - if scenario == 2: - # list only things that change: constraints on consumables - new_parameters = { - 'cons_availability': 'all', - } - self.sim.schedule_event( - HealthSystemChangeParameters( - self.sim.modules['HealthSystem'], parameters=new_parameters), - self.sim.date) class TbActiveCasePoll(RegularEvent, PopulationScopeEventMixin): @@ -1454,20 +1369,26 @@ def __init__(self, module): def apply(self, population): p = self.module.parameters + + current_year = min(self.sim.date.year, p["data_end"]) + inc_estimates = p["who_incidence_estimates"] incidence_year = (inc_estimates.loc[ - (inc_estimates.year == self.sim.date.year), "incidence_per_100k" + (inc_estimates.year == current_year), "incidence_per_100k" ].values[0]) / 100000 prop_untreated_ds = self.module.calculate_untreated_proportion(population, strain="ds") prop_untreated_mdr = self.module.calculate_untreated_proportion(population, strain="mdr") - scaled_incidence_ds = incidence_year * \ - p["scaling_factor_WHO"] * prop_untreated_ds - scaled_incidence_mdr = incidence_year * \ - p["prop_mdr2010"] * \ - p["scaling_factor_WHO"] * \ - prop_untreated_mdr + scaled_incidence_ds = ( + incidence_year * p["scaling_factor_WHO"] * prop_untreated_ds + ) + scaled_incidence_mdr = ( + incidence_year + * p["prop_mdr2010"] + * p["scaling_factor_WHO"] + * prop_untreated_mdr + ) # transmission ds-tb self.module.assign_active_tb(population, strain="ds", incidence=scaled_incidence_ds) @@ -1476,8 +1397,8 @@ def apply(self, population): self.module.assign_active_tb(population, strain="mdr", incidence=scaled_incidence_mdr) -class TbTreatmentAndRelapseEvents(RegularEvent, PopulationScopeEventMixin): - """ This event runs each month and calls three functions: +class TbRegularEvents(RegularEvent, PopulationScopeEventMixin): + """This event runs each month and calls three functions: * scheduling TB screening for the general population * ending treatment if end of treatment regimen has been reached * determining who will relapse after a primary infection @@ -1494,6 +1415,21 @@ def apply(self, population): self.module.relapse_event(population) +class TbScaleUpEvent(Event, PopulationScopeEventMixin): + """ This event exists to change parameters or functions + depending on the scenario for projections which has been set + It only occurs once on date: scaleup_start_date, + called by initialise_simulation + """ + + def __init__(self, module): + super().__init__(module) + + def apply(self, population): + + self.module.update_parameters_for_program_scaleup() + + class TbActiveEvent(RegularEvent, PopulationScopeEventMixin): """ * check for those with dates of active tb onset within last time-period @@ -1548,7 +1484,7 @@ def apply(self, population): active_and_hiv = df.loc[ (df.index.isin(active_idx) & df.hv_inf)].index - # higher probability of being smear positive than HIV- + # lower probability of being smear positive than HIV- smear_pos = ( rng.random_sample(len(active_and_hiv)) < p["prop_smear_positive_hiv"] ) @@ -1567,10 +1503,12 @@ def apply(self, population): # if Hiv not registered, give HIV+ person same time to death as HIV- for person_id in active_and_hiv: date_of_tb_death = self.sim.date + pd.DateOffset( - months=int(rng.uniform(low=1, high=6)) + months=int(rng.uniform(low=1, high=5)) ) self.sim.schedule_event( - event=TbDeathEvent(person_id=person_id, module=self.module, cause="AIDS_TB"), + event=TbDecideDeathEvent( + person_id=person_id, module=self.module, cause="AIDS_TB" + ), date=date_of_tb_death, ) @@ -1585,22 +1523,25 @@ def apply(self, population): months=int(rng.uniform(low=1, high=6)) ) self.sim.schedule_event( - event=TbDeathEvent(person_id=person_id, module=self.module, cause="TB"), + event=TbDecideDeathEvent( + person_id=person_id, module=self.module, cause="TB" + ), date=date_of_tb_death, ) # -------- 5) schedule screening for asymptomatic and symptomatic people -------- - # sample from all new active cases (active_idx) and determine whether they will seek a test + # sample from all NEW active cases (active_idx) and determine whether they will seek a test year = min(2019, max(2011, now.year)) active_testing_rates = p["rate_testing_active_tb"] # change to NTP testing rates - current_active_testing_rate = active_testing_rates.loc[ - ( - active_testing_rates.year == year), - "treatment_coverage"].values[ - 0] / 100 + current_active_testing_rate = ( + active_testing_rates.loc[ + (active_testing_rates.year == year), "treatment_coverage" + ].values[0] + / 100 + ) # multiply testing rate by average treatment availability to match treatment coverage current_active_testing_rate = current_active_testing_rate * (1 / 0.6) @@ -1611,7 +1552,8 @@ def apply(self, population): # would only be screened if have symptoms for >= 14 days # sample some of active_idx to go for screening screen_active_idx = df.loc[ - (df.index.isin(active_idx) & (random_draw < current_active_testing_rate))].index + (df.index.isin(active_idx) & (random_draw < current_active_testing_rate)) + ].index # TB screening checks for symptoms lasting at least 14 days, so add delay for person in screen_active_idx: @@ -1691,7 +1633,7 @@ def apply(self, population): class HSI_Tb_ScreeningAndRefer(HSI_Event, IndividualScopeEventMixin): """ - The is the Screening-and-Refer HSI. + This is the Screening-and-Refer HSI. A positive outcome from symptom-based screening will prompt referral to tb tests (sputum/xpert/xray) no consumables are required for screening (4 clinical questions) @@ -1711,16 +1653,17 @@ class HSI_Tb_ScreeningAndRefer(HSI_Event, IndividualScopeEventMixin): * give IPT for paediatric contacts of diagnosed case """ - def __init__(self, module, person_id, suppress_footprint=False): + def __init__(self, module, person_id, suppress_footprint=False, facility_level='1a'): super().__init__(module, person_id=person_id) assert isinstance(module, Tb) + self.facility_level = facility_level assert isinstance(suppress_footprint, bool) self.suppress_footprint = suppress_footprint self.TREATMENT_ID = "Tb_Test_Screening" self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({"Over5OPD": 1}) - self.ACCEPTED_FACILITY_LEVEL = '1a' + self.ACCEPTED_FACILITY_LEVEL = "1a" if self.facility_level == "1a" else "2" def apply(self, person_id, squeeze_factor): """Do the screening and referring to next tests""" @@ -1730,8 +1673,19 @@ def apply(self, person_id, squeeze_factor): p = self.module.parameters person = df.loc[person_id] - # If the person is dead or already diagnosed, do nothing do not occupy any resources - if not person["is_alive"] or person["tb_diagnosed"]: + if not person["is_alive"]: + return self.sim.modules["HealthSystem"].get_blank_appt_footprint() + + # If the person is already diagnosed, do nothing do not occupy any resources + if person["tb_diagnosed"]: + return self.sim.modules["HealthSystem"].get_blank_appt_footprint() + + # If the person is already on treatment and not failing, do nothing do not occupy any resources + if person["tb_on_treatment"] and not person["tb_treatment_failure"]: + return self.sim.modules["HealthSystem"].get_blank_appt_footprint() + + # if person has tested within last 14 days, do nothing + if person["tb_date_tested"] >= (self.sim.date - DateOffset(days=7)): return self.sim.modules["HealthSystem"].get_blank_appt_footprint() logger.debug( @@ -1740,15 +1694,11 @@ def apply(self, person_id, squeeze_factor): smear_status = person["tb_smear"] - # If the person is already on treatment and not failing, do nothing do not occupy any resources - if person["tb_on_treatment"] and not person["tb_treatment_failure"]: - return self.sim.modules["HealthSystem"].get_blank_appt_footprint() - # ------------------------- screening ------------------------- # # 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) + persons_symptoms = self.sim.modules["SymptomManager"].has_what(person_id=person_id) if not any(x in self.module.symptom_list for x in persons_symptoms): return self.make_appt_footprint({}) @@ -1763,13 +1713,17 @@ def apply(self, person_id, squeeze_factor): if not person["hv_diagnosed"] or (person["hv_last_test_date"] >= (now - DateOffset(days=7))): self.sim.modules["HealthSystem"].schedule_hsi_event( hsi_event=hiv.HSI_Hiv_TestAndRefer( - person_id=person_id, module=self.sim.modules["Hiv"], referred_from='Tb' + person_id=person_id, + module=self.sim.modules["Hiv"], + referred_from="Tb", ), priority=1, topen=now, tclose=None, ) + # ------------------------- x-ray for children ------------------------- # + # child under 5 -> chest x-ray, but access is limited # if xray not available, HSI_Tb_Xray_level1b will refer if person["age_years"] < 5: @@ -1786,6 +1740,8 @@ def apply(self, person_id, squeeze_factor): ) test_result = False # to avoid calling a clinical diagnosis + # ------------------------- select test for adults ------------------------- # + # for all presumptive cases over 5 years of age else: # this selects a test for the person @@ -1800,35 +1756,64 @@ def apply(self, person_id, squeeze_factor): # relevant test depends on smear status (changes parameters on sensitivity/specificity if smear_status: - test_result = self.sim.modules["HealthSystem"].dx_manager.run_dx_test( + test_result = self.sim.modules[ + "HealthSystem" + ].dx_manager.run_dx_test( dx_tests_to_run="tb_sputum_test_smear_positive", hsi_event=self ) else: # if smear-negative, sputum smear should always return negative # run the dx test to log the consumable - test_result = self.sim.modules["HealthSystem"].dx_manager.run_dx_test( + test_result = self.sim.modules[ + "HealthSystem" + ].dx_manager.run_dx_test( dx_tests_to_run="tb_sputum_test_smear_negative", hsi_event=self ) # if negative, check for presence of all symptoms (clinical diagnosis) if all(x in self.module.symptom_list for x in persons_symptoms): - test_result = self.sim.modules["HealthSystem"].dx_manager.run_dx_test( + test_result = self.sim.modules[ + "HealthSystem" + ].dx_manager.run_dx_test( dx_tests_to_run="tb_clinical", hsi_event=self ) + if test_result is not None: + # Add used equipment + self.add_equipment({'Sputum Collection box', 'Ordinary Microscope'}) elif test == "xpert": - ACTUAL_APPT_FOOTPRINT = self.make_appt_footprint( - {"Over5OPD": 1} - ) - # relevant test depends on smear status (changes parameters on sensitivity/specificity - if smear_status: - test_result = self.sim.modules["HealthSystem"].dx_manager.run_dx_test( - dx_tests_to_run="tb_xpert_test_smear_positive", hsi_event=self + + # this can only be performed at level 1b/2, refer if necessary + if self.facility_level == "1a": + self.sim.modules["HealthSystem"].schedule_hsi_event( + hsi_event=HSI_Tb_ScreeningAndRefer( + person_id=person_id, module=self.module, facility_level="2" + ), + topen=self.sim.date + DateOffset(days=1), + tclose=None, + priority=0, ) - # for smear-negative people + return self.make_appt_footprint({"Over5OPD": 1}) + else: - test_result = self.sim.modules["HealthSystem"].dx_manager.run_dx_test( - dx_tests_to_run="tb_xpert_test_smear_negative", hsi_event=self - ) + if smear_status: + # relevant test depends on smear status (changes parameters on sensitivity/specificity + test_result = self.sim.modules[ + "HealthSystem" + ].dx_manager.run_dx_test( + dx_tests_to_run="tb_xpert_test_smear_positive", + hsi_event=self, + ) + # for smear-negative people + else: + test_result = self.sim.modules[ + "HealthSystem" + ].dx_manager.run_dx_test( + dx_tests_to_run="tb_xpert_test_smear_negative", + hsi_event=self, + ) + if test_result is not None: + # Add used equipment + self.add_equipment({'Sputum Collection box', 'Gene Expert (16 Module)'}) # ------------------------- testing referrals ------------------------- # @@ -1847,6 +1832,9 @@ def apply(self, person_id, squeeze_factor): ACTUAL_APPT_FOOTPRINT = self.make_appt_footprint( {"Over5OPD": 2, "LabTBMicro": 1} ) + if test_result is not None: + # Add used equipment + self.add_equipment({'Sputum Collection box', 'Ordinary Microscope'}) # if still no result available, rely on clinical diagnosis if test_result is None: @@ -1905,9 +1893,7 @@ def apply(self, person_id, squeeze_factor): if ipt_eligible.any(): # select persons at highest risk of tb - rr_of_tb = self.module.lm["active_tb"].predict( - df.loc[ipt_eligible] - ) + rr_of_tb = self.module.lm["active_tb"].predict(df.loc[ipt_eligible]) # choose top 5 highest risk contacts ipt_sample = rr_of_tb.sort_values(ascending=False).head(5).index @@ -1975,7 +1961,7 @@ def apply(self, person_id, squeeze_factor): # check if patient has: cough, fever, night sweat, weight loss set_of_symptoms_that_indicate_tb = set(self.module.symptom_list) - persons_symptoms = self.sim.modules["SymptomManager"].has_what(person_id) + persons_symptoms = self.sim.modules["SymptomManager"].has_what(person_id=person_id) if not set_of_symptoms_that_indicate_tb.intersection(persons_symptoms): # if none of the above conditions are present, no further action @@ -1998,7 +1984,9 @@ def apply(self, person_id, squeeze_factor): ) self.sim.modules["HealthSystem"].schedule_hsi_event( - HSI_Tb_StartTreatment(person_id=person_id, module=self.module), + HSI_Tb_StartTreatment( + person_id=person_id, module=self.module, facility_level="1a" + ), topen=now, tclose=None, priority=0, @@ -2044,6 +2032,8 @@ def apply(self, person_id, squeeze_factor): test_result = self.sim.modules["HealthSystem"].dx_manager.run_dx_test( dx_tests_to_run="tb_xray_smear_negative", hsi_event=self ) + if test_result is not None: + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('X-ray')) # if consumables not available, refer to level 2 # return blank footprint as xray did not occur @@ -2064,7 +2054,9 @@ def apply(self, person_id, squeeze_factor): 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), + HSI_Tb_StartTreatment( + person_id=person_id, module=self.module, facility_level="1a" + ), topen=self.sim.date, tclose=None, priority=0, @@ -2079,7 +2071,7 @@ def apply(self, person_id, squeeze_factor): class HSI_Tb_Xray_level2(HSI_Event, IndividualScopeEventMixin): """ - The is the x-ray HSI performed at level 2 + This is the x-ray HSI performed at level 2 usually used for testing children unable to produce sputum positive result will prompt referral to start treatment """ @@ -2115,6 +2107,8 @@ def apply(self, person_id, squeeze_factor): test_result = self.sim.modules["HealthSystem"].dx_manager.run_dx_test( dx_tests_to_run="tb_xray_smear_negative", hsi_event=self ) + if test_result is not None: + self.add_equipment(self.healthcare_system.equipment.from_pkg_names('X-ray')) # if consumables not available, rely on clinical diagnosis # return blank footprint as xray was not available @@ -2135,7 +2129,9 @@ def apply(self, person_id, squeeze_factor): 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), + HSI_Tb_StartTreatment( + person_id=person_id, module=self.module, facility_level="1a" + ), topen=self.sim.date, tclose=None, priority=0, @@ -2156,13 +2152,15 @@ def apply(self, person_id, squeeze_factor): class HSI_Tb_StartTreatment(HSI_Event, IndividualScopeEventMixin): - def __init__(self, module, person_id): + def __init__(self, module, person_id, facility_level="1a"): super().__init__(module, person_id=person_id) assert isinstance(module, Tb) + self.facility_level = facility_level + self.TREATMENT_ID = "Tb_Treatment" - self.ACCEPTED_FACILITY_LEVEL = '1a' self.number_of_occurrences = 0 + self.ACCEPTED_FACILITY_LEVEL = "1a" if (self.facility_level == "1a") else "2" @property def EXPECTED_APPT_FOOTPRINT(self): @@ -2192,10 +2190,23 @@ def apply(self, person_id, squeeze_factor): return self.sim.modules["HealthSystem"].get_blank_appt_footprint() treatment_regimen = self.select_treatment(person_id) + # treatment supplied in kits, one kit per treatment course treatment_available = self.get_consumables( - item_codes=self.module.item_codes_for_consumables_required[treatment_regimen] + item_codes={self.module.item_codes_for_consumables_required[treatment_regimen]: 1} ) + # if require MDR treatment, and not currently at level 2, refer to level 2 + if (treatment_regimen == "tb_mdrtx") and (self.facility_level != "2"): + self.sim.modules["HealthSystem"].schedule_hsi_event( + hsi_event=HSI_Tb_StartTreatment( + person_id=person_id, module=self.module, facility_level="2" + ), + topen=self.sim.date + DateOffset(days=1), + tclose=None, + priority=0, + ) + return self.sim.modules["HealthSystem"].get_blank_appt_footprint() + if treatment_available: # start person on tb treatment - update properties df.at[person_id, "tb_on_treatment"] = True @@ -2207,16 +2218,15 @@ def apply(self, person_id, squeeze_factor): df.at[person_id, "tb_date_treated_mdr"] = now # schedule first follow-up appointment - follow_up_date = self.sim.date + DateOffset(months=1) logger.debug( key="message", data=f"HSI_Tb_StartTreatment: scheduling first follow-up " - f"for person {person_id} on {follow_up_date}", + f"for person {person_id}", ) self.sim.modules["HealthSystem"].schedule_hsi_event( HSI_Tb_FollowUp(person_id=person_id, module=self.module), - topen=follow_up_date, + topen=self.sim.date + DateOffset(months=1), tclose=None, priority=0, ) @@ -2224,17 +2234,19 @@ def apply(self, person_id, squeeze_factor): # if treatment not available, return for treatment start in 1 week # cap repeated visits at 5 else: - if self.number_of_occurrences <= 5: + + if ( + self.number_of_occurrences + <= self.module.parameters["tb_healthseekingbehaviour_cap"] + ): + self.sim.modules["HealthSystem"].schedule_hsi_event( - hsi_event=self, + self, topen=self.sim.date + DateOffset(weeks=1), tclose=None, priority=0, ) - def post_apply_hook(self): - self.number_of_occurrences += 1 - def select_treatment(self, person_id): """ helper function to select appropriate treatment and check whether @@ -2278,16 +2290,6 @@ def select_treatment(self, person_id): # treatment for reinfection ds-tb: child treatment_regimen = "tb_retx_child" - # -------- SHINE Trial shorter paediatric regimen -------- # - # shorter treatment for child with minimal tb - if (self.module.parameters["scenario"] == 5) \ - & (self.sim.date >= self.module.parameters["scenario_start_date"]) \ - & (person["age_years"] <= 16) \ - & ~(person["tb_smear"]) \ - & ~person["tb_ever_treated"] \ - & ~person["tb_diagnosed_mdr"]: - treatment_regimen = "tb_tx_child_shorter" - return treatment_regimen @@ -2353,11 +2355,6 @@ def apply(self, person_id, squeeze_factor): sputum_fup = follow_up_times["mdr_sputum"].dropna() treatment_length = p["mdr_treatment_length"] - # if person on shorter paediatric regimen - elif person["tb_treatment_regimen"] == "tb_tx_child_shorter": - sputum_fup = follow_up_times["shine_sputum"].dropna() - treatment_length = p["shine_treatment_length"] - # check schedule for sputum test and perform if necessary if months_since_tx in sputum_fup: ACTUAL_APPT_FOOTPRINT = self.make_appt_footprint( @@ -2373,6 +2370,9 @@ def apply(self, person_id, squeeze_factor): test_result = self.sim.modules["HealthSystem"].dx_manager.run_dx_test( dx_tests_to_run="tb_sputum_test_smear_negative", hsi_event=self ) + if test_result is not None: + # Add used equipment + self.add_equipment({'Sputum Collection box', 'Ordinary Microscope'}) # if sputum test was available and returned positive and not diagnosed with mdr, schedule xpert test if test_result and not person["tb_diagnosed_mdr"]: @@ -2387,6 +2387,9 @@ def apply(self, person_id, squeeze_factor): xperttest_result = self.sim.modules["HealthSystem"].dx_manager.run_dx_test( dx_tests_to_run="tb_xpert_test_smear_negative", hsi_event=self ) + if xperttest_result is not None: + # Add used equipment + self.add_equipment({'Sputum Collection box', 'Gene Expert (16 Module)'}) # if xpert test returns new mdr-tb diagnosis if xperttest_result and (df.at[person_id, "tb_strain"] == "mdr"): @@ -2432,8 +2435,9 @@ class HSI_Tb_Start_or_Continue_Ipt(HSI_Event, IndividualScopeEventMixin): * HIV.HSI_Hiv_StartOrContinueTreatment for PLHIV, diagnosed and on ART * Tb.HSI_Tb_StartTreatment for up to 5 contacts of diagnosed active TB case - if person referred by ART initiation (HIV+), IPT given for 36 months - paediatric IPT is 6-9 months + Isoniazid preventive therapy for HIV-infected children : 6 months, 180 doses + 3HP (Isoniazid/Rifapentine) for adults: 12 weeks, 12 doses + 3HP for children ages >2 yrs hiv- """ def __init__(self, module, person_id): @@ -2461,7 +2465,7 @@ def apply(self, person_id, squeeze_factor): return # if currently have symptoms of TB, refer for screening/testing - persons_symptoms = self.sim.modules["SymptomManager"].has_what(person_id) + persons_symptoms = self.sim.modules["SymptomManager"].has_what(person_id=person_id) if any(x in self.module.symptom_list for x in persons_symptoms): self.sim.modules["HealthSystem"].schedule_hsi_event( @@ -2473,10 +2477,23 @@ def apply(self, person_id, squeeze_factor): else: # Check/log use of consumables, and give IPT if available - # if not available, reschedule IPT start - if self.get_consumables( - item_codes=self.module.item_codes_for_consumables_required["tb_ipt"] - ): + + # if child and HIV+ or child under 2 yrs + if ((person["age_years"] <= 15) and person["hv_inf"]) or (person["age_years"] <= 2): + + # 6 months dispensation, once daily + drugs_available = self.get_consumables( + item_codes={self.module.item_codes_for_consumables_required["tb_ipt"]: 180}) + + # for all others + else: + # 12 weeks dispensation, once weekly + drugs_available = self.get_consumables( + item_codes={self.module.item_codes_for_consumables_required["tb_3HP"]: 12} + ) + + # if available, schedule IPT decision + if drugs_available: # Update properties df.at[person_id, "tb_on_ipt"] = True df.at[person_id, "tb_date_ipt"] = self.sim.date @@ -2488,8 +2505,11 @@ def apply(self, person_id, squeeze_factor): ) else: - # Reschedule this HSI to occur again, up to a 3 times in total - if self.number_of_occurrences < 3: + # Reschedule this HSI to occur again, up to a 5 times in total + if ( + self.number_of_occurrences + <= self.module.parameters["tb_healthseekingbehaviour_cap"] + ): self.sim.modules["HealthSystem"].schedule_hsi_event( self, topen=self.sim.date + pd.DateOffset(days=1), @@ -2498,6 +2518,39 @@ def apply(self, person_id, squeeze_factor): ) +class HSI_Tb_EndOfLifeCare(HSI_Event, IndividualScopeEventMixin): + """ + this is a hospital stay for terminally-ill patients with TB + it does not affect disability weight or probability of death + no consumables are logged but health system capacity (HR) is allocated + there are no consequences if hospital bed is not available as person has scheduled death + already within 2 weeks + """ + + def __init__(self, module, person_id, beddays=8): + super().__init__(module, person_id=person_id) + assert isinstance(module, Tb) + + self.TREATMENT_ID = "Tb_PalliativeCare" + self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({}) + self.ACCEPTED_FACILITY_LEVEL = "2" + + self.beddays = beddays + self.BEDDAYS_FOOTPRINT = self.make_beddays_footprint({"general_bed": self.beddays}) + + def apply(self, person_id, squeeze_factor): + df = self.sim.population.props + hs = self.sim.modules["HealthSystem"] + + if not df.at[person_id, "is_alive"]: + return hs.get_blank_appt_footprint() + + logger.debug( + key="message", + data=f"HSI_Tb_EndOfLifeCare: inpatient admission for {person_id}", + ) + + class Tb_DecisionToContinueIPT(Event, IndividualScopeEventMixin): """Helper event that is used to 'decide' if someone on IPT should continue or end This event is scheduled by 'HSI_Tb_Start_or_Continue_Ipt' after 6 months @@ -2540,11 +2593,13 @@ def apply(self, person_id): # --------------------------------------------------------------------------- -class TbDeathEvent(Event, IndividualScopeEventMixin): +class TbDecideDeathEvent(Event, IndividualScopeEventMixin): """ - The scheduled death for a tb case - check whether this death should occur using a linear model + The scheduled hospitalisation and subsequent death for a tb case + check whether death should occur using a linear model will depend on treatment status, smear status and age + then schedule a hospital stay prior to that death + hospital stay will not affect outcomes """ def __init__(self, module, person_id, cause): @@ -2553,6 +2608,7 @@ def __init__(self, module, person_id, cause): def apply(self, person_id): df = self.sim.population.props + p = self.module.parameters if not df.at[person_id, "is_alive"]: return @@ -2562,26 +2618,67 @@ def apply(self, person_id): logger.debug( key="message", - data=f"TbDeathEvent: checking whether death should occur for person {person_id}", + data=f"TbDecideDeathEvent: checking whether death should occur for person {person_id}", ) # use linear model to determine whether this person will die: rng = self.module.rng - result = self.module.lm["death_rate"].predict(df.loc[[person_id]], rng=rng) + will_die = self.module.lm["death_rate"].predict(df.loc[[person_id]], rng=rng) - if result: - logger.debug( - key="message", - data=f"TbDeathEvent: cause this death for person {person_id}", + if will_die: + # schedule hospital stay for this person + # schedule hospital stay + beddays = self.module.rng.randint( + low=p['length_of_inpatient_stay_if_terminal'][0], + high=p['length_of_inpatient_stay_if_terminal'][1]) + + self.sim.modules["HealthSystem"].schedule_hsi_event( + hsi_event=HSI_Tb_EndOfLifeCare( + person_id=person_id, module=self.sim.modules["Tb"], beddays=beddays + ), + priority=0, + topen=self.sim.date, + tclose=None, ) - self.sim.modules["Demography"].do_death( - individual_id=person_id, - cause=self.cause, - originating_module=self.module, + # schedule death for this person after hospital stay + self.sim.schedule_event( + event=TbDeathEvent(person_id=person_id, module=self.module), + date=self.sim.date + pd.DateOffset(days=beddays), ) +class TbDeathEvent(Event, IndividualScopeEventMixin): + """ + The scheduled death for a tb case + check whether this death should occur using a linear model + will depend on treatment status, smear status and age + """ + + def __init__(self, module, person_id): + super().__init__(module, person_id=person_id) + + def apply(self, person_id): + df = self.sim.population.props + + if not df.at[person_id, "is_alive"]: + return + + if not df.at[person_id, "tb_inf"] == "active": + return + + logger.debug( + key="message", + data=f"TbDeathEvent: cause this death for person {person_id}", + ) + + self.sim.modules["Demography"].do_death( + individual_id=person_id, + cause="TB", + originating_module=self.module, + ) + + # --------------------------------------------------------------------------- # Logging # --------------------------------------------------------------------------- @@ -2775,9 +2872,9 @@ def apply(self, population): # this will give ipt among whole population - not just eligible pop if new_tb_ipt: - ipt_coverage = new_tb_ipt / len(df[df.is_alive]) + current_ipt_coverage = new_tb_ipt / len(df[df.is_alive]) else: - ipt_coverage = 0 + current_ipt_coverage = 0 logger.info( key="tb_treatment", @@ -2786,7 +2883,7 @@ def apply(self, population): "tbNewDiagnosis": new_tb_diagnosis, "tbPropDiagnosed": prop_dx, "tbTreatmentCoverage": tx_coverage, - "tbIptCoverage": ipt_coverage, + "tbIptCoverage": current_ipt_coverage, }, ) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index aad8457ceb..abed021e95 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1,7 +1,7 @@ """Childhood wasting module""" import copy from pathlib import Path -from typing import Any, Dict, Union +from typing import TYPE_CHECKING, Any, Dict, Union import numpy as np import pandas as pd @@ -13,8 +13,13 @@ from tlo.methods import Metadata from tlo.methods.causes import Cause from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom +if TYPE_CHECKING: + from tlo.methods.hsi_generic_first_appts import HSIEventScheduler + from tlo.population import IndividualProperties + logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -25,7 +30,7 @@ # --------------------------------------------------------------------------- # MODULE DEFINITIONS # --------------------------------------------------------------------------- -class Wasting(Module): +class Wasting(Module, GenericFirstAppointmentsMixin): """ This module applies the prevalence of wasting at the population-level, based on the Malawi DHS Survey 2015-2016. The definitions: @@ -90,7 +95,7 @@ class Wasting(Module): 'rr_wasting_preterm_and_AGA': Parameter( Types.REAL, 'relative risk of wasting if born preterm and adequate for gestational age'), 'rr_wasting_SGA_and_term': Parameter( - Types.REAL, 'relative risk of wasting if born term and small for geatational age'), + Types.REAL, 'relative risk of wasting if born term and small for gestational age'), 'rr_wasting_SGA_and_preterm': Parameter( Types.REAL, 'relative risk of wasting if born preterm and small for gestational age'), 'rr_wasting_wealth_level': Parameter( @@ -324,7 +329,7 @@ def get_prob_severe_wasting_or_odds_wasting(self, agegp: str, get_odds: bool = F def muac_cutoff_by_WHZ(self, idx, whz): """ Proportion of MUAC<115mm in WHZ<-3 and -3<=WHZ<-2, and proportion of wasted children with oedematous - malnutrition ( Kwashiokor, marasmic-kwashiorkor) + malnutrition ( Kwashiorkor, marasmic-kwashiorkor) :param idx: index of children ages 6-59 months or person_id :param whz: weight for height category @@ -442,7 +447,7 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): def date_of_outcome_for_untreated_am(self, person_id, duration_am): """ - helper funtion to get the duration and the wasting episode and date of outcome (recovery, progression, or death) + helper function to get the duration, the wasting episode and date of outcome (recovery, progression, or death) :param person_id: :param duration_am: :return: @@ -519,8 +524,8 @@ def report_daly_values(self): (~df.un_am_bilateral_oedema)] = daly_wts['SAM_w/o_oedema'] total_daly_values.loc[df.is_alive & ( ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | ( - (df.un_WHZ_category != 'WHZ<-3') & ( - df.un_am_MUAC_category != "[115,125)mm"))) & df.un_am_bilateral_oedema] = daly_wts[ + (df.un_WHZ_category != 'WHZ<-3') & ( + df.un_am_MUAC_category != "[115,125)mm"))) & df.un_am_bilateral_oedema] = daly_wts[ 'MAM_with_oedema'] return total_daly_values @@ -541,26 +546,27 @@ def wasting_clinical_symptoms(self, person_id): disease_module=self ) - def do_when_acute_malnutrition_assessment(self, person_id): - """ - This is called by the generic HSI event when acute malnutrition is checked. - :param person_id: - :return: - """ - - df = self.sim.population.props + def do_at_generic_first_appt( + self, + person_id: int, + individual_properties: IndividualProperties, + schedule_hsi_event: HSIEventScheduler, + **kwargs, + ) -> None: + if individual_properties["age_years"] > 5: + return p = self.parameters # get the clinical states - clinical_am = df.at[person_id, 'un_clinical_acute_malnutrition'] - complications = df.at[person_id, 'un_sam_with_complications'] + clinical_am = individual_properties['un_clinical_acute_malnutrition'] + complications = individual_properties['un_sam_with_complications'] # Interventions for MAM if clinical_am == 'MAM': # Check for coverage of supplementary feeding if self.rng.random_sample() < p['coverage_supplementary_feeding_program']: # schedule HSI for supplementary feeding program for MAM - self.sim.modules['HealthSystem'].schedule_hsi_event( + schedule_hsi_event( hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), priority=0, topen=self.sim.date) else: @@ -571,7 +577,7 @@ def do_when_acute_malnutrition_assessment(self, person_id): # Check for coverage of outpatient therapeutic care if self.rng.random_sample() < p['coverage_outpatient_therapeutic_care']: # schedule HSI for supplementary feeding program for MAM - self.sim.modules['HealthSystem'].schedule_hsi_event( + schedule_hsi_event( hsi_event=HSI_Wasting_OutpatientTherapeuticProgramme_SAM( module=self, person_id=person_id), priority=0, topen=self.sim.date) else: @@ -581,7 +587,7 @@ def do_when_acute_malnutrition_assessment(self, person_id): # Check for coverage of outpatient therapeutic care if self.rng.random_sample() < p['coverage_inpatient_care']: # schedule HSI for supplementary feeding program for MAM - self.sim.modules['HealthSystem'].schedule_hsi_event( + schedule_hsi_event( hsi_event=HSI_Wasting_InpatientCareForComplicated_SAM( module=self, person_id=person_id), priority=0, topen=self.sim.date) else: @@ -633,7 +639,7 @@ def do_when_am_treatment(self, person_id, intervention): else: self.sim.schedule_event(event=UpdateToMAM(module=self, person_id=person_id), date=df.at[person_id, 'un_acute_malnutrition_tx_start_date'] + - DateOffset(weeks=3)) + DateOffset(weeks=3)) if intervention == 'ITC': sam_recovery = self.wasting_models.acute_malnutrition_recovery_sam_lm.predict( diff --git a/src/tlo/population.py b/src/tlo/population.py index d8b1379ff5..37f5fccfdf 100644 --- a/src/tlo/population.py +++ b/src/tlo/population.py @@ -1,51 +1,132 @@ -"""The Person and Population classes.""" +"""Types for representing a properties of a population of individuals.""" + import math +from collections.abc import Generator +from contextlib import contextmanager +from typing import Any, Dict, Optional, Set import pandas as pd -from tlo import logging +from tlo import Property, logging logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) +class IndividualProperties: + """Memoized view of population dataframe row that is optionally read-only. + + This class should not be instantiated directly but instead the + :py:meth:`Population.individual_properties` context manager method used to create + instances for a given population. + """ + + def __init__( + self, population_dataframe: pd.DataFrame, person_id: int, read_only: bool = True + ): + self._finalized = False + self._read_only = read_only + self._property_cache: Dict[str, Any] = {} + # Avoid storing a reference to population_dataframe internally by mediating + # access via closures to guard against direct access + self._get_value_at = lambda key: population_dataframe.at[person_id, key] + if not read_only: + self._properties_updated: Set[str] = set() + + def synchronize_updates_to_dataframe(): + row_index = population_dataframe.index.get_loc(person_id) + for key in self._properties_updated: + # This chained indexing approach to setting dataframe values is + # significantly (~3 to 4 times) quicker than using at / iat + # indexers, but will fail when copy-on-write is enabled which will + # be default in Pandas 3 + column = population_dataframe[key] + column.values[row_index] = self._property_cache[key] + + self._synchronize_updates_to_dataframe = synchronize_updates_to_dataframe + + def __getitem__(self, key: str) -> Any: + if self._finalized: + msg = f"Cannot read value for {key} as instance has been finalized" + raise ValueError(msg) + try: + return self._property_cache[key] + except KeyError: + value = self._get_value_at(key) + self._property_cache[key] = value + return value + + def __setitem__(self, key: str, value: Any) -> None: + if self._finalized: + msg = f"Cannot set value for {key} as instance has been finalized" + raise ValueError(msg) + if self._read_only: + msg = f"Cannot set value for {key} as destination is read-only" + raise ValueError(msg) + self._properties_updated.add(key) + self._property_cache[key] = value + + def synchronize_updates_to_dataframe(self) -> None: + """Synchronize values for any updated properties to population dataframe.""" + if not self._read_only: + self._synchronize_updates_to_dataframe() + self._properties_updated.clear() + + def finalize(self) -> None: + """Synchronize updates to population dataframe and prevent further access.""" + self.synchronize_updates_to_dataframe() + self._finalized = True + + class Population: """A complete population of individuals. Useful properties of a population: - `sim` - The Simulation instance controlling this population. - `props` A Pandas DataFrame with the properties of all individuals as columns. """ - __slots__ = ('props', 'sim', 'initial_size', 'new_row', 'next_person_id', 'new_rows') - - def __init__(self, sim, initial_size: int, append_size: int = None): + __slots__ = ( + "props", + "initial_size", + "new_row", + "next_person_id", + "new_rows", + ) + + def __init__( + self, + properties: Dict[str, Property], + initial_size: int, + append_size: Optional[int] = None, + ): """Create a new population. - This will create the required the population dataframe and initialise individual's - properties as dataframe columns with 'empty' values. The simulation will then call disease - modules to fill in suitable starting values. + This will create the required the population dataframe and initialise + individual's properties as dataframe columns with 'empty' values. The simulation + will then call disease modules to fill in suitable starting values. - :param sim: the Simulation containing this population - :param initial_size: the initial population size - :param append_size: how many rows to append when growing the population dataframe (optional) + :param properties: Dictionary defining properties (columns) to initialise + population dataframe with, keyed by property name and with values + :py:class:`Property` instances defining the property type. + :param initial_size: The initial population size. + :param append_size: How many rows to append when growing the population + dataframe (optional). """ - self.sim = sim self.initial_size = initial_size # Create empty property arrays - self.props = self._create_props(initial_size) + self.props = self._create_props(initial_size, properties) if append_size is None: # approximation based on runs to increase capacity of dataframe ~twice a year # TODO: profile adjustment of this and more clever calculation append_size = math.ceil(initial_size * 0.02) - assert append_size > 0, "Number of rows to append when growing must be greater than 0" + assert ( + append_size > 0 + ), "Number of rows to append when growing must be greater than 0" logger.info(key="info", data=f"Dataframe capacity append size: {append_size}") @@ -56,7 +137,7 @@ def __init__(self, sim, initial_size: int, append_size: int = None): # use the person_id of the next person to be added to the dataframe to increase capacity self.next_person_id = initial_size - def _create_props(self, size): + def _create_props(self, size: int, properties: Dict[str, Property]) -> pd.DataFrame: """Internal helper function to create a properties dataframe. :param size: the number of rows to create @@ -64,10 +145,9 @@ def _create_props(self, size): return pd.DataFrame( data={ property_name: property.create_series(property_name, size) - for module in self.sim.modules.values() - for property_name, property in module.PROPERTIES.items() + for property_name, property in properties.items() }, - index=pd.RangeIndex(stop=size, name="person") + index=pd.RangeIndex(stop=size, name="person"), ) def do_birth(self): @@ -83,9 +163,14 @@ def do_birth(self): # the index of the next person if self.next_person_id > index_of_last_row: # we need to add some rows - self.props = pd.concat((self.props, self.new_rows), ignore_index=True, sort=False) - self.props.index.name = 'person' - logger.info(key="info", data=f"Increased capacity of population dataframe to {len(self.props)}") + self.props = pd.concat( + (self.props, self.new_rows), ignore_index=True, sort=False + ) + self.props.index.name = "person" + logger.info( + key="info", + data=f"Increased capacity of population dataframe to {len(self.props)}", + ) new_index = self.next_person_id self.next_person_id += 1 @@ -107,6 +192,38 @@ def make_test_property(self, name, type_): the property """ from tlo import Property - prop = Property(type_, 'A test property') + + prop = Property(type_, "A test property") size = self.initial_size if self.props.empty else len(self.props) self.props[name] = prop.create_series(name, size) + + @contextmanager + def individual_properties( + self, person_id: int, read_only: bool = True + ) -> Generator[IndividualProperties, None, None]: + """ + Context manager for a memoized view of a row of the population dataframe. + + The view returned represents the properties of an individual with properties + accessible by indexing using string column names, and lazily read-on demand + from the population dataframe. + + Optionally the view returned may allow updating properties as well as reading. + In this case on exit from the ``with`` block in which the context is entered, + any updates to the individual properties will be written back to the population + dataframe. + + Once the ``with`` block in which the context is entered has been exited the view + returned will raise an error on any subsequent attempts at reading or writing + properties. + + :param person_id: Row index of the dataframe row to extract. + :param read_only: Whether view is read-only or allows updating properties. If + ``True`` :py:meth:`IndividualProperties.synchronize_updates_to_dataframe` + method needs to be called for any updates to be written back to population + dataframe. + :returns: Object allowing memoized access to an individual's properties. + """ + properties = IndividualProperties(self.props, person_id, read_only=read_only) + yield properties + properties.finalize() diff --git a/src/tlo/scenario.py b/src/tlo/scenario.py index d92f0b4aef..aa1be42aa9 100644 --- a/src/tlo/scenario.py +++ b/src/tlo/scenario.py @@ -60,12 +60,14 @@ def draw_parameters(self, draw_number, rng): """ import abc +import argparse import datetime import json import pickle +from collections.abc import Iterable from itertools import product from pathlib import Path, PurePosixPath -from typing import Optional +from typing import List, Optional import numpy as np @@ -125,6 +127,47 @@ def __init__( self.resources = resources_path self.rng = None self.scenario_path = None + self.arguments = [] + + def parse_arguments(self, extra_arguments: List[str]) -> None: + """Base class command line arguments handling for scenarios. This should not be overridden by subclasses. + Subclasses can add argument handling to their classes by implementing the `add_arguments` method.""" + + if extra_arguments is None: + return + + assert isinstance(extra_arguments, Iterable), "Arguments must be a list of strings" + + self.arguments = extra_arguments + + parser = argparse.ArgumentParser() + + # add arguments from the subclass + self.add_arguments(parser) + + arguments = parser.parse_args(self.arguments) + + # set the arguments as attributes of the scenario + for key, value in vars(arguments).items(): + if value is not None: + if hasattr(self, key): + logger.info(key="message", data=f"Overriding attribute: {key}: {getattr(self, key)} -> {value}") + setattr(self, key, value) + + def add_arguments(self, parser: argparse.ArgumentParser) -> None: + """Add scenario-specific arguments that can be passed to scenario from the command line. + + This method is called to add scenario-specific arguments to the command line parser. The method should add + arguments to the parser using the `add_argument` method. Arguments that have a value of None are not set or + overridden. + + :param parser: An instance of `argparse.ArgumentParser` to which arguments should be added. + + Example:: + + parser.add_argument('--pop-size', type=int, default=20_000, help='Population size') + """ + pass @abc.abstractmethod def log_configuration(self, **kwargs): @@ -282,11 +325,13 @@ def get_run_config(self, scenario_path): return { "scenario_script_path": str(PurePosixPath(scenario_path)), "scenario_seed": self.scenario.seed, + "arguments": self.scenario.arguments, "runs_per_draw": self.runs_per_draw, "draws": self.draws, } - def save_config(self, config, output_path): + @staticmethod + def save_config(config, output_path): with open(output_path, "w") as f: f.write(json.dumps(config, indent=2)) @@ -297,6 +342,8 @@ def __init__(self, run_configuration_path): with open(run_configuration_path, "r") as f: self.run_config = json.load(f) self.scenario = ScenarioLoader(self.run_config["scenario_script_path"]).get_scenario() + if self.run_config["arguments"] is not None: + self.scenario.parse_arguments(self.run_config["arguments"]) logger.info(key="message", data=f"Loaded scenario using {run_configuration_path}") logger.info(key="message", data=f"Found {self.number_of_draws} draws; {self.runs_per_draw} runs/draw") diff --git a/src/tlo/simulation.py b/src/tlo/simulation.py index 219b1b8a6f..761c161799 100644 --- a/src/tlo/simulation.py +++ b/src/tlo/simulation.py @@ -69,7 +69,7 @@ def __init__(self, *, start_date: Date, seed: int = None, log_config: dict = Non log_config = {} self._custom_log_levels = None self._log_filepath = None - self.configure_logging(**log_config) + self._configure_logging(**log_config) # random number generator seed_from = 'auto' if seed is None else 'user' @@ -81,8 +81,8 @@ def __init__(self, *, start_date: Date, seed: int = None, log_config: dict = Non ) self.rng = np.random.RandomState(np.random.MT19937(self._seed_seq)) - def configure_logging(self, filename: str = None, directory: Union[Path, str] = "./outputs", - custom_levels: Dict[str, int] = None, suppress_stdout: bool = False): + def _configure_logging(self, filename: str = None, directory: Union[Path, str] = "./outputs", + custom_levels: Dict[str, int] = None, suppress_stdout: bool = False): """Configure logging, can write logging to a logfile in addition the default of stdout. Minimum custom levels for each logger can be specified for filtering out messages @@ -183,7 +183,12 @@ def make_initial_population(self, *, n): module.pre_initialise_population() # Make the initial population - self.population = Population(self, n) + properties = { + name: prop + for module in self.modules.values() + for name, prop in module.PROPERTIES.items() + } + self.population = Population(properties, n) for module in self.modules.values(): start1 = time.time() module.initialise_population(self.population) diff --git a/src/tlo/test/random_birth.py b/src/tlo/test/random_birth.py index 950173797d..22a20879b1 100644 --- a/src/tlo/test/random_birth.py +++ b/src/tlo/test/random_birth.py @@ -68,7 +68,7 @@ def initialise_population(self, population): # We use 'broadcasting' to set the same value for every individual df.is_pregnant = False # We randomly sample birth dates for the initial population during the preceding decade - start_date = population.sim.date + start_date = self.sim.date dates = pd.date_range(start_date - DateOffset(years=10), start_date, freq='M') df.date_of_birth = self.rng.choice(dates, size=len(df)) # No children have yet been born. We iterate over the population to ensure each diff --git a/src/tlo/util.py b/src/tlo/util.py index bbc496af5e..77924e4fa3 100644 --- a/src/tlo/util.py +++ b/src/tlo/util.py @@ -7,7 +7,7 @@ import pandas as pd from pandas import DateOffset -from tlo import Population +from tlo import Population, Property, Types # Default mother_id value, assigned to individuals initialised as adults at the start of the simulation. DEFAULT_MOTHER_ID = -1e7 @@ -118,11 +118,14 @@ def sample_outcome(probs: pd.DataFrame, rng: np.random.RandomState): return outcome.loc[outcome != '_'].to_dict() +BitsetDType = Property.PANDAS_TYPE_MAP[Types.BITSET] + + class BitsetHandler: """Provides methods to operate on int column(s) in the population dataframe as a bitset""" def __init__(self, population: Population, column: Optional[str], elements: List[str]): - """"" + """ :param population: The TLO Population object (not the props dataframe). :param column: The integer property column that will be used as a bitset. If set to ``None`` then the optional `columns` argument to methods which act @@ -133,7 +136,10 @@ def __init__(self, population: Population, column: Optional[str], elements: List assert isinstance(population, Population), ( 'First argument is the population object (not the `props` dataframe)' ) - assert len(elements) <= 64, 'A maximum of 64 elements are supported' + dtype_bitwidth = BitsetDType(0).nbytes * 8 + assert len(elements) <= dtype_bitwidth, ( + f"A maximum of {dtype_bitwidth} elements are supported" + ) self._elements = elements self._element_to_int_map = {el: 2 ** i for i, el in enumerate(elements)} self._population = population @@ -141,8 +147,8 @@ def __init__(self, population: Population, column: Optional[str], elements: List assert column in population.props.columns, ( 'Column not found in population dataframe' ) - assert population.props[column].dtype == np.int64, ( - 'Column must be of int64 type' + assert population.props[column].dtype == BitsetDType, ( + f'Column must be of {BitsetDType} type' ) self._column = column @@ -150,11 +156,11 @@ def __init__(self, population: Population, column: Optional[str], elements: List def df(self) -> pd.DataFrame: return self._population.props - def element_repr(self, *elements: str) -> np.int64: + def element_repr(self, *elements: str) -> BitsetDType: """Returns integer representation of the specified element(s)""" - return np.int64(sum(self._element_to_int_map[el] for el in elements)) + return BitsetDType(sum(self._element_to_int_map[el] for el in elements)) - def to_strings(self, integer: np.int64) -> Set[str]: + def to_strings(self, integer: BitsetDType) -> Set[str]: """Given an integer value, returns the corresponding set of strings. :param integer: The integer value for the bitset. @@ -401,6 +407,11 @@ def random_date(start, end, rng): return start + DateOffset(days=rng.randint(0, (end - start).days)) +def str_to_pandas_date(date_string): + """Convert a string with the format YYYY-MM-DD to a pandas Timestamp (aka TLO Date) object.""" + return pd.to_datetime(date_string, format="%Y-%m-%d") + + def hash_dataframe(dataframe: pd.DataFrame): def coerce_lists_to_tuples(df: pd.DataFrame) -> pd.DataFrame: """Coerce columns in a pd.DataFrame that are lists to tuples. This step is needed before hashing a pd.DataFrame diff --git a/tests/resources/scenario.py b/tests/resources/scenario.py new file mode 100644 index 0000000000..204c322f11 --- /dev/null +++ b/tests/resources/scenario.py @@ -0,0 +1,35 @@ +from tlo import Date, logging +from tlo.scenario import BaseScenario + + +class TestScenario(BaseScenario): + def __init__(self): + super().__init__() + self.seed = 655123742 + self.start_date = Date(2010, 1, 1) + self.end_date = Date(2011, 1, 1) + self.pop_size = 2000 + self.number_of_draws = 5 + self.runs_per_draw = 1 + + def log_configuration(self): + return { + 'directory': None, + 'custom_levels': { + '*': logging.INFO, + } + } + + def modules(self): + return [] + + def add_arguments(self, parser): + parser.add_argument('--pop-size', type=int) + + def draw_parameters(self, draw_number, rng): + return { + 'Lifestyle': { + 'init_p_urban': rng.randint(10, 20) / 100.0, + 'init_p_high_sugar': 0.52, + }, + } diff --git a/tests/test_alri.py b/tests/test_alri.py index a98d2f277c..fcce8b4b42 100644 --- a/tests/test_alri.py +++ b/tests/test_alri.py @@ -54,7 +54,7 @@ def _get_person_id(df, age_bounds: tuple = (0.0, np.inf)) -> int: ].index[0] -def get_sim(tmpdir, seed, cons_available): +def get_sim(tmpdir, seed, cons_available, equip_available='all'): """Return simulation objection with Alri and other necessary modules registered.""" sim = Simulation( start_date=start_date, @@ -77,7 +77,8 @@ def get_sim(tmpdir, seed, cons_available): healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resourcefilepath), healthburden.HealthBurden(resourcefilepath=resourcefilepath), healthsystem.HealthSystem(resourcefilepath=resourcefilepath, - cons_availability=cons_available), + cons_availability=cons_available, + equip_availability=equip_available), alri.Alri(resourcefilepath=resourcefilepath, log_indivdual=0, do_checks=True), AlriPropertiesOfOtherModules(), ) @@ -85,10 +86,10 @@ def get_sim(tmpdir, seed, cons_available): @pytest.fixture -def sim_hs_all_consumables(tmpdir, seed): +def sim_hs_all_consumables_and_equipment(tmpdir, seed): """Return simulation objection with Alri and other necessary modules registered. All consumables available""" - return get_sim(tmpdir=tmpdir, seed=seed, cons_available='all') + return get_sim(tmpdir=tmpdir, seed=seed, cons_available='all', equip_available='all') @pytest.fixture @@ -127,17 +128,17 @@ def sim_hs_default_consumables(tmpdir, seed): return sim -def check_dtypes(sim_hs_all_consumables): - sim = sim_hs_all_consumables +def check_dtypes(sim_hs_all_consumables_and_equipment): + sim = sim_hs_all_consumables_and_equipment # Check types of columns df = sim.population.props orig = sim.population.new_row assert (df.dtypes == orig.dtypes).all() -def test_integrity_of_linear_models(sim_hs_all_consumables): +def test_integrity_of_linear_models(sim_hs_all_consumables_and_equipment): """Run the models to make sure that is specified correctly and can run.""" - sim = sim_hs_all_consumables + sim = sim_hs_all_consumables_and_equipment sim.make_initial_population(n=5000) alri_module = sim.modules['Alri'] df = sim.population.props @@ -322,21 +323,21 @@ def test_integrity_of_linear_models(sim_hs_all_consumables): assert isinstance(res, float) and (res is not None) and (0.0 <= res <= 1.0), f"Problem with: {kwargs=}" -def test_basic_run(sim_hs_all_consumables): +def test_basic_run(sim_hs_all_consumables_and_equipment): """Short run of the module using default parameters with check on dtypes""" - sim = sim_hs_all_consumables + sim = sim_hs_all_consumables_and_equipment dur = pd.DateOffset(months=1) popsize = 100 sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) - check_dtypes(sim_hs_all_consumables) + check_dtypes(sim_hs_all_consumables_and_equipment) @pytest.mark.slow -def test_basic_run_lasting_two_years(sim_hs_all_consumables): +def test_basic_run_lasting_two_years(sim_hs_all_consumables_and_equipment): """Check logging results in a run of the model for two years, including HSI, with daily property config checking""" - sim = sim_hs_all_consumables + sim = sim_hs_all_consumables_and_equipment dur = pd.DateOffset(years=2) popsize = 5000 @@ -362,9 +363,9 @@ def test_basic_run_lasting_two_years(sim_hs_all_consumables): assert set(log_one_person.columns) == set(sim.modules['Alri'].PROPERTIES.keys()) -def test_alri_polling(sim_hs_all_consumables): +def test_alri_polling(sim_hs_all_consumables_and_equipment): """Check polling events leads to incident cases""" - sim = sim_hs_all_consumables + sim = sim_hs_all_consumables_and_equipment # get simulation object: popsize = 100 @@ -386,10 +387,10 @@ def test_alri_polling(sim_hs_all_consumables): assert len([q for q in sim.event_queue.queue if isinstance(q[3], AlriIncidentCase)]) > 0 -def test_nat_hist_recovery(sim_hs_all_consumables): +def test_nat_hist_recovery(sim_hs_all_consumables_and_equipment): """Check: Infection onset --> recovery""" - sim = sim_hs_all_consumables + sim = sim_hs_all_consumables_and_equipment popsize = 100 sim.make_initial_population(n=popsize) @@ -434,7 +435,11 @@ def __will_die_of_alri(**kwargs): assert pd.isnull(person['ri_scheduled_death_date']) # Check that they have some symptoms caused by ALRI - assert 0 < len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Alri'])) + assert 0 < len( + sim.modules["SymptomManager"].has_what( + person_id=person_id, disease_module=sim.modules["Alri"] + ) + ) # Check that there is a AlriNaturalRecoveryEvent scheduled for this person: recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if @@ -457,7 +462,11 @@ def __will_die_of_alri(**kwargs): assert pd.isnull(person['ri_scheduled_death_date']) # check they they have no symptoms: - assert 0 == len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Alri'])) + assert 0 == len( + sim.modules["SymptomManager"].has_what( + person_id=person_id, disease_module=sim.modules["Alri"] + ) + ) # check it's logged (one infection + one recovery) assert 1 == sim.modules['Alri'].logging_event.trackers['incident_cases'].report_current_total() @@ -466,9 +475,9 @@ def __will_die_of_alri(**kwargs): assert 0 == sim.modules['Alri'].logging_event.trackers['cured_cases'].report_current_total() -def test_nat_hist_death(sim_hs_all_consumables): +def test_nat_hist_death(sim_hs_all_consumables_and_equipment): """Check: Infection onset --> death""" - sim = sim_hs_all_consumables + sim = sim_hs_all_consumables_and_equipment popsize = 100 sim.make_initial_population(n=popsize) @@ -523,10 +532,10 @@ def __will_die_of_alri(**kwargs): assert 0 == sim.modules['Alri'].logging_event.trackers['cured_cases'].report_current_total() -def test_nat_hist_cure_if_recovery_scheduled(sim_hs_all_consumables): +def test_nat_hist_cure_if_recovery_scheduled(sim_hs_all_consumables_and_equipment): """Show that if a cure event is run before when a person was going to recover naturally, it cause the episode to end earlier.""" - sim = sim_hs_all_consumables + sim = sim_hs_all_consumables_and_equipment popsize = 100 @@ -598,10 +607,10 @@ def death(**kwargs): assert 1 == sim.modules['Alri'].logging_event.trackers['cured_cases'].report_current_total() -def test_nat_hist_cure_if_death_scheduled(sim_hs_all_consumables): +def test_nat_hist_cure_if_death_scheduled(sim_hs_all_consumables_and_equipment): """Show that if a cure event is run before when a person was going to die, it cause the episode to end without the person dying.""" - sim = sim_hs_all_consumables + sim = sim_hs_all_consumables_and_equipment popsize = 100 sim.make_initial_population(n=popsize) @@ -667,10 +676,10 @@ def death(**kwargs): assert 1 == sim.modules['Alri'].logging_event.trackers['cured_cases'].report_current_total() -def test_immediate_onset_complications(sim_hs_all_consumables): +def test_immediate_onset_complications(sim_hs_all_consumables_and_equipment): """Check that if probability of immediately onsetting complications is 100%, then a person has all those complications immediately onset""" - sim = sim_hs_all_consumables + sim = sim_hs_all_consumables_and_equipment popsize = 100 sim.make_initial_population(n=popsize) @@ -712,11 +721,11 @@ def test_immediate_onset_complications(sim_hs_all_consumables): assert df.at[person_id, 'ri_SpO2_level'] != '>=93%' -def test_no_immediate_onset_complications(sim_hs_all_consumables): +def test_no_immediate_onset_complications(sim_hs_all_consumables_and_equipment): """Check that if probability of immediately onsetting complications is 0%, then a person has none of those complications immediately onset """ - sim = sim_hs_all_consumables + sim = sim_hs_all_consumables_and_equipment popsize = 100 @@ -748,7 +757,7 @@ def test_no_immediate_onset_complications(sim_hs_all_consumables): assert not df.loc[person_id, complications_cols].any() -def test_classification_based_on_symptoms_and_imci(sim_hs_all_consumables): +def test_classification_based_on_symptoms_and_imci(sim_hs_all_consumables_and_equipment): """Check that `_get_disease_classification` gives the expected classification.""" def make_hw_assesement_perfect(sim): @@ -760,7 +769,7 @@ def make_hw_assesement_perfect(sim): p['sensitivity_of_classification_of_non_severe_pneumonia_facility_level2'] = 1.0 p['sensitivity_of_classification_of_severe_pneumonia_facility_level2'] = 1.0 - sim = sim_hs_all_consumables + sim = sim_hs_all_consumables_and_equipment make_hw_assesement_perfect(sim) sim.make_initial_population(n=1000) hsi_alri_treatment = HSI_Alri_Treatment(sim.modules['Alri'], 0) @@ -846,9 +855,9 @@ def make_hw_assesement_perfect(sim): ), f"{_correct_imci_classification_on_symptoms=}" -def test_do_effects_of_alri_treatment(sim_hs_all_consumables): +def test_do_effects_of_alri_treatment(sim_hs_all_consumables_and_equipment): """Check that running `do_alri_treatment` can prevent a death from occurring.""" - sim = sim_hs_all_consumables + sim = sim_hs_all_consumables_and_equipment popsize = 100 sim.make_initial_population(n=popsize) @@ -921,10 +930,10 @@ def test_do_effects_of_alri_treatment(sim_hs_all_consumables): assert 1 == sim.modules['Alri'].logging_event.trackers['cured_cases'].report_current_total() -def test_severe_pneumonia_referral_from_hsi_first_appts(sim_hs_all_consumables): +def test_severe_pneumonia_referral_from_hsi_first_appts(sim_hs_all_consumables_and_equipment): """Check that a person is scheduled a treatment HSI following a presentation at HSI_GenericFirstApptAtFacilityLevel0 with severe pneumonia.""" - sim = sim_hs_all_consumables + sim = sim_hs_all_consumables_and_equipment popsize = 100 sim.make_initial_population(n=popsize) @@ -1234,6 +1243,7 @@ def initialise_simulation(self, sim): healthsystem.HealthSystem(resourcefilepath=resourcefilepath, disable_and_reject_all=disable_and_reject_all, cons_availability='all', + equip_availability='all', ), alri.Alri(resourcefilepath=resourcefilepath), AlriPropertiesOfOtherModules(), @@ -1338,6 +1348,7 @@ def initialise_simulation(self, sim): healthburden.HealthBurden(resourcefilepath=resourcefilepath), healthsystem.HealthSystem(resourcefilepath=resourcefilepath, cons_availability='all', + equip_availability='all', ), alri.Alri(resourcefilepath=resourcefilepath), AlriPropertiesOfOtherModules(), diff --git a/tests/test_analysis.py b/tests/test_analysis.py index 7658506a5c..2686e431b0 100644 --- a/tests/test_analysis.py +++ b/tests/test_analysis.py @@ -28,35 +28,39 @@ from tlo.events import PopulationScopeEventMixin, RegularEvent from tlo.methods import demography from tlo.methods.fullmodel import fullmodel -from tlo.methods.scenario_switcher import ScenarioSwitcher +from tlo.methods.scenario_switcher import ImprovedHealthSystemAndCareSeekingScenarioSwitcher -resourcefilepath = Path(os.path.dirname(__file__)) / '../resources' +resourcefilepath = Path(os.path.dirname(__file__)) / "../resources" def test_parse_log(): - log_file = Path(__file__).parent / 'resources' / 'structured_log.txt' + log_file = Path(__file__).parent / "resources" / "structured_log.txt" output = parse_log_file(log_file) - assert 'tlo.methods.epilepsy' in output - assert set(output['tlo.methods.epilepsy'].keys()) == {'incidence_epilepsy', 'epilepsy_logging', '_metadata'} + assert "tlo.methods.epilepsy" in output + assert set(output["tlo.methods.epilepsy"].keys()) == { + "incidence_epilepsy", + "epilepsy_logging", + "_metadata", + } def test_parse_log_levels(tmpdir): # setup a toy simulation to test logging - logger = logging.getLogger('tlo.methods.dummy') + logger = logging.getLogger("tlo.methods.dummy") start_date = Date(2010, 1, 1) end_date = Date(2011, 1, 1) pop_size = 100 class DummyEvent(RegularEvent, PopulationScopeEventMixin): def apply(self, population): - logger.info(key="info_level1", data={'number': np.random.randint(0, 100)}) - logger.info(key="info_level2", data={'number': np.random.randint(0, 100)}) - logger.debug(key="debug_level", data={'number': np.random.randint(0, 100)}) + logger.info(key="info_level1", data={"number": np.random.randint(0, 100)}) + logger.info(key="info_level2", data={"number": np.random.randint(0, 100)}) + logger.debug(key="debug_level", data={"number": np.random.randint(0, 100)}) class Dummy(Module): - PROPERTIES = {'dummy': Property(Types.INT, description='dummy')} + PROPERTIES = {"dummy": Property(Types.INT, description="dummy")} def read_parameters(self, data_folder): pass @@ -68,10 +72,14 @@ def on_birth(self, mother, child): pass def initialise_simulation(self, sim: Simulation): - sim.schedule_event(DummyEvent(self, frequency=DateOffset(months=1)), start_date) + sim.schedule_event( + DummyEvent(self, frequency=DateOffset(months=1)), start_date + ) # test parsing when log level is INFO - sim = Simulation(start_date=start_date, log_config={'filename': 'temp', 'directory': tmpdir}) + sim = Simulation( + start_date=start_date, log_config={"filename": "temp", "directory": tmpdir} + ) sim.register(Dummy()) logger.setLevel(logging.INFO) sim.make_initial_population(n=pop_size) @@ -79,28 +87,34 @@ def initialise_simulation(self, sim: Simulation): output = parse_log_file(sim.log_filepath) # At INFO level - assert len(output['tlo.methods.dummy']['_metadata']['tlo.methods.dummy']) == 2 # should have two tables + assert ( + len(output["tlo.methods.dummy"]["_metadata"]["tlo.methods.dummy"]) == 2 + ) # should have two tables # tables should be at level INFO - for k, v in output['tlo.methods.dummy']['_metadata']['tlo.methods.dummy'].items(): - assert v['level'] == 'INFO' + for k, v in output["tlo.methods.dummy"]["_metadata"]["tlo.methods.dummy"].items(): + assert v["level"] == "INFO" # test parsing when log level is DEBUG - sim = Simulation(start_date=start_date, log_config={'filename': 'temp2', 'directory': tmpdir}) + sim = Simulation( + start_date=start_date, log_config={"filename": "temp2", "directory": tmpdir} + ) sim.register(Dummy()) logger.setLevel(logging.DEBUG) sim.make_initial_population(n=pop_size) sim.simulate(end_date=end_date) - output = parse_log_file(sim.log_filepath, level=logging.INFO) # we're parsing everything above INFO level + output = parse_log_file( + sim.log_filepath, level=logging.INFO + ) # we're parsing everything above INFO level # logged DEBUG but parsed at INFO levels - assert len(output['tlo.methods.dummy']['_metadata']['tlo.methods.dummy']) == 2 - assert 'debug_level' not in output['tlo.methods.dummy'] + assert len(output["tlo.methods.dummy"]["_metadata"]["tlo.methods.dummy"]) == 2 + assert "debug_level" not in output["tlo.methods.dummy"] # logged DEBUG and parsed at DEBUG level output = parse_log_file(sim.log_filepath, level=logging.DEBUG) - assert len(output['tlo.methods.dummy']['_metadata']['tlo.methods.dummy']) == 3 - assert 'debug_level' in output['tlo.methods.dummy'] + assert len(output["tlo.methods.dummy"]["_metadata"]["tlo.methods.dummy"]) == 3 + assert "debug_level" in output["tlo.methods.dummy"] def test_flattening_and_unflattening_multiindex(tmpdir): @@ -113,7 +127,7 @@ def run_simulation_and_parse_log(series_to_log: pd.Series) -> pd.DataFrame: log it to a particular key on the first date of the simulation, and return the pd.DataFrame created by `parse_log` for that key.""" - logger = logging.getLogger('tlo.methods.demography') + logger = logging.getLogger("tlo.methods.demography") logger.setLevel(logging.INFO) class DummyModule(Module): @@ -125,39 +139,45 @@ def initialise_population(self, population): def initialise_simulation(self, sim): logger.info( - key='key', - data=flatten_multi_index_series_into_dict_for_logging(series_to_log) + key="key", + data=flatten_multi_index_series_into_dict_for_logging( + series_to_log + ), ) - sim = Simulation(start_date=sim_start_date, seed=0, log_config={ - 'filename': 'temp', - 'directory': tmpdir, - }) + sim = Simulation( + start_date=sim_start_date, + seed=0, + log_config={"filename": "temp", "directory": tmpdir, }, + ) sim.register( - demography.Demography(resourcefilepath=resourcefilepath), - DummyModule() + demography.Demography(resourcefilepath=resourcefilepath), DummyModule() ) sim.make_initial_population(n=100) sim.simulate(end_date=sim_start_date) - return parse_log_file(sim.log_filepath)['tlo.methods.demography']['key'] + return parse_log_file(sim.log_filepath)["tlo.methods.demography"]["key"] sim_start_date = Date(2010, 1, 1) for num_of_levels in range(1, 4): # Make original pd.Series with column-wise multi-index (with the specified number of levels). idx = pd.MultiIndex.from_product( - [['1', '2', '3'] for _ in range(num_of_levels)], - names=[f'col_level_{_x}' for _x in range(num_of_levels)] + [["1", "2", "3"] for _ in range(num_of_levels)], + names=[f"col_level_{_x}" for _x in range(num_of_levels)], + ) + original = pd.Series( + index=idx, data=100 * np.random.random([len(idx)]).round(4) ) - original = pd.Series(index=idx, data=100*np.random.random([len(idx)]).round(4)) # Let this original series be logged in the simulation and get the parsed log; df_rtn = run_simulation_and_parse_log(series_to_log=original) # Confirm that the original can retrieved from the log using `unflatten_flattened_multi_index_in_logging` series_unflattened = unflatten_flattened_multi_index_in_logging( - df_rtn.loc[pd.to_datetime(df_rtn.date) == sim_start_date].drop(columns=['date']) + df_rtn.loc[pd.to_datetime(df_rtn.date) == sim_start_date].drop( + columns=["date"] + ) ).iloc[0] # Check equal @@ -167,9 +187,7 @@ def initialise_simulation(self, sim): def test_get_root_path(): """Check that `get_root_path` works as expected.""" - ROOT_PATH = Path(os.path.abspath( - Path(os.path.dirname(__file__)) / '../' - )) + ROOT_PATH = Path(os.path.abspath(Path(os.path.dirname(__file__)) / "../")) def is_correct_absolute_path(_path): return (ROOT_PATH == _path) and _path.is_absolute() and isinstance(_path, Path) @@ -177,27 +195,35 @@ def is_correct_absolute_path(_path): assert is_correct_absolute_path(get_root_path()) for test_dir in [ - os.path.abspath(Path(os.path.dirname(__file__)) / '../src/'), - os.path.abspath(Path(os.path.dirname(__file__)) / '../resources/'), - os.path.abspath(Path(os.path.dirname(__file__)) / '../tests/'), - os.path.abspath(Path(os.path.dirname(__file__)) / '../'), + os.path.abspath(Path(os.path.dirname(__file__)) / "../src/"), + os.path.abspath(Path(os.path.dirname(__file__)) / "../resources/"), + os.path.abspath(Path(os.path.dirname(__file__)) / "../tests/"), + os.path.abspath(Path(os.path.dirname(__file__)) / "../"), os.path.abspath(Path(os.path.dirname(__file__))), ]: - assert is_correct_absolute_path(get_root_path(test_dir)), f"Failed on {test_dir=}" + assert is_correct_absolute_path( + get_root_path(test_dir) + ), f"Failed on {test_dir=}" def test_coarse_appt_type(): """Check the function that maps each appt_types to a coarser definition.""" appt_types = pd.read_csv( - resourcefilepath / 'healthsystem' / 'human_resources' / 'definitions' / 'ResourceFile_Appt_Types_Table.csv' - )['Appt_Type_Code'].values - - appts = pd.DataFrame({ + resourcefilepath + / "healthsystem" + / "human_resources" + / "definitions" + / "ResourceFile_Appt_Types_Table.csv" + )["Appt_Type_Code"].values + + appts = pd.DataFrame( + { "original": pd.Series(appt_types), - "coarse": pd.Series(appt_types).map(get_coarse_appt_type) - }) + "coarse": pd.Series(appt_types).map(get_coarse_appt_type), + } + ) - coarse_appts = appts['coarse'].drop_duplicates() + coarse_appts = appts["coarse"].drop_duplicates() assert not pd.isnull(appts).any().any() assert 13 == len(coarse_appts) # 12 coarse categories @@ -208,9 +234,18 @@ def test_coarse_appt_type(): def test_colormap_coarse_appts(): """Check the function that allocates a unique colour to each coarse appointment type.""" - coarse_appt_types = pd.read_csv( - resourcefilepath / 'healthsystem' / 'human_resources' / 'definitions' / 'ResourceFile_Appt_Types_Table.csv' - )['Appt_Type_Code'].map(get_coarse_appt_type).drop_duplicates().values + coarse_appt_types = ( + pd.read_csv( + resourcefilepath + / "healthsystem" + / "human_resources" + / "definitions" + / "ResourceFile_Appt_Types_Table.csv" + )["Appt_Type_Code"] + .map(get_coarse_appt_type) + .drop_duplicates() + .values + ) coarse_appt_types = sorted(coarse_appt_types, key=order_of_coarse_appt) @@ -218,15 +253,21 @@ def test_colormap_coarse_appts(): assert len(set(colors)) == len(colors) # No duplicates assert all([isinstance(_x, str) for _x in colors]) # All strings - assert np.nan is get_color_coarse_appt('????') # Return `np.nan` if appt_type not recognised. - assert all(map(lambda x: x in colors_in_matplotlib(), colors)) # All colors recognised + assert np.nan is get_color_coarse_appt( + "????" + ) # Return `np.nan` if appt_type not recognised. + assert all( + map(lambda x: x in colors_in_matplotlib(), colors) + ) # All colors recognised def test_get_treatment_ids(tmpdir): """Check the function that generates the list of TREATMENT_IDs defined in the model.""" x = get_filtered_treatment_ids() # All TREATMENT_IDs - y = get_filtered_treatment_ids(depth=1) # TREATMENT_IDs to the first level of depth (i.e. module level) + y = get_filtered_treatment_ids( + depth=1 + ) # TREATMENT_IDs to the first level of depth (i.e. module level) assert isinstance(x, list) assert all([isinstance(_x, str) for _x in x]) @@ -240,13 +281,19 @@ def test_get_treatment_ids(tmpdir): def test_colormap_short_treatment_id(): """Check the function that allocates a unique colour to each shortened TREATMENT_ID (i.e. each module)""" - short_treatment_ids = sorted(get_filtered_treatment_ids(depth=1), key=order_of_short_treatment_ids) + short_treatment_ids = sorted( + get_filtered_treatment_ids(depth=1), key=order_of_short_treatment_ids + ) colors = [get_color_short_treatment_id(x) for x in short_treatment_ids] assert len(set(colors)) == len(colors) # No duplicates assert all([isinstance(_x, str) for _x in colors]) # All strings - assert np.nan is get_color_coarse_appt('????') # Return `np.nan` if appt_type not recognised. - assert all(map(lambda x: x in colors_in_matplotlib(), colors)) # All colors recognised + assert np.nan is get_color_coarse_appt( + "????" + ) # Return `np.nan` if appt_type not recognised. + assert all( + map(lambda x: x in colors_in_matplotlib(), colors) + ) # All colors recognised def test_colormap_cause_of_death_label(seed): @@ -257,10 +304,14 @@ def get_all_cause_of_death_labels(seed=0) -> List[str]: """Return list of all the causes of death defined in the full model.""" start_date = Date(2010, 1, 1) sim = Simulation(start_date=start_date, seed=seed) - sim.register(*fullmodel(resourcefilepath=resourcefilepath, use_simplified_births=False)) + sim.register( + *fullmodel(resourcefilepath=resourcefilepath, use_simplified_births=False) + ) sim.make_initial_population(n=1_000) sim.simulate(end_date=start_date) - mapper, _ = (sim.modules['Demography']).create_mappers_from_causes_of_death_to_label() + mapper, _ = ( + sim.modules["Demography"] + ).create_mappers_from_causes_of_death_to_label() return sorted(set(mapper.values())) all_labels = get_all_cause_of_death_labels(seed) @@ -269,8 +320,12 @@ def get_all_cause_of_death_labels(seed=0) -> List[str]: assert len(set(colors)) == len(colors) # No duplicates assert all([isinstance(_x, str) for _x in colors]) # All strings - assert np.nan is get_color_coarse_appt('????') # Return `np.nan` if label is not recognised. - assert all(map(lambda x: x in colors_in_matplotlib(), colors)) # All colors recognised + assert np.nan is get_color_coarse_appt( + "????" + ) # Return `np.nan` if label is not recognised. + assert all( + map(lambda x: x in colors_in_matplotlib(), colors) + ) # All colors recognised def test_get_parameter_functions(seed): @@ -281,20 +336,20 @@ def test_get_parameter_functions(seed): funcs = [ get_parameters_for_status_quo, lambda: get_parameters_for_improved_healthsystem_and_healthcare_seeking( - resourcefilepath=resourcefilepath, - max_healthsystem_function=True, - max_healthcare_seeking=False - ), + resourcefilepath=resourcefilepath, + max_healthsystem_function=True, + max_healthcare_seeking=False, + ), lambda: get_parameters_for_improved_healthsystem_and_healthcare_seeking( resourcefilepath=resourcefilepath, max_healthsystem_function=False, - max_healthcare_seeking=True - ), + max_healthcare_seeking=True, + ), lambda: get_parameters_for_improved_healthsystem_and_healthcare_seeking( resourcefilepath=resourcefilepath, max_healthsystem_function=True, - max_healthcare_seeking=True - ) + max_healthcare_seeking=True, + ), ] # Create simulation @@ -312,238 +367,320 @@ def test_get_parameter_functions(seed): for name, updated_value in params[module].items(): # Check that the parameter identified exists in the simulation - assert name in sim.modules[module].parameters, f"Parameter not recognised: {module}:{name}." + assert ( + name in sim.modules[module].parameters + ), f"Parameter not recognised: {module}:{name}." # Check that the original value and the updated value are of the same type. original = sim.modules[module].parameters[name] - assert type(original) is type(updated_value), \ - f"Updated value type does not match original type: " \ - f"{module}:{name} >> {updated_value=}, " \ + assert type(original) is type(updated_value), ( + f"Updated value type does not match original type: " + f"{module}:{name} >> {updated_value=}, " f"{type(original)=}, {type(updated_value)=}" + ) def is_df_same_size_and_dtype(df1, df2): return ( - df1.index.equals(df2.index) and - all(df1.dtypes == df2.dtypes) and - all(df1.columns == df2.columns) if isinstance(df1, pd.DataFrame) else True + df1.index.equals(df2.index) + and all(df1.dtypes == df2.dtypes) + and all(df1.columns == df2.columns) + if isinstance(df1, pd.DataFrame) + else True ) def is_list_same_size_and_dtype(l1, l2): - return ( - (len(l1) == len(l2)) and - all([type(_i) is type(_j) for _i, _j in zip(l1, l2)]) + return (len(l1) == len(l2)) and all( + [type(_i) is type(_j) for _i, _j in zip(l1, l2)] ) # Check that, if the updated value is a pd.DataFrame, it has the same indicies as the original if isinstance(original, (pd.DataFrame, pd.Series)): - assert is_df_same_size_and_dtype(original, updated_value), \ - print(f"Dataframe or series if not of the expected size and shape:" - f"{module}:{name} >> {updated_value=}, {type(original)=}, {type(updated_value)=}") + assert is_df_same_size_and_dtype(original, updated_value), print( + f"Dataframe or series if not of the expected size and shape:" + f"{module}:{name} >> {updated_value=}, {type(original)=}, {type(updated_value)=}" + ) # Check that, if the updated value is a list/tuple, it has the same dimensions as the original elif isinstance(original, (list, tuple)): - assert is_list_same_size_and_dtype(original, updated_value), \ - print(f"List/tuple is not of the expected size and containing elements of expected type: " - f"{module}:{name} >> {updated_value=}, {type(original)=}, {type(updated_value)=}") + assert is_list_same_size_and_dtype(original, updated_value), print( + f"List/tuple is not of the expected size and containing elements of expected type: " + f"{module}:{name} >> {updated_value=}, {type(original)=}, {type(updated_value)=}" + ) def test_mix_scenarios(): """Check that `mix_scenarios` works as expected.""" - d1 = { - 'Mod1': { - 'param_a': 'value_in_d1', - 'param_b': 'value_in_d1', - } - } + d1 = {"Mod1": {"param_a": "value_in_d1", "param_b": "value_in_d1", }} - d2 = { - 'Mod2': { - 'param_a': 'value_in_d2', - 'param_b': 'value_in_d2', - } - } + d2 = {"Mod2": {"param_a": "value_in_d2", "param_b": "value_in_d2", }} - d3 = { - 'Mod1': { - 'param_b': 'value_in_d3', - 'param_c': 'value_in_d3' - } - } + d3 = {"Mod1": {"param_b": "value_in_d3", "param_c": "value_in_d3"}} with pytest.warns(UserWarning) as record: assert mix_scenarios(d1, d2, d3) == { - 'Mod1': { - 'param_a': 'value_in_d1', # <- only appears in d1, and is included despite d3 also having 'Mod1' key - 'param_b': 'value_in_d3', # <- appears in d1 and d3, but d3 is right-most, so 'wins' (raises Warning) - 'param_c': 'value_in_d3', # <- only appears in d3 + "Mod1": { + "param_a": "value_in_d1", # <- only appears in d1, and is included despite d3 also having 'Mod1' key + "param_b": "value_in_d3", # <- appears in d1 and d3, but d3 is right-most, so 'wins' (raises Warning) + "param_c": "value_in_d3", # <- only appears in d3 + }, + "Mod2": { + "param_a": "value_in_d2", # <- only appears in d2 (& attaches to Mod2 despite name being duplicated) + "param_b": "value_in_d2", # <- only appears in d2 (& attaches to Mod2 despite name being duplicated) }, - 'Mod2': { - 'param_a': 'value_in_d2', # <- only appears in d2 (& attaches to Mod2 despite name being duplicated) - 'param_b': 'value_in_d2', # <- only appears in d2 (& attaches to Mod2 despite name being duplicated) - } } assert 1 == len(record) - assert record.list[0].message.args[0] == 'Parameter is being updated more than once: module=Mod1, parameter=param_b' + assert ( + record.list[0].message.args[0] + == "Parameter is being updated more than once: module=Mod1, parameter=param_b" + ) # Test the behaviour of the `mix_scenarios` taking the value in the right-most dict. assert mix_scenarios( - {'Mod1': { - 'param_a': 'value_in_dict1', - 'param_b': 'value_in_dict1', - 'param_c': 'value_in_dict1', - }}, - {'Mod1': { - 'param_a': 'value_in_dict2', - 'param_b': 'value_in_dict2', - 'param_c': 'value_in_dict2', - }}, - {'Mod1': { - 'param_a': 'value_in_dict3', - 'param_b': 'value_in_dict_right_most', - 'param_c': 'value_in_dict3', - }}, - {'Mod1': { - 'param_a': 'value_in_dict_right_most', - 'param_c': 'value_in_dict4', - }}, - {"Mod1": { - "param_c": "value_in_dict_right_most", - }}, + { + "Mod1": { + "param_a": "value_in_dict1", + "param_b": "value_in_dict1", + "param_c": "value_in_dict1", + } + }, + { + "Mod1": { + "param_a": "value_in_dict2", + "param_b": "value_in_dict2", + "param_c": "value_in_dict2", + } + }, + { + "Mod1": { + "param_a": "value_in_dict3", + "param_b": "value_in_dict_right_most", + "param_c": "value_in_dict3", + } + }, + {"Mod1": {"param_a": "value_in_dict_right_most", "param_c": "value_in_dict4", }}, + {"Mod1": {"param_c": "value_in_dict_right_most", }}, ) == { - 'Mod1': {'param_a': 'value_in_dict_right_most', - 'param_b': 'value_in_dict_right_most', - 'param_c': 'value_in_dict_right_most', - } - } + "Mod1": { + "param_a": "value_in_dict_right_most", + "param_b": "value_in_dict_right_most", + "param_c": "value_in_dict_right_most", + } + } -def test_scenario_switcher(seed): - """Check the `ScenarioSwitcher` module can update parameter values in a manner similar to them being changed - directly after registration in the simulation (as would be done by the Scenario class).""" +def test_improved_healthsystem_and_care_seeking_scenario_switcher(seed): + """Check the `ImprovedHealthSystemAndCareSeekingScenarioSwitcher` module can update complex parameter values in a + manner similar to them being changed directly or mid-way through the simulation.""" - sim = Simulation(start_date=Date(2010, 1, 1), seed=seed) - sim.register(*( - fullmodel(resourcefilepath=resourcefilepath) + [ScenarioSwitcher(resourcefilepath=resourcefilepath)] - )) + # Define the changes we want the ScenarioSwitcher to implement + max_healthsystem_function = [False, True] + max_healthcare_seeking = [False, True] + year_of_change = 2011 - # Check that the 'ScenarioSwitcher` is the first registered module. - assert 'ScenarioSwitcher' == list(sim.modules.keys())[0] + # Set up a simulation in which the parameters are checked regularly to see if they are correct, given the + # phase of the simulation. - # Change the parameters for max_healthsystem_function and max_healthcare_seeking via the ScenarioSwitcher - sim.modules['ScenarioSwitcher'].parameters['max_healthsystem_function'] = True - sim.modules['ScenarioSwitcher'].parameters['max_healthcare_seeking'] = True + class CheckParametersEvent(RegularEvent, PopulationScopeEventMixin): + def __init__(self, module): + super().__init__(module, frequency=DateOffset(months=1)) # repeats every month - # Initialise the population - sim.make_initial_population(n=100) + def apply(self, population): + self.module.check_parameters() # Checks parameters are as expected + + class DummyModule(Module): + def read_parameters(self, data_folder): + pass + + def initialise_population(self, population): + pass + + def initialise_simulation(self, sim): + # Schedule `CheckParametersEvent` to run immediately (and it will then repeat monthly). + sim.schedule_event(CheckParametersEvent(self), sim.date) + + def on_birth(self, *args, **kwargs): + pass + + def check_parameters(self) -> None: + """Check that the parameter values in the simulation currently match expectations for this phase of the + simulation.""" + + sim = self.sim + + # Work out if we expect to be using the first or the second values for switchers (first value is + # for times before 1st Jan on the year of the change. + phase_of_simulation = 0 if sim.date.year < year_of_change else 1 + + # Load the parameters that should be being used currently. + correct_param_values = get_parameters_for_improved_healthsystem_and_healthcare_seeking( + resourcefilepath=resourcefilepath, + max_healthsystem_function=max_healthsystem_function[phase_of_simulation], + max_healthcare_seeking=max_healthcare_seeking[phase_of_simulation], + ) + + for mod, param in correct_param_values.items(): + for name, target_value in param.items(): + actual = sim.modules[mod].parameters[name] + if isinstance(target_value, pd.Series): + pd.testing.assert_series_equal(target_value, actual) + elif isinstance(target_value, pd.DataFrame): + pd.testing.assert_frame_equal(target_value, actual) + elif isinstance(target_value, list): + assert all([t == v for t, v in zip(target_value, actual)]) + else: + assert target_value == actual + print('Parameters all look good.') + + # Check for health care seeking being forced to occur for all symptoms + hcs = sim.modules["HealthSeekingBehaviour"].force_any_symptom_to_lead_to_healthcareseeking + assert isinstance(hcs, bool) and (hcs is max_healthcare_seeking[phase_of_simulation]) - # Check that all the parameter values in the simulation are updated to be the value expected. - updated_values = get_parameters_for_improved_healthsystem_and_healthcare_seeking( - resourcefilepath=resourcefilepath, - max_healthsystem_function=True, - max_healthcare_seeking=True + sim = Simulation(start_date=Date(2010, 1, 1), seed=seed) + sim.register( + *( + fullmodel(resourcefilepath=resourcefilepath) + + [ + ImprovedHealthSystemAndCareSeekingScenarioSwitcher( + resourcefilepath=resourcefilepath + ), + DummyModule(), + ] + ) ) - for module, param in updated_values.items(): - for name, target_value in param.items(): + # Check that the `ImprovedHealthSystemAndCareSeekingScenarioSwitcher` is the first registered module. + assert ( + "ImprovedHealthSystemAndCareSeekingScenarioSwitcher" + == list(sim.modules.keys())[0] + ) + module = sim.modules["ImprovedHealthSystemAndCareSeekingScenarioSwitcher"] - actual = sim.modules[module].parameters[name] + # Set the changes for the ScenarioSwitcher by manipulating its parameters (mimicking what `Scenario` class does). + module.parameters["year_of_switch"] = year_of_change + module.parameters["max_healthsystem_function"] = max_healthsystem_function + module.parameters["max_healthcare_seeking"] = max_healthcare_seeking - if isinstance(target_value, pd.Series): - pd.testing.assert_series_equal(target_value, actual) - elif isinstance(target_value, pd.DataFrame): - pd.testing.assert_frame_equal(target_value, actual) - elif isinstance(target_value, list): - assert all([t == v for t, v in zip(target_value, actual)]) - else: - assert target_value == actual + # Initialise the population + sim.make_initial_population(n=100) - # Spot check for health care seeking being forced to occur for all symptoms - hcs = sim.modules['HealthSeekingBehaviour'].force_any_symptom_to_lead_to_healthcareseeking - assert isinstance(hcs, bool) and hcs + # Run the simulation until well after the date of parameter change. (The checking will be occurring every month, + # and if any errors an `AssertionError` would be raised.) + sim.simulate(end_date=Date(year_of_change + 2, 1, 1)) def test_summarize(): """Check that the summarize utility function works as expected.""" results_multiple_draws = pd.DataFrame( - columns=pd.MultiIndex.from_tuples([ - ('DrawA', 'DrawA_Run1'), - ('DrawA', 'DrawA_Run2'), - ('DrawB', 'DrawB_Run1'), - ('DrawB', 'DrawB_Run2')], - names=('draw', 'run')), - index=['TimePoint0', 'TimePoint1'], - data=np.array([ - [0, 20, 1000, 2000], - [0, 20, 1000, 2000], - ]) + columns=pd.MultiIndex.from_tuples( + [ + ("DrawA", "DrawA_Run1"), + ("DrawA", "DrawA_Run2"), + ("DrawB", "DrawB_Run1"), + ("DrawB", "DrawB_Run2"), + ], + names=("draw", "run"), + ), + index=["TimePoint0", "TimePoint1"], + data=np.array([[0, 20, 1000, 2000], [0, 20, 1000, 2000], ]), ) results_one_draw = pd.DataFrame( - columns=pd.MultiIndex.from_tuples([ - ('DrawA', 'DrawA_Run1'), - ('DrawA', 'DrawA_Run2')], - names=('draw', 'run')), - index=['TimePoint0', 'TimePoint1'], - data=np.array([ - [0, 20], - [0, 20] - ]), + columns=pd.MultiIndex.from_tuples( + [("DrawA", "DrawA_Run1"), ("DrawA", "DrawA_Run2")], names=("draw", "run") + ), + index=["TimePoint0", "TimePoint1"], + data=np.array([[0, 20], [0, 20]]), ) # Without collapsing and all stats provided pd.testing.assert_frame_equal( pd.DataFrame( - columns=pd.MultiIndex.from_tuples([ - ('DrawA', 'lower'), - ('DrawA', 'mean'), - ('DrawA', 'upper'), - ("DrawB", "lower"), - ("DrawB", "mean"), - ("DrawB", "upper")], - names=('draw', 'stat')), - index=['TimePoint0', 'TimePoint1'], - data=np.array([ - [0.5, 10.0, 19.5, 1025.0, 1500.0, 1975.0], - [0.5, 10.0, 19.5, 1025.0, 1500.0, 1975.0], - ]) + columns=pd.MultiIndex.from_tuples( + [ + ("DrawA", "lower"), + ("DrawA", "mean"), + ("DrawA", "upper"), + ("DrawB", "lower"), + ("DrawB", "mean"), + ("DrawB", "upper"), + ], + names=("draw", "stat"), + ), + index=["TimePoint0", "TimePoint1"], + data=np.array( + [ + [0.5, 10.0, 19.5, 1025.0, 1500.0, 1975.0], + [0.5, 10.0, 19.5, 1025.0, 1500.0, 1975.0], + ] + ), ), - summarize(results_multiple_draws) + summarize(results_multiple_draws), ) # Without collapsing and only mean pd.testing.assert_frame_equal( pd.DataFrame( - columns=pd.Index([ - 'DrawA', - 'DrawB'], - name='draw'), - index=['TimePoint0', 'TimePoint1'], - data=np.array([ - [10.0, 1500.0], - [10.0, 1500.0] - ]) + columns=pd.Index(["DrawA", "DrawB"], name="draw"), + index=["TimePoint0", "TimePoint1"], + data=np.array([[10.0, 1500.0], [10.0, 1500.0]]), ), - summarize(results_multiple_draws, only_mean=True) + summarize(results_multiple_draws, only_mean=True), ) # With collapsing (as only one draw) pd.testing.assert_frame_equal( pd.DataFrame( - columns=pd.Index( - ['lower', - 'mean', - 'upper'], - name='stat' - ), - index=['TimePoint0', 'TimePoint1'], - data=np.array([ - [0.5, 10.0, 19.5], - [0.5, 10.0, 19.5], - ]) + columns=pd.Index(["lower", "mean", "upper"], name="stat"), + index=["TimePoint0", "TimePoint1"], + data=np.array([[0.5, 10.0, 19.5], [0.5, 10.0, 19.5], ]), ), - summarize(results_one_draw, collapse_columns=True) + summarize(results_one_draw, collapse_columns=True), ) + + +def test_control_loggers_from_same_module_independently(seed, tmpdir): + """Check that detailed/summary loggers in the same module can configured independently.""" + + # Check that the simulation can be set-up to get only the usual demography logger and *not* the detailed + # logger, when providing the config_log information when the simulation is initialised.""" + + log_config = { + 'filename': 'temp', + 'directory': tmpdir, + 'custom_levels': { + "*": logging.WARNING, + 'tlo.methods.demography.detail': logging.WARNING, # <-- Don't explicitly turn off the detailed logger + 'tlo.methods.demography': logging.INFO, # <-- Turning on the normal logger + } + } + + def run_simulation_and_cause_one_death(sim): + """Register demography in the simulations, runs it and causes one death; return the resulting log.""" + sim.register(demography.Demography(resourcefilepath=resourcefilepath)) + sim.make_initial_population(n=100) + sim.simulate(end_date=sim.start_date) + # Cause one death to occur + sim.modules['Demography'].do_death( + individual_id=0, + originating_module=sim.modules['Demography'], + cause='Other' + ) + return parse_log_file(sim.log_filepath) + + def check_log(log): + """Check the usual `tlo.methods.demography' log is created and that check persons have died (which would be + when the detailed logger would be used).""" + assert 'tlo.methods.demography' in log.keys() + assert 1 == len(log['tlo.methods.demography']['death']) + + # Check that the detailed logger is not created. + assert 'tlo.methods.demography.detail' not in log.keys() + + # 1) Provide custom_logs argument when creating Simulation object + sim = Simulation(start_date=Date(2010, 1, 1), seed=seed, log_config=log_config) + check_log(run_simulation_and_cause_one_death(sim)) + diff --git a/tests/test_basic_sims.py b/tests/test_basic_sims.py index 5200ab730c..ea29aa601f 100644 --- a/tests/test_basic_sims.py +++ b/tests/test_basic_sims.py @@ -184,7 +184,7 @@ def __init__(self, module, end_date): super().__init__(module=module, frequency=DateOffset(days=1), end_date=end_date) def apply(self, population): - population.props.loc[0, 'last_run'] = population.sim.date + population.props.loc[0, 'last_run'] = self.module.sim.date class MyOtherEvent(PopulationScopeEventMixin, RegularEvent): def __init__(self, module): diff --git a/tests/test_beddays.py b/tests/test_beddays.py index f8d060b72b..f3f3e7f087 100644 --- a/tests/test_beddays.py +++ b/tests/test_beddays.py @@ -11,7 +11,7 @@ from tlo.events import IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.methods import Metadata, demography, healthsystem from tlo.methods.bed_days import BedDays -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event resourcefilepath = Path(os.path.dirname(__file__)) / '../resources' @@ -211,7 +211,7 @@ def apply(self, person_id, squeeze_factor): assert not df.at[person_id, 'hs_is_inpatient'] # impose the footprint: - hsi_bd.post_apply_hook() + hsi_bd._run_after_hsi_event() # check that person is an in-patient now assert df.at[person_id, 'hs_is_inpatient'] @@ -973,3 +973,82 @@ def apply(self, person_id, squeeze_factor): # Check that the facility_id is included for each entry in the `HSI_Events` log, including HSI Events for # in-patient appointments. assert not (log_hsi['Facility_ID'] == -99).any() + +def test_beddays_availability_switch(seed): + """ + Test that calling bed_days.switch_beddays_availability correctly updates the + bed capacities and adjusts the existing trackers to reflect the new capacities. + """ + sim = Simulation(start_date=start_date, seed=seed) + sim.register( + demography.Demography(resourcefilepath=resourcefilepath), + healthsystem.HealthSystem(resourcefilepath=resourcefilepath), + ) + + # get shortcut to HealthSystem Module + hs: healthsystem.HealthSystem = sim.modules["HealthSystem"] + + # As obtained from the resource file + facility_id_with_patient = 128 + facility_id_without_patient = 129 + bedtype1_init_capacity = 5 + bedtype2_init_capacity = 10 + + # Create a simple bed capacity dataframe with capacity designated for two regions + hs.parameters["BedCapacity"] = pd.DataFrame( + data={ + "Facility_ID": [ + facility_id_with_patient, #<-- patient 0 is admitted here + facility_id_without_patient, + ], + "bedtype1": bedtype1_init_capacity, + "bedtype2": bedtype2_init_capacity, + } + ) + sim.make_initial_population(n=100) + sim.simulate(end_date=start_date) + + day_2 = start_date + pd.DateOffset(days=1) + day_3 = start_date + pd.DateOffset(days=2) + day_4 = start_date + pd.DateOffset(days=3) + + bed_days = hs.bed_days + # Reset the bed occupancies + bed_days.initialise_beddays_tracker() + # Have a patient occupy a bed at the start of the simulation + bed_days.impose_beddays_footprint(person_id=0, footprint={"bedtype1": 3, "bedtype2": 0}) + + # Have the bed_days availability switch to "none" on the 2nd simulation day + bed_days.switch_beddays_availability("none", effective_on_and_from=day_2) + + # We should now see that the scaled capacities are all zero + assert ( + not bed_days._scaled_capacity.any().any() + ), "At least one bed capacity was not set to 0" + # We should also see that bedtype1 should have -1 beds available for days 2 and 3 of the simulation, + # due to the existing occupancy and the new capacity of 0. + # It should have 4 beds available on the first day (since the original capacity was 5 and the availability + # switch happens day 2). + # It should then have 0 beds available after (not including) day 3 + bedtype1: pd.DataFrame = bed_days.bed_tracker["bedtype1"] + bedtype2: pd.DataFrame = bed_days.bed_tracker["bedtype2"] + + assert ( + bedtype1.loc[start_date, facility_id_with_patient] == bedtype1_init_capacity - 1 + and bedtype1.loc[start_date, facility_id_without_patient] + == bedtype1_init_capacity + ), "Day 1 capacities were incorrectly affected" + assert (bedtype1.loc[day_2:day_3, facility_id_with_patient] == -1).all() and ( + bedtype1.loc[day_2:day_3, facility_id_without_patient] == 0 + ).all(), "Day 2 & 3 capacities were not updated correctly" + assert ( + (bedtype1.loc[day_4:, :] == 0).all().all() + ), "Day 4 onwards did not have correct capacity" + + # Bedtype 2 should have also have been updated, but there is no funny business here. + assert ( + (bedtype2.loc[day_2:, :] == 0).all().all() + ), "Bedtype 2 was not updated correctly" + assert ( + (bedtype2.loc[start_date, :] == bedtype2_init_capacity).all().all() + ), "Bedtype 2 had capacity updated on the incorrect dates" diff --git a/tests/test_bitset.py b/tests/test_bitset.py index c7b2360b0f..0ca60f5c5e 100644 --- a/tests/test_bitset.py +++ b/tests/test_bitset.py @@ -6,16 +6,16 @@ from tlo import Population from tlo.lm import LinearModel, LinearModelType, Predictor -from tlo.util import BitsetHandler +from tlo.util import BitsetDType, BitsetHandler @pytest.fixture def dataframe(): return pd.DataFrame( data={ - 'symptoms': pd.Series(0, index=range(5), dtype=np.dtype('int64')), - 'sy_stomachache': pd.Series(0, index=range(5), dtype=np.dtype('int64')), - 'sy_injury': pd.Series(0, index=range(5), dtype=np.dtype('int64')), + 'symptoms': pd.Series(0, index=range(5), dtype=BitsetDType), + 'sy_stomachache': pd.Series(0, index=range(5), dtype=BitsetDType), + 'sy_injury': pd.Series(0, index=range(5), dtype=BitsetDType), 'is_alive': pd.Series(True, index=range(5), dtype=np.dtype('bool')), 'age': pd.Series([5, 10, 20, 30, 40], index=range(5), dtype=np.dtype('int')) } @@ -65,7 +65,7 @@ def test_error_on_too_many_elements(population): def test_error_on_incorrect_column_dtype(population): - with pytest.raises(AssertionError, match='int64'): + with pytest.raises(AssertionError, match=str(BitsetDType)): BitsetHandler(population, 'is_alive', [str(i) for i in range(8)]) @@ -343,7 +343,7 @@ def test_linearmodel_with_bitset(dataframe, symptoms): lm = LinearModel( LinearModelType.ADDITIVE, 0.0, - Predictor('symptoms').apply(lambda x: 2.0 if x & symptoms.element_repr('vomiting') else 20.0) + Predictor('symptoms').apply(lambda x: 2.0 if BitsetDType(x) & symptoms.element_repr('vomiting') else 20.0) ) out = lm.predict(dataframe) @@ -351,8 +351,8 @@ def test_linearmodel_with_bitset(dataframe, symptoms): # put more complex rules in its own function def symptom_coeff_calc(bitset): - if bitset & symptoms.element_repr('fever'): - if bitset & symptoms.element_repr('vomiting'): + if BitsetDType(bitset) & symptoms.element_repr('fever'): + if BitsetDType(bitset) & symptoms.element_repr('vomiting'): return 1 else: return 2 diff --git a/tests/test_cardiometabolicdisorders.py b/tests/test_cardiometabolicdisorders.py index a40fdad69b..977caa4c91 100644 --- a/tests/test_cardiometabolicdisorders.py +++ b/tests/test_cardiometabolicdisorders.py @@ -770,7 +770,7 @@ def test_hsi_emergency_events(seed): assert pd.isnull(df.at[person_id, f'nc_{event}_scheduled_date_death']) assert isinstance(sim.modules['HealthSystem'].HSI_EVENT_QUEUE[0].hsi_event, HSI_CardioMetabolicDisorders_StartWeightLossAndMedication) - assert f"{event}_damage" not in sim.modules['SymptomManager'].has_what(person_id) + assert f"{event}_damage" not in sim.modules['SymptomManager'].has_what(person_id=person_id) def test_no_availability_of_consumables_for_conditions(seed): diff --git a/tests/test_consumables.py b/tests/test_consumables.py index b1e9174af6..6eee6dac38 100644 --- a/tests/test_consumables.py +++ b/tests/test_consumables.py @@ -19,7 +19,7 @@ get_item_code_from_item_name, get_item_codes_from_package_name, ) -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event resourcefilepath = Path(os.path.dirname(__file__)) / '../resources' @@ -54,7 +54,7 @@ def test_using_recognised_item_codes(seed): date = datetime.datetime(2010, 1, 1) # Initiate Consumables class - cons = Consumables(data=data, rng=rng) + cons = Consumables(availability_data=data, rng=rng) # Start a new day (this trigger is usually called by the event `HealthSystemScheduler`). cons.on_start_of_day(date=date) @@ -81,7 +81,7 @@ def test_unrecognised_item_code_is_recorded(seed): date = datetime.datetime(2010, 1, 1) # Initiate Consumables class - cons = Consumables(data=data, rng=rng) + cons = Consumables(availability_data=data, rng=rng) # Start a new day (this trigger usually called by the event `HealthSystemScheduler`). cons.on_start_of_day(date=date) @@ -96,7 +96,7 @@ def test_unrecognised_item_code_is_recorded(seed): assert cons._not_recognised_item_codes # Some item_codes recorded as not recognised. # Check warning is issued at end of simulation - with pytest.warns(None) as recorded_warnings: + with pytest.warns(UserWarning) as recorded_warnings: cons.on_simulation_end() assert any_warnings_about_item_code(recorded_warnings) @@ -124,7 +124,7 @@ def test_consumables_availability_options(seed): # Check that for each option for `availability` the result is as expected. for _cons_availability_option, _expected_result in options_and_expected_results.items(): - cons = Consumables(data=data, rng=rng, availability=_cons_availability_option) + cons = Consumables(availability_data=data, rng=rng, availability=_cons_availability_option) cons.on_start_of_day(date=date) assert _expected_result == cons._request_consumables( @@ -162,7 +162,7 @@ def request_item(cons, item_code: Union[list, int]): for _availability in ('default', 'all', 'none'): # Create consumables class - cons = Consumables(data=data, rng=rng, availability=_availability) + cons = Consumables(availability_data=data, rng=rng, availability=_availability) # Check before overriding availability for _ in range(1000): @@ -241,7 +241,7 @@ def test_consumables_available_at_right_frequency(seed): date = datetime.datetime(2010, 1, 1) # Initiate Consumables class - cons = Consumables(data=data, rng=rng) + cons = Consumables(availability_data=data, rng=rng) # Make requests for consumables (which would normally come from an instance of `HSI_Event`). n_trials = 10_000 @@ -479,7 +479,7 @@ def test_check_format_of_consumables_file(): @pytest.mark.slow -def test_every_declared_consumable_for_every_possible_hsi_using_actual_data(): +def test_every_declared_consumable_for_every_possible_hsi_using_actual_data(recwarn): """Check that every item_code that is declared can be requested from a person at every district and facility_level. """ @@ -487,27 +487,26 @@ def test_every_declared_consumable_for_every_possible_hsi_using_actual_data(): hs = sim.modules['HealthSystem'] item_codes = hs.consumables.item_codes - with pytest.warns(None) as recorded_warnings: - for month in range(1, 13): - sim.date = Date(2010, month, 1) - hs.consumables._refresh_availability_of_consumables(date=sim.date) + for month in range(1, 13): + sim.date = Date(2010, month, 1) + hs.consumables._refresh_availability_of_consumables(date=sim.date) - for _district in sim.modules['Demography'].PROPERTIES['district_of_residence'].categories: - # Change the district of person 0 (for whom the HSI is created.) - sim.population.props.at[0, 'district_of_residence'] = _district - for _facility_id in fac_ids: - hsi_event = get_dummy_hsi_event_instance( - module=sim.modules['DummyModule'], - facility_id=_facility_id - ) - for _item_code in item_codes: - hsi_event.get_consumables(item_codes=_item_code) + for _district in sim.modules['Demography'].PROPERTIES['district_of_residence'].categories: + # Change the district of person 0 (for whom the HSI is created.) + sim.population.props.at[0, 'district_of_residence'] = _district + for _facility_id in fac_ids: + hsi_event = get_dummy_hsi_event_instance( + module=sim.modules['DummyModule'], + facility_id=_facility_id + ) + for _item_code in item_codes: + hsi_event.get_consumables(item_codes=_item_code) - sim.modules['HealthSystem'].on_simulation_end() + sim.modules['HealthSystem'].on_simulation_end() # Check that no warnings raised or item_codes recorded as being not recogised. assert not sim.modules['HealthSystem'].consumables._not_recognised_item_codes - assert not any_warnings_about_item_code(recorded_warnings) + assert not any_warnings_about_item_code(recwarn) def test_get_item_code_from_item_name(): @@ -554,3 +553,73 @@ def test_get_item_codes_from_package_name(): pd.Series(_item_codes).sort_index(), check_names=False ) + + +def test_consumables_availability_modes_that_depend_on_designations(seed): + """Test that consumables availability can be manipulated in a manner than depends on the designations of + consumables.""" + + sim = Simulation( + start_date=Date(2010, 1, 1), + seed=seed, + ) + + # Register the core modules + sim.register( + demography.Demography(resourcefilepath=resourcefilepath), + healthsystem.HealthSystem(resourcefilepath=resourcefilepath), + ) + sim.make_initial_population(n=100) + sim.simulate(end_date=sim.start_date) + hs = sim.modules['HealthSystem'] + consumables = hs.consumables + + # - Get the item_codes for each category + designations = hs.parameters['consumables_item_designations'] + items_all = consumables.item_codes + items_medicines = set(designations.index[designations['is_medicine']]).intersection(consumables.item_codes) + items_diagnostics = set(designations.index[designations['is_diagnostic']]).intersection(consumables.item_codes) + items_other = set(designations.index[designations['is_other']]).intersection(consumables.item_codes) + items_vital = set(designations.index[designations['is_vital']]).intersection(consumables.item_codes) + items_drug_or_vaccine = set( + designations.index[designations['is_drug_or_vaccine']] + ).intersection(consumables.item_codes) + + options_for_availability = consumables._options_for_availability + + for availability in options_for_availability: + # Manipulate consumables availability initially to be all medicines being available + consumables.availability = availability + + # Check that probabilities of availability are as expected: + if availability == 'all': + target_items = items_all + elif availability == 'all_medicines_available': + target_items = items_medicines + elif availability == 'all_diagnostics_available': + target_items = items_diagnostics + elif availability == 'all_medicines_and_other_available': + target_items = items_medicines.union(items_other) + elif availability == 'all_vital_available': + target_items = items_vital + elif availability == 'all_drug_or_vaccine_available': + target_items = items_drug_or_vaccine + elif availability == 'none': + target_items = set() + elif availability == 'default': + continue + else: + raise ValueError(f'Unexpected availability: {availability}') + + # - Check probabilities for selected items are 1.0 + if target_items: + assert ( + consumables._prob_item_codes_available.loc[(slice(None), slice(None), list(target_items))] == 1.0 + ).all() + + # - Check that probabilities for other items are not all equal to 1.0 + non_target_items = list(items_all - target_items) + if non_target_items: + assert not ( + consumables._prob_item_codes_available.loc[(slice(None), slice(None), non_target_items)] == 1.0 + ).all() diff --git a/tests/test_copd.py b/tests/test_copd.py index 6c8b8a0917..b47d803529 100644 --- a/tests/test_copd.py +++ b/tests/test_copd.py @@ -211,12 +211,12 @@ def test_moderate_exacerbation(): df.at[person_id, 'ch_has_inhaler'] = False # check individuals do not have symptoms before an event is run - assert 'breathless_moderate' not in sim.modules['SymptomManager'].has_what(person_id) + assert 'breathless_moderate' not in sim.modules['SymptomManager'].has_what(person_id=person_id) # run Copd Exacerbation event on an individual and confirm they now have a # non-emergency symptom(breathless moderate) copd.CopdExacerbationEvent(copd_module, person_id, severe=False).run() - assert 'breathless_moderate' in sim.modules['SymptomManager'].has_what(person_id) + assert 'breathless_moderate' in sim.modules['SymptomManager'].has_what(person_id=person_id) # Run health seeking behavior event and check non-emergency care is sought hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) @@ -259,13 +259,15 @@ def test_severe_exacerbation(): df.at[person_id, 'ch_has_inhaler'] = False # check an individual do not have emergency symptoms before an event is run - assert 'breathless_severe' not in sim.modules['SymptomManager'].has_what(person_id) + assert 'breathless_severe' not in sim.modules['SymptomManager'].has_what(person_id=person_id) # schedule exacerbations event setting severe to True. This will ensure the individual has severe exacerbation copd.CopdExacerbationEvent(copd_module, person_id, severe=True).run() # severe exacerbation should lead to severe symptom(breathless severe in this case). check this is true - assert 'breathless_severe' in sim.modules['SymptomManager'].has_what(person_id, copd_module) + assert "breathless_severe" in sim.modules["SymptomManager"].has_what( + person_id=person_id, disease_module=copd_module + ) # # Run health seeking behavior event and check emergency care is sought hsp = HealthSeekingBehaviourPoll(module=sim.modules['HealthSeekingBehaviour']) @@ -420,13 +422,15 @@ def test_referral_logic(): df.at[person_id, 'ch_has_inhaler'] = False # check an individual do not have emergency symptoms before an event is run - assert 'breathless_severe' not in sim.modules['SymptomManager'].has_what(person_id) + assert 'breathless_severe' not in sim.modules['SymptomManager'].has_what(person_id=person_id) # schedule exacerbations event setting severe to True. This will ensure the individual has severe exacerbation copd.CopdExacerbationEvent(copd_module, person_id, severe=True).run() # severe exacerbation should lead to severe symptom(breathless severe in this case). check this is true - assert 'breathless_severe' in sim.modules['SymptomManager'].has_what(person_id, copd_module) + assert "breathless_severe" in sim.modules["SymptomManager"].has_what( + person_id=person_id, disease_module=copd_module + ) # Run health seeking behavior event and check emergency care is sought hsp = HealthSeekingBehaviourPoll(module=sim.modules['HealthSeekingBehaviour']) diff --git a/tests/test_core.py b/tests/test_core.py index b7357541b3..c584ecf717 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -51,7 +51,7 @@ class TestLoadParametersFromDataframe: No explicit tests for correct parsing of boolean because of how python evaluates truthiness """ - def setup(self): + def setup_method(self): class ParameterModule(Module): def __init__(self): super().__init__(name=None) @@ -169,7 +169,7 @@ def test_bools(self): class TestLoadParametersFromDataframe_Bools_From_Csv: """Tests for the load_parameters_from_dataframe method, including handling of bools when loading from csv""" - def setup(self): + def setup_method(self): class ParameterModule(Module): def __init__(self): super().__init__(name=None) diff --git a/tests/test_demography.py b/tests/test_demography.py index 96b3ce1f7e..07a7d6fbca 100644 --- a/tests/test_demography.py +++ b/tests/test_demography.py @@ -374,3 +374,31 @@ def test_ageing_of_old_people_up_to_max_age(simulation): # All persons should have died, with a cause of 'Other' assert not df.loc[ever_alive].is_alive.any() assert (df.loc[ever_alive, 'cause_of_death'] == 'Other').all() + + +def test_equal_allocation_by_district(seed): + """ + Check when key-word argument `equal_allocation_by_district=True` that each district has an identical population size + """ + + resourcefilepath = Path(os.path.dirname(__file__)) / '../resources' + sim = Simulation(start_date=start_date, seed=seed) + sim.register( + demography.Demography( + resourcefilepath=resourcefilepath, + equal_allocation_by_district=True, + ) + ) + population_per_district = 10_000 + number_of_districts = len(sim.modules['Demography'].districts) + popsize = number_of_districts * population_per_district + sim.make_initial_population(n=popsize) + sim.simulate(end_date=sim.start_date) # Simulate for zero days + + # check population size + df = sim.population.props + assert sum(df.is_alive) == popsize + + # check total within each district is (close to being) identical and matches the target population of each district + pop_size_by_district = df.loc[df.is_alive].groupby('district_of_residence').size() + assert np.allclose(pop_size_by_district.values, pop_size_by_district, rtol=0.05) diff --git a/tests/test_diarrhoea.py b/tests/test_diarrhoea.py index 8681e9c024..3a4daebc5d 100644 --- a/tests/test_diarrhoea.py +++ b/tests/test_diarrhoea.py @@ -401,13 +401,28 @@ def test_do_when_presentation_with_diarrhoea_severe_dehydration(seed): } df.loc[person_id, props_new.keys()] = props_new.values() generic_hsi = HSI_GenericNonEmergencyFirstAppt( - module=sim.modules['HealthSeekingBehaviour'], person_id=person_id) + module=sim.modules["HealthSeekingBehaviour"], person_id=person_id + ) + symptoms = {"diarrhoea"} + + def diagnosis_fn(tests, use_dict: bool = False, report_tried: bool = False): + return generic_hsi.healthcare_system.dx_manager.run_dx_test( + tests, + hsi_event=generic_hsi, + use_dict_for_single=use_dict, + report_dxtest_tried=report_tried, + ) - # 1) If DxTest of danger signs perfect and 100% chance of referral --> Inpatient HSI should be created sim.modules['HealthSystem'].reset_queue() sim.modules['Diarrhoea'].parameters['prob_hospitalization_on_danger_signs'] = 1.0 - sim.modules['Diarrhoea'].do_when_presentation_with_diarrhoea( - person_id=person_id, hsi_event=generic_hsi) + with sim.population.individual_properties(person_id) as individual_properties: + sim.modules["Diarrhoea"].do_at_generic_first_appt( + person_id=person_id, + individual_properties=individual_properties, + schedule_hsi_event=sim.modules["HealthSystem"].schedule_hsi_event, + diagnosis_function=diagnosis_fn, + symptoms=symptoms, + ) evs = sim.modules['HealthSystem'].find_events_for_person(person_id) assert 1 == len(evs) @@ -416,8 +431,14 @@ def test_do_when_presentation_with_diarrhoea_severe_dehydration(seed): # 2) If DxTest of danger signs perfect but 0% chance of referral --> Inpatient HSI should not be created sim.modules['HealthSystem'].reset_queue() sim.modules['Diarrhoea'].parameters['prob_hospitalization_on_danger_signs'] = 0.0 - sim.modules['Diarrhoea'].do_when_presentation_with_diarrhoea( - person_id=person_id, hsi_event=generic_hsi) + with sim.population.individual_properties(person_id) as individual_properties: + sim.modules["Diarrhoea"].do_at_generic_first_appt( + person_id=person_id, + individual_properties=individual_properties, + schedule_hsi_event=sim.modules["HealthSystem"].schedule_hsi_event, + diagnosis_function=diagnosis_fn, + symptoms=symptoms, + ) evs = sim.modules['HealthSystem'].find_events_for_person(person_id) assert 1 == len(evs) assert isinstance(evs[0][1], HSI_Diarrhoea_Treatment_Outpatient) @@ -477,12 +498,27 @@ def test_do_when_presentation_with_diarrhoea_severe_dehydration_dxtest_notfuncti df.loc[person_id, props_new.keys()] = props_new.values() generic_hsi = HSI_GenericNonEmergencyFirstAppt( module=sim.modules['HealthSeekingBehaviour'], person_id=person_id) + symptoms = {"diarrhoea"} + + def diagnosis_fn(tests, use_dict: bool = False, report_tried: bool = False): + return generic_hsi.healthcare_system.dx_manager.run_dx_test( + tests, + hsi_event=generic_hsi, + use_dict_for_single=use_dict, + report_dxtest_tried=report_tried, + ) # Only an out-patient appointment should be created as the DxTest for danger signs is not functional. sim.modules['Diarrhoea'].parameters['prob_hospitalization_on_danger_signs'] = 0.0 sim.modules['HealthSystem'].reset_queue() - sim.modules['Diarrhoea'].do_when_presentation_with_diarrhoea( - person_id=person_id, hsi_event=generic_hsi) + with sim.population.individual_properties(person_id) as individual_properties: + sim.modules["Diarrhoea"].do_at_generic_first_appt( + person_id=person_id, + individual_properties=individual_properties, + schedule_hsi_event=sim.modules["HealthSystem"].schedule_hsi_event, + diagnosis_function=diagnosis_fn, + symptoms=symptoms, + ) evs = sim.modules['HealthSystem'].find_events_for_person(person_id) assert 1 == len(evs) assert isinstance(evs[0][1], HSI_Diarrhoea_Treatment_Outpatient) @@ -541,12 +577,26 @@ def test_do_when_presentation_with_diarrhoea_non_severe_dehydration(seed): df.loc[person_id, props_new.keys()] = props_new.values() generic_hsi = HSI_GenericNonEmergencyFirstAppt( module=sim.modules['HealthSeekingBehaviour'], person_id=person_id) - + symptoms = {"diarrhoea"} + + def diagnosis_fn(tests, use_dict: bool = False, report_tried: bool = False): + return generic_hsi.healthcare_system.dx_manager.run_dx_test( + tests, + hsi_event=generic_hsi, + use_dict_for_single=use_dict, + report_dxtest_tried=report_tried, + ) # 1) Outpatient HSI should be created - sim.modules['HealthSystem'].reset_queue() - sim.modules['Diarrhoea'].do_when_presentation_with_diarrhoea( - person_id=person_id, hsi_event=generic_hsi) - evs = sim.modules['HealthSystem'].find_events_for_person(person_id) + sim.modules["HealthSystem"].reset_queue() + with sim.population.individual_properties(person_id) as individual_properties: + sim.modules["Diarrhoea"].do_at_generic_first_appt( + person_id=person_id, + individual_properties=individual_properties, + schedule_hsi_event=sim.modules["HealthSystem"].schedule_hsi_event, + diagnosis_function=diagnosis_fn, + symptoms=symptoms, + ) + evs = sim.modules["HealthSystem"].find_events_for_person(person_id) assert 1 == len(evs) assert isinstance(evs[0][1], HSI_Diarrhoea_Treatment_Outpatient) diff --git a/tests/test_dxmanager.py b/tests/test_dxmanager.py index 06c22ec97d..1fbbb9a659 100644 --- a/tests/test_dxmanager.py +++ b/tests/test_dxmanager.py @@ -20,7 +20,7 @@ ) from tlo.methods.consumables import Consumables, create_dummy_data_for_cons_availability from tlo.methods.dxmanager import DxManager, DxTest -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event # -------------------------------------------------------------------------- # Create a very short-run simulation for use in the tests @@ -85,7 +85,7 @@ def apply(self, person_id, squeeze_factor): item_code_for_consumable_that_is_available = 1 sim.modules['HealthSystem'].consumables = Consumables( - data=create_dummy_data_for_cons_availability( + availability_data=create_dummy_data_for_cons_availability( intrinsic_availability={ item_code_for_consumable_that_is_not_available: 0.0, item_code_for_consumable_that_is_available: 1.0}, diff --git a/tests/test_equipment.py b/tests/test_equipment.py new file mode 100644 index 0000000000..1167023aa8 --- /dev/null +++ b/tests/test_equipment.py @@ -0,0 +1,480 @@ +"""This file contains all the tests to do with Equipment.""" +import os +from pathlib import Path +from typing import Dict + +import numpy as np +import pandas as pd +import pytest + +from tlo import Date, Module, Simulation +from tlo.analysis.utils import parse_log_file +from tlo.events import IndividualScopeEventMixin +from tlo.methods import Metadata, demography, healthsystem +from tlo.methods.equipment import Equipment +from tlo.methods.hsi_event import HSI_Event + +resourcefilepath = Path(os.path.dirname(__file__)) / "../resources" + + +def test_core_functionality_of_equipment_class(seed): + """Test that the core functionality of the equipment class works on toy data.""" + + # Create toy data + catalogue = pd.DataFrame( + # PkgWith0+1 stands alone or as multiple pkgs for one item; PkgWith1 is only as multiple pkgs + # for one item; PkgWith3 only stands alone + [ + {"Item_Description": "ItemZero", "Item_Code": 0, "Pkg_Name": 'PkgWith0+1'}, + {"Item_Description": "ItemOne", "Item_Code": 1, "Pkg_Name": 'PkgWith0+1, PkgWith1'}, + {"Item_Description": "ItemTwo", "Item_Code": 2, "Pkg_Name": float('nan')}, + {"Item_Description": "ItemThree", "Item_Code": 3, "Pkg_Name": 'PkgWith3'}, + ] + ) + data_availability = pd.DataFrame( + # item 0 is not available anywhere; item 1 is available everywhere; item 2 is available only at facility_id=1; + # item 3 is available only at facility_id=0 + [ + {"Item_Code": 0, "Facility_ID": 0, "Pr_Available": 0.0}, + {"Item_Code": 0, "Facility_ID": 1, "Pr_Available": 0.0}, + {"Item_Code": 1, "Facility_ID": 0, "Pr_Available": 1.0}, + {"Item_Code": 1, "Facility_ID": 1, "Pr_Available": 1.0}, + {"Item_Code": 2, "Facility_ID": 0, "Pr_Available": 0.0}, + {"Item_Code": 2, "Facility_ID": 1, "Pr_Available": 1.0}, + {"Item_Code": 3, "Facility_ID": 0, "Pr_Available": 1.0}, + {"Item_Code": 3, "Facility_ID": 1, "Pr_Available": 0.0}, + ] + ) + mfl = pd.DataFrame( + [ + {'District': 'D0', 'Facility_Level': '1a', 'Region': 'R0', 'Facility_ID': 0, 'Facility_Name': 'Fac0'}, + {'District': 'D0', 'Facility_Level': '1b', 'Region': 'R0', 'Facility_ID': 1, 'Facility_Name': 'Fac1'}, + ] + ) + + # Create instance of the Equipment class with these toy data and check availability of equipment... + # -- when using `default` behaviour: + eq_default = Equipment( + catalogue=catalogue, + data_availability=data_availability, + rng=np.random.RandomState(np.random.MT19937(np.random.SeedSequence(seed))), + master_facilities_list=mfl, + availability="default", + ) + + # Checks on parsing equipment items + # - using single integer for one item_code + assert {1} == eq_default.parse_items(1) + # - using list of integers for item_codes + assert {1, 2} == eq_default.parse_items([1, 2]) + # - using single string for one item descriptor + assert {1} == eq_default.parse_items('ItemOne') + # - using list of strings for item descriptors + assert {1, 2} == eq_default.parse_items(['ItemOne', 'ItemTwo']) + # - an empty iterable of equipment should always be work whether expressed as list/tuple/set + assert set() == eq_default.parse_items(list()) + assert set() == eq_default.parse_items(tuple()) + assert set() == eq_default.parse_items(set()) + + # - Calling for unrecognised item_codes (should raise warning) + with pytest.warns(): + eq_default.parse_items(10001) + with pytest.warns(): + eq_default.parse_items('ItemThatIsNotDefined') + + # Lookup the item_codes that belong in a particular package. + # - When package is recognised + # if items are in the same package (once standing alone, once within multiple pkgs defined for item) + assert {0, 1} == eq_default.from_pkg_names(pkg_names='PkgWith0+1') + # if the pkg within multiple pkgs defined for item + assert {1} == eq_default.from_pkg_names(pkg_names='PkgWith1') + # if the pkg only stands alone + assert {3} == eq_default.from_pkg_names(pkg_names='PkgWith3') + # Lookup the item_codes that belong to multiple specified packages. + assert {0, 1, 3} == eq_default.from_pkg_names(pkg_names={'PkgWith0+1', 'PkgWith3'}) + assert {1, 3} == eq_default.from_pkg_names(pkg_names={'PkgWith1', 'PkgWith3'}) + + # - When package is not recognised (should raise an error) + with pytest.raises(ValueError): + eq_default.from_pkg_names(pkg_names='') + + # Testing checking on available of items + # - calling when all items available (should be true) + assert eq_default.is_all_items_available(item_codes={1, 2}, facility_id=1) + # - calling when no items available (should be false) + assert not eq_default.is_all_items_available(item_codes={0, 2}, facility_id=0) + # - calling when some items available (should be false) + assert not eq_default.is_all_items_available(item_codes={1, 2}, facility_id=0) + # - calling for empty set of equipment (should always be available) + assert eq_default.is_all_items_available(item_codes=set(), facility_id=0) + + # -- calling for an unrecognised facility_id (should error) + with pytest.raises(AssertionError): + eq_default.is_all_items_available(item_codes={1}, facility_id=1001) + + # -- when using `none` availability behaviour: everything should not be available! + eq_none = Equipment( + catalogue=catalogue, + data_availability=data_availability, + rng=np.random.RandomState(np.random.MT19937(np.random.SeedSequence(seed))), + availability="none", + master_facilities_list=mfl, + ) + # - calling when all items available (should be false because using 'none' behaviour) + assert not eq_none.is_all_items_available(item_codes={1, 2}, facility_id=1) + # - calling when no items available (should be false) + assert not eq_none.is_all_items_available(item_codes={0, 2}, facility_id=0) + # - calling when some items available (should be false) + assert not eq_none.is_all_items_available(item_codes={1, 2}, facility_id=0) + # - calling for empty set of equipment (should always be available) + assert eq_none.is_all_items_available(item_codes=set(), facility_id=0) + + # -- when using `all` availability behaviour: everything should not be available! + eq_all = Equipment( + catalogue=catalogue, + data_availability=data_availability, + rng=np.random.RandomState(np.random.MT19937(np.random.SeedSequence(seed))), + availability="all", + master_facilities_list=mfl, + ) + # - calling when all items available (should be true) + assert eq_all.is_all_items_available(item_codes={1, 2}, facility_id=1) + # - calling when no items available (should be true because using 'all' behaviour) + assert eq_all.is_all_items_available(item_codes={0, 2}, facility_id=0) + # - calling when some items available (should be true because using 'all' behaviour) + assert eq_all.is_all_items_available(item_codes={1, 2}, facility_id=0) + # - calling for empty set of equipment (should always be available) + assert eq_all.is_all_items_available(item_codes=set(), facility_id=0) + + # Check recording use of equipment + # - Add records, using calls with integers and list to different facility_id + eq_default.record_use_of_equipment(item_codes={1}, facility_id=0) + eq_default.record_use_of_equipment(item_codes={0, 1}, facility_id=0) + eq_default.record_use_of_equipment(item_codes={0, 1}, facility_id=1) + # - Check that internal record is as expected + assert {0: {0: 1, 1: 2}, 1: {0: 1, 1: 1}} == dict(eq_default._record_of_equipment_used_by_facility_id) + + +equipment_item_code_that_is_available = [0, 1, ] +equipment_item_code_that_is_not_available = [2, 3,] + + +def run_simulation_and_return_log( + seed, tmpdir, equipment_in_init, equipment_in_apply +) -> Dict: + """Returns the parsed logs from `tlo.methods.healthsystem.summary` from a + simulation object in which a single event has been run with the specified equipment usage. The + availability of equipment has been manipulated so that the item_codes given in + `equipment_item_code_that_is_available` and `equipment_item_code_that_is_not_available` are as expected. """ + + class DummyHSIEvent(HSI_Event, IndividualScopeEventMixin): + def __init__( + self, + module, + person_id, + level, + essential_equipment, + other_equipment, + ): + super().__init__(module, person_id=person_id) + self.TREATMENT_ID = "DummyHSIEvent" + self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({}) + self.ACCEPTED_FACILITY_LEVEL = level + self.add_equipment(essential_equipment) # Declaration at init will mean that these items are considered + # essential. + self._other_equipment = other_equipment + + def apply(self, person_id, squeeze_factor): + if self._other_equipment is not None: + self.add_equipment(self._other_equipment) + + class DummyModule(Module): + METADATA = {Metadata.DISEASE_MODULE, Metadata.USES_HEALTHSYSTEM} + + def __init__(self, essential_equipment, other_equipment, name=None): + super().__init__(name) + self.essential_equipment = essential_equipment + self.other_equipment = other_equipment + + def read_parameters(self, data_folder): + pass + + def initialise_population(self, population): + pass + + def initialise_simulation(self, sim): + # Schedule the HSI_Event to occur on the first day of the simulation + sim.modules["HealthSystem"].schedule_hsi_event( + hsi_event=DummyHSIEvent( + person_id=0, + level="2", + module=sim.modules["DummyModule"], + essential_equipment=self.essential_equipment, + other_equipment=self.other_equipment, + ), + do_hsi_event_checks=False, + topen=sim.date, + tclose=None, + priority=0, + ) + + log_config = {"filename": "log", "directory": tmpdir} + sim = Simulation(start_date=Date(2010, 1, 1), seed=seed, log_config=log_config) + sim.register( + demography.Demography(resourcefilepath=resourcefilepath), + healthsystem.HealthSystem(resourcefilepath=resourcefilepath), + DummyModule( + essential_equipment=equipment_in_init, other_equipment=equipment_in_apply + ), + ) + + # Manipulate availability of equipment + df = sim.modules["HealthSystem"].parameters["equipment_availability_estimates"] + df.loc[df['Item_Code'].isin(equipment_item_code_that_is_available), 'Pr_Available'] = 1.0 + df.loc[df['Item_Code'].isin(equipment_item_code_that_is_not_available), 'Pr_Available'] = 0.0 + + # Run the simulation + sim.make_initial_population(n=100) + sim.simulate(end_date=sim.start_date + pd.DateOffset(months=1)) + + # Return the parsed log of `tlo.methods.healthsystem.summary` + return parse_log_file(sim.log_filepath)["tlo.methods.healthsystem.summary"] + + + +def test_equipment_use_is_logged(seed, tmpdir): + """Check that an HSI that after an HSI is run, the logs reflect the use of the equipment (and correctly record the + name of the HSI and the facility_level at which ran). + This is repeated for: + * An HSI that declares use of equipment during its `apply` method (but no essential equipment); + * An HSI that declare use of essential equipment but nothing in its `apply` method`; + * An HSI that declare use of essential equipment and equipment during its `apply` method; + * An HSI that declares not use of any equipment. + """ + the_item_code = equipment_item_code_that_is_available[0] + another_item_code = equipment_item_code_that_is_available[1] + + def all_equipment_ever_used(log: Dict) -> set: + """With the log of equipment used in the simulation, return a set of the equipment item that have been used + (at any facility).""" + s = set() + for i in log["EquipmentEverUsed_ByFacilityID"]['EquipmentEverUsed']: + s.update(eval(i)) + return s + + # * An HSI that declares no use of any equipment (logs should be empty). + assert set() == all_equipment_ever_used( + run_simulation_and_return_log( + seed=seed, + tmpdir=tmpdir, + equipment_in_init=set(), + equipment_in_apply=set(), + ) + ) + + # * An HSI that declares use of equipment only during its `apply` method. + assert {the_item_code} == all_equipment_ever_used( + run_simulation_and_return_log( + seed=seed, + tmpdir=tmpdir, + equipment_in_init=set(), + equipment_in_apply=the_item_code, + ) + ) + + # * An HSI that declare use of equipment only in its `__init__` method + assert {the_item_code} == all_equipment_ever_used( + run_simulation_and_return_log( + seed=seed, + tmpdir=tmpdir, + equipment_in_init=the_item_code, + equipment_in_apply=set(), + ) + ) + + # * An HSI that declare use of equipment in `__init__` _and_ `apply`. + assert {the_item_code, another_item_code} == all_equipment_ever_used( + run_simulation_and_return_log( + seed=seed, + tmpdir=tmpdir, + equipment_in_init=the_item_code, + equipment_in_apply=another_item_code, + ) + ) + + +def test_hsi_does_not_run_if_equipment_declared_in_init_is_not_available(seed, tmpdir): + """Check that an HSI which declares an item of equipment that is declared in the HSI_Event's __init__ does run if + that item is available and does not run if that item is not available.""" + + def did_the_hsi_run(log: Dict) -> bool: + """Read the log to work out if the `DummyHSIEvent` ran or not.""" + it_did_run = len(log['hsi_event_counts'].iloc[0]['hsi_event_key_to_counts']) > 0 + it_did_not_run = len(log['never_ran_hsi_event_counts'].iloc[0]['never_ran_hsi_event_key_to_counts']) > 0 + + # Check that there if it did not run, it has had its "never_ran" function called + assert it_did_run != it_did_not_run + + # Return indication of whether it did run + return it_did_run + + + # HSI_Event that requires equipment that is available --> will run + assert did_the_hsi_run( + run_simulation_and_return_log( + seed=seed, + tmpdir=tmpdir, + equipment_in_init=equipment_item_code_that_is_available, + equipment_in_apply=set(), + ) + ) + + # HSI_Event that requires equipment that is not available --> will not run + assert not did_the_hsi_run( + run_simulation_and_return_log( + seed=seed, + tmpdir=tmpdir, + equipment_in_init=equipment_item_code_that_is_not_available, + equipment_in_apply=set(), + ) + ) + + +def test_change_equipment_availability(seed): + """Test that we can change the probability of the availability of equipment midway through the simulation.""" + # Set-up simulation that starts with `all` availability and then changes to `none` after one year. In the + # simulation a DummyModule schedules a DummyHSI that runs every month and tries to get a piece of equipment; + # then, check that the probability that this piece of equipment is available each month during the simulation. + + class DummyHSIEvent(HSI_Event, IndividualScopeEventMixin): + def __init__( + self, + module, + person_id, + ): + super().__init__(module, person_id=person_id) + self.TREATMENT_ID = "DummyHSIEvent" + self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({}) + self.ACCEPTED_FACILITY_LEVEL = '1a' + self.store_of_equipment_checks = dict() + + def apply(self, person_id, squeeze_factor): + # Check availability of a piece of equipment, with item_code = 0 + self.store_of_equipment_checks.update( + { + self.sim.date: self.probability_all_equipment_available(item_codes={0}) + } + ) + + # Schedule recurrence of this event in one month's time + self.sim.modules["HealthSystem"].schedule_hsi_event( + hsi_event=self, + do_hsi_event_checks=False, + topen=self.sim.date + pd.DateOffset(months=1), + tclose=None, + priority=0, + ) + + class DummyModule(Module): + METADATA = {Metadata.DISEASE_MODULE, Metadata.USES_HEALTHSYSTEM} + + def read_parameters(self, data_folder): + pass + + def initialise_population(self, population): + pass + + def initialise_simulation(self, sim): + # Schedule the HSI_Event to occur on the first day of the simulation (it will schedule its own repeats) + self.the_hsi_event = DummyHSIEvent(person_id=0, module=self) + + sim.modules["HealthSystem"].schedule_hsi_event( + hsi_event=self.the_hsi_event, + do_hsi_event_checks=False, + topen=sim.date, + tclose=None, + priority=0, + ) + + sim = Simulation(start_date=Date(2010, 1, 1), seed=seed) + sim.register( + demography.Demography(resourcefilepath=resourcefilepath), + healthsystem.HealthSystem(resourcefilepath=resourcefilepath), + DummyModule(), + ) + # Modify the parameters of the healthsystem to effect a change in the availability of equipment + sim.modules['HealthSystem'].parameters['equip_availability'] = 'all' + sim.modules['HealthSystem'].parameters['equip_availability_postSwitch'] = 'none' + sim.modules['HealthSystem'].parameters['year_equip_availability_switch'] = 2011 + + sim.make_initial_population(n=100) + sim.simulate(end_date=sim.start_date + pd.DateOffset(years=2)) + + # Get store & check for availabilities of the equipment + log = pd.Series(sim.modules['DummyModule'].the_hsi_event.store_of_equipment_checks) + assert (1.0 == log[log.index < Date(2011, 1, 1)]).all() + assert (0.0 == log[log.index >= Date(2011, 1, 1)]).all() + + +def test_logging_of_equipment_from_multiple_hsi(seed, tmpdir): + """Test that we correctly capture in the log the equipment declared by different HSI_Events that run at different + levels.""" + + item_code_needed_at_each_level = { + '0': set({0}), '1a': set({10}), '2': set({30}), '3': set({44}), '4': set() + } + + class DummyHSIEvent(HSI_Event, IndividualScopeEventMixin): + def __init__( + self, + module, + person_id, + level, + equipment_item_code + ): + super().__init__(module, person_id=person_id) + self.TREATMENT_ID = f"DummyHSIEvent_Level:{level}" + self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({}) + self.ACCEPTED_FACILITY_LEVEL = level + self.add_equipment(equipment_item_code) + + def apply(self, person_id, squeeze_factor): + pass + + class DummyModule(Module): + METADATA = {Metadata.DISEASE_MODULE, Metadata.USES_HEALTHSYSTEM} + + def read_parameters(self, data_folder): + pass + + def initialise_population(self, population): + pass + + def initialise_simulation(self, sim): + # Schedule the HSI_Events to occur, with the level determining the item_code used + for level, item_code in item_code_needed_at_each_level.items(): + sim.modules["HealthSystem"].schedule_hsi_event( + hsi_event=DummyHSIEvent(person_id=0, module=self, level=level, equipment_item_code=item_code), + do_hsi_event_checks=False, + topen=sim.date, + tclose=None, + priority=0, + ) + + log_config = {"filename": "log", "directory": tmpdir} + sim = Simulation(start_date=Date(2010, 1, 1), seed=seed, log_config=log_config) + sim.register( + demography.Demography(resourcefilepath=resourcefilepath), + healthsystem.HealthSystem(resourcefilepath=resourcefilepath), + DummyModule(), + ) + sim.make_initial_population(n=100) + sim.simulate(end_date=sim.start_date + pd.DateOffset(days=1)) + + # Read log to find what equipment used + df = parse_log_file(sim.log_filepath)["tlo.methods.healthsystem.summary"]['EquipmentEverUsed_ByFacilityID'] + df = df.drop(index=df.index[~df['Facility_Level'].isin(item_code_needed_at_each_level.keys())]) + df['EquipmentEverUsed'] = df['EquipmentEverUsed'].apply(eval).apply(list) + + # Check that equipment used at each level matches expectations + assert item_code_needed_at_each_level == df.groupby('Facility_Level')['EquipmentEverUsed'].sum().apply(set).to_dict() diff --git a/tests/test_healthsystem.py b/tests/test_healthsystem.py index e07a2d5889..ae212a4f48 100644 --- a/tests/test_healthsystem.py +++ b/tests/test_healthsystem.py @@ -1,7 +1,7 @@ import heapq as hp import os from pathlib import Path -from typing import Set, Tuple +from typing import Dict, Set, Tuple import numpy as np import pandas as pd @@ -27,7 +27,9 @@ ) from tlo.methods.consumables import Consumables, create_dummy_data_for_cons_availability from tlo.methods.fullmodel import fullmodel -from tlo.methods.healthsystem import HealthSystem, HealthSystemChangeParameters, HSI_Event +from tlo.methods.healthsystem import HealthSystem, HealthSystemChangeParameters +from tlo.methods.hsi_event import HSI_Event +from tlo.util import BitsetDType resourcefilepath = Path(os.path.dirname(__file__)) / '../resources' @@ -187,7 +189,11 @@ def test_run_no_interventions_allowed(tmpdir, seed): # Do the checks for the symptom manager: some symptoms should be registered assert sim.population.props.loc[:, sim.population.props.columns.str.startswith('sy_')] \ .apply(lambda x: x != set()).any().any() - assert (sim.population.props.loc[:, sim.population.props.columns.str.startswith('sy_')].dtypes == 'int64').all() + assert ( + sim.population.props.loc[ + :, sim.population.props.columns.str.startswith('sy_') + ].dtypes == BitsetDType + ).all() assert not pd.isnull(sim.population.props.loc[:, sim.population.props.columns.str.startswith('sy_')]).any().any() # Check that no one was cured of mockitis: @@ -394,6 +400,86 @@ def test_run_in_mode_1_with_capacity(tmpdir, seed): assert any(sim.population.props['mi_status'] == 'P') +@pytest.mark.slow +def test_rescaling_capabilities_based_on_squeeze_factors(tmpdir, seed): + # Capabilities should increase when a HealthSystem that has low capabilities changes mode with + # the option `scale_to_effective_capabilities` set to `True`. + + # Establish the simulation object + sim = Simulation( + start_date=start_date, + seed=seed, + log_config={ + "filename": "log", + "directory": tmpdir, + "custom_levels": { + "tlo.methods.healthsystem": logging.DEBUG, + } + } + ) + + # Register the core modules + # Set the year in which mode is changed to start_date + 1 year, and mode after that still 1. + # Check that in second year, squeeze factor is smaller on average. + sim.register(demography.Demography(resourcefilepath=resourcefilepath), + simplified_births.SimplifiedBirths(resourcefilepath=resourcefilepath), + enhanced_lifestyle.Lifestyle(resourcefilepath=resourcefilepath), + healthsystem.HealthSystem(resourcefilepath=resourcefilepath, + capabilities_coefficient=0.0000001, # This will mean that capabilities are + # very close to 0 everywhere. + # (If the value was 0, then it would + # be interpreted as the officers NEVER + # being available at a facility, + # which would mean the HSIs should not + # run (as opposed to running with + # a very high squeeze factor)). + ), + symptommanager.SymptomManager(resourcefilepath=resourcefilepath), + healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resourcefilepath), + mockitis.Mockitis(), + chronicsyndrome.ChronicSyndrome() + ) + + # Define the "switch" from Mode 1 to Mode 1, with the rescaling + hs_params = sim.modules['HealthSystem'].parameters + hs_params['mode_appt_constraints'] = 1 + hs_params['mode_appt_constraints_postSwitch'] = 1 + hs_params['year_mode_switch'] = start_date.year + 1 + hs_params['scale_to_effective_capabilities'] = True + + # Run the simulation + sim.make_initial_population(n=popsize) + sim.simulate(end_date=end_date) + check_dtypes(sim) + + # read the results + output = parse_log_file(sim.log_filepath, level=logging.DEBUG) + + # Do the checks + assert len(output['tlo.methods.healthsystem']['HSI_Event']) > 0 + hsi_events = output['tlo.methods.healthsystem']['HSI_Event'] + hsi_events['date'] = pd.to_datetime(hsi_events['date']).dt.year + + # Check that all squeeze factors were high in 2010, but not all were high in 2011 + # thanks to rescaling of capabilities + assert ( + hsi_events.loc[ + (hsi_events['Person_ID'] >= 0) & + (hsi_events['Number_By_Appt_Type_Code'] != {}) & + (hsi_events['date'] == 2010), + 'Squeeze_Factor' + ] >= 100.0 + ).all() # All the events that had a non-blank footprint experienced high squeezing. + assert not ( + hsi_events.loc[ + (hsi_events['Person_ID'] >= 0) & + (hsi_events['Number_By_Appt_Type_Code'] != {}) & + (hsi_events['date'] == 2011), + 'Squeeze_Factor' + ] >= 100.0 + ).all() # All the events that had a non-blank footprint experienced high squeezing. + + @pytest.mark.slow def test_run_in_mode_1_with_almost_no_capacity(tmpdir, seed): # Events should run but (for those with non-blank footprints) with high squeeze factors @@ -845,7 +931,7 @@ def apply(self, person_id, squeeze_factor): all_fac_ids = set(mfl.loc[mfl.Facility_Level != '5'].Facility_ID) sim.modules['HealthSystem'].consumables = Consumables( - data=create_dummy_data_for_cons_availability( + availability_data=create_dummy_data_for_cons_availability( intrinsic_availability={0: 0.5, 1: 0.5}, months=list(range(1, 13)), facility_ids=list(all_fac_ids)), @@ -862,7 +948,7 @@ def apply(self, person_id, squeeze_factor): detailed_consumables = log["tlo.methods.healthsystem"]['Consumables'] assert {'date', 'TREATMENT_ID', 'did_run', 'Squeeze_Factor', 'priority', 'Number_By_Appt_Type_Code', 'Person_ID', - 'Facility_Level', 'Facility_ID', 'Event_Name', + 'Facility_Level', 'Facility_ID', 'Event_Name', 'Equipment' } == set(detailed_hsi_event.columns) assert {'date', 'Frac_Time_Used_Overall', 'Frac_Time_Used_By_Facility_ID', 'Frac_Time_Used_By_OfficerType', } == set(detailed_capacity.columns) @@ -1260,6 +1346,8 @@ def test_HealthSystemChangeParameters(seed, tmpdir): 'capabilities_coefficient': 0.5, 'cons_availability': 'all', 'beds_availability': 'default', + 'equip_availability': 'default', + 'use_funded_or_actual_staffing': 'funded_plus', } new_parameters = { 'mode_appt_constraints': 2, @@ -1267,6 +1355,8 @@ def test_HealthSystemChangeParameters(seed, tmpdir): 'capabilities_coefficient': 1.0, 'cons_availability': 'none', 'beds_availability': 'none', + 'equip_availability': 'all', + 'use_funded_or_actual_staffing': 'actual', } class CheckHealthSystemParameters(RegularEvent, PopulationScopeEventMixin): @@ -1280,8 +1370,10 @@ def apply(self, population): _params['mode_appt_constraints'] = hs.mode_appt_constraints _params['ignore_priority'] = hs.ignore_priority _params['capabilities_coefficient'] = hs.capabilities_coefficient - _params['cons_availability'] = hs.consumables.cons_availability + _params['cons_availability'] = hs.consumables.availability _params['beds_availability'] = hs.bed_days.availability + _params['equip_availability'] = hs.equipment.availability + _params['use_funded_or_actual_staffing'] = hs.use_funded_or_actual_staffing logger = logging.getLogger('tlo.methods.healthsystem') logger.info(key='CheckHealthSystemParameters', data=_params) @@ -1448,8 +1540,12 @@ def get_set_of_treatment_ids_that_run(service_availability) -> Set[str]: get_set_of_treatment_ids_that_run(service_availability=["Hiv_Test_*"]) - generic_first_appts # Allow all `Hiv` things (but nothing else) - assert set({'Hiv_Test', 'Hiv_Treatment', 'Hiv_Prevention_Circumcision'}) == \ - get_set_of_treatment_ids_that_run(service_availability=["Hiv_*"]) - generic_first_appts + hiv_hsi_events = {'Hiv_Test', 'Hiv_Treatment', 'Hiv_Prevention_Circumcision', 'Hiv_Prevention_Infant', + 'Hiv_Prevention_Prep', 'Hiv_PalliativeCare'} + returned_treatment_ids = get_set_of_treatment_ids_that_run(service_availability=["Hiv_*"]) + + assert returned_treatment_ids.intersection( + hiv_hsi_events), "None of the expected treatment IDs are found in the returned set" # Allow all except `Hiv_Test` everything_except_hiv_test = everything - set({'Hiv_Test'}) @@ -2243,25 +2339,28 @@ def get_hsi_log(service_availability, randomise_hsi_queue) -> pd.DataFrame: pd.testing.assert_frame_equal(run_with_asterisk, run_with_list) -def test_const_HR_scaling_assumption(seed, tmpdir): - """Check that we can use the parameter `const_HR_scaling_mode` to manipulate the minutes of time available for healthcare - workers.""" +def test_HR_scaling_by_level_and_officer_type_assumption(seed, tmpdir): + """Check that we can use the parameter `HR_scaling_by_level_and_officer_type_mode` to manipulate the minutes of + time available for healthcare workers.""" - def get_capabilities_today(const_HR_scaling_mode: str) -> pd.Series: + def get_capabilities_today(HR_scaling_by_level_and_officer_type_mode: str) -> pd.Series: sim = Simulation(start_date=start_date, seed=seed) sim.register( demography.Demography(resourcefilepath=resourcefilepath), healthsystem.HealthSystem(resourcefilepath=resourcefilepath) ) - sim.modules['HealthSystem'].parameters['const_HR_scaling_mode'] = const_HR_scaling_mode + sim.modules['HealthSystem'].parameters['HR_scaling_by_level_and_officer_type_mode'] = \ + HR_scaling_by_level_and_officer_type_mode + sim.modules['HealthSystem'].parameters['year_HR_scaling_by_level_and_officer_type'] = 2010 sim.make_initial_population(n=100) - sim.simulate(end_date=start_date + pd.DateOffset(days=0)) + # Days ran need to be offset by 1 in order for event on 2010,1,1 to take place + sim.simulate(end_date=start_date + pd.DateOffset(days=1)) return sim.modules['HealthSystem'].capabilities_today caps = { - _const_HR_scaling_mode: get_capabilities_today(_const_HR_scaling_mode) - for _const_HR_scaling_mode in ('default', 'data', 'custom') + _HR_scaling_by_level_and_officer_type_mode: get_capabilities_today(_HR_scaling_by_level_and_officer_type_mode) + for _HR_scaling_by_level_and_officer_type_mode in ('default', 'data', 'custom') } # Check that the custom assumption (multiplying all capabilities by 0.5) gives expected result @@ -2292,7 +2391,7 @@ def get_initial_capabilities() -> pd.Series: return sim.modules['HealthSystem'].capabilities_today - def get_capabilities_after_two_years(dynamic_HR_scaling_factor: float, scale_HR_by_pop_size: bool) -> tuple: + def get_capabilities_after_two_updates(dynamic_HR_scaling_factor: float, scale_HR_by_pop_size: bool) -> tuple: sim = Simulation(start_date=start_date, seed=seed) sim.register( demography.Demography(resourcefilepath=resourcefilepath), @@ -2300,17 +2399,20 @@ def get_capabilities_after_two_years(dynamic_HR_scaling_factor: float, scale_HR_ simplified_births.SimplifiedBirths(resourcefilepath=resourcefilepath), ) - sim.modules['HealthSystem'].parameters['dynamic_HR_scaling_factor'] = dynamic_HR_scaling_factor - sim.modules['HealthSystem'].parameters['scale_HR_by_popsize'] = scale_HR_by_pop_size - sim.make_initial_population(n=100) - - # Ensure simulation lasts long enough so that current capabilities reflect that used in the third year of - # simulation (i.e. after two annual updates) - sim.simulate(end_date=start_date + pd.DateOffset(years=2, days=1)) + params = sim.modules['HealthSystem'].parameters + df = params['yearly_HR_scaling'][params['yearly_HR_scaling_mode']] + df.loc[df['year'] == 2010, 'dynamic_HR_scaling_factor'] = dynamic_HR_scaling_factor + df.loc[df['year'] == 2010, 'scale_HR_by_popsize'] = scale_HR_by_pop_size + popsize = 100 + sim.make_initial_population(n=popsize) - popsize = sim.modules['Demography'].popsize_by_year + # Ensure simulation lasts long enough so that current capabilities reflect that used after two updates + # (updates occur on 1st Jan, starting in 2010, so simulation should stop on 2nd Jan 2011). + sim.simulate(end_date=Date(2011, 1, 2)) - final_popsize_increase = popsize[2012]/popsize[2010] + popsize_start = popsize + popsize_curr = sim.population.props['is_alive'].sum() + final_popsize_increase = popsize_curr / popsize_start return sim.modules['HealthSystem'].capabilities_today, final_popsize_increase @@ -2321,17 +2423,17 @@ def get_capabilities_after_two_years(dynamic_HR_scaling_factor: float, scale_HR_ initial_caps = initial_caps[initial_caps != 0] # Check that dynamic expansion over two years leads to expansion = dynamic_HR_scaling_factor^2 - caps, final_popsize_increase = get_capabilities_after_two_years( + caps, final_popsize_increase = get_capabilities_after_two_updates( dynamic_HR_scaling_factor=dynamic_HR_scaling_factor, scale_HR_by_pop_size=False ) caps = caps[caps != 0] ratio_in_sim = caps/initial_caps - expected_value = dynamic_HR_scaling_factor*dynamic_HR_scaling_factor + expected_value = dynamic_HR_scaling_factor * dynamic_HR_scaling_factor assert np.allclose(ratio_in_sim, expected_value) # Check that expansion over two years with scaling prop to pop expansion works as expected - caps, final_popsize_increase = get_capabilities_after_two_years( + caps, final_popsize_increase = get_capabilities_after_two_updates( dynamic_HR_scaling_factor=1.0, scale_HR_by_pop_size=True ) @@ -2341,7 +2443,7 @@ def get_capabilities_after_two_years(dynamic_HR_scaling_factor: float, scale_HR_ assert np.allclose(ratio_in_sim, expected_value) # Check that expansion over two years with both fixed scaling and pop expansion scaling works as expected - caps, final_popsize_increase = get_capabilities_after_two_years( + caps, final_popsize_increase = get_capabilities_after_two_updates( dynamic_HR_scaling_factor=dynamic_HR_scaling_factor, scale_HR_by_pop_size=True ) @@ -2349,3 +2451,69 @@ def get_capabilities_after_two_years(dynamic_HR_scaling_factor: float, scale_HR_ ratio_in_sim = caps/initial_caps expected_value = final_popsize_increase*dynamic_HR_scaling_factor*dynamic_HR_scaling_factor assert np.allclose(ratio_in_sim, expected_value) + + +def test_dynamic_HR_scaling_multiple_changes(seed, tmpdir): + """Check that we can scale the minutes of time available for healthcare workers with a sequence of factors that + apply in different years.""" + + def get_initial_capabilities() -> pd.Series: + sim = Simulation(start_date=start_date, seed=seed) + sim.register( + demography.Demography(resourcefilepath=resourcefilepath), + healthsystem.HealthSystem(resourcefilepath=resourcefilepath) + ) + sim.make_initial_population(n=100) + sim.simulate(end_date=start_date + pd.DateOffset(days=0)) + + return sim.modules['HealthSystem'].capabilities_today + + def run_sim(dynamic_HR_scaling_factor: Dict[int, float]) -> tuple: + """Run simulation for 10 years, with a sequence of factors that apply, specified in a dict of the form + {year: factor_to_apply_this_year_and_subsequent_years_until_next_instruction} (i.e. how the ResourceFile should + be structured.) + Returns capabilities at the end of the 10-year simulation""" + + sim = Simulation(start_date=start_date, seed=seed) + sim.register( + demography.Demography(resourcefilepath=resourcefilepath), + healthsystem.HealthSystem(resourcefilepath=resourcefilepath), + simplified_births.SimplifiedBirths(resourcefilepath=resourcefilepath), + + ) + params = sim.modules['HealthSystem'].parameters + params['yearly_HR_scaling'][params['yearly_HR_scaling_mode']] = pd.DataFrame({ + 'year': dynamic_HR_scaling_factor.keys(), + 'dynamic_HR_scaling_factor': dynamic_HR_scaling_factor.values(), + 'scale_HR_by_popsize': False, + }) + + popsize = 100 + sim.make_initial_population(n=popsize) + + # Ensure simulation lasts long enough so that current capabilities reflect that used after two updates + # (updates occur on 1st Jan, starting in 2010, so simulation should stop on 2nd Jan 2011). + sim.simulate(end_date=sim.date + pd.DateOffset(years=10, days=1)) + + return sim.modules['HealthSystem'].capabilities_today + + dynamic_HR_scaling_factor = { + 2010: 1.0, + 2011: 2.0, + # (2012 and 2013) are skipped: implies that the value for 2010 should apply in these years + 2014: 0.2, + 2015: 1.0, + # (2016, ..., 2020 are skipped: implies that the value for 2015 should apply in the years) + } + expected_overall_scaling = 2.0 * 2.0 * 2.0 * 0.2 + + # Get initial capabilities and remove all officers with no minutes available + initial_caps = get_initial_capabilities() + initial_caps = initial_caps[initial_caps != 0] + + # Check that dynamic expansion over two years leads to expansion = dynamic_HR_scaling_factor^2 + caps = run_sim(dynamic_HR_scaling_factor=dynamic_HR_scaling_factor) + caps = caps[caps != 0] + ratio_in_sim = caps / initial_caps + + assert np.allclose(ratio_in_sim, expected_overall_scaling) diff --git a/tests/test_hiv.py b/tests/test_hiv.py index 59746f21ff..5a27cf2c33 100644 --- a/tests/test_hiv.py +++ b/tests/test_hiv.py @@ -30,6 +30,7 @@ from tlo.methods.healthseekingbehaviour import HealthSeekingBehaviourPoll from tlo.methods.healthsystem import HealthSystemScheduler from tlo.methods.hiv import ( + HivAidsDeathEvent, HivAidsOnsetEvent, HSI_Hiv_StartOrContinueTreatment, HSI_Hiv_TestAndRefer, @@ -136,18 +137,18 @@ def test_initialisation(seed): for idx in before_aids_idx: events_for_this_person = sim.find_events_for_person(idx) - assert 1 == len(events_for_this_person) - next_event_date, next_event_obj = events_for_this_person[0] - assert isinstance(next_event_obj, hiv.HivAidsOnsetEvent) - assert next_event_date >= sim.date + assert len(events_for_this_person) > 0 + assert len([event for _ , event in events_for_this_person if isinstance(event, HivAidsOnsetEvent)]) + assert all(date_of_event >= sim.date for date_of_event, _ in + events_for_this_person), "Not all dates in the event list are after the current date" - # check that everyone who is infected and has got AIDS event get a future AIDS death event but nothing else + # check that everyone who is infected and has got AIDS event get a future AIDS death event for idx in aids: events_for_this_person = sim.find_events_for_person(idx) - assert 1 == len(events_for_this_person) - next_event_date, next_event_obj = events_for_this_person[0] - assert isinstance(next_event_obj, hiv.HivAidsDeathEvent) - assert next_event_date >= sim.date + assert len(events_for_this_person) > 0 + assert len([event for _ , event in events_for_this_person if isinstance(event, HivAidsDeathEvent)]) + assert all(date >= sim.date for date, _ in + events_for_this_person), "Not all dates in the event list are after the current date" def test_generation_of_new_infection(seed): @@ -223,7 +224,7 @@ def test_generation_of_natural_history_process_no_art(seed): # run the AIDS onset event for this person: aids_event.apply(person_id) - assert "aids_symptoms" in sim.modules['SymptomManager'].has_what(person_id) + assert "aids_symptoms" in sim.modules['SymptomManager'].has_what(person_id=person_id) # find the AIDS death event for this person date_aids_death_event, aids_death_event = \ @@ -273,7 +274,7 @@ def test_generation_of_natural_history_process_with_art_before_aids(seed): assert [] == [ev for ev in sim.find_events_for_person(person_id) if isinstance(ev[1], hiv.HivAidsDeathEvent)] # check no AIDS symptoms for this person - assert "aids_symptoms" not in sim.modules['SymptomManager'].has_what(person_id) + assert "aids_symptoms" not in sim.modules['SymptomManager'].has_what(person_id=person_id) def test_generation_of_natural_history_process_with_art_after_aids(seed): @@ -311,7 +312,7 @@ def test_generation_of_natural_history_process_with_art_after_aids(seed): date_aids_death_event, aids_death_event = \ [ev for ev in sim.find_events_for_person(person_id) if isinstance(ev[1], hiv.HivAidsDeathEvent)][0] assert date_aids_death_event > sim.date - assert "aids_symptoms" in sim.modules['SymptomManager'].has_what(person_id) + assert "aids_symptoms" in sim.modules['SymptomManager'].has_what(person_id=person_id) # Put the person on ART with VL suppression prior to the AIDS death (but following AIDS onset) df.at[person_id, 'hv_art'] = "on_VL_suppressed" @@ -515,7 +516,7 @@ def test_aids_symptoms_lead_to_treatment_being_initiated(seed): aids_event.apply(person_id) # Confirm that they have aids symptoms and an AIDS death schedule - assert 'aids_symptoms' in sim.modules['SymptomManager'].has_what(person_id) + assert 'aids_symptoms' in sim.modules['SymptomManager'].has_what(person_id=person_id) assert 1 == len( [ev[0] for ev in sim.find_events_for_person(person_id) if isinstance(ev[1], hiv.HivAidsTbDeathEvent)]) diff --git a/tests/test_hiv_tb_scenarios.py b/tests/test_hiv_tb_scenarios.py deleted file mode 100644 index e872eab63f..0000000000 --- a/tests/test_hiv_tb_scenarios.py +++ /dev/null @@ -1,270 +0,0 @@ -""" Tests for setting up the HIV and TB scenarios used for projections """ - -import os -from pathlib import Path - -import pandas as pd -import pytest - -from tlo import Date, Simulation -from tlo.methods import ( - demography, - enhanced_lifestyle, - epi, - healthburden, - healthseekingbehaviour, - healthsystem, - hiv, - simplified_births, - symptommanager, - tb, -) - -try: - resourcefilepath = Path(os.path.dirname(__file__)) / '../resources' -except NameError: - # running interactively - resourcefilepath = 'resources' - - -def get_sim(seed): - """ - register all necessary modules for the tests to run - """ - - start_date = Date(2010, 1, 1) - sim = Simulation(start_date=start_date, seed=seed) - - # Register the appropriate modules - sim.register( - demography.Demography(resourcefilepath=resourcefilepath), - simplified_births.SimplifiedBirths(resourcefilepath=resourcefilepath), - enhanced_lifestyle.Lifestyle(resourcefilepath=resourcefilepath), - healthsystem.HealthSystem( - resourcefilepath=resourcefilepath, - service_availability=["*"], # all treatment allowed - mode_appt_constraints=0, # mode of constraints to do with officer numbers and time - cons_availability="all", # mode for consumable constraints (if ignored, all consumables available) - ignore_priority=True, # do not use the priority information in HSI event to schedule - capabilities_coefficient=1.0, # multiplier for the capabilities of health officers - disable=False, # disables the healthsystem (no constraints and no logging) and every HSI runs - disable_and_reject_all=False, # disable healthsystem and no HSI runs - ), - symptommanager.SymptomManager(resourcefilepath=resourcefilepath), - healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resourcefilepath), - healthburden.HealthBurden(resourcefilepath=resourcefilepath), - epi.Epi(resourcefilepath=resourcefilepath), - hiv.Hiv(resourcefilepath=resourcefilepath), - tb.Tb(resourcefilepath=resourcefilepath), - ) - - return sim - - -@pytest.mark.slow -def test_scenario_ipt_expansion(seed): - """ test scenario IPT expansion is set up correctly - should be expanded age eligibility in scenario 3 - otherwise only ages <5 are eligible - """ - - popsize = 100 - - sim = get_sim(seed=seed) - - # stop PLHIV getting IPT for purpose of tests - sim.modules['Tb'].parameters['ipt_coverage'].coverage_plhiv = 0 - # set coverage of IPT for TB contacts to 100% - sim.modules['Tb'].parameters['ipt_coverage'].coverage_paediatric = 100 - - # Make the population - sim.make_initial_population(n=popsize) - # simulate for 0 days, just get everything set up (dxtests etc) - sim.simulate(end_date=sim.date + pd.DateOffset(days=0)) - df = sim.population.props - - # check default scenario is set to 0 - assert sim.modules['Tb'].parameters['scenario'] == 0 - - # ipt eligibility should be limited to ages <=5 years - # assign all population into one district - so all are eligible as contacts - df.loc[df.is_alive, 'district_of_residence'] = 'Blantyre' - - # assign active TB to person 0 - person_id = 0 - - # assign person_id 0 active tb - df.at[person_id, 'tb_inf'] = 'active' - df.at[person_id, 'tb_strain'] = 'ds' - df.at[person_id, 'tb_date_active'] = sim.date - df.at[person_id, 'tb_smear'] = True - df.at[person_id, 'age_exact_years'] = 20 - df.at[person_id, 'age_years'] = 20 - - # assign symptoms - symptom_list = {"fever", "respiratory_symptoms", "fatigue", "night_sweats"} - sim.modules["SymptomManager"].change_symptom( - person_id=person_id, - symptom_string=symptom_list, - add_or_remove="+", - disease_module=sim.modules['Tb'], - duration_in_days=None, - ) - - # run diagnosis (HSI_Tb_ScreeningAndRefer) for person 0 - assert "tb_sputum_test_smear_positive" in sim.modules["HealthSystem"].dx_manager.dx_tests - screening_appt = tb.HSI_Tb_ScreeningAndRefer(person_id=person_id, - module=sim.modules['Tb']) - screening_appt.apply(person_id=person_id, squeeze_factor=0.0) - - assert pd.notnull(df.at[person_id, 'tb_date_tested']) - assert df.at[person_id, 'tb_diagnosed'] - - # check ages of those scheduled for HSI_Tb_Start_or_Continue_Ipt - list_of_events = list() - - for ev_tuple in sim.modules['HealthSystem'].HSI_EVENT_QUEUE: - date = ev_tuple.topen # this is the 'topen' value - event = ev_tuple.hsi_event - if isinstance(event, tb.HSI_Tb_Start_or_Continue_Ipt): - list_of_events.append((date, event, event.target)) - - idx_of_ipt_candidates = [x[2] for x in list_of_events] - ages_of_ipt_candidates = df.loc[idx_of_ipt_candidates, "age_exact_years"] - assert (ages_of_ipt_candidates < 6).all() - - -@pytest.mark.slow -def test_check_tb_test_under_each_scenario(seed): - """ test correct test is scheduled under each scenario - """ - - popsize = 10 - - sim = get_sim(seed=seed) - - # Make the population - sim.make_initial_population(n=popsize) - - sim.modules['Tb'].parameters["prop_presumptive_mdr_has_xpert"] = 1.0 # xpert always available - sim.modules['Tb'].parameters["sens_xpert"] = 1.0 # increase sensitivity of xpert testing - - # ------------------------- scenario 0 ------------------------- # - sim.modules['Tb'].parameters['scenario'] = 0 - - # simulate for 0 days, just get everything set up (dxtests etc) - sim.simulate(end_date=sim.date + pd.DateOffset(days=0)) - - df = sim.population.props - - # assign person_id active tb - hiv_neg_person = 0 - hiv_pos_person = 1 - both_people = [hiv_neg_person, hiv_pos_person] - - df.loc[both_people, 'tb_inf'] = 'active' - df.loc[both_people, 'tb_strain'] = 'ds' - df.loc[both_people, 'tb_date_active'] = sim.date - df.loc[both_people, 'tb_smear'] = True - df.loc[both_people, 'age_exact_years'] = 20 - df.loc[both_people, 'age_years'] = 20 - - # set HIV status - df.at[hiv_neg_person, 'hv_inf'] = False - df.at[hiv_pos_person, 'hv_inf'] = True - df.at[hiv_neg_person, 'hv_diagnosed'] = False # this is used for tb test selection - df.at[hiv_pos_person, 'hv_diagnosed'] = True - - # assign symptoms - symptom_list = {"fever", "respiratory_symptoms", "fatigue", "night_sweats"} - sim.modules["SymptomManager"].change_symptom( - person_id=both_people, - symptom_string=symptom_list, - add_or_remove="+", - disease_module=sim.modules['Tb'], - duration_in_days=None, - ) - - # select test for each person under baseline scenario - standard guidelines - assert "sputum" == sim.modules["Tb"].select_tb_test(hiv_neg_person) - assert "xpert" == sim.modules["Tb"].select_tb_test(hiv_pos_person) - - # screen and test hiv_neg_person - screening_appt = tb.HSI_Tb_ScreeningAndRefer(person_id=hiv_neg_person, - module=sim.modules['Tb']) - screening_appt.apply(person_id=hiv_neg_person, squeeze_factor=0.0) - - assert pd.notnull(df.at[hiv_neg_person, 'tb_date_tested']) - assert df.at[hiv_neg_person, 'tb_diagnosed'] - assert not df.at[hiv_neg_person, 'tb_diagnosed_mdr'] - - # screen and test hiv_pos_person - screening_appt = tb.HSI_Tb_ScreeningAndRefer(person_id=hiv_pos_person, - module=sim.modules['Tb']) - screening_appt.apply(person_id=hiv_pos_person, squeeze_factor=0.0) - - assert pd.notnull(df.at[hiv_pos_person, 'tb_date_tested']) - assert df.at[hiv_pos_person, 'tb_diagnosed'] - assert not df.at[hiv_pos_person, 'tb_diagnosed_mdr'] - - # apply scenario change, re-test, should be same - scenario_change_event = tb.ScenarioSetupEvent(module=sim.modules['Tb']) - scenario_change_event.apply(sim.population) - - # select test for each person under baseline scenario - standard guidelines - # this person should still qualify for sputum as they have not been treated - assert "sputum" == sim.modules["Tb"].select_tb_test(hiv_neg_person) - assert "xpert" == sim.modules["Tb"].select_tb_test(hiv_pos_person) - - # ------------------------- scenario 1 ------------------------- # - sim = get_sim(seed=seed) - - # Make the population - sim.make_initial_population(n=popsize) - - sim.modules['Tb'].parameters["prop_presumptive_mdr_has_xpert"] = 1.0 # xpert always available - sim.modules['Tb'].parameters["sens_xpert"] = 1.0 # increase sensitivity of xpert testing - sim.modules['Tb'].parameters['scenario'] = 1 - - # simulate for 0 days, just get everything set up (dxtests etc) - sim.simulate(end_date=sim.date + pd.DateOffset(days=0)) - - df = sim.population.props - - # assign person_id active tb - hiv_neg_person = 0 - hiv_pos_person = 1 - both_people = [hiv_neg_person, hiv_pos_person] - - df.loc[both_people, 'tb_inf'] = 'active' - df.loc[both_people, 'tb_strain'] = 'ds' - df.loc[both_people, 'tb_date_active'] = sim.date - df.loc[both_people, 'tb_smear'] = True - df.loc[both_people, 'age_exact_years'] = 20 - df.loc[both_people, 'age_years'] = 20 - # set HIV status - df.at[hiv_neg_person, 'hv_inf'] = False - df.at[hiv_pos_person, 'hv_inf'] = True - df.at[hiv_pos_person, 'hv_diagnosed'] = True - - # assign symptoms - symptom_list = {"fever", "respiratory_symptoms", "fatigue", "night_sweats"} - sim.modules["SymptomManager"].change_symptom( - person_id=both_people, - symptom_string=symptom_list, - add_or_remove="+", - disease_module=sim.modules['Tb'], - duration_in_days=None, - ) - - # select test for each person under scenario 1, should be standard at first - assert "sputum" == sim.modules["Tb"].select_tb_test(hiv_neg_person) - assert "xpert" == sim.modules["Tb"].select_tb_test(hiv_pos_person) - - # apply scenario change, re-test, should be xpert for all - scenario_change_event = tb.ScenarioSetupEvent(module=sim.modules['Tb']) - scenario_change_event.apply(sim.population) - - # select test for each person under changed guidelines - assert "xpert" == sim.modules["Tb"].select_tb_test(hiv_neg_person) - assert "xpert" == sim.modules["Tb"].select_tb_test(hiv_pos_person) diff --git a/tests/test_htm_scaleup.py b/tests/test_htm_scaleup.py new file mode 100644 index 0000000000..dbb2638c88 --- /dev/null +++ b/tests/test_htm_scaleup.py @@ -0,0 +1,210 @@ +""" Tests for setting up the HIV, TB and malaria scenarios used for projections """ + +import os +from pathlib import Path + +import pandas as pd + +from tlo import Date, Simulation +from tlo.methods import ( + demography, + enhanced_lifestyle, + epi, + healthburden, + healthseekingbehaviour, + healthsystem, + hiv, + malaria, + simplified_births, + symptommanager, + tb, +) + +resourcefilepath = Path(os.path.dirname(__file__)) / "../resources" + +start_date = Date(2010, 1, 1) +scaleup_start_year = 2012 # <-- the scale-up will occur on 1st January of that year +end_date = Date(2013, 1, 1) + + +def get_sim(seed): + """ + register all necessary modules for the tests to run + """ + + sim = Simulation(start_date=start_date, seed=seed) + + # Register the appropriate modules + sim.register( + demography.Demography(resourcefilepath=resourcefilepath), + simplified_births.SimplifiedBirths(resourcefilepath=resourcefilepath), + enhanced_lifestyle.Lifestyle(resourcefilepath=resourcefilepath), + healthsystem.HealthSystem(resourcefilepath=resourcefilepath), + symptommanager.SymptomManager(resourcefilepath=resourcefilepath), + healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resourcefilepath), + healthburden.HealthBurden(resourcefilepath=resourcefilepath), + epi.Epi(resourcefilepath=resourcefilepath), + hiv.Hiv(resourcefilepath=resourcefilepath), + tb.Tb(resourcefilepath=resourcefilepath), + malaria.Malaria(resourcefilepath=resourcefilepath), + ) + + return sim + + +def check_initial_params(sim): + + original_params = pd.read_excel(resourcefilepath / 'ResourceFile_HIV.xlsx', sheet_name='parameters') + + # check initial parameters + assert sim.modules["Hiv"].parameters["beta"] == \ + original_params.loc[original_params.parameter_name == "beta", "value"].values[0] + assert sim.modules["Hiv"].parameters["prob_prep_for_fsw_after_hiv_test"] == original_params.loc[ + original_params.parameter_name == "prob_prep_for_fsw_after_hiv_test", "value"].values[0] + assert sim.modules["Hiv"].parameters["prob_prep_for_agyw"] == original_params.loc[ + original_params.parameter_name == "prob_prep_for_agyw", "value"].values[0] + assert sim.modules["Hiv"].parameters["probability_of_being_retained_on_prep_every_3_months"] == original_params.loc[ + original_params.parameter_name == "probability_of_being_retained_on_prep_every_3_months", "value"].values[0] + assert sim.modules["Hiv"].parameters["prob_circ_after_hiv_test"] == original_params.loc[ + original_params.parameter_name == "prob_circ_after_hiv_test", "value"].values[0] + + +def test_hiv_scale_up(seed): + """ test hiv program scale-up changes parameters correctly + and on correct date """ + + original_params = pd.read_excel(resourcefilepath / 'ResourceFile_HIV.xlsx', sheet_name="parameters") + new_params = pd.read_excel(resourcefilepath / 'ResourceFile_HIV.xlsx', sheet_name="scaleup_parameters") + + popsize = 100 + + sim = get_sim(seed=seed) + + # check initial parameters + check_initial_params(sim) + + # update parameters to instruct there to be a scale-up + sim.modules["Hiv"].parameters["do_scaleup"] = True + sim.modules["Hiv"].parameters["scaleup_start_year"] = scaleup_start_year + + # Make the population + sim.make_initial_population(n=popsize) + sim.simulate(end_date=end_date) + + # check HIV parameters changed + assert sim.modules["Hiv"].parameters["beta"] < original_params.loc[ + original_params.parameter_name == "beta", "value"].values[0] + assert sim.modules["Hiv"].parameters["prob_prep_for_fsw_after_hiv_test"] == new_params.loc[ + new_params.parameter == "prob_prep_for_fsw_after_hiv_test", "scaleup_value"].values[0] + assert sim.modules["Hiv"].parameters["prob_prep_for_agyw"] == new_params.loc[ + new_params.parameter == "prob_prep_for_agyw", "scaleup_value"].values[0] + assert sim.modules["Hiv"].parameters["probability_of_being_retained_on_prep_every_3_months"] == new_params.loc[ + new_params.parameter == "probability_of_being_retained_on_prep_every_3_months", "scaleup_value"].values[0] + assert sim.modules["Hiv"].parameters["prob_circ_after_hiv_test"] == new_params.loc[ + new_params.parameter == "prob_circ_after_hiv_test", "scaleup_value"].values[0] + + # check malaria parameters unchanged + mal_original_params = pd.read_excel(resourcefilepath / 'malaria' / 'ResourceFile_malaria.xlsx', + sheet_name="parameters") + mal_rdt_testing = pd.read_excel(resourcefilepath / 'malaria' / 'ResourceFile_malaria.xlsx', + sheet_name="WHO_TestData2023") + + assert sim.modules["Malaria"].parameters["prob_malaria_case_tests"] == mal_original_params.loc[ + mal_original_params.parameter_name == "prob_malaria_case_tests", "value"].values[0] + pd.testing.assert_series_equal(sim.modules["Malaria"].parameters["rdt_testing_rates"]["Rate_rdt_testing"], + mal_rdt_testing["Rate_rdt_testing"]) + + # all irs coverage levels should be < 1.0 + assert sim.modules["Malaria"].itn_irs['irs_rate'].all() < 1.0 + # itn rates for 2019 onwards + assert sim.modules["Malaria"].parameters["itn"] == mal_original_params.loc[ + mal_original_params.parameter_name == "itn", "value"].values[0] + + # check tb parameters unchanged + tb_original_params = pd.read_excel(resourcefilepath / 'ResourceFile_TB.xlsx', sheet_name="parameters") + tb_testing = pd.read_excel(resourcefilepath / 'ResourceFile_TB.xlsx', sheet_name="NTP2019") + + pd.testing.assert_series_equal(sim.modules["Tb"].parameters["rate_testing_active_tb"]["treatment_coverage"], + tb_testing["treatment_coverage"]) + assert sim.modules["Tb"].parameters["prob_tx_success_ds"] == tb_original_params.loc[ + tb_original_params.parameter_name == "prob_tx_success_ds", "value"].values[0] + assert sim.modules["Tb"].parameters["prob_tx_success_mdr"] == tb_original_params.loc[ + tb_original_params.parameter_name == "prob_tx_success_mdr", "value"].values[0] + assert sim.modules["Tb"].parameters["prob_tx_success_0_4"] == tb_original_params.loc[ + tb_original_params.parameter_name == "prob_tx_success_0_4", "value"].values[0] + assert sim.modules["Tb"].parameters["prob_tx_success_5_14"] == tb_original_params.loc[ + tb_original_params.parameter_name == "prob_tx_success_5_14", "value"].values[0] + assert sim.modules["Tb"].parameters["first_line_test"] == tb_original_params.loc[ + tb_original_params.parameter_name == "first_line_test", "value"].values[0] + + +def test_htm_scale_up(seed): + """ test hiv/tb/malaria program scale-up changes parameters correctly + and on correct date """ + + # Load data on HIV prevalence + original_hiv_params = pd.read_excel(resourcefilepath / 'ResourceFile_HIV.xlsx', sheet_name="parameters") + new_hiv_params = pd.read_excel(resourcefilepath / 'ResourceFile_HIV.xlsx', sheet_name="scaleup_parameters") + + popsize = 100 + + sim = get_sim(seed=seed) + + # check initial parameters + check_initial_params(sim) + + # update parameters + sim.modules["Hiv"].parameters["do_scaleup"] = True + sim.modules["Hiv"].parameters["scaleup_start_year"] = scaleup_start_year + sim.modules["Tb"].parameters["do_scaleup"] = True + sim.modules["Tb"].parameters["scaleup_start_year"] = scaleup_start_year + sim.modules["Malaria"].parameters["do_scaleup"] = True + sim.modules["Malaria"].parameters["scaleup_start_year"] = scaleup_start_year + + # Make the population + sim.make_initial_population(n=popsize) + sim.simulate(end_date=end_date) + + # check HIV parameters changed + assert sim.modules["Hiv"].parameters["beta"] < original_hiv_params.loc[ + original_hiv_params.parameter_name == "beta", "value"].values[0] + assert sim.modules["Hiv"].parameters["prob_prep_for_fsw_after_hiv_test"] == new_hiv_params.loc[ + new_hiv_params.parameter == "prob_prep_for_fsw_after_hiv_test", "scaleup_value"].values[0] + assert sim.modules["Hiv"].parameters["prob_prep_for_agyw"] == new_hiv_params.loc[ + new_hiv_params.parameter == "prob_prep_for_agyw", "scaleup_value"].values[0] + assert sim.modules["Hiv"].parameters["probability_of_being_retained_on_prep_every_3_months"] == new_hiv_params.loc[ + new_hiv_params.parameter == "probability_of_being_retained_on_prep_every_3_months", "scaleup_value"].values[0] + assert sim.modules["Hiv"].parameters["prob_circ_after_hiv_test"] == new_hiv_params.loc[ + new_hiv_params.parameter == "prob_circ_after_hiv_test", "scaleup_value"].values[0] + + # check malaria parameters changed + new_mal_params = pd.read_excel(resourcefilepath / 'malaria' / 'ResourceFile_malaria.xlsx', + sheet_name="scaleup_parameters") + + assert sim.modules["Malaria"].parameters["prob_malaria_case_tests"] == new_mal_params.loc[ + new_mal_params.parameter == "prob_malaria_case_tests", "scaleup_value"].values[0] + assert sim.modules["Malaria"].parameters["rdt_testing_rates"]["Rate_rdt_testing"].eq(new_mal_params.loc[ + new_mal_params.parameter == "rdt_testing_rates", "scaleup_value"].values[0]).all() + + # some irs coverage levels should now = 1.0 + assert sim.modules["Malaria"].itn_irs['irs_rate'].any() == 1.0 + # itn rates for 2019 onwards + assert sim.modules["Malaria"].parameters["itn"] == new_mal_params.loc[ + new_mal_params.parameter == "itn", "scaleup_value"].values[0] + + # check tb parameters changed + new_tb_params = pd.read_excel(resourcefilepath / 'ResourceFile_TB.xlsx', sheet_name="scaleup_parameters") + + assert sim.modules["Tb"].parameters["rate_testing_active_tb"]["treatment_coverage"].eq(new_tb_params.loc[ + new_tb_params.parameter == "tb_treatment_coverage", "scaleup_value"].values[0]).all() + assert sim.modules["Tb"].parameters["prob_tx_success_ds"] == new_tb_params.loc[ + new_tb_params.parameter == "tb_prob_tx_success_ds", "scaleup_value"].values[0] + assert sim.modules["Tb"].parameters["prob_tx_success_mdr"] == new_tb_params.loc[ + new_tb_params.parameter == "tb_prob_tx_success_mdr", "scaleup_value"].values[0] + assert sim.modules["Tb"].parameters["prob_tx_success_0_4"] == new_tb_params.loc[ + new_tb_params.parameter == "tb_prob_tx_success_0_4", "scaleup_value"].values[0] + assert sim.modules["Tb"].parameters["prob_tx_success_5_14"] == new_tb_params.loc[ + new_tb_params.parameter == "tb_prob_tx_success_5_14", "scaleup_value"].values[0] + assert sim.modules["Tb"].parameters["first_line_test"] == new_tb_params.loc[ + new_tb_params.parameter == "first_line_test", "scaleup_value"].values[0] + diff --git a/tests/test_labour.py b/tests/test_labour.py index f3be99ac36..21f94c200d 100644 --- a/tests/test_labour.py +++ b/tests/test_labour.py @@ -524,7 +524,7 @@ def test_bemonc_treatments_are_delivered_correctly_with_no_cons_or_quality_const # create a dummy hsi event that the treatment functions will call from tlo.events import IndividualScopeEventMixin - from tlo.methods.healthsystem import HSI_Event + from tlo.methods.hsi_event import HSI_Event class HSI_Dummy(HSI_Event, IndividualScopeEventMixin): def __init__(self, module, person_id): diff --git a/tests/test_logging.py b/tests/test_logging.py index 4396e08abf..13151c8be5 100644 --- a/tests/test_logging.py +++ b/tests/test_logging.py @@ -137,7 +137,7 @@ def test_messages_lower_level(self, simulation_configuration, message_level): class TestConvertLogData: - def setup(self): + def setup_method(self): self.expected_output = {'item_1': 1, 'item_2': 2} self.logger = logging.getLogger('tlo.test.logger') diff --git a/tests/test_malaria.py b/tests/test_malaria.py index 822d3795f9..2b16da0000 100644 --- a/tests/test_malaria.py +++ b/tests/test_malaria.py @@ -20,7 +20,7 @@ symptommanager, tb, ) -from tlo.methods.healthsystem import HSI_Event +from tlo.methods.hsi_event import HSI_Event start_date = Date(2010, 1, 1) end_date = Date(2015, 12, 31) @@ -40,6 +40,24 @@ def check_dtypes(simulation): orig = simulation.population.new_row assert (df.dtypes == orig.dtypes).all() +# Create the HSI event that is notionally doing the call on diagnostic algorithm +class DummyHSIEvent(HSI_Event, IndividualScopeEventMixin): + def __init__(self, module, person_id): + super().__init__(module, person_id=person_id) + self.TREATMENT_ID = "DummyHSIEvent" + + the_appt_footprint = self.sim.modules[ + "HealthSystem" + ].get_blank_appt_footprint() + the_appt_footprint["Under5OPD"] = 1 # This requires one out patient + + self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint + self.ACCEPTED_FACILITY_LEVEL = "1a" + self.ALERT_OTHER_DISEASES = [] + + def apply(self, person_id, squeeze_factor): + pass + @pytest.fixture def sim(seed): @@ -108,10 +126,9 @@ def test_sims(sim): assert not df.at[person, "ma_inf_type"] == "none" # if on treatment, must have treatment start date - for person in df.index[(df.ma_tx == 'uncomplicated')]: + for person in df.index[df.ma_tx.isin(["uncomplicated", "complicated"])]: assert not pd.isnull(df.at[person, "ma_date_tx"]) - # remove scheduled rdt testing and disable health system, should be no rdts and no treatment # increase cfr for severe cases (all severe cases will die) @pytest.mark.slow @@ -192,94 +209,53 @@ def test_schedule_rdt_for_all(sim): df = sim.population.props # check no treatment unless infected - for person in df.index[(df.ma_tx == 'uncomplicated')]: + for person in df.index[df.ma_tx.isin(["uncomplicated", "complicated"])]: assert not pd.isnull(df.at[person, "ma_date_infected"]) # check clinical counter is working assert sum(df["ma_clinical_counter"]) > 0 - -def _setup_simulation_for_dx_algorithm_test(sim): +@pytest.fixture +def setup_simulation_for_dx_algorithm_test(sim): popsize = 200 # smallest population size that works sim.make_initial_population(n=popsize) sim.modules['Malaria'].parameters['sensitivity_rdt'] = 1.0 sim.simulate(end_date=start_date) - # Create the HSI event that is notionally doing the call on diagnostic algorithm - class DummyHSIEvent(HSI_Event, IndividualScopeEventMixin): - def __init__(self, module, person_id): - super().__init__(module, person_id=person_id) - self.TREATMENT_ID = 'DummyHSIEvent' - - the_appt_footprint = self.sim.modules["HealthSystem"].get_blank_appt_footprint() - the_appt_footprint["Under5OPD"] = 1 # This requires one out patient - - self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint - self.ACCEPTED_FACILITY_LEVEL = '1a' - - def apply(self, person_id, squeeze_factor): - pass - - hsi_event = DummyHSIEvent(module=sim.modules['Malaria'], person_id=0) - - # check that the queue of events is empty + # Check that the queue of events is empty assert 0 == len(sim.modules['HealthSystem'].HSI_EVENT_QUEUE) - - return sim, hsi_event + # Run wrapped test + yield -def test_dx_algorithm_for_malaria_outcomes_clinical(sim): - """ - Create a person with clinical malaria and check if the functions in - dx_algorithm_child return the correct diagnosis. - """ - # Set up the simulation: - sim, hsi_event = _setup_simulation_for_dx_algorithm_test(sim) - - # Set up the person - clinical malaria and aged <5 years: - df = sim.population.props - df.at[0, 'ma_is_infected'] = True - df.at[0, 'ma_date_infected'] = sim.date - df.at[0, 'ma_date_symptoms'] = sim.date - df.at[0, 'ma_inf_type'] = 'clinical' - - symptom_list = {"fever", "headache", "vomiting", "stomachache"} - - for symptom in symptom_list: - # no symptom resolution - sim.modules['SymptomManager'].change_symptom( - person_id=0, - symptom_string=symptom, - disease_module=sim.modules['Malaria'], - add_or_remove='+' - ) - - person_id = 0 - assert "fever" in sim.modules["SymptomManager"].has_what(person_id) - - assert sim.modules['Malaria'].check_if_fever_is_caused_by_malaria( - person_id=0, - hsi_event=hsi_event - ) == "clinical_malaria" - - -def test_dx_algorithm_for_malaria_outcomes_severe(sim): +@pytest.mark.usefixtures("setup_simulation_for_dx_algorithm_test") +@pytest.mark.parametrize( + "ma_inf_type, expected_diagnosis", + [ + pytest.param("clinical", "clinical_malaria", id="Clinical diagnosis"), + pytest.param("severe", "severe_malaria", id="Severe diagnosis"), + ], +) +def test_dx_algorithm_for_malaria_outcomes_clinical( + sim, + ma_inf_type: str, + expected_diagnosis: str, + person_id: int = 0, +): """ - Create a person with severe malaria and check if the functions in + Create a person with clinical malaria and check if the functions in dx_algorithm_child return the correct diagnosis. """ # Set up the simulation: - sim, hsi_event = _setup_simulation_for_dx_algorithm_test(sim) + hsi_event = DummyHSIEvent(module=sim.modules["Malaria"], person_id=person_id) # Set up the person - clinical malaria and aged <5 years: df = sim.population.props - person_id = 1 - df.at[person_id, 'ma_is_infected'] = True df.at[person_id, 'ma_date_infected'] = sim.date df.at[person_id, 'ma_date_symptoms'] = sim.date - df.at[person_id, 'ma_inf_type'] = 'severe' + df.at[person_id, 'ma_inf_type'] = ma_inf_type symptom_list = {"fever", "headache", "vomiting", "stomachache"} @@ -292,12 +268,21 @@ def test_dx_algorithm_for_malaria_outcomes_severe(sim): add_or_remove='+' ) - assert "fever" in sim.modules["SymptomManager"].has_what(person_id) + assert "fever" in sim.modules["SymptomManager"].has_what(person_id=person_id) + + def diagnosis_function(tests, use_dict: bool = False, report_tried: bool = False): + return hsi_event.healthcare_system.dx_manager.run_dx_test( + tests, + hsi_event=hsi_event, + use_dict_for_single=use_dict, + report_dxtest_tried=report_tried, + ) assert sim.modules['Malaria'].check_if_fever_is_caused_by_malaria( + true_malaria_infection_type = df.at[person_id, "ma_inf_type"], + diagnosis_function = diagnosis_function, person_id=person_id, - hsi_event=hsi_event - ) == "severe_malaria" + ) == expected_diagnosis # check non-malarial fever returns correct diagnosis string (and no malaria treatment) @@ -337,22 +322,6 @@ def make_blank_simulation(): sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date) - # Create the HSI event that is notionally doing the call on diagnostic algorithm - class DummyHSIEvent(HSI_Event, IndividualScopeEventMixin): - def __init__(self, module, person_id): - super().__init__(module, person_id=person_id) - self.TREATMENT_ID = 'DummyHSIEvent' - - the_appt_footprint = self.sim.modules["HealthSystem"].get_blank_appt_footprint() - the_appt_footprint["Under5OPD"] = 1 # This requires one out patient - - self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint - self.ACCEPTED_FACILITY_LEVEL = '1a' - self.ALERT_OTHER_DISEASES = [] - - def apply(self, person_id, squeeze_factor): - pass - # assume diarrhoea has created a fever (as an example of a non-malarial fever) hsi_event = DummyHSIEvent(module=sim.modules['Diarrhoea'], person_id=0) @@ -377,12 +346,26 @@ def apply(self, person_id, squeeze_factor): add_or_remove='+' ) - assert "fever" in sim.modules["SymptomManager"].has_what(person_id) + assert "fever" in sim.modules["SymptomManager"].has_what(person_id=person_id) - assert sim.modules['Malaria'].check_if_fever_is_caused_by_malaria( - person_id=0, - hsi_event=hsi_event - ) == "negative_malaria_test" + def diagnosis_function(tests, use_dict: bool = False, report_tried: bool = False): + return hsi_event.healthcare_system.dx_manager.run_dx_test( + tests, + hsi_event=hsi_event, + use_dict_for_single=use_dict, + report_dxtest_tried=report_tried, + ) + + assert ( + sim.modules["Malaria"].check_if_fever_is_caused_by_malaria( + true_malaria_infection_type=sim.population.props.at[ + person_id, "ma_inf_type" + ], + diagnosis_function=diagnosis_function, + person_id=person_id, + ) + == "negative_malaria_test" + ) def test_severe_malaria_deaths_perfect_treatment(sim): @@ -405,7 +388,7 @@ def test_severe_malaria_deaths_perfect_treatment(sim): treatment_appt = malaria.HSI_Malaria_Treatment_Complicated(person_id=person_id, module=sim.modules['Malaria']) treatment_appt.apply(person_id=person_id, squeeze_factor=0.0) - assert df.at[person_id, 'ma_tx'] == 'complicated' + assert df.at[person_id, "ma_tx"] != "none" assert df.at[person_id, "ma_date_tx"] == sim.date assert df.at[person_id, "ma_tx_counter"] > 0 @@ -440,7 +423,7 @@ def test_severe_malaria_deaths_treatment_failure(sim): treatment_appt = malaria.HSI_Malaria_Treatment_Complicated(person_id=person_id, module=sim.modules['Malaria']) treatment_appt.apply(person_id=person_id, squeeze_factor=0.0) - assert df.at[person_id, 'ma_tx'] == 'complicated' + assert df.at[person_id, 'ma_tx'] != 'none' assert df.at[person_id, "ma_date_tx"] == sim.date assert df.at[person_id, "ma_tx_counter"] > 0 @@ -459,7 +442,7 @@ def test_severe_malaria_deaths_treatment_failure(sim): person_id = 1 df.loc[person_id, ["ma_is_infected", "ma_inf_type"]] = (True, "severe") - assert not df.at[person_id, 'ma_tx'] == 'complicated' + assert df.at[person_id, "ma_tx"] == "none" assert df.at[person_id, "ma_date_tx"] is pd.NaT assert df.at[person_id, "ma_tx_counter"] == 0 @@ -534,7 +517,7 @@ def test_individual_testing_and_treatment(sim): pollevent.run() assert not pd.isnull(df.at[person_id, "ma_date_symptoms"]) - assert set(sim.modules['SymptomManager'].has_what(person_id)) == {"fever", "headache", "vomiting", "stomachache"} + assert set(sim.modules['SymptomManager'].has_what(person_id=person_id)) == {"fever", "headache", "vomiting", "stomachache"} # check rdt is scheduled date_event, event = [ @@ -577,7 +560,7 @@ def test_individual_testing_and_treatment(sim): pollevent = malaria.MalariaUpdateEvent(module=sim.modules['Malaria']) pollevent.apply(sim.population) - assert sim.modules['SymptomManager'].has_what(person_id) == [] + assert sim.modules['SymptomManager'].has_what(person_id=person_id) == [] # check no rdt is scheduled assert "malaria.HSI_Malaria_rdt" not in sim.modules['HealthSystem'].find_events_for_person(person_id) @@ -651,7 +634,7 @@ def test_individual_testing_and_treatment(sim): tx_appt.apply(person_id=person_id, squeeze_factor=0.0) assert df.at[person_id, "ma_tx_counter"] == 1 - assert df.at[person_id, "ma_tx"] == 'complicated' + assert df.at[person_id, "ma_tx"] != "none" def test_population_testing_and_treatment(sim): diff --git a/tests/test_maternal_health_helper_and_analysis_functions.py b/tests/test_maternal_health_helper_and_analysis_functions.py index 4c55c3a366..daea95a5e6 100644 --- a/tests/test_maternal_health_helper_and_analysis_functions.py +++ b/tests/test_maternal_health_helper_and_analysis_functions.py @@ -11,7 +11,7 @@ pregnancy_helper_functions, ) from tlo.methods.fullmodel import fullmodel -from tlo.methods.healthsystem import FacilityInfo +from tlo.methods.hsi_event import FacilityInfo start_date = Date(2010, 1, 1) @@ -26,7 +26,7 @@ def get_dummy_hsi(sim, mother_id, id, fl): """create dummy HSI to test that consumables truly are unavailable when using standard method""" from tlo.events import IndividualScopeEventMixin - from tlo.methods.healthsystem import HSI_Event + from tlo.methods.hsi_event import HSI_Event class HSI_Dummy(HSI_Event, IndividualScopeEventMixin): def __init__(self, module, person_id): @@ -258,9 +258,9 @@ def test_analysis_events_force_availability_of_consumables_when_scheduled_in_anc syph_test = module.item_codes_preg_consumables['syphilis_test'] syph_treat = module.item_codes_preg_consumables['syphilis_treatment'] - for cons in iron, protein, calcium, syph_test, syph_treat: - sim.modules['HealthSystem'].override_availability_of_consumables( - {cons[0]: 0.0}) + for cons in 'iron_folic_acid', 'balanced_energy_protein', 'calcium', 'syphilis_test', 'syphilis_treatment': + updated_cons = {k: v * 0 for (k, v) in module.item_codes_preg_consumables[cons].items()} + sim.modules['HealthSystem'].override_availability_of_consumables(updated_cons) # refresh the consumables sim.modules['HealthSystem'].consumables._refresh_availability_of_consumables(date=sim.date) @@ -625,7 +625,7 @@ def test_analysis_events_circumnavigates_sf_and_competency_parameters(seed): params['prob_successful_assisted_vaginal_delivery'] = 1.0 # Next define the actual HSI of interest - from tlo.methods.healthsystem import FacilityInfo + from tlo.methods.hsi_event import FacilityInfo # run the event and check the interventions were delivered as expected sba = labour.HSI_Labour_ReceivesSkilledBirthAttendanceDuringLabour( diff --git a/tests/test_module_dependencies.py b/tests/test_module_dependencies.py index fd61bb40be..ca5bf58482 100644 --- a/tests/test_module_dependencies.py +++ b/tests/test_module_dependencies.py @@ -30,7 +30,11 @@ module_class_map = get_module_class_map( - excluded_modules={'Module', 'Skeleton', 'SimplifiedPregnancyAndLabour'} + excluded_modules={ + "Module", + "Skeleton", + "SimplifiedPregnancyAndLabour", + } ) diff --git a/tests/test_population.py b/tests/test_population.py new file mode 100644 index 0000000000..e8a549209d --- /dev/null +++ b/tests/test_population.py @@ -0,0 +1,216 @@ +import numpy as np +import pandas as pd +import pytest + +from tlo.core import Property, Types +from tlo.population import Population + + +@pytest.fixture +def properties(): + return { + f"{type_.name.lower()}_{i}": Property(type_, f"Column {i} of type {type_}") + for type_ in [Types.INT, Types.BOOL, Types.REAL, Types.DATE, Types.BITSET] + for i in range(5) + } + + +@pytest.fixture(params=[1, 100, 1000]) +def initial_size(request): + return request.param + + +@pytest.fixture(params=[None, 0.02, 0.1]) +def append_size(request, initial_size): + return ( + request.param + if request.param is None + else max(int(initial_size * request.param), 1) + ) + + +@pytest.fixture +def population(properties, initial_size, append_size): + return Population(properties, initial_size, append_size) + + +@pytest.fixture +def rng(seed): + return np.random.RandomState(seed % 2**32) + + +def _generate_random_values(property, rng, size=None): + if property.type_ == Types.DATE: + return np.datetime64("2010-01-01") + rng.randint(0, 4000, size=size) + elif property.type_ in (Types.INT, Types.BITSET): + return rng.randint(low=0, high=100, size=size) + elif property.type_ == Types.REAL: + return rng.standard_normal(size=size) + elif property.type_ == Types.BOOL: + return rng.uniform(size=size) < 0.5 + else: + msg = f"Unhandled type {property.type_}" + raise ValueError(msg) + + +@pytest.fixture +def population_with_random_property_values(population, properties, initial_size, rng): + + for name, property in properties.items(): + population.props[name] = pd.Series( + _generate_random_values(property, rng, initial_size), + dtype=property.pandas_type, + ) + + return population + + +def test_population_invalid_append_size_raises(properties, initial_size): + with pytest.raises(AssertionError, match="greater than 0"): + Population(properties, initial_size, append_size=-1) + + +def test_population_attributes(population, properties, initial_size, append_size): + assert population.initial_size == initial_size + assert population.next_person_id == initial_size + if append_size is not None: + assert len(population.new_rows) == append_size + else: + assert 0 < len(population.new_rows) <= initial_size + assert len(population.props.index) == initial_size + assert len(population.props.columns) == len(properties) + assert set(population.props.columns) == properties.keys() + assert all( + properties[name].pandas_type == col.dtype + for name, col in population.props.items() + ) + + +def test_population_do_birth(population): + initial_population_props_copy = population.props.copy() + initial_size = population.initial_size + append_size = len(population.new_rows) + + def check_population(population, birth_number): + expected_next_person_id = initial_size + birth_number + # population size should increase by append_size on first birth and after + # every subsequent append_size births by a further append_size + expected_size = ( + initial_size + ((birth_number - 1) // append_size + 1) * append_size + ) + assert all(initial_population_props_copy.columns == population.props.columns) + assert all(initial_population_props_copy.dtypes == population.props.dtypes) + assert population.next_person_id == expected_next_person_id + assert len(population.props.index) == expected_size + + for birth_number in range(1, append_size + 2): + population.do_birth() + check_population(population, birth_number) + + +def test_population_individual_properties_read_only_write_raises( + population, properties +): + with population.individual_properties( + person_id=0, read_only=True + ) as individual_properties: + for property_name in properties: + with pytest.raises(ValueError, match="read-only"): + individual_properties[property_name] = 0 + + +@pytest.mark.parametrize("read_only", [True, False]) +@pytest.mark.parametrize("person_id", [0, 1, -1]) +def test_population_individual_properties_read( + population_with_random_property_values, properties, rng, read_only, person_id +): + person_id = person_id % population_with_random_property_values.initial_size + population_dataframe = population_with_random_property_values.props + with population_with_random_property_values.individual_properties( + person_id=person_id, read_only=read_only + ) as individual_properties: + for property_name in properties: + assert ( + individual_properties[property_name] + == population_dataframe.at[person_id, property_name] + ) + # Try reading all properties (in a new random order) a second time to check any + # caching mechanism is working as expected + shuffled_property_names = list(properties.keys()) + rng.shuffle(shuffled_property_names) + for property_name in shuffled_property_names: + assert ( + individual_properties[property_name] + == population_dataframe.at[person_id, property_name] + ) + + +@pytest.mark.parametrize("read_only", [True, False]) +@pytest.mark.parametrize("person_id", [0, 1, -1]) +def test_population_individual_properties_access_raises_when_finalized( + population_with_random_property_values, properties, rng, read_only, person_id +): + person_id = person_id % population_with_random_property_values.initial_size + with population_with_random_property_values.individual_properties( + person_id=person_id, read_only=read_only + ) as individual_properties: + pass + for property_name in properties: + with pytest.raises(ValueError, match="finalized"): + individual_properties[property_name] + with pytest.raises(ValueError, match="finalized"): + individual_properties[property_name] = None + + +@pytest.mark.parametrize("person_id", [0, 1, -1]) +def test_population_individual_properties_write_with_context_manager( + population_with_random_property_values, properties, rng, person_id +): + initial_population_dataframe = population_with_random_property_values.props.copy() + person_id = person_id % population_with_random_property_values.initial_size + updated_values = {} + with population_with_random_property_values.individual_properties( + person_id=person_id, read_only=False + ) as individual_properties: + for property_name, property in properties.items(): + updated_values[property_name] = _generate_random_values(property, rng) + individual_properties[property_name] = updated_values[property_name] + # Population dataframe should see updated properties for person_id row + for property_name, property in properties.items(): + assert ( + population_with_random_property_values.props.at[person_id, property_name] + == updated_values[property_name] + ) + # All other rows in population dataframe should be unchanged + all_rows_except_updated = ~initial_population_dataframe.index.isin([person_id]) + assert population_with_random_property_values.props[all_rows_except_updated].equals( + initial_population_dataframe[all_rows_except_updated] + ) + + +@pytest.mark.parametrize("person_id", [0, 1, -1]) +def test_population_individual_properties_write_with_sync( + population_with_random_property_values, properties, rng, person_id +): + initial_population_dataframe = population_with_random_property_values.props.copy() + person_id = person_id % population_with_random_property_values.initial_size + updated_values = {} + with population_with_random_property_values.individual_properties( + person_id=person_id, read_only=False + ) as individual_properties: + for property_name, property in properties.items(): + updated_values[property_name] = _generate_random_values(property, rng) + individual_properties[property_name] = updated_values[property_name] + # Before synchronization all values in population dataframe should be unchanged + assert initial_population_dataframe.equals( + population_with_random_property_values.props + ) + individual_properties.synchronize_updates_to_dataframe() + # After synchronization all values in population dataframe should be updated + for property_name, property in properties.items(): + assert ( + population_with_random_property_values.props.at[ + person_id, property_name + ] + == updated_values[property_name] + ) diff --git a/tests/test_rti.py b/tests/test_rti.py index 0e231fb4af..3075d5f70b 100644 --- a/tests/test_rti.py +++ b/tests/test_rti.py @@ -91,7 +91,9 @@ def test_all_injuries_run(seed): assert "none" not in sim.population.props['rt_injury_1'].unique() assert not sim.population.props['rt_injury_1'].str.contains('P').any() # Assign people the emergency care triggering symptom so they enter the health system - sim.population.props['sy_severe_trauma'] = 2 + sim.modules["SymptomManager"].change_symptom( + sim.population.props.index, "severe_trauma", "+", sim.modules["RTI"] + ) # Assign an injury date sim.population.props['rt_date_inj'] = sim.start_date # Show that they have been injured @@ -160,7 +162,9 @@ def test_all_injuries_run_no_healthsystem(seed): assert "none" not in sim.population.props['rt_injury_1'].unique() assert not sim.population.props['rt_injury_1'].str.contains('P').any() # Assign people the emergency care triggering symptom so they enter the health system - sim.population.props['sy_severe_trauma'] = 2 + sim.modules["SymptomManager"].change_symptom( + sim.population.props.index, "severe_trauma", "+", sim.modules["RTI"] + ) # Assign an injury date sim.population.props['rt_date_inj'] = sim.start_date # Show that they have been injured diff --git a/tests/test_scenario.py b/tests/test_scenario.py new file mode 100644 index 0000000000..1feac8ef87 --- /dev/null +++ b/tests/test_scenario.py @@ -0,0 +1,68 @@ +import json +import os +from pathlib import Path + +import pytest + +from tlo.scenario import BaseScenario, SampleRunner, ScenarioLoader + + +@pytest.fixture +def scenario_path(): + return Path(f'{os.path.dirname(__file__)}/resources/scenario.py') + + +@pytest.fixture +def pop_size(): + return 100 + + +@pytest.fixture +def loaded_scenario(scenario_path): + return ScenarioLoader(scenario_path).get_scenario() + + +@pytest.fixture +def arguments(pop_size): + return ['--pop-size', str(pop_size)] + + +@pytest.fixture +def loaded_scenario_with_parsed_arguments(loaded_scenario, arguments): + loaded_scenario.parse_arguments(arguments) + return loaded_scenario + + +def test_load(loaded_scenario, scenario_path): + """Check we can load the scenario class from a file""" + assert isinstance(loaded_scenario, BaseScenario) + assert loaded_scenario.scenario_path == scenario_path + assert hasattr(loaded_scenario, "pop_size") # Default value set in initialiser + + +def test_parse_arguments(loaded_scenario_with_parsed_arguments, pop_size): + """Check we can parse arguments related to the scenario. pop-size is used by our scenario, + suspend-date is used in base class""" + assert loaded_scenario_with_parsed_arguments.pop_size == pop_size + + +def test_config(tmp_path, loaded_scenario_with_parsed_arguments, arguments): + """Create the run configuration and check we've got the right values in there.""" + config = loaded_scenario_with_parsed_arguments.save_draws(return_config=True) + assert config['scenario_seed'] == loaded_scenario_with_parsed_arguments.seed + assert config['arguments'] == arguments + assert len(config['draws']) == loaded_scenario_with_parsed_arguments.number_of_draws + + +def test_runner(tmp_path, loaded_scenario_with_parsed_arguments, pop_size): + """Check we can load the scenario from a configuration file.""" + config = loaded_scenario_with_parsed_arguments.save_draws(return_config=True) + config_path = tmp_path / 'scenario.json' + with open(config_path, 'w') as f: + f.write(json.dumps(config, indent=2)) + runner = SampleRunner(config_path) + scenario = runner.scenario + assert isinstance(scenario, BaseScenario) + assert scenario.__class__.__name__ == 'TestScenario' + assert scenario.pop_size == pop_size + assert runner.number_of_draws == loaded_scenario_with_parsed_arguments.number_of_draws diff --git a/tests/test_stunting.py b/tests/test_stunting.py index bee11bd54d..f41bab7c78 100644 --- a/tests/test_stunting.py +++ b/tests/test_stunting.py @@ -222,7 +222,7 @@ def test_polling_event_progression(seed): def test_routine_assessment_for_chronic_undernutrition_if_stunted_and_correctly_diagnosed(seed): - """Check that a call to `do_routine_assessment_for_chronic_undernutrition` can lead to immediate recovery for a + """Check that a call to `do_at_generic_first_appt` can lead to immediate recovery for a stunted child (via an HSI), if there is checking and correct diagnosis.""" popsize = 100 sim = get_sim(seed) @@ -234,18 +234,23 @@ def test_routine_assessment_for_chronic_undernutrition_if_stunted_and_correctly_ df = sim.population.props person_id = 0 df.loc[person_id, 'age_years'] = 2 - df.loc[person_id, 'age_exact_year'] = 2.0 - df.loc[person_id, 'un_HAZ_category'] = '-3<=HAZ<-2' + df.loc[person_id, "un_HAZ_category"] = "-3<=HAZ<-2" # Make the probability of stunting checking/diagnosis as 1.0 sim.modules['Stunting'].parameters['prob_stunting_diagnosed_at_generic_appt'] = 1.0 - # Subject the person to `do_routine_assessment_for_chronic_undernutrition` - sim.modules['Stunting'].do_routine_assessment_for_chronic_undernutrition(person_id=person_id) + with sim.population.individual_properties(person_id) as individual_properties: + # Subject the person to `do_at_generic_first_appt` + sim.modules["Stunting"].do_at_generic_first_appt( + person_id=person_id, + individual_properties=individual_properties, + schedule_hsi_event=sim.modules["HealthSystem"].schedule_hsi_event, + ) # Check that there is an HSI scheduled for this person hsi_event_scheduled = [ - ev for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) + ev + for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) if isinstance(ev[1], HSI_Stunting_ComplementaryFeeding) ] assert 1 == len(hsi_event_scheduled) @@ -264,14 +269,15 @@ def test_routine_assessment_for_chronic_undernutrition_if_stunted_and_correctly_ # Check that the person is not longer stunted assert df.at[person_id, 'un_HAZ_category'] == 'HAZ>=-2' - # Check that there is a follow-up appointment scheduled hsi_event_scheduled_after_first_appt = [ ev for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], HSI_Stunting_ComplementaryFeeding) ] assert 2 == len(hsi_event_scheduled_after_first_appt) - assert (sim.date + pd.DateOffset(months=6)) == hsi_event_scheduled_after_first_appt[1][0] + assert (sim.date + pd.DateOffset(months=6)) == hsi_event_scheduled_after_first_appt[ + 1 + ][0] the_follow_up_hsi_event = hsi_event_scheduled_after_first_appt[1][1] # Run the Follow-up HSI event @@ -285,7 +291,7 @@ def test_routine_assessment_for_chronic_undernutrition_if_stunted_and_correctly_ def test_routine_assessment_for_chronic_undernutrition_if_stunted_but_no_checking(seed): - """Check that a call to `do_routine_assessment_for_chronic_undernutrition` does not lead to an HSI for a stunted + """Check that a call to `do_at_generic_first_appt` does not lead to an HSI for a stunted child, if there is no checking/diagnosis.""" popsize = 100 sim = get_sim(seed) @@ -297,30 +303,46 @@ def test_routine_assessment_for_chronic_undernutrition_if_stunted_but_no_checkin df = sim.population.props person_id = 0 df.loc[person_id, 'age_years'] = 2 - df.loc[person_id, 'age_exact_year'] = 2.0 - df.loc[person_id, 'un_HAZ_category'] = 'HAZ<-3' + df.loc[person_id, "un_HAZ_category"] = "HAZ<-3" # Make the probability of stunting checking/diagnosis as 0.0 sim.modules['Stunting'].parameters['prob_stunting_diagnosed_at_generic_appt'] = 0.0 - # Subject the person to `do_routine_assessment_for_chronic_undernutrition` - sim.modules['Stunting'].do_routine_assessment_for_chronic_undernutrition(person_id=person_id) + with sim.population.individual_properties(person_id) as individual_properties: + # Subject the person to `do_at_generic_first_appt` + sim.modules['Stunting'].do_at_generic_first_appt( + person_id=person_id, + individual_properties=individual_properties, + schedule_hsi_event=sim.modules["HealthSystem"].schedule_hsi_event, + ) # Check that there is no HSI scheduled for this person - hsi_event_scheduled = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], HSI_Stunting_ComplementaryFeeding)] + hsi_event_scheduled = [ + ev[1] + for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) + if isinstance(ev[1], HSI_Stunting_ComplementaryFeeding) + ] assert 0 == len(hsi_event_scheduled) - # Then make the probability of stunting checking/diagnosis as 1.0 and check the HSI is scheduled for this person - sim.modules['Stunting'].parameters['prob_stunting_diagnosed_at_generic_appt'] = 1.0 - sim.modules['Stunting'].do_routine_assessment_for_chronic_undernutrition(person_id=person_id) - hsi_event_scheduled = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], HSI_Stunting_ComplementaryFeeding)] + # Then make the probability of stunting checking/diagnosis 1.0 + # and check the HSI is scheduled for this person + sim.modules['Stunting'].parameters["prob_stunting_diagnosed_at_generic_appt"] = 1.0 + with sim.population.individual_properties(person_id) as individual_properties: + sim.modules['Stunting'].do_at_generic_first_appt( + person_id=person_id, + individual_properties=individual_properties, + schedule_hsi_event=sim.modules["HealthSystem"].schedule_hsi_event, + ) + hsi_event_scheduled = [ + ev[1] + for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) + if isinstance(ev[1], HSI_Stunting_ComplementaryFeeding) + ] assert 1 == len(hsi_event_scheduled) def test_routine_assessment_for_chronic_undernutrition_if_not_stunted(seed): - """Check that a call to `do_routine_assessment_for_chronic_undernutrition` does not lead to an HSI if there is no + """Check that a call to `do_at_generic_first_appt` does not lead to an HSI if there is no stunting.""" popsize = 100 sim = get_sim(seed) @@ -332,15 +354,21 @@ def test_routine_assessment_for_chronic_undernutrition_if_not_stunted(seed): df = sim.population.props person_id = 0 df.loc[person_id, 'age_years'] = 2 - df.loc[person_id, 'age_exact_year'] = 2.0 df.loc[person_id, 'un_HAZ_category'] = 'HAZ>=-2' - - # Subject the person to `do_routine_assessment_for_chronic_undernutrition` - sim.modules['Stunting'].do_routine_assessment_for_chronic_undernutrition(person_id=person_id) + with sim.population.individual_properties(person_id) as individual_properties: + # Subject the person to `do_at_generic_first_appt` + sim.modules["Stunting"].do_at_generic_first_appt( + person_id=person_id, + individual_properties=individual_properties, + schedule_hsi_event=sim.modules["HealthSystem"].schedule_hsi_event, + ) # Check that there is no HSI scheduled for this person - hsi_event_scheduled = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], HSI_Stunting_ComplementaryFeeding)] + hsi_event_scheduled = [ + ev[1] + for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) + if isinstance(ev[1], HSI_Stunting_ComplementaryFeeding) + ] assert 0 == len(hsi_event_scheduled) diff --git a/tests/test_symptommanager.py b/tests/test_symptommanager.py index 85c7156902..73ea7619d0 100644 --- a/tests/test_symptommanager.py +++ b/tests/test_symptommanager.py @@ -1,5 +1,8 @@ +from __future__ import annotations + import os from pathlib import Path +from typing import TYPE_CHECKING, List import pytest from pandas import DateOffset @@ -24,6 +27,9 @@ SymptomManager_SpuriousSymptomOnset, ) +if TYPE_CHECKING: + from tlo.methods.symptommanager import SymptomManager + try: resourcefilepath = Path(os.path.dirname(__file__)) / '../resources' except NameError: @@ -187,8 +193,9 @@ def test_adding_quering_and_removing_symptoms(seed): assert set(has_symp) == set(ids) for person_id in ids: - assert symp in sim.modules['SymptomManager'].has_what(person_id=person_id, - disease_module=sim.modules['Mockitis']) + assert symp in sim.modules["SymptomManager"].has_what( + person_id=person_id, disease_module=sim.modules["Mockitis"] + ) # Check cause of the symptom: for person in ids: @@ -203,6 +210,103 @@ def test_adding_quering_and_removing_symptoms(seed): assert list() == sim.modules['SymptomManager'].who_has(symp) +@pytest.mark.parametrize( + "supply_disease_module", + [ + pytest.param(False, id="disease_module kwarg NOT supplied"), + pytest.param(True, id="disease_module kwarg supplied"), + ], +) +def test_has_what_via_individual_properties(seed, supply_disease_module: bool): + """ + Test that the has_what method returns the same symptoms for an individual + when supplied a person_id and the individual_properties context for that + same person. + + Test the case when the optional disease_module kwarg is supplied as well. + + We will create 3 'dummy' symptoms and select 8 individuals in the + population to infect with these symptoms; in the following combinations: + + id has_symp1 has_symp2 has_symp3 + 0 1 1 1 + 1 1 1 0 + 2 1 0 1 + 3 1 0 0 + 4 0 1 1 + 5 0 1 0 + 6 0 0 1 + 7 0 0 0 + + We will then assert that has_what returns the expected symptoms for the + individuals, and that supplying either the person_id keyword or the + individual_properties keyword gives the same answer. + """ + sim = Simulation(start_date=start_date, seed=seed) + sim.register( + demography.Demography(resourcefilepath=resourcefilepath), + enhanced_lifestyle.Lifestyle(resourcefilepath=resourcefilepath), + healthsystem.HealthSystem(resourcefilepath=resourcefilepath, disable=True), + symptommanager.SymptomManager(resourcefilepath=resourcefilepath), + healthseekingbehaviour.HealthSeekingBehaviour( + resourcefilepath=resourcefilepath + ), + simplified_births.SimplifiedBirths(resourcefilepath=resourcefilepath), + mockitis.Mockitis(), + chronicsyndrome.ChronicSyndrome(), + ) + disease_module: mockitis.Mockitis = sim.modules["Mockitis"] + symptom_manager: SymptomManager = sim.modules["SymptomManager"] + + # Generate the symptoms and select the people to infect + n_symptoms = 3 + n_patients = 2 ** n_symptoms + symptoms = [f"test_symptom{i}" for i in range(n_symptoms)] + symptom_manager.register_symptom(*[Symptom(name=symptom) for symptom in symptoms]) + + # Create the initial population after generating extra symptoms, so that they are registered + sim.make_initial_population(n=popsize) + df = sim.population.props + + # Infect the people with the corresponding symptoms + persons_infected_with: List[int] = [ + id for id in sim.rng.choice(list(df.index[df.is_alive]), n_patients) + ] + for i, id in enumerate(persons_infected_with): + bin_rep = format(i, f"0{n_symptoms}b") + for symptom_number, digit in enumerate(bin_rep): + if digit == "1": + symptom_manager.change_symptom( + symptom_string=symptoms[symptom_number], + person_id=[id], + add_or_remove="+", + disease_module=disease_module, + ) + + # Now check that has_what returns the same (correct!) arguments when supplied with + # individual_properties and person_id. + for person_id in persons_infected_with: + symptoms_via_pid = symptom_manager.has_what( + person_id=person_id, + disease_module=disease_module if supply_disease_module else None, + ) + with sim.population.individual_properties( + person_id, read_only=True + ) as individual_properties: + symptoms_via_iprops = symptom_manager.has_what( + individual_details=individual_properties, + disease_module=disease_module if supply_disease_module else None, + ) + + # Assert all returned symptoms are in agreement + assert len(symptoms_via_pid) == len( + symptoms_via_iprops + ), "Method does not return same number of symptoms." + assert set(symptoms_via_pid) == set( + symptoms_via_iprops + ), "Method does not return the same symptoms" + + def test_baby_born_has_no_symptoms(seed): sim = Simulation(start_date=start_date, seed=seed) @@ -227,7 +331,7 @@ def test_baby_born_has_no_symptoms(seed): person_id = sim.do_birth(mother_id) # check that the new person does not have symptoms: - assert [] == sim.modules['SymptomManager'].has_what(person_id) + assert [] == sim.modules['SymptomManager'].has_what(person_id=person_id) def test_auto_onset_symptom(seed): @@ -250,7 +354,7 @@ def test_auto_onset_symptom(seed): sim.population.props.loc[person_id, 'is_alive'] = True for symptom in sm.symptom_names: sim.population.props.loc[person_id, sm.get_column_name_for_symptom(symptom)] = 0 - assert 0 == len(sm.has_what(person_id)) + assert 0 == len(sm.has_what(person_id=person_id)) def get_events_in_sim(): return [ev for ev in sim.event_queue.queue if (person_id in ev[3].person_id)] @@ -273,7 +377,7 @@ def get_events_in_sim(): ) # check that the symptom is not imposed - assert 0 == len(sm.has_what(person_id)) + assert 0 == len(sm.has_what(person_id=person_id)) # get the future events for this person (should be just the auto-onset event) assert 1 == len(get_events_in_sim()) @@ -285,7 +389,7 @@ def get_events_in_sim(): # run the events and check for the changing of symptoms sim.date = date_of_onset onset[3].apply(sim.population) - assert symptom_string in sm.has_what(person_id) + assert symptom_string in sm.has_what(person_id=person_id) # get the future events for this person (should now include the auto-resolve event) assert 2 == len(get_events_in_sim()) @@ -295,7 +399,7 @@ def get_events_in_sim(): assert isinstance(resolve[3], SymptomManager_AutoResolveEvent) resolve[3].apply(sim.population) - assert 0 == len(sm.has_what(person_id)) + assert 0 == len(sm.has_what(person_id=person_id)) def test_nonemergency_spurious_symptoms_during_simulation(seed): @@ -504,13 +608,26 @@ def test_has_what( df.is_alive & (df[symptom_manager.get_column_name_for_symptom(symptom)] > 0) ][0] - assert symptom in symptom_manager.has_what(person_with_symptom) + assert symptom in symptom_manager.has_what(person_id=person_with_symptom) person_without_symptom = df.index[ df.is_alive & (df[symptom_manager.get_column_name_for_symptom(symptom)] == 0) ][0] - assert symptom not in symptom_manager.has_what(person_without_symptom) - + assert symptom not in symptom_manager.has_what(person_id=person_without_symptom) + + # Do the same checks but using an IndividualDetails context + with simulation.population.individual_properties( + person_with_symptom, read_only=True + ) as with_symptom_properties: + assert symptom in symptom_manager.has_what( + individual_details=with_symptom_properties + ) + with simulation.population.individual_properties( + person_without_symptom, read_only=True + ) as without_symptom_properties: + assert symptom not in symptom_manager.has_what( + individual_details=without_symptom_properties + ) def test_has_what_disease_module( symptom_manager, disease_module, disease_module_symptoms, simulation @@ -522,12 +639,16 @@ def test_has_what_disease_module( df.is_alive & (df[symptom_manager.get_column_name_for_symptom(symptom)] > 0) ][0] - assert symptom in symptom_manager.has_what(person_with_symptom, disease_module) + assert symptom in symptom_manager.has_what( + person_id=person_with_symptom, disease_module=disease_module + ) person_without_symptom = df.index[ df.is_alive & (df[symptom_manager.get_column_name_for_symptom(symptom)] == 0) ][0] - assert symptom not in symptom_manager.has_what(person_without_symptom, disease_module) + assert symptom not in symptom_manager.has_what( + person_id=person_without_symptom, disease_module=disease_module + ) def test_have_what( diff --git a/tests/test_tb.py b/tests/test_tb.py index 5c2943b310..66d5abd60e 100644 --- a/tests/test_tb.py +++ b/tests/test_tb.py @@ -431,8 +431,8 @@ def get_appt_footprints(_consumables_availability): def test_treatment_failure(seed): """ - test treatment failure occurs and - retreatment properties / follow-up occurs correctly + test treatment failure occurs and properties set correctly + treatment failure will schedule referral for xpert test at level 2 """ popsize = 10 @@ -504,26 +504,30 @@ def test_treatment_failure(seed): # check referral for screening/testing again # screen and test person_id screening_appt = tb.HSI_Tb_ScreeningAndRefer(person_id=person_id, - module=sim.modules['Tb']) + module=sim.modules['Tb'], + facility_level="1a") test = screening_appt.apply(person_id=person_id, squeeze_factor=0.0) - # should schedule xpert - if available - # check that the event returned a footprint for an xpert test + # should schedule a referral for xpert testing at facility level 2 + # check that the event returned a footprint Over5OPD assert test == screening_appt.make_appt_footprint({'Over5OPD': 1}) - # start treatment - tx_start = tb.HSI_Tb_StartTreatment(person_id=person_id, - module=sim.modules['Tb']) - tx_start.apply(person_id=person_id, squeeze_factor=0.0) - - # clinical monitoring - # check tb.HSI_Tb_FollowUp scheduled - followup_event = [ + # check tb.HSI_Tb_ScreeningAndRefer scheduled + followup_test = [ ev for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], tb.HSI_Tb_FollowUp) + isinstance(ev[1], tb.HSI_Tb_ScreeningAndRefer) ][-1] - assert followup_event[0] > sim.date + assert followup_test[0] > sim.date + + # schedule follow-up test at level 2 to get xpert + screening_appt = tb.HSI_Tb_ScreeningAndRefer(person_id=person_id, + module=sim.modules['Tb'], + facility_level="2") + test = screening_appt.apply(person_id=person_id, squeeze_factor=0.0) + + # assert now should be diagnosed as active TB again + assert df.at[person_id, 'tb_diagnosed'] def test_children_referrals(seed): @@ -572,7 +576,7 @@ def test_children_referrals(seed): duration_in_days=None, ) - assert set(sim.modules['SymptomManager'].has_what(person_id)) == symptom_list + assert set(sim.modules['SymptomManager'].has_what(person_id=person_id)) == symptom_list # run HSI_Tb_ScreeningAndRefer and check outcomes sim.modules['HealthSystem'].schedule_hsi_event( @@ -783,7 +787,8 @@ def test_mdr(seed): # next screening should pick up case as retreatment / mdr screening_appt = tb.HSI_Tb_ScreeningAndRefer(person_id=person_id, - module=sim.modules['Tb']) + module=sim.modules['Tb'], + facility_level='2') screening_appt.apply(person_id=person_id, squeeze_factor=0.0) assert df.at[person_id, 'tb_diagnosed_mdr'] @@ -791,7 +796,8 @@ def test_mdr(seed): # schedule mdr treatment start # this calls clinical_monitoring which should schedule all follow-up appts tx_start = tb.HSI_Tb_StartTreatment(person_id=person_id, - module=sim.modules['Tb']) + module=sim.modules['Tb'], + facility_level='2') tx_start.apply(person_id=person_id, squeeze_factor=0.0) # check treatment appropriate for mdr-tb @@ -1030,7 +1036,7 @@ def test_hsi_scheduling(seed): duration_in_days=None, ) - assert set(sim.modules['SymptomManager'].has_what(person_id)) == symptom_list + assert set(sim.modules['SymptomManager'].has_what(person_id=person_id)) == symptom_list hsi_event = tb.HSI_Tb_ScreeningAndRefer(person_id=person_id, module=sim.modules['Tb']) hsi_event.run(squeeze_factor=0) @@ -1074,7 +1080,7 @@ def test_hsi_scheduling(seed): duration_in_days=None, ) - assert set(sim.modules['SymptomManager'].has_what(person_id)) == symptom_list + assert set(sim.modules['SymptomManager'].has_what(person_id=person_id)) == symptom_list hsi_event = tb.HSI_Tb_ScreeningAndRefer(person_id=person_id, module=sim.modules['Tb']) hsi_event.run(squeeze_factor=0) @@ -1119,18 +1125,29 @@ def test_hsi_scheduling(seed): duration_in_days=None, ) - assert set(sim.modules['SymptomManager'].has_what(person_id)) == symptom_list + assert set(sim.modules['SymptomManager'].has_what(person_id=person_id)) == symptom_list hsi_event = tb.HSI_Tb_ScreeningAndRefer(person_id=person_id, module=sim.modules['Tb']) hsi_event.run(squeeze_factor=0) + # person is HIV+ and will be referred for xpert - only available at level 2 + # Check person_id has a further testing event scheduled + date_event, event = [ + ev for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if + isinstance(ev[1], tb.HSI_Tb_ScreeningAndRefer) + ][0] + assert date_event >= sim.date + + # run testing event for xpert + hsi_event = tb.HSI_Tb_ScreeningAndRefer(person_id=person_id, + module=sim.modules['Tb'], + facility_level='2') + hsi_event.run(squeeze_factor=0) + + # person should now have treatment event scheduled # Check person_id has a treatment event scheduled date_event, event = [ ev for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], tb.HSI_Tb_StartTreatment) ][0] assert date_event == sim.date - - # check this is the only event scheduled - tmp = sim.modules['HealthSystem'].find_events_for_person(person_id) - assert len(tmp) == 1 From 4558afd67f89fc96ff76d27725e6758fae7eaf14 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 23 Jul 2024 22:11:12 +0100 Subject: [PATCH 073/755] PEP8 --- .../wasting_analyses/scenario_wasting.py | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/scenario_wasting.py b/src/scripts/wasting_analyses/scenario_wasting.py index 65832556c6..6851b1277e 100644 --- a/src/scripts/wasting_analyses/scenario_wasting.py +++ b/src/scripts/wasting_analyses/scenario_wasting.py @@ -12,9 +12,24 @@ import warnings from tlo import Date, logging -from tlo.methods import demography, healthsystem, healthseekingbehaviour, healthburden, symptommanager, \ - enhanced_lifestyle, labour, care_of_women_during_pregnancy, contraception, pregnancy_supervisor, \ - postnatal_supervisor, newborn_outcomes, hiv, tb, epi, wasting +from tlo.methods import ( + care_of_women_during_pregnancy, + contraception, + demography, + enhanced_lifestyle, + epi, + healthburden, + healthseekingbehaviour, + healthsystem, + hiv, + labour, + newborn_outcomes, + postnatal_supervisor, + pregnancy_supervisor, + symptommanager, + tb, + wasting, +) from tlo.scenario import BaseScenario # capture warnings during simulation run From de06bf6b50e8ee55eb6c035fbcaf6b83568b24e8 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 24 Jul 2024 14:45:15 +0100 Subject: [PATCH 074/755] RF_Wast, wast: [115,125) -> [115-125) (comma confuses the data as it separates individual columns); wast: minor updates in comments --- resources/ResourceFile_Wasting.csv | 2 +- src/tlo/methods/wasting.py | 45 +++++++++++++++--------------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 820fe24507..04167eb9b7 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:648395680f8980d2f68e31b89a47c4d53a21290a76a1ff8775e788d0df8ae3ca +oid sha256:8f111c69ca9fc2965fec30a18cc20cbe003ffcdbb61533f98f4997cba541c946 size 2688 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index e338a02a75..924d2897d5 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -125,11 +125,11 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.REAL, 'proportion of severe wasting with MUAC < 115mm'), 'proportion_-3<=WHZ<-2_with_MUAC<115mm': Parameter( Types.REAL, 'proportion of moderate wasting with MUAC < 115mm'), - 'proportion_-3<=WHZ<-2_with_MUAC_[115,125)mm': Parameter( + 'proportion_-3<=WHZ<-2_with_MUAC_[115-125)mm': Parameter( Types.REAL, 'proportion of moderate wasting with 115 mm ≤ MUAC < 125mm'), - 'proportion_mam_with_MUAC_[115,125)mm_and_normal_whz': Parameter( + 'proportion_mam_with_MUAC_[115-125)mm_and_normal_whz': Parameter( Types.REAL, 'proportion of MAM cases with 115 mm ≤ MUAC < 125 mm and normal/mild WHZ'), - 'proportion_mam_with_MUAC_[115,125)mm_and_-3<=WHZ<-2': Parameter( + 'proportion_mam_with_MUAC_[115-125)mm_and_-3<=WHZ<-2': Parameter( Types.REAL, 'proportion of MAM cases with both 115 mm ≤ MUAC < 125 mm and moderate wasting'), 'proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC': Parameter( Types.REAL, 'proportion of MAM cases with moderate wasting and normal MUAC'), @@ -174,7 +174,7 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'un_am_bilateral_oedema': Property(Types.BOOL, 'bilateral pitting oedema present in wasting episode'), 'un_am_MUAC_category': Property(Types.CATEGORICAL, 'MUAC measurement categories, based on WHO ' 'cut-offs', - categories=['<115mm', '[115,125)mm', '>=125mm']), + categories=['<115mm', '[115-125)mm', '>=125mm']), 'un_sam_with_complications': Property(Types.BOOL, 'medical complications in SAM episode'), 'un_sam_death_date': Property(Types.DATE, 'death date from severe acute malnutrition'), 'un_am_recovery_date': Property(Types.DATE, 'recovery date from acute malnutrition'), @@ -194,8 +194,7 @@ def __init__(self, name=None, resourcefilepath=None): # wasting symptom self.wasting_symptom = 'weight_loss' - # dict to hold counters for the number of episodes by wasting-type - # and age-group + # dict to hold counters for the number of episodes by wasting-type and age-group blank_counter = dict( zip(self.wasting_states, [list() for _ in self.wasting_states])) self.wasting_incident_case_tracker_blank = { @@ -265,8 +264,7 @@ def initialise_population(self, population): df.at[idx, 'un_am_treatment_type'] = 'none' # ------------------------------------------------------------------ - # # # # # # Give MUAC category, presence of oedema, and determine - # acute malnutrition state # # # # # + # # # # # # Give MUAC category, presence of oedema, and determine acute malnutrition state # # # # # self.population_poll_clinical_am(df) def initialise_simulation(self, sim): @@ -339,27 +337,28 @@ def muac_cutoff_by_WHZ(self, idx, whz): df = self.sim.population.props p = self.parameters - # ----- MUAC < 115 mm in severe wasting (WHZ < -3) and moderate (-3 <= WHZ < -2) ------ + # ----- MUAC distribution for severe wasting (WHZ < -3) ------ if whz == 'WHZ<-3': # apply probability of MUAC < 115 mm in severe wasting low_muac_in_severe_wasting = self.rng.random_sample(size=len(idx)) < p['proportion_WHZ<-3_with_MUAC<115mm'] df.loc[idx[low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '<115mm' - # other with severe wasting will have MUAC within [115,125)mm - df.loc[idx[~low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '[115,125)mm' + # other with severe wasting will have MUAC within [115-125)mm + df.loc[idx[~low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '[115-125)mm' + # ----- MUAC distribution for moderate wasting (-3 <= WHZ < -2) ------ if whz == '-3<=WHZ<-2': # apply probability of MUAC < 115 mm in moderate wasting low_muac_in_moderate_wasting = self.rng.random_sample(size=len(idx)) < \ p['proportion_-3<=WHZ<-2_with_MUAC<115mm'] df.loc[idx[low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = '<115mm' - # apply probability of MUAC within [115,125)mm in moderate wasting + # apply probability of MUAC within [115-125)mm in moderate wasting moderate_low_muac_in_moderate_wasting = \ self.rng.random_sample(size=len(idx[~low_muac_in_moderate_wasting])) < \ - p['proportion_-3<=WHZ<-2_with_MUAC_[115,125)mm'] + p['proportion_-3<=WHZ<-2_with_MUAC_[115-125)mm'] df.loc[idx[~low_muac_in_moderate_wasting][moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] \ - = '[115,125)mm' + = '[115-125)mm' # other with moderate wasting will have normal MUAC df.loc[idx[~low_muac_in_moderate_wasting][~moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] \ = '>=125mm' @@ -377,7 +376,7 @@ def muac_cutoff_by_WHZ(self, idx, whz): pro_between_115_125 = probability_over_or_equal_115 - probability_over_or_equal_125 for pid in idx: - muac_cat = self.rng.choice(['<115mm', '[115,125)mm', '>=125mm'], + muac_cat = self.rng.choice(['<115mm', '[115-125)mm', '>=125mm'], p=[prob_less_than_115, pro_between_115_125, probability_over_or_equal_125]) df.at[pid, 'un_am_MUAC_category'] = muac_cat @@ -390,8 +389,8 @@ def nutritional_oedema_present(self, idx): df = self.sim.population.props p = self.parameters - # Knowing the prevalence of nutritional oedema in under 5 - # population, apply the probability of oedema in WHZ < -2 + # Knowing the prevalence of nutritional oedema in under 5 population, + # apply the probability of oedema in WHZ < -2 # get those children with wasting children_with_wasting = idx.intersection(df.index[df.un_WHZ_category != 'WHZ>=-2']) children_without_wasting = idx.intersection(df.index[df.un_WHZ_category == 'WHZ>=-2']) @@ -526,7 +525,7 @@ def report_daly_values(self): total_daly_values.loc[df.is_alive & ( ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | ( (df.un_WHZ_category != 'WHZ<-3') & ( - df.un_am_MUAC_category != "[115,125)mm"))) & df.un_am_bilateral_oedema] = daly_wts[ + df.un_am_MUAC_category != "[115-125)mm"))) & df.un_am_bilateral_oedema] = daly_wts[ 'MAM_with_oedema'] return total_daly_values @@ -914,23 +913,23 @@ def apply(self, person_id): # oedema, or low muac - do not change the WHZ if df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2': # mam by muac only - df.at[person_id, 'un_am_MUAC_category'] = '[115,125)mm' + df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' else: # using the probability of mam classification by anthropometric # indices mam_classification = rng.choice(['mam_by_muac_only', 'mam_by_muac_and_whz', 'mam_by_whz_only'], - p=[p['proportion_mam_with_MUAC_[115,125)mm_and_normal_whz'], - p['proportion_mam_with_MUAC_[115,125)mm_and_-3<=WHZ<-2'], + p=[p['proportion_mam_with_MUAC_[115-125)mm_and_normal_whz'], + p['proportion_mam_with_MUAC_[115-125)mm_and_-3<=WHZ<-2'], p['proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC']]) if mam_classification == 'mam_by_muac_only': df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' - df.at[person_id, 'un_am_MUAC_category'] = '[115,125)mm' + df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' if mam_classification == 'mam_by_muac_and_whz': df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' - df.at[person_id, 'un_am_MUAC_category'] = '[115,125)mm' + df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' if mam_classification == 'mam_by_whz_only': df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' From 070ec85afb96ddc2de7affb2f7bb6bc44fa9da16 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 24 Jul 2024 15:58:58 +0100 Subject: [PATCH 075/755] wast: fix the imports of HSIEventScheduler and IndividualProperties --- src/tlo/methods/wasting.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 924d2897d5..d789a62326 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1,4 +1,6 @@ """Childhood wasting module""" +from __future__ import annotations + import copy from pathlib import Path from typing import TYPE_CHECKING, Any, Dict, Union From 17e4f21cefaa1d2807430f823c8ab06796dd336f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 25 Jul 2024 17:15:18 +0100 Subject: [PATCH 076/755] RF_PriorityRanking_ALLPOLICIES: priorities changed for undernutrition_ in RMNCH, ClinicallyVulnerable, VerticalProgrammes, and CVD as suggested by Margherita --- .../ResourceFile_PriorityRanking_ALLPOLICIES.xlsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx index 646c8cfd80..d2ca93b849 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:8a78bd1a7521c5df441f806e28780b55262d0ed1c9f83e834bcf2defba2d6c1d -size 40633 +oid sha256:d0d38f37b92d11f2c9aac3897f4075b091208b001a204e5d394e83c074bab725 +size 40612 From 79ba5e159004f66d3d9855f5726fcb464b303853 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 25 Jul 2024 17:57:43 +0100 Subject: [PATCH 077/755] test_wast: input params of sim.modules['SymptomManager'].has_what fixed --- tests/test_wasting.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index f1b066dca1..769930f68f 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -403,7 +403,9 @@ def test_recovery_severe_wasting_without_complications(tmpdir): progression_event.apply(person_id=person_id) # Check this individual has symptom(weight loss) caused by Wasting (SAM only) - assert 'weight_loss' in sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting']) + assert 'weight_loss' in sim.modules['SymptomManager'].has_what( + person_id=person_id, disease_module=sim.modules['Wasting'] + ) # Check properties of this individual: (should now be severely wasted, diagnosed as SAM and without a scheduled # death date) @@ -454,7 +456,7 @@ def test_recovery_severe_wasting_without_complications(tmpdir): assert pd.isnull(person['un_sam_death_date']) # check they have no symptoms: - assert 0 == len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) + assert 0 == len(sim.modules['SymptomManager'].has_what(person_id=person_id, disease_module=sim.modules['Wasting'])) def test_recovery_severe_wasting_with_complications(tmpdir): @@ -542,7 +544,7 @@ def test_recovery_severe_wasting_with_complications(tmpdir): assert pd.isnull(person['un_sam_death_date']) # check they have no symptoms: - assert 0 == len(sim.modules['SymptomManager'].has_what(person_id, sim.modules['Wasting'])) + assert 0 == len(sim.modules['SymptomManager'].has_what(person_id=person_id, disease_module=sim.modules['Wasting'])) def test_nat_hist_death(tmpdir): From c2646e22542578cdb6029b16379a93019e383963 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 29 Jul 2024 17:00:21 +0100 Subject: [PATCH 078/755] wast: duplicated logger setup rm; logger arguments added --- src/tlo/methods/wasting.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index d789a62326..899d3732f1 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -25,9 +25,6 @@ logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) -logger = logging.getLogger(__name__) -logger.setLevel(logging.INFO) - # --------------------------------------------------------------------------- # MODULE DEFINITIONS @@ -1002,7 +999,7 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data="PkgCode1 is not available, so can't use it.") def did_not_run(self): - logger.debug("Undernutrition_Feeding_Supplementary: did not run") + logger.debug(key='debug', data='Undernutrition_Feeding_Supplementary: did not run') pass @@ -1058,7 +1055,7 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data="consumables not available, so can't use it.") def did_not_run(self): - logger.debug("HSI_Undernutrition_Feeding_Outpatient: did not run") + logger.debug(key='debug', data="HSI_Undernutrition_Feeding_Outpatient: did not run") pass @@ -1109,7 +1106,7 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data="consumables not available, so can't use it.") def did_not_run(self): - logger.debug("HSI_inpatient_care_for_complicated_SAM: did not run") + logger.debug(key='debug', data='HSI_inpatient_care_for_complicated_SAM: did not run') pass From e59c24a316c44da092fd99f94d68f72c49d534b3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 30 Jul 2024 19:31:59 +0100 Subject: [PATCH 079/755] wast: fix MUAC distribution for moderate wasting; apply choice fnc to get MUAC distribution for each WHZ category --- src/tlo/methods/wasting.py | 50 ++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 899d3732f1..b6f85913ea 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -338,46 +338,43 @@ def muac_cutoff_by_WHZ(self, idx, whz): # ----- MUAC distribution for severe wasting (WHZ < -3) ------ if whz == 'WHZ<-3': - # apply probability of MUAC < 115 mm in severe wasting - low_muac_in_severe_wasting = self.rng.random_sample(size=len(idx)) < p['proportion_WHZ<-3_with_MUAC<115mm'] + # for severe wasting assumed no MUAC >= 125mm + prop_severe_wasting_with_muac_between_115and125mm = 1 - p['proportion_WHZ<-3_with_MUAC<115mm'] - df.loc[idx[low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '<115mm' - # other with severe wasting will have MUAC within [115-125)mm - df.loc[idx[~low_muac_in_severe_wasting], 'un_am_MUAC_category'] = '[115-125)mm' + df.loc[idx, 'un_am_MUAC_category'] = df.loc[idx].apply( + lambda x: self.rng.choice(['<115mm', '[115-125)mm'], + p=[p['proportion_WHZ<-3_with_MUAC<115mm'], + prop_severe_wasting_with_muac_between_115and125mm]) + ) # ----- MUAC distribution for moderate wasting (-3 <= WHZ < -2) ------ if whz == '-3<=WHZ<-2': - # apply probability of MUAC < 115 mm in moderate wasting - low_muac_in_moderate_wasting = self.rng.random_sample(size=len(idx)) < \ - p['proportion_-3<=WHZ<-2_with_MUAC<115mm'] - df.loc[idx[low_muac_in_moderate_wasting], 'un_am_MUAC_category'] = '<115mm' - - # apply probability of MUAC within [115-125)mm in moderate wasting - moderate_low_muac_in_moderate_wasting = \ - self.rng.random_sample(size=len(idx[~low_muac_in_moderate_wasting])) < \ - p['proportion_-3<=WHZ<-2_with_MUAC_[115-125)mm'] - df.loc[idx[~low_muac_in_moderate_wasting][moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] \ - = '[115-125)mm' - # other with moderate wasting will have normal MUAC - df.loc[idx[~low_muac_in_moderate_wasting][~moderate_low_muac_in_moderate_wasting], 'un_am_MUAC_category'] \ - = '>=125mm' + prop_moderate_wasting_with_muac_over_125mm = \ + 1 - p['proportion_-3<=WHZ<-2_with_MUAC<115mm'] - p['proportion_-3<=WHZ<-2_with_MUAC_[115-125)mm'] + + df.loc[idx, 'un_am_MUAC_category'] = df.loc[idx].apply( + lambda x: self.rng.choice(['<115mm', '[115-125)mm', '>=125mm'], + p=[p['proportion_-3<=WHZ<-2_with_MUAC<115mm'], + p['proportion_-3<=WHZ<-2_with_MUAC_[115-125)mm'], + prop_moderate_wasting_with_muac_over_125mm]) + ) # ----- MUAC distribution for WHZ >= -2 ----- if whz == 'WHZ>=-2': muac_distribution_in_well_group = norm(loc=p['MUAC_distribution_WHZ>=-2'][0], scale=p['MUAC_distribution_WHZ>=-2'][1]) - # get probability of MUAC < 115 mm + # get probabilities of MUAC probability_over_or_equal_115 = muac_distribution_in_well_group.sf(11.5) probability_over_or_equal_125 = muac_distribution_in_well_group.sf(12.5) prob_less_than_115 = 1 - probability_over_or_equal_115 pro_between_115_125 = probability_over_or_equal_115 - probability_over_or_equal_125 - for pid in idx: - muac_cat = self.rng.choice(['<115mm', '[115-125)mm', '>=125mm'], - p=[prob_less_than_115, pro_between_115_125, probability_over_or_equal_125]) - df.at[pid, 'un_am_MUAC_category'] = muac_cat + df.loc[idx, 'un_am_MUAC_category'] = df.loc[idx].apply( + lambda x: self.rng.choice(['<115mm', '[115-125)mm', '>=125mm'], + p=[prob_less_than_115, pro_between_115_125, probability_over_or_equal_125]) + ) def nutritional_oedema_present(self, idx): """ @@ -908,11 +905,16 @@ def apply(self, person_id): if not df.at[person_id, 'is_alive']: return + # if not df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM': + # return + # # TODO: check if this is correct before added (maybe it should be == 'SAM'? + # For cases with normal WHZ and other acute malnutrition signs: # oedema, or low muac - do not change the WHZ if df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2': # mam by muac only df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' + # TODO: I think this changes the proportions below as some of the cases will be issued here else: # using the probability of mam classification by anthropometric From baa263117e0ca00e3d455ccf86002882462ca24b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 30 Jul 2024 23:02:17 +0100 Subject: [PATCH 080/755] RF_PriorityRanking_ALLPOLICIES: priorities changed for undernutrition in EHP_III, and LCOA_EHP as suggested by Sakshi --- .../ResourceFile_PriorityRanking_ALLPOLICIES.xlsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx index d2ca93b849..e8d9aff1d1 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:d0d38f37b92d11f2c9aac3897f4075b091208b001a204e5d394e83c074bab725 -size 40612 +oid sha256:4838fa5922a84b34de3250077d3465e365a03368e237bbaa5ee37b1ed8abcd85 +size 40616 From 11c7124b3a480fc1b8bc817b842cb75ddb4ae064 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 31 Jul 2024 17:23:20 +0100 Subject: [PATCH 081/755] wast: apply fixed to be used on rows --- src/tlo/methods/wasting.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index b6f85913ea..bb2563de72 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -344,7 +344,8 @@ def muac_cutoff_by_WHZ(self, idx, whz): df.loc[idx, 'un_am_MUAC_category'] = df.loc[idx].apply( lambda x: self.rng.choice(['<115mm', '[115-125)mm'], p=[p['proportion_WHZ<-3_with_MUAC<115mm'], - prop_severe_wasting_with_muac_between_115and125mm]) + prop_severe_wasting_with_muac_between_115and125mm]), + axis=1 ) # ----- MUAC distribution for moderate wasting (-3 <= WHZ < -2) ------ @@ -356,7 +357,8 @@ def muac_cutoff_by_WHZ(self, idx, whz): lambda x: self.rng.choice(['<115mm', '[115-125)mm', '>=125mm'], p=[p['proportion_-3<=WHZ<-2_with_MUAC<115mm'], p['proportion_-3<=WHZ<-2_with_MUAC_[115-125)mm'], - prop_moderate_wasting_with_muac_over_125mm]) + prop_moderate_wasting_with_muac_over_125mm]), + axis=1 ) # ----- MUAC distribution for WHZ >= -2 ----- @@ -373,7 +375,8 @@ def muac_cutoff_by_WHZ(self, idx, whz): df.loc[idx, 'un_am_MUAC_category'] = df.loc[idx].apply( lambda x: self.rng.choice(['<115mm', '[115-125)mm', '>=125mm'], - p=[prob_less_than_115, pro_between_115_125, probability_over_or_equal_125]) + p=[prob_less_than_115, pro_between_115_125, probability_over_or_equal_125]), + axis=1 ) def nutritional_oedema_present(self, idx): @@ -471,9 +474,9 @@ def date_of_outcome_for_untreated_am(self, person_id, duration_am): def population_poll_clinical_am(self, population): """ - Update at the population level other anthropometric indices and clinical signs (MUAC, oedema, - medical complications) that determine the clinical state of acute malnutrition This will include both wasted - and non-wasted children with other signs of acute malnutrition + Update at the population level other anthropometric indices and clinical signs (MUAC, oedema, + medical complications) that determine the clinical state of acute malnutrition. This will include both wasted + and non-wasted children with other signs of acute malnutrition. :param population: population dataframe :return: """ From 005e3a8641c5744acefb0f4cf05238bf49f60ce3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 31 Jul 2024 18:15:00 +0100 Subject: [PATCH 082/755] test_wast: update checking of scheduled hsi events; outpatient and inpatient care for SAM cases depend on coverage --- tests/test_wasting.py | 41 +++++++++++++++++++++++++++++++---------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 769930f68f..0a34956d7b 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -427,8 +427,12 @@ def test_recovery_severe_wasting_without_complications(tmpdir): ge.run(squeeze_factor=0.0) # check HSI event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[1][1], - HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + hsi_event_scheduled = [ + ev + for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) + if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + ] + assert 1 == len(hsi_event_scheduled) # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if @@ -499,6 +503,7 @@ def test_recovery_severe_wasting_with_complications(tmpdir): # make recovery rate to 100% and death rate to zero so that # this individual should recover wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel.multiplicative() + wmodule.parameters['prob_death_after_care'] = 0.0 # run care seeking event and ensure HSI for complicated SAM is scheduled hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) @@ -509,13 +514,19 @@ def test_recovery_severe_wasting_with_complications(tmpdir): hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought + # make inpatient care coverage 100% + wmodule.parameters['coverage_inpatient_care'] = 1.0 ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) # check HSI event for complicated SAM is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - HSI_Wasting_InpatientCareForComplicated_SAM) + hsi_event_scheduled = [ + ev + for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) + if isinstance(ev[1], HSI_Wasting_InpatientCareForComplicated_SAM) + ] + assert 1 == len(hsi_event_scheduled) # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if @@ -595,13 +606,19 @@ def test_nat_hist_death(tmpdir): hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought + # make outpatient care coverage 100% + wmodule.parameters['coverage_outpatient_therapeutic_care'] = 1.0 ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) - # check inpatient care event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + # check outpatient care event is scheduled + hsi_event_scheduled = [ + ev + for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) + if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + ] + assert 1 == len(hsi_event_scheduled) # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) @@ -772,9 +789,13 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) - # check inpatient care event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[1][1], - HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + # check outpatient care event is scheduled + hsi_event_scheduled = [ + ev + for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) + if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + ] + assert 1 == len(hsi_event_scheduled) # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if From dad77e601a469768fdf95062b23559cb35a4df7f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 31 Jul 2024 19:27:26 +0100 Subject: [PATCH 083/755] wast: simplified setting of oedema status --- src/tlo/methods/wasting.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index bb2563de72..c3a1ca25d6 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -397,14 +397,12 @@ def nutritional_oedema_present(self, idx): # oedema among wasted children oedema_in_wasted_children = self.rng.random_sample(size=len( children_with_wasting)) < p['prevalence_nutritional_oedema'] * p['proportion_oedema_with_WHZ<-2'] - df.loc[children_with_wasting[oedema_in_wasted_children], 'un_am_bilateral_oedema'] = True - df.loc[children_with_wasting[~oedema_in_wasted_children], 'un_am_bilateral_oedema'] = False + df.loc[children_with_wasting, 'un_am_bilateral_oedema'] = oedema_in_wasted_children # oedema among non-wasted children oedema_in_non_wasted = self.rng.random_sample(size=len( children_without_wasting)) < p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) - df.loc[children_without_wasting[oedema_in_non_wasted], 'un_am_bilateral_oedema'] = True - df.loc[children_without_wasting[~oedema_in_non_wasted], 'un_am_bilateral_oedema'] = False + df.loc[children_without_wasting, 'un_am_bilateral_oedema'] = oedema_in_non_wasted def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): """ From 190ede14c1ed70e696f59d8b4e4f5c756192a523 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 31 Jul 2024 22:48:08 +0100 Subject: [PATCH 084/755] wast: returns rm from fnc descriptions if no return, outdated params rm from fnc descriptions --- src/tlo/methods/wasting.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index c3a1ca25d6..a3e8efa4cf 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -205,7 +205,6 @@ def read_parameters(self, data_folder): """ :param data_folder: path of a folder supplied to the Simulation containing data files. Typically, modules would read a particular file within here. - :return: """ # Read parameters from the resource file self.load_parameters_from_dataframe( @@ -222,7 +221,6 @@ def initialise_population(self, population): of those properties 'owned' by this module, i.e. those declared in the PROPERTIES dictionary above. :param population: - :return: """ df = population.props @@ -383,7 +381,6 @@ def nutritional_oedema_present(self, idx): """ This function applies the probability of bilateral oedema present in wasting and non-wasted cases :param idx: index of children under 5, or person_id - :return: """ df = self.sim.population.props p = self.parameters @@ -411,7 +408,6 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): complications, applicable to SAM cases only, requiring inpatient care. :param person_id: individual id :param pop_dataframe: population dataframe - :return: """ df = pop_dataframe p = self.parameters @@ -476,7 +472,6 @@ def population_poll_clinical_am(self, population): medical complications) that determine the clinical state of acute malnutrition. This will include both wasted and non-wasted children with other signs of acute malnutrition. :param population: population dataframe - :return: """ df = population @@ -501,6 +496,7 @@ def report_daly_values(self): experienced by persons in the previous month. Only rows for alive-persons must be returned. The names of the series of columns is taken to be the label of the cause of this disability. It will be recorded by the healthburden module as _. + :return: """ # Dict to hold the DALY weights daly_wts = dict() @@ -595,7 +591,6 @@ def do_when_am_treatment(self, person_id, intervention): This function will apply the linear model of recovery based on intervention given :param person_id: :param intervention: - :return: """ df = self.sim.population.props # Log that the treatment is provided: @@ -1151,8 +1146,9 @@ def __init__(self, module): self.wasting_incidence_lm = self.get_wasting_incidence() def get_wasting_incidence(self) -> LinearModel: - """ return a scaled wasting incidence linear model amongst young children - :params df: population dataframe """ + """ + :return: a scaled wasting incidence linear model amongst young children + """ df = self.module.sim.population.props def unscaled_wasting_lm(intercept: Union[float, int] = 1.0) -> LinearModel: @@ -1191,9 +1187,9 @@ def unscaled_wasting_lm(intercept: Union[float, int] = 1.0) -> LinearModel: return scaled_wasting_incidence_lm def get_wasting_prevalence(self, agegp: str) -> LinearModel: - """ return a scaled wasting prevalence linear model amongst young children less than 5 years - :params df: population dataframe + """ :param agegp: children's age group + :return: a scaled wasting prevalence linear model amongst young children less than 5 years """ df = self.module.sim.population.props From cc05882520b760eaddc81c7d0abf624a33138fb3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 2 Aug 2024 11:32:42 +0100 Subject: [PATCH 085/755] wast: update the var/fnc names to reflect what they store/do (esp. do not confuse MAM with moderate wasting etc) --- src/tlo/methods/wasting.py | 58 ++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index a3e8efa4cf..cc221d3f7b 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -439,31 +439,33 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): assert not (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') & \ (df.at[person_id, 'un_sam_with_complications']) - def date_of_outcome_for_untreated_am(self, person_id, duration_am): + def date_of_outcome_for_untreated_wasting(self, person_id): """ - helper function to get the duration, the wasting episode and date of outcome (recovery, progression, or death) + Helper function to use the duration of the wasting episode to get date of outcome (recovery, progression, + or death) :param person_id: - :param duration_am: - :return: + :return: date of outcome, which can be recovery to no wasting or progression to severe wasting from moderate + wasting; or recovery to moderate wasting or death due to severe wasting """ df = self.sim.population.props p = self.parameters + whz_category = df.at[person_id, 'un_WHZ_category'] - # moderate wasting (for progression to severe, or recovery from MAM) ----- - if duration_am == 'MAM': + # moderate wasting (for progression to severe, or recovery to no wasting) ----- + if whz_category == '-3<=WHZ<-2': # Allocate the duration of the moderate wasting episode - duration_mam = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'])) + duration_mod_wasting = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'])) # Allocate a date of outcome (progression, recovery or death) - date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_mam) + date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_mod_wasting) return date_of_outcome # severe wasting (for death, or recovery to moderate wasting) ----- - if duration_am == 'SAM': + if whz_category == 'WHZ<-3': # determine the duration of SAM episode - duration_sam = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'] - + p['average_duration_of_untreated_SAM'])) + duration_sev_wasting = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'] + + p['average_duration_of_untreated_SAM'])) # Allocate a date of outcome (progression, recovery or death) - date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_sam) + date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_sev_wasting) return date_of_outcome def population_poll_clinical_am(self, population): @@ -683,22 +685,22 @@ def apply(self, population): # # # INCIDENCE OF WASTING # # # # # # # # # # # # # # # # # # # # # # Determine who will be onset with wasting among those who are not currently wasted ------------- - inc_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & ( - df.un_WHZ_category == 'WHZ>=-2')] - incidence_of_wasting = self.module.wasting_models.wasting_incidence_lm.predict(inc_wasting, + not_wasted = df.loc[df.is_alive & (df.age_exact_years < 5) & ( + df.un_WHZ_category == 'WHZ>=-2')] + incidence_of_wasting = self.module.wasting_models.wasting_incidence_lm.predict(not_wasted, rng=rng ) - wasting_idx = inc_wasting.index + not_wasted_idx = not_wasted.index # update the properties for wasted children - df.loc[wasting_idx[incidence_of_wasting], 'un_ever_wasted'] = True - df.loc[wasting_idx[incidence_of_wasting], 'un_last_wasting_date_of_onset'] = self.sim.date + df.loc[not_wasted_idx[incidence_of_wasting], 'un_ever_wasted'] = True + df.loc[not_wasted_idx[incidence_of_wasting], 'un_last_wasting_date_of_onset'] = self.sim.date # start as moderate wasting - df.loc[wasting_idx[incidence_of_wasting], 'un_WHZ_category'] = '-3<=WHZ<-2' + df.loc[not_wasted_idx[incidence_of_wasting], 'un_WHZ_category'] = '-3<=WHZ<-2' # start without treatment - df.loc[wasting_idx[incidence_of_wasting], 'un_am_treatment_type'] = 'none' + df.loc[not_wasted_idx[incidence_of_wasting], 'un_am_treatment_type'] = 'none' # -------------------------------------------------------------------- # Add these incident cases to the tracker - for person in wasting_idx: + for person in not_wasted_idx: wasting_severity = df.at[person, 'un_WHZ_category'] age_group = WastingPollingEvent.AGE_GROUPS.get(df.loc[person].age_years, '5+y') # if wasting_severity != 'WHZ>=-2': @@ -708,14 +710,14 @@ def apply(self, population): # # # PROGRESS TO SEVERE WASTING # # # # # # # # # # # # # # # # # # # Determine those that will progress to severe wasting (WHZ < -3) and schedule progression event --------- - progression_sev_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & - (df.un_WHZ_category == '-3<=WHZ<-2')] + mod_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & + (df.un_WHZ_category == '-3<=WHZ<-2')] progression_severe_wasting = self.module.wasting_models.severe_wasting_progression_lm.predict( - progression_sev_wasting, rng=rng, squeeze_single_row_output=False) + mod_wasting, rng=rng, squeeze_single_row_output=False) # determine those individuals who will progress to severe wasting and time of progression - for person in progression_sev_wasting.index[progression_severe_wasting]: - outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') + for person in mod_wasting.index[progression_severe_wasting]: + outcome_date = self.module.date_of_outcome_for_untreated_wasting(person_id=person) # schedule severe wasting WHZ < -3 onset if outcome_date <= self.sim.date: # schedule severe wasting (WHZ < -3) onset today @@ -729,8 +731,8 @@ def apply(self, population): # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # Schedule recovery from moderate wasting for those not progressing to severe wasting --------- - for person in progression_sev_wasting.index[~progression_severe_wasting]: - outcome_date = self.module.date_of_outcome_for_untreated_am(person_id=person, duration_am='MAM') + for person in mod_wasting.index[~progression_severe_wasting]: + outcome_date = self.module.date_of_outcome_for_untreated_wasting(person_id=person) if outcome_date <= self.sim.date: # schedule recovery for today self.sim.schedule_event(event=WastingNaturalRecoveryEvent( From 4c29cca7a6cad694b606e92fbbdf5136f479be5d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 2 Aug 2024 16:36:37 +0100 Subject: [PATCH 086/755] [no ci] wast: update the par names to reflect what they represent --- src/tlo/methods/wasting.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index cc221d3f7b..53bea67c11 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -102,10 +102,10 @@ class Wasting(Module, GenericFirstAppointmentsMixin): # progression 'min_days_duration_of_wasting': Parameter( Types.REAL, 'minimum duration in days of wasting (MAM and SAM)'), - 'average_duration_of_untreated_MAM': Parameter( - Types.REAL, 'average duration of untreated MAM'), - 'average_duration_of_untreated_SAM': Parameter( - Types.REAL, 'average duration of untreated SAM'), + 'duration_of_untreated_mod_wasting': Parameter( + Types.REAL, 'duration of untreated moderate wasting (days)'), + 'duration_of_untreated_sev_wasting': Parameter( + Types.REAL, 'duration of untreated severe wasting (days)'), 'progression_severe_wasting_by_agegp': Parameter( Types.LIST, 'List with progression rates to severe wasting by age group'), 'prob_complications_in_SAM': Parameter( @@ -454,16 +454,16 @@ def date_of_outcome_for_untreated_wasting(self, person_id): # moderate wasting (for progression to severe, or recovery to no wasting) ----- if whz_category == '-3<=WHZ<-2': # Allocate the duration of the moderate wasting episode - duration_mod_wasting = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'])) - # Allocate a date of outcome (progression, recovery or death) + duration_mod_wasting = int(max(p['min_days_duration_of_wasting'], p['duration_of_untreated_mod_wasting'])) + # Allocate a date of outcome (progression, or recovery) date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_mod_wasting) return date_of_outcome # severe wasting (for death, or recovery to moderate wasting) ----- if whz_category == 'WHZ<-3': # determine the duration of SAM episode - duration_sev_wasting = int(max(p['min_days_duration_of_wasting'], p['average_duration_of_untreated_MAM'] - + p['average_duration_of_untreated_SAM'])) + duration_sev_wasting = int(max(p['min_days_duration_of_wasting'], p['duration_of_untreated_mod_wasting'] + + p['duration_of_untreated_sev_wasting'])) # Allocate a date of outcome (progression, recovery or death) date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_sev_wasting) return date_of_outcome From 14e6b18a27f5a9067f07ec01a01248c706e95fa7 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 2 Aug 2024 16:46:49 +0100 Subject: [PATCH 087/755] RF_Wast: update the par names to reflect what they represent --- resources/ResourceFile_Wasting.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 04167eb9b7..7c5833bd0f 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8f111c69ca9fc2965fec30a18cc20cbe003ffcdbb61533f98f4997cba541c946 +oid sha256:187dc5d77671837777430e32ebb1d4cba7c14ff6f81566b72032b8da0c34d6ad size 2688 From 71582862257eaa87439b351d1bd7e75de19ae001 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 6 Aug 2024 16:56:00 +0100 Subject: [PATCH 088/755] wast: assert added as stated in comment + minor changes (out of loop calculation of value independent of loop var; fnc description and comments updated) --- src/tlo/methods/wasting.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 53bea67c11..3e0b965374 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -250,8 +250,8 @@ def initialise_population(self, population): # apply prevalence of wasting and categorise into moderate (-3 <= WHZ < -2) or severe (WHZ < -3) wasting wasted = self.rng.random_sample(len(prevalence_of_wasting)) < prevalence_of_wasting + probability_of_severe = self.get_prob_severe_wasting_or_odds_wasting(agegp=agegp, get_odds=False) for idx in prevalence_of_wasting.index[wasted]: - probability_of_severe = self.get_prob_severe_wasting_or_odds_wasting(agegp=agegp) wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], p=[probability_of_severe, 1 - probability_of_severe]) df.at[idx, 'un_WHZ_category'] = wasted_category @@ -300,8 +300,7 @@ def get_prob_severe_wasting_or_odds_wasting(self, agegp: str, get_odds: bool = F This function will calculate the WHZ scores by categories and return probability of severe wasting for those with wasting status, or odds of wasting :param agegp: age grouped in months - :param get_odds: when set to True, this argument will cause this method return the odds of wasting to be used - for scaling wasting prevalence linear model + :param get_odds: True/False (default: False), indicates which output from fnc name will be returned :return: probability of severe wasting among all wasting cases (if 'get_odds' == False), or odds of wasting among all children under 5 (if 'get_odds' == True) """ @@ -464,7 +463,7 @@ def date_of_outcome_for_untreated_wasting(self, person_id): # determine the duration of SAM episode duration_sev_wasting = int(max(p['min_days_duration_of_wasting'], p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'])) - # Allocate a date of outcome (progression, recovery or death) + # Allocate a date of outcome (death, or recovery) date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_sev_wasting) return date_of_outcome @@ -687,11 +686,9 @@ def apply(self, population): # Determine who will be onset with wasting among those who are not currently wasted ------------- not_wasted = df.loc[df.is_alive & (df.age_exact_years < 5) & ( df.un_WHZ_category == 'WHZ>=-2')] - incidence_of_wasting = self.module.wasting_models.wasting_incidence_lm.predict(not_wasted, - rng=rng - ) + incidence_of_wasting = self.module.wasting_models.wasting_incidence_lm.predict(not_wasted, rng=rng) not_wasted_idx = not_wasted.index - # update the properties for wasted children + # update the properties for new cases of wasted children df.loc[not_wasted_idx[incidence_of_wasting], 'un_ever_wasted'] = True df.loc[not_wasted_idx[incidence_of_wasting], 'un_last_wasting_date_of_onset'] = self.sim.date # start as moderate wasting @@ -1247,6 +1244,8 @@ def apply(self, population): for age_grp in self.module.wasting_incident_case_tracker.keys(): for state in self.module.wasting_states: inc_df.loc[age_grp, state] = len(self.module.wasting_incident_case_tracker[age_grp][state]) + assert all(date >= self.date_last_run for + date in self.module.wasting_incident_case_tracker[age_grp][state]) logger.info(key='wasting_incidence_count', data=inc_df.to_dict()) From 1f033fad24ecfe27fb742493c0698c197951fe96 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 6 Aug 2024 17:24:21 +0100 Subject: [PATCH 089/755] wast & analysis_wast: logging key updated to reflect prevalence props not counts are logged --- src/scripts/wasting_analyses/analysis_wasting.py | 4 ++-- src/tlo/methods/wasting.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 8c72c501fe..c1f13341d6 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -104,7 +104,7 @@ def plot_wasting_incidence(self): def plot_wasting_prevalence_per_year(self): """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of children wasted divide by the total number of children less than 5 years""" - w_prev_df = self.__logs_dict["wasting_prevalence_count"] + w_prev_df = self.__logs_dict["wasting_prevalence_props"] w_prev_df = w_prev_df[['date', 'total_under5_prop']] w_prev_df.set_index(w_prev_df.date.dt.year, inplace=True) w_prev_df.drop(columns='date', inplace=True) @@ -126,7 +126,7 @@ def plot_wasting_prevalence_per_year(self): def plot_wasting_prevalence_by_age_group(self): """ plot wasting prevalence per each age group. Proportions are obtained by getting a total number of children wasted in a particular age-group divide by the total number of children per that age-group""" - w_prev_df = self.__logs_dict["wasting_prevalence_count"] + w_prev_df = self.__logs_dict["wasting_prevalence_props"] w_prev_df.drop(columns={'total_under5_prop'}, inplace=True) w_prev_df.set_index(w_prev_df.date.dt.year, inplace=True) w_prev_df = w_prev_df.loc[w_prev_df.index == 2023] diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 3e0b965374..120909d9b7 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1273,4 +1273,4 @@ def apply(self, population): # add to dictionary proportion of all wasted children under 5 years wasting_prev_dict['total_under5_prop'] = (under5s.un_WHZ_category != 'WHZ>=-2').sum() / len(under5s) # log wasting prevalence - logger.info(key='wasting_prevalence_count', data=wasting_prev_dict) + logger.info(key='wasting_prevalence_props', data=wasting_prev_dict) From 32465008f8976c0de86f7c32cbe2fdd3f09ca33f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 6 Aug 2024 18:46:08 +0100 Subject: [PATCH 090/755] wast & test_wast: MAM/SAM corrected to mod/sev wasting --- src/tlo/methods/wasting.py | 12 ++++++------ tests/test_wasting.py | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 120909d9b7..7c15683d15 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -506,21 +506,21 @@ def report_daly_values(self): # Get DALY weights get_daly_weight = self.sim.modules['HealthBurden'].get_daly_weight - daly_wts['MAM_with_oedema'] = get_daly_weight(sequlae_code=461) - daly_wts['SAM_w/o_oedema'] = get_daly_weight(sequlae_code=462) - daly_wts['SAM_with_oedema'] = get_daly_weight(sequlae_code=463) + daly_wts['mod_wasting_with_oedema'] = get_daly_weight(sequlae_code=461) + daly_wts['sev_wasting_w/o_oedema'] = get_daly_weight(sequlae_code=462) + daly_wts['sev_wasting_with_oedema'] = get_daly_weight(sequlae_code=463) total_daly_values = pd.Series(data=0.0, index=df.index[df.is_alive]) total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & - df.un_am_bilateral_oedema] = daly_wts['SAM_with_oedema'] + df.un_am_bilateral_oedema] = daly_wts['sev_wasting_with_oedema'] total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & - (~df.un_am_bilateral_oedema)] = daly_wts['SAM_w/o_oedema'] + (~df.un_am_bilateral_oedema)] = daly_wts['sev_wasting_w/o_oedema'] total_daly_values.loc[df.is_alive & ( ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | ( (df.un_WHZ_category != 'WHZ<-3') & ( df.un_am_MUAC_category != "[115-125)mm"))) & df.un_am_bilateral_oedema] = daly_wts[ - 'MAM_with_oedema'] + 'mod_wasting_with_oedema'] return total_daly_values def wasting_clinical_symptoms(self, person_id): diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 0a34956d7b..5aed1f058c 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -242,7 +242,7 @@ def test_report_daly_weights(tmpdir): # Reset diagnosis and check correct daly weight is given for MAM df.loc[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' df.loc[person_id, 'un_am_bilateral_oedema'] = True - daly_wts['MAM_with_oedema'] = get_daly_weights(sequlae_code=461) + daly_wts['mod_wasting_with_oedema'] = get_daly_weights(sequlae_code=461) # Verify diagnosis assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'MAM' @@ -252,7 +252,7 @@ def test_report_daly_weights(tmpdir): daly_weights_reported = sim.modules["Wasting"].report_daly_values() # Compare the daly weight of this individual with the daly weight obtained from HealthBurden module - assert daly_wts['MAM_with_oedema'] == daly_weights_reported.loc[person_id] + assert daly_wts['mod_wasting_with_oedema'] == daly_weights_reported.loc[person_id] # Check daly weight for person with SAM and oedema (SAM_oedema weight is 0.172) # Reset diagnosis @@ -269,10 +269,10 @@ def test_report_daly_weights(tmpdir): daly_weights_reported = sim.modules["Wasting"].report_daly_values() # Get daly weights of SAM with Oedema - daly_wts['SAM_with_oedema'] = get_daly_weights(sequlae_code=463) + daly_wts['sev_wasting_with_oedema'] = get_daly_weights(sequlae_code=463) # Compare the daly weight of this individual with the daly weight obtained from HealthBurden module - assert daly_wts['SAM_with_oedema'] == daly_weights_reported.loc[person_id] + assert daly_wts['sev_wasting_with_oedema'] == daly_weights_reported.loc[person_id] # Check daly weight for person with SAM no Oedema (SAM no oedema weight is 0.128) # Reset diagnosis @@ -280,7 +280,7 @@ def test_report_daly_weights(tmpdir): df.loc[person_id, 'un_am_bilateral_oedema'] = False # Get day weights of SAM without Oedema - daly_wts['SAM_w/o_oedema'] = get_daly_weights(sequlae_code=462) + daly_wts['sev_wasting_w/o_oedema'] = get_daly_weights(sequlae_code=462) # Report daly weight for this individual daly_weights_reported = sim.modules["Wasting"].report_daly_values() @@ -290,7 +290,7 @@ def test_report_daly_weights(tmpdir): assert not df.loc[person_id, 'un_am_bilateral_oedema'] # Compare the daly weight of this individual with the daly weight obtained from HealthBurden module - assert daly_wts['SAM_w/o_oedema'] == daly_weights_reported.loc[person_id] + assert daly_wts['sev_wasting_w/o_oedema'] == daly_weights_reported.loc[person_id] def test_recovery_moderate_wasting(tmpdir): From 2fad6be3b70b127ae31bc3a6e26740b950e303f5 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 6 Aug 2024 19:00:23 +0100 Subject: [PATCH 091/755] wast & test_wast: DALY calculations corrected --- src/tlo/methods/wasting.py | 11 +++---- tests/test_wasting.py | 61 +++++++++++++++++++++----------------- 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 7c15683d15..d6aac6baf3 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -512,15 +512,12 @@ def report_daly_values(self): total_daly_values = pd.Series(data=0.0, index=df.index[df.is_alive]) - total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & + total_daly_values.loc[df.is_alive & (df.un_WHZ_category == 'WHZ<-3') & df.un_am_bilateral_oedema] = daly_wts['sev_wasting_with_oedema'] - total_daly_values.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'SAM') & + total_daly_values.loc[df.is_alive & (df.un_WHZ_category == 'WHZ<-3') & (~df.un_am_bilateral_oedema)] = daly_wts['sev_wasting_w/o_oedema'] - total_daly_values.loc[df.is_alive & ( - ((df.un_WHZ_category == '-3<=WHZ<-2') & (df.un_am_MUAC_category != "<115mm")) | ( - (df.un_WHZ_category != 'WHZ<-3') & ( - df.un_am_MUAC_category != "[115-125)mm"))) & df.un_am_bilateral_oedema] = daly_wts[ - 'mod_wasting_with_oedema'] + total_daly_values.loc[df.is_alive & (df.un_WHZ_category == '-3<=WHZ<-2') & + df.un_am_bilateral_oedema] = daly_wts['mod_wasting_with_oedema'] return total_daly_values def wasting_clinical_symptoms(self, person_id): diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 5aed1f058c..78b9e1ef21 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -208,10 +208,10 @@ def test_wasting_incidence(tmpdir): def test_report_daly_weights(tmpdir): """Check if daly weights reporting is done as expected. Four checks are made: - 1. For an individual who is well (No weights are expected/must be 0.0) - 2. For an individual with MAM and Oedema (expected daly weight is 0.051) - 3. For an individual with SAM, Oedema and Weight for Height Z-score(WHZ<-3), expected daly weight is 0.172 - 4. For an individual with SAM but no Oedema (expected daly weight is 0.128)""" + 1. For an individual who is well (No weight is expected/must be 0.0) + 2. For an individual with moderate wasting and oedema (expected daly weight is 0.051) + 3. For an individual with severe wasting and oedema (expected daly weight is 0.172) + 4. For an individual with severe wasting without oedema (expected daly weight is 0.128)""" dur = pd.DateOffset(days=0) popsize = 1 @@ -225,10 +225,17 @@ def test_report_daly_weights(tmpdir): # Get person to use df = sim.population.props person_id = df.index[0] - - # Check when no daly weight is available and person is not undernourished df.at[person_id, 'is_alive'] = True - df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' + + # Check daly weight for not undernourished person (weight is 0.0) + # Reset diagnostic properties + df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' + df.loc[person_id, 'un_am_bilateral_oedema'] = False + df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' + + # Verify diagnosis - an individual should be well + sim.modules["Wasting"].clinical_acute_malnutrition_state(person_id, df) + assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'well' # Report daly weight for this individual daly_weights_reported = sim.modules["Wasting"].report_daly_values() @@ -236,58 +243,58 @@ def test_report_daly_weights(tmpdir): # Verify that individual has no daly weight assert daly_weights_reported.loc[person_id] == 0.0 - # Check daly weight for person with MAM (MAM daly weight is 0.051) get_daly_weights = sim.modules['HealthBurden'].get_daly_weight - # Reset diagnosis and check correct daly weight is given for MAM - df.loc[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' + # Check daly weight for person with moderate wasting and oedema (weight is 0.051) + # Reset diagnostic properties + df.loc[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' df.loc[person_id, 'un_am_bilateral_oedema'] = True - daly_wts['mod_wasting_with_oedema'] = get_daly_weights(sequlae_code=461) - # Verify diagnosis - assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'MAM' - assert df.loc[person_id, 'un_am_bilateral_oedema'] + # Verify diagnosis - an individual should be SAM + sim.modules["Wasting"].clinical_acute_malnutrition_state(person_id, df) + assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' # Report daly weight for this individual daly_weights_reported = sim.modules["Wasting"].report_daly_values() + # Get daly weight of moderate wasting with oedema + daly_wts['mod_wasting_with_oedema'] = get_daly_weights(sequlae_code=461) + # Compare the daly weight of this individual with the daly weight obtained from HealthBurden module assert daly_wts['mod_wasting_with_oedema'] == daly_weights_reported.loc[person_id] - # Check daly weight for person with SAM and oedema (SAM_oedema weight is 0.172) - # Reset diagnosis + # Check daly weight for person with severe wasting and oedema (weight is 0.172) + # Reset diagnostic properties df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' - df.loc[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' df.loc[person_id, 'un_am_bilateral_oedema'] = True # Verify diagnosis - an individual should be SAM - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ<-3' + sim.modules["Wasting"].clinical_acute_malnutrition_state(person_id, df) assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' - assert df.loc[person_id, 'un_am_bilateral_oedema'] # Report daly weight for this individual daly_weights_reported = sim.modules["Wasting"].report_daly_values() - # Get daly weights of SAM with Oedema + # Get daly weight of severe wasting with oedema daly_wts['sev_wasting_with_oedema'] = get_daly_weights(sequlae_code=463) # Compare the daly weight of this individual with the daly weight obtained from HealthBurden module assert daly_wts['sev_wasting_with_oedema'] == daly_weights_reported.loc[person_id] - # Check daly weight for person with SAM no Oedema (SAM no oedema weight is 0.128) + # Check daly weight for person with severe wasting without oedema (weight is 0.128) # Reset diagnosis - df.loc[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' + df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' df.loc[person_id, 'un_am_bilateral_oedema'] = False - # Get day weights of SAM without Oedema - daly_wts['sev_wasting_w/o_oedema'] = get_daly_weights(sequlae_code=462) + # Verify diagnosis - an individual should be SAM + sim.modules["Wasting"].clinical_acute_malnutrition_state(person_id, df) + assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' # Report daly weight for this individual daly_weights_reported = sim.modules["Wasting"].report_daly_values() - # Verify diagnosis - assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' - assert not df.loc[person_id, 'un_am_bilateral_oedema'] + # Get day weight of severe wasting without oedema + daly_wts['sev_wasting_w/o_oedema'] = get_daly_weights(sequlae_code=462) # Compare the daly weight of this individual with the daly weight obtained from HealthBurden module assert daly_wts['sev_wasting_w/o_oedema'] == daly_weights_reported.loc[person_id] From d0c88f494b93856db2e55d8121850b5b64713d20 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 6 Aug 2024 23:56:57 +0100 Subject: [PATCH 092/755] wast: minor changes (comments, debug messages adjusted) --- src/tlo/methods/wasting.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index d6aac6baf3..83b936ed82 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -211,7 +211,7 @@ def read_parameters(self, data_folder): pd.read_csv(Path(self.resourcefilepath) / 'ResourceFile_Wasting.csv') ) - # Register wasting symptom(weight loss) in Symptoms Manager + # Register wasting symptom (weight loss) in Symptoms Manager self.sim.modules['SymptomManager'].register_symptom(Symptom(name=self.wasting_symptom)) def initialise_population(self, population): @@ -591,7 +591,7 @@ def do_when_am_treatment(self, person_id, intervention): :param intervention: """ df = self.sim.population.props - # Log that the treatment is provided: + # Set the date when the treatment is provided: df.at[person_id, 'un_am_tx_start_date'] = self.sim.date if intervention == 'SFP': @@ -956,7 +956,7 @@ def __init__(self, module, person_id): # Get a blank footprint and then edit to define call on resources # of this treatment event the_appt_footprint = self.sim.modules["HealthSystem"].get_blank_appt_footprint() - the_appt_footprint['Under5OPD'] = 1 # This requires one out patient + the_appt_footprint['Under5OPD'] = 1 # This requires one outpatient # Define the necessary information for an HSI self.TREATMENT_ID = 'Undernutrition_Feeding_Supplementary' @@ -967,13 +967,11 @@ def __init__(self, module, person_id): def apply(self, person_id, squeeze_factor): df = self.sim.population.props - # Stop the person from dying of acute malnutrition (if they were - # going to die) + # Stop the person from dying of acute malnutrition (if they were going to die) if not df.at[person_id, 'is_alive']: return - # Do here whatever happens to an individual during this health - # system interaction event + # Do here whatever happens to an individual during this health system interaction event # ~~~~~~~~~~~~~~~~~~~~~~ # Make request for some consumables consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] @@ -990,10 +988,11 @@ def apply(self, person_id, squeeze_factor): df.at[person_id, 'un_am_treatment_type'] = 'CSB++' self.module.do_when_am_treatment(person_id, intervention='SFP') else: - logger.debug(key='debug', data="PkgCode1 is not available, so can't use it.") + logger.debug(key='debug', + data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") def did_not_run(self): - logger.debug(key='debug', data='Undernutrition_Feeding_Supplementary: did not run') + logger.debug(key='debug', data=f'{self.TREATMENT_ID}: did not run') pass @@ -1046,10 +1045,11 @@ def apply(self, person_id, squeeze_factor): df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' self.module.do_when_am_treatment(person_id, intervention='OTC') else: - logger.debug(key='debug', data="consumables not available, so can't use it.") + logger.debug(key='debug', + data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") def did_not_run(self): - logger.debug(key='debug', data="HSI_Undernutrition_Feeding_Outpatient: did not run") + logger.debug(key='debug', data=f'{self.TREATMENT_ID}: did not run') pass @@ -1097,10 +1097,11 @@ def apply(self, person_id, squeeze_factor): df.at[person_id, 'un_am_treatment_type'] = 'inpatient_care' self.module.do_when_am_treatment(person_id, intervention='ITC') else: - logger.debug(key='debug', data="consumables not available, so can't use it.") + logger.debug(key='debug', + data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") def did_not_run(self): - logger.debug(key='debug', data='HSI_inpatient_care_for_complicated_SAM: did not run') + logger.debug(key='debug', data=f'{self.TREATMENT_ID}: did not run') pass From daef56b45208272f1e45813b2322cda3b9b87178 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 8 Aug 2024 16:45:44 +0100 Subject: [PATCH 093/755] wast: minor changes (params descriptions adjusted) --- src/tlo/methods/wasting.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 83b936ed82..e362999178 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -121,17 +121,19 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ >= -2'), 'proportion_WHZ<-3_with_MUAC<115mm': Parameter( - Types.REAL, 'proportion of severe wasting with MUAC < 115mm'), + Types.REAL, 'proportion of individuals with severe wasting who have MUAC < 115 mm'), 'proportion_-3<=WHZ<-2_with_MUAC<115mm': Parameter( - Types.REAL, 'proportion of moderate wasting with MUAC < 115mm'), + Types.REAL, 'proportion of individuals with moderate wasting who have MUAC < 115 mm'), 'proportion_-3<=WHZ<-2_with_MUAC_[115-125)mm': Parameter( - Types.REAL, 'proportion of moderate wasting with 115 mm ≤ MUAC < 125mm'), + Types.REAL, 'proportion of individuals with moderate wasting who have 115 mm ≤ MUAC < 125 mm'), 'proportion_mam_with_MUAC_[115-125)mm_and_normal_whz': Parameter( - Types.REAL, 'proportion of MAM cases with 115 mm ≤ MUAC < 125 mm and normal/mild WHZ'), + Types.REAL, 'proportion of individuals with MAM who have 115 mm ≤ MUAC < 125 mm and normal/mild' + ' WHZ'), 'proportion_mam_with_MUAC_[115-125)mm_and_-3<=WHZ<-2': Parameter( - Types.REAL, 'proportion of MAM cases with both 115 mm ≤ MUAC < 125 mm and moderate wasting'), + Types.REAL, 'proportion of individuals with MAM who have both 115 mm ≤ MUAC < 125 mm and moderate' + ' wasting'), 'proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC': Parameter( - Types.REAL, 'proportion of MAM cases with moderate wasting and normal MUAC'), + Types.REAL, 'proportion of individuals with MAM who have moderate wasting and normal MUAC'), # bilateral oedema 'prevalence_nutritional_oedema': Parameter( Types.REAL, 'prevalence of nutritional oedema in children under 5 in Malawi'), From c73742c3086e107fdaa8c9574ab648a7e2c3a009 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 9 Aug 2024 18:25:24 +0100 Subject: [PATCH 094/755] wast & RF_wast: probs corrected --- resources/ResourceFile_Wasting.csv | 4 ++-- src/tlo/methods/wasting.py | 17 ++++++++++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 7c5833bd0f..72352ead6d 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:187dc5d77671837777430e32ebb1d4cba7c14ff6f81566b72032b8da0c34d6ad -size 2688 +oid sha256:c340fe4708e9d4edb8bd7923c372f3fc616ba5d06725befe57def02dd6c5e168 +size 2733 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index e362999178..d59f65a8f0 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -137,8 +137,10 @@ class Wasting(Module, GenericFirstAppointmentsMixin): # bilateral oedema 'prevalence_nutritional_oedema': Parameter( Types.REAL, 'prevalence of nutritional oedema in children under 5 in Malawi'), + 'proportion_WHZ<-2_with_oedema': Parameter( + Types.REAL, 'proportion of individuals with wasting (moderate or severe) who have oedema'), 'proportion_oedema_with_WHZ<-2': Parameter( - Types.REAL, 'proportion of oedematous malnutrition with concurrent wasting'), + Types.REAL, 'proportion of individuals with oedema who are wasted (moderately or severely)'), # treatment 'coverage_supplementary_feeding_program': Parameter( Types.REAL, 'coverage of supplementary feeding program for MAM in health centres'), @@ -383,6 +385,8 @@ def nutritional_oedema_present(self, idx): This function applies the probability of bilateral oedema present in wasting and non-wasted cases :param idx: index of children under 5, or person_id """ + if len(idx) == 0: + return df = self.sim.population.props p = self.parameters @@ -394,12 +398,19 @@ def nutritional_oedema_present(self, idx): # oedema among wasted children oedema_in_wasted_children = self.rng.random_sample(size=len( - children_with_wasting)) < p['prevalence_nutritional_oedema'] * p['proportion_oedema_with_WHZ<-2'] + children_with_wasting)) < p['proportion_WHZ<-2_with_oedema'] df.loc[children_with_wasting, 'un_am_bilateral_oedema'] = oedema_in_wasted_children # oedema among non-wasted children + if len(children_without_wasting) == 0: + return + # proportion_normalWHZ_with_oedema: P(oedema|WHZ>=-2) = + # P(oedema & WHZ>=-2) / P(WHZ>=-2) = P(oedema) * [1 -P(WHZ<-2|oedema)] / (#WHZ>=-2 / #all under 5) + proportion_normal_whz_with_oedema = \ + p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) / \ + (len(children_without_wasting) / len(idx)) oedema_in_non_wasted = self.rng.random_sample(size=len( - children_without_wasting)) < p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) + children_without_wasting)) < proportion_normal_whz_with_oedema df.loc[children_without_wasting, 'un_am_bilateral_oedema'] = oedema_in_non_wasted def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): From 5baa6de39aaa7fa1302814dc9ee428fd256bf602 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 9 Aug 2024 18:27:14 +0100 Subject: [PATCH 095/755] wast & test_wast: PollingEvent name specified --- src/tlo/methods/wasting.py | 8 ++++---- tests/test_wasting.py | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index d59f65a8f0..d2f271749c 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -275,7 +275,7 @@ def initialise_simulation(self, sim): """ # schedule wasting pool event - sim.schedule_event(WastingPollingEvent(self), sim.date + DateOffset(months=3)) + sim.schedule_event(IncidenceWastingPollingEvent(self), sim.date + DateOffset(months=3)) # schedule wasting logging event sim.schedule_event(WastingLoggingEvent(self), sim.date + DateOffset(months=12)) @@ -668,7 +668,7 @@ def do_when_am_treatment(self, person_id, intervention): date=df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=4)) -class WastingPollingEvent(RegularEvent, PopulationScopeEventMixin): +class IncidenceWastingPollingEvent(RegularEvent, PopulationScopeEventMixin): """ Regular event that determines new cases of wasting (WHZ < -2) to the under-5 population, and schedules individual incident cases to represent onset. It determines those who will progress to severe wasting @@ -709,7 +709,7 @@ def apply(self, population): # Add these incident cases to the tracker for person in not_wasted_idx: wasting_severity = df.at[person, 'un_WHZ_category'] - age_group = WastingPollingEvent.AGE_GROUPS.get(df.loc[person].age_years, '5+y') + age_group = IncidenceWastingPollingEvent.AGE_GROUPS.get(df.loc[person].age_years, '5+y') # if wasting_severity != 'WHZ>=-2': self.module.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) @@ -796,7 +796,7 @@ def apply(self, person_id): # ------------------------------------------------------------------------------------------- # Add this incident case to the tracker wasting_severity = df.at[person_id, 'un_WHZ_category'] - age_group = WastingPollingEvent.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') + age_group = IncidenceWastingPollingEvent.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') if wasting_severity != 'WHZ>=-2': m.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 78b9e1ef21..ffa5b92cc8 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -28,11 +28,11 @@ ClinicalAcuteMalnutritionRecoveryEvent, HSI_Wasting_InpatientCareForComplicated_SAM, HSI_Wasting_OutpatientTherapeuticProgramme_SAM, + IncidenceWastingPollingEvent, ProgressionSevereWastingEvent, SevereAcuteMalnutritionDeathEvent, UpdateToMAM, WastingNaturalRecoveryEvent, - WastingPollingEvent, ) # Path to the resource files used by the disease and intervention methods @@ -196,7 +196,7 @@ def test_wasting_incidence(tmpdir): sim.modules['Wasting'].wasting_models.wasting_incidence_lm = LinearModel.multiplicative() # Run polling event: check that all children should now have moderate wasting: - polling = WastingPollingEvent(sim.modules['Wasting']) + polling = IncidenceWastingPollingEvent(sim.modules['Wasting']) polling.apply(sim.population) # Check properties of individuals: should now be moderately wasted @@ -323,7 +323,7 @@ def test_recovery_moderate_wasting(tmpdir): sim.modules['Wasting'].wasting_models.wasting_incidence_lm = LinearModel.multiplicative() # Run Wasting Polling event: This event should cause all young children to be moderate wasting - polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling = IncidenceWastingPollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) # Check properties of this individual: should now be moderately wasted @@ -391,7 +391,7 @@ def test_recovery_severe_wasting_without_complications(tmpdir): wmodule.parameters['prob_mam_after_care'] = 1.0 # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling = IncidenceWastingPollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) # Check properties of this individual: should now be moderately wasted @@ -680,7 +680,7 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling = IncidenceWastingPollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) # Check properties of this individual: (should now be moderately wasted without progression to severe) @@ -751,7 +751,7 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' # Run Wasting Polling event to get new incident cases: - polling = WastingPollingEvent(module=sim.modules['Wasting']) + polling = IncidenceWastingPollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) From 211544149c82131a859df2bd85ef1466c74e8dc2 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 9 Aug 2024 18:29:35 +0100 Subject: [PATCH 096/755] wast: MUAC, oedema, clinical state of acute malnutrition, and complications if SAM updated only when WHZ changed --- src/tlo/methods/wasting.py | 68 ++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 40 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index d2f271749c..0221012801 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -266,7 +266,8 @@ def initialise_population(self, population): # ------------------------------------------------------------------ # # # # # # Give MUAC category, presence of oedema, and determine acute malnutrition state # # # # # - self.population_poll_clinical_am(df) + index_under5 = df.index[df.is_alive & (df.age_exact_years < 5)] + self.clinical_am_poll(index_under5) def initialise_simulation(self, sim): """Prepares for simulation: @@ -480,28 +481,31 @@ def date_of_outcome_for_untreated_wasting(self, person_id): date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_sev_wasting) return date_of_outcome - def population_poll_clinical_am(self, population): + def clinical_am_poll(self, idx): """ - Update at the population level other anthropometric indices and clinical signs (MUAC, oedema, + When WHZ changed, update other anthropometric indices and clinical signs (MUAC, oedema, medical complications) that determine the clinical state of acute malnutrition. This will include both wasted and non-wasted children with other signs of acute malnutrition. - :param population: population dataframe + :param idx: index of children or person_id less than 5 years old """ - df = population + df = self.sim.population.props + + # if idx only person_id, transform into an Index object + if not isinstance(idx, pd.Index): + idx = pd.Index([idx]) # give MUAC measurement category for all WHZ, including well # nourished children ----- for whz in ['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2']: - index_6_59mo_by_whz = df.index[df.is_alive & (df.age_exact_years.between(0.5, 5, inclusive='left')) - & (df.un_WHZ_category == whz)] + index_6_59mo_by_whz = idx.intersection(df.index[df.age_exact_years.between(0.5, 5, inclusive='left') + & (df.un_WHZ_category == whz)]) self.muac_cutoff_by_WHZ(idx=index_6_59mo_by_whz, whz=whz) # determine the presence of bilateral oedema / oedematous malnutrition - index_under5 = df.index[df.is_alive & (df.age_exact_years < 5)] - self.nutritional_oedema_present(idx=index_under5) + self.nutritional_oedema_present(idx=idx) # determine the clinical acute malnutrition state ----- - for person_id in index_under5: + for person_id in idx: self.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) def report_daly_values(self): @@ -712,7 +716,9 @@ def apply(self, population): age_group = IncidenceWastingPollingEvent.AGE_GROUPS.get(df.loc[person].age_years, '5+y') # if wasting_severity != 'WHZ>=-2': self.module.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) - + # Update properties related to clinical acute malnutrition + # (MUAC, oedema, clinical state of acute malnutrition, and check complications if SAM) + self.module.clinical_am_poll(not_wasted_idx[incidence_of_wasting]) # --------------------------------------------------------------------- # # # PROGRESS TO SEVERE WASTING # # # # # # # # # # # # # # # # # # @@ -749,16 +755,6 @@ def apply(self, population): self.sim.schedule_event(event=WastingNaturalRecoveryEvent( module=self.module, person_id=person), date=outcome_date) - # ------------------------------------------------------------------------------------------ - # ## UPDATE PROPERTIES RELATED TO CLINICAL ACUTE MALNUTRITION # # # # - # ------------------------------------------------------------------------------------------ - # This applies to all children under 5 - - # give MUAC measurement category for all WHZ, including well nourished children ----- - # determine the presence of bilateral oedema / oedematous malnutrition - # determine the clinical state of acute malnutrition, and check complications if SAM - self.module.population_poll_clinical_am(df) - class ProgressionSevereWastingEvent(Event, IndividualScopeEventMixin): """ @@ -774,6 +770,9 @@ def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe m = self.module + if (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'age_exact_years'] >= 5): + return + # before progression to severe wasting, check those who started # supplementary feeding programme before today if df.at[person_id, 'un_last_wasting_date_of_onset'] < \ @@ -783,15 +782,10 @@ def apply(self, person_id): # continue with progression to severe if not treated/recovered else: # update properties + # - WHZ df.at[person_id, 'un_WHZ_category'] = 'WHZ<-3' - - # Give MUAC measurement category for WHZ < -3 - if df.at[person_id, 'age_exact_years'] > 0.5: - m.muac_cutoff_by_WHZ(idx=df.loc[[person_id]].index, whz='WHZ<-3') - - # update the clinical state of acute malnutrition, and check - # complications if SAM - m.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) + # - MUAC, oedema, clinical state of acute malnutrition, and check complications if SAM + self.module.clinical_am_poll(person_id) # ------------------------------------------------------------------------------------------- # Add this incident case to the tracker @@ -838,24 +832,18 @@ def __init__(self, module, person_id): def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe - m = self.module if not df.at[person_id, 'is_alive']: return df.at[person_id, 'un_am_recovery_date'] = self.sim.date + # update properties + # - WHZ df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished + # - MUAC, oedema, clinical state of acute malnutrition, and check complications if SAM + self.module.clinical_am_poll(person_id) - # For cases with normal WHZ, attribute probability of MUAC category - if df.at[person_id, 'age_exact_years'] > 0.5: - m.muac_cutoff_by_WHZ(idx=df.loc[[person_id]].index, whz='WHZ>=-2') - - # Note assumption: prob of oedema remained the same as applied in - # wasting onset - - # update the clinical acute malnutrition state - m.clinical_acute_malnutrition_state(person_id=person_id, pop_dataframe=df) - if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': + if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well': # this will clear all wasting symptoms self.sim.modules["SymptomManager"].clear_symptoms( person_id=person_id, disease_module=self.module From 42b9bf5ea7d865e6388271aa9c5a329b35a3bf42 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 24 Aug 2024 00:32:43 +0100 Subject: [PATCH 097/755] wast & test_wast: natural recovery -prepared for future (to improve also severe wasting, not used yet), -clear symptoms moved to clinical_acute_malnutrition_state(), -recovery date only if recovered; initial condition checks updated; predict() use updated to be consistent with other usages; var/fn names updated; minor (comments/fnc description updated) --- src/tlo/methods/wasting.py | 126 +++++++++++++++++++------------------ tests/test_wasting.py | 9 +-- 2 files changed, 70 insertions(+), 65 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 0221012801..1d5aea8051 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -141,7 +141,7 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.REAL, 'proportion of individuals with wasting (moderate or severe) who have oedema'), 'proportion_oedema_with_WHZ<-2': Parameter( Types.REAL, 'proportion of individuals with oedema who are wasted (moderately or severely)'), - # treatment + # treatment/interventions 'coverage_supplementary_feeding_program': Parameter( Types.REAL, 'coverage of supplementary feeding program for MAM in health centres'), 'coverage_outpatient_therapeutic_care': Parameter( @@ -152,7 +152,7 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.REAL, 'probability of returning to MAM after seeking care'), 'prob_death_after_care': Parameter( Types.REAL, 'probability of dying after seeking care'), - # recovery + # recovery due to treatment/interventions 'recovery_rate_with_standard_RUTF': Parameter( Types.REAL, 'probability of recovery from wasting following treatment with standard RUTF'), 'recovery_rate_with_soy_RUSF': Parameter( @@ -248,14 +248,16 @@ def initialise_population(self, population): high_bound_age_in_years = (1 + high_bound_mos) / 12.0 # linear model external variables agegp = f'{low_bound_mos}_{high_bound_mos}mo' - mask = (df.is_alive & df.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, - inclusive='left')) - prevalence_of_wasting = self.wasting_models.get_wasting_prevalence(agegp=agegp).predict(df.loc[mask]) + children_of_agegp = df.loc[df.is_alive & df.age_exact_years.between( + low_bound_age_in_years, high_bound_age_in_years, inclusive='left' + )] # apply prevalence of wasting and categorise into moderate (-3 <= WHZ < -2) or severe (WHZ < -3) wasting - wasted = self.rng.random_sample(len(prevalence_of_wasting)) < prevalence_of_wasting + wasted = self.wasting_models.get_wasting_prevalence(agegp=agegp).predict( + children_of_agegp, self.rng + ) probability_of_severe = self.get_prob_severe_wasting_or_odds_wasting(agegp=agegp, get_odds=False) - for idx in prevalence_of_wasting.index[wasted]: + for idx in children_of_agegp.index[wasted]: wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], p=[probability_of_severe, 1 - probability_of_severe]) df.at[idx, 'un_WHZ_category'] = wasted_category @@ -267,7 +269,7 @@ def initialise_population(self, population): # ------------------------------------------------------------------ # # # # # # Give MUAC category, presence of oedema, and determine acute malnutrition state # # # # # index_under5 = df.index[df.is_alive & (df.age_exact_years < 5)] - self.clinical_am_poll(index_under5) + self.clinical_signs_acute_malnutrition(index_under5) def initialise_simulation(self, sim): """Prepares for simulation: @@ -448,6 +450,10 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): df.at[person_id, 'un_sam_with_complications'] = False else: df.at[person_id, 'un_sam_with_complications'] = False + # clear all wasting symptoms + self.sim.modules["SymptomManager"].clear_symptoms( + person_id=person_id, disease_module=self + ) assert not (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') & \ (df.at[person_id, 'un_sam_with_complications']) @@ -472,20 +478,20 @@ def date_of_outcome_for_untreated_wasting(self, person_id): date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_mod_wasting) return date_of_outcome - # severe wasting (for death, or recovery to moderate wasting) ----- + # severe wasting (recovery to moderate wasting) ----- if whz_category == 'WHZ<-3': - # determine the duration of SAM episode + # determine the duration of severe wasting episode duration_sev_wasting = int(max(p['min_days_duration_of_wasting'], p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'])) - # Allocate a date of outcome (death, or recovery) + # Allocate a date of outcome (recovery) date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_sev_wasting) return date_of_outcome - def clinical_am_poll(self, idx): + def clinical_signs_acute_malnutrition(self, idx): """ - When WHZ changed, update other anthropometric indices and clinical signs (MUAC, oedema, - medical complications) that determine the clinical state of acute malnutrition. This will include both wasted - and non-wasted children with other signs of acute malnutrition. + When WHZ changed, update other anthropometric indices and clinical signs (MUAC, oedema) that determine the + clinical state of acute malnutrition. If SAM, update medical complications. If not SAM, clear symptoms. + This will include both wasted and non-wasted children with other signs of acute malnutrition. :param idx: index of children or person_id less than 5 years old """ df = self.sim.population.props @@ -494,8 +500,7 @@ def clinical_am_poll(self, idx): if not isinstance(idx, pd.Index): idx = pd.Index([idx]) - # give MUAC measurement category for all WHZ, including well - # nourished children ----- + # give MUAC measurement category for all WHZ, including normal WHZ ----- for whz in ['WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2']: index_6_59mo_by_whz = idx.intersection(df.index[df.age_exact_years.between(0.5, 5, inclusive='left') & (df.un_WHZ_category == whz)]) @@ -696,7 +701,7 @@ def apply(self, population): df = population.props rng = self.module.rng - # # # INCIDENCE OF WASTING # # # # # # # # # # # # # # # # # # # # # + # # # INCIDENCE OF MODERATE WASTING # # # # # # # # # # # # # # # # # # # # # # Determine who will be onset with wasting among those who are not currently wasted ------------- not_wasted = df.loc[df.is_alive & (df.age_exact_years < 5) & ( df.un_WHZ_category == 'WHZ>=-2')] @@ -709,7 +714,7 @@ def apply(self, population): df.loc[not_wasted_idx[incidence_of_wasting], 'un_WHZ_category'] = '-3<=WHZ<-2' # start without treatment df.loc[not_wasted_idx[incidence_of_wasting], 'un_am_treatment_type'] = 'none' - # -------------------------------------------------------------------- + # ------------------------------------------------------------------------------------------- # Add these incident cases to the tracker for person in not_wasted_idx: wasting_severity = df.at[person, 'un_WHZ_category'] @@ -717,16 +722,17 @@ def apply(self, population): # if wasting_severity != 'WHZ>=-2': self.module.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) # Update properties related to clinical acute malnutrition - # (MUAC, oedema, clinical state of acute malnutrition, and check complications if SAM) - self.module.clinical_am_poll(not_wasted_idx[incidence_of_wasting]) - # --------------------------------------------------------------------- + # (MUAC, oedema, clinical state of acute malnutrition and if SAM complications; clear symptoms if not SAM) + self.module.clinical_signs_acute_malnutrition(not_wasted_idx[incidence_of_wasting]) + # ------------------------------------------------------------------------------------------- # # # PROGRESS TO SEVERE WASTING # # # # # # # # # # # # # # # # # # # Determine those that will progress to severe wasting (WHZ < -3) and schedule progression event --------- mod_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == '-3<=WHZ<-2')] progression_severe_wasting = self.module.wasting_models.severe_wasting_progression_lm.predict( - mod_wasting, rng=rng, squeeze_single_row_output=False) + mod_wasting, rng=rng, squeeze_single_row_output=False + ) # determine those individuals who will progress to severe wasting and time of progression for person in mod_wasting.index[progression_severe_wasting]: @@ -770,7 +776,8 @@ def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe m = self.module - if (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'age_exact_years'] >= 5): + if ((not df.at[person_id, 'is_alive']) or (df.at[person_id, 'age_exact_years'] >= 5) + or df.at[person_id, 'un_WHZ_category'] != '-3<=WHZ<-2'): return # before progression to severe wasting, check those who started @@ -778,14 +785,14 @@ def apply(self, person_id): if df.at[person_id, 'un_last_wasting_date_of_onset'] < \ df.at[person_id, 'un_am_tx_start_date'] < self.sim.date: return - + # # # INCIDENCE OF SEVERE WASTING # # # # # # # # # # # # # # # # # # # # # # continue with progression to severe if not treated/recovered else: # update properties # - WHZ df.at[person_id, 'un_WHZ_category'] = 'WHZ<-3' - # - MUAC, oedema, clinical state of acute malnutrition, and check complications if SAM - self.module.clinical_am_poll(person_id) + # - MUAC, oedema, clinical state of acute malnutrition, complications + self.module.clinical_signs_acute_malnutrition(person_id) # ------------------------------------------------------------------------------------------- # Add this incident case to the tracker @@ -807,12 +814,12 @@ def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe # The event should not run if the person is not currently alive - if not df.at[person_id, 'is_alive']: + if ((not df.at[person_id, 'is_alive']) + or df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM'): return # # Check if this person should still die from SAM: - if pd.isnull(df.at[person_id, 'un_am_recovery_date']) & \ - (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM'): + if pd.isnull(df.at[person_id, 'un_am_recovery_date']): # Cause the death to happen immediately df.at[person_id, 'un_sam_death_date'] = self.sim.date self.sim.modules['Demography'].do_death( @@ -823,8 +830,9 @@ def apply(self, person_id): class WastingNaturalRecoveryEvent(Event, IndividualScopeEventMixin): """ - This event sets wasting properties back to normal state, based on home care/ improvement without - interventions, low-moderate MUAC categories oedema may or may not be present + This event improves wasting by 1 SD, based on home care/improvement without interventions. + MUAC, oedema, clinical state of acute malnutrition, and if SAM complications are updated, + and symptoms cleared if not SAM. """ def __init__(self, module, person_id): @@ -833,21 +841,24 @@ def __init__(self, module, person_id): def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe - if not df.at[person_id, 'is_alive']: + if (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2'): return - df.at[person_id, 'un_am_recovery_date'] = self.sim.date - # update properties - # - WHZ - df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished - # - MUAC, oedema, clinical state of acute malnutrition, and check complications if SAM - self.module.clinical_am_poll(person_id) - + whz = df.at[person_id, 'un_WHZ_category'] + if whz == '-3<=WHZ<-2': + # improve WHZ + df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished + else: + # whz == 'WHZ<-3' + # improve WHZ + df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' # moderate wasting + + # update MUAC, oedema, clinical state of acute malnutrition and if SAM complications, + # clear symptoms if not SAM + self.module.clinical_signs_acute_malnutrition(person_id) + # set recovery date if recovered if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well': - # this will clear all wasting symptoms - self.sim.modules["SymptomManager"].clear_symptoms( - person_id=person_id, disease_module=self.module - ) + df.at[person_id, 'un_am_recovery_date'] = self.sim.date class ClinicalAcuteMalnutritionRecoveryEvent(Event, IndividualScopeEventMixin): @@ -895,17 +906,13 @@ def apply(self, person_id): rng = m.rng p = m.parameters - if not df.at[person_id, 'is_alive']: + if (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM'): return - # if not df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM': - # return - # # TODO: check if this is correct before added (maybe it should be == 'SAM'? - # For cases with normal WHZ and other acute malnutrition signs: - # oedema, or low muac - do not change the WHZ + # oedema, or low MUAC - do not change the WHZ if df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2': - # mam by muac only + # MAM by MUAC only df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' # TODO: I think this changes the proportions below as some of the cases will be issued here @@ -968,7 +975,6 @@ def __init__(self, module, person_id): def apply(self, person_id, squeeze_factor): df = self.sim.population.props - # Stop the person from dying of acute malnutrition (if they were going to die) if not df.at[person_id, 'is_alive']: return @@ -1020,8 +1026,6 @@ def __init__(self, module, person_id): def apply(self, person_id, squeeze_factor): df = self.sim.population.props - # Stop the person from dying of acute malnutrition (if they were - # going to die) if not df.at[person_id, 'is_alive']: return @@ -1149,7 +1153,7 @@ def get_wasting_incidence(self) -> LinearModel: """ df = self.module.sim.population.props - def unscaled_wasting_lm(intercept: Union[float, int] = 1.0) -> LinearModel: + def unscaled_wasting_incidence_lm(intercept: Union[float, int] = 1.0) -> LinearModel: # linear model to predict the incidence of wasting return LinearModel( LinearModelType.MULTIPLICATIVE, @@ -1174,14 +1178,14 @@ def unscaled_wasting_lm(intercept: Union[float, int] = 1.0) -> LinearModel: lambda x: 1 if x == 1 else (x - 1) ** (self.params['rr_wasting_wealth_level'])), ) - unscaled_lm = unscaled_wasting_lm() + unscaled_lm = unscaled_wasting_incidence_lm() target_mean = self.params['base_inc_rate_wasting_by_agegp'][2] # base inc rate for 12-23mo old actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1) & (df.un_WHZ_category == 'WHZ>=-2')]).mean() scaled_intercept = 1.0 * (target_mean / actual_mean) \ if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else 1.0 - scaled_wasting_incidence_lm = unscaled_wasting_lm(intercept=scaled_intercept) + scaled_wasting_incidence_lm = unscaled_wasting_incidence_lm(intercept=scaled_intercept) return scaled_wasting_incidence_lm def get_wasting_prevalence(self, agegp: str) -> LinearModel: @@ -1191,7 +1195,7 @@ def get_wasting_prevalence(self, agegp: str) -> LinearModel: """ df = self.module.sim.population.props - def make_linear_model_wasting(intercept: Union[float, int]) -> LinearModel: + def unscaled_wasting_prevalence_lm(intercept: Union[float, int]) -> LinearModel: return LinearModel( LinearModelType.LOGISTIC, intercept, # baseline odds: get_odds_wasting(agegp=agegp) @@ -1212,14 +1216,14 @@ def make_linear_model_wasting(intercept: Union[float, int]) -> LinearModel: ) get_odds_wasting = self.module.get_prob_severe_wasting_or_odds_wasting(agegp=agegp, get_odds=True) - unscaled_lm = make_linear_model_wasting(intercept=get_odds_wasting) + unscaled_lm = unscaled_wasting_prevalence_lm(intercept=get_odds_wasting) target_mean = self.module.get_prob_severe_wasting_or_odds_wasting(agegp='12_23mo', get_odds=True) actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1)]).mean() scaled_intercept = get_odds_wasting * (target_mean / actual_mean) if \ (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else get_odds_wasting - scaled_lm = make_linear_model_wasting(intercept=scaled_intercept) + scaled_wasting_prevalence_lm = unscaled_wasting_prevalence_lm(intercept=scaled_intercept) - return scaled_lm + return scaled_wasting_prevalence_lm class WastingLoggingEvent(RegularEvent, PopulationScopeEventMixin): diff --git a/tests/test_wasting.py b/tests/test_wasting.py index ffa5b92cc8..0cd76f61ee 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -186,7 +186,7 @@ def test_wasting_incidence(tmpdir): sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) - # reset properties of all individuals so that they are don't have wasting + # reset properties of all individuals so that they are not wasted df = sim.population.props df.loc[df.is_alive, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished df.loc[df.is_alive, 'un_ever_wasted'] = False @@ -350,7 +350,10 @@ def test_recovery_moderate_wasting(tmpdir): # Check properties of this individual person = df.loc[person_id] assert person['un_WHZ_category'] == 'WHZ>=-2' - assert person['un_am_recovery_date'] == sim.date + if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well': + assert person['un_am_recovery_date'] == sim.date + else: + assert pd.isnull(df.at[person_id, 'un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) @@ -746,9 +749,7 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] - # Let this person have severe wasting df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' # Run Wasting Polling event to get new incident cases: polling = IncidenceWastingPollingEvent(module=sim.modules['Wasting']) From 0770b133be41d76df16b9937d5fc9d9df4dad817 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 24 Aug 2024 00:48:38 +0100 Subject: [PATCH 098/755] wast, RF_Wast & test_wast: treatment -lengths as parameters, -var names updated, -duplicated code of treatments for SAM simplified; event names updated to follow naming convention --- resources/ResourceFile_Wasting.csv | 4 +- src/tlo/methods/wasting.py | 114 ++++++++++++++--------------- tests/test_wasting.py | 49 +++++++------ 3 files changed, 83 insertions(+), 84 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 72352ead6d..9d9243dfa0 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c340fe4708e9d4edb8bd7923c372f3fc616ba5d06725befe57def02dd6c5e168 -size 2733 +oid sha256:625f7525702ab856b8b84147009767ccd7024298a1d6e29a9fb07ba32c662e0b +size 2835 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 1d5aea8051..7886ef8c83 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -161,6 +161,15 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.REAL, 'probability of recovery from wasting following treatment with CSB++'), 'recovery_rate_with_inpatient_care': Parameter( Types.REAL, 'probability of recovery from wasting following treatment with inpatient care'), + 'tx_length_weeks_SuppFeedingMAM': Parameter( + Types.REAL, 'number of weeks the patient receives treatment in the Supplementary Feeding ' + 'Programme for MAM before being discharged'), + 'tx_length_weeks_OutpatientSAM': Parameter( + Types.REAL, 'number of weeks the patient receives treatment in the Outpatient Therapeutic ' + 'Programme for SAM before being discharged if they do not die beforehand'), + 'tx_length_weeks_InpatientSAM': Parameter( + Types.REAL, 'number of weeks the patient receives treatment in the Inpatient Care for complicated' + ' SAM before being discharged if they do not die beforehand'), } PROPERTIES = { @@ -278,7 +287,7 @@ def initialise_simulation(self, sim): """ # schedule wasting pool event - sim.schedule_event(IncidenceWastingPollingEvent(self), sim.date + DateOffset(months=3)) + sim.schedule_event(WastingIncidencePollingEvent(self), sim.date + DateOffset(months=3)) # schedule wasting logging event sim.schedule_event(WastingLoggingEvent(self), sim.date + DateOffset(months=12)) @@ -613,71 +622,62 @@ def do_when_am_treatment(self, person_id, intervention): :param intervention: """ df = self.sim.population.props + p = self.parameters # Set the date when the treatment is provided: df.at[person_id, 'un_am_tx_start_date'] = self.sim.date if intervention == 'SFP': - mam_recovery = self.wasting_models.acute_malnutrition_recovery_mam_lm.predict( - df.loc[[person_id]], self.rng) + mam_full_recovery = self.wasting_models.acute_malnutrition_recovery_mam_lm.predict( + df.loc[[person_id]], self.rng + ) - if mam_recovery: + if mam_full_recovery: # schedule recovery date - self.sim.schedule_event(event=ClinicalAcuteMalnutritionRecoveryEvent( - module=self, person_id=person_id), - date=df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=3)) + self.sim.schedule_event( + event=WastingClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), + date=(df.at[person_id, 'un_am_tx_start_date'] + + DateOffset(weeks=p['tx_length_weeks_SuppFeedingMAM'])) + ) # cancel progression date (in ProgressionEvent) else: # remained MAM return - if intervention == 'OTC': - sam_recovery = self.wasting_models.acute_malnutrition_recovery_sam_lm.predict( - df.loc[[person_id]], self.rng) - if sam_recovery: - # schedule recovery date - self.sim.schedule_event(event=ClinicalAcuteMalnutritionRecoveryEvent( - module=self, person_id=person_id), - date=df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=3)) - # cancel death date - df.at[person_id, 'un_sam_death_date'] = pd.NaT + elif (intervention == 'OTC') or (intervention == 'ITC'): + if intervention == 'OTC': + outcome_date = (df.at[person_id, 'un_am_tx_start_date'] + + DateOffset(weeks=p['tx_length_weeks_OutpatientSAM'])) else: - outcome = self.rng.choice(['remained_mam', 'death'], p=[self.parameters['prob_mam_after_care'], - self.parameters['prob_death_after_care']]) - if outcome == 'death': - self.sim.schedule_event(event=SevereAcuteMalnutritionDeathEvent( - module=self, person_id=person_id), - date=df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=3)) + outcome_date = (df.at[person_id, 'un_am_tx_start_date'] + + DateOffset(weeks=p['tx_length_weeks_InpatientSAM'])) - else: - self.sim.schedule_event(event=UpdateToMAM(module=self, person_id=person_id), - date=df.at[person_id, 'un_am_tx_start_date'] + - DateOffset(weeks=3)) - - if intervention == 'ITC': - sam_recovery = self.wasting_models.acute_malnutrition_recovery_sam_lm.predict( - df.loc[[person_id]], self.rng) - if sam_recovery: - # schedule recovery date - self.sim.schedule_event(event=ClinicalAcuteMalnutritionRecoveryEvent( - module=self, person_id=person_id), - date=df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=4)) + sam_full_recovery = self.wasting_models.acute_malnutrition_recovery_sam_lm.predict( + df.loc[[person_id]], self.rng + ) + if sam_full_recovery: + # schedule full recovery + self.sim.schedule_event( + event=WastingClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), + date=outcome_date + ) # cancel death date df.at[person_id, 'un_sam_death_date'] = pd.NaT else: - outcome = self.rng.choice(['remained_mam', 'death'], - p=[self.parameters['prob_mam_after_care'], self.parameters[ - 'prob_death_after_care']]) + outcome = self.rng.choice(['recovery_to_mam', 'death'], p=[self.parameters['prob_mam_after_care'], + self.parameters['prob_death_after_care']]) if outcome == 'death': - self.sim.schedule_event(event=SevereAcuteMalnutritionDeathEvent( - module=self, person_id=person_id), - date=df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=4)) - else: self.sim.schedule_event( - event=UpdateToMAM(module=self, person_id=person_id), - date=df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=4)) + event=WastingSevereAcuteMalnutritionDeathEvent(module=self, person_id=person_id), + date=outcome_date + ) + else: + self.sim.schedule_event(event=WastingUpdateToMAM(module=self, person_id=person_id), + date=outcome_date) + # cancel death date + df.at[person_id, 'un_sam_death_date'] = pd.NaT -class IncidenceWastingPollingEvent(RegularEvent, PopulationScopeEventMixin): +class WastingIncidencePollingEvent(RegularEvent, PopulationScopeEventMixin): """ Regular event that determines new cases of wasting (WHZ < -2) to the under-5 population, and schedules individual incident cases to represent onset. It determines those who will progress to severe wasting @@ -718,7 +718,7 @@ def apply(self, population): # Add these incident cases to the tracker for person in not_wasted_idx: wasting_severity = df.at[person, 'un_WHZ_category'] - age_group = IncidenceWastingPollingEvent.AGE_GROUPS.get(df.loc[person].age_years, '5+y') + age_group = WastingIncidencePollingEvent.AGE_GROUPS.get(df.loc[person].age_years, '5+y') # if wasting_severity != 'WHZ>=-2': self.module.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) # Update properties related to clinical acute malnutrition @@ -740,12 +740,12 @@ def apply(self, population): # schedule severe wasting WHZ < -3 onset if outcome_date <= self.sim.date: # schedule severe wasting (WHZ < -3) onset today - self.sim.schedule_event(event=ProgressionSevereWastingEvent( + self.sim.schedule_event(event=WastingProgressionToSevereEvent( module=self.module, person_id=person), date=self.sim.date) else: # schedule severe wasting WHZ < -3 onset according to duration self.sim.schedule_event( - event=ProgressionSevereWastingEvent( + event=WastingProgressionToSevereEvent( module=self.module, person_id=person), date=outcome_date) # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # @@ -762,7 +762,7 @@ def apply(self, population): module=self.module, person_id=person), date=outcome_date) -class ProgressionSevereWastingEvent(Event, IndividualScopeEventMixin): +class WastingProgressionToSevereEvent(Event, IndividualScopeEventMixin): """ This Event is for the onset of severe wasting (WHZ < -3). * Refreshes all the properties so that they pertain to this current episode of wasting @@ -795,14 +795,12 @@ def apply(self, person_id): self.module.clinical_signs_acute_malnutrition(person_id) # ------------------------------------------------------------------------------------------- - # Add this incident case to the tracker - wasting_severity = df.at[person_id, 'un_WHZ_category'] - age_group = IncidenceWastingPollingEvent.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') - if wasting_severity != 'WHZ>=-2': - m.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) + # Add this severe wasting incident case to the tracker + age_group = WastingIncidencePollingEvent.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') + m.wasting_incident_case_tracker[age_group]['WHZ<-3'].append(self.sim.date) -class SevereAcuteMalnutritionDeathEvent(Event, IndividualScopeEventMixin): +class WastingSevereAcuteMalnutritionDeathEvent(Event, IndividualScopeEventMixin): """ This event applies the death function """ @@ -861,7 +859,7 @@ def apply(self, person_id): df.at[person_id, 'un_am_recovery_date'] = self.sim.date -class ClinicalAcuteMalnutritionRecoveryEvent(Event, IndividualScopeEventMixin): +class WastingClinicalAcuteMalnutritionRecoveryEvent(Event, IndividualScopeEventMixin): """ This event sets wasting properties back to normal state. """ @@ -891,7 +889,7 @@ def apply(self, person_id): ) -class UpdateToMAM(Event, IndividualScopeEventMixin): +class WastingUpdateToMAM(Event, IndividualScopeEventMixin): """ This event updates the properties for those cases that remained/improved from SAM to MAM following treatment diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 0cd76f61ee..61a9aee3af 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -25,14 +25,14 @@ ) from tlo.methods.healthseekingbehaviour import HealthSeekingBehaviourPoll from tlo.methods.wasting import ( - ClinicalAcuteMalnutritionRecoveryEvent, HSI_Wasting_InpatientCareForComplicated_SAM, HSI_Wasting_OutpatientTherapeuticProgramme_SAM, - IncidenceWastingPollingEvent, - ProgressionSevereWastingEvent, - SevereAcuteMalnutritionDeathEvent, - UpdateToMAM, + WastingClinicalAcuteMalnutritionRecoveryEvent, + WastingIncidencePollingEvent, WastingNaturalRecoveryEvent, + WastingProgressionToSevereEvent, + WastingSevereAcuteMalnutritionDeathEvent, + WastingUpdateToMAM, ) # Path to the resource files used by the disease and intervention methods @@ -196,7 +196,7 @@ def test_wasting_incidence(tmpdir): sim.modules['Wasting'].wasting_models.wasting_incidence_lm = LinearModel.multiplicative() # Run polling event: check that all children should now have moderate wasting: - polling = IncidenceWastingPollingEvent(sim.modules['Wasting']) + polling = WastingIncidencePollingEvent(sim.modules['Wasting']) polling.apply(sim.population) # Check properties of individuals: should now be moderately wasted @@ -323,7 +323,7 @@ def test_recovery_moderate_wasting(tmpdir): sim.modules['Wasting'].wasting_models.wasting_incidence_lm = LinearModel.multiplicative() # Run Wasting Polling event: This event should cause all young children to be moderate wasting - polling = IncidenceWastingPollingEvent(module=sim.modules['Wasting']) + polling = WastingIncidencePollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) # Check properties of this individual: should now be moderately wasted @@ -394,16 +394,16 @@ def test_recovery_severe_wasting_without_complications(tmpdir): wmodule.parameters['prob_mam_after_care'] = 1.0 # Run Wasting Polling event to get new incident cases: - polling = IncidenceWastingPollingEvent(module=sim.modules['Wasting']) + polling = WastingIncidencePollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) # Check properties of this individual: should now be moderately wasted person = df.loc[person_id] assert person['un_WHZ_category'] == '-3<=WHZ<-2' - # Check that there is a ProgressionSevereWastingEvent scheduled for this person: + # Check that there is a WastingProgressionToSevereEvent scheduled for this person: progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], ProgressionSevereWastingEvent)][0] + if isinstance(event_tuple[1], WastingProgressionToSevereEvent)][0] date_of_scheduled_progression = progression_event_tuple[0] progression_event = progression_event_tuple[1] assert date_of_scheduled_progression > sim.date @@ -450,11 +450,11 @@ def test_recovery_severe_wasting_without_complications(tmpdir): sam_ev.run(squeeze_factor=0.0) # check recovery event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[1][1], UpdateToMAM) + assert isinstance(sim.find_events_for_person(person_id)[1][1], WastingUpdateToMAM) # Run the recovery event and check the individual has recovered from SAM: sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], UpdateToMAM)][0] + isinstance(event_tuple[1], WastingUpdateToMAM)][0] date_of_scheduled_recovery_to_mam = sam_recovery_event_tuple[0] sam_recovery_event = sam_recovery_event_tuple[1] @@ -544,11 +544,11 @@ def test_recovery_severe_wasting_with_complications(tmpdir): sam_ev.run(squeeze_factor=0.0) # check recovery event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[0][1], ClinicalAcuteMalnutritionRecoveryEvent) + assert isinstance(sim.find_events_for_person(person_id)[0][1], WastingClinicalAcuteMalnutritionRecoveryEvent) # Run the recovery event and check the individual has recovered from SAM: sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], ClinicalAcuteMalnutritionRecoveryEvent)][0] + if isinstance(event_tuple[1], WastingClinicalAcuteMalnutritionRecoveryEvent)][0] date_of_scheduled_recovery_to_mam = sam_recovery_event_tuple[0] sam_recovery_event = sam_recovery_event_tuple[1] @@ -636,11 +636,11 @@ def test_nat_hist_death(tmpdir): sam_ev.run(squeeze_factor=0.0) # since there is zero recovery rate, check death event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[0][1], SevereAcuteMalnutritionDeathEvent) + assert isinstance(sim.find_events_for_person(person_id)[0][1], WastingSevereAcuteMalnutritionDeathEvent) # # Run the acute death event and ensure the person is now dead: death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent)][0] + if isinstance(event_tuple[1], WastingSevereAcuteMalnutritionDeathEvent)][0] date_of_scheduled_death = death_event_tuple[0] death_event = death_event_tuple[1] assert date_of_scheduled_death > sim.date @@ -683,7 +683,7 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' # Run Wasting Polling event to get new incident cases: - polling = IncidenceWastingPollingEvent(module=sim.modules['Wasting']) + polling = WastingIncidencePollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) # Check properties of this individual: (should now be moderately wasted without progression to severe) @@ -703,7 +703,7 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): assert date_of_scheduled_recov > sim.date # Run a Cure Event - cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) + cure_event = WastingClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) cure_event.apply(person_id=person_id) # Check that the person is not wasted and is alive still: @@ -752,7 +752,7 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # Run Wasting Polling event to get new incident cases: - polling = IncidenceWastingPollingEvent(module=sim.modules['Wasting']) + polling = WastingIncidencePollingEvent(module=sim.modules['Wasting']) polling.apply(sim.population) # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) @@ -764,9 +764,10 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Check that there is a ProgressionSevereWastingEvent scheduled for this person: + # Check that there is a WastingProgressionToSevereEvent scheduled for this person and if the person is scheduled for + # death due to SAM, the death happens after the progression to severe wasting: progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], ProgressionSevereWastingEvent)][0] + if isinstance(event_tuple[1], WastingProgressionToSevereEvent)][0] date_of_scheduled_progression = progression_event_tuple[0] progression_event = progression_event_tuple[1] assert date_of_scheduled_progression > sim.date @@ -811,17 +812,17 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): sam_ev.run(squeeze_factor=0.0) # since there is zero recovery rate, check death event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[1][1], SevereAcuteMalnutritionDeathEvent) + assert isinstance(sim.find_events_for_person(person_id)[1][1], WastingSevereAcuteMalnutritionDeathEvent) # Check a date of death is scheduled. it should be any date in the future: death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], SevereAcuteMalnutritionDeathEvent)][0] + if isinstance(event_tuple[1], WastingSevereAcuteMalnutritionDeathEvent)][0] date_of_scheduled_death = death_event_tuple[0] death_event = death_event_tuple[1] assert date_of_scheduled_death > sim.date # Run a Cure Event now - cure_event = ClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) + cure_event = WastingClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) cure_event.apply(person_id=person_id) # Check that the person is not wasted and is alive still: From a2efbf8a841cbd40dcaed722121a41e51da3218a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 24 Aug 2024 00:53:12 +0100 Subject: [PATCH 099/755] wast: actual mean for wasting incidence lm corrected --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 7886ef8c83..be2afca9e6 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1179,7 +1179,7 @@ def unscaled_wasting_incidence_lm(intercept: Union[float, int] = 1.0) -> LinearM unscaled_lm = unscaled_wasting_incidence_lm() target_mean = self.params['base_inc_rate_wasting_by_agegp'][2] # base inc rate for 12-23mo old actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1) & - (df.un_WHZ_category == 'WHZ>=-2')]).mean() + (df.un_WHZ_category != 'WHZ>=-2')]).mean() scaled_intercept = 1.0 * (target_mean / actual_mean) \ if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else 1.0 From ebca72011214dd6136a8a0a24de4ec8930b9175e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 24 Aug 2024 01:11:03 +0100 Subject: [PATCH 100/755] wast: track incidence only (it is not incidence if they remained non-wasted) --- src/tlo/methods/wasting.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index be2afca9e6..1b5eb04ca6 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -716,10 +716,9 @@ def apply(self, population): df.loc[not_wasted_idx[incidence_of_wasting], 'un_am_treatment_type'] = 'none' # ------------------------------------------------------------------------------------------- # Add these incident cases to the tracker - for person in not_wasted_idx: - wasting_severity = df.at[person, 'un_WHZ_category'] - age_group = WastingIncidencePollingEvent.AGE_GROUPS.get(df.loc[person].age_years, '5+y') - # if wasting_severity != 'WHZ>=-2': + for person_id in not_wasted_idx[incidence_of_wasting]: + wasting_severity = df.at[person_id, 'un_WHZ_category'] + age_group = WastingIncidencePollingEvent.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') self.module.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) # Update properties related to clinical acute malnutrition # (MUAC, oedema, clinical state of acute malnutrition and if SAM complications; clear symptoms if not SAM) From cc8d4ba92cca04d8472fa51462fadf2acd978323 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 8 Oct 2024 11:26:44 +0100 Subject: [PATCH 101/755] wast: return wasted always as series (even if 1 bool retuned) when initialise_population --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 1b5eb04ca6..302f5df507 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -263,7 +263,7 @@ def initialise_population(self, population): # apply prevalence of wasting and categorise into moderate (-3 <= WHZ < -2) or severe (WHZ < -3) wasting wasted = self.wasting_models.get_wasting_prevalence(agegp=agegp).predict( - children_of_agegp, self.rng + children_of_agegp, self.rng, False ) probability_of_severe = self.get_prob_severe_wasting_or_odds_wasting(agegp=agegp, get_odds=False) for idx in children_of_agegp.index[wasted]: From cf83494ed3ff4303ddde04ce435bad822524992d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 8 Oct 2024 22:01:02 +0100 Subject: [PATCH 102/755] wast: progress/recovery from moderate wasting schedule only for new cases --- src/tlo/methods/wasting.py | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 302f5df507..89774f18de 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -706,35 +706,31 @@ def apply(self, population): not_wasted = df.loc[df.is_alive & (df.age_exact_years < 5) & ( df.un_WHZ_category == 'WHZ>=-2')] incidence_of_wasting = self.module.wasting_models.wasting_incidence_lm.predict(not_wasted, rng=rng) - not_wasted_idx = not_wasted.index + mod_wasting_new_cases_idx = not_wasted.index[incidence_of_wasting] # update the properties for new cases of wasted children - df.loc[not_wasted_idx[incidence_of_wasting], 'un_ever_wasted'] = True - df.loc[not_wasted_idx[incidence_of_wasting], 'un_last_wasting_date_of_onset'] = self.sim.date - # start as moderate wasting - df.loc[not_wasted_idx[incidence_of_wasting], 'un_WHZ_category'] = '-3<=WHZ<-2' + df.loc[mod_wasting_new_cases_idx, 'un_ever_wasted'] = True + df.loc[mod_wasting_new_cases_idx, 'un_last_wasting_date_of_onset'] = self.sim.date + # initiate moderate wasting + df.loc[mod_wasting_new_cases_idx, 'un_WHZ_category'] = '-3<=WHZ<-2' # start without treatment - df.loc[not_wasted_idx[incidence_of_wasting], 'un_am_treatment_type'] = 'none' + df.loc[mod_wasting_new_cases_idx, 'un_am_treatment_type'] = 'none' # ------------------------------------------------------------------------------------------- # Add these incident cases to the tracker - for person_id in not_wasted_idx[incidence_of_wasting]: - wasting_severity = df.at[person_id, 'un_WHZ_category'] + for person_id in mod_wasting_new_cases_idx: age_group = WastingIncidencePollingEvent.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') - self.module.wasting_incident_case_tracker[age_group][wasting_severity].append(self.sim.date) + self.module.wasting_incident_case_tracker[age_group]['-3<=WHZ<-2'].append(self.sim.date) # Update properties related to clinical acute malnutrition # (MUAC, oedema, clinical state of acute malnutrition and if SAM complications; clear symptoms if not SAM) - self.module.clinical_signs_acute_malnutrition(not_wasted_idx[incidence_of_wasting]) + self.module.clinical_signs_acute_malnutrition(mod_wasting_new_cases_idx) # ------------------------------------------------------------------------------------------- # # # PROGRESS TO SEVERE WASTING # # # # # # # # # # # # # # # # # # # Determine those that will progress to severe wasting (WHZ < -3) and schedule progression event --------- - mod_wasting = df.loc[df.is_alive & (df.age_exact_years < 5) & - (df.un_WHZ_category == '-3<=WHZ<-2')] progression_severe_wasting = self.module.wasting_models.severe_wasting_progression_lm.predict( - mod_wasting, rng=rng, squeeze_single_row_output=False + df.loc[mod_wasting_new_cases_idx], rng=rng, squeeze_single_row_output=False ) - # determine those individuals who will progress to severe wasting and time of progression - for person in mod_wasting.index[progression_severe_wasting]: + for person in mod_wasting_new_cases_idx[progression_severe_wasting]: outcome_date = self.module.date_of_outcome_for_untreated_wasting(person_id=person) # schedule severe wasting WHZ < -3 onset if outcome_date <= self.sim.date: @@ -749,7 +745,7 @@ def apply(self, population): # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # Schedule recovery from moderate wasting for those not progressing to severe wasting --------- - for person in mod_wasting.index[~progression_severe_wasting]: + for person in mod_wasting_new_cases_idx[~progression_severe_wasting]: outcome_date = self.module.date_of_outcome_for_untreated_wasting(person_id=person) if outcome_date <= self.sim.date: # schedule recovery for today From be8521ec33c7d5b65154cf91f8d6cb27160cf625 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 8 Oct 2024 22:13:49 +0100 Subject: [PATCH 103/755] wast: split get_prob_severe_wasting_or_odds_wasting() fnc into two separate fncs --- src/tlo/methods/wasting.py | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 89774f18de..c55ff1a345 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -265,7 +265,7 @@ def initialise_population(self, population): wasted = self.wasting_models.get_wasting_prevalence(agegp=agegp).predict( children_of_agegp, self.rng, False ) - probability_of_severe = self.get_prob_severe_wasting_or_odds_wasting(agegp=agegp, get_odds=False) + probability_of_severe = self.get_prob_severe_wasting(agegp=agegp) for idx in children_of_agegp.index[wasted]: wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], p=[probability_of_severe, 1 - probability_of_severe]) @@ -311,14 +311,12 @@ def on_birth(self, mother_id, child_id): df.at[child_id, 'un_am_MUAC_category'] = '>=125mm' df.at[child_id, 'un_am_treatment_type'] = 'not_applicable' - def get_prob_severe_wasting_or_odds_wasting(self, agegp: str, get_odds: bool = False) -> Union[float, int]: + def get_prob_severe_wasting(self, agegp: str) -> Union[float, int]: """ This function will calculate the WHZ scores by categories and return probability of severe wasting - for those with wasting status, or odds of wasting + for those with wasting status :param agegp: age grouped in months - :param get_odds: True/False (default: False), indicates which output from fnc name will be returned - :return: probability of severe wasting among all wasting cases (if 'get_odds' == False), - or odds of wasting among all children under 5 (if 'get_odds' == True) + :return: probability of severe wasting among all wasting cases """ # generate random numbers from N(mean, sd) mean, stdev = self.parameters[f'prev_WHZ_distribution_age_{agegp}'] @@ -327,10 +325,6 @@ def get_prob_severe_wasting_or_odds_wasting(self, agegp: str, get_odds: bool = F # get probability of any wasting: WHZ < -2 probability_less_than_minus2sd = 1 - whz_normal_distribution.sf(-2) - if get_odds: - # convert probability of wasting to odds and return the odds of wasting - return probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) - # get probability of severe wasting: WHZ < -3 probability_less_than_minus3sd = 1 - whz_normal_distribution.sf(-3) @@ -338,6 +332,22 @@ def get_prob_severe_wasting_or_odds_wasting(self, agegp: str, get_odds: bool = F # return the probability of severe wasting among all wasting cases return probability_less_than_minus3sd / probability_less_than_minus2sd + def get_odds_wasting(self, agegp: str) -> Union[float, int]: + """ + This function will calculate the WHZ scores by categories and return odds of wasting + :param agegp: age grouped in months + :return: odds of wasting among all children under 5 + """ + # generate random numbers from N(mean, sd) + mean, stdev = self.parameters[f'prev_WHZ_distribution_age_{agegp}'] + whz_normal_distribution = norm(loc=mean, scale=stdev) + + # get probability of any wasting: WHZ < -2 + probability_less_than_minus2sd = 1 - whz_normal_distribution.sf(-2) + + # convert probability of wasting to odds and return the odds of wasting + return probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) + def muac_cutoff_by_WHZ(self, idx, whz): """ Proportion of MUAC < 115 mm in WHZ < -3 and -3 <= WHZ < -2, @@ -1208,9 +1218,9 @@ def unscaled_wasting_prevalence_lm(intercept: Union[float, int]) -> LinearModel: self.params['or_wasting_preterm_and_AGA']) ) - get_odds_wasting = self.module.get_prob_severe_wasting_or_odds_wasting(agegp=agegp, get_odds=True) + get_odds_wasting = self.module.get_odds_wasting(agegp=agegp) unscaled_lm = unscaled_wasting_prevalence_lm(intercept=get_odds_wasting) - target_mean = self.module.get_prob_severe_wasting_or_odds_wasting(agegp='12_23mo', get_odds=True) + target_mean = self.module.get_odds_wasting(agegp='12_23mo') actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1)]).mean() scaled_intercept = get_odds_wasting * (target_mean / actual_mean) if \ (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else get_odds_wasting From c7a25a43e21bf0a7e193c6f3103cfb44ff5f28d3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 8 Oct 2024 22:33:42 +0100 Subject: [PATCH 104/755] wast: fix wasting_prevalence_props calculations (logged) --- src/tlo/methods/wasting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index c55ff1a345..af4b3291dd 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1272,7 +1272,8 @@ def apply(self, population): wasted_agegrp = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, inclusive='left') & (under5s.un_WHZ_category != 'WHZ>=-2')).sum() - total_per_agegrp = (under5s.age_exact_years < high_bound_age_in_years).sum() + total_per_agegrp = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, + inclusive='left')).sum() # add proportions to the dictionary wasting_prev_dict[f'{low_bound_mos}_{high_bound_mos}mo'] = wasted_agegrp / total_per_agegrp From 03cae887329af1d925491fa79badb0a824ea7f04 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 9 Oct 2024 18:03:15 +0100 Subject: [PATCH 105/755] wast: typo --- src/tlo/methods/wasting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index af4b3291dd..5ee02eed35 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -394,11 +394,11 @@ def muac_cutoff_by_WHZ(self, idx, whz): probability_over_or_equal_125 = muac_distribution_in_well_group.sf(12.5) prob_less_than_115 = 1 - probability_over_or_equal_115 - pro_between_115_125 = probability_over_or_equal_115 - probability_over_or_equal_125 + prob_between_115_125 = probability_over_or_equal_115 - probability_over_or_equal_125 df.loc[idx, 'un_am_MUAC_category'] = df.loc[idx].apply( lambda x: self.rng.choice(['<115mm', '[115-125)mm', '>=125mm'], - p=[prob_less_than_115, pro_between_115_125, probability_over_or_equal_125]), + p=[prob_less_than_115, prob_between_115_125, probability_over_or_equal_125]), axis=1 ) From 9ae10c10bce5f38064246a6d865a5b8755b37098 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 9 Oct 2024 19:15:08 +0100 Subject: [PATCH 106/755] wast & test_wast: fix and simplify calculation of proportion_normalWHZ_with_oedema by calculating prob_normal_whz once when population initiated --- src/tlo/methods/wasting.py | 18 +++++++++++------- tests/test_wasting.py | 1 + 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 5ee02eed35..84d475e015 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -199,6 +199,7 @@ class Wasting(Module, GenericFirstAppointmentsMixin): def __init__(self, name=None, resourcefilepath=None): super().__init__(name) + self.prob_normal_whz = None self.wasting_models = None self.resourcefilepath = resourcefilepath # wasting states @@ -265,7 +266,7 @@ def initialise_population(self, population): wasted = self.wasting_models.get_wasting_prevalence(agegp=agegp).predict( children_of_agegp, self.rng, False ) - probability_of_severe = self.get_prob_severe_wasting(agegp=agegp) + probability_of_severe = self.get_prob_severe_wasting_among_wasted(agegp=agegp) for idx in children_of_agegp.index[wasted]: wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], p=[probability_of_severe, 1 - probability_of_severe]) @@ -275,9 +276,13 @@ def initialise_population(self, population): # start without treatment df.at[idx, 'un_am_treatment_type'] = 'none' - # ------------------------------------------------------------------ - # # # # # # Give MUAC category, presence of oedema, and determine acute malnutrition state # # # # # index_under5 = df.index[df.is_alive & (df.age_exact_years < 5)] + # calculate approximation of probability of having normal WHZ in children under 5 to be used later + self.prob_normal_whz = \ + len(index_under5.intersection(df.index[df.un_WHZ_category == 'WHZ>=-2'])) / len(index_under5) + # -------------------------------------------------------------------------------------------------- # + # # # # Give MUAC category, presence of oedema, and determine acute malnutrition state # # # # + # # # # and, in SAM cases, determine presence of complications # # # # self.clinical_signs_acute_malnutrition(index_under5) def initialise_simulation(self, sim): @@ -311,7 +316,7 @@ def on_birth(self, mother_id, child_id): df.at[child_id, 'un_am_MUAC_category'] = '>=125mm' df.at[child_id, 'un_am_treatment_type'] = 'not_applicable' - def get_prob_severe_wasting(self, agegp: str) -> Union[float, int]: + def get_prob_severe_wasting_among_wasted(self, agegp: str) -> Union[float, int]: """ This function will calculate the WHZ scores by categories and return probability of severe wasting for those with wasting status @@ -427,10 +432,9 @@ def nutritional_oedema_present(self, idx): if len(children_without_wasting) == 0: return # proportion_normalWHZ_with_oedema: P(oedema|WHZ>=-2) = - # P(oedema & WHZ>=-2) / P(WHZ>=-2) = P(oedema) * [1 -P(WHZ<-2|oedema)] / (#WHZ>=-2 / #all under 5) + # P(oedema & WHZ>=-2) / P(WHZ>=-2) = P(oedema) * [1 - P(WHZ<-2|oedema)] / P(WHZ>=-2) proportion_normal_whz_with_oedema = \ - p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) / \ - (len(children_without_wasting) / len(idx)) + p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) / self.prob_normal_whz oedema_in_non_wasted = self.rng.random_sample(size=len( children_without_wasting)) < proportion_normal_whz_with_oedema df.loc[children_without_wasting, 'un_am_bilateral_oedema'] = oedema_in_non_wasted diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 61a9aee3af..1df3d5655a 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -216,6 +216,7 @@ def test_report_daly_weights(tmpdir): dur = pd.DateOffset(days=0) popsize = 1 sim = get_sim(tmpdir) + sim.modules['Demography'].parameters['max_age_initial'] = 4.9 sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) From 91b70e5ea32e32f6f10dbeffe5e339418b9bc50a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 10 Oct 2024 17:00:07 +0100 Subject: [PATCH 107/755] wast: more descriptive names (consistent with other names) --- src/tlo/methods/wasting.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 84d475e015..c93030a188 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -395,15 +395,18 @@ def muac_cutoff_by_WHZ(self, idx, whz): muac_distribution_in_well_group = norm(loc=p['MUAC_distribution_WHZ>=-2'][0], scale=p['MUAC_distribution_WHZ>=-2'][1]) # get probabilities of MUAC - probability_over_or_equal_115 = muac_distribution_in_well_group.sf(11.5) - probability_over_or_equal_125 = muac_distribution_in_well_group.sf(12.5) + prob_normal_whz_with_muac_over_115mm = muac_distribution_in_well_group.sf(11.5) + prob_normal_whz_with_muac_over_125mm = muac_distribution_in_well_group.sf(12.5) - prob_less_than_115 = 1 - probability_over_or_equal_115 - prob_between_115_125 = probability_over_or_equal_115 - probability_over_or_equal_125 + prob_normal_whz_with_muac_less_than_115mm = 1 - prob_normal_whz_with_muac_over_115mm + prob_normal_whz_with_muac_between_115and125mm = \ + prob_normal_whz_with_muac_over_115mm - prob_normal_whz_with_muac_over_125mm df.loc[idx, 'un_am_MUAC_category'] = df.loc[idx].apply( lambda x: self.rng.choice(['<115mm', '[115-125)mm', '>=125mm'], - p=[prob_less_than_115, prob_between_115_125, probability_over_or_equal_125]), + p=[prob_normal_whz_with_muac_less_than_115mm, + prob_normal_whz_with_muac_between_115and125mm, + prob_normal_whz_with_muac_over_125mm]), axis=1 ) @@ -433,6 +436,7 @@ def nutritional_oedema_present(self, idx): return # proportion_normalWHZ_with_oedema: P(oedema|WHZ>=-2) = # P(oedema & WHZ>=-2) / P(WHZ>=-2) = P(oedema) * [1 - P(WHZ<-2|oedema)] / P(WHZ>=-2) + print(f"{self.prob_normal_whz=}") proportion_normal_whz_with_oedema = \ p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) / self.prob_normal_whz oedema_in_non_wasted = self.rng.random_sample(size=len( From 15272c80e2054ce8005ed21fe6c72abf8df80d79 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 11 Oct 2024 10:49:35 +0100 Subject: [PATCH 108/755] analysis_wast: rm note, update axis label --- src/scripts/wasting_analyses/analysis_wasting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index c1f13341d6..b6d6480c91 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -112,10 +112,10 @@ def plot_wasting_prevalence_per_year(self): w_prev_df["total_under5_prop"].plot(kind='bar', stacked=True, ax=ax, title="Wasting prevalence in children 0-59 months per year", - ylabel='proportions', + ylabel='proportion of wasted children within the age-group', xlabel='year', ylim=[0, 0.05]) - add_footnote(fig, "Proportion = total number of wasted children < 5 years / total number of children < 5 years") + # add_footnote(fig, "proportion of wasted children within each age-group") plt.tight_layout() fig.savefig( outputs / ('wasting_prevalence_per_year' + datestamp + ".pdf"), From b45439825561a5047e97e626b686d32ca535965e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 11 Oct 2024 11:00:49 +0100 Subject: [PATCH 109/755] RF_wast: more precise value of proportion_oedema_with_WHZ<-2 --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 9d9243dfa0..1365452bd6 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:625f7525702ab856b8b84147009767ccd7024298a1d6e29a9fb07ba32c662e0b -size 2835 +oid sha256:c5df521ce5c4ea1c5daef144c63bd37b61c769fd18a07e6b07132fcb3e5c634e +size 2859 From 61e6570e233aec550da6677143d1bc57aeb23530 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 11 Oct 2024 23:25:13 +0100 Subject: [PATCH 110/755] scenario_wast: create 2 scenarios incl. wasting - minimal and full_model, keep original scenario --- .../scenario_wasting_full_model.py} | 0 .../scenario_wasting_minimal_model.py | 91 +++++++++++++++++++ .../scenarios/scenario_wasting_orig.py | 91 +++++++++++++++++++ 3 files changed, 182 insertions(+) rename src/scripts/wasting_analyses/{scenario_wasting.py => scenarios/scenario_wasting_full_model.py} (100%) create mode 100644 src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py create mode 100644 src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py diff --git a/src/scripts/wasting_analyses/scenario_wasting.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py similarity index 100% rename from src/scripts/wasting_analyses/scenario_wasting.py rename to src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py new file mode 100644 index 0000000000..6851b1277e --- /dev/null +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -0,0 +1,91 @@ +""" +This file defines a scenario for wasting analysis. + +It can be submitted on Azure Batch by running: + + tlo batch-submit src/scripts/wasting_analyses/scenario_wasting.py + +or locally using: + + tlo scenario-run src/scripts/wasting_analyses/scenario_wasting.py +""" +import warnings + +from tlo import Date, logging +from tlo.methods import ( + care_of_women_during_pregnancy, + contraception, + demography, + enhanced_lifestyle, + epi, + healthburden, + healthseekingbehaviour, + healthsystem, + hiv, + labour, + newborn_outcomes, + postnatal_supervisor, + pregnancy_supervisor, + symptommanager, + tb, + wasting, +) +from tlo.scenario import BaseScenario + +# capture warnings during simulation run +warnings.simplefilter('default', (UserWarning, RuntimeWarning)) + + +class WastingAnalysis(BaseScenario): + + def __init__(self): + super().__init__( + seed=0, + start_date=Date(2010, 1, 1), + end_date=Date(2030, 1, 1), + initial_population_size=20_000, + number_of_draws=1, + runs_per_draw=1, + ) + + def log_configuration(self): + return { + 'filename': 'wasting_analysis', + 'directory': './outputs', + "custom_levels": { # Customise the output of specific loggers + "tlo.methods.demography": logging.INFO, + "tlo.methods.population": logging.INFO, + "tlo.methods.wasting": logging.INFO, + '*': logging.WARNING + } + } + + def modules(self): + return [demography.Demography(resourcefilepath=self.resources), + healthsystem.HealthSystem(resourcefilepath=self.resources, + service_availability=['*'], + cons_availability='default'), + healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=self.resources), + healthburden.HealthBurden(resourcefilepath=self.resources), + symptommanager.SymptomManager(resourcefilepath=self.resources), + enhanced_lifestyle.Lifestyle(resourcefilepath=self.resources), + labour.Labour(resourcefilepath=self.resources), + care_of_women_during_pregnancy.CareOfWomenDuringPregnancy( + resourcefilepath=self.resources), + contraception.Contraception(resourcefilepath=self.resources), + pregnancy_supervisor.PregnancySupervisor(resourcefilepath=self.resources), + postnatal_supervisor.PostnatalSupervisor(resourcefilepath=self.resources), + newborn_outcomes.NewbornOutcomes(resourcefilepath=self.resources), + hiv.Hiv(resourcefilepath=self.resources), + tb.Tb(resourcefilepath=self.resources), + epi.Epi(resourcefilepath=self.resources), + wasting.Wasting(resourcefilepath=self.resources)] + + def draw_parameters(self, draw_number, rng): + return {} + + +if __name__ == '__main__': + from tlo.cli import scenario_run + + scenario_run([__file__]) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py new file mode 100644 index 0000000000..6851b1277e --- /dev/null +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py @@ -0,0 +1,91 @@ +""" +This file defines a scenario for wasting analysis. + +It can be submitted on Azure Batch by running: + + tlo batch-submit src/scripts/wasting_analyses/scenario_wasting.py + +or locally using: + + tlo scenario-run src/scripts/wasting_analyses/scenario_wasting.py +""" +import warnings + +from tlo import Date, logging +from tlo.methods import ( + care_of_women_during_pregnancy, + contraception, + demography, + enhanced_lifestyle, + epi, + healthburden, + healthseekingbehaviour, + healthsystem, + hiv, + labour, + newborn_outcomes, + postnatal_supervisor, + pregnancy_supervisor, + symptommanager, + tb, + wasting, +) +from tlo.scenario import BaseScenario + +# capture warnings during simulation run +warnings.simplefilter('default', (UserWarning, RuntimeWarning)) + + +class WastingAnalysis(BaseScenario): + + def __init__(self): + super().__init__( + seed=0, + start_date=Date(2010, 1, 1), + end_date=Date(2030, 1, 1), + initial_population_size=20_000, + number_of_draws=1, + runs_per_draw=1, + ) + + def log_configuration(self): + return { + 'filename': 'wasting_analysis', + 'directory': './outputs', + "custom_levels": { # Customise the output of specific loggers + "tlo.methods.demography": logging.INFO, + "tlo.methods.population": logging.INFO, + "tlo.methods.wasting": logging.INFO, + '*': logging.WARNING + } + } + + def modules(self): + return [demography.Demography(resourcefilepath=self.resources), + healthsystem.HealthSystem(resourcefilepath=self.resources, + service_availability=['*'], + cons_availability='default'), + healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=self.resources), + healthburden.HealthBurden(resourcefilepath=self.resources), + symptommanager.SymptomManager(resourcefilepath=self.resources), + enhanced_lifestyle.Lifestyle(resourcefilepath=self.resources), + labour.Labour(resourcefilepath=self.resources), + care_of_women_during_pregnancy.CareOfWomenDuringPregnancy( + resourcefilepath=self.resources), + contraception.Contraception(resourcefilepath=self.resources), + pregnancy_supervisor.PregnancySupervisor(resourcefilepath=self.resources), + postnatal_supervisor.PostnatalSupervisor(resourcefilepath=self.resources), + newborn_outcomes.NewbornOutcomes(resourcefilepath=self.resources), + hiv.Hiv(resourcefilepath=self.resources), + tb.Tb(resourcefilepath=self.resources), + epi.Epi(resourcefilepath=self.resources), + wasting.Wasting(resourcefilepath=self.resources)] + + def draw_parameters(self, draw_number, rng): + return {} + + +if __name__ == '__main__': + from tlo.cli import scenario_run + + scenario_run([__file__]) From 92eb80615fdbf6c8967916042d613f83b22e8b4f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 11 Oct 2024 23:58:20 +0100 Subject: [PATCH 111/755] scenario_wast_full|minimal_model: scenarios updated --- .../scenarios/scenario_wasting_full_model.py | 46 +++---------------- .../scenario_wasting_minimal_model.py | 17 ++++--- 2 files changed, 18 insertions(+), 45 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py index 6851b1277e..46052087aa 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py @@ -12,24 +12,7 @@ import warnings from tlo import Date, logging -from tlo.methods import ( - care_of_women_during_pregnancy, - contraception, - demography, - enhanced_lifestyle, - epi, - healthburden, - healthseekingbehaviour, - healthsystem, - hiv, - labour, - newborn_outcomes, - postnatal_supervisor, - pregnancy_supervisor, - symptommanager, - tb, - wasting, -) +from tlo.methods.fullmodel import fullmodel from tlo.scenario import BaseScenario # capture warnings during simulation run @@ -50,8 +33,8 @@ def __init__(self): def log_configuration(self): return { - 'filename': 'wasting_analysis', - 'directory': './outputs', + 'filename': 'wasting_analysis__full_model', + 'directory': './outputs/wasting_analysis', "custom_levels": { # Customise the output of specific loggers "tlo.methods.demography": logging.INFO, "tlo.methods.population": logging.INFO, @@ -61,27 +44,12 @@ def log_configuration(self): } def modules(self): - return [demography.Demography(resourcefilepath=self.resources), - healthsystem.HealthSystem(resourcefilepath=self.resources, - service_availability=['*'], - cons_availability='default'), - healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=self.resources), - healthburden.HealthBurden(resourcefilepath=self.resources), - symptommanager.SymptomManager(resourcefilepath=self.resources), - enhanced_lifestyle.Lifestyle(resourcefilepath=self.resources), - labour.Labour(resourcefilepath=self.resources), - care_of_women_during_pregnancy.CareOfWomenDuringPregnancy( - resourcefilepath=self.resources), - contraception.Contraception(resourcefilepath=self.resources), - pregnancy_supervisor.PregnancySupervisor(resourcefilepath=self.resources), - postnatal_supervisor.PostnatalSupervisor(resourcefilepath=self.resources), - newborn_outcomes.NewbornOutcomes(resourcefilepath=self.resources), - hiv.Hiv(resourcefilepath=self.resources), - tb.Tb(resourcefilepath=self.resources), - epi.Epi(resourcefilepath=self.resources), - wasting.Wasting(resourcefilepath=self.resources)] + return fullmodel( + resourcefilepath=self.resources + ) def draw_parameters(self, draw_number, rng): + # Using default parameters in all cases return {} diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 6851b1277e..59541b534e 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -13,9 +13,11 @@ from tlo import Date, logging from tlo.methods import ( + alri, care_of_women_during_pregnancy, contraception, demography, + diarrhoea, enhanced_lifestyle, epi, healthburden, @@ -26,6 +28,7 @@ newborn_outcomes, postnatal_supervisor, pregnancy_supervisor, + stunting, symptommanager, tb, wasting, @@ -50,8 +53,8 @@ def __init__(self): def log_configuration(self): return { - 'filename': 'wasting_analysis', - 'directory': './outputs', + 'filename': 'wasting_analysis__minimal_model', + 'directory': './outputs/wasting_analysis', "custom_levels": { # Customise the output of specific loggers "tlo.methods.demography": logging.INFO, "tlo.methods.population": logging.INFO, @@ -63,15 +66,13 @@ def log_configuration(self): def modules(self): return [demography.Demography(resourcefilepath=self.resources), healthsystem.HealthSystem(resourcefilepath=self.resources, - service_availability=['*'], - cons_availability='default'), + service_availability=['*'], cons_availability='default'), healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=self.resources), healthburden.HealthBurden(resourcefilepath=self.resources), symptommanager.SymptomManager(resourcefilepath=self.resources), enhanced_lifestyle.Lifestyle(resourcefilepath=self.resources), labour.Labour(resourcefilepath=self.resources), - care_of_women_during_pregnancy.CareOfWomenDuringPregnancy( - resourcefilepath=self.resources), + care_of_women_during_pregnancy.CareOfWomenDuringPregnancy(resourcefilepath=self.resources), contraception.Contraception(resourcefilepath=self.resources), pregnancy_supervisor.PregnancySupervisor(resourcefilepath=self.resources), postnatal_supervisor.PostnatalSupervisor(resourcefilepath=self.resources), @@ -79,9 +80,13 @@ def modules(self): hiv.Hiv(resourcefilepath=self.resources), tb.Tb(resourcefilepath=self.resources), epi.Epi(resourcefilepath=self.resources), + alri.Alri(resourcefilepath=self.resources), + diarrhoea.Diarrhoea(resourcefilepath=self.resources), + stunting.Stunting(resourcefilepath=self.resources), wasting.Wasting(resourcefilepath=self.resources)] def draw_parameters(self, draw_number, rng): + # Using default parameters in all cases return {} From 16bf5bbca9a5fbf0f973234402852ec8668cca39 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 12 Oct 2024 00:02:49 +0100 Subject: [PATCH 112/755] analysis_wast: renamed -> .._with_sim_running --- .../{analysis_wasting.py => analysis_wasting_with_sim_running.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/scripts/wasting_analyses/{analysis_wasting.py => analysis_wasting_with_sim_running.py} (100%) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting_with_sim_running.py similarity index 100% rename from src/scripts/wasting_analyses/analysis_wasting.py rename to src/scripts/wasting_analyses/analysis_wasting_with_sim_running.py From 9e12d961dd827b4919c41c287e0988a2538c6f82 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 12 Oct 2024 00:05:16 +0100 Subject: [PATCH 113/755] analysis_wast: new analysis script analysis without running sim, to analyse outputs from a separate scenario run (scenario_wasting_minimal|full_model) --- .../wasting_analyses/analysis_wasting.py | 252 ++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 src/scripts/wasting_analyses/analysis_wasting.py diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py new file mode 100644 index 0000000000..b6d6480c91 --- /dev/null +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -0,0 +1,252 @@ +""" +An analysis file for the wasting module +""" +import datetime +# %% Import statements +from pathlib import Path + +import pandas as pd +from matplotlib import pyplot as plt + +from tlo import Date, Simulation, logging +from tlo.analysis.utils import compare_number_of_deaths, parse_log_file +from tlo.methods import ( + care_of_women_during_pregnancy, + contraception, + demography, + enhanced_lifestyle, + epi, + healthburden, + healthseekingbehaviour, + healthsystem, + hiv, + labour, + newborn_outcomes, + postnatal_supervisor, + pregnancy_supervisor, + symptommanager, + tb, + wasting, +) + + +def add_footnote(fig: plt.Figure, footnote: str): + """ A function that adds a footnote below each plot. Here we are explaining what a denominator for every + graph is """ + fig.figure.text(0.5, 0.01, footnote, ha="center", fontsize=10, + bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) + + +class WastingAnalyses: + """ + This class looks at plotting all important outputs from the wasting module + """ + + def __init__(self, log_file_path): + self.__log_file_path = log_file_path + # parse wasting logs + self.__logs_dict = \ + parse_log_file(self.__log_file_path)['tlo.methods.wasting'] + + # gender description + self.__gender_desc = {'M': 'Males', + 'F': 'Females'} + + # wasting types description + self.__wasting_types_desc = {'WHZ<-3': 'severe wasting', + '-3<=WHZ<-2': 'moderate wasting', + 'WHZ>=-2': 'not undernourished'} + + def plot_wasting_incidence(self): + """ plot the incidence of wasting over time """ + w_inc_df = self.__logs_dict['wasting_incidence_count'] + w_inc_df.set_index(w_inc_df.date.dt.year, inplace=True) + w_inc_df.drop(columns='date', inplace=True) + # get age year. doesn't matter what wasting category you choose for + # they all have same age groups + age_years = list(w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys( + + )) + age_years.remove('5+y') + + _row_counter = 0 + _col_counter = 0 + # plot setup + fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True) + for _age in age_years: + new_df = pd.DataFrame() + for state in w_inc_df.columns: + new_df[state] = \ + w_inc_df.apply(lambda row: row[state][_age], axis=1) + + new_df = new_df.apply(lambda _row: _row / _row.sum(), axis=1) + plotting = new_df[["WHZ<-3", "-3<=WHZ<-2"]] + # convert into proportions + ax = plotting.plot(kind='bar', stacked=True, + ax=axes[_row_counter, _col_counter], + title=f"incidence of wasting in {_age} infants", + ylim=[0, 0.05]) + ax.legend(self.__wasting_types_desc.values(), loc='lower right') + ax.set_xlabel('year') + ax.set_ylabel('proportions') + # move to another row + if _col_counter == 2: + _row_counter += 1 + _col_counter = -1 + _col_counter += 1 # increment column counter + fig.tight_layout() + fig.savefig( + outputs / ('wasting incidence' + datestamp + ".pdf"), + format="pdf" + ) + plt.show() + + def plot_wasting_prevalence_per_year(self): + """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of + children wasted divide by the total number of children less than 5 years""" + w_prev_df = self.__logs_dict["wasting_prevalence_props"] + w_prev_df = w_prev_df[['date', 'total_under5_prop']] + w_prev_df.set_index(w_prev_df.date.dt.year, inplace=True) + w_prev_df.drop(columns='date', inplace=True) + fig, ax = plt.subplots() + w_prev_df["total_under5_prop"].plot(kind='bar', stacked=True, + ax=ax, + title="Wasting prevalence in children 0-59 months per year", + ylabel='proportion of wasted children within the age-group', + xlabel='year', + ylim=[0, 0.05]) + # add_footnote(fig, "proportion of wasted children within each age-group") + plt.tight_layout() + fig.savefig( + outputs / ('wasting_prevalence_per_year' + datestamp + ".pdf"), + format="pdf" + ) + plt.show() + + def plot_wasting_prevalence_by_age_group(self): + """ plot wasting prevalence per each age group. Proportions are obtained by getting a total number of + children wasted in a particular age-group divide by the total number of children per that age-group""" + w_prev_df = self.__logs_dict["wasting_prevalence_props"] + w_prev_df.drop(columns={'total_under5_prop'}, inplace=True) + w_prev_df.set_index(w_prev_df.date.dt.year, inplace=True) + w_prev_df = w_prev_df.loc[w_prev_df.index == 2023] + w_prev_df.drop(columns='date', inplace=True) + fig, ax = plt.subplots() + # plot wasting prevalence + w_prev_df.squeeze().plot(kind='bar', stacked=False, + ax=ax, + title="Wasting prevalence in children 0-59 months per each age group in 2023", + ylabel='proportions', + xlabel='year', + ylim=[0, 0.1]) + add_footnote(fig, "Proportion = total number of wasted children < 5 years per each age-group / total number of " + "children < 5 years per each age-group") + plt.tight_layout() + fig.savefig( + outputs / ('wasting_prevalence_per_each_age_group' + datestamp + ".pdf"), + format="pdf" + ) + plt.show() + + def plot_modal_gbd_deaths_by_gender(self): + """ compare modal and GBD deaths by gender """ + death_compare = \ + compare_number_of_deaths(self.__log_file_path, resources) + fig, axs = plt.subplots(nrows=1, ncols=2, sharey=True, sharex=True) + for _col, sex in enumerate(('M', 'F')): + plot_df = death_compare.loc[(['2010-2014', '2015-2019'], + sex, slice(None), 'Childhood Undernutrition' + )].groupby('period').sum() + plotting = plot_df.loc[['2010-2014', '2015-2019']] + ax = plotting['model'].plot.bar(label='Model', ax=axs[_col], rot=0) + ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, + yerr=[plotting.GBD_lower, plotting.GBD_upper], + fmt='o', color='#000', label="GBD") + ax.set_title(f'{self.__gender_desc[sex]} ' + f'wasting deaths, 2010-2014') + ax.set_xlabel("Time period") + ax.set_ylabel("Number of deaths") + ax.legend(loc=2) + fig.tight_layout() + add_footnote(fig, "Model output against Global Burden of Diseases(GDB) study data") + fig.savefig( + outputs / ('modal_gbd_deaths_by_gender' + datestamp + ".pdf"), + format="pdf" + ) + plt.show() + + +if __name__ == "__main__": + seed = 1 + + # Path to the resource files used by the disease and intervention methods + resources = Path("./resources") + outputs = Path("./outputs") + + # create a datestamp + datestamp = datetime.date.today().strftime("__%Y_%m_%d") + \ + datetime.datetime.now().strftime("%H_%M_%S") + + # configure logging + log_config = { + # output filename. A timestamp will be added to this. + "filename": "wasting", + "custom_levels": { # Customise the output of specific loggers + "tlo.methods.demography": logging.INFO, + "tlo.methods.population": logging.INFO, + "tlo.methods.wasting": logging.INFO, + '*': logging.WARNING + } + } + + # Basic arguments required for the simulation + start_date = Date(2010, 1, 1) + end_date = Date(2030, 1, 2) + pop_size = 20000 + + # Create simulation instance for this run. + sim = Simulation(start_date=start_date, seed=seed, log_config=log_config) + + # Register modules for simulation + sim.register( + demography.Demography(resourcefilepath=resources), + healthsystem.HealthSystem(resourcefilepath=resources, + service_availability=['*'], + cons_availability='default'), + healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resources), + healthburden.HealthBurden(resourcefilepath=resources), + symptommanager.SymptomManager(resourcefilepath=resources), + enhanced_lifestyle.Lifestyle(resourcefilepath=resources), + labour.Labour(resourcefilepath=resources), + care_of_women_during_pregnancy.CareOfWomenDuringPregnancy( + resourcefilepath=resources), + contraception.Contraception(resourcefilepath=resources), + pregnancy_supervisor.PregnancySupervisor(resourcefilepath=resources), + postnatal_supervisor.PostnatalSupervisor(resourcefilepath=resources), + newborn_outcomes.NewbornOutcomes(resourcefilepath=resources), + hiv.Hiv(resourcefilepath=resources), + tb.Tb(resourcefilepath=resources), + epi.Epi(resourcefilepath=resources), + wasting.Wasting(resourcefilepath=resources), + ) + + sim.make_initial_population(n=pop_size) + sim.simulate(end_date=end_date) + + # read the results + output_path = sim.log_filepath + + # initialise the wasting class + wasting_analyses = WastingAnalyses(output_path) + + # plot wasting incidence + wasting_analyses.plot_wasting_incidence() + + # plot wasting prevalence + wasting_analyses.plot_wasting_prevalence_per_year() + + # plot wasting prevalence by age group + wasting_analyses.plot_wasting_prevalence_by_age_group() + + # plot wasting deaths by gender as compared to GBD deaths + wasting_analyses.plot_modal_gbd_deaths_by_gender() From a6de785a5eeb2285c57edceda1d07e4e6b44b9b4 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 12 Oct 2024 00:08:36 +0100 Subject: [PATCH 114/755] scenarios wast: names udpated in comments --- .../wasting_analyses/scenarios/scenario_wasting_full_model.py | 4 ++-- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- .../wasting_analyses/scenarios/scenario_wasting_orig.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py index 46052087aa..cdbc87ec9c 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py @@ -3,11 +3,11 @@ It can be submitted on Azure Batch by running: - tlo batch-submit src/scripts/wasting_analyses/scenario_wasting.py + tlo batch-submit src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py or locally using: - tlo scenario-run src/scripts/wasting_analyses/scenario_wasting.py + tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py """ import warnings diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 59541b534e..1eb9261b2f 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -3,11 +3,11 @@ It can be submitted on Azure Batch by running: - tlo batch-submit src/scripts/wasting_analyses/scenario_wasting.py + tlo batch-submit src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py or locally using: - tlo scenario-run src/scripts/wasting_analyses/scenario_wasting.py + tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py """ import warnings diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py index 6851b1277e..8db0806c6f 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py @@ -3,11 +3,11 @@ It can be submitted on Azure Batch by running: - tlo batch-submit src/scripts/wasting_analyses/scenario_wasting.py + tlo batch-submit src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py or locally using: - tlo scenario-run src/scripts/wasting_analyses/scenario_wasting.py + tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py """ import warnings From 3d7adfb2e5b13a4ed31dcfbbc4b61647f586d0a4 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 12 Oct 2024 00:21:38 +0100 Subject: [PATCH 115/755] scenarios wast: start and end dates corrected --- .../wasting_analyses/scenarios/scenario_wasting_full_model.py | 4 ++-- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- .../wasting_analyses/scenarios/scenario_wasting_orig.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py index cdbc87ec9c..293101138d 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py @@ -24,8 +24,8 @@ class WastingAnalysis(BaseScenario): def __init__(self): super().__init__( seed=0, - start_date=Date(2010, 1, 1), - end_date=Date(2030, 1, 1), + start_date=Date(year=2010, month=1, day=1), + end_date=Date(year=2030, month=1, day=1), initial_population_size=20_000, number_of_draws=1, runs_per_draw=1, diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 1eb9261b2f..dc5c2dded0 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -44,8 +44,8 @@ class WastingAnalysis(BaseScenario): def __init__(self): super().__init__( seed=0, - start_date=Date(2010, 1, 1), - end_date=Date(2030, 1, 1), + start_date=Date(year=2010, month=1, day=1), + end_date=Date(year=2030, month=1, day=1), initial_population_size=20_000, number_of_draws=1, runs_per_draw=1, diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py index 8db0806c6f..8204ac5438 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py @@ -41,8 +41,8 @@ class WastingAnalysis(BaseScenario): def __init__(self): super().__init__( seed=0, - start_date=Date(2010, 1, 1), - end_date=Date(2030, 1, 1), + start_date=Date(year=2010, month=1, day=1), + end_date=Date(year=2030, month=1, day=1), initial_population_size=20_000, number_of_draws=1, runs_per_draw=1, From 4880416eb0a9df9323ed784802918aef1b971a8e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 12 Oct 2024 00:28:50 +0100 Subject: [PATCH 116/755] scenario_wast_min_model: 1 year sim & 2K pop --- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index dc5c2dded0..0fcd394390 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -45,8 +45,8 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2030, month=1, day=1), - initial_population_size=20_000, + end_date=Date(year=2011, month=1, day=1), + initial_population_size=2_000, number_of_draws=1, runs_per_draw=1, ) From 4b18b145c04f821d05da52b78b2a6313c8004ce5 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 14 Oct 2024 13:57:17 +0100 Subject: [PATCH 117/755] scenario_wast_orig: match modules with minimal_model --- .../scenarios/scenario_wasting_orig.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py index 8204ac5438..2d0a0c58a0 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py @@ -13,9 +13,11 @@ from tlo import Date, logging from tlo.methods import ( + alri, care_of_women_during_pregnancy, contraception, demography, + diarrhoea, enhanced_lifestyle, epi, healthburden, @@ -26,6 +28,7 @@ newborn_outcomes, postnatal_supervisor, pregnancy_supervisor, + stunting, symptommanager, tb, wasting, @@ -63,15 +66,13 @@ def log_configuration(self): def modules(self): return [demography.Demography(resourcefilepath=self.resources), healthsystem.HealthSystem(resourcefilepath=self.resources, - service_availability=['*'], - cons_availability='default'), + service_availability=['*'], cons_availability='default'), healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=self.resources), healthburden.HealthBurden(resourcefilepath=self.resources), symptommanager.SymptomManager(resourcefilepath=self.resources), enhanced_lifestyle.Lifestyle(resourcefilepath=self.resources), labour.Labour(resourcefilepath=self.resources), - care_of_women_during_pregnancy.CareOfWomenDuringPregnancy( - resourcefilepath=self.resources), + care_of_women_during_pregnancy.CareOfWomenDuringPregnancy(resourcefilepath=self.resources), contraception.Contraception(resourcefilepath=self.resources), pregnancy_supervisor.PregnancySupervisor(resourcefilepath=self.resources), postnatal_supervisor.PostnatalSupervisor(resourcefilepath=self.resources), @@ -79,9 +80,13 @@ def modules(self): hiv.Hiv(resourcefilepath=self.resources), tb.Tb(resourcefilepath=self.resources), epi.Epi(resourcefilepath=self.resources), + alri.Alri(resourcefilepath=self.resources), + diarrhoea.Diarrhoea(resourcefilepath=self.resources), + stunting.Stunting(resourcefilepath=self.resources), wasting.Wasting(resourcefilepath=self.resources)] def draw_parameters(self, draw_number, rng): + # Using default parameters in all cases return {} From e607927e50982cc2ca91dc98325352815641e51b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 14 Oct 2024 17:20:41 +0100 Subject: [PATCH 118/755] scenario_wast_orig: add name of scenario to output filename --- src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py index 2d0a0c58a0..8454c13a4f 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py @@ -53,7 +53,7 @@ def __init__(self): def log_configuration(self): return { - 'filename': 'wasting_analysis', + 'filename': 'wasting_analysis__orig', 'directory': './outputs', "custom_levels": { # Customise the output of specific loggers "tlo.methods.demography": logging.INFO, From 9a52b8945fc744ac7dafdb867959ca645927fc65 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 14 Oct 2024 17:28:15 +0100 Subject: [PATCH 119/755] undernutrion_analyses folder renamed -> stunting_analyses --- .../stunting/stunting_analysis_plots.py | 0 .../stunting/stunting_analysis_scenario.py | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/scripts/{undernutrition_analyses => stunting_analyses}/stunting/stunting_analysis_plots.py (100%) rename src/scripts/{undernutrition_analyses => stunting_analyses}/stunting/stunting_analysis_scenario.py (93%) diff --git a/src/scripts/undernutrition_analyses/stunting/stunting_analysis_plots.py b/src/scripts/stunting_analyses/stunting/stunting_analysis_plots.py similarity index 100% rename from src/scripts/undernutrition_analyses/stunting/stunting_analysis_plots.py rename to src/scripts/stunting_analyses/stunting/stunting_analysis_plots.py diff --git a/src/scripts/undernutrition_analyses/stunting/stunting_analysis_scenario.py b/src/scripts/stunting_analyses/stunting/stunting_analysis_scenario.py similarity index 93% rename from src/scripts/undernutrition_analyses/stunting/stunting_analysis_scenario.py rename to src/scripts/stunting_analyses/stunting/stunting_analysis_scenario.py index 86cb03414c..04f02ce2aa 100644 --- a/src/scripts/undernutrition_analyses/stunting/stunting_analysis_scenario.py +++ b/src/scripts/stunting_analyses/stunting/stunting_analysis_scenario.py @@ -3,10 +3,10 @@ HealthSystem availability - including the effects of Diarrhoea and Alri and all the Labour modules. Run on the batch system using: -```tlo batch-submit src/scripts/undernutrition_analyses/stunting/stunting_analysis_scenario.py``` +```tlo batch-submit src/scripts/stunting_analyses/stunting/stunting_analysis_scenario.py``` Or locally using: -```tlo scenario-run src/scripts/undernutrition_analyses/stunting/stunting_analysis_scenario.py``` +```tlo scenario-run src/scripts/stunting_analyses/stunting/stunting_analysis_scenario.py``` """ from pathlib import Path From 57796ee4fa508ee9446265a3d7ee4830ff028bd2 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 14 Oct 2024 20:53:42 +0100 Subject: [PATCH 120/755] wast: print rm --- src/tlo/methods/wasting.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index c93030a188..28e613dadb 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -436,7 +436,6 @@ def nutritional_oedema_present(self, idx): return # proportion_normalWHZ_with_oedema: P(oedema|WHZ>=-2) = # P(oedema & WHZ>=-2) / P(WHZ>=-2) = P(oedema) * [1 - P(WHZ<-2|oedema)] / P(WHZ>=-2) - print(f"{self.prob_normal_whz=}") proportion_normal_whz_with_oedema = \ p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) / self.prob_normal_whz oedema_in_non_wasted = self.rng.random_sample(size=len( From dbaae8238835fa2a2527580463536196dc372b05 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 15 Oct 2024 16:56:31 +0100 Subject: [PATCH 121/755] analysis_wast: update the analysis script to analyse sim run from Azure + minor updates (save all figures as png, and save all figures together in one pdf) --- .../wasting_analyses/analysis_wasting.py | 285 ++++++++++-------- 1 file changed, 165 insertions(+), 120 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index b6d6480c91..c8c28b5667 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -1,40 +1,36 @@ """ -An analysis file for the wasting module +An analysis file for the wasting module (so far only for 1 run, 1 draw) """ -import datetime # %% Import statements +import glob +import gzip +import os +import PyPDF2 +import shutil +import time + +from fpdf import FPDF from pathlib import Path +from PIL import Image import pandas as pd from matplotlib import pyplot as plt from tlo import Date, Simulation, logging -from tlo.analysis.utils import compare_number_of_deaths, parse_log_file -from tlo.methods import ( - care_of_women_during_pregnancy, - contraception, - demography, - enhanced_lifestyle, - epi, - healthburden, - healthseekingbehaviour, - healthsystem, - hiv, - labour, - newborn_outcomes, - postnatal_supervisor, - pregnancy_supervisor, - symptommanager, - tb, - wasting, +from tlo.analysis.utils import ( + compare_number_of_deaths, + get_scenario_outputs, + load_pickled_dataframes, + parse_log_file ) +# start time of the analysis +time_start = time.time() -def add_footnote(fig: plt.Figure, footnote: str): - """ A function that adds a footnote below each plot. Here we are explaining what a denominator for every - graph is """ - fig.figure.text(0.5, 0.01, footnote, ha="center", fontsize=10, - bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) +# ####### TO SET ####################################################################################################### +scenario_filename = 'wasting_analysis__minimal_model' +outputs_path = Path("./outputs/sejjej5@ucl.ac.uk/wasting") +######################################################################################################################## class WastingAnalyses: @@ -42,8 +38,37 @@ class WastingAnalyses: This class looks at plotting all important outputs from the wasting module """ - def __init__(self, log_file_path): - self.__log_file_path = log_file_path + def __init__(self, in_scenario_filename, in_outputs_path): + + self.__scenario_filename = in_scenario_filename + self.__outputs_path = in_outputs_path + + # Find results_folder associated with a given batch_file (and get most recent [-1]) + results_folder = get_scenario_outputs(self.__scenario_filename, self.__outputs_path)[-1] + results_parent_folder_name = str(results_folder.parent) + results_folder_name = results_folder.name + # Get the datestamp + if results_folder_name.startswith(scenario_filename + '-'): + self.datestamp = results_folder_name[(len(scenario_filename)+1):] + else: + print("The scenario output name does not correspond with the set scenario_filename.") + + # Path to the .log.gz file + results_folder_path_run0_draw0 = results_parent_folder_name + '/' + results_folder_name + '/0/0/' + results_file_name_prefix = scenario_filename + results_file_name_extension = '.log.gz' + gz_results_file_path = Path(glob.glob(os.path.join(results_folder_path_run0_draw0, + f"{results_file_name_prefix}*{results_file_name_extension}"))[0]) + + # Path to the decompressed .log file + log_results_file_path = gz_results_file_path.with_suffix('') + + # Decompress the .log.gz file + with gzip.open(gz_results_file_path, 'rb') as f_in: + with open(log_results_file_path, 'wb') as f_out: + shutil.copyfileobj(f_in, f_out) + + self.__log_file_path = log_results_file_path # parse wasting logs self.__logs_dict = \ parse_log_file(self.__log_file_path)['tlo.methods.wasting'] @@ -57,6 +82,9 @@ def __init__(self, log_file_path): '-3<=WHZ<-2': 'moderate wasting', 'WHZ>=-2': 'not undernourished'} + self.fig_files = [] + self.type_of_individual_figs = 'png' + def plot_wasting_incidence(self): """ plot the incidence of wasting over time """ w_inc_df = self.__logs_dict['wasting_incidence_count'] @@ -72,7 +100,7 @@ def plot_wasting_incidence(self): _row_counter = 0 _col_counter = 0 # plot setup - fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True) + fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 6)) for _age in age_years: new_df = pd.DataFrame() for state in w_inc_df.columns: @@ -84,21 +112,21 @@ def plot_wasting_incidence(self): # convert into proportions ax = plotting.plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], - title=f"incidence of wasting in {_age} infants", - ylim=[0, 0.05]) + title=f"incidence of wasting in {_age} old", + ylim=[0, 1]) ax.legend(self.__wasting_types_desc.values(), loc='lower right') ax.set_xlabel('year') - ax.set_ylabel('proportions') + ax.set_ylabel('proportion') # move to another row if _col_counter == 2: _row_counter += 1 _col_counter = -1 _col_counter += 1 # increment column counter fig.tight_layout() - fig.savefig( - outputs / ('wasting incidence' + datestamp + ".pdf"), - format="pdf" - ) + fig_output_name = (str(outputs_path) + '/wasting_incidence__' + self.datestamp + '.' + + self.type_of_individual_figs) + fig.savefig(fig_output_name, format=self.type_of_individual_figs) + self.fig_files.append(fig_output_name) plt.show() def plot_wasting_prevalence_per_year(self): @@ -106,53 +134,64 @@ def plot_wasting_prevalence_per_year(self): children wasted divide by the total number of children less than 5 years""" w_prev_df = self.__logs_dict["wasting_prevalence_props"] w_prev_df = w_prev_df[['date', 'total_under5_prop']] - w_prev_df.set_index(w_prev_df.date.dt.year, inplace=True) - w_prev_df.drop(columns='date', inplace=True) + w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) + w_prev_df = w_prev_df.drop(columns='date') fig, ax = plt.subplots() w_prev_df["total_under5_prop"].plot(kind='bar', stacked=True, ax=ax, title="Wasting prevalence in children 0-59 months per year", - ylabel='proportion of wasted children within the age-group', + ylabel='proportion of wasted children in the year', xlabel='year', - ylim=[0, 0.05]) + ylim=[0, 0.15]) # add_footnote(fig, "proportion of wasted children within each age-group") plt.tight_layout() - fig.savefig( - outputs / ('wasting_prevalence_per_year' + datestamp + ".pdf"), - format="pdf" - ) + fig_output_name = (str(outputs_path) + '/wasting_prevalence_per_year__' + self.datestamp + '.' + + self.type_of_individual_figs) + fig.savefig(fig_output_name, format=self.type_of_individual_figs) + self.fig_files.append(fig_output_name) plt.show() def plot_wasting_prevalence_by_age_group(self): """ plot wasting prevalence per each age group. Proportions are obtained by getting a total number of children wasted in a particular age-group divide by the total number of children per that age-group""" w_prev_df = self.__logs_dict["wasting_prevalence_props"] - w_prev_df.drop(columns={'total_under5_prop'}, inplace=True) - w_prev_df.set_index(w_prev_df.date.dt.year, inplace=True) + w_prev_df = w_prev_df.drop(columns={'total_under5_prop'}) + w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) w_prev_df = w_prev_df.loc[w_prev_df.index == 2023] - w_prev_df.drop(columns='date', inplace=True) - fig, ax = plt.subplots() + w_prev_df = w_prev_df.drop(columns='date') + print(f"{w_prev_df=}") + order_x_axis = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo'] + # Assert that all columns are included + assert set(w_prev_df.columns) == set(order_x_axis), "Not all columns are included in the order_x_axis." + w_prev_df = w_prev_df[order_x_axis] + + fig, ax = plt.subplots(figsize=(10, 6)) # plot wasting prevalence w_prev_df.squeeze().plot(kind='bar', stacked=False, ax=ax, title="Wasting prevalence in children 0-59 months per each age group in 2023", - ylabel='proportions', - xlabel='year', - ylim=[0, 0.1]) - add_footnote(fig, "Proportion = total number of wasted children < 5 years per each age-group / total number of " - "children < 5 years per each age-group") + ylabel='proportion', + xlabel='age group', + ylim=[0, 0.3]) + # Adjust the layout to make space for the footnote + plt.subplots_adjust(bottom=0.85) # Adjust the bottom margin + # Add footnote + fig.figure.text(0.45, 0.88, + "proportion = number of wasted children in the age group " + "/ total number of children in the age group", + ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) plt.tight_layout() - fig.savefig( - outputs / ('wasting_prevalence_per_each_age_group' + datestamp + ".pdf"), - format="pdf" - ) + fig_output_name = (str(outputs_path) + '/wasting_prevalence_per_each_age_group__' + self.datestamp + '.' + + self.type_of_individual_figs) + fig.savefig(fig_output_name, format=self.type_of_individual_figs) + self.fig_files.append(fig_output_name) plt.show() def plot_modal_gbd_deaths_by_gender(self): """ compare modal and GBD deaths by gender """ death_compare = \ - compare_number_of_deaths(self.__log_file_path, resources) - fig, axs = plt.subplots(nrows=1, ncols=2, sharey=True, sharex=True) + compare_number_of_deaths(self.__log_file_path, resources_path) + fig, axs = plt.subplots(nrows=1, ncols=2, sharey=True, sharex=True, figsize=(10, 6)) for _col, sex in enumerate(('M', 'F')): plot_df = death_compare.loc[(['2010-2014', '2015-2019'], sex, slice(None), 'Childhood Undernutrition' @@ -168,76 +207,79 @@ def plot_modal_gbd_deaths_by_gender(self): ax.set_ylabel("Number of deaths") ax.legend(loc=2) fig.tight_layout() - add_footnote(fig, "Model output against Global Burden of Diseases(GDB) study data") - fig.savefig( - outputs / ('modal_gbd_deaths_by_gender' + datestamp + ".pdf"), - format="pdf" - ) + # Adjust the layout to make space for the footnote + plt.subplots_adjust(bottom=0.15) # Adjust the bottom margin + # Add footnote + fig.figure.text(0.5, 0.02, + "Model output against Global Burden of Diseases (GDB) study data", + ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) + fig_output_name = (str(outputs_path) + '/modal_gbd_deaths_by_gender__' + self.datestamp + '.' + + self.type_of_individual_figs) + fig.savefig(fig_output_name, format=self.type_of_individual_figs) + self.fig_files.append(fig_output_name) plt.show() + def plot_all_figs_in_one_pdf(self): + + output_file_path = str(self.__outputs_path) + '/wasting_all_figures__' + self.datestamp + '.pdf' + # Remove the existing output file if it exists to ensure a clean start + if os.path.exists(output_file_path): + os.remove(output_file_path) + + # Assert that the file doesn't exist anymore after removal + assert not os.path.exists(output_file_path), "The file was not successfully removed." + + # Create instance of FPDF class + pdf = FPDF() + + # Standard A4 page size in millimeters + a4_width_mm = 210 + a4_height_mm = 297 + + # Iterate through the figure files and add each as a new page + for figure_file in self.fig_files: + # Open the figure file + figure = Image.open(figure_file) + + # Convert the figure to RGB mode if it's not already + if figure.mode != 'RGB': + figure = figure.convert('RGB') + + # Get the size of the figure + width, height = figure.size + + # Convert pixels to millimeters (1 pixel = 0.264583 mm) + width_mm = width * 0.264583 + height_mm = height * 0.264583 + + # Calculate the scaling factor to fit the figure within A4 dimensions + scale_factor = min(a4_width_mm / width_mm, a4_height_mm / height_mm) + + # Calculate the new dimensions of the figure + new_width_mm = width_mm * scale_factor + new_height_mm = height_mm * scale_factor + + # Add a new page to the PDF + pdf.add_page() + + # Center the figure on the page + x_offset = (a4_width_mm - new_width_mm) / 2 + y_offset = (a4_height_mm - new_height_mm) / 2 + + # Add the figure to the page + pdf.image(figure_file, x=x_offset, y=y_offset, w=new_width_mm, h=new_height_mm) + + # Save the PDF to a file + pdf.output(output_file_path) + if __name__ == "__main__": - seed = 1 # Path to the resource files used by the disease and intervention methods - resources = Path("./resources") - outputs = Path("./outputs") - - # create a datestamp - datestamp = datetime.date.today().strftime("__%Y_%m_%d") + \ - datetime.datetime.now().strftime("%H_%M_%S") - - # configure logging - log_config = { - # output filename. A timestamp will be added to this. - "filename": "wasting", - "custom_levels": { # Customise the output of specific loggers - "tlo.methods.demography": logging.INFO, - "tlo.methods.population": logging.INFO, - "tlo.methods.wasting": logging.INFO, - '*': logging.WARNING - } - } - - # Basic arguments required for the simulation - start_date = Date(2010, 1, 1) - end_date = Date(2030, 1, 2) - pop_size = 20000 - - # Create simulation instance for this run. - sim = Simulation(start_date=start_date, seed=seed, log_config=log_config) - - # Register modules for simulation - sim.register( - demography.Demography(resourcefilepath=resources), - healthsystem.HealthSystem(resourcefilepath=resources, - service_availability=['*'], - cons_availability='default'), - healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resources), - healthburden.HealthBurden(resourcefilepath=resources), - symptommanager.SymptomManager(resourcefilepath=resources), - enhanced_lifestyle.Lifestyle(resourcefilepath=resources), - labour.Labour(resourcefilepath=resources), - care_of_women_during_pregnancy.CareOfWomenDuringPregnancy( - resourcefilepath=resources), - contraception.Contraception(resourcefilepath=resources), - pregnancy_supervisor.PregnancySupervisor(resourcefilepath=resources), - postnatal_supervisor.PostnatalSupervisor(resourcefilepath=resources), - newborn_outcomes.NewbornOutcomes(resourcefilepath=resources), - hiv.Hiv(resourcefilepath=resources), - tb.Tb(resourcefilepath=resources), - epi.Epi(resourcefilepath=resources), - wasting.Wasting(resourcefilepath=resources), - ) - - sim.make_initial_population(n=pop_size) - sim.simulate(end_date=end_date) - - # read the results - output_path = sim.log_filepath + resources_path = Path("./resources") # initialise the wasting class - wasting_analyses = WastingAnalyses(output_path) + wasting_analyses = WastingAnalyses(scenario_filename, outputs_path) # plot wasting incidence wasting_analyses.plot_wasting_incidence() @@ -250,3 +292,6 @@ def plot_modal_gbd_deaths_by_gender(self): # plot wasting deaths by gender as compared to GBD deaths wasting_analyses.plot_modal_gbd_deaths_by_gender() + + # save all figures in one pdf + wasting_analyses.plot_all_figs_in_one_pdf() From b38e79a43d5f1aacd359b76d9a6c091f1354daff Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 15 Oct 2024 17:40:42 +0100 Subject: [PATCH 122/755] analysis_wast: PEP 8 --- src/scripts/wasting_analyses/analysis_wasting.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index c8c28b5667..74f5f5a3cd 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -5,24 +5,16 @@ import glob import gzip import os -import PyPDF2 import shutil import time - -from fpdf import FPDF from pathlib import Path -from PIL import Image import pandas as pd +from fpdf import FPDF from matplotlib import pyplot as plt +from PIL import Image -from tlo import Date, Simulation, logging -from tlo.analysis.utils import ( - compare_number_of_deaths, - get_scenario_outputs, - load_pickled_dataframes, - parse_log_file -) +from tlo.analysis.utils import compare_number_of_deaths, get_scenario_outputs, parse_log_file # start time of the analysis time_start = time.time() From 62af5e7968354ac0baa1e6e31f207850ee6603c9 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 15 Oct 2024 18:11:46 +0100 Subject: [PATCH 123/755] analysis_wast: save both png and pdf for each figure & all_figures in one pdf (pages of size of figs) --- .../wasting_analyses/analysis_wasting.py | 84 ++++++------------- 1 file changed, 26 insertions(+), 58 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 74f5f5a3cd..7d2369c3bb 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -10,7 +10,7 @@ from pathlib import Path import pandas as pd -from fpdf import FPDF +from PyPDF2 import PdfReader, PdfWriter from matplotlib import pyplot as plt from PIL import Image @@ -75,7 +75,11 @@ def __init__(self, in_scenario_filename, in_outputs_path): 'WHZ>=-2': 'not undernourished'} self.fig_files = [] - self.type_of_individual_figs = 'png' + + def save_fig__store_pdf_file(self, fig, fig_output_name: str) -> None: + fig.savefig(fig_output_name + '.png', format='png') + fig.savefig(fig_output_name + '.pdf', format='pdf') + self.fig_files.append(fig_output_name + '.pdf') def plot_wasting_incidence(self): """ plot the incidence of wasting over time """ @@ -115,10 +119,8 @@ def plot_wasting_incidence(self): _col_counter = -1 _col_counter += 1 # increment column counter fig.tight_layout() - fig_output_name = (str(outputs_path) + '/wasting_incidence__' + self.datestamp + '.' + - self.type_of_individual_figs) - fig.savefig(fig_output_name, format=self.type_of_individual_figs) - self.fig_files.append(fig_output_name) + fig_output_name = (str(outputs_path) + '/wasting_incidence__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) plt.show() def plot_wasting_prevalence_per_year(self): @@ -137,10 +139,8 @@ def plot_wasting_prevalence_per_year(self): ylim=[0, 0.15]) # add_footnote(fig, "proportion of wasted children within each age-group") plt.tight_layout() - fig_output_name = (str(outputs_path) + '/wasting_prevalence_per_year__' + self.datestamp + '.' + - self.type_of_individual_figs) - fig.savefig(fig_output_name, format=self.type_of_individual_figs) - self.fig_files.append(fig_output_name) + fig_output_name = (str(outputs_path) + '/wasting_prevalence_per_year__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) plt.show() def plot_wasting_prevalence_by_age_group(self): @@ -173,10 +173,8 @@ def plot_wasting_prevalence_by_age_group(self): "/ total number of children in the age group", ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) plt.tight_layout() - fig_output_name = (str(outputs_path) + '/wasting_prevalence_per_each_age_group__' + self.datestamp + '.' - + self.type_of_individual_figs) - fig.savefig(fig_output_name, format=self.type_of_individual_figs) - self.fig_files.append(fig_output_name) + fig_output_name = (str(outputs_path) + '/wasting_prevalence_per_each_age_group__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) plt.show() def plot_modal_gbd_deaths_by_gender(self): @@ -205,10 +203,8 @@ def plot_modal_gbd_deaths_by_gender(self): fig.figure.text(0.5, 0.02, "Model output against Global Burden of Diseases (GDB) study data", ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) - fig_output_name = (str(outputs_path) + '/modal_gbd_deaths_by_gender__' + self.datestamp + '.' + - self.type_of_individual_figs) - fig.savefig(fig_output_name, format=self.type_of_individual_figs) - self.fig_files.append(fig_output_name) + fig_output_name = (str(outputs_path) + '/modal_gbd_deaths_by_gender__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) plt.show() def plot_all_figs_in_one_pdf(self): @@ -221,48 +217,20 @@ def plot_all_figs_in_one_pdf(self): # Assert that the file doesn't exist anymore after removal assert not os.path.exists(output_file_path), "The file was not successfully removed." - # Create instance of FPDF class - pdf = FPDF() - - # Standard A4 page size in millimeters - a4_width_mm = 210 - a4_height_mm = 297 - - # Iterate through the figure files and add each as a new page - for figure_file in self.fig_files: - # Open the figure file - figure = Image.open(figure_file) - - # Convert the figure to RGB mode if it's not already - if figure.mode != 'RGB': - figure = figure.convert('RGB') - - # Get the size of the figure - width, height = figure.size - - # Convert pixels to millimeters (1 pixel = 0.264583 mm) - width_mm = width * 0.264583 - height_mm = height * 0.264583 - - # Calculate the scaling factor to fit the figure within A4 dimensions - scale_factor = min(a4_width_mm / width_mm, a4_height_mm / height_mm) - - # Calculate the new dimensions of the figure - new_width_mm = width_mm * scale_factor - new_height_mm = height_mm * scale_factor - - # Add a new page to the PDF - pdf.add_page() - - # Center the figure on the page - x_offset = (a4_width_mm - new_width_mm) / 2 - y_offset = (a4_height_mm - new_height_mm) / 2 + # Merge the PDF files + # Create a PDF writer object + pdf_writer = PdfWriter() - # Add the figure to the page - pdf.image(figure_file, x=x_offset, y=y_offset, w=new_width_mm, h=new_height_mm) + # Iterate through the figure files and add each to the writer + for fig_file in self.fig_files: + pdf_reader = PdfReader(fig_file) + for page_num in range(len(pdf_reader.pages)): + page = pdf_reader.pages[page_num] + pdf_writer.add_page(page) - # Save the PDF to a file - pdf.output(output_file_path) + # Write the merged PDF to a file + with open(output_file_path, 'wb') as out_file: + pdf_writer.write(out_file) if __name__ == "__main__": From a0efad120286ff9e512ad33716c17a07b4d36a67 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 15 Oct 2024 19:02:30 +0100 Subject: [PATCH 124/755] analysis_wast: save figs into simulation results folder --- .../wasting_analyses/analysis_wasting.py | 50 +++++++++---------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 7d2369c3bb..2a6ebd34ef 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -12,7 +12,6 @@ import pandas as pd from PyPDF2 import PdfReader, PdfWriter from matplotlib import pyplot as plt -from PIL import Image from tlo.analysis.utils import compare_number_of_deaths, get_scenario_outputs, parse_log_file @@ -32,25 +31,23 @@ class WastingAnalyses: def __init__(self, in_scenario_filename, in_outputs_path): - self.__scenario_filename = in_scenario_filename - self.__outputs_path = in_outputs_path - - # Find results_folder associated with a given batch_file (and get most recent [-1]) - results_folder = get_scenario_outputs(self.__scenario_filename, self.__outputs_path)[-1] - results_parent_folder_name = str(results_folder.parent) - results_folder_name = results_folder.name + # Find sim_results_folder associated with a given batch_file (and get most recent [-1]) + sim_results_folder = get_scenario_outputs(in_scenario_filename, in_outputs_path)[-1] + sim_results_parent_folder_name = str(sim_results_folder.parent) + sim_results_folder_name = sim_results_folder.name + self.outcomes_path_name = str(in_outputs_path) + "/" + sim_results_folder_name # Get the datestamp - if results_folder_name.startswith(scenario_filename + '-'): - self.datestamp = results_folder_name[(len(scenario_filename)+1):] + if sim_results_folder_name.startswith(scenario_filename + '-'): + self.datestamp = sim_results_folder_name[(len(scenario_filename)+1):] else: print("The scenario output name does not correspond with the set scenario_filename.") # Path to the .log.gz file - results_folder_path_run0_draw0 = results_parent_folder_name + '/' + results_folder_name + '/0/0/' - results_file_name_prefix = scenario_filename - results_file_name_extension = '.log.gz' - gz_results_file_path = Path(glob.glob(os.path.join(results_folder_path_run0_draw0, - f"{results_file_name_prefix}*{results_file_name_extension}"))[0]) + sim_results_folder_path_run0_draw0 = sim_results_parent_folder_name + '/' + sim_results_folder_name + '/0/0/' + sim_results_file_name_prefix = scenario_filename + sim_results_file_name_extension = '.log.gz' + gz_results_file_path = Path(glob.glob(os.path.join(sim_results_folder_path_run0_draw0, + f"{sim_results_file_name_prefix}*{sim_results_file_name_extension}"))[0]) # Path to the decompressed .log file log_results_file_path = gz_results_file_path.with_suffix('') @@ -77,8 +74,8 @@ def __init__(self, in_scenario_filename, in_outputs_path): self.fig_files = [] def save_fig__store_pdf_file(self, fig, fig_output_name: str) -> None: - fig.savefig(fig_output_name + '.png', format='png') - fig.savefig(fig_output_name + '.pdf', format='pdf') + fig.savefig(self.outcomes_path_name + "/" + fig_output_name + '.png', format='png') + fig.savefig(self.outcomes_path_name + "/" + fig_output_name + '.pdf', format='pdf') self.fig_files.append(fig_output_name + '.pdf') def plot_wasting_incidence(self): @@ -119,9 +116,9 @@ def plot_wasting_incidence(self): _col_counter = -1 _col_counter += 1 # increment column counter fig.tight_layout() - fig_output_name = (str(outputs_path) + '/wasting_incidence__' + self.datestamp) + fig_output_name = ('wasting_incidence__' + self.datestamp) self.save_fig__store_pdf_file(fig, fig_output_name) - plt.show() + # plt.show() def plot_wasting_prevalence_per_year(self): """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of @@ -139,9 +136,9 @@ def plot_wasting_prevalence_per_year(self): ylim=[0, 0.15]) # add_footnote(fig, "proportion of wasted children within each age-group") plt.tight_layout() - fig_output_name = (str(outputs_path) + '/wasting_prevalence_per_year__' + self.datestamp) + fig_output_name = ('wasting_prevalence_per_year__' + self.datestamp) self.save_fig__store_pdf_file(fig, fig_output_name) - plt.show() + # plt.show() def plot_wasting_prevalence_by_age_group(self): """ plot wasting prevalence per each age group. Proportions are obtained by getting a total number of @@ -151,7 +148,6 @@ def plot_wasting_prevalence_by_age_group(self): w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) w_prev_df = w_prev_df.loc[w_prev_df.index == 2023] w_prev_df = w_prev_df.drop(columns='date') - print(f"{w_prev_df=}") order_x_axis = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo'] # Assert that all columns are included assert set(w_prev_df.columns) == set(order_x_axis), "Not all columns are included in the order_x_axis." @@ -173,7 +169,7 @@ def plot_wasting_prevalence_by_age_group(self): "/ total number of children in the age group", ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) plt.tight_layout() - fig_output_name = (str(outputs_path) + '/wasting_prevalence_per_each_age_group__' + self.datestamp) + fig_output_name = ('wasting_prevalence_per_each_age_group__' + self.datestamp) self.save_fig__store_pdf_file(fig, fig_output_name) plt.show() @@ -203,13 +199,13 @@ def plot_modal_gbd_deaths_by_gender(self): fig.figure.text(0.5, 0.02, "Model output against Global Burden of Diseases (GDB) study data", ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) - fig_output_name = (str(outputs_path) + '/modal_gbd_deaths_by_gender__' + self.datestamp) + fig_output_name = ('modal_gbd_deaths_by_gender__' + self.datestamp) self.save_fig__store_pdf_file(fig, fig_output_name) - plt.show() + # plt.show() def plot_all_figs_in_one_pdf(self): - output_file_path = str(self.__outputs_path) + '/wasting_all_figures__' + self.datestamp + '.pdf' + output_file_path = Path(self.outcomes_path_name + '/wasting_all_figures__' + self.datestamp + '.pdf') # Remove the existing output file if it exists to ensure a clean start if os.path.exists(output_file_path): os.remove(output_file_path) @@ -223,7 +219,7 @@ def plot_all_figs_in_one_pdf(self): # Iterate through the figure files and add each to the writer for fig_file in self.fig_files: - pdf_reader = PdfReader(fig_file) + pdf_reader = PdfReader(self.outcomes_path_name + "/" + fig_file) for page_num in range(len(pdf_reader.pages)): page = pdf_reader.pages[page_num] pdf_writer.add_page(page) From c7c3497d8ef97127d2904b933449c0f25d56765e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 15 Oct 2024 19:09:20 +0100 Subject: [PATCH 125/755] scenario_wast_full|minimal_model: sim 2010-2030(incl), 20K pop, 10 runs --- .../scenarios/scenario_wasting_full_model.py | 4 ++-- .../scenarios/scenario_wasting_minimal_model.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py index 293101138d..f4472a6794 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py @@ -25,10 +25,10 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2030, month=1, day=1), + end_date=Date(year=2031, month=1, day=1), initial_population_size=20_000, number_of_draws=1, - runs_per_draw=1, + runs_per_draw=10, ) def log_configuration(self): diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 0fcd394390..4b8237dbb6 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -45,10 +45,10 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2011, month=1, day=1), - initial_population_size=2_000, + end_date=Date(year=2031, month=1, day=1), + initial_population_size=20_000, number_of_draws=1, - runs_per_draw=1, + runs_per_draw=10, ) def log_configuration(self): From ef9cb70167c409503b533d70afb051961c8572c0 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 15 Oct 2024 19:12:54 +0100 Subject: [PATCH 126/755] analysis_wast: PEP 8 --- src/scripts/wasting_analyses/analysis_wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 2a6ebd34ef..fd612232d2 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -10,8 +10,8 @@ from pathlib import Path import pandas as pd -from PyPDF2 import PdfReader, PdfWriter from matplotlib import pyplot as plt +from PyPDF2 import PdfReader, PdfWriter from tlo.analysis.utils import compare_number_of_deaths, get_scenario_outputs, parse_log_file From 065d1f4a1e240f98a34a8c9e94effec999321c07 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 15 Oct 2024 19:34:08 +0100 Subject: [PATCH 127/755] scenario_wast_full|minimal_model: up to 2023-01-02 (wasting log after each year finished, on 01-01) --- .../wasting_analyses/scenarios/scenario_wasting_full_model.py | 2 +- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py index f4472a6794..b3653d0134 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py @@ -25,7 +25,7 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2031, month=1, day=1), + end_date=Date(year=2031, month=1, day=2), initial_population_size=20_000, number_of_draws=1, runs_per_draw=10, diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 4b8237dbb6..3be0d4536f 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -45,7 +45,7 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2031, month=1, day=1), + end_date=Date(year=2031, month=1, day=2), initial_population_size=20_000, number_of_draws=1, runs_per_draw=10, From 5695d7415528c63fd5a5a6bb9dc5cf092c081e51 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 17 Oct 2024 11:55:34 +0100 Subject: [PATCH 128/755] wast: clinical acute malnutrition categories written together --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 28e613dadb..3830794a25 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -182,7 +182,7 @@ class Wasting(Module, GenericFirstAppointmentsMixin): # Properties related to clinical acute malnutrition 'un_clinical_acute_malnutrition': Property(Types.CATEGORICAL, 'clinical acute malnutrition state based' ' on WHZ and/or MUAC and/or oedema', - categories=['MAM', 'SAM'] + ['well']), + categories=['MAM', 'SAM', 'well']), 'un_am_bilateral_oedema': Property(Types.BOOL, 'bilateral pitting oedema present in wasting episode'), 'un_am_MUAC_category': Property(Types.CATEGORICAL, 'MUAC measurement categories, based on WHO ' 'cut-offs', From 4601dc6b5ba35696153926dafca0851072c35c70 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 17 Oct 2024 11:56:19 +0100 Subject: [PATCH 129/755] analysis_wast: footnote corrected --- src/scripts/wasting_analyses/analysis_wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index fd612232d2..e2729e91e1 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -197,7 +197,7 @@ def plot_modal_gbd_deaths_by_gender(self): plt.subplots_adjust(bottom=0.15) # Adjust the bottom margin # Add footnote fig.figure.text(0.5, 0.02, - "Model output against Global Burden of Diseases (GDB) study data", + "Model output against Global Burden of Diseases (GBD) study data", ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) fig_output_name = ('modal_gbd_deaths_by_gender__' + self.datestamp) self.save_fig__store_pdf_file(fig, fig_output_name) From c328ddb0f8349e565d5931b0897b0715b7b8630b Mon Sep 17 00:00:00 2001 From: Eva Janouskova <48157464+EvaJanouskova@users.noreply.github.com> Date: Thu, 17 Oct 2024 21:51:01 +0200 Subject: [PATCH 130/755] wast: tidy up Co-authored-by: Watipaso Mulwafu <39279950+thewati@users.noreply.github.com> --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 3830794a25..e53fd238c6 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -660,7 +660,7 @@ def do_when_am_treatment(self, person_id, intervention): # remained MAM return - elif (intervention == 'OTC') or (intervention == 'ITC'): + elif intervention in ['OTC', 'ITC']: if intervention == 'OTC': outcome_date = (df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=p['tx_length_weeks_OutpatientSAM'])) From 3deb9f759f32859495a65a7fcd19c8b083445180 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 17 Oct 2024 12:11:31 +0100 Subject: [PATCH 131/755] analysis_wast: title corrected --- src/scripts/wasting_analyses/analysis_wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index e2729e91e1..d1522a4853 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -188,7 +188,7 @@ def plot_modal_gbd_deaths_by_gender(self): yerr=[plotting.GBD_lower, plotting.GBD_upper], fmt='o', color='#000', label="GBD") ax.set_title(f'{self.__gender_desc[sex]} ' - f'wasting deaths, 2010-2014') + f'deaths due to wasting') ax.set_xlabel("Time period") ax.set_ylabel("Number of deaths") ax.legend(loc=2) From d463b56c1a297f4a422b7b7fd38c4c3cba339d86 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 22 Oct 2024 15:07:48 +0100 Subject: [PATCH 132/755] wast: increase care_seeking_odds_ratio for SAM symptom, so almost everyone with SAM will get the treatment --- src/tlo/methods/wasting.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index e53fd238c6..380fb6b6fe 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -225,8 +225,13 @@ def read_parameters(self, data_folder): pd.read_csv(Path(self.resourcefilepath) / 'ResourceFile_Wasting.csv') ) - # Register wasting symptom (weight loss) in Symptoms Manager - self.sim.modules['SymptomManager'].register_symptom(Symptom(name=self.wasting_symptom)) + # Register wasting symptom (weight loss) in Symptoms Manager with high odds of seeking care + self.sim.modules["SymptomManager"].register_symptom( + Symptom( + name=self.wasting_symptom, + odds_ratio_health_seeking_in_children=20.0, + ) + ) def initialise_population(self, population): """ From 88bc3f01451128c0114ad77ede041e6b2ad8eb61 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 22 Oct 2024 15:17:54 +0100 Subject: [PATCH 133/755] wast: follow-up MAM treatment after SAM treatment when recovered to MAM --- src/tlo/methods/wasting.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 380fb6b6fe..46d4d1106b 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -692,9 +692,12 @@ def do_when_am_treatment(self, person_id, intervention): event=WastingSevereAcuteMalnutritionDeathEvent(module=self, person_id=person_id), date=outcome_date ) - else: + else: # recovery to MAM and follow-up treatment for MAM self.sim.schedule_event(event=WastingUpdateToMAM(module=self, person_id=person_id), date=outcome_date) + self.sim.modules['HealthSystem'].schedule_hsi_event( + hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), + priority=0, topen=outcome_date) # cancel death date df.at[person_id, 'un_sam_death_date'] = pd.NaT From 5b5d8a28ab5426eac9f084e13cdb07cbe9245570 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 22 Oct 2024 16:31:57 +0100 Subject: [PATCH 134/755] wast: *new MAM, SAM cases start with 'none' treatment (not only wasting cases); *if MAM/SAM treated do not send for another treatment with generic_first_appt --- src/tlo/methods/wasting.py | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 46d4d1106b..4f78d84286 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -278,8 +278,6 @@ def initialise_population(self, population): df.at[idx, 'un_WHZ_category'] = wasted_category df.at[idx, 'un_last_wasting_date_of_onset'] = self.sim.date df.at[idx, 'un_ever_wasted'] = True - # start without treatment - df.at[idx, 'un_am_treatment_type'] = 'none' index_under5 = df.index[df.is_alive & (df.age_exact_years < 5)] # calculate approximation of probability of having normal WHZ in children under 5 to be used later @@ -458,20 +456,25 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): df = pop_dataframe p = self.parameters - # check if person is not wasted + # if person well if ((df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2') & (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & (~df.at[person_id, 'un_am_bilateral_oedema'])): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' + # if person not well + else: + # start without treatment + df.at[person_id, 'un_am_treatment_type'] = 'none' - # severe acute malnutrition -- MUAC < 115 mm and/or WHZ < -3 and/or bilateral oedema - elif ((df.at[person_id, 'un_am_MUAC_category'] == '<115mm') | (df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3') - | (df.at[person_id, 'un_am_bilateral_oedema'])): - df.at[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' - # apply symptoms to all SAM cases - self.wasting_clinical_symptoms(person_id=person_id) + # severe acute malnutrition (SAM): MUAC < 115 mm and/or WHZ < -3 and/or bilateral oedema + if ((df.at[person_id, 'un_am_MUAC_category'] == '<115mm') + | (df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3') | (df.at[person_id, 'un_am_bilateral_oedema'])): + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' + # apply symptoms to all SAM cases + self.wasting_clinical_symptoms(person_id=person_id) - else: - df.at[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' + # otherwise moderate acute malnutrition (MAM) + else: + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' # Determine if SAM episode has complications if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM': @@ -597,7 +600,9 @@ def do_at_generic_first_appt( schedule_hsi_event: HSIEventScheduler, **kwargs, ) -> None: - if individual_properties["age_years"] > 5: + if (individual_properties["age_years"] >= 5) or \ + (individual_properties["un_am_treatment_type"] in + ['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']): return p = self.parameters @@ -737,8 +742,6 @@ def apply(self, population): df.loc[mod_wasting_new_cases_idx, 'un_last_wasting_date_of_onset'] = self.sim.date # initiate moderate wasting df.loc[mod_wasting_new_cases_idx, 'un_WHZ_category'] = '-3<=WHZ<-2' - # start without treatment - df.loc[mod_wasting_new_cases_idx, 'un_am_treatment_type'] = 'none' # ------------------------------------------------------------------------------------------- # Add these incident cases to the tracker for person_id in mod_wasting_new_cases_idx: @@ -961,8 +964,8 @@ def apply(self, person_id): df.at[person_id, 'un_am_tx_start_date'] = pd.NaT df.at[person_id, 'un_am_recovery_date'] = pd.NaT df.at[person_id, 'un_am_discharge_date'] = pd.NaT - # will start the process again - df.at[person_id, 'un_am_treatment_type'] = 'not_applicable' + # Start without treatment, treatment will be applied with HSI if care sought + df.at[person_id, 'un_am_treatment_type'] = 'none' # this will clear all wasting symptoms (applicable for SAM, not MAM) self.sim.modules["SymptomManager"].clear_symptoms( From d96b53a24527772056af1d9bebe1e4c64407d0eb Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 27 Oct 2024 01:49:28 +0100 Subject: [PATCH 135/755] wast & test_wast: new HSI_Wasting_GrowthMonitoring; other events renamed --- src/tlo/methods/wasting.py | 126 ++++++++++++++++++++++++++++--------- tests/test_wasting.py | 64 +++++++++---------- 2 files changed, 129 insertions(+), 61 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 4f78d84286..b799d9050a 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -289,16 +289,17 @@ def initialise_population(self, population): self.clinical_signs_acute_malnutrition(index_under5) def initialise_simulation(self, sim): - """Prepares for simulation: - * Schedules the main polling event - * Schedules the main logging event + """Prepares for simulation. Schedules: + * the first growth monitoring to happen straight away, scheduled monthly to detect new cases for treatment. + * the main incidence polling event. + * the main logging event. """ - # schedule wasting pool event - sim.schedule_event(WastingIncidencePollingEvent(self), sim.date + DateOffset(months=3)) - - # schedule wasting logging event - sim.schedule_event(WastingLoggingEvent(self), sim.date + DateOffset(months=12)) + sim.modules['HealthSystem'].schedule_hsi_event(hsi_event=HSI_Wasting_GrowthMonitoring(module=self), + topen=self.sim.date, tclose=None, + priority=1) + sim.schedule_event(Wasting_IncidencePoll(self), sim.date + DateOffset(months=3)) + sim.schedule_event(Wasting_LoggingEvent(self), sim.date + DateOffset(years=1) - DateOffset(days=1)) def on_birth(self, mother_id, child_id): """Initialise properties for a newborn individual. @@ -637,7 +638,7 @@ def do_at_generic_first_appt( if self.rng.random_sample() < p['coverage_inpatient_care']: # schedule HSI for supplementary feeding program for MAM schedule_hsi_event( - hsi_event=HSI_Wasting_InpatientCareForComplicated_SAM( + hsi_event=HSI_Wasting_InpatientCare_ComplicatedSAM( module=self, person_id=person_id), priority=0, topen=self.sim.date) else: return @@ -661,7 +662,7 @@ def do_when_am_treatment(self, person_id, intervention): if mam_full_recovery: # schedule recovery date self.sim.schedule_event( - event=WastingClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), + event=Wasting_ClinicalAcuteMalnutritionRecovery_Event(module=self, person_id=person_id), date=(df.at[person_id, 'un_am_tx_start_date'] + DateOffset(weeks=p['tx_length_weeks_SuppFeedingMAM'])) ) @@ -684,7 +685,7 @@ def do_when_am_treatment(self, person_id, intervention): if sam_full_recovery: # schedule full recovery self.sim.schedule_event( - event=WastingClinicalAcuteMalnutritionRecoveryEvent(module=self, person_id=person_id), + event=Wasting_ClinicalAcuteMalnutritionRecovery_Event(module=self, person_id=person_id), date=outcome_date ) # cancel death date @@ -694,11 +695,11 @@ def do_when_am_treatment(self, person_id, intervention): self.parameters['prob_death_after_care']]) if outcome == 'death': self.sim.schedule_event( - event=WastingSevereAcuteMalnutritionDeathEvent(module=self, person_id=person_id), + event=Wasting_SevereAcuteMalnutritionDeath_Event(module=self, person_id=person_id), date=outcome_date ) else: # recovery to MAM and follow-up treatment for MAM - self.sim.schedule_event(event=WastingUpdateToMAM(module=self, person_id=person_id), + self.sim.schedule_event(event=Wasting_UpdateToMAM_Event(module=self, person_id=person_id), date=outcome_date) self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), @@ -707,7 +708,7 @@ def do_when_am_treatment(self, person_id, intervention): df.at[person_id, 'un_sam_death_date'] = pd.NaT -class WastingIncidencePollingEvent(RegularEvent, PopulationScopeEventMixin): +class Wasting_IncidencePoll(RegularEvent, PopulationScopeEventMixin): """ Regular event that determines new cases of wasting (WHZ < -2) to the under-5 population, and schedules individual incident cases to represent onset. It determines those who will progress to severe wasting @@ -745,7 +746,7 @@ def apply(self, population): # ------------------------------------------------------------------------------------------- # Add these incident cases to the tracker for person_id in mod_wasting_new_cases_idx: - age_group = WastingIncidencePollingEvent.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') + age_group = Wasting_IncidencePoll.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') self.module.wasting_incident_case_tracker[age_group]['-3<=WHZ<-2'].append(self.sim.date) # Update properties related to clinical acute malnutrition # (MUAC, oedema, clinical state of acute malnutrition and if SAM complications; clear symptoms if not SAM) @@ -763,12 +764,12 @@ def apply(self, population): # schedule severe wasting WHZ < -3 onset if outcome_date <= self.sim.date: # schedule severe wasting (WHZ < -3) onset today - self.sim.schedule_event(event=WastingProgressionToSevereEvent( + self.sim.schedule_event(event=Wasting_ProgressionToSevere_Event( module=self.module, person_id=person), date=self.sim.date) else: # schedule severe wasting WHZ < -3 onset according to duration self.sim.schedule_event( - event=WastingProgressionToSevereEvent( + event=Wasting_ProgressionToSevere_Event( module=self.module, person_id=person), date=outcome_date) # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # @@ -777,15 +778,15 @@ def apply(self, population): outcome_date = self.module.date_of_outcome_for_untreated_wasting(person_id=person) if outcome_date <= self.sim.date: # schedule recovery for today - self.sim.schedule_event(event=WastingNaturalRecoveryEvent( + self.sim.schedule_event(event=Wasting_NaturalRecovery_Event( module=self.module, person_id=person), date=self.sim.date) else: # schedule recovery according to duration - self.sim.schedule_event(event=WastingNaturalRecoveryEvent( + self.sim.schedule_event(event=Wasting_NaturalRecovery_Event( module=self.module, person_id=person), date=outcome_date) -class WastingProgressionToSevereEvent(Event, IndividualScopeEventMixin): +class Wasting_ProgressionToSevere_Event(Event, IndividualScopeEventMixin): """ This Event is for the onset of severe wasting (WHZ < -3). * Refreshes all the properties so that they pertain to this current episode of wasting @@ -819,11 +820,11 @@ def apply(self, person_id): # ------------------------------------------------------------------------------------------- # Add this severe wasting incident case to the tracker - age_group = WastingIncidencePollingEvent.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') + age_group = Wasting_IncidencePoll.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') m.wasting_incident_case_tracker[age_group]['WHZ<-3'].append(self.sim.date) -class WastingSevereAcuteMalnutritionDeathEvent(Event, IndividualScopeEventMixin): +class Wasting_SevereAcuteMalnutritionDeath_Event(Event, IndividualScopeEventMixin): """ This event applies the death function """ @@ -849,7 +850,7 @@ def apply(self, person_id): originating_module=self.module) -class WastingNaturalRecoveryEvent(Event, IndividualScopeEventMixin): +class Wasting_NaturalRecovery_Event(Event, IndividualScopeEventMixin): """ This event improves wasting by 1 SD, based on home care/improvement without interventions. MUAC, oedema, clinical state of acute malnutrition, and if SAM complications are updated, @@ -882,7 +883,7 @@ def apply(self, person_id): df.at[person_id, 'un_am_recovery_date'] = self.sim.date -class WastingClinicalAcuteMalnutritionRecoveryEvent(Event, IndividualScopeEventMixin): +class Wasting_ClinicalAcuteMalnutritionRecovery_Event(Event, IndividualScopeEventMixin): """ This event sets wasting properties back to normal state. """ @@ -912,7 +913,7 @@ def apply(self, person_id): ) -class WastingUpdateToMAM(Event, IndividualScopeEventMixin): +class Wasting_UpdateToMAM_Event(Event, IndividualScopeEventMixin): """ This event updates the properties for those cases that remained/improved from SAM to MAM following treatment @@ -938,8 +939,7 @@ def apply(self, person_id): # TODO: I think this changes the proportions below as some of the cases will be issued here else: - # using the probability of mam classification by anthropometric - # indices + # using the probability of mam classification by anthropometric indices mam_classification = rng.choice(['mam_by_muac_only', 'mam_by_muac_and_whz', 'mam_by_whz_only'], p=[p['proportion_mam_with_MUAC_[115-125)mm_and_normal_whz'], p['proportion_mam_with_MUAC_[115-125)mm_and_-3<=WHZ<-2'], @@ -1079,7 +1079,7 @@ def did_not_run(self): pass -class HSI_Wasting_InpatientCareForComplicated_SAM(HSI_Event, IndividualScopeEventMixin): +class HSI_Wasting_InpatientCare_ComplicatedSAM(HSI_Event, IndividualScopeEventMixin): """ This is the inpatient management of SAM with medical complications """ @@ -1131,6 +1131,74 @@ def did_not_run(self): pass +class HSI_Wasting_GrowthMonitoring(HSI_Event, PopulationScopeEventMixin): + """ Growth Monitoring is conducted every month. MAM/SAM can be diagnosed and children scheduled for appropriate + treatment. + """ + + def __init__(self, module): + super().__init__(module) + assert isinstance(module, Wasting) + + self.TREATMENT_ID = "Undernutrition_GrowthMonitoring" + self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({'Under5OPD': 1}) + # TODO: update the # to smt like #Under5 * prob_attend_growth_monitoring + self.ACCEPTED_FACILITY_LEVEL = '1a' + + def apply(self, population, squeeze_factor): + logger.debug(key='debug', data='This is HSI_Wasting_GrowthMonitoring') + + df = population.props + p = self.module.parameters + rng = self.module.rng + + wasted_not_treated = df.loc[ + df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category != 'WHZ>=-2') & + ~df.un_am_treatment_type.isin(['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']) + ] + + self.add_equipment({'Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape'}) + + def schedule_events_by_coverage(idx, coverage_prob, hsi_event): + if len(idx) > 0: + random_samples = rng.random_sample(size=len(idx)) + coverage = random_samples < coverage_prob + for person_id in idx[coverage]: + self.sim.modules['HealthSystem'].schedule_hsi_event( + hsi_event=hsi_event(module=self.module, person_id=person_id), + priority=0, topen=self.sim.date # TODO: to any random date within the month? + ) + + # get the clinical states + clinical_am = wasted_not_treated['un_clinical_acute_malnutrition'] + complications = wasted_not_treated['un_sam_with_complications'] + + # MAM diagnoses + mam_cases_idx = np.where(clinical_am == 'MAM')[0] + schedule_events_by_coverage(mam_cases_idx, p['coverage_supplementary_feeding_program'], + HSI_Wasting_SupplementaryFeedingProgramme_MAM) + # uncomplicated SAM diagnoses + uncomplicated_sam_cases_idx = np.where((clinical_am == 'SAM') & (~complications))[0] + schedule_events_by_coverage(uncomplicated_sam_cases_idx, p['coverage_outpatient_therapeutic_care'], + HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + # complicated SAM diagnoses + complicated_sam_cases_idx = np.where((clinical_am == 'SAM') & complications)[0] + assert len(clinical_am) == len(mam_cases_idx) + len(uncomplicated_sam_cases_idx) + len(complicated_sam_cases_idx) + schedule_events_by_coverage(complicated_sam_cases_idx, p['coverage_inpatient_care'], + HSI_Wasting_InpatientCare_ComplicatedSAM) + + # schedule growth monitoring for next month + self.sim.modules['HealthSystem'].schedule_hsi_event(hsi_event=HSI_Wasting_GrowthMonitoring(module=self.module), + topen=self.sim.date + pd.DateOffset(months=1), tclose=None, + priority=1) + + def did_not_run(self): + logger.debug(key="HSI_Wasting_GrowthMonitoring", + data="HSI_Wasting_GrowthMonitoring: did not run" + ) + pass + + class WastingModels: """ houses all wasting linear models """ @@ -1247,7 +1315,7 @@ def unscaled_wasting_prevalence_lm(intercept: Union[float, int]) -> LinearModel: return scaled_wasting_prevalence_lm -class WastingLoggingEvent(RegularEvent, PopulationScopeEventMixin): +class Wasting_LoggingEvent(RegularEvent, PopulationScopeEventMixin): """ This Event logs the number of incident cases that have occurred since the previous logging event. Analysis scripts expect that the frequency of this logging event is once per year. diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 1df3d5655a..592f6dde6a 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -25,14 +25,14 @@ ) from tlo.methods.healthseekingbehaviour import HealthSeekingBehaviourPoll from tlo.methods.wasting import ( - HSI_Wasting_InpatientCareForComplicated_SAM, + HSI_Wasting_InpatientCare_ComplicatedSAM, HSI_Wasting_OutpatientTherapeuticProgramme_SAM, - WastingClinicalAcuteMalnutritionRecoveryEvent, - WastingIncidencePollingEvent, - WastingNaturalRecoveryEvent, - WastingProgressionToSevereEvent, - WastingSevereAcuteMalnutritionDeathEvent, - WastingUpdateToMAM, + Wasting_ClinicalAcuteMalnutritionRecovery_Event, + Wasting_IncidencePoll, + Wasting_NaturalRecovery_Event, + Wasting_ProgressionToSevere_Event, + Wasting_SevereAcuteMalnutritionDeath_Event, + Wasting_UpdateToMAM_Event, ) # Path to the resource files used by the disease and intervention methods @@ -196,7 +196,7 @@ def test_wasting_incidence(tmpdir): sim.modules['Wasting'].wasting_models.wasting_incidence_lm = LinearModel.multiplicative() # Run polling event: check that all children should now have moderate wasting: - polling = WastingIncidencePollingEvent(sim.modules['Wasting']) + polling = Wasting_IncidencePoll(sim.modules['Wasting']) polling.apply(sim.population) # Check properties of individuals: should now be moderately wasted @@ -324,7 +324,7 @@ def test_recovery_moderate_wasting(tmpdir): sim.modules['Wasting'].wasting_models.wasting_incidence_lm = LinearModel.multiplicative() # Run Wasting Polling event: This event should cause all young children to be moderate wasting - polling = WastingIncidencePollingEvent(module=sim.modules['Wasting']) + polling = Wasting_IncidencePoll(module=sim.modules['Wasting']) polling.apply(sim.population) # Check properties of this individual: should now be moderately wasted @@ -336,10 +336,10 @@ def test_recovery_moderate_wasting(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Check that there is a WastingNaturalRecoveryEvent scheduled + # Check that there is a Wasting_NaturalRecovery_Event scheduled # for this person recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], WastingNaturalRecoveryEvent)][0] + if isinstance(event_tuple[1], Wasting_NaturalRecovery_Event)][0] date_of_scheduled_recov = recov_event_tuple[0] recov_event = recov_event_tuple[1] assert date_of_scheduled_recov > sim.date @@ -395,16 +395,16 @@ def test_recovery_severe_wasting_without_complications(tmpdir): wmodule.parameters['prob_mam_after_care'] = 1.0 # Run Wasting Polling event to get new incident cases: - polling = WastingIncidencePollingEvent(module=sim.modules['Wasting']) + polling = Wasting_IncidencePoll(module=sim.modules['Wasting']) polling.apply(sim.population) # Check properties of this individual: should now be moderately wasted person = df.loc[person_id] assert person['un_WHZ_category'] == '-3<=WHZ<-2' - # Check that there is a WastingProgressionToSevereEvent scheduled for this person: + # Check that there is a Wasting_ProgressionToSevere_Event scheduled for this person: progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], WastingProgressionToSevereEvent)][0] + if isinstance(event_tuple[1], Wasting_ProgressionToSevere_Event)][0] date_of_scheduled_progression = progression_event_tuple[0] progression_event = progression_event_tuple[1] assert date_of_scheduled_progression > sim.date @@ -451,11 +451,11 @@ def test_recovery_severe_wasting_without_complications(tmpdir): sam_ev.run(squeeze_factor=0.0) # check recovery event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[1][1], WastingUpdateToMAM) + assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_UpdateToMAM_Event) # Run the recovery event and check the individual has recovered from SAM: sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], WastingUpdateToMAM)][0] + isinstance(event_tuple[1], Wasting_UpdateToMAM_Event)][0] date_of_scheduled_recovery_to_mam = sam_recovery_event_tuple[0] sam_recovery_event = sam_recovery_event_tuple[1] @@ -535,21 +535,21 @@ def test_recovery_severe_wasting_with_complications(tmpdir): hsi_event_scheduled = [ ev for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) - if isinstance(ev[1], HSI_Wasting_InpatientCareForComplicated_SAM) + if isinstance(ev[1], HSI_Wasting_InpatientCare_ComplicatedSAM) ] assert 1 == len(hsi_event_scheduled) # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], HSI_Wasting_InpatientCareForComplicated_SAM)][0] + isinstance(ev[1], HSI_Wasting_InpatientCare_ComplicatedSAM)][0] sam_ev.run(squeeze_factor=0.0) # check recovery event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[0][1], WastingClinicalAcuteMalnutritionRecoveryEvent) + assert isinstance(sim.find_events_for_person(person_id)[0][1], Wasting_ClinicalAcuteMalnutritionRecovery_Event) # Run the recovery event and check the individual has recovered from SAM: sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], WastingClinicalAcuteMalnutritionRecoveryEvent)][0] + if isinstance(event_tuple[1], Wasting_ClinicalAcuteMalnutritionRecovery_Event)][0] date_of_scheduled_recovery_to_mam = sam_recovery_event_tuple[0] sam_recovery_event = sam_recovery_event_tuple[1] @@ -637,11 +637,11 @@ def test_nat_hist_death(tmpdir): sam_ev.run(squeeze_factor=0.0) # since there is zero recovery rate, check death event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[0][1], WastingSevereAcuteMalnutritionDeathEvent) + assert isinstance(sim.find_events_for_person(person_id)[0][1], Wasting_SevereAcuteMalnutritionDeath_Event) # # Run the acute death event and ensure the person is now dead: death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], WastingSevereAcuteMalnutritionDeathEvent)][0] + if isinstance(event_tuple[1], Wasting_SevereAcuteMalnutritionDeath_Event)][0] date_of_scheduled_death = death_event_tuple[0] death_event = death_event_tuple[1] assert date_of_scheduled_death > sim.date @@ -684,7 +684,7 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' # Run Wasting Polling event to get new incident cases: - polling = WastingIncidencePollingEvent(module=sim.modules['Wasting']) + polling = Wasting_IncidencePoll(module=sim.modules['Wasting']) polling.apply(sim.population) # Check properties of this individual: (should now be moderately wasted without progression to severe) @@ -696,15 +696,15 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Check that there is a WastingNaturalRecoveryEvent scheduled for this person: + # Check that there is a Wasting_NaturalRecovery_Event scheduled for this person: recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], WastingNaturalRecoveryEvent)][0] + if isinstance(event_tuple[1], Wasting_NaturalRecovery_Event)][0] date_of_scheduled_recov = recov_event_tuple[0] recov_event = recov_event_tuple[1] assert date_of_scheduled_recov > sim.date # Run a Cure Event - cure_event = WastingClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) + cure_event = Wasting_ClinicalAcuteMalnutritionRecovery_Event(person_id=person_id, module=sim.modules['Wasting']) cure_event.apply(person_id=person_id) # Check that the person is not wasted and is alive still: @@ -753,7 +753,7 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # Run Wasting Polling event to get new incident cases: - polling = WastingIncidencePollingEvent(module=sim.modules['Wasting']) + polling = Wasting_IncidencePoll(module=sim.modules['Wasting']) polling.apply(sim.population) # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) @@ -765,10 +765,10 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Check that there is a WastingProgressionToSevereEvent scheduled for this person and if the person is scheduled for + # Check that there is a Wasting_ProgressionToSevere_Event scheduled for this person and if the person is scheduled for # death due to SAM, the death happens after the progression to severe wasting: progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], WastingProgressionToSevereEvent)][0] + if isinstance(event_tuple[1], Wasting_ProgressionToSevere_Event)][0] date_of_scheduled_progression = progression_event_tuple[0] progression_event = progression_event_tuple[1] assert date_of_scheduled_progression > sim.date @@ -813,17 +813,17 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): sam_ev.run(squeeze_factor=0.0) # since there is zero recovery rate, check death event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[1][1], WastingSevereAcuteMalnutritionDeathEvent) + assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_SevereAcuteMalnutritionDeath_Event) # Check a date of death is scheduled. it should be any date in the future: death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], WastingSevereAcuteMalnutritionDeathEvent)][0] + if isinstance(event_tuple[1], Wasting_SevereAcuteMalnutritionDeath_Event)][0] date_of_scheduled_death = death_event_tuple[0] death_event = death_event_tuple[1] assert date_of_scheduled_death > sim.date # Run a Cure Event now - cure_event = WastingClinicalAcuteMalnutritionRecoveryEvent(person_id=person_id, module=sim.modules['Wasting']) + cure_event = Wasting_ClinicalAcuteMalnutritionRecovery_Event(person_id=person_id, module=sim.modules['Wasting']) cure_event.apply(person_id=person_id) # Check that the person is not wasted and is alive still: From 5ae59580e5650499c15f02c3a8c2e1ff716d8643 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 28 Oct 2024 23:26:27 +0000 Subject: [PATCH 136/755] wast: rm duplicated setting of tx_start_date --- src/tlo/methods/wasting.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index b799d9050a..3c3a390e34 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1011,7 +1011,6 @@ def apply(self, person_id, squeeze_factor): if self.get_consumables([item_code1]): logger.debug(key='debug', data='consumables are available') # Log that the treatment is provided: - df.at[person_id, 'un_am_tx_start_date'] = self.sim.date df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=3) df.at[person_id, 'un_am_treatment_type'] = 'CSB++' self.module.do_when_am_treatment(person_id, intervention='SFP') @@ -1066,7 +1065,6 @@ def apply(self, person_id, squeeze_factor): if self.get_consumables(item_code1) and self.get_consumables(item_code2): logger.debug(key='debug', data='consumables are available.') # Log that the treatment is provided: - df.at[person_id, 'un_am_tx_start_date'] = self.sim.date df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=3) df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' self.module.do_when_am_treatment(person_id, intervention='OTC') @@ -1118,7 +1116,6 @@ def apply(self, person_id, squeeze_factor): if self.get_consumables(item_code1) and self.get_consumables(item_code2): logger.debug(key='debug', data='consumables available, so use it.') # Log that the treatment is provided: - df.at[person_id, 'un_am_tx_start_date'] = self.sim.date df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=4) df.at[person_id, 'un_am_treatment_type'] = 'inpatient_care' self.module.do_when_am_treatment(person_id, intervention='ITC') From c7adae133f80c1b7c4f67600d3e4715c4803d724 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Oct 2024 11:25:47 +0000 Subject: [PATCH 137/755] wast: diagnosis any rnd day within the month; fasten run by excluding well group from seeking care sooner --- src/tlo/methods/wasting.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 3c3a390e34..2c30e0d5a2 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -17,6 +17,7 @@ from tlo.methods.healthsystem import HSI_Event from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom +from tlo.util import random_date if TYPE_CHECKING: from tlo.methods.hsi_generic_first_appts import HSIEventScheduler @@ -611,6 +612,10 @@ def do_at_generic_first_appt( clinical_am = individual_properties['un_clinical_acute_malnutrition'] complications = individual_properties['un_sam_with_complications'] + # No interventions if well + if clinical_am == 'well': + return + # Interventions for MAM if clinical_am == 'MAM': # Check for coverage of supplementary feeding @@ -1163,7 +1168,10 @@ def schedule_events_by_coverage(idx, coverage_prob, hsi_event): for person_id in idx[coverage]: self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=hsi_event(module=self.module, person_id=person_id), - priority=0, topen=self.sim.date # TODO: to any random date within the month? + priority=0, topen=random_date( + self.sim.date, + self.sim.date + pd.DateOffset(months=1) - pd.DateOffset(days=1), + rng) ) # get the clinical states From 164f0550dcb5f3075e92fac9b3bd1ed144e52a2c Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Oct 2024 12:10:18 +0000 Subject: [PATCH 138/755] wast: priority=2 for HSI_Wasting_GrowthMonitoring --- src/tlo/methods/wasting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 2c30e0d5a2..1e86f53b93 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -298,7 +298,7 @@ def initialise_simulation(self, sim): sim.modules['HealthSystem'].schedule_hsi_event(hsi_event=HSI_Wasting_GrowthMonitoring(module=self), topen=self.sim.date, tclose=None, - priority=1) + priority=2) sim.schedule_event(Wasting_IncidencePoll(self), sim.date + DateOffset(months=3)) sim.schedule_event(Wasting_LoggingEvent(self), sim.date + DateOffset(years=1) - DateOffset(days=1)) @@ -1195,7 +1195,7 @@ def schedule_events_by_coverage(idx, coverage_prob, hsi_event): # schedule growth monitoring for next month self.sim.modules['HealthSystem'].schedule_hsi_event(hsi_event=HSI_Wasting_GrowthMonitoring(module=self.module), topen=self.sim.date + pd.DateOffset(months=1), tclose=None, - priority=1) + priority=2) def did_not_run(self): logger.debug(key="HSI_Wasting_GrowthMonitoring", From fa8cf23d50cb071e3544d7231579ab5be1cc0d36 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Oct 2024 14:42:23 +0000 Subject: [PATCH 139/755] wast: comment corrected --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 1e86f53b93..a3748e6bb3 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -639,7 +639,7 @@ def do_at_generic_first_appt( return # Interventions for complicated SAM if complications: - # Check for coverage of outpatient therapeutic care + # Check for coverage of inpatient care if self.rng.random_sample() < p['coverage_inpatient_care']: # schedule HSI for supplementary feeding program for MAM schedule_hsi_event( From c2028d6e5d6d387381d723f360698b9787b292a9 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Oct 2024 22:02:45 +0000 Subject: [PATCH 140/755] RF_PriorityRanking_ALLPOLICIES: Undernutrition_GrowthMonitoring added --- .../ResourceFile_PriorityRanking_ALLPOLICIES.xlsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx index e8d9aff1d1..3798feb0eb 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:4838fa5922a84b34de3250077d3465e365a03368e237bbaa5ee37b1ed8abcd85 -size 40616 +oid sha256:99c4cc3e3ca21ddc67c9faee8f05cdef86b4d30e6aaa634b24408a9fffb1452f +size 40926 From 14a8e1185ec991d5e840ad4a3f37ad45d20da350 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 30 Oct 2024 11:47:33 +0000 Subject: [PATCH 141/755] Revert "RF_PriorityRanking_ALLPOLICIES: Undernutrition_GrowthMonitoring added" This reverts commit c2028d6e5d6d387381d723f360698b9787b292a9. --- .../ResourceFile_PriorityRanking_ALLPOLICIES.xlsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx index 3798feb0eb..e8d9aff1d1 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:99c4cc3e3ca21ddc67c9faee8f05cdef86b4d30e6aaa634b24408a9fffb1452f -size 40926 +oid sha256:4838fa5922a84b34de3250077d3465e365a03368e237bbaa5ee37b1ed8abcd85 +size 40616 From 4f8190c7ba0b5d2611279ea10b5eda1cf6410ce5 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Oct 2024 22:02:45 +0000 Subject: [PATCH 142/755] RF_PriorityRanking_ALLPOLICIES: Undernutrition_GrowthMonitoring added; lowest_priority_considered mv to the bottom --- .../ResourceFile_PriorityRanking_ALLPOLICIES.xlsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx index e8d9aff1d1..de82d73ff2 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:4838fa5922a84b34de3250077d3465e365a03368e237bbaa5ee37b1ed8abcd85 -size 40616 +oid sha256:5a779bf34959d66eb3680e954f8c59a274dc79a868a5303f5182091f213bff1d +size 41985 From 17e7f2045ea0d729b4b5af3096fde06bc8d78ce8 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 30 Oct 2024 17:45:08 +0000 Subject: [PATCH 143/755] hs: enforce_priority_policy() fnc updated to work for individual & population hsi_event.target --- src/tlo/methods/healthsystem.py | 54 ++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/src/tlo/methods/healthsystem.py b/src/tlo/methods/healthsystem.py index 5c6b2022e1..3a49d60898 100644 --- a/src/tlo/methods/healthsystem.py +++ b/src/tlo/methods/healthsystem.py @@ -36,6 +36,7 @@ HSIEventQueueItem, HSIEventWrapper, ) +from tlo.population import Population logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -1370,25 +1371,48 @@ def enforce_priority_policy(self, hsi_event) -> int: # Look up relevant attributes for HSI_Event's target list_targets = [_t[0] for _t in self.list_fasttrack] - target_attributes = pdf.loc[hsi_event.target, list_targets] - # Warning: here assuming that the first fast-tracking eligibility encountered - # will determine the priority to be used. If different fast-tracking channels have - # different priorities for the same treatment, this will be a problem! - # First item in Lists is age-related, therefore need to invoke different logic. - if ( - (pr[hsi_event.TREATMENT_ID][self.list_fasttrack[0][1]] > -1) - and (target_attributes['age_exact_years'] <= 5) - ): - return pr[hsi_event.TREATMENT_ID][self.list_fasttrack[0][1]] + # individual hsi_event.target + if not isinstance(hsi_event.target, Population): + target_attributes = pdf.loc[hsi_event.target, list_targets] + + # Warning: here assuming that the first fast-tracking eligibility encountered + # will determine the priority to be used. If different fast-tracking channels have + # different priorities for the same treatment, this will be a problem! + # First item in Lists is age-related, therefore need to invoke different logic. + if ( + (pr[hsi_event.TREATMENT_ID][self.list_fasttrack[0][1]] > -1) + and (target_attributes['age_exact_years'] <= 5).all() + ): + return pr[hsi_event.TREATMENT_ID][self.list_fasttrack[0][1]] + + # All other attributes are looked up the same way, so can do this in for loop + for i in range(1, len(self.list_fasttrack)): + if ( + (pr[hsi_event.TREATMENT_ID][self.list_fasttrack[i][1]] > - 1) + and target_attributes[i] + ): + return pr[hsi_event.TREATMENT_ID][self.list_fasttrack[i][1]] + # population hsi_event.target + else: + target_attributes = pdf.loc[:, list_targets] - # All other attributes are looked up the same way, so can do this in for loop - for i in range(1, len(self.list_fasttrack)): + # Warning: here assuming that the first fast-tracking eligibility encountered + # will determine the priority to be used. If different fast-tracking channels have + # different priorities for the same treatment, this will be a problem! + # First item in Lists is age-related, therefore need to invoke different logic. if ( - (pr[hsi_event.TREATMENT_ID][self.list_fasttrack[i][1]] > - 1) - and target_attributes[i] + (pr[hsi_event.TREATMENT_ID][self.list_fasttrack[0][1]] > -1) + and (target_attributes['age_exact_years'] <= 5).all() ): - return pr[hsi_event.TREATMENT_ID][self.list_fasttrack[i][1]] + return pr[hsi_event.TREATMENT_ID][self.list_fasttrack[0][1]] + + for i in range(1, len(self.list_fasttrack)): + if ( + (pr[hsi_event.TREATMENT_ID][self.list_fasttrack[i][1]] > -1) + and target_attributes[self.list_fasttrack[i][0]].all() + ): + return pr[hsi_event.TREATMENT_ID][self.list_fasttrack[i][1]] return _priority_ranking From 7da7768a64a41d4a9d14da079ee78ef212b8d880 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 30 Oct 2024 17:48:16 +0000 Subject: [PATCH 144/755] scenario_wast_full_model|minimal_model|orig: till the end of 2030 no more no less --- .../wasting_analyses/scenarios/scenario_wasting_full_model.py | 2 +- .../scenarios/scenario_wasting_minimal_model.py | 2 +- src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py index b3653d0134..f4472a6794 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py @@ -25,7 +25,7 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2031, month=1, day=2), + end_date=Date(year=2031, month=1, day=1), initial_population_size=20_000, number_of_draws=1, runs_per_draw=10, diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 3be0d4536f..4b8237dbb6 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -45,7 +45,7 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2031, month=1, day=2), + end_date=Date(year=2031, month=1, day=1), initial_population_size=20_000, number_of_draws=1, runs_per_draw=10, diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py index 8454c13a4f..59f7470afd 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py @@ -45,7 +45,7 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2030, month=1, day=1), + end_date=Date(year=2031, month=1, day=1), initial_population_size=20_000, number_of_draws=1, runs_per_draw=1, From 1c04df100ef04878e5d106fd1a281544782922bd Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 30 Oct 2024 23:14:23 +0000 Subject: [PATCH 145/755] Revert "hs: enforce_priority_policy() fnc updated to work for individual & population hsi_event.target" This reverts commit 17e7f2045ea0d729b4b5af3096fde06bc8d78ce8. --- src/tlo/methods/healthsystem.py | 54 +++++++++------------------------ 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/src/tlo/methods/healthsystem.py b/src/tlo/methods/healthsystem.py index 3a49d60898..5c6b2022e1 100644 --- a/src/tlo/methods/healthsystem.py +++ b/src/tlo/methods/healthsystem.py @@ -36,7 +36,6 @@ HSIEventQueueItem, HSIEventWrapper, ) -from tlo.population import Population logger = logging.getLogger(__name__) logger.setLevel(logging.INFO) @@ -1371,48 +1370,25 @@ def enforce_priority_policy(self, hsi_event) -> int: # Look up relevant attributes for HSI_Event's target list_targets = [_t[0] for _t in self.list_fasttrack] + target_attributes = pdf.loc[hsi_event.target, list_targets] - # individual hsi_event.target - if not isinstance(hsi_event.target, Population): - target_attributes = pdf.loc[hsi_event.target, list_targets] - - # Warning: here assuming that the first fast-tracking eligibility encountered - # will determine the priority to be used. If different fast-tracking channels have - # different priorities for the same treatment, this will be a problem! - # First item in Lists is age-related, therefore need to invoke different logic. - if ( - (pr[hsi_event.TREATMENT_ID][self.list_fasttrack[0][1]] > -1) - and (target_attributes['age_exact_years'] <= 5).all() - ): - return pr[hsi_event.TREATMENT_ID][self.list_fasttrack[0][1]] - - # All other attributes are looked up the same way, so can do this in for loop - for i in range(1, len(self.list_fasttrack)): - if ( - (pr[hsi_event.TREATMENT_ID][self.list_fasttrack[i][1]] > - 1) - and target_attributes[i] - ): - return pr[hsi_event.TREATMENT_ID][self.list_fasttrack[i][1]] - # population hsi_event.target - else: - target_attributes = pdf.loc[:, list_targets] + # Warning: here assuming that the first fast-tracking eligibility encountered + # will determine the priority to be used. If different fast-tracking channels have + # different priorities for the same treatment, this will be a problem! + # First item in Lists is age-related, therefore need to invoke different logic. + if ( + (pr[hsi_event.TREATMENT_ID][self.list_fasttrack[0][1]] > -1) + and (target_attributes['age_exact_years'] <= 5) + ): + return pr[hsi_event.TREATMENT_ID][self.list_fasttrack[0][1]] - # Warning: here assuming that the first fast-tracking eligibility encountered - # will determine the priority to be used. If different fast-tracking channels have - # different priorities for the same treatment, this will be a problem! - # First item in Lists is age-related, therefore need to invoke different logic. + # All other attributes are looked up the same way, so can do this in for loop + for i in range(1, len(self.list_fasttrack)): if ( - (pr[hsi_event.TREATMENT_ID][self.list_fasttrack[0][1]] > -1) - and (target_attributes['age_exact_years'] <= 5).all() + (pr[hsi_event.TREATMENT_ID][self.list_fasttrack[i][1]] > - 1) + and target_attributes[i] ): - return pr[hsi_event.TREATMENT_ID][self.list_fasttrack[0][1]] - - for i in range(1, len(self.list_fasttrack)): - if ( - (pr[hsi_event.TREATMENT_ID][self.list_fasttrack[i][1]] > -1) - and target_attributes[self.list_fasttrack[i][0]].all() - ): - return pr[hsi_event.TREATMENT_ID][self.list_fasttrack[i][1]] + return pr[hsi_event.TREATMENT_ID][self.list_fasttrack[i][1]] return _priority_ranking From dbcd5771bbaee2a8d20d7c04151b2e98e7130e62 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 8 Nov 2024 23:46:20 +0000 Subject: [PATCH 146/755] wast & RF_Wast: used coverage wasn't treatment coverage, hence rm --- resources/ResourceFile_Wasting.csv | 4 +-- src/tlo/methods/wasting.py | 48 +++++++++++------------------- 2 files changed, 19 insertions(+), 33 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 1365452bd6..5e10b0f75d 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c5df521ce5c4ea1c5daef144c63bd37b61c769fd18a07e6b07132fcb3e5c634e -size 2859 +oid sha256:85abf8b9c436068f6423778312a872a44792932e9aff1c7f89b5df7f616845c0 +size 2614 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index a3748e6bb3..0186c05b36 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -143,12 +143,6 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'proportion_oedema_with_WHZ<-2': Parameter( Types.REAL, 'proportion of individuals with oedema who are wasted (moderately or severely)'), # treatment/interventions - 'coverage_supplementary_feeding_program': Parameter( - Types.REAL, 'coverage of supplementary feeding program for MAM in health centres'), - 'coverage_outpatient_therapeutic_care': Parameter( - Types.REAL, 'coverage of outpatient therapeutic care for SAM in health centres'), - 'coverage_inpatient_care': Parameter( - Types.REAL, 'coverage of inpatient care for complicated SAM in hospitals'), 'prob_mam_after_care': Parameter( Types.REAL, 'probability of returning to MAM after seeking care'), 'prob_death_after_care': Parameter( @@ -617,36 +611,28 @@ def do_at_generic_first_appt( return # Interventions for MAM - if clinical_am == 'MAM': - # Check for coverage of supplementary feeding - if self.rng.random_sample() < p['coverage_supplementary_feeding_program']: + elif clinical_am == 'MAM': + # schedule HSI for supplementary feeding program for MAM + schedule_hsi_event( + hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), + priority=0, topen=self.sim.date) + + elif clinical_am == 'SAM': + + # Interventions for uncomplicated SAM + if not complications: # schedule HSI for supplementary feeding program for MAM schedule_hsi_event( - hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), + hsi_event=HSI_Wasting_OutpatientTherapeuticProgramme_SAM(module=self, person_id=person_id), priority=0, topen=self.sim.date) - else: - return - # Interventions for uncomplicated SAM - if clinical_am == 'SAM': - if not complications: - # Check for coverage of outpatient therapeutic care - if self.rng.random_sample() < p['coverage_outpatient_therapeutic_care']: - # schedule HSI for supplementary feeding program for MAM - schedule_hsi_event( - hsi_event=HSI_Wasting_OutpatientTherapeuticProgramme_SAM( - module=self, person_id=person_id), priority=0, topen=self.sim.date) - else: - return + # Interventions for complicated SAM if complications: - # Check for coverage of inpatient care - if self.rng.random_sample() < p['coverage_inpatient_care']: - # schedule HSI for supplementary feeding program for MAM - schedule_hsi_event( - hsi_event=HSI_Wasting_InpatientCare_ComplicatedSAM( - module=self, person_id=person_id), priority=0, topen=self.sim.date) - else: - return + # schedule HSI for supplementary feeding program for MAM + schedule_hsi_event( + hsi_event=HSI_Wasting_InpatientCare_ComplicatedSAM(module=self, person_id=person_id), + priority=0, topen=self.sim.date) + def do_when_am_treatment(self, person_id, intervention): """ From 35acc35864601f600a889525161676616e3258a1 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 9 Nov 2024 23:30:55 +0000 Subject: [PATCH 147/755] wast: HSI_Wasting_GrowthMonitoring changed to IndividualScope (incl. TODOs) --- src/tlo/methods/wasting.py | 265 ++++++++++++++++++++++++++----------- 1 file changed, 188 insertions(+), 77 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 0186c05b36..74d78103e5 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -17,7 +17,6 @@ from tlo.methods.healthsystem import HSI_Event from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom -from tlo.util import random_date if TYPE_CHECKING: from tlo.methods.hsi_generic_first_appts import HSIEventScheduler @@ -290,9 +289,7 @@ def initialise_simulation(self, sim): * the main logging event. """ - sim.modules['HealthSystem'].schedule_hsi_event(hsi_event=HSI_Wasting_GrowthMonitoring(module=self), - topen=self.sim.date, tclose=None, - priority=2) + sim.schedule_event(Wasting_InitiateGrowthMonitoring(self), sim.date) sim.schedule_event(Wasting_IncidencePoll(self), sim.date + DateOffset(months=3)) sim.schedule_event(Wasting_LoggingEvent(self), sim.date + DateOffset(years=1) - DateOffset(days=1)) @@ -600,7 +597,8 @@ def do_at_generic_first_appt( (individual_properties["un_am_treatment_type"] in ['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']): return - p = self.parameters + + # p = self.parameters # get the clinical states clinical_am = individual_properties['un_clinical_acute_malnutrition'] @@ -633,7 +631,6 @@ def do_at_generic_first_appt( hsi_event=HSI_Wasting_InpatientCare_ComplicatedSAM(module=self, person_id=person_id), priority=0, topen=self.sim.date) - def do_when_am_treatment(self, person_id, intervention): """ This function will apply the linear model of recovery based on intervention given @@ -964,6 +961,191 @@ def apply(self, person_id): ) +class Wasting_InitiateGrowthMonitoring(Event, PopulationScopeEventMixin): + # TODO: will be updated for children 1-5 (monitoring for 0-1 will be integrated in epi module) + # For now, children are only monitored if in population when sim. initiated, but when new child born, it is not + # scheduled for monitoring at all yet, it needs to be done in the epi module, or if better, done in epi for 0-1, + # and scheduled to be done in here from when they are 1y old + """ + Event that schedules HSI_Wasting_GrowthMonitoring for all under-5 children for a random day within the age-dependent + frequency. + """ + + def __init__(self, module): + """Runs only once, when simulation is initiated. + :param module: the module that created this event + """ + super().__init__(module) + assert isinstance(module, Wasting) + + def apply(self, population): + """Apply this event to the population. + :param population: the current population + """ + + df = population.props + # p = self.module.parameters + rng = self.module.rng + + # TODO: including treated children? + index_under5 = df.index[df.is_alive & (df.age_exact_years < 5)] + # and ~df.un_am_treatment_type.isin(['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']) + + def get_monitoring_frequency_days(age): + if age < 2: # TODO: expecting here, that 0-1 will be excluded and dealt with within epi module + return int(365.25 / 5) # 5 appts a year # TODO: add as parameters p[''] + else: + return int(365.25 / 2) # 2 appts a year # TODO: add as parameters p[''] + + # schedule monitoring within age-dependent frequency + for person_id in index_under5: + next_event_days = rng.randint(0, (get_monitoring_frequency_days(df.at[person_id, 'age_exact_years']) - 2)) + if (df.at[person_id, 'age_exact_years'] + (next_event_days / 365.25)) < 5: + self.sim.modules['HealthSystem'].schedule_hsi_event( + hsi_event=HSI_Wasting_GrowthMonitoring(module=self.module, person_id=person_id), + priority=2, topen=self.sim.date + pd.DateOffset(days=next_event_days) + ) + + +class HSI_Wasting_GrowthMonitoring(HSI_Event, IndividualScopeEventMixin): + """ Attendance is determined for the HSI. If the child attends, measurements with available equipment are performed + for that child. Based on these measurements, the child can be diagnosed as well/MAM/SAM and eventually scheduled + for appropriate treatment. If the child (attending or not) is still under 5 at the time of the next growth + monitoring, the next event is scheduled with age-dependent frequency. + """ + + def __init__(self, module, person_id): + super().__init__(module, person_id=person_id) + assert isinstance(module, Wasting) + + self.attendance = None + + self.TREATMENT_ID = "Undernutrition_GrowthMonitoring" + self.ACCEPTED_FACILITY_LEVEL = '1a' + + @property + def EXPECTED_APPT_FOOTPRINT(self): + """Return the expected appt footprint based on contraception method and whether the HSI has been rescheduled.""" + rng = self.module.rng + person_id = self.target + person_age = self.sim.population.props.loc[person_id].age_exact_years + + def get_attendance_prob(age): + if age < 2: # TODO: expecting here, that 0-1 will be excluded and dealt with within epi module + return 0.14 # TODO: add as parameters p[''] + else: + return 0.5 # TODO: add as parameters p[''] + + # perform growth monitoring if attending + self.attendance = rng.random_sample() < get_attendance_prob(person_age) + if self.attendance: + return self.make_appt_footprint({'Under5OPD': 1}) + else: + return self.make_appt_footprint({}) + + def apply(self, person_id, squeeze_factor): + logger.debug(key='debug', data='This is HSI_Wasting_GrowthMonitoring') + + df = self.sim.population.props + # p = self.module.parameters + rng = self.module.rng + + # TODO: Will they be monitored during the treatment? Can we assume, that after the treatment they will be + # always properly checked (all measurements and oedema checked), or should be the assumed "treatment outcome" + # be also based on equipment availability and probability of checking oedema? Maybe they should be sent for + # after treatment monitoring, where the assumed "treatment outcome" will be determined and follow-up treatment + # based on that? - The easiest way (currently coded) is assuming that after treatment all measurements are + # done, hence correctly diagnosed. The growth monitoring is scheduled for them as usual, ie, for instance, for + # a child 2-5 old, if they were sent for treatment via growth monitoring, they will be on treatment 3 or 4 + # weeks, but next monitoring will be done in ~5 months after the treatment. - Or we could schedule for the + # treated children a monitoring sooner after the treatment. + if (~df.at[person_id, 'is_alive']) or (df.at[person_id, 'age_exact_years'] >= 5): + # or + # df.at[person_id, 'un_am_treatment_type'].isin(['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']): + return + + def schedule_next_monitoring(): + def get_monitoring_frequency_days(age): + if age < 2: # TODO: expecting here, that 0-1 will be excluded and dealt with within epi module + return int(365.25 / 5) # 5 appts a year # TODO: add as parameters p[''] + else: + return int(365.25 / 2) # 2 appts a year # TODO: add as parameters p[''] + + person_monitoring_frequency = get_monitoring_frequency_days(df.at[person_id, 'age_exact_years']) + if (df.at[person_id, 'age_exact_years'] + (person_monitoring_frequency / 365.25)) < 5: + # schedule next growth monitoring + self.sim.modules['HealthSystem'].schedule_hsi_event( + hsi_event=HSI_Wasting_GrowthMonitoring(module=self.module, person_id=person_id), + topen=self.sim.date + pd.DateOffset(days=person_monitoring_frequency), + tclose=None, + priority=2 + ) + + # TODO: as stated above, for now we schedule next monitoring for all children, even those sent for treatment + schedule_next_monitoring() + + if not self.attendance: + return + + # TODO: check availability of equipment and base diagnosis on equipment used + available_equipment = ['Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape'] + self.add_equipment(set(available_equipment)) + + def schedule_tx_by_diagnosis(hsi_event): + self.sim.modules['HealthSystem'].schedule_hsi_event( + hsi_event=hsi_event(module=self.module, person_id=person_id), + priority=0, topen=self.sim.date + ) + + complications = df.at[person_id, 'un_sam_with_complications'] + oedema_checked = rng.random_sample() < 0.1 # TODO: find correct value & add as parameter p[''] + # diagnosis based on measurements that can be performed with available equipment + if oedema_checked and df.at[person_id, 'un_am_bilateral_oedema']: + diagnosis = 'SAM' + else: + if all(item in available_equipment for item in + ['Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape']): + if oedema_checked: + diagnosis = df.at[person_id, 'un_clinical_acute_malnutrition'] + else: + whz = df.at[person_id, 'un_WHZ_category'] + muac = df.at[person_id, 'un_am_MUAC_category'] + # if person well + if whz == 'WHZ>=-2' and muac == '>=125mm': + diagnosis = 'well' + elif whz == 'WHZ<-3' or muac == '<115mm': + diagnosis = 'SAM' + else: + diagnosis = 'MAM' + else: + diagnosis = 'well' + # TODO: update the above, define what to do otherwise: + # if height pole or weight scale not available & MUAC tape avail. + # => low MUAC = SAM, middle MUAC = MAM, normal MUAC = well; + # if height pole and weight scale avail & MUAC not avail + # => low WHZ = SAM, middle WHZ = MAM, normal WHZ = well; + # if height pole or weight scale not avail & MUAC not avail + # => ? could we assume that in that case, they will at least check the oedema? or what? + + # TODO: will the presence of complications change the above diagnosis, or will it be taken in account + # only if SAM is diagnosed based on the above? + + if diagnosis == 'well': + return + elif diagnosis == 'MAM': + schedule_tx_by_diagnosis(HSI_Wasting_SupplementaryFeedingProgramme_MAM) + elif (diagnosis == 'SAM') and (~complications): + schedule_tx_by_diagnosis(HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + elif (diagnosis == 'SAM') and complications: + schedule_tx_by_diagnosis(HSI_Wasting_InpatientCare_ComplicatedSAM) + + def did_not_run(self): + logger.debug(key="HSI_Wasting_GrowthMonitoring", + data="HSI_Wasting_GrowthMonitoring: did not run" + ) + pass + + class HSI_Wasting_SupplementaryFeedingProgramme_MAM(HSI_Event, IndividualScopeEventMixin): """ This is the supplementary feeding programme for MAM without complications @@ -1119,77 +1301,6 @@ def did_not_run(self): pass -class HSI_Wasting_GrowthMonitoring(HSI_Event, PopulationScopeEventMixin): - """ Growth Monitoring is conducted every month. MAM/SAM can be diagnosed and children scheduled for appropriate - treatment. - """ - - def __init__(self, module): - super().__init__(module) - assert isinstance(module, Wasting) - - self.TREATMENT_ID = "Undernutrition_GrowthMonitoring" - self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({'Under5OPD': 1}) - # TODO: update the # to smt like #Under5 * prob_attend_growth_monitoring - self.ACCEPTED_FACILITY_LEVEL = '1a' - - def apply(self, population, squeeze_factor): - logger.debug(key='debug', data='This is HSI_Wasting_GrowthMonitoring') - - df = population.props - p = self.module.parameters - rng = self.module.rng - - wasted_not_treated = df.loc[ - df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category != 'WHZ>=-2') & - ~df.un_am_treatment_type.isin(['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']) - ] - - self.add_equipment({'Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape'}) - - def schedule_events_by_coverage(idx, coverage_prob, hsi_event): - if len(idx) > 0: - random_samples = rng.random_sample(size=len(idx)) - coverage = random_samples < coverage_prob - for person_id in idx[coverage]: - self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=hsi_event(module=self.module, person_id=person_id), - priority=0, topen=random_date( - self.sim.date, - self.sim.date + pd.DateOffset(months=1) - pd.DateOffset(days=1), - rng) - ) - - # get the clinical states - clinical_am = wasted_not_treated['un_clinical_acute_malnutrition'] - complications = wasted_not_treated['un_sam_with_complications'] - - # MAM diagnoses - mam_cases_idx = np.where(clinical_am == 'MAM')[0] - schedule_events_by_coverage(mam_cases_idx, p['coverage_supplementary_feeding_program'], - HSI_Wasting_SupplementaryFeedingProgramme_MAM) - # uncomplicated SAM diagnoses - uncomplicated_sam_cases_idx = np.where((clinical_am == 'SAM') & (~complications))[0] - schedule_events_by_coverage(uncomplicated_sam_cases_idx, p['coverage_outpatient_therapeutic_care'], - HSI_Wasting_OutpatientTherapeuticProgramme_SAM) - # complicated SAM diagnoses - complicated_sam_cases_idx = np.where((clinical_am == 'SAM') & complications)[0] - assert len(clinical_am) == len(mam_cases_idx) + len(uncomplicated_sam_cases_idx) + len(complicated_sam_cases_idx) - schedule_events_by_coverage(complicated_sam_cases_idx, p['coverage_inpatient_care'], - HSI_Wasting_InpatientCare_ComplicatedSAM) - - # schedule growth monitoring for next month - self.sim.modules['HealthSystem'].schedule_hsi_event(hsi_event=HSI_Wasting_GrowthMonitoring(module=self.module), - topen=self.sim.date + pd.DateOffset(months=1), tclose=None, - priority=2) - - def did_not_run(self): - logger.debug(key="HSI_Wasting_GrowthMonitoring", - data="HSI_Wasting_GrowthMonitoring: did not run" - ) - pass - - class WastingModels: """ houses all wasting linear models """ From cfa03aa36ba612e1f9bf18cae33a4730f7ae3c1e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 10 Nov 2024 17:26:01 +0000 Subject: [PATCH 148/755] wast: improved code readability --- src/tlo/methods/wasting.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 74d78103e5..35eb8677a2 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -449,9 +449,12 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): df = pop_dataframe p = self.parameters + whz = df.at[person_id, 'un_WHZ_category'] + muac = df.at[person_id, 'un_am_MUAC_category'] + oedema_presence = df.at[person_id, 'un_am_bilateral_oedema'] + # if person well - if ((df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2') & - (df.at[person_id, 'un_am_MUAC_category'] == '>=125mm') & (~df.at[person_id, 'un_am_bilateral_oedema'])): + if (whz == 'WHZ>=-2') and (muac == '>=125mm') and (not oedema_presence): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' # if person not well else: @@ -459,8 +462,7 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): df.at[person_id, 'un_am_treatment_type'] = 'none' # severe acute malnutrition (SAM): MUAC < 115 mm and/or WHZ < -3 and/or bilateral oedema - if ((df.at[person_id, 'un_am_MUAC_category'] == '<115mm') - | (df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3') | (df.at[person_id, 'un_am_bilateral_oedema'])): + if (muac == '<115mm') or (whz == 'WHZ<-3') or oedema_presence: df.at[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' # apply symptoms to all SAM cases self.wasting_clinical_symptoms(person_id=person_id) @@ -482,8 +484,8 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): person_id=person_id, disease_module=self ) - assert not (df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') & \ - (df.at[person_id, 'un_sam_with_complications']) + assert not ((df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') + and (df.at[person_id, 'un_sam_with_complications'])) def date_of_outcome_for_untreated_wasting(self, person_id): """ @@ -1059,7 +1061,7 @@ def apply(self, person_id, squeeze_factor): # a child 2-5 old, if they were sent for treatment via growth monitoring, they will be on treatment 3 or 4 # weeks, but next monitoring will be done in ~5 months after the treatment. - Or we could schedule for the # treated children a monitoring sooner after the treatment. - if (~df.at[person_id, 'is_alive']) or (df.at[person_id, 'age_exact_years'] >= 5): + if (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'age_exact_years'] >= 5): # or # df.at[person_id, 'un_am_treatment_type'].isin(['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']): return @@ -1134,7 +1136,7 @@ def schedule_tx_by_diagnosis(hsi_event): return elif diagnosis == 'MAM': schedule_tx_by_diagnosis(HSI_Wasting_SupplementaryFeedingProgramme_MAM) - elif (diagnosis == 'SAM') and (~complications): + elif (diagnosis == 'SAM') and (not complications): schedule_tx_by_diagnosis(HSI_Wasting_OutpatientTherapeuticProgramme_SAM) elif (diagnosis == 'SAM') and complications: schedule_tx_by_diagnosis(HSI_Wasting_InpatientCare_ComplicatedSAM) From d4e93222deedf8314bc977ec6852f391fbe60b30 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 10 Nov 2024 18:36:14 +0000 Subject: [PATCH 149/755] wast & RF_Wast: parameters added and used --- resources/ResourceFile_Wasting.csv | 4 +- src/tlo/methods/wasting.py | 80 +++++++++++++++++------------- 2 files changed, 47 insertions(+), 37 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 5e10b0f75d..dac2e36dca 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:85abf8b9c436068f6423778312a872a44792932e9aff1c7f89b5df7f616845c0 -size 2614 +oid sha256:8d425bd0d03fdaa419751994ba608124834e9578ec74438bfa271e95b69a1200 +size 2821 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 35eb8677a2..6da010ced7 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -90,7 +90,7 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.REAL, 'odds ratio of wasting if born preterm and small for gestational age'), # incidence 'base_inc_rate_wasting_by_agegp': Parameter( - Types.LIST, 'List with baseline incidence of wasting by age group'), + Types.LIST, 'List with baseline incidence rate of moderate wasting by age group'), 'rr_wasting_preterm_and_AGA': Parameter( Types.REAL, 'relative risk of wasting if born preterm and adequate for gestational age'), 'rr_wasting_SGA_and_term': Parameter( @@ -111,15 +111,6 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'prob_complications_in_SAM': Parameter( Types.REAL, 'probability of medical complications in SAM '), # MUAC distributions - 'MUAC_distribution_WHZ<-3': Parameter( - Types.LIST, - 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ < -3'), - 'MUAC_distribution_-3<=WHZ<-2': Parameter( - Types.LIST, - 'mean and standard deviation of a normal distribution of MUAC measurements for -3 <= WHZ < -2'), - 'MUAC_distribution_WHZ>=-2': Parameter( - Types.LIST, - 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ >= -2'), 'proportion_WHZ<-3_with_MUAC<115mm': Parameter( Types.REAL, 'proportion of individuals with severe wasting who have MUAC < 115 mm'), 'proportion_-3<=WHZ<-2_with_MUAC<115mm': Parameter( @@ -134,6 +125,15 @@ class Wasting(Module, GenericFirstAppointmentsMixin): ' wasting'), 'proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC': Parameter( Types.REAL, 'proportion of individuals with MAM who have moderate wasting and normal MUAC'), + 'MUAC_distribution_WHZ<-3': Parameter( + Types.LIST, + 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ < -3'), + 'MUAC_distribution_-3<=WHZ<-2': Parameter( + Types.LIST, + 'mean and standard deviation of a normal distribution of MUAC measurements for -3 <= WHZ < -2'), + 'MUAC_distribution_WHZ>=-2': Parameter( + Types.LIST, + 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ >= -2'), # bilateral oedema 'prevalence_nutritional_oedema': Parameter( Types.REAL, 'prevalence of nutritional oedema in children under 5 in Malawi'), @@ -141,18 +141,18 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.REAL, 'proportion of individuals with wasting (moderate or severe) who have oedema'), 'proportion_oedema_with_WHZ<-2': Parameter( Types.REAL, 'proportion of individuals with oedema who are wasted (moderately or severely)'), - # treatment/interventions - 'prob_mam_after_care': Parameter( - Types.REAL, 'probability of returning to MAM after seeking care'), - 'prob_death_after_care': Parameter( - Types.REAL, 'probability of dying after seeking care'), + # detection + 'growth_monitoring_frequency_days': Parameter( + Types.LIST, 'growth monitoring frequency (days), for children [1–2, 2–5] years old'), + 'growth_monitoring_attendance_prob': Parameter( + Types.LIST, 'probability to attend the growth monitoring, for children [1–2, 2–5] years old'), # recovery due to treatment/interventions - 'recovery_rate_with_standard_RUTF': Parameter( - Types.REAL, 'probability of recovery from wasting following treatment with standard RUTF'), 'recovery_rate_with_soy_RUSF': Parameter( Types.REAL, 'probability of recovery from wasting following treatment with soy RUSF'), 'recovery_rate_with_CSB++': Parameter( Types.REAL, 'probability of recovery from wasting following treatment with CSB++'), + 'recovery_rate_with_standard_RUTF': Parameter( + Types.REAL, 'probability of recovery from wasting following treatment with standard RUTF'), 'recovery_rate_with_inpatient_care': Parameter( Types.REAL, 'probability of recovery from wasting following treatment with inpatient care'), 'tx_length_weeks_SuppFeedingMAM': Parameter( @@ -164,6 +164,11 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'tx_length_weeks_InpatientSAM': Parameter( Types.REAL, 'number of weeks the patient receives treatment in the Inpatient Care for complicated' ' SAM before being discharged if they do not die beforehand'), + # treatment/intervention outcomes + 'prob_mam_after_care': Parameter( + Types.REAL, 'probability of returning to MAM after seeking care'), + 'prob_death_after_care': Parameter( + Types.REAL, 'probability of dying after seeking care'), } PROPERTIES = { @@ -724,8 +729,7 @@ def apply(self, population): # # # INCIDENCE OF MODERATE WASTING # # # # # # # # # # # # # # # # # # # # # # Determine who will be onset with wasting among those who are not currently wasted ------------- - not_wasted = df.loc[df.is_alive & (df.age_exact_years < 5) & ( - df.un_WHZ_category == 'WHZ>=-2')] + not_wasted = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == 'WHZ>=-2')] incidence_of_wasting = self.module.wasting_models.wasting_incidence_lm.predict(not_wasted, rng=rng) mod_wasting_new_cases_idx = not_wasted.index[incidence_of_wasting] # update the properties for new cases of wasted children @@ -986,7 +990,7 @@ def apply(self, population): """ df = population.props - # p = self.module.parameters + p = self.module.parameters rng = self.module.rng # TODO: including treated children? @@ -994,10 +998,10 @@ def apply(self, population): # and ~df.un_am_treatment_type.isin(['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']) def get_monitoring_frequency_days(age): - if age < 2: # TODO: expecting here, that 0-1 will be excluded and dealt with within epi module - return int(365.25 / 5) # 5 appts a year # TODO: add as parameters p[''] + if age <= 2: # TODO: expecting here, that 0-1 will be excluded and dealt with within epi module + return p['growth_monitoring_frequency_days'][0] else: - return int(365.25 / 2) # 2 appts a year # TODO: add as parameters p[''] + return p['growth_monitoring_frequency_days'][1] # schedule monitoring within age-dependent frequency for person_id in index_under5: @@ -1028,15 +1032,15 @@ def __init__(self, module, person_id): @property def EXPECTED_APPT_FOOTPRINT(self): """Return the expected appt footprint based on contraception method and whether the HSI has been rescheduled.""" + p = self.module.parameters rng = self.module.rng - person_id = self.target - person_age = self.sim.population.props.loc[person_id].age_exact_years + person_age = self.sim.population.props.loc[self.target].age_exact_years def get_attendance_prob(age): - if age < 2: # TODO: expecting here, that 0-1 will be excluded and dealt with within epi module - return 0.14 # TODO: add as parameters p[''] + if age <= 2: # TODO: expecting here, that 0-1 will be excluded and dealt with within epi module + return p['growth_monitoring_attendance_prob'][0] else: - return 0.5 # TODO: add as parameters p[''] + return p['growth_monitoring_attendance_prob'][1] # perform growth monitoring if attending self.attendance = rng.random_sample() < get_attendance_prob(person_age) @@ -1049,7 +1053,7 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data='This is HSI_Wasting_GrowthMonitoring') df = self.sim.population.props - # p = self.module.parameters + p = self.module.parameters rng = self.module.rng # TODO: Will they be monitored during the treatment? Can we assume, that after the treatment they will be @@ -1068,10 +1072,10 @@ def apply(self, person_id, squeeze_factor): def schedule_next_monitoring(): def get_monitoring_frequency_days(age): - if age < 2: # TODO: expecting here, that 0-1 will be excluded and dealt with within epi module - return int(365.25 / 5) # 5 appts a year # TODO: add as parameters p[''] + if age <= 2: # TODO: expecting here, that 0-1 will be excluded and dealt with within epi module + return p['growth_monitoring_frequency_days'][0] else: - return int(365.25 / 2) # 2 appts a year # TODO: add as parameters p[''] + return p['growth_monitoring_frequency_days'][1] person_monitoring_frequency = get_monitoring_frequency_days(df.at[person_id, 'age_exact_years']) if (df.at[person_id, 'age_exact_years'] + (person_monitoring_frequency / 365.25)) < 5: @@ -1170,6 +1174,7 @@ def __init__(self, module, person_id): def apply(self, person_id, squeeze_factor): df = self.sim.population.props + p = self.module.parameters if not df.at[person_id, 'is_alive']: return @@ -1186,7 +1191,8 @@ def apply(self, person_id, squeeze_factor): if self.get_consumables([item_code1]): logger.debug(key='debug', data='consumables are available') # Log that the treatment is provided: - df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=3) + df.at[person_id, 'un_am_discharge_date'] = \ + self.sim.date + DateOffset(weeks=p['tx_length_weeks_SuppFeedingMAM']) df.at[person_id, 'un_am_treatment_type'] = 'CSB++' self.module.do_when_am_treatment(person_id, intervention='SFP') else: @@ -1220,6 +1226,7 @@ def __init__(self, module, person_id): def apply(self, person_id, squeeze_factor): df = self.sim.population.props + p = self.module.parameters if not df.at[person_id, 'is_alive']: return @@ -1240,7 +1247,8 @@ def apply(self, person_id, squeeze_factor): if self.get_consumables(item_code1) and self.get_consumables(item_code2): logger.debug(key='debug', data='consumables are available.') # Log that the treatment is provided: - df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=3) + df.at[person_id, 'un_am_discharge_date'] = \ + self.sim.date + DateOffset(weeks=p['tx_length_weeks_OutpatientSAM']) df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' self.module.do_when_am_treatment(person_id, intervention='OTC') else: @@ -1274,6 +1282,7 @@ def __init__(self, module, person_id): def apply(self, person_id, squeeze_factor): df = self.sim.population.props + p = self.module.parameters # Stop the person from dying of acute malnutrition (if they were going to die) if not df.at[person_id, 'is_alive']: @@ -1291,7 +1300,8 @@ def apply(self, person_id, squeeze_factor): if self.get_consumables(item_code1) and self.get_consumables(item_code2): logger.debug(key='debug', data='consumables available, so use it.') # Log that the treatment is provided: - df.at[person_id, 'un_am_discharge_date'] = self.sim.date + DateOffset(weeks=4) + df.at[person_id, 'un_am_discharge_date'] = \ + self.sim.date + DateOffset(weeks=p['tx_length_weeks_InpatientSAM']) df.at[person_id, 'un_am_treatment_type'] = 'inpatient_care' self.module.do_when_am_treatment(person_id, intervention='ITC') else: From a1542f34870af0c9271dd417ce22ec1099d58046 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 12 Nov 2024 18:38:53 +0000 Subject: [PATCH 150/755] wast: vars names and description updated --- src/tlo/methods/wasting.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 6da010ced7..5cb47b07d2 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -165,10 +165,10 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.REAL, 'number of weeks the patient receives treatment in the Inpatient Care for complicated' ' SAM before being discharged if they do not die beforehand'), # treatment/intervention outcomes - 'prob_mam_after_care': Parameter( - Types.REAL, 'probability of returning to MAM after seeking care'), - 'prob_death_after_care': Parameter( - Types.REAL, 'probability of dying after seeking care'), + 'prob_mam_after_SAMcare': Parameter( + Types.REAL, 'probability of returning to MAM from SAM after receiving care'), + 'prob_death_after_SAMcare': Parameter( + Types.REAL, 'probability of dying from SAM after receiving care'), } PROPERTIES = { @@ -686,8 +686,8 @@ def do_when_am_treatment(self, person_id, intervention): # cancel death date df.at[person_id, 'un_sam_death_date'] = pd.NaT else: - outcome = self.rng.choice(['recovery_to_mam', 'death'], p=[self.parameters['prob_mam_after_care'], - self.parameters['prob_death_after_care']]) + outcome = self.rng.choice(['recovery_to_mam', 'death'], p=[self.parameters['prob_mam_after_SAMcare'], + self.parameters['prob_death_after_SAMcare']]) if outcome == 'death': self.sim.schedule_event( event=Wasting_SevereAcuteMalnutritionDeath_Event(module=self, person_id=person_id), From fb0e8a5bb08fa3d450a63f5471d9a6b6cf4f8c52 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 13 Nov 2024 22:28:08 +0000 Subject: [PATCH 151/755] scenario_wast_min_model: use simplified_births --- .../scenarios/scenario_wasting_minimal_model.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 4b8237dbb6..07764efd68 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -14,7 +14,6 @@ from tlo import Date, logging from tlo.methods import ( alri, - care_of_women_during_pregnancy, contraception, demography, diarrhoea, @@ -24,10 +23,7 @@ healthseekingbehaviour, healthsystem, hiv, - labour, - newborn_outcomes, - postnatal_supervisor, - pregnancy_supervisor, + simplified_births, stunting, symptommanager, tb, @@ -71,12 +67,8 @@ def modules(self): healthburden.HealthBurden(resourcefilepath=self.resources), symptommanager.SymptomManager(resourcefilepath=self.resources), enhanced_lifestyle.Lifestyle(resourcefilepath=self.resources), - labour.Labour(resourcefilepath=self.resources), - care_of_women_during_pregnancy.CareOfWomenDuringPregnancy(resourcefilepath=self.resources), + simplified_births.SimplifiedBirths(resourcefilepath=resourcefilepath), contraception.Contraception(resourcefilepath=self.resources), - pregnancy_supervisor.PregnancySupervisor(resourcefilepath=self.resources), - postnatal_supervisor.PostnatalSupervisor(resourcefilepath=self.resources), - newborn_outcomes.NewbornOutcomes(resourcefilepath=self.resources), hiv.Hiv(resourcefilepath=self.resources), tb.Tb(resourcefilepath=self.resources), epi.Epi(resourcefilepath=self.resources), From d36304a5350396f39adb5a7005910412a4816c33 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 15 Nov 2024 17:30:07 +0000 Subject: [PATCH 152/755] wast: minor (tidy up) --- src/tlo/methods/wasting.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 5cb47b07d2..dc1cf5b057 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -716,8 +716,7 @@ def __init__(self, module): """schedule to run every month :param module: the module that created this event """ - self.repeat_months = 1 - super().__init__(module, frequency=DateOffset(months=self.repeat_months)) + super().__init__(module, frequency=DateOffset(months=1)) assert isinstance(module, Wasting) def apply(self, population): From 1ea06b4672982f7e2fa29e2348b62e866608729f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 15 Nov 2024 17:37:00 +0000 Subject: [PATCH 153/755] RF_Wast & test_wast: parameter names udpated --- resources/ResourceFile_Wasting.csv | 4 ++-- tests/test_wasting.py | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index dac2e36dca..eb9fbfab74 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8d425bd0d03fdaa419751994ba608124834e9578ec74438bfa271e95b69a1200 -size 2821 +oid sha256:d05baa184d02579da111fcaa9c70b1c91a3a78e451b1cc996e7e131b03d7b322 +size 2827 diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 592f6dde6a..f72dd8f794 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -391,8 +391,8 @@ def test_recovery_severe_wasting_without_complications(tmpdir): wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) # Set death rate at 0% and recovery to MAM at 100% - wmodule.parameters['prob_death_after_care'] = 0.0 - wmodule.parameters['prob_mam_after_care'] = 1.0 + wmodule.parameters['prob_death_after_SAMcare'] = 0.0 + wmodule.parameters['prob_mam_after_SAMcare'] = 1.0 # Run Wasting Polling event to get new incident cases: polling = Wasting_IncidencePoll(module=sim.modules['Wasting']) @@ -514,7 +514,7 @@ def test_recovery_severe_wasting_with_complications(tmpdir): # make recovery rate to 100% and death rate to zero so that # this individual should recover wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel.multiplicative() - wmodule.parameters['prob_death_after_care'] = 0.0 + wmodule.parameters['prob_death_after_SAMcare'] = 0.0 # run care seeking event and ensure HSI for complicated SAM is scheduled hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) @@ -584,8 +584,8 @@ def test_nat_hist_death(tmpdir): wmodule = sim.modules['Wasting'] # Set death rate at 100% - wmodule.parameters['prob_death_after_care'] = 1.0 - wmodule.parameters['prob_mam_after_care'] = 0.0 + wmodule.parameters['prob_death_after_SAMcare'] = 1.0 + wmodule.parameters['prob_mam_after_SAMcare'] = 0.0 # make zero recovery rate. reset recovery linear model wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) @@ -669,8 +669,8 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): wmodule = sim.modules['Wasting'] # Make 0% death rate by replacing with empty linear model 0.0 - wmodule.parameters['prob_death_after_care'] = 0.0 - wmodule.parameters['prob_mam_after_care'] = 1.0 + wmodule.parameters['prob_death_after_SAMcare'] = 0.0 + wmodule.parameters['prob_mam_after_SAMcare'] = 1.0 # increase wasting incidence rate to 100% and reduce rate of progress to severe wasting to zero.We don't want # individuals to progress to SAM as we are testing for MAM natural recovery @@ -743,8 +743,8 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() wmodule.wasting_models.severe_wasting_progression_lm = LinearModel.multiplicative() wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) - wmodule.parameters['prob_mam_after_care'] = 0.0 - wmodule.parameters['prob_death_after_care'] = 1.0 + wmodule.parameters['prob_mam_after_SAMcare'] = 0.0 + wmodule.parameters['prob_death_after_SAMcare'] = 1.0 # Get person to use: df = sim.population.props From 277ede25e6dad6d4236e08ee5806e9fc5f3edd5a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 15 Nov 2024 17:48:20 +0000 Subject: [PATCH 154/755] wast: minor (comment updated) --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index dc1cf5b057..aed5d45bd6 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1030,7 +1030,7 @@ def __init__(self, module, person_id): @property def EXPECTED_APPT_FOOTPRINT(self): - """Return the expected appt footprint based on contraception method and whether the HSI has been rescheduled.""" + """Return the expected appointment footprint based on attendance at the HSI event.""" p = self.module.parameters rng = self.module.rng person_age = self.sim.population.props.loc[self.target].age_exact_years From 11985b10e5d732d4813a07d18668ce71851a0a96 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 15 Nov 2024 17:49:52 +0000 Subject: [PATCH 155/755] test_wast: minor (superfluous assert rm) --- tests/test_wasting.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index f72dd8f794..391e8a220e 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -375,8 +375,6 @@ def test_recovery_severe_wasting_without_complications(tmpdir): person_id = under5s.index[0] # make this individual have no wasting df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' - # confirm wasting property is reset. This individual should have no wasting - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' # get wasting module wmodule = sim.modules['Wasting'] From e61f1b7bdccd913c786ceb76e9bde2121ed42473 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 15 Nov 2024 17:50:54 +0000 Subject: [PATCH 156/755] scenario_wast_min_model: contraception module not needed --- .../scenarios/scenario_wasting_minimal_model.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 07764efd68..d3b0eb58cc 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -14,7 +14,6 @@ from tlo import Date, logging from tlo.methods import ( alri, - contraception, demography, diarrhoea, enhanced_lifestyle, @@ -41,10 +40,10 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2031, month=1, day=1), + end_date=Date(year=2011, month=1, day=1), initial_population_size=20_000, number_of_draws=1, - runs_per_draw=10, + runs_per_draw=1, ) def log_configuration(self): @@ -67,8 +66,7 @@ def modules(self): healthburden.HealthBurden(resourcefilepath=self.resources), symptommanager.SymptomManager(resourcefilepath=self.resources), enhanced_lifestyle.Lifestyle(resourcefilepath=self.resources), - simplified_births.SimplifiedBirths(resourcefilepath=resourcefilepath), - contraception.Contraception(resourcefilepath=self.resources), + simplified_births.SimplifiedBirths(resourcefilepath=self.resources), hiv.Hiv(resourcefilepath=self.resources), tb.Tb(resourcefilepath=self.resources), epi.Epi(resourcefilepath=self.resources), From 4baf50a0170cbd04c5807949806b1fdcfe76ba1f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 15 Nov 2024 19:00:33 +0000 Subject: [PATCH 157/755] equipment: description updated --- src/tlo/methods/equipment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/equipment.py b/src/tlo/methods/equipment.py index 62776fb3ad..be32006813 100644 --- a/src/tlo/methods/equipment.py +++ b/src/tlo/methods/equipment.py @@ -27,7 +27,7 @@ class Equipment: running even if equipment is declared is not available. For this reason, the ``HSI_Event`` should declare equipment that is *essential* for the healthcare service in its ``__init__`` method. If the logic inside the ``apply`` method of the ``HSI_Event`` depends on the availability of equipment, then it can find the probability with which - item(s) will be available using :py:meth:`.HSI_Event.probability_equipment_available`. + item(s) will be available using :py:meth:`.HSI_Event.probability_all_equipment_available`. The data on the availability of equipment data refers to the proportion of facilities in a district of a particular level (i.e., the ``Facility_ID``) that do have that piece of equipment. In the model, we do not know From e116ac8235fb40771a577aa7aeaeaab9d96ab1bf Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 15 Nov 2024 22:55:45 +0000 Subject: [PATCH 158/755] wast: diagnosis code completed --- src/tlo/methods/wasting.py | 69 +++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index aed5d45bd6..ddad7b65e8 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1092,8 +1092,11 @@ def get_monitoring_frequency_days(age): if not self.attendance: return - # TODO: check availability of equipment and base diagnosis on equipment used - available_equipment = ['Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape'] + available_equipment = [] + for equip in ['Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape']: + available = rng.random_sample() < HSI_Event.probability_all_equipment_available(self, equip) + if available: + available_equipment.append(equip) self.add_equipment(set(available_equipment)) def schedule_tx_by_diagnosis(hsi_event): @@ -1104,36 +1107,54 @@ def schedule_tx_by_diagnosis(hsi_event): complications = df.at[person_id, 'un_sam_with_complications'] oedema_checked = rng.random_sample() < 0.1 # TODO: find correct value & add as parameter p[''] - # diagnosis based on measurements that can be performed with available equipment + + # DIAGNOSIS + # based on performed measurements (depends on whether oedema is checked, and what equipment is available) if oedema_checked and df.at[person_id, 'un_am_bilateral_oedema']: diagnosis = 'SAM' else: - if all(item in available_equipment for item in - ['Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape']): - if oedema_checked: - diagnosis = df.at[person_id, 'un_clinical_acute_malnutrition'] + if 'MUAC tape' in available_equipment: + # all equip available and used + if all(item in available_equipment for item in + ['Height Pole (Stadiometer)', 'Weighing scale']): + if oedema_checked: + diagnosis = df.at[person_id, 'un_clinical_acute_malnutrition'] + else: + whz = df.at[person_id, 'un_WHZ_category'] + muac = df.at[person_id, 'un_am_MUAC_category'] + if whz == 'WHZ>=-2' and muac == '>=125mm': + diagnosis = 'well' + elif whz == 'WHZ<-3' or muac == '<115mm': + diagnosis = 'SAM' + else: + diagnosis = 'MAM' + # MUAC measurement is solely used for diagnosis else: - whz = df.at[person_id, 'un_WHZ_category'] muac = df.at[person_id, 'un_am_MUAC_category'] - # if person well - if whz == 'WHZ>=-2' and muac == '>=125mm': + if muac == '>=125mm': diagnosis = 'well' - elif whz == 'WHZ<-3' or muac == '<115mm': + elif muac == '<115mm': diagnosis = 'SAM' else: diagnosis = 'MAM' - else: - diagnosis = 'well' - # TODO: update the above, define what to do otherwise: - # if height pole or weight scale not available & MUAC tape avail. - # => low MUAC = SAM, middle MUAC = MAM, normal MUAC = well; - # if height pole and weight scale avail & MUAC not avail - # => low WHZ = SAM, middle WHZ = MAM, normal WHZ = well; - # if height pole or weight scale not avail & MUAC not avail - # => ? could we assume that in that case, they will at least check the oedema? or what? - - # TODO: will the presence of complications change the above diagnosis, or will it be taken in account - # only if SAM is diagnosed based on the above? + + else: # MUAC tape not available + # WHZ score is solely used for diagnosis + if all(item in available_equipment for item in + ['Height Pole (Stadiometer)', 'Weighing scale']): + whz = df.at[person_id, 'un_WHZ_category'] + if whz == 'WHZ>=-2': + diagnosis = 'well' + elif whz == 'WHZ<-3': + diagnosis = 'SAM' + else: + diagnosis = 'MAM' + # WHZ score nor MUAC measurement available, hence diagnosis based solely on presence of oedema + else: + if df.at[person_id, 'un_am_bilateral_oedema']: + diagnosis = 'SAM' + else: + diagnosis = 'well' if diagnosis == 'well': return @@ -1141,7 +1162,7 @@ def schedule_tx_by_diagnosis(hsi_event): schedule_tx_by_diagnosis(HSI_Wasting_SupplementaryFeedingProgramme_MAM) elif (diagnosis == 'SAM') and (not complications): schedule_tx_by_diagnosis(HSI_Wasting_OutpatientTherapeuticProgramme_SAM) - elif (diagnosis == 'SAM') and complications: + else: # (diagnosis == 'SAM') and complications: schedule_tx_by_diagnosis(HSI_Wasting_InpatientCare_ComplicatedSAM) def did_not_run(self): From 172725da61c38e4cfdc10e9b9de16a2423198084 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 3 Dec 2024 18:04:20 +0000 Subject: [PATCH 159/755] wast & test wast: property un_am_bilateral_oedema renamed to un_am_nutritional_oedema (for consistency with write-up) --- src/tlo/methods/wasting.py | 38 +++++++++++++++++++------------------- tests/test_wasting.py | 10 +++++----- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index ddad7b65e8..0f38459f8e 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -134,7 +134,7 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'MUAC_distribution_WHZ>=-2': Parameter( Types.LIST, 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ >= -2'), - # bilateral oedema + # nutritional oedema 'prevalence_nutritional_oedema': Parameter( Types.REAL, 'prevalence of nutritional oedema in children under 5 in Malawi'), 'proportion_WHZ<-2_with_oedema': Parameter( @@ -180,9 +180,9 @@ class Wasting(Module, GenericFirstAppointmentsMixin): # Properties related to clinical acute malnutrition 'un_clinical_acute_malnutrition': Property(Types.CATEGORICAL, 'clinical acute malnutrition state based' - ' on WHZ and/or MUAC and/or oedema', + ' on WHZ and/or MUAC and/or nutritional oedema', categories=['MAM', 'SAM', 'well']), - 'un_am_bilateral_oedema': Property(Types.BOOL, 'bilateral pitting oedema present in wasting episode'), + 'un_am_nutritional_oedema': Property(Types.BOOL, 'bilateral pitting oedema present in wasting episode'), 'un_am_MUAC_category': Property(Types.CATEGORICAL, 'MUAC measurement categories, based on WHO ' 'cut-offs', categories=['<115mm', '[115-125)mm', '>=125mm']), @@ -247,7 +247,7 @@ def initialise_population(self, population): df.loc[df.is_alive, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished df.loc[df.is_alive, 'un_last_wasting_date_of_onset'] = pd.NaT df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' - df.loc[df.is_alive, 'un_am_bilateral_oedema'] = False + df.loc[df.is_alive, 'un_am_nutritional_oedema'] = False df.loc[df.is_alive, 'un_am_MUAC_category'] = '>=125mm' df.loc[df.is_alive, 'un_sam_death_date'] = pd.NaT df.loc[df.is_alive, 'un_am_tx_start_date'] = pd.NaT @@ -313,7 +313,7 @@ def on_birth(self, mother_id, child_id): df.at[child_id, 'un_last_wasting_date_of_onset'] = pd.NaT df.at[child_id, 'un_am_tx_start_date'] = pd.NaT df.at[child_id, 'un_sam_death_date'] = pd.NaT - df.at[child_id, 'un_am_bilateral_oedema'] = False + df.at[child_id, 'un_am_nutritional_oedema'] = False df.at[child_id, 'un_am_MUAC_category'] = '>=125mm' df.at[child_id, 'un_am_treatment_type'] = 'not_applicable' @@ -413,7 +413,7 @@ def muac_cutoff_by_WHZ(self, idx, whz): def nutritional_oedema_present(self, idx): """ - This function applies the probability of bilateral oedema present in wasting and non-wasted cases + This function applies the probability of nutritional oedema present in wasting and non-wasted cases :param idx: index of children under 5, or person_id """ if len(idx) == 0: @@ -430,7 +430,7 @@ def nutritional_oedema_present(self, idx): # oedema among wasted children oedema_in_wasted_children = self.rng.random_sample(size=len( children_with_wasting)) < p['proportion_WHZ<-2_with_oedema'] - df.loc[children_with_wasting, 'un_am_bilateral_oedema'] = oedema_in_wasted_children + df.loc[children_with_wasting, 'un_am_nutritional_oedema'] = oedema_in_wasted_children # oedema among non-wasted children if len(children_without_wasting) == 0: @@ -441,12 +441,12 @@ def nutritional_oedema_present(self, idx): p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) / self.prob_normal_whz oedema_in_non_wasted = self.rng.random_sample(size=len( children_without_wasting)) < proportion_normal_whz_with_oedema - df.loc[children_without_wasting, 'un_am_bilateral_oedema'] = oedema_in_non_wasted + df.loc[children_without_wasting, 'un_am_nutritional_oedema'] = oedema_in_non_wasted def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): """ This function will determine the clinical acute malnutrition status (MAM, SAM) based on anthropometric indices - and presence of bilateral oedema (Kwashiorkor); And help determine whether the individual will have medical + and presence of nutritional oedema (Kwashiorkor); And help determine whether the individual will have medical complications, applicable to SAM cases only, requiring inpatient care. :param person_id: individual id :param pop_dataframe: population dataframe @@ -456,7 +456,7 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): whz = df.at[person_id, 'un_WHZ_category'] muac = df.at[person_id, 'un_am_MUAC_category'] - oedema_presence = df.at[person_id, 'un_am_bilateral_oedema'] + oedema_presence = df.at[person_id, 'un_am_nutritional_oedema'] # if person well if (whz == 'WHZ>=-2') and (muac == '>=125mm') and (not oedema_presence): @@ -466,7 +466,7 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): # start without treatment df.at[person_id, 'un_am_treatment_type'] = 'none' - # severe acute malnutrition (SAM): MUAC < 115 mm and/or WHZ < -3 and/or bilateral oedema + # severe acute malnutrition (SAM): MUAC < 115 mm and/or WHZ < -3 and/or nutritional oedema if (muac == '<115mm') or (whz == 'WHZ<-3') or oedema_presence: df.at[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' # apply symptoms to all SAM cases @@ -540,7 +540,7 @@ def clinical_signs_acute_malnutrition(self, idx): & (df.un_WHZ_category == whz)]) self.muac_cutoff_by_WHZ(idx=index_6_59mo_by_whz, whz=whz) - # determine the presence of bilateral oedema / oedematous malnutrition + # determine the presence of nutritional oedema (oedematous malnutrition) self.nutritional_oedema_present(idx=idx) # determine the clinical acute malnutrition state ----- @@ -569,11 +569,11 @@ def report_daly_values(self): total_daly_values = pd.Series(data=0.0, index=df.index[df.is_alive]) total_daly_values.loc[df.is_alive & (df.un_WHZ_category == 'WHZ<-3') & - df.un_am_bilateral_oedema] = daly_wts['sev_wasting_with_oedema'] + df.un_am_nutritional_oedema] = daly_wts['sev_wasting_with_oedema'] total_daly_values.loc[df.is_alive & (df.un_WHZ_category == 'WHZ<-3') & - (~df.un_am_bilateral_oedema)] = daly_wts['sev_wasting_w/o_oedema'] + (~df.un_am_nutritional_oedema)] = daly_wts['sev_wasting_w/o_oedema'] total_daly_values.loc[df.is_alive & (df.un_WHZ_category == '-3<=WHZ<-2') & - df.un_am_bilateral_oedema] = daly_wts['mod_wasting_with_oedema'] + df.un_am_nutritional_oedema] = daly_wts['mod_wasting_with_oedema'] return total_daly_values def wasting_clinical_symptoms(self, person_id): @@ -894,7 +894,7 @@ def apply(self, person_id): df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' df.at[person_id, 'un_sam_death_date'] = pd.NaT - df.at[person_id, 'un_am_bilateral_oedema'] = False + df.at[person_id, 'un_am_nutritional_oedema'] = False df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' df.at[person_id, 'un_sam_with_complications'] = False df.at[person_id, 'un_am_tx_start_date'] = pd.NaT @@ -952,7 +952,7 @@ def apply(self, person_id): # Update all other properties equally df.at[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' - df.at[person_id, 'un_am_bilateral_oedema'] = False + df.at[person_id, 'un_am_nutritional_oedema'] = False df.at[person_id, 'un_sam_with_complications'] = False df.at[person_id, 'un_am_tx_start_date'] = pd.NaT df.at[person_id, 'un_am_recovery_date'] = pd.NaT @@ -1110,7 +1110,7 @@ def schedule_tx_by_diagnosis(hsi_event): # DIAGNOSIS # based on performed measurements (depends on whether oedema is checked, and what equipment is available) - if oedema_checked and df.at[person_id, 'un_am_bilateral_oedema']: + if oedema_checked and df.at[person_id, 'un_am_nutritional_oedema']: diagnosis = 'SAM' else: if 'MUAC tape' in available_equipment: @@ -1151,7 +1151,7 @@ def schedule_tx_by_diagnosis(hsi_event): diagnosis = 'MAM' # WHZ score nor MUAC measurement available, hence diagnosis based solely on presence of oedema else: - if df.at[person_id, 'un_am_bilateral_oedema']: + if df.at[person_id, 'un_am_nutritional_oedema']: diagnosis = 'SAM' else: diagnosis = 'well' diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 391e8a220e..ddf85d824f 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -156,7 +156,7 @@ def check_configuration_of_properties(self, population): # WHZ standard deviation of -3, oedema, and MUAC <115mm should cause severe acute malnutrition whz_index = df.index[df['un_WHZ_category'] == 'WHZ<-3'] - oedema_index = df.index[df['un_am_bilateral_oedema']] + oedema_index = df.index[df['un_am_nutritional_oedema']] muac_index = df.index[df['un_am_MUAC_category'] == '<115mm'] assert (df.loc[whz_index, 'un_clinical_acute_malnutrition'] == "SAM").all() assert (df.loc[oedema_index, 'un_clinical_acute_malnutrition'] == "SAM").all() @@ -231,7 +231,7 @@ def test_report_daly_weights(tmpdir): # Check daly weight for not undernourished person (weight is 0.0) # Reset diagnostic properties df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' - df.loc[person_id, 'un_am_bilateral_oedema'] = False + df.loc[person_id, 'un_am_nutritional_oedema'] = False df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' # Verify diagnosis - an individual should be well @@ -249,7 +249,7 @@ def test_report_daly_weights(tmpdir): # Check daly weight for person with moderate wasting and oedema (weight is 0.051) # Reset diagnostic properties df.loc[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' - df.loc[person_id, 'un_am_bilateral_oedema'] = True + df.loc[person_id, 'un_am_nutritional_oedema'] = True # Verify diagnosis - an individual should be SAM sim.modules["Wasting"].clinical_acute_malnutrition_state(person_id, df) @@ -267,7 +267,7 @@ def test_report_daly_weights(tmpdir): # Check daly weight for person with severe wasting and oedema (weight is 0.172) # Reset diagnostic properties df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' - df.loc[person_id, 'un_am_bilateral_oedema'] = True + df.loc[person_id, 'un_am_nutritional_oedema'] = True # Verify diagnosis - an individual should be SAM sim.modules["Wasting"].clinical_acute_malnutrition_state(person_id, df) @@ -285,7 +285,7 @@ def test_report_daly_weights(tmpdir): # Check daly weight for person with severe wasting without oedema (weight is 0.128) # Reset diagnosis df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' - df.loc[person_id, 'un_am_bilateral_oedema'] = False + df.loc[person_id, 'un_am_nutritional_oedema'] = False # Verify diagnosis - an individual should be SAM sim.modules["Wasting"].clinical_acute_malnutrition_state(person_id, df) From 09382071144ebd1c0618768f09e6528399a32aa0 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 3 Dec 2024 22:19:24 +0000 Subject: [PATCH 160/755] wast: initial & on birth properties setup (not need to set up dates to pd.NaT) --- src/tlo/methods/wasting.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 0f38459f8e..3178a82418 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -245,12 +245,14 @@ def initialise_population(self, population): # Set initial properties df.loc[df.is_alive, 'un_ever_wasted'] = False df.loc[df.is_alive, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished - df.loc[df.is_alive, 'un_last_wasting_date_of_onset'] = pd.NaT + # df.loc[df.is_alive, 'un_last_wasting_date_of_onset'] = pd.NaT df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' df.loc[df.is_alive, 'un_am_nutritional_oedema'] = False df.loc[df.is_alive, 'un_am_MUAC_category'] = '>=125mm' - df.loc[df.is_alive, 'un_sam_death_date'] = pd.NaT - df.loc[df.is_alive, 'un_am_tx_start_date'] = pd.NaT + # df.loc[df.is_alive, 'un_sam_death_date'] = pd.NaT + # df.loc[df.is_alive, 'un_am_recovery_date'] = pd.NaT + # df.loc[df.is_alive, 'un_am_discharge_date'] = pd.NaT + # df.loc[df.is_alive, 'un_am_tx_start_date'] = pd.NaT df.loc[df.is_alive, 'un_am_treatment_type'] = 'not_applicable' # initialise wasting linear models. @@ -309,12 +311,14 @@ def on_birth(self, mother_id, child_id): # Set initial properties df.at[child_id, 'un_ever_wasted'] = False df.at[child_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished + # df.at[child_id, 'un_last_wasting_date_of_onset'] = pd.NaT df.at[child_id, 'un_clinical_acute_malnutrition'] = 'well' - df.at[child_id, 'un_last_wasting_date_of_onset'] = pd.NaT - df.at[child_id, 'un_am_tx_start_date'] = pd.NaT - df.at[child_id, 'un_sam_death_date'] = pd.NaT df.at[child_id, 'un_am_nutritional_oedema'] = False df.at[child_id, 'un_am_MUAC_category'] = '>=125mm' + # df.loc[df.is_alive, 'un_sam_death_date'] = pd.NaT + # df.loc[df.is_alive, 'un_am_recovery_date'] = pd.NaT + # df.loc[df.is_alive, 'un_am_discharge_date'] = pd.NaT + # df.loc[df.is_alive, 'un_am_tx_start_date'] = pd.NaT df.at[child_id, 'un_am_treatment_type'] = 'not_applicable' def get_prob_severe_wasting_among_wasted(self, agegp: str) -> Union[float, int]: From add465de9e056f97d6480824bc37908b9c3e4070 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 3 Dec 2024 22:21:25 +0000 Subject: [PATCH 161/755] test_wast: correct asserts --- tests/test_wasting.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index ddf85d824f..145c40b536 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -127,10 +127,9 @@ def check_configuration_of_properties(self, population): assert (df.loc[~df.un_ever_wasted & ~df.date_of_birth.isna(), 'un_WHZ_category'] == 'WHZ>=-2').all() # Those for whom the death date has past should be dead - assert not df.loc[df.un_ever_wasted & (df['un_sam_death_date'] < self.sim.date), 'is_alive'].any() - assert not df.loc[ - (df.un_clinical_acute_malnutrition == 'SAM') & (df['un_sam_death_date'] < self.sim.date), - 'is_alive'].any() + assert not df.loc[(df['un_sam_death_date'] < self.sim.date), 'is_alive'].any() + # Those who died due to SAM should have SAM + assert (df.loc[(df['un_sam_death_date']) < self.sim.date, 'un_clinical_acute_malnutrition'] == 'SAM').all() # Check that those in a current episode have symptoms of wasting # [caused by the wasting module] but not others (among those alive) @@ -763,8 +762,8 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Check that there is a Wasting_ProgressionToSevere_Event scheduled for this person and if the person is scheduled for - # death due to SAM, the death happens after the progression to severe wasting: + # Check that there is a Wasting_ProgressionToSevere_Event scheduled for this person and if the person is scheduled + # for death due to SAM, the death happens after the progression to severe wasting: progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if isinstance(event_tuple[1], Wasting_ProgressionToSevere_Event)][0] date_of_scheduled_progression = progression_event_tuple[0] From 57458f8a3bfc95932d113ac84f99e2b1162bb492 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 3 Dec 2024 22:31:21 +0000 Subject: [PATCH 162/755] wast: apply mod wast incidence only if not on tx, and reset recovery date --- src/tlo/methods/wasting.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 3178a82418..102423d520 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -732,12 +732,14 @@ def apply(self, population): # # # INCIDENCE OF MODERATE WASTING # # # # # # # # # # # # # # # # # # # # # # Determine who will be onset with wasting among those who are not currently wasted ------------- - not_wasted = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == 'WHZ>=-2')] - incidence_of_wasting = self.module.wasting_models.wasting_incidence_lm.predict(not_wasted, rng=rng) - mod_wasting_new_cases_idx = not_wasted.index[incidence_of_wasting] + not_wasted_or_treated = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == 'WHZ>=-2') & + (df.un_am_tx_start_date != pd.NaT)] + incidence_of_wasting = self.module.wasting_models.wasting_incidence_lm.predict(not_wasted_or_treated, rng=rng) + mod_wasting_new_cases_idx = not_wasted_or_treated.index[incidence_of_wasting] # update the properties for new cases of wasted children df.loc[mod_wasting_new_cases_idx, 'un_ever_wasted'] = True df.loc[mod_wasting_new_cases_idx, 'un_last_wasting_date_of_onset'] = self.sim.date + df.loc[mod_wasting_new_cases_idx, 'un_am_recovery_date'] = pd.NaT # initiate moderate wasting df.loc[mod_wasting_new_cases_idx, 'un_WHZ_category'] = '-3<=WHZ<-2' # ------------------------------------------------------------------------------------------- From 8935a5ddf47f480aabff31d93c6b0b4acaf7b938 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 6 Dec 2024 00:18:19 +0000 Subject: [PATCH 163/755] wast: joining the conditions when the Event should not run into one if statement --- src/tlo/methods/wasting.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 102423d520..edc988a01a 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -799,15 +799,15 @@ def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe m = self.module - if ((not df.at[person_id, 'is_alive']) or (df.at[person_id, 'age_exact_years'] >= 5) - or df.at[person_id, 'un_WHZ_category'] != '-3<=WHZ<-2'): + if ( + (not df.at[person_id, 'is_alive']) or + (df.at[person_id, 'age_exact_years'] >= 5) or + (df.at[person_id, 'un_WHZ_category'] != '-3<=WHZ<-2') or + (df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[person_id, 'un_am_tx_start_date'] < + self.sim.date) + ): return - # before progression to severe wasting, check those who started - # supplementary feeding programme before today - if df.at[person_id, 'un_last_wasting_date_of_onset'] < \ - df.at[person_id, 'un_am_tx_start_date'] < self.sim.date: - return # # # INCIDENCE OF SEVERE WASTING # # # # # # # # # # # # # # # # # # # # # # continue with progression to severe if not treated/recovered else: From ad8a143e5780e343b54badd6f8136382efca4b4e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 6 Dec 2024 17:31:57 +0000 Subject: [PATCH 164/755] wast: if on tx, and discharge date scheduled, they shouldn't have die from SAM --- src/tlo/methods/wasting.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index edc988a01a..659701e02c 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -834,13 +834,16 @@ def __init__(self, module, person_id): def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe - # The event should not run if the person is not currently alive + # The event should not run if the person is not currently alive or doesn't have SAM if ((not df.at[person_id, 'is_alive']) or df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM'): return # # Check if this person should still die from SAM: - if pd.isnull(df.at[person_id, 'un_am_recovery_date']): + if ( + pd.isnull(df.at[person_id, 'un_am_recovery_date']) and + not (df.at[person_id, 'un_am_discharge_date'] > df.at[person_id, 'un_am_tx_start_date']) + ): # Cause the death to happen immediately df.at[person_id, 'un_sam_death_date'] = self.sim.date self.sim.modules['Demography'].do_death( From 85ada277e48254bbbf308c8cfd175b7d938e52bb Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 6 Dec 2024 17:39:39 +0000 Subject: [PATCH 165/755] wast: minor (HSI_Event description updated) --- src/tlo/methods/wasting.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 659701e02c..ded3a8c0c5 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1023,9 +1023,9 @@ def get_monitoring_frequency_days(age): class HSI_Wasting_GrowthMonitoring(HSI_Event, IndividualScopeEventMixin): """ Attendance is determined for the HSI. If the child attends, measurements with available equipment are performed - for that child. Based on these measurements, the child can be diagnosed as well/MAM/SAM and eventually scheduled - for appropriate treatment. If the child (attending or not) is still under 5 at the time of the next growth - monitoring, the next event is scheduled with age-dependent frequency. + for that child. Based on these measurements, the child can be diagnosed as well/MAM/(un)complicated SAM and + eventually scheduled for the appropriate treatment. If the child (attending or not) is still under 5 at the time of + the next growth monitoring, the next event is scheduled with age-dependent frequency. """ def __init__(self, module, person_id): From 6cbd18d39a77150c4503975e5d1b1b341c482a8d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 6 Dec 2024 20:44:52 +0000 Subject: [PATCH 166/755] wast: set discharge date only if not destined to die; do not reset with recovery to MAM, they may not get the follow-up tx --- src/tlo/methods/wasting.py | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index ded3a8c0c5..b08efc85b6 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -189,7 +189,7 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'un_sam_with_complications': Property(Types.BOOL, 'medical complications in SAM episode'), 'un_sam_death_date': Property(Types.DATE, 'death date from severe acute malnutrition'), 'un_am_recovery_date': Property(Types.DATE, 'recovery date from acute malnutrition'), - 'un_am_discharge_date': Property(Types.DATE, 'discharge date from treatment of MAM/SAM'), + 'un_am_discharge_date': Property(Types.DATE, 'discharge date from last treatment of MAM/SAM'), 'un_am_tx_start_date': Property(Types.DATE, 'intervention start date'), 'un_am_treatment_type': Property(Types.CATEGORICAL, 'treatment types for acute malnutrition', categories=['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care'] + [ @@ -652,8 +652,13 @@ def do_when_am_treatment(self, person_id, intervention): p = self.parameters # Set the date when the treatment is provided: df.at[person_id, 'un_am_tx_start_date'] = self.sim.date + # Reset tx discharge date + df.at[person_id, 'un_am_discharge_date'] = pd.NaT if intervention == 'SFP': + df.at[person_id, 'un_am_discharge_date'] = \ + self.sim.date + DateOffset(weeks=p['tx_length_weeks_SuppFeedingMAM']) + mam_full_recovery = self.wasting_models.acute_malnutrition_recovery_mam_lm.predict( df.loc[[person_id]], self.rng ) @@ -662,8 +667,7 @@ def do_when_am_treatment(self, person_id, intervention): # schedule recovery date self.sim.schedule_event( event=Wasting_ClinicalAcuteMalnutritionRecovery_Event(module=self, person_id=person_id), - date=(df.at[person_id, 'un_am_tx_start_date'] + - DateOffset(weeks=p['tx_length_weeks_SuppFeedingMAM'])) + date=(df.at[person_id, 'un_am_discharge_date']) ) # cancel progression date (in ProgressionEvent) else: @@ -672,16 +676,15 @@ def do_when_am_treatment(self, person_id, intervention): elif intervention in ['OTC', 'ITC']: if intervention == 'OTC': - outcome_date = (df.at[person_id, 'un_am_tx_start_date'] + - DateOffset(weeks=p['tx_length_weeks_OutpatientSAM'])) + outcome_date = (self.sim.date + DateOffset(weeks=p['tx_length_weeks_OutpatientSAM'])) else: - outcome_date = (df.at[person_id, 'un_am_tx_start_date'] + - DateOffset(weeks=p['tx_length_weeks_InpatientSAM'])) + outcome_date = (self.sim.date + DateOffset(weeks=p['tx_length_weeks_InpatientSAM'])) sam_full_recovery = self.wasting_models.acute_malnutrition_recovery_sam_lm.predict( df.loc[[person_id]], self.rng ) if sam_full_recovery: + df.at[person_id, 'un_am_discharge_date'] = outcome_date # schedule full recovery self.sim.schedule_event( event=Wasting_ClinicalAcuteMalnutritionRecovery_Event(module=self, person_id=person_id), @@ -698,6 +701,7 @@ def do_when_am_treatment(self, person_id, intervention): date=outcome_date ) else: # recovery to MAM and follow-up treatment for MAM + df.at[person_id, 'un_am_discharge_date'] = outcome_date self.sim.schedule_event(event=Wasting_UpdateToMAM_Event(module=self, person_id=person_id), date=outcome_date) self.sim.modules['HealthSystem'].schedule_hsi_event( @@ -835,8 +839,10 @@ def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe # The event should not run if the person is not currently alive or doesn't have SAM - if ((not df.at[person_id, 'is_alive']) - or df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM'): + if ( + (not df.at[person_id, 'is_alive']) or + (df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM') + ): return # # Check if this person should still die from SAM: @@ -965,7 +971,6 @@ def apply(self, person_id): df.at[person_id, 'un_sam_with_complications'] = False df.at[person_id, 'un_am_tx_start_date'] = pd.NaT df.at[person_id, 'un_am_recovery_date'] = pd.NaT - df.at[person_id, 'un_am_discharge_date'] = pd.NaT # Start without treatment, treatment will be applied with HSI if care sought df.at[person_id, 'un_am_treatment_type'] = 'none' @@ -1220,8 +1225,6 @@ def apply(self, person_id, squeeze_factor): if self.get_consumables([item_code1]): logger.debug(key='debug', data='consumables are available') # Log that the treatment is provided: - df.at[person_id, 'un_am_discharge_date'] = \ - self.sim.date + DateOffset(weeks=p['tx_length_weeks_SuppFeedingMAM']) df.at[person_id, 'un_am_treatment_type'] = 'CSB++' self.module.do_when_am_treatment(person_id, intervention='SFP') else: @@ -1276,8 +1279,6 @@ def apply(self, person_id, squeeze_factor): if self.get_consumables(item_code1) and self.get_consumables(item_code2): logger.debug(key='debug', data='consumables are available.') # Log that the treatment is provided: - df.at[person_id, 'un_am_discharge_date'] = \ - self.sim.date + DateOffset(weeks=p['tx_length_weeks_OutpatientSAM']) df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' self.module.do_when_am_treatment(person_id, intervention='OTC') else: @@ -1329,8 +1330,6 @@ def apply(self, person_id, squeeze_factor): if self.get_consumables(item_code1) and self.get_consumables(item_code2): logger.debug(key='debug', data='consumables available, so use it.') # Log that the treatment is provided: - df.at[person_id, 'un_am_discharge_date'] = \ - self.sim.date + DateOffset(weeks=p['tx_length_weeks_InpatientSAM']) df.at[person_id, 'un_am_treatment_type'] = 'inpatient_care' self.module.do_when_am_treatment(person_id, intervention='ITC') else: From f42e82b3793785feaae934d8b697115c167bbf49 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 6 Dec 2024 20:46:27 +0000 Subject: [PATCH 167/755] test_wast: tx coverages were rm --- tests/test_wasting.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 145c40b536..f0a7b39bfe 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -522,8 +522,6 @@ def test_recovery_severe_wasting_with_complications(tmpdir): hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought - # make inpatient care coverage 100% - wmodule.parameters['coverage_inpatient_care'] = 1.0 ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) @@ -614,8 +612,6 @@ def test_nat_hist_death(tmpdir): hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought - # make outpatient care coverage 100% - wmodule.parameters['coverage_outpatient_therapeutic_care'] = 1.0 ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) From bec0769e6e3a41bc44711b3f11aa1bbd9f8ffbdf Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 6 Dec 2024 22:50:57 +0000 Subject: [PATCH 168/755] wast: rm unused local vars --- src/tlo/methods/wasting.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index b08efc85b6..70b65edc4b 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1208,7 +1208,7 @@ def __init__(self, module, person_id): def apply(self, person_id, squeeze_factor): df = self.sim.population.props - p = self.module.parameters + # p = self.module.parameters if not df.at[person_id, 'is_alive']: return @@ -1258,7 +1258,7 @@ def __init__(self, module, person_id): def apply(self, person_id, squeeze_factor): df = self.sim.population.props - p = self.module.parameters + # p = self.module.parameters if not df.at[person_id, 'is_alive']: return @@ -1312,7 +1312,7 @@ def __init__(self, module, person_id): def apply(self, person_id, squeeze_factor): df = self.sim.population.props - p = self.module.parameters + # p = self.module.parameters # Stop the person from dying of acute malnutrition (if they were going to die) if not df.at[person_id, 'is_alive']: From b949156a47aefecb0ccb9cf32266385af28e3443 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 7 Dec 2024 00:18:49 +0000 Subject: [PATCH 169/755] wast: footprint assignment simplified; dates properties: tidy up description; death date assigned only when happening, reset recovery date when malnutrition state changes to MAM/SAM --- src/tlo/methods/wasting.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 70b65edc4b..59f7300b19 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -188,10 +188,11 @@ class Wasting(Module, GenericFirstAppointmentsMixin): categories=['<115mm', '[115-125)mm', '>=125mm']), 'un_sam_with_complications': Property(Types.BOOL, 'medical complications in SAM episode'), 'un_sam_death_date': Property(Types.DATE, 'death date from severe acute malnutrition'), - 'un_am_recovery_date': Property(Types.DATE, 'recovery date from acute malnutrition'), + 'un_am_recovery_date': Property(Types.DATE, 'recovery date from last acute malnutrition episode (MAM/SAM)'), 'un_am_discharge_date': Property(Types.DATE, 'discharge date from last treatment of MAM/SAM'), - 'un_am_tx_start_date': Property(Types.DATE, 'intervention start date'), - 'un_am_treatment_type': Property(Types.CATEGORICAL, 'treatment types for acute malnutrition', + 'un_am_tx_start_date': Property(Types.DATE, 'treatment start date, if currently on treatment'), + 'un_am_treatment_type': Property(Types.CATEGORICAL, 'treatment type for acute malnutrition the person ' + 'is currently on; set to not_applicable if well hence no treatment required', categories=['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care'] + [ 'none', 'not_applicable']), } @@ -469,6 +470,8 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): else: # start without treatment df.at[person_id, 'un_am_treatment_type'] = 'none' + # reset recovery date + df.at[person_id, 'un_am_recovery_date'] = pd.NaT # severe acute malnutrition (SAM): MUAC < 115 mm and/or WHZ < -3 and/or nutritional oedema if (muac == '<115mm') or (whz == 'WHZ<-3') or oedema_presence: @@ -690,8 +693,7 @@ def do_when_am_treatment(self, person_id, intervention): event=Wasting_ClinicalAcuteMalnutritionRecovery_Event(module=self, person_id=person_id), date=outcome_date ) - # cancel death date - df.at[person_id, 'un_sam_death_date'] = pd.NaT + else: outcome = self.rng.choice(['recovery_to_mam', 'death'], p=[self.parameters['prob_mam_after_SAMcare'], self.parameters['prob_death_after_SAMcare']]) @@ -707,8 +709,6 @@ def do_when_am_treatment(self, person_id, intervention): self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), priority=0, topen=outcome_date) - # cancel death date - df.at[person_id, 'un_sam_death_date'] = pd.NaT class Wasting_IncidencePoll(RegularEvent, PopulationScopeEventMixin): @@ -743,7 +743,6 @@ def apply(self, population): # update the properties for new cases of wasted children df.loc[mod_wasting_new_cases_idx, 'un_ever_wasted'] = True df.loc[mod_wasting_new_cases_idx, 'un_last_wasting_date_of_onset'] = self.sim.date - df.loc[mod_wasting_new_cases_idx, 'un_am_recovery_date'] = pd.NaT # initiate moderate wasting df.loc[mod_wasting_new_cases_idx, 'un_WHZ_category'] = '-3<=WHZ<-2' # ------------------------------------------------------------------------------------------- @@ -908,7 +907,6 @@ def apply(self, person_id): df.at[person_id, 'un_am_recovery_date'] = self.sim.date df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' - df.at[person_id, 'un_sam_death_date'] = pd.NaT df.at[person_id, 'un_am_nutritional_oedema'] = False df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' df.at[person_id, 'un_sam_with_complications'] = False @@ -970,7 +968,6 @@ def apply(self, person_id): df.at[person_id, 'un_am_nutritional_oedema'] = False df.at[person_id, 'un_sam_with_complications'] = False df.at[person_id, 'un_am_tx_start_date'] = pd.NaT - df.at[person_id, 'un_am_recovery_date'] = pd.NaT # Start without treatment, treatment will be applied with HSI if care sought df.at[person_id, 'un_am_treatment_type'] = 'none' @@ -1299,13 +1296,9 @@ def __init__(self, module, person_id): super().__init__(module, person_id=person_id) assert isinstance(module, Wasting) - # Get a blank footprint and then edit to define call on resources of this treatment event - the_appt_footprint = self.sim.modules["HealthSystem"].get_blank_appt_footprint() - the_appt_footprint['U5Malnutr'] = 1 - # Define the necessary information for an HSI self.TREATMENT_ID = 'Undernutrition_Feeding_Inpatient' - self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint + self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({"U5Malnutr": 1}) self.ACCEPTED_FACILITY_LEVEL = '2' self.ALERT_OTHER_DISEASES = [] self.BEDDAYS_FOOTPRINT = self.make_beddays_footprint({'general_bed': 7}) From 30ba983f0a9728a0251b8e0d38921702618a6b18 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 7 Dec 2024 16:26:30 +0000 Subject: [PATCH 170/755] wast & test_wast: update names of tx programmes to be in line with write-up --- src/tlo/methods/wasting.py | 12 ++++++------ tests/test_wasting.py | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 59f7300b19..5760fc5b42 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -642,7 +642,7 @@ def do_at_generic_first_appt( if complications: # schedule HSI for supplementary feeding program for MAM schedule_hsi_event( - hsi_event=HSI_Wasting_InpatientCare_ComplicatedSAM(module=self, person_id=person_id), + hsi_event=HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM(module=self, person_id=person_id), priority=0, topen=self.sim.date) def do_when_am_treatment(self, person_id, intervention): @@ -677,8 +677,8 @@ def do_when_am_treatment(self, person_id, intervention): # remained MAM return - elif intervention in ['OTC', 'ITC']: - if intervention == 'OTC': + elif intervention in ['OTP', 'ITC']: + if intervention == 'OTP': outcome_date = (self.sim.date + DateOffset(weeks=p['tx_length_weeks_OutpatientSAM'])) else: outcome_date = (self.sim.date + DateOffset(weeks=p['tx_length_weeks_InpatientSAM'])) @@ -1174,7 +1174,7 @@ def schedule_tx_by_diagnosis(hsi_event): elif (diagnosis == 'SAM') and (not complications): schedule_tx_by_diagnosis(HSI_Wasting_OutpatientTherapeuticProgramme_SAM) else: # (diagnosis == 'SAM') and complications: - schedule_tx_by_diagnosis(HSI_Wasting_InpatientCare_ComplicatedSAM) + schedule_tx_by_diagnosis(HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM) def did_not_run(self): logger.debug(key="HSI_Wasting_GrowthMonitoring", @@ -1277,7 +1277,7 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data='consumables are available.') # Log that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' - self.module.do_when_am_treatment(person_id, intervention='OTC') + self.module.do_when_am_treatment(person_id, intervention='OTP') else: logger.debug(key='debug', data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") @@ -1287,7 +1287,7 @@ def did_not_run(self): pass -class HSI_Wasting_InpatientCare_ComplicatedSAM(HSI_Event, IndividualScopeEventMixin): +class HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM(HSI_Event, IndividualScopeEventMixin): """ This is the inpatient management of SAM with medical complications """ diff --git a/tests/test_wasting.py b/tests/test_wasting.py index f0a7b39bfe..5b11be693f 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -25,7 +25,7 @@ ) from tlo.methods.healthseekingbehaviour import HealthSeekingBehaviourPoll from tlo.methods.wasting import ( - HSI_Wasting_InpatientCare_ComplicatedSAM, + HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM, HSI_Wasting_OutpatientTherapeuticProgramme_SAM, Wasting_ClinicalAcuteMalnutritionRecovery_Event, Wasting_IncidencePoll, @@ -530,13 +530,13 @@ def test_recovery_severe_wasting_with_complications(tmpdir): hsi_event_scheduled = [ ev for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) - if isinstance(ev[1], HSI_Wasting_InpatientCare_ComplicatedSAM) + if isinstance(ev[1], HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM) ] assert 1 == len(hsi_event_scheduled) # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if - isinstance(ev[1], HSI_Wasting_InpatientCare_ComplicatedSAM)][0] + isinstance(ev[1], HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM)][0] sam_ev.run(squeeze_factor=0.0) # check recovery event is scheduled From 745d548426e433af52819edbee5a1bb1ec340ffc Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 10 Dec 2024 14:43:34 +0000 Subject: [PATCH 171/755] scenario_wast_min_model: 30K pop, 2010-2030 for 1st round calibration --- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index d3b0eb58cc..552c80d474 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -40,8 +40,8 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2011, month=1, day=1), - initial_population_size=20_000, + end_date=Date(year=2031, month=1, day=1), + initial_population_size=30_000, number_of_draws=1, runs_per_draw=1, ) From 92e3ed85a43a77a33cf15d2fe439d1a5de46ca7a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 11 Dec 2024 11:09:23 +0000 Subject: [PATCH 172/755] RF_Wast: prob_death_after_SAMcare updated (substantially lower), hence prob_mam_after_SAMcare increased --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index eb9fbfab74..1c6827eb6e 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d05baa184d02579da111fcaa9c70b1c91a3a78e451b1cc996e7e131b03d7b322 -size 2827 +oid sha256:9ca109b2ebfcad9ed760850559147b566abf02fc4105c20f89e0d378fe0ad8fe +size 2829 From 66cf53c1933ebac18137b7e89ea2b1bd249ba4ba Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 11 Dec 2024 12:08:51 +0000 Subject: [PATCH 173/755] analysis_wast: minor (tidy up comments) --- src/scripts/wasting_analyses/analysis_wasting.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index d1522a4853..c8dc0bf536 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -141,8 +141,8 @@ def plot_wasting_prevalence_per_year(self): # plt.show() def plot_wasting_prevalence_by_age_group(self): - """ plot wasting prevalence per each age group. Proportions are obtained by getting a total number of - children wasted in a particular age-group divide by the total number of children per that age-group""" + """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of + children wasted in a particular age-group divided by the total number of children per that age-group""" w_prev_df = self.__logs_dict["wasting_prevalence_props"] w_prev_df = w_prev_df.drop(columns={'total_under5_prop'}) w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) @@ -154,7 +154,7 @@ def plot_wasting_prevalence_by_age_group(self): w_prev_df = w_prev_df[order_x_axis] fig, ax = plt.subplots(figsize=(10, 6)) - # plot wasting prevalence + # Plot wasting prevalence w_prev_df.squeeze().plot(kind='bar', stacked=False, ax=ax, title="Wasting prevalence in children 0-59 months per each age group in 2023", From ce8b0eceba625a678d982c8593febf3838d6a757 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 11 Dec 2024 17:15:09 +0000 Subject: [PATCH 174/755] analysis_wast: combine deaths of both genders together --- .../wasting_analyses/analysis_wasting.py | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index c8dc0bf536..fab9809031 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -171,27 +171,25 @@ def plot_wasting_prevalence_by_age_group(self): plt.tight_layout() fig_output_name = ('wasting_prevalence_per_each_age_group__' + self.datestamp) self.save_fig__store_pdf_file(fig, fig_output_name) - plt.show() + # plt.show() def plot_modal_gbd_deaths_by_gender(self): """ compare modal and GBD deaths by gender """ death_compare = \ compare_number_of_deaths(self.__log_file_path, resources_path) - fig, axs = plt.subplots(nrows=1, ncols=2, sharey=True, sharex=True, figsize=(10, 6)) - for _col, sex in enumerate(('M', 'F')): - plot_df = death_compare.loc[(['2010-2014', '2015-2019'], - sex, slice(None), 'Childhood Undernutrition' - )].groupby('period').sum() - plotting = plot_df.loc[['2010-2014', '2015-2019']] - ax = plotting['model'].plot.bar(label='Model', ax=axs[_col], rot=0) - ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, - yerr=[plotting.GBD_lower, plotting.GBD_upper], - fmt='o', color='#000', label="GBD") - ax.set_title(f'{self.__gender_desc[sex]} ' - f'deaths due to wasting') - ax.set_xlabel("Time period") - ax.set_ylabel("Number of deaths") - ax.legend(loc=2) + fig, ax = plt.subplots(figsize=(10, 6)) + plot_df = death_compare.loc[(['2010-2014', '2015-2019'], + slice(None), slice(None), 'Childhood Undernutrition' + )].groupby('period').sum() + plotting = plot_df.loc[['2010-2014', '2015-2019']] + ax = plotting['model'].plot.bar(label='Model', ax=ax, rot=0) + ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, + yerr=[plotting.GBD_lower, plotting.GBD_upper], + fmt='o', color='#000', label="GBD") + ax.set_title(f'Direct deaths due to wasting') + ax.set_xlabel("time period") + ax.set_ylabel("number of deaths") + ax.legend(loc=2) fig.tight_layout() # Adjust the layout to make space for the footnote plt.subplots_adjust(bottom=0.15) # Adjust the bottom margin From 560196920e0309d0f4f083cd841d302c24691580 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 11 Dec 2024 17:18:18 +0000 Subject: [PATCH 175/755] wast: log both mod & sev wasting prevalence (instead of overall prev.) + log prevalence in above 5 years old --- src/tlo/methods/wasting.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 5760fc5b42..a82b285116 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1490,15 +1490,25 @@ def apply(self, population): low_bound_age_in_years = low_bound_mos / 12.0 high_bound_age_in_years = (1 + high_bound_mos) / 12.0 # get those children who are wasted - wasted_agegrp = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, - inclusive='left') & (under5s.un_WHZ_category - != 'WHZ>=-2')).sum() + mod_wasted_agegrp = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, + inclusive='left') & (under5s.un_WHZ_category + == '-3<=WHZ<-2')).sum() + sev_wasted_agegrp = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, + inclusive='left') & (under5s.un_WHZ_category + == 'WHZ<-3')).sum() total_per_agegrp = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, inclusive='left')).sum() # add proportions to the dictionary - wasting_prev_dict[f'{low_bound_mos}_{high_bound_mos}mo'] = wasted_agegrp / total_per_agegrp - - # add to dictionary proportion of all wasted children under 5 years - wasting_prev_dict['total_under5_prop'] = (under5s.un_WHZ_category != 'WHZ>=-2').sum() / len(under5s) + wasting_prev_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = mod_wasted_agegrp / total_per_agegrp + wasting_prev_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = sev_wasted_agegrp / total_per_agegrp + # add prevalence in children above 5y, to see if they are 0 as they should + # add proportions of children 5 years old and above who are wasted to the dictionary + above5s = df.loc[df.is_alive & df.age_exact_years >= 5] + wasting_prev_dict[f'mod__5y+'] = (above5s.un_WHZ_category == '-3<=WHZ<-2').sum() / len(above5s) + wasting_prev_dict[f'sev__5y+'] = (above5s.un_WHZ_category == 'WHZ<-3').sum() / len(above5s) + + # add to dictionary proportion of all moderately/severely wasted children under 5 years + wasting_prev_dict['total_mod_under5_prop'] = (under5s.un_WHZ_category == '-3<=WHZ<-2').sum() / len(under5s) + wasting_prev_dict['total_sev_under5_prop'] = (under5s.un_WHZ_category == 'WHZ<-3').sum() / len(under5s) # log wasting prevalence logger.info(key='wasting_prevalence_props', data=wasting_prev_dict) From a41986d01b056824055c916e5406135122b8925d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 11 Dec 2024 17:42:37 +0000 Subject: [PATCH 176/755] wast & analysis_wast: tidy up --- src/scripts/wasting_analyses/analysis_wasting.py | 2 +- src/tlo/methods/wasting.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index fab9809031..64540d8a95 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -186,7 +186,7 @@ def plot_modal_gbd_deaths_by_gender(self): ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, yerr=[plotting.GBD_lower, plotting.GBD_upper], fmt='o', color='#000', label="GBD") - ax.set_title(f'Direct deaths due to wasting') + ax.set_title('Direct deaths due to wasting') ax.set_xlabel("time period") ax.set_ylabel("number of deaths") ax.legend(loc=2) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index a82b285116..19934a43b0 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1504,8 +1504,8 @@ def apply(self, population): # add prevalence in children above 5y, to see if they are 0 as they should # add proportions of children 5 years old and above who are wasted to the dictionary above5s = df.loc[df.is_alive & df.age_exact_years >= 5] - wasting_prev_dict[f'mod__5y+'] = (above5s.un_WHZ_category == '-3<=WHZ<-2').sum() / len(above5s) - wasting_prev_dict[f'sev__5y+'] = (above5s.un_WHZ_category == 'WHZ<-3').sum() / len(above5s) + wasting_prev_dict['mod__5y+'] = (above5s.un_WHZ_category == '-3<=WHZ<-2').sum() / len(above5s) + wasting_prev_dict['sev__5y+'] = (above5s.un_WHZ_category == 'WHZ<-3').sum() / len(above5s) # add to dictionary proportion of all moderately/severely wasted children under 5 years wasting_prev_dict['total_mod_under5_prop'] = (under5s.un_WHZ_category == '-3<=WHZ<-2').sum() / len(under5s) From 85f52530b927a939d2131a2d4a9e486abb815250 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 11 Dec 2024 17:42:37 +0000 Subject: [PATCH 177/755] wast: rm above5 prevalence logging --- src/tlo/methods/wasting.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 19934a43b0..6646c9354a 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1501,11 +1501,6 @@ def apply(self, population): # add proportions to the dictionary wasting_prev_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = mod_wasted_agegrp / total_per_agegrp wasting_prev_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = sev_wasted_agegrp / total_per_agegrp - # add prevalence in children above 5y, to see if they are 0 as they should - # add proportions of children 5 years old and above who are wasted to the dictionary - above5s = df.loc[df.is_alive & df.age_exact_years >= 5] - wasting_prev_dict['mod__5y+'] = (above5s.un_WHZ_category == '-3<=WHZ<-2').sum() / len(above5s) - wasting_prev_dict['sev__5y+'] = (above5s.un_WHZ_category == 'WHZ<-3').sum() / len(above5s) # add to dictionary proportion of all moderately/severely wasted children under 5 years wasting_prev_dict['total_mod_under5_prop'] = (under5s.un_WHZ_category == '-3<=WHZ<-2').sum() / len(under5s) From 7666291d2af33a5b822166f2224f18741cd3adc0 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 12 Dec 2024 01:11:25 +0000 Subject: [PATCH 178/755] analysis_wast: incidence - fix legend names, prevalence - mod & sev wasting --- .../wasting_analyses/analysis_wasting.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 64540d8a95..5011d04939 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -99,15 +99,15 @@ def plot_wasting_incidence(self): for state in w_inc_df.columns: new_df[state] = \ w_inc_df.apply(lambda row: row[state][_age], axis=1) - + # convert into proportions new_df = new_df.apply(lambda _row: _row / _row.sum(), axis=1) plotting = new_df[["WHZ<-3", "-3<=WHZ<-2"]] - # convert into proportions + plotting = plotting.rename(columns=self.__wasting_types_desc) ax = plotting.plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], title=f"incidence of wasting in {_age} old", ylim=[0, 1]) - ax.legend(self.__wasting_types_desc.values(), loc='lower right') + ax.legend(loc='lower right') ax.set_xlabel('year') ax.set_ylabel('proportion') # move to another row @@ -124,16 +124,16 @@ def plot_wasting_prevalence_per_year(self): """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of children wasted divide by the total number of children less than 5 years""" w_prev_df = self.__logs_dict["wasting_prevalence_props"] - w_prev_df = w_prev_df[['date', 'total_under5_prop']] + w_prev_df = w_prev_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']] w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) w_prev_df = w_prev_df.drop(columns='date') fig, ax = plt.subplots() - w_prev_df["total_under5_prop"].plot(kind='bar', stacked=True, - ax=ax, - title="Wasting prevalence in children 0-59 months per year", - ylabel='proportion of wasted children in the year', - xlabel='year', - ylim=[0, 0.15]) + w_prev_df.plot(kind='bar', stacked=True, + ax=ax, + title="Wasting prevalence in children 0-59 months per year", + ylabel='proportion of wasted children in the year', + xlabel='year', + ylim=[0, 0.15]) # add_footnote(fig, "proportion of wasted children within each age-group") plt.tight_layout() fig_output_name = ('wasting_prevalence_per_year__' + self.datestamp) From 037d40dbac1eafd304c73f2ec90fa5b2deafc4c7 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 12 Dec 2024 12:17:31 +0000 Subject: [PATCH 179/755] wast: calculation of under5s for prevalence logging fixed --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 6646c9354a..441d849d6a 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1482,7 +1482,7 @@ def apply(self, population): self.date_last_run = self.sim.date # Wasting totals (prevalence at logging time) - under5s = df.loc[df.is_alive & df.age_exact_years < 5] + under5s = df.loc[df.is_alive & (df.age_exact_years < 5)] # declare a dictionary that will hold proportions of wasting prevalence per each age group wasting_prev_dict: Dict[str, Any] = dict() # loop through different age groups and get proportions of wasting prevalence per each age group From 86b4c85e871ba8c6936f573684a7a54d801ed386 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 12 Dec 2024 13:07:50 +0000 Subject: [PATCH 180/755] wast: log wasting prev in 5y+ olds --- src/tlo/methods/wasting.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 441d849d6a..2818d78e7c 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1501,9 +1501,16 @@ def apply(self, population): # add proportions to the dictionary wasting_prev_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = mod_wasted_agegrp / total_per_agegrp wasting_prev_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = sev_wasted_agegrp / total_per_agegrp + # add prevalence in children above 5y, to see if they are 0 as they should + # add proportions of children 5 years old and above who are wasted to the dictionary + above5s = df.loc[df.is_alive & (df.age_exact_years >= 5)] + assert (len(under5s) + len(above5s)) == len(df.loc[df.is_alive]) + wasting_prev_dict['mod__5y+'] = (above5s.un_WHZ_category == '-3<=WHZ<-2').sum() / len(above5s) + wasting_prev_dict['sev__5y+'] = (above5s.un_WHZ_category == 'WHZ<-3').sum() / len(above5s) # add to dictionary proportion of all moderately/severely wasted children under 5 years wasting_prev_dict['total_mod_under5_prop'] = (under5s.un_WHZ_category == '-3<=WHZ<-2').sum() / len(under5s) wasting_prev_dict['total_sev_under5_prop'] = (under5s.un_WHZ_category == 'WHZ<-3').sum() / len(under5s) + # log wasting prevalence logger.info(key='wasting_prevalence_props', data=wasting_prev_dict) From 46a3f58b3a15b7b770a46b6105b8583cb56689ff Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 12 Dec 2024 17:02:23 +0000 Subject: [PATCH 181/755] analysis_wast: prev by age grp - plot mod/sev wast separately, for year 2020, --- .../wasting_analyses/analysis_wasting.py | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 5011d04939..12adbf7f95 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -144,23 +144,31 @@ def plot_wasting_prevalence_by_age_group(self): """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of children wasted in a particular age-group divided by the total number of children per that age-group""" w_prev_df = self.__logs_dict["wasting_prevalence_props"] - w_prev_df = w_prev_df.drop(columns={'total_under5_prop'}) + w_prev_df = w_prev_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) - w_prev_df = w_prev_df.loc[w_prev_df.index == 2023] + w_prev_df = w_prev_df.loc[w_prev_df.index == 2020] w_prev_df = w_prev_df.drop(columns='date') - order_x_axis = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo'] - # Assert that all columns are included - assert set(w_prev_df.columns) == set(order_x_axis), "Not all columns are included in the order_x_axis." - w_prev_df = w_prev_df[order_x_axis] + plotting = {'severe wasting': {}, 'moderate wasting': {}} + for col in w_prev_df.columns: + prefix, age_group = col.split('__') + if prefix == 'sev': + plotting['severe wasting'][age_group] = w_prev_df[col].values[0] + elif prefix == 'mod': + plotting['moderate wasting'][age_group] = w_prev_df[col].values[0] + plotting = pd.DataFrame(plotting) + order_x_axis = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] + # Assert all age groups are included + assert set(plotting.index) == set(order_x_axis), "age groups are not in line with the order_x_axis." + plotting = plotting.reindex(order_x_axis) - fig, ax = plt.subplots(figsize=(10, 6)) # Plot wasting prevalence - w_prev_df.squeeze().plot(kind='bar', stacked=False, - ax=ax, - title="Wasting prevalence in children 0-59 months per each age group in 2023", - ylabel='proportion', - xlabel='age group', - ylim=[0, 0.3]) + fig, ax = plt.subplots(figsize=(10, 6)) + plotting.squeeze().plot(kind='bar', stacked=True, + ax=ax, + title="Wasting prevalence in children 0-59 months per each age group in 2020", + ylabel='proportion', + xlabel='age group', + ylim=[0, 0.3]) # Adjust the layout to make space for the footnote plt.subplots_adjust(bottom=0.85) # Adjust the bottom margin # Add footnote From e515e0d7f776b009f102d0fa55f92746103c2149 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 12 Dec 2024 17:25:08 +0000 Subject: [PATCH 182/755] analysis_wast: incidence mod:wast props - tidy up --- src/scripts/wasting_analyses/analysis_wasting.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 12adbf7f95..75ee927626 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -83,7 +83,11 @@ def plot_wasting_incidence(self): w_inc_df = self.__logs_dict['wasting_incidence_count'] w_inc_df.set_index(w_inc_df.date.dt.year, inplace=True) w_inc_df.drop(columns='date', inplace=True) - # get age year. doesn't matter what wasting category you choose for + # check no incidence of well-nourished + all_zeros = w_inc_df['WHZ>=-2'].apply(lambda x: all(value == 0 for value in x.values())) + assert all(all_zeros) + w_inc_df = w_inc_df[["WHZ<-3", "-3<=WHZ<-2"]] + # get age_years, doesn't matter what wasting category you choose, # they all have same age groups age_years = list(w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys( @@ -94,6 +98,7 @@ def plot_wasting_incidence(self): _col_counter = 0 # plot setup fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 6)) + fig.delaxes(axes[1, 2]) for _age in age_years: new_df = pd.DataFrame() for state in w_inc_df.columns: @@ -101,8 +106,7 @@ def plot_wasting_incidence(self): w_inc_df.apply(lambda row: row[state][_age], axis=1) # convert into proportions new_df = new_df.apply(lambda _row: _row / _row.sum(), axis=1) - plotting = new_df[["WHZ<-3", "-3<=WHZ<-2"]] - plotting = plotting.rename(columns=self.__wasting_types_desc) + plotting = new_df.rename(columns=self.__wasting_types_desc) ax = plotting.plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], title=f"incidence of wasting in {_age} old", From 0c4468b6c271bb6ced3d48742f713d2bd280427d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 12 Dec 2024 17:37:56 +0000 Subject: [PATCH 183/755] wast: add logging of under5s pop size --- src/tlo/methods/wasting.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 2818d78e7c..4067736a9a 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1514,3 +1514,7 @@ def apply(self, population): # log wasting prevalence logger.info(key='wasting_prevalence_props', data=wasting_prev_dict) + + # log under5s pop size + logger.info(key='under5s pop size', data=len(under5s)) + From f77381e669a87adbc5c57148d6012ccf9be565da Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 12 Dec 2024 17:45:38 +0000 Subject: [PATCH 184/755] analysis_wast: tidy up update of df --- src/scripts/wasting_analyses/analysis_wasting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 75ee927626..713e7a949a 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -81,8 +81,8 @@ def save_fig__store_pdf_file(self, fig, fig_output_name: str) -> None: def plot_wasting_incidence(self): """ plot the incidence of wasting over time """ w_inc_df = self.__logs_dict['wasting_incidence_count'] - w_inc_df.set_index(w_inc_df.date.dt.year, inplace=True) - w_inc_df.drop(columns='date', inplace=True) + w_inc_df = w_inc_df.set_index(w_inc_df.date.dt.year) + w_inc_df = w_inc_df.drop(columns='date') # check no incidence of well-nourished all_zeros = w_inc_df['WHZ>=-2'].apply(lambda x: all(value == 0 for value in x.values())) assert all(all_zeros) From ecb01f2c4c246374a9015539991caf95dee071ff Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 12 Dec 2024 23:17:08 +0000 Subject: [PATCH 185/755] wast: log pop sizes (mod/sev/total) --- src/tlo/methods/wasting.py | 58 ++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 4067736a9a..1cb3af46cd 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1481,40 +1481,56 @@ def apply(self, population): self.module.wasting_incident_case_tracker_blank) self.date_last_run = self.sim.date - # Wasting totals (prevalence at logging time) - under5s = df.loc[df.is_alive & (df.age_exact_years < 5)] + # Wasting totals (prevalence & pop size at logging time) # declare a dictionary that will hold proportions of wasting prevalence per each age group wasting_prev_dict: Dict[str, Any] = dict() + # declare a dictionary that will hold pop sizes + pop_sizes_dict: Dict[str, Any] = dict() + + under5s = df.loc[df.is_alive & (df.age_exact_years < 5)] # loop through different age groups and get proportions of wasting prevalence per each age group for low_bound_mos, high_bound_mos in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months low_bound_age_in_years = low_bound_mos / 12.0 high_bound_age_in_years = (1 + high_bound_mos) / 12.0 # get those children who are wasted - mod_wasted_agegrp = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, - inclusive='left') & (under5s.un_WHZ_category - == '-3<=WHZ<-2')).sum() - sev_wasted_agegrp = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, - inclusive='left') & (under5s.un_WHZ_category - == 'WHZ<-3')).sum() - total_per_agegrp = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, - inclusive='left')).sum() - # add proportions to the dictionary - wasting_prev_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = mod_wasted_agegrp / total_per_agegrp - wasting_prev_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = sev_wasted_agegrp / total_per_agegrp - # add prevalence in children above 5y, to see if they are 0 as they should - # add proportions of children 5 years old and above who are wasted to the dictionary + mod_wasted_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, + inclusive='left') & (under5s.un_WHZ_category + == '-3<=WHZ<-2')).sum() + sev_wasted_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, + inclusive='left') & (under5s.un_WHZ_category + == 'WHZ<-3')).sum() + total_per_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, + inclusive='left')).sum() + # add moderate and severe wasting prevalence to the dictionary + wasting_prev_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = mod_wasted_agegrp_nmb / total_per_agegrp_nmb + wasting_prev_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = sev_wasted_agegrp_nmb / total_per_agegrp_nmb + # add pop sizes to the dataframe + pop_sizes_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = mod_wasted_agegrp_nmb + pop_sizes_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = sev_wasted_agegrp_nmb + pop_sizes_dict[f'total__{low_bound_mos}_{high_bound_mos}mo'] = total_per_agegrp_nmb + # log prevalence & pop size for children above 5y above5s = df.loc[df.is_alive & (df.age_exact_years >= 5)] assert (len(under5s) + len(above5s)) == len(df.loc[df.is_alive]) - wasting_prev_dict['mod__5y+'] = (above5s.un_WHZ_category == '-3<=WHZ<-2').sum() / len(above5s) - wasting_prev_dict['sev__5y+'] = (above5s.un_WHZ_category == 'WHZ<-3').sum() / len(above5s) + mod_wasted_above5_nmb = (above5s.un_WHZ_category == '-3<=WHZ<-2').sum() + sev_wasted_above5_nmb = (above5s.un_WHZ_category == 'WHZ<-3').sum() + wasting_prev_dict['mod__5y+'] = mod_wasted_above5_nmb / len(above5s) + wasting_prev_dict['sev__5y+'] = sev_wasted_above5_nmb / len(above5s) + pop_sizes_dict['mod__5y+'] = mod_wasted_above5_nmb + pop_sizes_dict['sev__5y+'] = sev_wasted_above5_nmb + pop_sizes_dict['total__5y+'] = len(above5s) # add to dictionary proportion of all moderately/severely wasted children under 5 years - wasting_prev_dict['total_mod_under5_prop'] = (under5s.un_WHZ_category == '-3<=WHZ<-2').sum() / len(under5s) - wasting_prev_dict['total_sev_under5_prop'] = (under5s.un_WHZ_category == 'WHZ<-3').sum() / len(under5s) + mod_under5_nmb = (under5s.un_WHZ_category == '-3<=WHZ<-2').sum() + sev_under5_nmb = (under5s.un_WHZ_category == 'WHZ<-3').sum() + wasting_prev_dict['total_mod_under5_prop'] = mod_under5_nmb / len(under5s) + wasting_prev_dict['total_sev_under5_prop'] = sev_under5_nmb / len(under5s) + pop_sizes_dict['mod__under5'] = mod_under5_nmb + pop_sizes_dict['sev__under5'] = sev_under5_nmb + pop_sizes_dict['total__under5'] = len(under5s) # log wasting prevalence logger.info(key='wasting_prevalence_props', data=wasting_prev_dict) - # log under5s pop size - logger.info(key='under5s pop size', data=len(under5s)) + # log pop sizes + logger.info(key='pop sizes', data=pop_sizes_dict) From ca519f953f9fe14eba7914b6e1040f05646d86ed Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 13 Dec 2024 14:27:06 +0000 Subject: [PATCH 186/755] analysis_wast: incidence - plot nmbs of new cases instead of props mod:wast incidence cases. --- .../wasting_analyses/analysis_wasting.py | 106 ++++++++++++++---- 1 file changed, 87 insertions(+), 19 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 713e7a949a..701ef7f2a2 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -46,8 +46,9 @@ def __init__(self, in_scenario_filename, in_outputs_path): sim_results_folder_path_run0_draw0 = sim_results_parent_folder_name + '/' + sim_results_folder_name + '/0/0/' sim_results_file_name_prefix = scenario_filename sim_results_file_name_extension = '.log.gz' - gz_results_file_path = Path(glob.glob(os.path.join(sim_results_folder_path_run0_draw0, - f"{sim_results_file_name_prefix}*{sim_results_file_name_extension}"))[0]) + gz_results_file_path = \ + Path(glob.glob(os.path.join(sim_results_folder_path_run0_draw0, + f"{sim_results_file_name_prefix}*{sim_results_file_name_extension}"))[0]) # Path to the decompressed .log file log_results_file_path = gz_results_file_path.with_suffix('') @@ -59,8 +60,12 @@ def __init__(self, in_scenario_filename, in_outputs_path): self.__log_file_path = log_results_file_path # parse wasting logs - self.__logs_dict = \ - parse_log_file(self.__log_file_path)['tlo.methods.wasting'] + self.__w_logs_dict = parse_log_file(self.__log_file_path)['tlo.methods.wasting'] + # parse scaling factor log + self.__scaling_factor = \ + parse_log_file(self.__log_file_path)['tlo.methods.population']['scaling_factor'].set_index('date').loc[ + '2010-01-01', 'scaling_factor' + ] # gender description self.__gender_desc = {'M': 'Males', @@ -80,7 +85,7 @@ def save_fig__store_pdf_file(self, fig, fig_output_name: str) -> None: def plot_wasting_incidence(self): """ plot the incidence of wasting over time """ - w_inc_df = self.__logs_dict['wasting_incidence_count'] + w_inc_df = self.__w_logs_dict['wasting_incidence_count'] w_inc_df = w_inc_df.set_index(w_inc_df.date.dt.year) w_inc_df = w_inc_df.drop(columns='date') # check no incidence of well-nourished @@ -92,28 +97,39 @@ def plot_wasting_incidence(self): age_years = list(w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys( )) - age_years.remove('5+y') + # age_years.remove('5+y') _row_counter = 0 _col_counter = 0 # plot setup fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 6)) - fig.delaxes(axes[1, 2]) + axes[1, 2].axis('off') # 5+y has no data (no new cases in 5+y), its space is used to display the label for _age in age_years: - new_df = pd.DataFrame() + plotting = pd.DataFrame() for state in w_inc_df.columns: - new_df[state] = \ + plotting[state] = \ w_inc_df.apply(lambda row: row[state][_age], axis=1) - # convert into proportions - new_df = new_df.apply(lambda _row: _row / _row.sum(), axis=1) - plotting = new_df.rename(columns=self.__wasting_types_desc) + # remove sev cases from mod cases (all sev cases went through mod state) + plotting["-3<=WHZ<-2"] = plotting["-3<=WHZ<-2"] - plotting["WHZ<-3"] + # rescale nmbs from simulated pop_size to pop size of Malawi + plotting = plotting * self.__scaling_factor + plotting = plotting.rename(columns=self.__wasting_types_desc) + ax = plotting.plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], - title=f"incidence of wasting in {_age} old", - ylim=[0, 1]) - ax.legend(loc='lower right') + title=f"incidence of wasting in {_age} old")#, + #ylim=[0, 1]) + show_legend = (_row_counter == 1 and _col_counter == 2) + # show_x_axis_label = (_row_counter == 0 and _col_counter == 2) + if show_legend: + ax.legend(loc='center') + ax.set_title('') + else: + ax.get_legend().remove() + # if show_x_axis_label: + # ax.set_xlabel('Year') # TODO: this is not working ax.set_xlabel('year') - ax.set_ylabel('proportion') + ax.set_ylabel('number of incidence cases') # move to another row if _col_counter == 2: _row_counter += 1 @@ -124,10 +140,59 @@ def plot_wasting_incidence(self): self.save_fig__store_pdf_file(fig, fig_output_name) # plt.show() + # def plot_wasting_incidence_mod_to_sev_props(self): + # """ plot the incidence of wasting over time """ + # w_inc_df = self.__w_logs_dict['wasting_incidence_count'] + # w_inc_df = w_inc_df.set_index(w_inc_df.date.dt.year) + # w_inc_df = w_inc_df.drop(columns='date') + # # check no incidence of well-nourished + # all_zeros = w_inc_df['WHZ>=-2'].apply(lambda x: all(value == 0 for value in x.values())) + # assert all(all_zeros) + # w_inc_df = w_inc_df[["WHZ<-3", "-3<=WHZ<-2"]] + # # get age_years, doesn't matter what wasting category you choose, + # # they all have same age groups + # age_years = list(w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys( + # + # )) + # age_years.remove('5+y') + # + # _row_counter = 0 + # _col_counter = 0 + # # plot setup + # fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 6)) + # fig.delaxes(axes[1, 2]) + # for _age in age_years: + # new_df = pd.DataFrame() + # for state in w_inc_df.columns: + # new_df[state] = \ + # w_inc_df.apply(lambda row: row[state][_age], axis=1) + # # convert into proportions + # new_df = new_df.apply(lambda _row: _row / _row.sum(), axis=1) + # plotting = new_df.rename(columns=self.__wasting_types_desc) + # ax = plotting.plot(kind='bar', stacked=True, + # ax=axes[_row_counter, _col_counter], + # title=f"incidence of wasting in {_age} old", + # ylim=[0, 1]) + # ax.legend(loc='lower right') + # ax.set_xlabel('year') + # ax.set_ylabel('proportion') + # # move to another row + # if _col_counter == 2: + # _row_counter += 1 + # _col_counter = -1 + # _col_counter += 1 # increment column counter + # + # handles, labels = axes[1, 1].get_legend_handles_labels() + # fig.legend(handles, labels, loc='center left', bbox_to_anchor=(1.05, 0.5)) + # fig_output_name = ('wasting_incidence_mod_to_sev_props__' + self.datestamp) + # fig.tight_layout() + # self.save_fig__store_pdf_file(fig, fig_output_name) + # # plt.show() + def plot_wasting_prevalence_per_year(self): """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of children wasted divide by the total number of children less than 5 years""" - w_prev_df = self.__logs_dict["wasting_prevalence_props"] + w_prev_df = self.__w_logs_dict["wasting_prevalence_props"] w_prev_df = w_prev_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']] w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) w_prev_df = w_prev_df.drop(columns='date') @@ -147,7 +212,7 @@ def plot_wasting_prevalence_per_year(self): def plot_wasting_prevalence_by_age_group(self): """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of children wasted in a particular age-group divided by the total number of children per that age-group""" - w_prev_df = self.__logs_dict["wasting_prevalence_props"] + w_prev_df = self.__w_logs_dict["wasting_prevalence_props"] w_prev_df = w_prev_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) w_prev_df = w_prev_df.loc[w_prev_df.index == 2020] @@ -198,7 +263,7 @@ def plot_modal_gbd_deaths_by_gender(self): ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, yerr=[plotting.GBD_lower, plotting.GBD_upper], fmt='o', color='#000', label="GBD") - ax.set_title('Direct deaths due to wasting') + ax.set_title('Direct deaths due to severe acute malnutrition') ax.set_xlabel("time period") ax.set_ylabel("number of deaths") ax.legend(loc=2) @@ -250,6 +315,9 @@ def plot_all_figs_in_one_pdf(self): # plot wasting incidence wasting_analyses.plot_wasting_incidence() + # plot wasting incidence mod:sev proportions + # wasting_analyses.plot_wasting_incidence_mod_to_sev_props() + # plot wasting prevalence wasting_analyses.plot_wasting_prevalence_per_year() From 3554a4071263934860aaefb964a2e4ff1ed1d60d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 13 Dec 2024 18:03:35 +0000 Subject: [PATCH 187/755] wast: log avg length of wasting --- src/tlo/methods/wasting.py | 107 ++++++++++++++++++++++++++++++++++--- 1 file changed, 100 insertions(+), 7 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 1cb3af46cd..29f7145e24 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -208,13 +208,25 @@ def __init__(self, name=None, resourcefilepath=None): self.wasting_symptom = 'weight_loss' # dict to hold counters for the number of episodes by wasting-type and age-group - blank_counter = dict( + blank_inc_counter = dict( zip(self.wasting_states, [list() for _ in self.wasting_states])) self.wasting_incident_case_tracker_blank = { - _agrp: copy.deepcopy(blank_counter) for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} - + _agrp: copy.deepcopy(blank_inc_counter) for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} self.wasting_incident_case_tracker = copy.deepcopy(self.wasting_incident_case_tracker_blank) + self.recovery_options = ['mod_nat_recov', + 'mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', + 'sev_MAM_tx_full_recov', 'sev_SAM_tx_full_recov', + 'mod_SAM_tx_recov_to_MAM', 'sev_SAM_tx_recov_to_MAM', + 'mod_not_yet_recovered', 'sev_not_yet_recovered'] + blank_length_counter = dict( + zip(self.recovery_options, [list() for _ in self.recovery_options])) + self.wasting_length_tracker_blank = { + _agrp: copy.deepcopy(blank_length_counter) for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} + self.wasting_length_tracker = copy.deepcopy(self.wasting_length_tracker_blank) + + self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} + def read_parameters(self, data_folder): """ :param data_folder: path of a folder supplied to the Simulation containing data files. Typically, @@ -877,6 +889,11 @@ def apply(self, person_id): if whz == '-3<=WHZ<-2': # improve WHZ df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished + age_group = self.module.age_grps.get(df.loc[person_id].age_years, '5+y') + self.module.wasting_length_tracker[age_group]['mod_nat_recov'].append( + (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days + ) + else: # whz == 'WHZ<-3' # improve WHZ @@ -904,6 +921,16 @@ def apply(self, person_id): if not df.at[person_id, 'is_alive']: return + if df.at[person_id, 'un_WHZ_category'] != 'WHZ>=-2': + if df.at[person_id, 'un_WHZ_category'] == '-3<=WHZ<-2': + recov_opt = f"mod_{df.at[person_id, 'un_clinical_acute_malnutrition']}_tx_full_recov" + elif df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3': + recov_opt = f"sev_{df.at[person_id, 'un_clinical_acute_malnutrition']}_tx_full_recov" + age_group = self.module.age_grps.get(df.loc[person_id].age_years, '5+y') + self.module.wasting_length_tracker[age_group][recov_opt].append( + (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days + ) + df.at[person_id, 'un_am_recovery_date'] = self.sim.date df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' @@ -952,6 +979,14 @@ def apply(self, person_id): p['proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC']]) if mam_classification == 'mam_by_muac_only': + if df.at[person_id, 'un_WHZ_category'] == '-3<=WHZ<-2': + recov_opt = "mod_SAM_tx_recov_to_MAM" + elif df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3': + recov_opt = "sev_SAM_tx_recov_to_MAM" + age_group = self.module.age_grps.get(df.loc[person_id].age_years, '5+y') + self.module.wasting_length_tracker[age_group][recov_opt].append( + (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days + ) df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' @@ -1464,6 +1499,8 @@ def __init__(self, module): def apply(self, population): df = self.sim.population.props + + # ----- INCIDENCE LOG ---------------- # Convert the list of timestamps into a number of timestamps # and check that all the dates have occurred since self.date_last_run inc_df = pd.DataFrame(index=self.module.wasting_incident_case_tracker.keys(), @@ -1476,18 +1513,74 @@ def apply(self, population): logger.info(key='wasting_incidence_count', data=inc_df.to_dict()) - # Reset the counters and the date_last_run - self.module.wasting_incident_case_tracker = copy.deepcopy( - self.module.wasting_incident_case_tracker_blank) + # Reset the tracker and the date_last_run + self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) self.date_last_run = self.sim.date + # ----- LENGTH LOG ---------------- + # Convert the list of lengths to an avg length + # and check that all the lengths are positive + length_df = pd.DataFrame(index=self.module.wasting_length_tracker.keys(), + columns=self.module.recovery_options) + for age_grp in self.module.wasting_length_tracker.keys(): + for recov_opt in self.module.recovery_options: + if self.module.wasting_length_tracker[age_grp][recov_opt]: + length_df.loc[age_grp, recov_opt] = (sum(self.module.wasting_length_tracker[age_grp][recov_opt]) / + len(self.module.wasting_length_tracker[age_grp][recov_opt])) + else: + length_df.loc[age_grp, recov_opt] = 0 + assert not np.isnan(length_df.loc[age_grp, recov_opt]) + assert all(length > 0 for length in self.module.wasting_length_tracker[age_grp][recov_opt]) + + # Reset the tracker + self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) + + under5s = df.loc[df.is_alive & (df.age_exact_years < 5)] + + for age_ys in range(5): + age_grp = self.module.age_grps.get(age_ys, '5+y') + + # get those children who are wasted + mod_wasted_whole_ys_agegrp = under5s[( + under5s.age_years.between(age_ys, age_ys + 1, inclusive='left') & + (under5s.un_WHZ_category == '-3<=WHZ<-2') + )] + sev_wasted_whole_ys_agegrp = under5s[( + under5s.age_years.between(age_ys, age_ys + 1, inclusive='left') & + (under5s.un_WHZ_category == 'WHZ<-3') + )] + mod_wasted_whole_ys_agegrp['wasting_length'] = \ + (self.sim.date - mod_wasted_whole_ys_agegrp['un_last_wasting_date_of_onset']).dt.days + sev_wasted_whole_ys_agegrp['wasting_length'] = \ + (self.sim.date - sev_wasted_whole_ys_agegrp['un_last_wasting_date_of_onset']).dt.days + if len(mod_wasted_whole_ys_agegrp) > 0: + assert not np.isnan(mod_wasted_whole_ys_agegrp['wasting_length']).all() + assert all(length > 0 for length in mod_wasted_whole_ys_agegrp['wasting_length']) + length_df.loc[age_grp, 'mod_not_yet_recovered'] = ( + sum(mod_wasted_whole_ys_agegrp['wasting_length']) / len(mod_wasted_whole_ys_agegrp['wasting_length']) + ) + else: + length_df.loc[age_grp, 'mod_not_yet_recovered'] = 0 + assert not np.isnan(length_df.loc[age_grp, 'mod_not_yet_recovered']) + if len(sev_wasted_whole_ys_agegrp) > 0: + assert not np.isnan(sev_wasted_whole_ys_agegrp['wasting_length']).all() + assert all(length > 0 for length in sev_wasted_whole_ys_agegrp['wasting_length']) + length_df.loc[age_grp, 'sev_not_yet_recovered'] = ( + sum(sev_wasted_whole_ys_agegrp['wasting_length']) / len(sev_wasted_whole_ys_agegrp['wasting_length']) + ) + else: + length_df.loc[age_grp, 'sev_not_yet_recovered'] = 0 + assert not np.isnan(length_df.loc[age_grp, 'sev_not_yet_recovered']) + + logger.info(key='wasting_length_avg', data=length_df.to_dict()) + + # ----- PREVALENCE LOG ---------------- # Wasting totals (prevalence & pop size at logging time) # declare a dictionary that will hold proportions of wasting prevalence per each age group wasting_prev_dict: Dict[str, Any] = dict() # declare a dictionary that will hold pop sizes pop_sizes_dict: Dict[str, Any] = dict() - under5s = df.loc[df.is_alive & (df.age_exact_years < 5)] # loop through different age groups and get proportions of wasting prevalence per each age group for low_bound_mos, high_bound_mos in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months low_bound_age_in_years = low_bound_mos / 12.0 From 4fcd605358823ac638b0de71753ad88f808368bc Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 15 Dec 2024 19:56:42 +0000 Subject: [PATCH 188/755] wast: log initial prevalence --- src/tlo/methods/wasting.py | 69 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 29f7145e24..2ec5b42c46 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -309,6 +309,7 @@ def initialise_simulation(self, sim): * the main logging event. """ + sim.schedule_event(Wasting_InitLoggingEvent(self), sim.date) sim.schedule_event(Wasting_InitiateGrowthMonitoring(self), sim.date) sim.schedule_event(Wasting_IncidencePoll(self), sim.date + DateOffset(months=3)) sim.schedule_event(Wasting_LoggingEvent(self), sim.date + DateOffset(years=1) - DateOffset(days=1)) @@ -1627,3 +1628,71 @@ def apply(self, population): # log pop sizes logger.info(key='pop sizes', data=pop_sizes_dict) + +class Wasting_InitLoggingEvent(Event, PopulationScopeEventMixin): + """ + This Event logs the number of incident cases that have occurred since the previous logging event. + Analysis scripts expect that the frequency of this logging event is once per year. + """ + + def __init__(self, module): + # This event to occur every year + super().__init__(module) + + def apply(self, population): + df = self.sim.population.props + + # ----- PREVALENCE LOG ---------------- + # Wasting totals (prevalence & pop size at logging time) + # declare a dictionary that will hold proportions of wasting prevalence per each age group + wasting_prev_dict: Dict[str, Any] = dict() + # declare a dictionary that will hold pop sizes + pop_sizes_dict: Dict[str, Any] = dict() + + under5s = df.loc[df.is_alive & (df.age_exact_years < 5)] + # loop through different age groups and get proportions of wasting prevalence per each age group + for low_bound_mos, high_bound_mos in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months + low_bound_age_in_years = low_bound_mos / 12.0 + high_bound_age_in_years = (1 + high_bound_mos) / 12.0 + # get those children who are wasted + mod_wasted_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, + inclusive='left') & (under5s.un_WHZ_category + == '-3<=WHZ<-2')).sum() + sev_wasted_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, + inclusive='left') & (under5s.un_WHZ_category + == 'WHZ<-3')).sum() + total_per_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, + inclusive='left')).sum() + # add moderate and severe wasting prevalence to the dictionary + wasting_prev_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = mod_wasted_agegrp_nmb / total_per_agegrp_nmb + wasting_prev_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = sev_wasted_agegrp_nmb / total_per_agegrp_nmb + # add pop sizes to the dataframe + pop_sizes_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = mod_wasted_agegrp_nmb + pop_sizes_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = sev_wasted_agegrp_nmb + pop_sizes_dict[f'total__{low_bound_mos}_{high_bound_mos}mo'] = total_per_agegrp_nmb + # log prevalence & pop size for children above 5y + above5s = df.loc[df.is_alive & (df.age_exact_years >= 5)] + assert (len(under5s) + len(above5s)) == len(df.loc[df.is_alive]) + mod_wasted_above5_nmb = (above5s.un_WHZ_category == '-3<=WHZ<-2').sum() + sev_wasted_above5_nmb = (above5s.un_WHZ_category == 'WHZ<-3').sum() + wasting_prev_dict['mod__5y+'] = mod_wasted_above5_nmb / len(above5s) + wasting_prev_dict['sev__5y+'] = sev_wasted_above5_nmb / len(above5s) + pop_sizes_dict['mod__5y+'] = mod_wasted_above5_nmb + pop_sizes_dict['sev__5y+'] = sev_wasted_above5_nmb + pop_sizes_dict['total__5y+'] = len(above5s) + + # add to dictionary proportion of all moderately/severely wasted children under 5 years + mod_under5_nmb = (under5s.un_WHZ_category == '-3<=WHZ<-2').sum() + sev_under5_nmb = (under5s.un_WHZ_category == 'WHZ<-3').sum() + wasting_prev_dict['total_mod_under5_prop'] = mod_under5_nmb / len(under5s) + wasting_prev_dict['total_sev_under5_prop'] = sev_under5_nmb / len(under5s) + pop_sizes_dict['mod__under5'] = mod_under5_nmb + pop_sizes_dict['sev__under5'] = sev_under5_nmb + pop_sizes_dict['total__under5'] = len(under5s) + + # log wasting prevalence + logger.info(key='wasting_init_prevalence_props', data=wasting_prev_dict) + + # log pop sizes + logger.info(key='init pop sizes', data=pop_sizes_dict) + From 3fdd9dac72a0e7a04677653b95aee6ad37ba76f1 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 15 Dec 2024 19:58:51 +0000 Subject: [PATCH 189/755] wast: length logging - sev wasted cannot be on MAM tx --- src/tlo/methods/wasting.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 2ec5b42c46..064bfde200 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -215,10 +215,11 @@ def __init__(self, name=None, resourcefilepath=None): self.wasting_incident_case_tracker = copy.deepcopy(self.wasting_incident_case_tracker_blank) self.recovery_options = ['mod_nat_recov', - 'mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', - 'sev_MAM_tx_full_recov', 'sev_SAM_tx_full_recov', - 'mod_SAM_tx_recov_to_MAM', 'sev_SAM_tx_recov_to_MAM', - 'mod_not_yet_recovered', 'sev_not_yet_recovered'] + 'mod_MAM_tx_full_recov', + 'mod_SAM_tx_full_recov', 'mod_SAM_tx_recov_to_MAM', + 'mod_not_yet_recovered', + 'sev_SAM_tx_full_recov', 'sev_SAM_tx_recov_to_MAM', + 'sev_not_yet_recovered'] blank_length_counter = dict( zip(self.recovery_options, [list() for _ in self.recovery_options])) self.wasting_length_tracker_blank = { From d1d2cce9105b162a5dedb06a96764b859ec617ae Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 15 Dec 2024 20:00:05 +0000 Subject: [PATCH 190/755] analysis_wast: plot avg length of wasting by recovery options --- .../wasting_analyses/analysis_wasting.py | 77 ++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 701ef7f2a2..ff3daa598f 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -60,7 +60,7 @@ def __init__(self, in_scenario_filename, in_outputs_path): self.__log_file_path = log_results_file_path # parse wasting logs - self.__w_logs_dict = parse_log_file(self.__log_file_path)['tlo.methods.wasting'] + self.__w_logs_dict = parse_log_file(self.__log_file_path)['tlo.methods.wasting'] # parse scaling factor log self.__scaling_factor = \ parse_log_file(self.__log_file_path)['tlo.methods.population']['scaling_factor'].set_index('date').loc[ @@ -78,6 +78,15 @@ def __init__(self, in_scenario_filename, in_outputs_path): self.fig_files = [] + cycle = plt.rcParams['axes.prop_cycle'].by_key()['color'] + # # define colo(u)rs to use: + self.__colors = { + 'severe wasting': cycle[0], + 'moderate wasting': cycle[1], + 'SAM': cycle[2], + 'MAM': cycle[3], + } + def save_fig__store_pdf_file(self, fig, fig_output_name: str) -> None: fig.savefig(self.outcomes_path_name + "/" + fig_output_name + '.png', format='png') fig.savefig(self.outcomes_path_name + "/" + fig_output_name + '.pdf', format='pdf') @@ -189,6 +198,69 @@ def plot_wasting_incidence(self): # self.save_fig__store_pdf_file(fig, fig_output_name) # # plt.show() + def plot_wasting_length(self): + """ plot the average length of wasting over time """ + w_length_df = self.__w_logs_dict['wasting_length_avg'] + w_length_df = w_length_df.set_index(w_length_df.date.dt.year) + w_length_df = w_length_df.drop(columns='date') + # get age_years, doesn't matter from which dict + age_years = list(w_length_df.loc[w_length_df.index[0], 'mod_MAM_tx_full_recov'].keys()) + print(f"{w_length_df=}") + # age_years.remove('5+y') + w_length_df = w_length_df.loc[:, ['mod_nat_recov', 'mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', + 'mod_SAM_tx_recov_to_MAM', 'mod_not_yet_recovered', + 'sev_SAM_tx_full_recov', 'sev_SAM_tx_recov_to_MAM', + 'sev_not_yet_recovered']] + + for recov_opt in w_length_df.columns: + _row_counter = 0 + _col_counter = 0 + # plot setup + fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 7)) + # axes[1, 2].axis('off') # 5+y has no data (no new cases in 5+y), its space is used to display the label + for _age in age_years: + print(f"{_col_counter=}, {_col_counter=}") + plotting = pd.DataFrame() + # dict to dataframe + plotting[recov_opt] = \ + w_length_df.apply(lambda row: row[recov_opt][_age], axis=1) + print(f"{plotting=}") + + if recov_opt.startswith("mod_"): + colour_to_use = self.__colors['moderate wasting'] + y_upper_lim = 355 + else: + colour_to_use = self.__colors['severe wasting'] + y_upper_lim = 1000 + ax = plotting.plot(kind='bar', stacked=False, + ax=axes[_row_counter, _col_counter], + title=f"length of wasting in {_age} old", + color=colour_to_use, + ylim=[0, y_upper_lim]) + # show_legend = (_row_counter == 0 and _col_counter == 0) + # # show_x_axis_label = (_row_counter == 0 and _col_counter == 2) + # if show_legend: + # ax.legend(loc='upper right', bbox_to_anchor=(0.5, 1.2), + # fancybox=True, shadow=True, ncol=5) + # else: + ax.get_legend().remove() + # if show_x_axis_label: + # ax.set_xlabel('Year') # TODO: this is not working + ax.set_xlabel('year') + ax.set_ylabel('avg length of wasting (days)') + # move to another row + if _col_counter == 2: + _row_counter += 1 + _col_counter = -1 + _col_counter += 1 # increment column counter + + fig.suptitle(f'{recov_opt}', fontsize=16) + # Adjust layout to make room for the suptitle + fig.tight_layout(rect=[0, 0, 1, 0.95]) + fig_output_name = ('wasting_length__' + recov_opt + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) + # plt.show() + def plot_wasting_prevalence_per_year(self): """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of children wasted divide by the total number of children less than 5 years""" @@ -318,6 +390,9 @@ def plot_all_figs_in_one_pdf(self): # plot wasting incidence mod:sev proportions # wasting_analyses.plot_wasting_incidence_mod_to_sev_props() + # plot wasting length + wasting_analyses.plot_wasting_length() + # plot wasting prevalence wasting_analyses.plot_wasting_prevalence_per_year() From d1582c1b4fff1dfcf006ec09c6147dabe3596715 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 15 Dec 2024 23:47:26 +0000 Subject: [PATCH 191/755] analysis_wast: prints rm --- src/scripts/wasting_analyses/analysis_wasting.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index ff3daa598f..1f667f6f8a 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -205,7 +205,6 @@ def plot_wasting_length(self): w_length_df = w_length_df.drop(columns='date') # get age_years, doesn't matter from which dict age_years = list(w_length_df.loc[w_length_df.index[0], 'mod_MAM_tx_full_recov'].keys()) - print(f"{w_length_df=}") # age_years.remove('5+y') w_length_df = w_length_df.loc[:, ['mod_nat_recov', 'mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', 'mod_SAM_tx_recov_to_MAM', 'mod_not_yet_recovered', @@ -219,12 +218,10 @@ def plot_wasting_length(self): fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 7)) # axes[1, 2].axis('off') # 5+y has no data (no new cases in 5+y), its space is used to display the label for _age in age_years: - print(f"{_col_counter=}, {_col_counter=}") plotting = pd.DataFrame() # dict to dataframe plotting[recov_opt] = \ w_length_df.apply(lambda row: row[recov_opt][_age], axis=1) - print(f"{plotting=}") if recov_opt.startswith("mod_"): colour_to_use = self.__colors['moderate wasting'] From e81f630f341064e56248ae5b74a95e10afd285da Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 15 Dec 2024 23:49:03 +0000 Subject: [PATCH 192/755] analysis_wast: add plot init prevalence by age grp --- .../wasting_analyses/analysis_wasting.py | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 1f667f6f8a..8e7b407542 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -306,7 +306,7 @@ def plot_wasting_prevalence_by_age_group(self): title="Wasting prevalence in children 0-59 months per each age group in 2020", ylabel='proportion', xlabel='age group', - ylim=[0, 0.3]) + ylim=[0, 0.2]) # Adjust the layout to make space for the footnote plt.subplots_adjust(bottom=0.85) # Adjust the bottom margin # Add footnote @@ -319,6 +319,49 @@ def plot_wasting_prevalence_by_age_group(self): self.save_fig__store_pdf_file(fig, fig_output_name) # plt.show() + def plot_wasting_initial_prevalence_by_age_group(self): + """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of + children wasted in a particular age-group divided by the total number of children per that age-group""" + w_prev_df = self.__w_logs_dict["wasting_init_prevalence_props"] + w_prev_df = w_prev_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) + w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) + w_prev_df = w_prev_df.drop(columns='date') + plotting = {'severe wasting': {}, 'moderate wasting': {}} + for col in w_prev_df.columns: + prefix, age_group = col.split('__') + if prefix == 'sev': + plotting['severe wasting'][age_group] = w_prev_df[col].values[0] + elif prefix == 'mod': + plotting['moderate wasting'][age_group] = w_prev_df[col].values[0] + plotting = pd.DataFrame(plotting) + order_x_axis = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] + # Assert all age groups are included + assert set(plotting.index) == set(order_x_axis), "age groups are not in line with the order_x_axis." + plotting = plotting.reindex(order_x_axis) + + # Plot wasting prevalence + fig, ax = plt.subplots(figsize=(10, 6)) + plotting.squeeze().plot(kind='bar', stacked=True, + ax=ax, + ylabel='proportion', + xlabel='age group', + ylim=[0, 0.2]) + ax.set_title(r"Wasting prevalence in children 0-59 months per each age group $\bf{at}$ $\bf{initiation}$") + # Adjust the layout to make space for the footnote + plt.subplots_adjust(bottom=0.85) # Adjust the bottom margin + # Add footnote + fig.figure.text(0.45, 0.88, + "proportion = number of wasted children in the age group " + "/ total number of children in the age group", + ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) + plt.tight_layout() + fig_output_name = ('wasting_initial_prevalence_per_each_age_group__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) + # plt.show() + + def add_wasting_initial_prevalence_by_age_group(self): + self.fig_files.append('wasting_initial_prevalence_per_each_age_group__' + self.datestamp + '.pdf') + def plot_modal_gbd_deaths_by_gender(self): """ compare modal and GBD deaths by gender """ death_compare = \ @@ -396,6 +439,9 @@ def plot_all_figs_in_one_pdf(self): # plot wasting prevalence by age group wasting_analyses.plot_wasting_prevalence_by_age_group() + # plot wasting initial prevalence by age group + wasting_analyses.plot_wasting_initial_prevalence_by_age_group() + # plot wasting deaths by gender as compared to GBD deaths wasting_analyses.plot_modal_gbd_deaths_by_gender() From dd59b080e455305eac43fe975f29a3fd3326e81c Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 16 Dec 2024 14:12:41 +0000 Subject: [PATCH 193/755] wast: log length for above5 too --- src/tlo/methods/wasting.py | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 064bfde200..c8d45e5d97 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1538,19 +1538,28 @@ def apply(self, population): self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) under5s = df.loc[df.is_alive & (df.age_exact_years < 5)] + above5s = df.loc[df.is_alive & (df.age_exact_years >= 5)] - for age_ys in range(5): + for age_ys in range(6): age_grp = self.module.age_grps.get(age_ys, '5+y') # get those children who are wasted - mod_wasted_whole_ys_agegrp = under5s[( - under5s.age_years.between(age_ys, age_ys + 1, inclusive='left') & - (under5s.un_WHZ_category == '-3<=WHZ<-2') - )] - sev_wasted_whole_ys_agegrp = under5s[( - under5s.age_years.between(age_ys, age_ys + 1, inclusive='left') & - (under5s.un_WHZ_category == 'WHZ<-3') - )] + if age_ys < 5: + mod_wasted_whole_ys_agegrp = under5s[( + under5s.age_years.between(age_ys, age_ys + 1, inclusive='left') & + (under5s.un_WHZ_category == '-3<=WHZ<-2') + )] + sev_wasted_whole_ys_agegrp = under5s[( + under5s.age_years.between(age_ys, age_ys + 1, inclusive='left') & + (under5s.un_WHZ_category == 'WHZ<-3') + )] + else: + mod_wasted_whole_ys_agegrp = above5s[( + above5s.un_WHZ_category == '-3<=WHZ<-2' + )] + sev_wasted_whole_ys_agegrp = above5s[( + above5s.un_WHZ_category == 'WHZ<-3' + )] mod_wasted_whole_ys_agegrp['wasting_length'] = \ (self.sim.date - mod_wasted_whole_ys_agegrp['un_last_wasting_date_of_onset']).dt.days sev_wasted_whole_ys_agegrp['wasting_length'] = \ From 0cb7c4c86222958044b5989ac3e43fd1cabe9528 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 18 Dec 2024 23:46:43 +0100 Subject: [PATCH 194/755] analysis_wast: higher upper y-axis limit for length of not yet recovered --- src/scripts/wasting_analyses/analysis_wasting.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 8e7b407542..ffc8bf5ea0 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -229,6 +229,9 @@ def plot_wasting_length(self): else: colour_to_use = self.__colors['severe wasting'] y_upper_lim = 1000 + if recov_opt.endswith("not_yet_recovered"): + y_upper_lim = 4000 + ax = plotting.plot(kind='bar', stacked=False, ax=axes[_row_counter, _col_counter], title=f"length of wasting in {_age} old", From 0d820023513fc4316417d889e41d34c7a8fe4a4b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 27 Dec 2024 14:18:32 +0100 Subject: [PATCH 195/755] wast: minor (properties description updated) --- src/tlo/methods/wasting.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index c8d45e5d97..2ed5e72be5 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -179,20 +179,24 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'un_last_wasting_date_of_onset': Property(Types.DATE, 'date of onset of last episode of wasting'), # Properties related to clinical acute malnutrition - 'un_clinical_acute_malnutrition': Property(Types.CATEGORICAL, 'clinical acute malnutrition state based' - ' on WHZ and/or MUAC and/or nutritional oedema', + 'un_clinical_acute_malnutrition': Property(Types.CATEGORICAL, 'clinical acute malnutrition state ' + 'based on WHZ and/or MUAC and/or nutritional ' + 'oedema', categories=['MAM', 'SAM', 'well']), - 'un_am_nutritional_oedema': Property(Types.BOOL, 'bilateral pitting oedema present in wasting episode'), + 'un_am_nutritional_oedema': Property(Types.BOOL, 'bilateral pitting oedema present in wasting ' + 'episode'), 'un_am_MUAC_category': Property(Types.CATEGORICAL, 'MUAC measurement categories, based on WHO ' 'cut-offs', categories=['<115mm', '[115-125)mm', '>=125mm']), 'un_sam_with_complications': Property(Types.BOOL, 'medical complications in SAM episode'), 'un_sam_death_date': Property(Types.DATE, 'death date from severe acute malnutrition'), - 'un_am_recovery_date': Property(Types.DATE, 'recovery date from last acute malnutrition episode (MAM/SAM)'), - 'un_am_discharge_date': Property(Types.DATE, 'discharge date from last treatment of MAM/SAM'), + 'un_am_recovery_date': Property(Types.DATE, 'recovery date from last acute malnutrition episode ' + '(MAM/SAM)'), + 'un_am_discharge_date': Property(Types.DATE, 'planned discharge date from last treatment of MAM/SAM ' + 'when recovery will happen if not yet recovered'), 'un_am_tx_start_date': Property(Types.DATE, 'treatment start date, if currently on treatment'), - 'un_am_treatment_type': Property(Types.CATEGORICAL, 'treatment type for acute malnutrition the person ' - 'is currently on; set to not_applicable if well hence no treatment required', + 'un_am_treatment_type': Property(Types.CATEGORICAL, 'treatment type for acute malnutrition the person' + ' is currently on; set to not_applicable if well hence no treatment required', categories=['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care'] + [ 'none', 'not_applicable']), } From f13b1697ecc567a17c0383668e412bc3291d0519 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 27 Dec 2024 14:24:07 +0100 Subject: [PATCH 196/755] wast: logging adjusted to avoid division by zero --- src/tlo/methods/wasting.py | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 2ed5e72be5..e600a9554f 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1600,18 +1600,26 @@ def apply(self, population): for low_bound_mos, high_bound_mos in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months low_bound_age_in_years = low_bound_mos / 12.0 high_bound_age_in_years = (1 + high_bound_mos) / 12.0 - # get those children who are wasted - mod_wasted_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, - inclusive='left') & (under5s.un_WHZ_category - == '-3<=WHZ<-2')).sum() - sev_wasted_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, - inclusive='left') & (under5s.un_WHZ_category - == 'WHZ<-3')).sum() total_per_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, inclusive='left')).sum() - # add moderate and severe wasting prevalence to the dictionary - wasting_prev_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = mod_wasted_agegrp_nmb / total_per_agegrp_nmb - wasting_prev_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = sev_wasted_agegrp_nmb / total_per_agegrp_nmb + if total_per_agegrp_nmb > 0: + # get those children who are wasted + mod_wasted_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, + inclusive='left') & (under5s.un_WHZ_category + == '-3<=WHZ<-2')).sum() + sev_wasted_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, + inclusive='left') & (under5s.un_WHZ_category + == 'WHZ<-3')).sum() + # add moderate and severe wasting prevalence to the dictionary + wasting_prev_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = \ + mod_wasted_agegrp_nmb / total_per_agegrp_nmb + wasting_prev_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = \ + sev_wasted_agegrp_nmb / total_per_agegrp_nmb + else: + # add zero moderate and severe wasting prevalence to the dictionary + wasting_prev_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = 0 + wasting_prev_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = 0 + # add pop sizes to the dataframe pop_sizes_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = mod_wasted_agegrp_nmb pop_sizes_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = sev_wasted_agegrp_nmb From 3ac65652e8f9aa10b89b340aed85bac724e2c25e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 27 Dec 2024 14:37:11 +0100 Subject: [PATCH 197/755] wast & RF_Wast & test_wast: natural death due SAM scheduled when SAM developed; natural recovery from severe wasting if not dying;date_of_outcome_for_untreated_wasting's fnc input parameter changed to whz_category --- resources/ResourceFile_Wasting.csv | 4 +- src/tlo/methods/wasting.py | 171 +++++++++++++++++++---------- tests/test_wasting.py | 157 ++++++++++++++++++-------- 3 files changed, 223 insertions(+), 109 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 1c6827eb6e..e4c7d87238 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9ca109b2ebfcad9ed760850559147b566abf02fc4105c20f89e0d378fe0ad8fe -size 2829 +oid sha256:dbd6e80601a7ed0343f1d143ea028be4046615d0323e5250fa3aed69d5028940 +size 2927 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index e600a9554f..de1a207c19 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -110,6 +110,10 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.LIST, 'List with progression rates to severe wasting by age group'), 'prob_complications_in_SAM': Parameter( Types.REAL, 'probability of medical complications in SAM '), + 'duration_sam_to_death': Parameter( + Types.REAL, 'duration of SAM till death if supposed to die due to SAM (days)'), + 'death_rate_untreated_SAM_by_agegp': Parameter( + Types.LIST, 'List with death rates due to untreated SAM by age group'), # MUAC distributions 'proportion_WHZ<-3_with_MUAC<115mm': Parameter( Types.REAL, 'proportion of individuals with severe wasting who have MUAC < 115 mm'), @@ -302,9 +306,9 @@ def initialise_population(self, population): # calculate approximation of probability of having normal WHZ in children under 5 to be used later self.prob_normal_whz = \ len(index_under5.intersection(df.index[df.un_WHZ_category == 'WHZ>=-2'])) / len(index_under5) - # -------------------------------------------------------------------------------------------------- # - # # # # Give MUAC category, presence of oedema, and determine acute malnutrition state # # # # - # # # # and, in SAM cases, determine presence of complications # # # # + # ----------------------------------------------------------------------------------------------------- # + # # # # Give MUAC category, presence of oedema, and determine acute malnutrition state # # # # + # # # # and, in SAM cases, determine presence of complications and eventually schedule death # # # # self.clinical_signs_acute_malnutrition(index_under5) def initialise_simulation(self, sim): @@ -501,12 +505,24 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): else: df.at[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' - # Determine if SAM episode has complications if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM': + # Determine if SAM episode has complications if self.rng.random_sample() < p['prob_complications_in_SAM']: df.at[person_id, 'un_sam_with_complications'] = True else: df.at[person_id, 'un_sam_with_complications'] = False + # Determine whether the SAM leads to death + death_due_to_sam = self.wasting_models.death_due_to_sam_lm.predict( + df.loc[[person_id]], rng=self.rng + ) + if death_due_to_sam: + outcome_date = self.date_of_death_for_untreated_sam() + self.sim.schedule_event( + event=Wasting_SevereAcuteMalnutritionDeath_Event(module=self, person_id=person_id), + date=outcome_date + ) + df.at[person_id, 'un_sam_death_date'] = outcome_date + else: df.at[person_id, 'un_sam_with_complications'] = False # clear all wasting symptoms @@ -517,35 +533,46 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): assert not ((df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') and (df.at[person_id, 'un_sam_with_complications'])) - def date_of_outcome_for_untreated_wasting(self, person_id): + def date_of_outcome_for_untreated_wasting(self, whz_category): """ - Helper function to use the duration of the wasting episode to get date of outcome (recovery, progression, - or death) - :param person_id: - :return: date of outcome, which can be recovery to no wasting or progression to severe wasting from moderate - wasting; or recovery to moderate wasting or death due to severe wasting + Helper function to determine the duration of the wasting episode to get date of outcome (recovery, progression, + or death). + :param whz_category: 'WHZ<-3', or '-3<=WHZ<-2' + :return: date of outcome, which can be recovery to no wasting, progression to severe wasting, or death due to + SAM in cases of moderate wasting; or recovery to moderate wasting or death due to SAM in cases of severe wasting """ - df = self.sim.population.props p = self.parameters - whz_category = df.at[person_id, 'un_WHZ_category'] # moderate wasting (for progression to severe, or recovery to no wasting) ----- if whz_category == '-3<=WHZ<-2': # Allocate the duration of the moderate wasting episode duration_mod_wasting = int(max(p['min_days_duration_of_wasting'], p['duration_of_untreated_mod_wasting'])) - # Allocate a date of outcome (progression, or recovery) - date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_mod_wasting) + # Allocate a date of outcome (death, progression, or recovery) + date_of_outcome = self.sim.date + DateOffset(days=duration_mod_wasting) return date_of_outcome # severe wasting (recovery to moderate wasting) ----- if whz_category == 'WHZ<-3': # determine the duration of severe wasting episode - duration_sev_wasting = int(max(p['min_days_duration_of_wasting'], p['duration_of_untreated_mod_wasting'] - + p['duration_of_untreated_sev_wasting'])) - # Allocate a date of outcome (recovery) - date_of_outcome = df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_sev_wasting) + duration_sev_wasting = int(max(p['min_days_duration_of_wasting'], p['duration_of_untreated_sev_wasting'])) + # Allocate a date of outcome (death, progression, or recovery) + date_of_outcome = self.sim.date + DateOffset(days=duration_sev_wasting) return date_of_outcome + def date_of_death_for_untreated_sam(self): + """ + Helper function to determine date of death, assuming it occurs earlier than the progression/recovery from any + wasting, moderate or severe. + :return: date of death + """ + p = self.parameters + + duration_sam_to_death = int(min(p['duration_of_untreated_mod_wasting'], p['duration_of_untreated_sev_wasting'], + p['duration_sam_to_death'])) + date_of_death = self.sim.date + DateOffset(days=duration_sam_to_death) + return date_of_death + + def clinical_signs_acute_malnutrition(self, idx): """ When WHZ changed, update other anthropometric indices and clinical signs (MUAC, oedema) that determine the @@ -675,6 +702,8 @@ def do_when_am_treatment(self, person_id, intervention): df.at[person_id, 'un_am_tx_start_date'] = self.sim.date # Reset tx discharge date df.at[person_id, 'un_am_discharge_date'] = pd.NaT + # Cancel natural death with due to tx + df.at[person_id, 'un_sam_death_date'] = pd.NaT if intervention == 'SFP': df.at[person_id, 'un_am_discharge_date'] = \ @@ -720,6 +749,7 @@ def do_when_am_treatment(self, person_id, intervention): event=Wasting_SevereAcuteMalnutritionDeath_Event(module=self, person_id=person_id), date=outcome_date ) + df.at[person_id, 'un_sam_death_date'] = outcome_date else: # recovery to MAM and follow-up treatment for MAM df.at[person_id, 'un_am_discharge_date'] = outcome_date self.sim.schedule_event(event=Wasting_UpdateToMAM_Event(module=self, person_id=person_id), @@ -757,7 +787,8 @@ def apply(self, population): not_wasted_or_treated = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == 'WHZ>=-2') & (df.un_am_tx_start_date != pd.NaT)] incidence_of_wasting = self.module.wasting_models.wasting_incidence_lm.predict(not_wasted_or_treated, rng=rng) - mod_wasting_new_cases_idx = not_wasted_or_treated.index[incidence_of_wasting] + mod_wasting_new_cases = not_wasted_or_treated.loc[incidence_of_wasting] + mod_wasting_new_cases_idx = mod_wasting_new_cases.index # update the properties for new cases of wasted children df.loc[mod_wasting_new_cases_idx, 'un_ever_wasted'] = True df.loc[mod_wasting_new_cases_idx, 'un_last_wasting_date_of_onset'] = self.sim.date @@ -769,41 +800,32 @@ def apply(self, population): age_group = Wasting_IncidencePoll.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') self.module.wasting_incident_case_tracker[age_group]['-3<=WHZ<-2'].append(self.sim.date) # Update properties related to clinical acute malnutrition - # (MUAC, oedema, clinical state of acute malnutrition and if SAM complications; clear symptoms if not SAM) + # (MUAC, oedema, clinical state of acute malnutrition and if SAM complications and death; + # clear symptoms if not SAM) self.module.clinical_signs_acute_malnutrition(mod_wasting_new_cases_idx) # ------------------------------------------------------------------------------------------- + outcome_date = self.module.date_of_outcome_for_untreated_wasting(whz_category='-3<=WHZ<-2') + # # # PROGRESS TO SEVERE WASTING # # # # # # # # # # # # # # # # # # # Determine those that will progress to severe wasting (WHZ < -3) and schedule progression event --------- progression_severe_wasting = self.module.wasting_models.severe_wasting_progression_lm.predict( df.loc[mod_wasting_new_cases_idx], rng=rng, squeeze_single_row_output=False ) - for person in mod_wasting_new_cases_idx[progression_severe_wasting]: - outcome_date = self.module.date_of_outcome_for_untreated_wasting(person_id=person) - # schedule severe wasting WHZ < -3 onset - if outcome_date <= self.sim.date: - # schedule severe wasting (WHZ < -3) onset today - self.sim.schedule_event(event=Wasting_ProgressionToSevere_Event( - module=self.module, person_id=person), date=self.sim.date) - else: - # schedule severe wasting WHZ < -3 onset according to duration - self.sim.schedule_event( - event=Wasting_ProgressionToSevere_Event( - module=self.module, person_id=person), date=outcome_date) + for person_id in mod_wasting_new_cases_idx[progression_severe_wasting]: + # schedule severe wasting WHZ < -3 onset after duration of moderate wasting + self.sim.schedule_event( + event=Wasting_ProgressionToSevere_Event( + module=self.module, person_id=person_id), date=outcome_date + ) # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # Schedule recovery from moderate wasting for those not progressing to severe wasting --------- - for person in mod_wasting_new_cases_idx[~progression_severe_wasting]: - outcome_date = self.module.date_of_outcome_for_untreated_wasting(person_id=person) - if outcome_date <= self.sim.date: - # schedule recovery for today - self.sim.schedule_event(event=Wasting_NaturalRecovery_Event( - module=self.module, person_id=person), date=self.sim.date) - else: - # schedule recovery according to duration - self.sim.schedule_event(event=Wasting_NaturalRecovery_Event( - module=self.module, person_id=person), date=outcome_date) + for person_id in mod_wasting_new_cases_idx[~progression_severe_wasting]: + # schedule recovery after duration of moderate wasting + self.sim.schedule_event(event=Wasting_NaturalRecovery_Event( + module=self.module, person_id=person_id), date=outcome_date) class Wasting_ProgressionToSevere_Event(Event, IndividualScopeEventMixin): @@ -818,7 +840,6 @@ def __init__(self, module, person_id): def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe - m = self.module if ( (not df.at[person_id, 'is_alive']) or @@ -829,19 +850,26 @@ def apply(self, person_id): ): return - # # # INCIDENCE OF SEVERE WASTING # # # # # # # # # # # # # # # # # # # # # - # continue with progression to severe if not treated/recovered else: + # # # INCIDENCE OF SEVERE WASTING # # # # # # # # # # # # # # # # # # # # # + # Continue with progression to severe if not treated/recovered # update properties # - WHZ df.at[person_id, 'un_WHZ_category'] = 'WHZ<-3' - # - MUAC, oedema, clinical state of acute malnutrition, complications + # - MUAC, oedema, clinical state of acute malnutrition, complications, death self.module.clinical_signs_acute_malnutrition(person_id) # ------------------------------------------------------------------------------------------- # Add this severe wasting incident case to the tracker age_group = Wasting_IncidencePoll.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') - m.wasting_incident_case_tracker[age_group]['WHZ<-3'].append(self.sim.date) + self.module.wasting_incident_case_tracker[age_group]['WHZ<-3'].append(self.sim.date) + + if pd.isnull(df.at[person_id, 'un_sam_death_date']): + # # # SEVERE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # # + # Schedule recovery from severe wasting for those not dying due to SAM + outcome_date = self.module.date_of_outcome_for_untreated_wasting(whz_category='WHZ<-3') + self.sim.schedule_event(event=Wasting_NaturalRecovery_Event( + module=self.module, person_id=person_id), date=outcome_date) class Wasting_SevereAcuteMalnutritionDeath_Event(Event, IndividualScopeEventMixin): @@ -856,23 +884,24 @@ def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe # The event should not run if the person is not currently alive or doesn't have SAM - if ( - (not df.at[person_id, 'is_alive']) or - (df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM') - ): + if not df.at[person_id, 'is_alive']: return # # Check if this person should still die from SAM: if ( pd.isnull(df.at[person_id, 'un_am_recovery_date']) and - not (df.at[person_id, 'un_am_discharge_date'] > df.at[person_id, 'un_am_tx_start_date']) + not (df.at[person_id, 'un_am_discharge_date'] > df.at[person_id, 'un_am_tx_start_date']) and + not pd.isnull(df.at[person_id, 'un_sam_death_date']) ): + assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' # Cause the death to happen immediately df.at[person_id, 'un_sam_death_date'] = self.sim.date self.sim.modules['Demography'].do_death( individual_id=person_id, cause='Severe Acute Malnutrition', originating_module=self.module) + else: + df.at[person_id, 'un_sam_death_date'] = pd.NaT class Wasting_NaturalRecovery_Event(Event, IndividualScopeEventMixin): @@ -888,7 +917,11 @@ def __init__(self, module, person_id): def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe - if (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2'): + if ( + (not df.at[person_id, 'is_alive']) or + (df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2') or + (not pd.isnull(df.at[person_id, 'un_sam_death_date'])) + ): return whz = df.at[person_id, 'un_WHZ_category'] @@ -905,12 +938,13 @@ def apply(self, person_id): # improve WHZ df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' # moderate wasting - # update MUAC, oedema, clinical state of acute malnutrition and if SAM complications, + # update MUAC, oedema, clinical state of acute malnutrition and if SAM complications and death, # clear symptoms if not SAM self.module.clinical_signs_acute_malnutrition(person_id) # set recovery date if recovered if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well': df.at[person_id, 'un_am_recovery_date'] = self.sim.date + df.at[person_id, 'un_sam_death_date'] = pd.NaT class Wasting_ClinicalAcuteMalnutritionRecovery_Event(Event, IndividualScopeEventMixin): @@ -943,6 +977,7 @@ def apply(self, person_id): df.at[person_id, 'un_am_nutritional_oedema'] = False df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' df.at[person_id, 'un_sam_with_complications'] = False + df.at[person_id, 'un_sam_death_date'] = pd.NaT df.at[person_id, 'un_am_tx_start_date'] = pd.NaT df.at[person_id, 'un_am_treatment_type'] = 'not_applicable' @@ -1385,14 +1420,16 @@ def __init__(self, module): # a linear model to predict the probability of individual's recovery from moderate acute malnutrition self.acute_malnutrition_recovery_mam_lm = LinearModel.multiplicative( - Predictor('un_am_treatment_type', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) + Predictor('un_am_treatment_type', + conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) .when('soy_RUSF', self.params['recovery_rate_with_soy_RUSF']) .when('CSB++', self.params['recovery_rate_with_CSB++']) ) # a linear model to predict the probability of individual's recovery from severe acute malnutrition self.acute_malnutrition_recovery_sam_lm = LinearModel.multiplicative( - Predictor('un_am_treatment_type', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) + Predictor('un_am_treatment_type', + conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) .when('standard_RUTF', self.params['recovery_rate_with_standard_RUTF']) .when('inpatient_care', self.params['recovery_rate_with_inpatient_care']) ) @@ -1400,7 +1437,8 @@ def __init__(self, module): # Linear model for the probability of progression to severe wasting (age-dependent only) # (natural history only, no interventions) self.severe_wasting_progression_lm = LinearModel.multiplicative( - Predictor('age_exact_years', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=False) + Predictor('age_exact_years', + conditions_are_mutually_exclusive=True, conditions_are_exhaustive=False) .when('<0.5', self.params['progression_severe_wasting_by_agegp'][0]) .when('.between(0.5,1, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][1]) .when('.between(1,2, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][2]) @@ -1412,6 +1450,19 @@ def __init__(self, module): # get wasting incidence linear model self.wasting_incidence_lm = self.get_wasting_incidence() + # Linear model for the probability of death due to SAM + self.death_due_to_sam_lm = LinearModel.multiplicative( + Predictor('age_exact_years', + conditions_are_mutually_exclusive=True, conditions_are_exhaustive=False) + .when('<0.5', self.params['death_rate_untreated_SAM_by_agegp'][0]) + .when('.between(0.5,1, inclusive="left")', self.params['death_rate_untreated_SAM_by_agegp'][1]) + .when('.between(1,2, inclusive="left")', self.params['death_rate_untreated_SAM_by_agegp'][2]) + .when('.between(2,3, inclusive="left")', self.params['death_rate_untreated_SAM_by_agegp'][3]) + .when('.between(3,4, inclusive="left")', self.params['death_rate_untreated_SAM_by_agegp'][4]) + .when('.between(4,5, inclusive="left")', self.params['death_rate_untreated_SAM_by_agegp'][5]), + Predictor().when('un_clinical_acute_malnutrition != "SAM"', 0), + ) + def get_wasting_incidence(self) -> LinearModel: """ :return: a scaled wasting incidence linear model amongst young children @@ -1423,7 +1474,8 @@ def unscaled_wasting_incidence_lm(intercept: Union[float, int] = 1.0) -> LinearM return LinearModel( LinearModelType.MULTIPLICATIVE, intercept, - Predictor('age_exact_years', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=False) + Predictor('age_exact_years', + conditions_are_mutually_exclusive=True, conditions_are_exhaustive=False) .when('<0.5', self.params['base_inc_rate_wasting_by_agegp'][0]) .when('.between(0.5,1, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][1]) .when('.between(1,2, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][2]) @@ -1464,7 +1516,8 @@ def unscaled_wasting_prevalence_lm(intercept: Union[float, int]) -> LinearModel: return LinearModel( LinearModelType.LOGISTIC, intercept, # baseline odds: get_odds_wasting(agegp=agegp) - Predictor('li_wealth', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=False) + Predictor('li_wealth', + conditions_are_mutually_exclusive=True, conditions_are_exhaustive=False) .when(2, self.params['or_wasting_hhwealth_Q2']) .when(3, self.params['or_wasting_hhwealth_Q3']) .when(4, self.params['or_wasting_hhwealth_Q4']) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 5b11be693f..d99671d01b 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -357,13 +357,21 @@ def test_recovery_moderate_wasting(tmpdir): assert pd.isnull(person['un_sam_death_date']) -def test_recovery_severe_wasting_without_complications(tmpdir): - """ Check recovery to MAM by removing death rate for those with severe wasting, and check the onset of - symptoms with SAM and revolving of symptoms when recovered to MAM """ +def test_recovery_severe_acute_malnutrition_without_complications(tmpdir): + """ Check the onset of symptoms with SAM, check recovery to MAM with tx when + the progression to severe wasting is certain, hence no natural recovery from moderate wasting, + the natural death due to SAM is certain, hence no natural recovery from severe wasting, + and check death canceled and symptoms resolved when recovered to MAM with tx. """ dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) + # get wasting module + wmodule = sim.modules['Wasting'] + + # set death due to untreated SAM at 100%, hence no natural recovery from severe wasting + wmodule.parameters['death_rate_untreated_SAM_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) sim.event_queue.queue = [] # clear the queue @@ -372,22 +380,27 @@ def test_recovery_severe_wasting_without_complications(tmpdir): df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] - # make this individual have no wasting + # Manually set this individual properties to be well df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' + df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' + df.loc[person_id, 'un_am_nutritional_oedema'] = False + df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' + df.at[person_id, 'un_sam_with_complications'] = False + df.at[person_id, 'un_sam_death_date'] = pd.NaT - # get wasting module - wmodule = sim.modules['Wasting'] + # ensure the individual has no complications when SAM occurs + wmodule.parameters['prob_complications_in_SAM'] = 0.0 - # Set incidence of wasting at 100% + # set incidence of wasting at 100% wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() - # set progress to severe wasting at 100% as well + # set progress to severe wasting at 100% as well, hence no natural recovery from moderate wasting wmodule.wasting_models.severe_wasting_progression_lm = LinearModel.multiplicative() - # set complete recovery from wasting to zero. We want those with SAM to recover to MAM + # set complete recovery from wasting to zero. We want those with SAM to recover to MAM with tx wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) - # Set death rate at 0% and recovery to MAM at 100% + # set prob of death after tx at 0% and recovery to MAM at 100% wmodule.parameters['prob_death_after_SAMcare'] = 0.0 wmodule.parameters['prob_mam_after_SAMcare'] = 1.0 @@ -408,19 +421,18 @@ def test_recovery_severe_wasting_without_complications(tmpdir): # Run the progression to severe wasting event: sim.date = date_of_scheduled_progression - progression_event.apply(person_id=person_id) + progression_event.apply(person_id) - # Check this individual has symptom(weight loss) caused by Wasting (SAM only) + # Check this individual has symptom (weight loss) caused by Wasting (SAM only) assert 'weight_loss' in sim.modules['SymptomManager'].has_what( person_id=person_id, disease_module=sim.modules['Wasting'] ) - # Check properties of this individual: (should now be severely wasted, diagnosed as SAM and without a scheduled - # death date) + # Check properties of this individual + # (should now be severely wasted, diagnosed as SAM person = df.loc[person_id] assert person['un_WHZ_category'] == 'WHZ<-3' assert person['un_clinical_acute_malnutrition'] == 'SAM' - assert pd.isnull(person['un_sam_death_date']) hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) hsp.run() @@ -447,31 +459,47 @@ def test_recovery_severe_wasting_without_complications(tmpdir): isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] sam_ev.run(squeeze_factor=0.0) - # check recovery event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_UpdateToMAM_Event) + # Check death is scheduled, but was canceled with tx + person = df.loc[person_id] + assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_SevereAcuteMalnutritionDeath_Event) + assert pd.isnull(person['un_sam_death_date']) + # get date of death and death event + death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], Wasting_SevereAcuteMalnutritionDeath_Event)][0] + date_of_scheduled_death = death_event_tuple[0] + death_event = death_event_tuple[1] + assert date_of_scheduled_death > sim.date - # Run the recovery event and check the individual has recovered from SAM: + # Check recovery to MAM due to tx is scheduled + assert isinstance(sim.find_events_for_person(person_id)[2][1], Wasting_UpdateToMAM_Event) + # get date of recovery to MAM and the recovery event sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if isinstance(event_tuple[1], Wasting_UpdateToMAM_Event)][0] - date_of_scheduled_recovery_to_mam = sam_recovery_event_tuple[0] sam_recovery_event = sam_recovery_event_tuple[1] assert date_of_scheduled_recovery_to_mam > sim.date - # Run SAM recovery - sim.date = date_of_scheduled_recovery_to_mam - sam_recovery_event.apply(person_id=person_id) + # Run death event (death should not happen) & recovery to MAM in correct order + sim.date = min(date_of_scheduled_death, date_of_scheduled_recovery_to_mam) + if sim.date == date_of_scheduled_death: + death_event.apply(person_id) + sim.date = date_of_scheduled_recovery_to_mam + sam_recovery_event.apply(person_id) + else: + sam_recovery_event.apply(person_id) + sim.date = date_of_scheduled_death + death_event.apply(person_id) # Check properties of this individual person = df.loc[person_id] - assert person['un_clinical_acute_malnutrition'] == 'MAM' + assert person['is_alive'] assert pd.isnull(person['un_sam_death_date']) - + assert person['un_clinical_acute_malnutrition'] == 'MAM' # check they have no symptoms: assert 0 == len(sim.modules['SymptomManager'].has_what(person_id=person_id, disease_module=sim.modules['Wasting'])) -def test_recovery_severe_wasting_with_complications(tmpdir): +def test_recovery_severe_acute_malnutrition_with_complications(tmpdir): """ test individual's recovery from wasting with complications """ dur = pd.DateOffset(days=0) popsize = 1000 @@ -489,11 +517,14 @@ def test_recovery_severe_wasting_with_complications(tmpdir): # get wasting module wmodule = sim.modules['Wasting'] + # set death due to untreated SAM at 100%, hence no natural recovery from severe wasting + wmodule.parameters['death_rate_untreated_SAM_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + # Manually set this individual properties to have # severe acute malnutrition with complications df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' - # make the individual have wasting complications + # ensure the individual has complications due to SAM wmodule.parameters['prob_complications_in_SAM'] = 1.0 # assign diagnosis @@ -508,7 +539,7 @@ def test_recovery_severe_wasting_with_complications(tmpdir): # should have complications assert df.at[person_id, 'un_sam_with_complications'] - # make recovery rate to 100% and death rate to zero so that + # make full recovery rate to 100% and death rate to zero so that # this individual should recover wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel.multiplicative() wmodule.parameters['prob_death_after_SAMcare'] = 0.0 @@ -539,20 +570,36 @@ def test_recovery_severe_wasting_with_complications(tmpdir): isinstance(ev[1], HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM)][0] sam_ev.run(squeeze_factor=0.0) - # check recovery event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[0][1], Wasting_ClinicalAcuteMalnutritionRecovery_Event) - - # Run the recovery event and check the individual has recovered from SAM: - sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], Wasting_ClinicalAcuteMalnutritionRecovery_Event)][0] + # Check death is scheduled, but was canceled due to tx + person = df.loc[person_id] + print(f"{sim.find_events_for_person(person_id)=}") + assert isinstance(sim.find_events_for_person(person_id)[0][1], Wasting_SevereAcuteMalnutritionDeath_Event) + assert pd.isnull(person['un_sam_death_date']) + # get date of death and death event + death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], Wasting_SevereAcuteMalnutritionDeath_Event)][0] + date_of_scheduled_death = death_event_tuple[0] + death_event = death_event_tuple[1] - date_of_scheduled_recovery_to_mam = sam_recovery_event_tuple[0] + # Check full recovery due to tx is scheduled + assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_ClinicalAcuteMalnutritionRecovery_Event) + # get date of full recovery and the recovery event + sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], Wasting_ClinicalAcuteMalnutritionRecovery_Event)][0] + date_of_scheduled_full_recovery = sam_recovery_event_tuple[0] sam_recovery_event = sam_recovery_event_tuple[1] - assert date_of_scheduled_recovery_to_mam > sim.date - - # Run SAM recovery - sim.date = date_of_scheduled_recovery_to_mam - sam_recovery_event.apply(person_id=person_id) + assert date_of_scheduled_full_recovery > sim.date + + # Run death event (death should not happen) & full recovery in correct order + sim.date = min(date_of_scheduled_death, date_of_scheduled_full_recovery) + if sim.date == date_of_scheduled_death: + death_event.apply(person_id) + sim.date = date_of_scheduled_full_recovery + sam_recovery_event.apply(person_id) + else: + sam_recovery_event.apply(person_id) + sim.date = date_of_scheduled_death + death_event.apply(person_id) # Check properties of this individual. Should now be well person = df.loc[person_id] @@ -665,7 +712,7 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): wmodule.parameters['prob_death_after_SAMcare'] = 0.0 wmodule.parameters['prob_mam_after_SAMcare'] = 1.0 - # increase wasting incidence rate to 100% and reduce rate of progress to severe wasting to zero.We don't want + # increase wasting incidence rate to 100% and reduce rate of progress to severe wasting to zero. We don't want # individuals to progress to SAM as we are testing for MAM natural recovery wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() wmodule.wasting_models.severe_wasting_progression_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) @@ -725,14 +772,18 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): popsize = 1000 sim = get_sim(tmpdir) + # get wasting module + wmodule = sim.modules['Wasting'] + + # set death due to untreated SAM at 0%, hence always scheduled natural recovery from severe wasting + wmodule.parameters['death_rate_untreated_SAM_by_agegp'] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) sim.event_queue.queue = [] # clear the queue - # get wasting module parameters - wmodule = sim.modules['Wasting'] - - # increase to 100% death rate, incidence and progress to severe wasting + # increase to 100% wasting incidence, progress to severe wasting, and death rate after SAM care; + # set full recovery ad recovery to MAM with SAM care at 0% wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() wmodule.wasting_models.severe_wasting_progression_lm = LinearModel.multiplicative() wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) @@ -743,7 +794,13 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] + # Manually set this individual properties to be well df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' + df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' + df.loc[person_id, 'un_am_nutritional_oedema'] = False + df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' + df.at[person_id, 'un_sam_with_complications'] = False + df.at[person_id, 'un_sam_death_date'] = pd.NaT # Run Wasting Polling event to get new incident cases: polling = Wasting_IncidencePoll(module=sim.modules['Wasting']) @@ -758,8 +815,7 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) - # Check that there is a Wasting_ProgressionToSevere_Event scheduled for this person and if the person is scheduled - # for death due to SAM, the death happens after the progression to severe wasting: + # Check that there is a Wasting_ProgressionToSevere_Event scheduled for this person progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if isinstance(event_tuple[1], Wasting_ProgressionToSevere_Event)][0] date_of_scheduled_progression = progression_event_tuple[0] @@ -805,8 +861,13 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] sam_ev.run(squeeze_factor=0.0) - # since there is zero recovery rate, check death event is scheduled - assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_SevereAcuteMalnutritionDeath_Event) + # since there is no natural death, natural recovery should be scheduled, and + # since there is zero recovery rate with tx, death event after care should be scheduled + print(f"{sim.find_events_for_person(person_id)=}") + assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_NaturalRecovery_Event) or \ + isinstance(sim.find_events_for_person(person_id)[2][1], Wasting_NaturalRecovery_Event) + assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_SevereAcuteMalnutritionDeath_Event) or \ + isinstance(sim.find_events_for_person(person_id)[2][1], Wasting_SevereAcuteMalnutritionDeath_Event) # Check a date of death is scheduled. it should be any date in the future: death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) From 8164ed6c00bd2fc113ef023b2fef5600dda53cc9 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 29 Dec 2024 16:33:46 +0100 Subject: [PATCH 198/755] wast: tidy up --- src/tlo/methods/wasting.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index de1a207c19..bdf797e860 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -998,9 +998,8 @@ def __init__(self, module, person_id): def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe - m = self.module - rng = m.rng - p = m.parameters + rng = self.module.rng + p = self.module.parameters if (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM'): return @@ -1076,8 +1075,8 @@ def apply(self, population): """ df = population.props - p = self.module.parameters rng = self.module.rng + p = self.module.parameters # TODO: including treated children? index_under5 = df.index[df.is_alive & (df.age_exact_years < 5)] @@ -1118,8 +1117,8 @@ def __init__(self, module, person_id): @property def EXPECTED_APPT_FOOTPRINT(self): """Return the expected appointment footprint based on attendance at the HSI event.""" - p = self.module.parameters rng = self.module.rng + p = self.module.parameters person_age = self.sim.population.props.loc[self.target].age_exact_years def get_attendance_prob(age): @@ -1139,8 +1138,8 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data='This is HSI_Wasting_GrowthMonitoring') df = self.sim.population.props - p = self.module.parameters rng = self.module.rng + p = self.module.parameters # TODO: Will they be monitored during the treatment? Can we assume, that after the treatment they will be # always properly checked (all measurements and oedema checked), or should be the assumed "treatment outcome" @@ -1415,8 +1414,8 @@ class WastingModels: def __init__(self, module): self.module = module - self.params = module.parameters self.rng = module.rng + self.params = module.parameters # a linear model to predict the probability of individual's recovery from moderate acute malnutrition self.acute_malnutrition_recovery_mam_lm = LinearModel.multiplicative( From 067062f28e275e1a4d8c93e7a44f369bfc4dc842 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 29 Dec 2024 16:54:42 +0100 Subject: [PATCH 199/755] wast: log wasting_length_avg only at debug level --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index bdf797e860..113744c38d 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1639,7 +1639,7 @@ def apply(self, population): length_df.loc[age_grp, 'sev_not_yet_recovered'] = 0 assert not np.isnan(length_df.loc[age_grp, 'sev_not_yet_recovered']) - logger.info(key='wasting_length_avg', data=length_df.to_dict()) + logger.debug(key='wasting_length_avg', data=length_df.to_dict()) # ----- PREVALENCE LOG ---------------- # Wasting totals (prevalence & pop size at logging time) From 0a4dee7cef5834488fcdf7888ef68d3784623817 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 20 Dec 2024 12:14:55 +0100 Subject: [PATCH 200/755] scenario_wast_min_model: setup as for status quo --- .../scenarios/scenario_wasting_minimal_model.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 552c80d474..0830b4b73c 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -61,10 +61,13 @@ def log_configuration(self): def modules(self): return [demography.Demography(resourcefilepath=self.resources), healthsystem.HealthSystem(resourcefilepath=self.resources, - service_availability=['*'], cons_availability='default'), + service_availability=['*'], use_funded_or_actual_staffing='actual', + mode_appt_constraints=1, + cons_availability='default', beds_availability='default', + equip_availability='all'), healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=self.resources), healthburden.HealthBurden(resourcefilepath=self.resources), - symptommanager.SymptomManager(resourcefilepath=self.resources), + symptommanager.SymptomManager(resourcefilepath=self.resources, spurious_symptoms=True), enhanced_lifestyle.Lifestyle(resourcefilepath=self.resources), simplified_births.SimplifiedBirths(resourcefilepath=self.resources), hiv.Hiv(resourcefilepath=self.resources), From f388ae83964631c0d1a51cd46fc97b1ec2392ce3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 29 Dec 2024 19:49:18 +0100 Subject: [PATCH 201/755] RF_PriorityRanking_ALLPOLICIES: after-merge update --- .../ResourceFile_PriorityRanking_ALLPOLICIES.xlsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES.xlsx index 1748d3f5e9..b8d2fa1d8f 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:59a7b6737589f04bc5fc80c3ca3c60f6dae2e1cf95e41ebefa995294298fbc84 -size 42958 +oid sha256:5d1a13f50e13f26aa00f5588cd012a8599ac558b7ac10fb427639a2987856ab9 +size 41075 From b632c012248ba26e4be273e67b82e2efed6385fe Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 11 Dec 2024 01:09:56 +0000 Subject: [PATCH 202/755] scenario_wast_min_model: 2K pop, 2010-2013 --- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 0830b4b73c..d434484e4d 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -40,8 +40,8 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + end_date=Date(year=2014, month=1, day=1), + initial_population_size=2_000, number_of_draws=1, runs_per_draw=1, ) From 451e1e8baf360468e48898c28d7190f68103d596 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 11 Dec 2024 12:09:26 +0000 Subject: [PATCH 203/755] scenario_wast_min_model: 4K pop, 2010-2030 --- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index d434484e4d..9b20812e5b 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -40,8 +40,8 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2014, month=1, day=1), - initial_population_size=2_000, + end_date=Date(year=2031, month=1, day=1), + initial_population_size=4_000, number_of_draws=1, runs_per_draw=1, ) From 9765631db8c99ac39bcd3e5378b41b81f1993ffd Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 13 Dec 2024 18:06:33 +0000 Subject: [PATCH 204/755] scenario_wast: 30K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 9b20812e5b..0830b4b73c 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -41,7 +41,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=1, runs_per_draw=1, ) From 5e96c668aa5d5ce7a8f43054370db60832dfd916 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 15 Dec 2024 20:00:43 +0000 Subject: [PATCH 205/755] scenario_wast_min_model: sim 1 day --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 0830b4b73c..98ec6d83af 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -40,7 +40,7 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2031, month=1, day=1), + end_date=Date(year=2010, month=1, day=2), initial_population_size=30_000, number_of_draws=1, runs_per_draw=1, From 687d262f13cef01f801b6ab4a07989d64d1e00cb Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 15 Dec 2024 23:46:52 +0000 Subject: [PATCH 206/755] scenario_wast_min_model: 2010-2030 incl., 30K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 98ec6d83af..0830b4b73c 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -40,7 +40,7 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2010, month=1, day=2), + end_date=Date(year=2031, month=1, day=1), initial_population_size=30_000, number_of_draws=1, runs_per_draw=1, From 7687a0728e3bd19a72cee47a5302f51511ece67e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 17 Dec 2024 10:42:04 +0000 Subject: [PATCH 207/755] scenario_wast_min_model: full availability of cons, beds, equip diff --git src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 0830b4b73..14ba49d5c 100644 --- src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -63,7 +63,7 @@ class WastingAnalysis(BaseScenario): healthsystem.HealthSystem(resourcefilepath=self.resources, service_availability=['*'], use_funded_or_actual_staffing='actual', mode_appt_constraints=1, - cons_availability='default', beds_availability='default', + cons_availability='all', beds_availability='all', equip_availability='all'), healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=self.resources), healthburden.HealthBurden(resourcefilepath=self.resources), --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 0830b4b73c..14ba49d5cc 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -63,7 +63,7 @@ def modules(self): healthsystem.HealthSystem(resourcefilepath=self.resources, service_availability=['*'], use_funded_or_actual_staffing='actual', mode_appt_constraints=1, - cons_availability='default', beds_availability='default', + cons_availability='all', beds_availability='all', equip_availability='all'), healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=self.resources), healthburden.HealthBurden(resourcefilepath=self.resources), From 524221768987a2cadefa9de9813bd13a4b2c7349 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 18 Dec 2024 12:44:24 +0000 Subject: [PATCH 208/755] long_run_all_dis: 100K pop, 1 draw --- .../calibration_analyses/scenarios/long_run_all_diseases.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/calibration_analyses/scenarios/long_run_all_diseases.py b/src/scripts/calibration_analyses/scenarios/long_run_all_diseases.py index 4a354e026c..f83cd3f613 100644 --- a/src/scripts/calibration_analyses/scenarios/long_run_all_diseases.py +++ b/src/scripts/calibration_analyses/scenarios/long_run_all_diseases.py @@ -22,9 +22,9 @@ def __init__(self): self.seed = 0 self.start_date = Date(2010, 1, 1) self.end_date = Date(2031, 1, 1) # The simulation will stop before reaching this date. - self.pop_size = 20_000 + self.pop_size = 100_000 self.number_of_draws = 1 - self.runs_per_draw = 10 + self.runs_per_draw = 1 def log_configuration(self): return { From 35e3fd38ad8771c536a6bbd60699613fe19a4b19 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 20 Dec 2024 13:14:55 +0100 Subject: [PATCH 209/755] scenario_wast_min_model: setup as for status quo diff --git src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 14ba49d5c..674af91dc 100644 --- src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -64,6 +64,9 @@ class WastingAnalysis(BaseScenario): service_availability=['*'], use_funded_or_actual_staffing='actual', mode_appt_constraints=1, cons_availability='all', beds_availability='all', + service_availability=['*'], use_funded_or_actual_staffing='actual', + mode_appt_constraints=1, + cons_availability='default', beds_availability='default', equip_availability='all'), healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=self.resources), healthburden.HealthBurden(resourcefilepath=self.resources), --- .../scenarios/scenario_wasting_minimal_model.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 14ba49d5cc..674af91dc8 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -64,6 +64,9 @@ def modules(self): service_availability=['*'], use_funded_or_actual_staffing='actual', mode_appt_constraints=1, cons_availability='all', beds_availability='all', + service_availability=['*'], use_funded_or_actual_staffing='actual', + mode_appt_constraints=1, + cons_availability='default', beds_availability='default', equip_availability='all'), healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=self.resources), healthburden.HealthBurden(resourcefilepath=self.resources), From fc90e804a38d16a9a924065d133e92d4d66608ce Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 29 Dec 2024 16:57:38 +0100 Subject: [PATCH 210/755] scenario_wast_min_model: log wasting at debug level --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 674af91dc8..5c17918d9c 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -53,7 +53,7 @@ def log_configuration(self): "custom_levels": { # Customise the output of specific loggers "tlo.methods.demography": logging.INFO, "tlo.methods.population": logging.INFO, - "tlo.methods.wasting": logging.INFO, + "tlo.methods.wasting": logging.DEBUG, '*': logging.WARNING } } From 3a620e03104fa2c536b5125f092c3823c05021ff Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 30 Dec 2024 09:27:20 +0100 Subject: [PATCH 211/755] RF_Wast: death rate due to untreated SAM by age gp: [0.25, 0.25, 0.2, 0.2, 0.2, 0.2] --- resources/ResourceFile_Wasting.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index e4c7d87238..dff9f55c55 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dbd6e80601a7ed0343f1d143ea028be4046615d0323e5250fa3aed69d5028940 +oid sha256:70515a4af246719ad441eec1fc0a8b69ee3b49b63cb531a614f3f644080f59e0 size 2927 From 1f6cd56d49a1f73b0b4d15c87a013f8213c8d470 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 30 Dec 2024 16:52:26 +0100 Subject: [PATCH 212/755] RF_Wast: mod & sev wast incidence [Maleta et al., 2003] --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index dff9f55c55..63ba43f45d 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70515a4af246719ad441eec1fc0a8b69ee3b49b63cb531a614f3f644080f59e0 -size 2927 +oid sha256:fd95fab83a578e89edc403b1465ac39e0e686a618da30de752a6c7f1284a2375 +size 3143 From 083123390b1d80bccb9bf1b7857a8548b108f856 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 30 Dec 2024 16:54:04 +0100 Subject: [PATCH 213/755] RF_Wast: death after SAM care adjusted as it is cond. prob if not fully recovered --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 63ba43f45d..5c3bf3eb91 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fd95fab83a578e89edc403b1465ac39e0e686a618da30de752a6c7f1284a2375 -size 3143 +oid sha256:84ac06fa15d655a8b80c15a0f2816dee7a9799b4e04a986ea2cbc0f7f587b3cc +size 3203 From cac4d84330cd6bc5f74561a387b2d458e7a98db3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 30 Dec 2024 16:54:31 +0100 Subject: [PATCH 214/755] analysis_wast: plot avg_length only if it was logged --- .../wasting_analyses/analysis_wasting.py | 121 +++++++++--------- 1 file changed, 61 insertions(+), 60 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index ffc8bf5ea0..88e6bf18b0 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -200,66 +200,67 @@ def plot_wasting_incidence(self): def plot_wasting_length(self): """ plot the average length of wasting over time """ - w_length_df = self.__w_logs_dict['wasting_length_avg'] - w_length_df = w_length_df.set_index(w_length_df.date.dt.year) - w_length_df = w_length_df.drop(columns='date') - # get age_years, doesn't matter from which dict - age_years = list(w_length_df.loc[w_length_df.index[0], 'mod_MAM_tx_full_recov'].keys()) - # age_years.remove('5+y') - w_length_df = w_length_df.loc[:, ['mod_nat_recov', 'mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', - 'mod_SAM_tx_recov_to_MAM', 'mod_not_yet_recovered', - 'sev_SAM_tx_full_recov', 'sev_SAM_tx_recov_to_MAM', - 'sev_not_yet_recovered']] - - for recov_opt in w_length_df.columns: - _row_counter = 0 - _col_counter = 0 - # plot setup - fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 7)) - # axes[1, 2].axis('off') # 5+y has no data (no new cases in 5+y), its space is used to display the label - for _age in age_years: - plotting = pd.DataFrame() - # dict to dataframe - plotting[recov_opt] = \ - w_length_df.apply(lambda row: row[recov_opt][_age], axis=1) - - if recov_opt.startswith("mod_"): - colour_to_use = self.__colors['moderate wasting'] - y_upper_lim = 355 - else: - colour_to_use = self.__colors['severe wasting'] - y_upper_lim = 1000 - if recov_opt.endswith("not_yet_recovered"): - y_upper_lim = 4000 - - ax = plotting.plot(kind='bar', stacked=False, - ax=axes[_row_counter, _col_counter], - title=f"length of wasting in {_age} old", - color=colour_to_use, - ylim=[0, y_upper_lim]) - # show_legend = (_row_counter == 0 and _col_counter == 0) - # # show_x_axis_label = (_row_counter == 0 and _col_counter == 2) - # if show_legend: - # ax.legend(loc='upper right', bbox_to_anchor=(0.5, 1.2), - # fancybox=True, shadow=True, ncol=5) - # else: - ax.get_legend().remove() - # if show_x_axis_label: - # ax.set_xlabel('Year') # TODO: this is not working - ax.set_xlabel('year') - ax.set_ylabel('avg length of wasting (days)') - # move to another row - if _col_counter == 2: - _row_counter += 1 - _col_counter = -1 - _col_counter += 1 # increment column counter - - fig.suptitle(f'{recov_opt}', fontsize=16) - # Adjust layout to make room for the suptitle - fig.tight_layout(rect=[0, 0, 1, 0.95]) - fig_output_name = ('wasting_length__' + recov_opt + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name) - # plt.show() + if 'wasting_length_avg' in self.__w_logs_dict: + w_length_df = self.__w_logs_dict['wasting_length_avg'] + w_length_df = w_length_df.set_index(w_length_df.date.dt.year) + w_length_df = w_length_df.drop(columns='date') + # get age_years, doesn't matter from which dict + age_years = list(w_length_df.loc[w_length_df.index[0], 'mod_MAM_tx_full_recov'].keys()) + # age_years.remove('5+y') + w_length_df = w_length_df.loc[:, ['mod_nat_recov', 'mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', + 'mod_SAM_tx_recov_to_MAM', 'mod_not_yet_recovered', + 'sev_SAM_tx_full_recov', 'sev_SAM_tx_recov_to_MAM', + 'sev_not_yet_recovered']] + + for recov_opt in w_length_df.columns: + _row_counter = 0 + _col_counter = 0 + # plot setup + fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 7)) + # axes[1, 2].axis('off') # 5+y has no data (no new cases in 5+y), its space is used to display the label + for _age in age_years: + plotting = pd.DataFrame() + # dict to dataframe + plotting[recov_opt] = \ + w_length_df.apply(lambda row: row[recov_opt][_age], axis=1) + + if recov_opt.startswith("mod_"): + colour_to_use = self.__colors['moderate wasting'] + y_upper_lim = 355 + else: + colour_to_use = self.__colors['severe wasting'] + y_upper_lim = 1000 + if recov_opt.endswith("not_yet_recovered"): + y_upper_lim = 4000 + + ax = plotting.plot(kind='bar', stacked=False, + ax=axes[_row_counter, _col_counter], + title=f"length of wasting in {_age} old", + color=colour_to_use, + ylim=[0, y_upper_lim]) + # show_legend = (_row_counter == 0 and _col_counter == 0) + # # show_x_axis_label = (_row_counter == 0 and _col_counter == 2) + # if show_legend: + # ax.legend(loc='upper right', bbox_to_anchor=(0.5, 1.2), + # fancybox=True, shadow=True, ncol=5) + # else: + ax.get_legend().remove() + # if show_x_axis_label: + # ax.set_xlabel('Year') # TODO: this is not working + ax.set_xlabel('year') + ax.set_ylabel('avg length of wasting (days)') + # move to another row + if _col_counter == 2: + _row_counter += 1 + _col_counter = -1 + _col_counter += 1 # increment column counter + + fig.suptitle(f'{recov_opt}', fontsize=16) + # Adjust layout to make room for the suptitle + fig.tight_layout(rect=[0, 0, 1, 0.95]) + fig_output_name = ('wasting_length__' + recov_opt + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) + # plt.show(`) def plot_wasting_prevalence_per_year(self): """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of From 44adb7ec41cc0a94111730edb40b41410ad5eb9a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 30 Dec 2024 16:58:23 +0100 Subject: [PATCH 215/755] wast & scenario_wast_min_model: wasting_length_avg logging back to INFO level --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- src/tlo/methods/wasting.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 5c17918d9c..674af91dc8 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -53,7 +53,7 @@ def log_configuration(self): "custom_levels": { # Customise the output of specific loggers "tlo.methods.demography": logging.INFO, "tlo.methods.population": logging.INFO, - "tlo.methods.wasting": logging.DEBUG, + "tlo.methods.wasting": logging.INFO, '*': logging.WARNING } } diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 113744c38d..bdf797e860 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1639,7 +1639,7 @@ def apply(self, population): length_df.loc[age_grp, 'sev_not_yet_recovered'] = 0 assert not np.isnan(length_df.loc[age_grp, 'sev_not_yet_recovered']) - logger.debug(key='wasting_length_avg', data=length_df.to_dict()) + logger.info(key='wasting_length_avg', data=length_df.to_dict()) # ----- PREVALENCE LOG ---------------- # Wasting totals (prevalence & pop size at logging time) From b681565f36dffab1d2003e0f51ed8ed1f1b19f6f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 30 Dec 2024 18:10:04 +0100 Subject: [PATCH 216/755] wast & RF_Wast: death rate due to untreat. SAM calculated with base death rate and rr by age gp (to be able to change single par when calibrating) --- resources/ResourceFile_Wasting.csv | 4 ++-- src/tlo/methods/wasting.py | 24 ++++++++++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 5c3bf3eb91..0202cd2f1c 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:84ac06fa15d655a8b80c15a0f2816dee7a9799b4e04a986ea2cbc0f7f587b3cc -size 3203 +oid sha256:7a51974709788d34fd91684861b34dc84d1a6d31cfac556a4a1ea31b551acef8 +size 3277 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index bdf797e860..3f3771219b 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -107,13 +107,15 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'duration_of_untreated_sev_wasting': Parameter( Types.REAL, 'duration of untreated severe wasting (days)'), 'progression_severe_wasting_by_agegp': Parameter( - Types.LIST, 'List with progression rates to severe wasting by age group'), + Types.LIST, 'list with progression rates to severe wasting by age group'), 'prob_complications_in_SAM': Parameter( Types.REAL, 'probability of medical complications in SAM '), 'duration_sam_to_death': Parameter( Types.REAL, 'duration of SAM till death if supposed to die due to SAM (days)'), - 'death_rate_untreated_SAM_by_agegp': Parameter( - Types.LIST, 'List with death rates due to untreated SAM by age group'), + 'base_death_rate_untreated_SAM': Parameter( + Types.REAL, 'base death rate due to untreated SAM for age group of children <0.5 months old'), + 'rr_death_rate_by_agegp': Parameter( + Types.LIST, 'list with relative risks of death due to untreated SAM by age gp, reference gp <0.5 months'), # MUAC distributions 'proportion_WHZ<-3_with_MUAC<115mm': Parameter( Types.REAL, 'proportion of individuals with severe wasting who have MUAC < 115 mm'), @@ -1450,15 +1452,17 @@ def __init__(self, module): self.wasting_incidence_lm = self.get_wasting_incidence() # Linear model for the probability of death due to SAM - self.death_due_to_sam_lm = LinearModel.multiplicative( + self.death_due_to_sam_lm = LinearModel( + LinearModelType.MULTIPLICATIVE, + self.params['base_death_rate_untreated_SAM'], Predictor('age_exact_years', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=False) - .when('<0.5', self.params['death_rate_untreated_SAM_by_agegp'][0]) - .when('.between(0.5,1, inclusive="left")', self.params['death_rate_untreated_SAM_by_agegp'][1]) - .when('.between(1,2, inclusive="left")', self.params['death_rate_untreated_SAM_by_agegp'][2]) - .when('.between(2,3, inclusive="left")', self.params['death_rate_untreated_SAM_by_agegp'][3]) - .when('.between(3,4, inclusive="left")', self.params['death_rate_untreated_SAM_by_agegp'][4]) - .when('.between(4,5, inclusive="left")', self.params['death_rate_untreated_SAM_by_agegp'][5]), + .when('<0.5', self.params['rr_death_rate_by_agegp'][0]) + .when('.between(0.5,1, inclusive="left")', self.params['rr_death_rate_by_agegp'][1]) + .when('.between(1,2, inclusive="left")', self.params['rr_death_rate_by_agegp'][2]) + .when('.between(2,3, inclusive="left")', self.params['rr_death_rate_by_agegp'][3]) + .when('.between(3,4, inclusive="left")', self.params['rr_death_rate_by_agegp'][4]) + .when('.between(4,5, inclusive="left")', self.params['rr_death_rate_by_agegp'][5]), Predictor().when('un_clinical_acute_malnutrition != "SAM"', 0), ) From 85f0b936378e7c755a1e2a30e755e89afb166c8d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 4 Jan 2025 00:48:08 +0100 Subject: [PATCH 217/755] analysis_wast: prev per year - plot model outputs + calibration prev data --- .../wasting_analyses/analysis_wasting.py | 61 ++++++++++++++++--- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 88e6bf18b0..e75f8dd6e0 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -9,6 +9,7 @@ import time from pathlib import Path +import numpy as np import pandas as pd from matplotlib import pyplot as plt from PyPDF2 import PdfReader, PdfWriter @@ -80,12 +81,16 @@ def __init__(self, in_scenario_filename, in_outputs_path): cycle = plt.rcParams['axes.prop_cycle'].by_key()['color'] # # define colo(u)rs to use: - self.__colors = { + self.__colors_model = { 'severe wasting': cycle[0], 'moderate wasting': cycle[1], 'SAM': cycle[2], 'MAM': cycle[3], } + self.__colors_data = { + 'severe wasting': '#82C1EC', + 'moderate wasting': '#C71E1E', + } def save_fig__store_pdf_file(self, fig, fig_output_name: str) -> None: fig.savefig(self.outcomes_path_name + "/" + fig_output_name + '.png', format='png') @@ -225,10 +230,10 @@ def plot_wasting_length(self): w_length_df.apply(lambda row: row[recov_opt][_age], axis=1) if recov_opt.startswith("mod_"): - colour_to_use = self.__colors['moderate wasting'] + colour_to_use = self.__colors_model['moderate wasting'] y_upper_lim = 355 else: - colour_to_use = self.__colors['severe wasting'] + colour_to_use = self.__colors_model['severe wasting'] y_upper_lim = 1000 if recov_opt.endswith("not_yet_recovered"): y_upper_lim = 4000 @@ -265,18 +270,54 @@ def plot_wasting_length(self): def plot_wasting_prevalence_per_year(self): """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of children wasted divide by the total number of children less than 5 years""" + w_prev_calib_data_years_only_df = pd.DataFrame({ + 'sev_wast_calib': [0.015, 0.011, 0.006, 0.007], + 'mod_wast_calib': [0.025, 0.027, 0.021, 0.019] + }, index=[2010, 2014, 2016, 2020]) + date_range = pd.Index(range(2010, 2031), name='date') + w_prev_calib = pd.DataFrame(index=date_range) + # filling missing values with 0 + w_prev_calib_df = w_prev_calib.merge( + w_prev_calib_data_years_only_df, left_index=True, right_index=True, how='left' + ).fillna(0) + w_prev_df = self.__w_logs_dict["wasting_prevalence_props"] w_prev_df = w_prev_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']] w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) w_prev_df = w_prev_df.drop(columns='date') + + w_prev_plot_df = pd.merge(w_prev_df, w_prev_calib_df, on='date') + columns_to_plot = [['total_sev_under5_prop', 'total_mod_under5_prop'], ['sev_wast_calib', 'mod_wast_calib']] + colors_to_plot = { + 'total_sev_under5_prop': self.__colors_model['severe wasting'], + 'total_mod_under5_prop': self.__colors_model['moderate wasting'], + 'sev_wast_calib': self.__colors_data['severe wasting'], + 'mod_wast_calib': self.__colors_data['moderate wasting'] + } + labels_to_plot = { + 'total_sev_under5_prop': 'severe wasting (model)', + 'total_mod_under5_prop': 'moderate wasting (model)', + 'sev_wast_calib': 'severe wasting (data)', + 'mod_wast_calib': 'moderate wasting (data)' + } + fig, ax = plt.subplots() - w_prev_df.plot(kind='bar', stacked=True, - ax=ax, - title="Wasting prevalence in children 0-59 months per year", - ylabel='proportion of wasted children in the year', - xlabel='year', - ylim=[0, 0.15]) - # add_footnote(fig, "proportion of wasted children within each age-group") + bar_spots = len(columns_to_plot) + bar_width = 0.8 / bar_spots + pos = np.arange(len(w_prev_plot_df)) + dodge_offsets = np.linspace(-bar_spots * bar_width / 2, bar_spots * bar_width / 2, bar_spots, endpoint=False) + for columns, offset in zip(columns_to_plot, dodge_offsets): + bottom = 0 + for col in ([columns] if isinstance(columns, str) else columns): + ax.bar(pos + offset, w_prev_plot_df[col], bottom=bottom, width=bar_width, align='edge', + label=labels_to_plot[col], color=colors_to_plot[col]) + bottom += w_prev_plot_df[col] + ax.set_xticks(pos) + ax.set_xticklabels(w_prev_plot_df.index, rotation=90) + ax.set_title("Wasting prevalence in children 0-59 months per year") + ax.set_ylabel('proportion of wasted children in the year') + ax.set_xlabel('year') + ax.legend() plt.tight_layout() fig_output_name = ('wasting_prevalence_per_year__' + self.datestamp) self.save_fig__store_pdf_file(fig, fig_output_name) From a07f6dab3744040c27b4107a7be50e7d5676bece Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 7 Jan 2025 13:59:00 +0100 Subject: [PATCH 218/755] RF_Wast: progression to sev. wast adjusted to 45-days incidence --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 0202cd2f1c..542aed82ea 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a51974709788d34fd91684861b34dc84d1a6d31cfac556a4a1ea31b551acef8 -size 3277 +oid sha256:d38c4896c1fa05ad59e43b4af45be04413e1b9257aef45da3e8bddc00c35c4e0 +size 3494 From 3727c6cd325d587073d8a2f418988adc4d783e79 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 8 Jan 2025 14:51:18 +0100 Subject: [PATCH 219/755] analysis_wast: prev_by_age_group for all years calib data avail; add calib data to compare --- .../wasting_analyses/analysis_wasting.py | 154 +++++++++++++----- 1 file changed, 112 insertions(+), 42 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index e75f8dd6e0..aa41ee49ae 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -205,6 +205,7 @@ def plot_wasting_incidence(self): def plot_wasting_length(self): """ plot the average length of wasting over time """ + if 'wasting_length_avg' in self.__w_logs_dict: w_length_df = self.__w_logs_dict['wasting_length_avg'] w_length_df = w_length_df.set_index(w_length_df.date.dt.year) @@ -270,6 +271,7 @@ def plot_wasting_length(self): def plot_wasting_prevalence_per_year(self): """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of children wasted divide by the total number of children less than 5 years""" + w_prev_calib_data_years_only_df = pd.DataFrame({ 'sev_wast_calib': [0.015, 0.011, 0.006, 0.007], 'mod_wast_calib': [0.025, 0.027, 0.021, 0.019] @@ -326,43 +328,111 @@ def plot_wasting_prevalence_per_year(self): def plot_wasting_prevalence_by_age_group(self): """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of children wasted in a particular age-group divided by the total number of children per that age-group""" - w_prev_df = self.__w_logs_dict["wasting_prevalence_props"] - w_prev_df = w_prev_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) - w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) - w_prev_df = w_prev_df.loc[w_prev_df.index == 2020] - w_prev_df = w_prev_df.drop(columns='date') - plotting = {'severe wasting': {}, 'moderate wasting': {}} - for col in w_prev_df.columns: - prefix, age_group = col.split('__') - if prefix == 'sev': - plotting['severe wasting'][age_group] = w_prev_df[col].values[0] - elif prefix == 'mod': - plotting['moderate wasting'][age_group] = w_prev_df[col].values[0] - plotting = pd.DataFrame(plotting) - order_x_axis = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] - # Assert all age groups are included - assert set(plotting.index) == set(order_x_axis), "age groups are not in line with the order_x_axis." - plotting = plotting.reindex(order_x_axis) - # Plot wasting prevalence - fig, ax = plt.subplots(figsize=(10, 6)) - plotting.squeeze().plot(kind='bar', stacked=True, - ax=ax, - title="Wasting prevalence in children 0-59 months per each age group in 2020", - ylabel='proportion', - xlabel='age group', - ylim=[0, 0.2]) - # Adjust the layout to make space for the footnote - plt.subplots_adjust(bottom=0.85) # Adjust the bottom margin - # Add footnote - fig.figure.text(0.45, 0.88, - "proportion = number of wasted children in the age group " - "/ total number of children in the age group", - ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) - plt.tight_layout() - fig_output_name = ('wasting_prevalence_per_each_age_group__' + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name) - # plt.show() + age_groups = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] + columns = [f'mod__{age}' for age in age_groups] + [f'sev__{age}' for age in age_groups] + # data in percent (0% to 100%) + data = { + 2010: { + 'wasted_calib': [7.0, 13.0, 12.7, 2.4, 2.7, 1.9, 0.0], + 'sev_wast_calib': [2.1, 7.1, 4.7, 0.9, 0.7, 0.6, 0.0] + }, + 2014: { + 'wasted_calib': [5.8, 5.8, 5.4, 3.9, 2.2, 2.0, 0.0], + 'sev_wast_calib': [2.6, 2.5, 1.1, 0.8, 0.7, 0.3, 0.0] + }, + 2016: { + 'wasted_calib': [3.7, 7.7, 6.5, 2.2, 1.9, 2.6, 0.0], + 'sev_wast_calib': [1.1, 1.0, 0.7, 1.0, 0.1, 0.5, 0.0] + }, + 2020: { + 'wasted_calib': [2.5, 2.6, 9.1, 2.0, 1.8, 1.8, 0.0], + 'sev_wast_calib': [1.0, 1.0, 2.7, 0.8, 0.2, 0.3, 0.0] + } + } + # recalculate data to proportions (0 to 1) and separate mod wast as (wasted - sev wast) + for year in data: + data[year]['mod_wast_calib'] = \ + [(w - s)/100 for w, s in zip(data[year]['wasted_calib'], data[year]['sev_wast_calib'])] + data[year]['sev_wast_calib'] = \ + [s/100 for s in data[year]['sev_wast_calib']] + data_list = [] + for year in data: + values = data[year]['mod_wast_calib'] + data[year]['sev_wast_calib'] + data_list.append(values) + w_prev_calib_data_df = pd.DataFrame(data_list, columns=columns, index=data.keys()) + + w_prev_model_df = self.__w_logs_dict["wasting_prevalence_props"] + w_prev_model_df = w_prev_model_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) + w_prev_model_df = w_prev_model_df.set_index(w_prev_model_df.date.dt.year) + w_prev_model_df = w_prev_model_df.drop(columns='date') + + for year_calib in w_prev_calib_data_df.index: + w_prev_calib_data_year_df = w_prev_calib_data_df.loc[w_prev_calib_data_df.index == year_calib] + w_prev_model_year_df = w_prev_model_df.loc[w_prev_model_df.index == year_calib] + order_x_axis = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] + + def create_plotting_data(df, df_name): + plotting = {'severe wasting': {}, 'moderate wasting': {}} + for col in df.columns: + prefix, age_group = col.split('__') + if prefix == 'sev': + plotting['severe wasting'][age_group] = df[col].values[0] + elif prefix == 'mod': + plotting['moderate wasting'][age_group] = df[col].values[0] + plotting_df = pd.DataFrame(plotting) + assert set(plotting_df.index) == set( + order_x_axis), f"age groups in {w_prev_calib_data_year_df} are not in line with the order_x_axis." + plotting_df = plotting_df.reindex(order_x_axis) + return plotting_df + + # Create plotting data for both dataframes + plotting_model = create_plotting_data(w_prev_model_year_df, 'w_prev_model_year_df') + plotting_calib = create_plotting_data(w_prev_calib_data_year_df, 'w_prev_calib_data_year_df') + + # Plot wasting prevalence + fig, ax = plt.subplots(figsize=(10, 6)) + bar_width = 0.35 + # Set positions of bars on x-axis + r1 = range(len(plotting_model)) + r2 = [x + bar_width for x in r1] + + # Plot the first set of bars (model data) + ax.bar(r1, plotting_model['severe wasting'], + color=self.__colors_model['severe wasting'], width=bar_width, + label='severe wasting (model)') + ax.bar(r1, plotting_model['moderate wasting'], bottom=plotting_model['severe wasting'], + color=self.__colors_model['moderate wasting'], width=bar_width, + label='moderate wasting (model)') + + # Plot the second set of bars (calibration data) + ax.bar(r2, plotting_calib['severe wasting'], + color=self.__colors_data['severe wasting'], width=bar_width, + label='severe wasting (data)') + ax.bar(r2, plotting_calib['moderate wasting'], bottom=plotting_calib['severe wasting'], + color=self.__colors_data['moderate wasting'], width=bar_width, + label='moderate wasting (data)') + + ax.set_xlabel('age group') + ax.set_ylabel('proportion') + ax.set_title(f"Wasting prevalence in children 0-59 months per each age group in {year_calib}") + ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) + ax.set_xticklabels(order_x_axis) + ax.set_ylim([0, 0.14]) + ax.legend() + + # Adjust the layout to make space for the footnote + plt.subplots_adjust(top=0.15) # Adjust the bottom margin + # Add footnote + fig.figure.text(0.43, 0.95, + "proportion = number of wasted children in the age group " + "/ total number of children in the age group", + ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) + + plt.tight_layout() + fig_output_name = (f'wasting_prevalence_per_each_age_group_{year_calib}__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) + # plt.show() def plot_wasting_initial_prevalence_by_age_group(self): """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of @@ -390,12 +460,12 @@ def plot_wasting_initial_prevalence_by_age_group(self): ax=ax, ylabel='proportion', xlabel='age group', - ylim=[0, 0.2]) + ylim=[0, 0.14]) ax.set_title(r"Wasting prevalence in children 0-59 months per each age group $\bf{at}$ $\bf{initiation}$") # Adjust the layout to make space for the footnote - plt.subplots_adjust(bottom=0.85) # Adjust the bottom margin + plt.subplots_adjust(top=0.35) # Adjust the bottom margin # Add footnote - fig.figure.text(0.45, 0.88, + fig.figure.text(0.44, 0.9, "proportion = number of wasted children in the age group " "/ total number of children in the age group", ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) @@ -481,12 +551,12 @@ def plot_all_figs_in_one_pdf(self): # plot wasting prevalence wasting_analyses.plot_wasting_prevalence_per_year() - # plot wasting prevalence by age group - wasting_analyses.plot_wasting_prevalence_by_age_group() - # plot wasting initial prevalence by age group wasting_analyses.plot_wasting_initial_prevalence_by_age_group() + # plot wasting prevalence by age group + wasting_analyses.plot_wasting_prevalence_by_age_group() + # plot wasting deaths by gender as compared to GBD deaths wasting_analyses.plot_modal_gbd_deaths_by_gender() From 6cb98e1201efc50bd2c09cfa7fc51efbb41b6243 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 8 Jan 2025 14:55:24 +0100 Subject: [PATCH 220/755] RF_Wast & wast: progression_severe_wasting_by_agegp to set as monthly and adjust to duration of mod. wast. in the code --- resources/ResourceFile_Wasting.csv | 4 ++-- src/tlo/methods/wasting.py | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 542aed82ea..988d3089d1 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d38c4896c1fa05ad59e43b4af45be04413e1b9257aef45da3e8bddc00c35c4e0 -size 3494 +oid sha256:ad157ca93f7f0589f9a5d74eda43e54c31aa5454d5f9843cc664c436d655ab8a +size 3536 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 3f3771219b..f975ef0ef5 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -106,7 +106,7 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.REAL, 'duration of untreated moderate wasting (days)'), 'duration_of_untreated_sev_wasting': Parameter( Types.REAL, 'duration of untreated severe wasting (days)'), - 'progression_severe_wasting_by_agegp': Parameter( + 'progression_severe_wasting_monthly_by_agegp': Parameter( Types.LIST, 'list with progression rates to severe wasting by age group'), 'prob_complications_in_SAM': Parameter( Types.REAL, 'probability of medical complications in SAM '), @@ -255,6 +255,10 @@ def read_parameters(self, data_folder): odds_ratio_health_seeking_in_children=20.0, ) ) + # Adjust monthly severe wasting incidence to the duration of untreated moderate wasting + p = self.parameters + p['progression_severe_wasting_by_agegp'] = \ + [s/30*p['duration_of_untreated_mod_wasting'] for s in p['progression_severe_wasting_monthly_by_agegp']] def initialise_population(self, population): """ From 03831685e824f5c3b5082899b08633485e3517ee Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 8 Jan 2025 18:37:09 +0000 Subject: [PATCH 221/755] scenario_wast_min_model: fix bug from rebase --- .../scenarios/scenario_wasting_minimal_model.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 674af91dc8..0830b4b73c 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -61,9 +61,6 @@ def log_configuration(self): def modules(self): return [demography.Demography(resourcefilepath=self.resources), healthsystem.HealthSystem(resourcefilepath=self.resources, - service_availability=['*'], use_funded_or_actual_staffing='actual', - mode_appt_constraints=1, - cons_availability='all', beds_availability='all', service_availability=['*'], use_funded_or_actual_staffing='actual', mode_appt_constraints=1, cons_availability='default', beds_availability='default', From c33a951a334494b272277eb5022dd40d30ebf7e6 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 9 Jan 2025 18:05:55 +0000 Subject: [PATCH 222/755] test_wast: update death rate settings for untreated SAM *Split into `base_death_rate_untreated_SAM` and `rr_death_rate_by_agegp`; *Fix test by setting the death rate before population initialisation --- tests/test_wasting.py | 78 ++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index d99671d01b..55fdda7122 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -369,8 +369,9 @@ def test_recovery_severe_acute_malnutrition_without_complications(tmpdir): # get wasting module wmodule = sim.modules['Wasting'] - # set death due to untreated SAM at 100%, hence no natural recovery from severe wasting - wmodule.parameters['death_rate_untreated_SAM_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] + # set death due to untreated SAM at 100% for all, hence no natural recovery from severe wasting + wmodule.parameters['base_death_rate_untreated_SAM'] = 1.0 + wmodule.parameters['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) @@ -434,6 +435,16 @@ def test_recovery_severe_acute_malnutrition_without_complications(tmpdir): assert person['un_WHZ_category'] == 'WHZ<-3' assert person['un_clinical_acute_malnutrition'] == 'SAM' + # Check death is scheduled + assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_SevereAcuteMalnutritionDeath_Event) + assert not pd.isnull(person['un_sam_death_date']) + # get date of death and death event + death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], Wasting_SevereAcuteMalnutritionDeath_Event)][0] + date_of_scheduled_death = death_event_tuple[0] + death_event = death_event_tuple[1] + assert date_of_scheduled_death > sim.date + hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) hsp.run() @@ -459,16 +470,8 @@ def test_recovery_severe_acute_malnutrition_without_complications(tmpdir): isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] sam_ev.run(squeeze_factor=0.0) - # Check death is scheduled, but was canceled with tx - person = df.loc[person_id] - assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_SevereAcuteMalnutritionDeath_Event) - assert pd.isnull(person['un_sam_death_date']) - # get date of death and death event - death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], Wasting_SevereAcuteMalnutritionDeath_Event)][0] - date_of_scheduled_death = death_event_tuple[0] - death_event = death_event_tuple[1] - assert date_of_scheduled_death > sim.date + # Check death was canceled with tx + assert pd.isnull(df.loc[person_id]['un_sam_death_date']) # Check recovery to MAM due to tx is scheduled assert isinstance(sim.find_events_for_person(person_id)[2][1], Wasting_UpdateToMAM_Event) @@ -505,6 +508,13 @@ def test_recovery_severe_acute_malnutrition_with_complications(tmpdir): popsize = 1000 sim = get_sim(tmpdir) + # get wasting module + wmodule = sim.modules['Wasting'] + + # set death due to untreated SAM at 100% for all, hence no natural recovery from severe wasting + wmodule.parameters['base_death_rate_untreated_SAM'] = 1.0 + wmodule.parameters['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] + sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) sim.event_queue.queue = [] # clear the queue @@ -514,35 +524,32 @@ def test_recovery_severe_acute_malnutrition_with_complications(tmpdir): under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] - # get wasting module - wmodule = sim.modules['Wasting'] - - # set death due to untreated SAM at 100%, hence no natural recovery from severe wasting - wmodule.parameters['death_rate_untreated_SAM_by_agegp'] = [1.0, 1.0, 1.0, 1.0, 1.0, 1.0] - - # Manually set this individual properties to have - # severe acute malnutrition with complications + # Manually set this individual properties to have severe acute malnutrition df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' - # ensure the individual has complications due to SAM wmodule.parameters['prob_complications_in_SAM'] = 1.0 - # assign diagnosis wmodule.clinical_acute_malnutrition_state(person_id, df) # by having severe wasting, this individual should be diagnosed as SAM assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' - + # should have complications + assert df.at[person_id, 'un_sam_with_complications'] # symptoms should be applied assert person_id in set(sim.modules['SymptomManager'].who_has('weight_loss')) - # should have complications - assert df.at[person_id, 'un_sam_with_complications'] + # Check death is scheduled + assert isinstance(sim.find_events_for_person(person_id)[0][1], Wasting_SevereAcuteMalnutritionDeath_Event) + assert not pd.isnull(df.loc[person_id]['un_sam_death_date']) + # get date of death and death event + death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], Wasting_SevereAcuteMalnutritionDeath_Event)][0] + date_of_scheduled_death = death_event_tuple[0] + death_event = death_event_tuple[1] + assert date_of_scheduled_death > sim.date - # make full recovery rate to 100% and death rate to zero so that - # this individual should recover + # make full recovery rate to 100% so that this individual should fully recover with tx wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel.multiplicative() - wmodule.parameters['prob_death_after_SAMcare'] = 0.0 # run care seeking event and ensure HSI for complicated SAM is scheduled hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) @@ -572,14 +579,7 @@ def test_recovery_severe_acute_malnutrition_with_complications(tmpdir): # Check death is scheduled, but was canceled due to tx person = df.loc[person_id] - print(f"{sim.find_events_for_person(person_id)=}") - assert isinstance(sim.find_events_for_person(person_id)[0][1], Wasting_SevereAcuteMalnutritionDeath_Event) assert pd.isnull(person['un_sam_death_date']) - # get date of death and death event - death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], Wasting_SevereAcuteMalnutritionDeath_Event)][0] - date_of_scheduled_death = death_event_tuple[0] - death_event = death_event_tuple[1] # Check full recovery due to tx is scheduled assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_ClinicalAcuteMalnutritionRecovery_Event) @@ -601,11 +601,12 @@ def test_recovery_severe_acute_malnutrition_with_complications(tmpdir): sim.date = date_of_scheduled_death death_event.apply(person_id) - # Check properties of this individual. Should now be well + # Check properties of this individual. Should now be well and alive person = df.loc[person_id] assert person['un_WHZ_category'] == 'WHZ>=-2' assert (person['un_am_MUAC_category'] == '>=125mm') assert pd.isnull(person['un_sam_death_date']) + assert person['is_alive'] # check they have no symptoms: assert 0 == len(sim.modules['SymptomManager'].has_what(person_id=person_id, disease_module=sim.modules['Wasting'])) @@ -775,8 +776,9 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): # get wasting module wmodule = sim.modules['Wasting'] - # set death due to untreated SAM at 0%, hence always scheduled natural recovery from severe wasting - wmodule.parameters['death_rate_untreated_SAM_by_agegp'] = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + # set death due to untreated SAM at 0% for all, hence always scheduled natural recovery from severe wasting + wmodule.parameters['base_death_rate_untreated_SAM'] = 0.0 + wmodule.parameters['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) From 037b303ab696524fcb4dcaf1ae6df37b05583c53 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 9 Jan 2025 18:13:25 +0000 Subject: [PATCH 223/755] scenario_wast_min_model: 4 draws (base_death_rate_untreated_SAM: [0.05, 0.1, 0.15, 0.2]) --- .../scenarios/scenario_wasting_minimal_model.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 0830b4b73c..0084419b73 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=30_000, - number_of_draws=1, + number_of_draws=4, runs_per_draw=1, ) @@ -80,7 +80,12 @@ def modules(self): def draw_parameters(self, draw_number, rng): # Using default parameters in all cases - return {} + base_death_rate_untreated_SAM__draws = [0.05, 0.1, 0.15, 0.2] + return { + 'Wasting': { + 'base_death_rate_untreated_SAM': base_death_rate_untreated_SAM__draws[draw_number] + } + } if __name__ == '__main__': From 97089712eff414704332916b8cf00e8d3b6cd5e9 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 9 Jan 2025 18:20:11 +0000 Subject: [PATCH 224/755] scenario_wast_min_model: 4K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 0084419b73..ba82c4c74a 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -41,7 +41,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + initial_population_size=4_000, number_of_draws=4, runs_per_draw=1, ) From 9ce9cffeebfc41bfecb73c6a84b3807041a8a401 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 9 Jan 2025 18:32:24 +0000 Subject: [PATCH 225/755] scenario_wast_min_model: 30K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index ba82c4c74a..0084419b73 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -41,7 +41,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=4, runs_per_draw=1, ) From 79aac312c37430fb935fee9f7df654682226fe11 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 9 Jan 2025 19:34:18 +0000 Subject: [PATCH 226/755] analysis_wast: incidence as proportion within age grp --- .../wasting_analyses/analysis_wasting.py | 34 ++++++++++++++----- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index aa41ee49ae..4a9b29f5eb 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -106,11 +106,27 @@ def plot_wasting_incidence(self): all_zeros = w_inc_df['WHZ>=-2'].apply(lambda x: all(value == 0 for value in x.values())) assert all(all_zeros) w_inc_df = w_inc_df[["WHZ<-3", "-3<=WHZ<-2"]] + + pop_sizes_df = self.__w_logs_dict['pop sizes'] + pop_sizes_df = pop_sizes_df.set_index(pop_sizes_df.date.dt.year) + pop_sizes_df = pop_sizes_df.drop(columns='date') + po_sizes_to_keep = [col for col in pop_sizes_df.columns if + col.startswith('total__') and col not in ['total__under5']] + age_gps_total_pop_sizes_df = pop_sizes_df[po_sizes_to_keep].copy() + age_gps_total_pop_sizes_df['0y'] = \ + age_gps_total_pop_sizes_df['total__0_5mo'] + age_gps_total_pop_sizes_df['total__6_11mo'] + age_gps_total_pop_sizes_df = age_gps_total_pop_sizes_df.drop(columns=['total__0_5mo', 'total__6_11mo']) + age_gps_total_pop_sizes_df = age_gps_total_pop_sizes_df.rename(columns={ + 'total__12_23mo': '1y', + 'total__24_35mo': '2y', + 'total__36_47mo': '3y', + 'total__48_59mo': '4y', + 'total__5y+': '5+y' + }) + # get age_years, doesn't matter what wasting category you choose, # they all have same age groups - age_years = list(w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys( - - )) + age_years = list(w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys()) # age_years.remove('5+y') _row_counter = 0 @@ -118,20 +134,20 @@ def plot_wasting_incidence(self): # plot setup fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 6)) axes[1, 2].axis('off') # 5+y has no data (no new cases in 5+y), its space is used to display the label - for _age in age_years: + for age in age_years: plotting = pd.DataFrame() for state in w_inc_df.columns: plotting[state] = \ - w_inc_df.apply(lambda row: row[state][_age], axis=1) + w_inc_df.apply(lambda row: row[state][age], axis=1) # remove sev cases from mod cases (all sev cases went through mod state) plotting["-3<=WHZ<-2"] = plotting["-3<=WHZ<-2"] - plotting["WHZ<-3"] - # rescale nmbs from simulated pop_size to pop size of Malawi - plotting = plotting * self.__scaling_factor + # calculate props within the age group + plotting = plotting.div(age_gps_total_pop_sizes_df[age], axis=0) plotting = plotting.rename(columns=self.__wasting_types_desc) ax = plotting.plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], - title=f"incidence of wasting in {_age} old")#, + title=f"incidence of wasting in {age} old")#, #ylim=[0, 1]) show_legend = (_row_counter == 1 and _col_counter == 2) # show_x_axis_label = (_row_counter == 0 and _col_counter == 2) @@ -143,7 +159,7 @@ def plot_wasting_incidence(self): # if show_x_axis_label: # ax.set_xlabel('Year') # TODO: this is not working ax.set_xlabel('year') - ax.set_ylabel('number of incidence cases') + ax.set_ylabel('proportion (within age group)') # move to another row if _col_counter == 2: _row_counter += 1 From 67f560d57d423e720606648b9063e98186a5c8cb Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 9 Jan 2025 23:40:56 +0000 Subject: [PATCH 227/755] RF_Wast, test_wast, & wast: rm prob_mam_after_SAMcare, use 1-prob_death_after_SAMcare --- resources/ResourceFile_Wasting.csv | 4 ++-- src/tlo/methods/wasting.py | 9 +++++---- tests/test_wasting.py | 14 +++++--------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 988d3089d1..617a1b4269 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad157ca93f7f0589f9a5d74eda43e54c31aa5454d5f9843cc664c436d655ab8a -size 3536 +oid sha256:366dffc3dd0f4fa959cc4427d21a6a52c47b4149a882a86c9acff17808133c8a +size 3474 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index f975ef0ef5..79d460d54c 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -171,8 +171,6 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.REAL, 'number of weeks the patient receives treatment in the Inpatient Care for complicated' ' SAM before being discharged if they do not die beforehand'), # treatment/intervention outcomes - 'prob_mam_after_SAMcare': Parameter( - Types.REAL, 'probability of returning to MAM from SAM after receiving care'), 'prob_death_after_SAMcare': Parameter( Types.REAL, 'probability of dying from SAM after receiving care'), } @@ -748,8 +746,11 @@ def do_when_am_treatment(self, person_id, intervention): ) else: - outcome = self.rng.choice(['recovery_to_mam', 'death'], p=[self.parameters['prob_mam_after_SAMcare'], - self.parameters['prob_death_after_SAMcare']]) + outcome = self.rng.choice(['recovery_to_mam', 'death'], + p=[ + 1-self.parameters['prob_death_after_SAMcare'], + self.parameters['prob_death_after_SAMcare'] + ]) if outcome == 'death': self.sim.schedule_event( event=Wasting_SevereAcuteMalnutritionDeath_Event(module=self, person_id=person_id), diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 55fdda7122..0a82b11464 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -401,9 +401,8 @@ def test_recovery_severe_acute_malnutrition_without_complications(tmpdir): # set complete recovery from wasting to zero. We want those with SAM to recover to MAM with tx wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) - # set prob of death after tx at 0% and recovery to MAM at 100% + # set prob of death after tx at 0% (hence recovery to MAM at 100%) wmodule.parameters['prob_death_after_SAMcare'] = 0.0 - wmodule.parameters['prob_mam_after_SAMcare'] = 1.0 # Run Wasting Polling event to get new incident cases: polling = Wasting_IncidencePoll(module=sim.modules['Wasting']) @@ -626,9 +625,8 @@ def test_nat_hist_death(tmpdir): # get wasting module wmodule = sim.modules['Wasting'] - # Set death rate at 100% + # Set death rate with tx at 100% wmodule.parameters['prob_death_after_SAMcare'] = 1.0 - wmodule.parameters['prob_mam_after_SAMcare'] = 0.0 # make zero recovery rate. reset recovery linear model wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) @@ -709,9 +707,8 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): sim.event_queue.queue = [] # clear the queue wmodule = sim.modules['Wasting'] - # Make 0% death rate by replacing with empty linear model 0.0 + # set prob of death after tx at 0% (hence recovery to MAM at 100%) wmodule.parameters['prob_death_after_SAMcare'] = 0.0 - wmodule.parameters['prob_mam_after_SAMcare'] = 1.0 # increase wasting incidence rate to 100% and reduce rate of progress to severe wasting to zero. We don't want # individuals to progress to SAM as we are testing for MAM natural recovery @@ -784,12 +781,11 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): sim.simulate(end_date=start_date + dur) sim.event_queue.queue = [] # clear the queue - # increase to 100% wasting incidence, progress to severe wasting, and death rate after SAM care; - # set full recovery ad recovery to MAM with SAM care at 0% + # increase to 100% wasting incidence, progress to severe wasting, and death rate after SAM care, + # set full recovery with SAM care at 0% (and as 100% death rate after SAM care, no recovery to MAM) wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() wmodule.wasting_models.severe_wasting_progression_lm = LinearModel.multiplicative() wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) - wmodule.parameters['prob_mam_after_SAMcare'] = 0.0 wmodule.parameters['prob_death_after_SAMcare'] = 1.0 # Get person to use: From 47d0552bca7ae20e871d93aa46e319a6b80ac7c9 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 9 Jan 2025 23:45:56 +0000 Subject: [PATCH 228/755] RF_Wast: base_death_rate_untreated_SAM set to 0.01 --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 617a1b4269..fd80130b3f 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:366dffc3dd0f4fa959cc4427d21a6a52c47b4149a882a86c9acff17808133c8a -size 3474 +oid sha256:c3237524d30b4e7b840277b47d2b1a8c195446fb311b9e5483abe58ac34a162d +size 3475 From c445393d1ef81a6014a6021a155cb89222893e5b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 9 Jan 2025 23:47:13 +0000 Subject: [PATCH 229/755] analysis_wast: analyse mutliple draws; add running time prints --- .../wasting_analyses/analysis_wasting.py | 106 ++++++++++-------- 1 file changed, 62 insertions(+), 44 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 4a9b29f5eb..f1dcb3febc 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -16,8 +16,8 @@ from tlo.analysis.utils import compare_number_of_deaths, get_scenario_outputs, parse_log_file -# start time of the analysis -time_start = time.time() +# start time of the whole analysis +total_time_start = time.time() # ####### TO SET ####################################################################################################### scenario_filename = 'wasting_analysis__minimal_model' @@ -30,43 +30,30 @@ class WastingAnalyses: This class looks at plotting all important outputs from the wasting module """ - def __init__(self, in_scenario_filename, in_outputs_path): - - # Find sim_results_folder associated with a given batch_file (and get most recent [-1]) - sim_results_folder = get_scenario_outputs(in_scenario_filename, in_outputs_path)[-1] - sim_results_parent_folder_name = str(sim_results_folder.parent) - sim_results_folder_name = sim_results_folder.name - self.outcomes_path_name = str(in_outputs_path) + "/" + sim_results_folder_name - # Get the datestamp - if sim_results_folder_name.startswith(scenario_filename + '-'): - self.datestamp = sim_results_folder_name[(len(scenario_filename)+1):] - else: - print("The scenario output name does not correspond with the set scenario_filename.") - - # Path to the .log.gz file - sim_results_folder_path_run0_draw0 = sim_results_parent_folder_name + '/' + sim_results_folder_name + '/0/0/' + def __init__(self, in_sim_results_folder_path_draw_x_run_0, in_datestamp): + self.outcomes_path_name = in_sim_results_folder_path_draw_x_run_0 + self.datestamp = in_datestamp sim_results_file_name_prefix = scenario_filename sim_results_file_name_extension = '.log.gz' gz_results_file_path = \ - Path(glob.glob(os.path.join(sim_results_folder_path_run0_draw0, + Path(glob.glob(os.path.join(sim_results_folder_path_draw_x_run_0, f"{sim_results_file_name_prefix}*{sim_results_file_name_extension}"))[0]) # Path to the decompressed .log file - log_results_file_path = gz_results_file_path.with_suffix('') - + self.__log_file_path = gz_results_file_path.with_suffix('') # Decompress the .log.gz file with gzip.open(gz_results_file_path, 'rb') as f_in: - with open(log_results_file_path, 'wb') as f_out: + with open(self.__log_file_path, 'wb') as f_out: shutil.copyfileobj(f_in, f_out) - self.__log_file_path = log_results_file_path # parse wasting logs self.__w_logs_dict = parse_log_file(self.__log_file_path)['tlo.methods.wasting'] + # TODO: Why it prints the messages from parse_log_file() twice? # parse scaling factor log - self.__scaling_factor = \ - parse_log_file(self.__log_file_path)['tlo.methods.population']['scaling_factor'].set_index('date').loc[ - '2010-01-01', 'scaling_factor' - ] + # self.__scaling_factor = \ + # parse_log_file(self.__log_file_path)['tlo.methods.population']['scaling_factor'].set_index('date').loc[ + # '2010-01-01', 'scaling_factor' + # ] # gender description self.__gender_desc = {'M': 'Males', @@ -552,29 +539,60 @@ def plot_all_figs_in_one_pdf(self): # Path to the resource files used by the disease and intervention methods resources_path = Path("./resources") - # initialise the wasting class - wasting_analyses = WastingAnalyses(scenario_filename, outputs_path) + # Find sim_results_folder associated with a given batch_file (and get most recent [-1]) + sim_results_folder = get_scenario_outputs(scenario_filename, outputs_path)[-1] + sim_results_parent_folder_name = str(sim_results_folder.parent) + sim_results_folder_name = sim_results_folder.name + # Get the datestamp + assert sim_results_folder_name.startswith(scenario_filename + '-'),\ + "The scenario output name does not correspond with the set scenario_filename." + datestamp = sim_results_folder_name[(len(scenario_filename) + 1):] + + # Path to the results folder + sim_results_folder_path = sim_results_parent_folder_name + '/' + sim_results_folder_name + print(f"{sim_results_folder_path=}") + folders = [name for name in os.listdir(sim_results_folder_path) if \ + os.path.isdir(os.path.join(sim_results_folder_path, name))] + + # Analyse each draw + for draw_nmb in range(len(folders)): + print(f"Analysing {draw_nmb=} ...") + time_start = time.time() + # Path to the draw folder + sim_results_folder_path_draw_x_run_0 = \ + sim_results_parent_folder_name + '/' + sim_results_folder_name + f'/{draw_nmb}/0/' + + # initialise the wasting class + wasting_analyses = WastingAnalyses(sim_results_folder_path_draw_x_run_0, datestamp) + + # plot wasting incidence + wasting_analyses.plot_wasting_incidence() + + # plot wasting incidence mod:sev proportions + # wasting_analyses.plot_wasting_incidence_mod_to_sev_props() + + # plot wasting length + wasting_analyses.plot_wasting_length() + + # plot wasting prevalence + wasting_analyses.plot_wasting_prevalence_per_year() - # plot wasting incidence - wasting_analyses.plot_wasting_incidence() + # plot wasting initial prevalence by age group + wasting_analyses.plot_wasting_initial_prevalence_by_age_group() - # plot wasting incidence mod:sev proportions - # wasting_analyses.plot_wasting_incidence_mod_to_sev_props() + # plot wasting prevalence by age group + wasting_analyses.plot_wasting_prevalence_by_age_group() - # plot wasting length - wasting_analyses.plot_wasting_length() + # plot wasting deaths by gender as compared to GBD deaths + wasting_analyses.plot_modal_gbd_deaths_by_gender() - # plot wasting prevalence - wasting_analyses.plot_wasting_prevalence_per_year() + # save all figures in one pdf + wasting_analyses.plot_all_figs_in_one_pdf() - # plot wasting initial prevalence by age group - wasting_analyses.plot_wasting_initial_prevalence_by_age_group() + time_end = time.time() + print(f"... finished in (s): {(time_end - time_start)}") - # plot wasting prevalence by age group - wasting_analyses.plot_wasting_prevalence_by_age_group() + total_time_end = time.time() + print(f"total running time (s): {(total_time_end - total_time_start)}") - # plot wasting deaths by gender as compared to GBD deaths - wasting_analyses.plot_modal_gbd_deaths_by_gender() - # save all figures in one pdf - wasting_analyses.plot_all_figs_in_one_pdf() From 3596b70fa138c2f5c99246a5bf0e3193018e8293 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 10 Jan 2025 00:57:59 +0000 Subject: [PATCH 230/755] scenario_wast_min_model: multiple draws - death rates with(out) tx, mod & sev incidences --- .../scenario_wasting_minimal_model.py | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 0084419b73..d5201b39a9 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -9,6 +9,7 @@ tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py """ +import itertools import warnings from tlo import Date, logging @@ -42,7 +43,7 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=30_000, - number_of_draws=4, + number_of_draws=5*5*5*4, runs_per_draw=1, ) @@ -80,10 +81,29 @@ def modules(self): def draw_parameters(self, draw_number, rng): # Using default parameters in all cases - base_death_rate_untreated_SAM__draws = [0.05, 0.1, 0.15, 0.2] + base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] + mod_wast_incidence__coef = [1, 5, 10, 15, 20] + base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] + progression_to_sev_wast__coef = [1, 5, 10, 15, 20] + progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] + + pars_combinations = list(itertools.product( + base_death_rate_untreated_sam__draws, + mod_wast_incidence__coef, + progression_to_sev_wast__coef, + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam + )) return { 'Wasting': { - 'base_death_rate_untreated_SAM': base_death_rate_untreated_SAM__draws[draw_number] + 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], + 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ + s in base_inc_rate_wasting_props_by_agegp], + 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ + s in progression_severe_wasting_monthly_props_by_agegp], + 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam[3]) / + (1-0.738)) } } From ccd5bb799a46386f27a4d911c6b7d436ed3c39e0 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 10 Jan 2025 00:59:14 +0000 Subject: [PATCH 231/755] RF_Wast: minor (par description updated) --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index fd80130b3f..9def25001a 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c3237524d30b4e7b840277b47d2b1a8c195446fb311b9e5483abe58ac34a162d -size 3475 +oid sha256:2bc5311c1e0f549f669044f4cba992a310dd5792170bdb1e545d4aa3193610eb +size 3524 From 90ea4740152acdbad5e0745eb279232cb0fdaf80 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 10 Jan 2025 20:58:42 +0000 Subject: [PATCH 232/755] scenario_wast_min_model: test_run for Myriad - 4Kpop, 1 draw --- .../scenario_wasting_minimal_model.py | 57 ++++++++++--------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index d5201b39a9..ab8501c886 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,8 +42,8 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, - number_of_draws=5*5*5*4, + initial_population_size=4_000, + number_of_draws=1, runs_per_draw=1, ) @@ -81,31 +81,34 @@ def modules(self): def draw_parameters(self, draw_number, rng): # Using default parameters in all cases - base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] - mod_wast_incidence__coef = [1, 5, 10, 15, 20] - base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] - progression_to_sev_wast__coef = [1, 5, 10, 15, 20] - progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] - - pars_combinations = list(itertools.product( - base_death_rate_untreated_sam__draws, - mod_wast_incidence__coef, - progression_to_sev_wast__coef, - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam - )) - return { - 'Wasting': { - 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], - 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ - s in base_inc_rate_wasting_props_by_agegp], - 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ - s in progression_severe_wasting_monthly_props_by_agegp], - 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam[3]) / - (1-0.738)) - } - } + return {} + + # def draw_parameters(self, draw_number, rng): + # base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] + # mod_wast_incidence__coef = [1, 5, 10, 15, 20] + # base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] + # progression_to_sev_wast__coef = [1, 5, 10, 15, 20] + # progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] + # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] + # + # pars_combinations = list(itertools.product( + # base_death_rate_untreated_sam__draws, + # mod_wast_incidence__coef, + # progression_to_sev_wast__coef, + # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam + # )) + # return { + # 'Wasting': { + # 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], + # 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ + # s in base_inc_rate_wasting_props_by_agegp], + # 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ + # s in progression_severe_wasting_monthly_props_by_agegp], + # 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * + # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam[3]) / + # (1-0.738)) + # } + # } if __name__ == '__main__': From 58e8dc1fdb712a6c30d2c89844095f5d784f5280 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 11 Jan 2025 22:29:32 +0000 Subject: [PATCH 233/755] RF_Wast: mod & sev incidence - back to Emmanuel's values; death w\out tx updated to be closer to original but a bit lower --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 9def25001a..225463d864 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2bc5311c1e0f549f669044f4cba992a310dd5792170bdb1e545d4aa3193610eb -size 3524 +oid sha256:76d261eae1759a64cdf80e3af4aa82900048759462775da599e070e357b9f9d7 +size 3608 From 8d38d94c89ebcd9b322e38d987710499196f8ed5 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 11 Jan 2025 22:38:26 +0000 Subject: [PATCH 234/755] scenario_wast_min_model: 30K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index ab8501c886..afc46ff07f 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=1, runs_per_draw=1, ) From 1347af18f68823f2ddc8290543ccd9bc962d9ee3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 11 Jan 2025 22:43:44 +0000 Subject: [PATCH 235/755] analysis_wast: analyse all draws --- .../wasting_analyses/analysis_wasting.py | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index f1dcb3febc..cee335f6e4 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -30,9 +30,14 @@ class WastingAnalyses: This class looks at plotting all important outputs from the wasting module """ - def __init__(self, in_sim_results_folder_path_draw_x_run_0, in_datestamp): - self.outcomes_path_name = in_sim_results_folder_path_draw_x_run_0 + def __init__(self, in_sim_results_folder_path, in_datestamp, in_draw_nmb, in_run_nmb,in_png=False): + self.outcomes_folder_path = in_sim_results_folder_path self.datestamp = in_datestamp + self.draw_nmb = in_draw_nmb + self.run_nmb = in_run_nmb + self.png = in_png, """bool indicating whether we want to save all figures not only as pdf, but also as png""" + + sim_results_folder_path_draw_x_run_0 = in_sim_results_folder_path + f'/{draw_nmb}/{run_nmb}/' sim_results_file_name_prefix = scenario_filename sim_results_file_name_extension = '.log.gz' gz_results_file_path = \ @@ -80,9 +85,12 @@ def __init__(self, in_sim_results_folder_path_draw_x_run_0, in_datestamp): } def save_fig__store_pdf_file(self, fig, fig_output_name: str) -> None: - fig.savefig(self.outcomes_path_name + "/" + fig_output_name + '.png', format='png') - fig.savefig(self.outcomes_path_name + "/" + fig_output_name + '.pdf', format='pdf') - self.fig_files.append(fig_output_name + '.pdf') + full_path_and_file_name = self.outcomes_folder_path + f'/{self.draw_nmb}/{self.run_nmb}/' + fig_output_name + \ + f'_{self.draw_nmb}_{self.run_nmb}' + if self.png: #TODO: doesn't seem to be working + fig.savefig(full_path_and_file_name + '.png', format='png') + fig.savefig(full_path_and_file_name + '.pdf', format='pdf') + self.fig_files.append(full_path_and_file_name + '.pdf') def plot_wasting_incidence(self): """ plot the incidence of wasting over time """ @@ -510,7 +518,8 @@ def plot_modal_gbd_deaths_by_gender(self): def plot_all_figs_in_one_pdf(self): - output_file_path = Path(self.outcomes_path_name + '/wasting_all_figures__' + self.datestamp + '.pdf') + output_file_path = Path(self.outcomes_folder_path + '/wasting_all_figures__' + self.datestamp + + f'_{self.draw_nmb}_{self.run_nmb}' + '.pdf') # Remove the existing output file if it exists to ensure a clean start if os.path.exists(output_file_path): os.remove(output_file_path) @@ -524,7 +533,7 @@ def plot_all_figs_in_one_pdf(self): # Iterate through the figure files and add each to the writer for fig_file in self.fig_files: - pdf_reader = PdfReader(self.outcomes_path_name + "/" + fig_file) + pdf_reader = PdfReader(fig_file) for page_num in range(len(pdf_reader.pages)): page = pdf_reader.pages[page_num] pdf_writer.add_page(page) @@ -550,20 +559,18 @@ def plot_all_figs_in_one_pdf(self): # Path to the results folder sim_results_folder_path = sim_results_parent_folder_name + '/' + sim_results_folder_name - print(f"{sim_results_folder_path=}") folders = [name for name in os.listdir(sim_results_folder_path) if \ os.path.isdir(os.path.join(sim_results_folder_path, name))] # Analyse each draw + # for now, we always have just one run, run 0 + run_nmb = 0 for draw_nmb in range(len(folders)): print(f"Analysing {draw_nmb=} ...") time_start = time.time() - # Path to the draw folder - sim_results_folder_path_draw_x_run_0 = \ - sim_results_parent_folder_name + '/' + sim_results_folder_name + f'/{draw_nmb}/0/' # initialise the wasting class - wasting_analyses = WastingAnalyses(sim_results_folder_path_draw_x_run_0, datestamp) + wasting_analyses = WastingAnalyses(sim_results_folder_path, datestamp, draw_nmb, run_nmb) # plot wasting incidence wasting_analyses.plot_wasting_incidence() From d4c82f5fd3a9b717ddf6f6288fa3e9b1db4432fa Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 12 Jan 2025 14:03:23 +0000 Subject: [PATCH 236/755] scenario_Wast_min_model: end_date = 2. 1. 2012; 30K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index afc46ff07f..6c767c246b 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -41,7 +41,7 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2031, month=1, day=1), + end_date=Date(year=2012, month=1, day=2), initial_population_size=30_000, number_of_draws=1, runs_per_draw=1, From 74be8ed615b218952011519feb90477dc60806bb Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 12 Jan 2025 14:18:17 +0000 Subject: [PATCH 237/755] wast: warning instead of assert --- src/tlo/methods/wasting.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 79d460d54c..98228948f2 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -7,6 +7,7 @@ import numpy as np import pandas as pd +import warnings from scipy.stats import norm from tlo import DateOffset, Module, Parameter, Property, Types, logging @@ -1597,7 +1598,9 @@ def apply(self, population): else: length_df.loc[age_grp, recov_opt] = 0 assert not np.isnan(length_df.loc[age_grp, recov_opt]) - assert all(length > 0 for length in self.module.wasting_length_tracker[age_grp][recov_opt]) + if not all(length > 0 for length in self.module.wasting_length_tracker[age_grp][recov_opt]): + warnings.warn(f'{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains 0 length;' + f' {age_grp=}, {recov_opt=}') # Reset the tracker self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) From 327b8f394b3c8149d32a0b072c5901800d4f0d63 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 13 Jan 2025 19:03:23 +0000 Subject: [PATCH 238/755] wast: debug - warnings if not correct wasting length logged --- src/tlo/methods/wasting.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 98228948f2..06354f647d 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1598,9 +1598,18 @@ def apply(self, population): else: length_df.loc[age_grp, recov_opt] = 0 assert not np.isnan(length_df.loc[age_grp, recov_opt]) - if not all(length > 0 for length in self.module.wasting_length_tracker[age_grp][recov_opt]): - warnings.warn(f'{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains 0 length;' - f' {age_grp=}, {recov_opt=}') + if recov_opt == 'mod_nat_recov': + if not all(length >= 81 for length in self.module.wasting_length_tracker[age_grp][recov_opt]): + warnings.warn(f'{self.module.wasting_length_tracker[age_grp][recov_opt]=} ' + f'contains length < 3 weeks; {age_grp=}, {recov_opt=}') + elif recov_opt in ['mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', 'sev_SAM_tx_full_recov', + 'mod_SAM_tx_recov_to_MAM', 'sev_SAM_tx_recov_to_MAM']: + if not all(length >= 21 for length in self.module.wasting_length_tracker[age_grp][recov_opt]): + warnings.warn(f'{self.module.wasting_length_tracker[age_grp][recov_opt]=} ' + f'contains length < 3 weeks; {age_grp=}, {recov_opt=}') + else: + assert recov_opt in ['mod_not_yet_recovered', 'sev_not_yet_recovered'] + # Reset the tracker self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) From edcf9f2e5064f0b542d30211a17f657b6a75e71e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 13 Jan 2025 19:08:01 +0000 Subject: [PATCH 239/755] scenario_wast_min_model: 2010-2030(incl) sim --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 6c767c246b..afc46ff07f 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -41,7 +41,7 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2012, month=1, day=2), + end_date=Date(year=2031, month=1, day=1), initial_population_size=30_000, number_of_draws=1, runs_per_draw=1, From ddad6dd051992699a0e3ea4ddfe01c7a48c42afe Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 14 Jan 2025 10:32:39 +0000 Subject: [PATCH 240/755] scenario_wast_min_model: 1 year sim, 2K pop --- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index afc46ff07f..7bb52a7b37 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -41,8 +41,8 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + end_date=Date(year=2011, month=1, day=1), + initial_population_size=2_000, number_of_draws=1, runs_per_draw=1, ) From a4b124080533fbfe1e29363156d861c358a9058a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 14 Jan 2025 11:50:07 +0000 Subject: [PATCH 241/755] scenario_wast_min_model: 2010-2030(incl) sim; 30K pop --- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 7bb52a7b37..afc46ff07f 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -41,8 +41,8 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2011, month=1, day=1), - initial_population_size=2_000, + end_date=Date(year=2031, month=1, day=1), + initial_population_size=30_000, number_of_draws=1, runs_per_draw=1, ) From 37728590ca871b8faef72e98860bdbe65699e8c1 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 14 Jan 2025 16:32:36 +0000 Subject: [PATCH 242/755] wast: if dying but not having SAM warn before assert (show person_id and am state) --- src/tlo/methods/wasting.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 06354f647d..f9a095b358 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -901,6 +901,8 @@ def apply(self, person_id): not (df.at[person_id, 'un_am_discharge_date'] > df.at[person_id, 'un_am_tx_start_date']) and not pd.isnull(df.at[person_id, 'un_sam_death_date']) ): + if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': + warnings.warn(f"{person_id=},\n{df.at[person_id, 'un_clinical_acute_malnutrition']=}") assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' # Cause the death to happen immediately df.at[person_id, 'un_sam_death_date'] = self.sim.date From 598c8071ed2ddde91d7fe95c70a4847f1e780863 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 14 Jan 2025 10:32:39 +0000 Subject: [PATCH 243/755] scenario_wast_min_model: 1 year sim, 2K pop (2nd time) --- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index afc46ff07f..7bb52a7b37 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -41,8 +41,8 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + end_date=Date(year=2011, month=1, day=1), + initial_population_size=2_000, number_of_draws=1, runs_per_draw=1, ) From 214f15918de4c13db829aa362d78d822735029fe Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 15 Jan 2025 15:56:10 +0000 Subject: [PATCH 244/755] wast: warnings added before each assert --- src/tlo/methods/wasting.py | 45 +++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index f9a095b358..57da215a18 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -535,6 +535,9 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): person_id=person_id, disease_module=self ) + if ((df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') and + (df.at[person_id, 'un_sam_with_complications'])): + warnings.warn(f'{person_id=} has MAM with complications.') assert not ((df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') and (df.at[person_id, 'un_sam_with_complications'])) @@ -902,7 +905,7 @@ def apply(self, person_id): not pd.isnull(df.at[person_id, 'un_sam_death_date']) ): if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': - warnings.warn(f"{person_id=},\n{df.at[person_id, 'un_clinical_acute_malnutrition']=}") + warnings.warn(f"{person_id=} dying due to SAM while \n{df.at[person_id, 'un_clinical_acute_malnutrition']=}") assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' # Cause the death to happen immediately df.at[person_id, 'un_sam_death_date'] = self.sim.date @@ -1578,6 +1581,10 @@ def apply(self, population): for age_grp in self.module.wasting_incident_case_tracker.keys(): for state in self.module.wasting_states: inc_df.loc[age_grp, state] = len(self.module.wasting_incident_case_tracker[age_grp][state]) + if not all(date >= self.date_last_run for + date in self.module.wasting_incident_case_tracker[age_grp][state]): + warnings.warn(f"Some incident cases trying to be logged on {self.sim.date=} from the day of last" + f"log {self.date_last_run=} or before.") assert all(date >= self.date_last_run for date in self.module.wasting_incident_case_tracker[age_grp][state]) @@ -1599,6 +1606,8 @@ def apply(self, population): len(self.module.wasting_length_tracker[age_grp][recov_opt])) else: length_df.loc[age_grp, recov_opt] = 0 + if np.isnan(length_df.loc[age_grp, recov_opt]): + warnings.warn(f'There is an empty length for {age_grp=}, {recov_opt=}.') assert not np.isnan(length_df.loc[age_grp, recov_opt]) if recov_opt == 'mod_nat_recov': if not all(length >= 81 for length in self.module.wasting_length_tracker[age_grp][recov_opt]): @@ -1610,6 +1619,8 @@ def apply(self, population): warnings.warn(f'{self.module.wasting_length_tracker[age_grp][recov_opt]=} ' f'contains length < 3 weeks; {age_grp=}, {recov_opt=}') else: + if recov_opt not in ['mod_not_yet_recovered', 'sev_not_yet_recovered']: + warnings.warn(f'\nInvalid {recov_opt=}.') assert recov_opt in ['mod_not_yet_recovered', 'sev_not_yet_recovered'] @@ -1643,23 +1654,45 @@ def apply(self, population): (self.sim.date - mod_wasted_whole_ys_agegrp['un_last_wasting_date_of_onset']).dt.days sev_wasted_whole_ys_agegrp['wasting_length'] = \ (self.sim.date - sev_wasted_whole_ys_agegrp['un_last_wasting_date_of_onset']).dt.days + print_lengths = False if len(mod_wasted_whole_ys_agegrp) > 0: - assert not np.isnan(mod_wasted_whole_ys_agegrp['wasting_length']).all() + if np.isnan(mod_wasted_whole_ys_agegrp['wasting_length']).any(): + print_lengths = True + warnings.warn("There is at least one NaN length.") + if not all(length > 0 for length in mod_wasted_whole_ys_agegrp['wasting_length']): + print_lengths = True + warnings.warn("There is at least one zero length.") + if print_lengths: + warnings.warn(f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") + assert not np.isnan(mod_wasted_whole_ys_agegrp['wasting_length']).any() assert all(length > 0 for length in mod_wasted_whole_ys_agegrp['wasting_length']) length_df.loc[age_grp, 'mod_not_yet_recovered'] = ( sum(mod_wasted_whole_ys_agegrp['wasting_length']) / len(mod_wasted_whole_ys_agegrp['wasting_length']) ) else: length_df.loc[age_grp, 'mod_not_yet_recovered'] = 0 + if np.isnan(length_df.loc[age_grp, 'mod_not_yet_recovered']): + warnings.warn(f"The avg {length_df.loc[age_grp, 'mod_not_yet_recovered']=} for {age_grp=} is empty.") assert not np.isnan(length_df.loc[age_grp, 'mod_not_yet_recovered']) + if len(sev_wasted_whole_ys_agegrp) > 0: - assert not np.isnan(sev_wasted_whole_ys_agegrp['wasting_length']).all() + if np.isnan(mod_wasted_whole_ys_agegrp['wasting_length']).any(): + print_lengths = True + warnings.warn("There is at least one NaN length.") + if not all(length > 0 for length in mod_wasted_whole_ys_agegrp['wasting_length']): + print_lengths = True + warnings.warn("There is at least one zero length.") + if print_lengths: + warnings.warn(f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") + assert not np.isnan(sev_wasted_whole_ys_agegrp['wasting_length']).any() assert all(length > 0 for length in sev_wasted_whole_ys_agegrp['wasting_length']) length_df.loc[age_grp, 'sev_not_yet_recovered'] = ( sum(sev_wasted_whole_ys_agegrp['wasting_length']) / len(sev_wasted_whole_ys_agegrp['wasting_length']) ) else: length_df.loc[age_grp, 'sev_not_yet_recovered'] = 0 + if np.isnan(length_df.loc[age_grp, 'sev_not_yet_recovered']): + warnings.warn(f"The avg {length_df.loc[age_grp, 'sev_not_yet_recovered']=} for {age_grp=} is empty.") assert not np.isnan(length_df.loc[age_grp, 'sev_not_yet_recovered']) logger.info(key='wasting_length_avg', data=length_df.to_dict()) @@ -1701,6 +1734,9 @@ def apply(self, population): pop_sizes_dict[f'total__{low_bound_mos}_{high_bound_mos}mo'] = total_per_agegrp_nmb # log prevalence & pop size for children above 5y above5s = df.loc[df.is_alive & (df.age_exact_years >= 5)] + if (len(under5s) + len(above5s)) != len(df.loc[df.is_alive]): + warnings.warn("The numbers of persons under and above 5 don't sum to all alive person, when logging on" + f"{self.sim.date=}.") assert (len(under5s) + len(above5s)) == len(df.loc[df.is_alive]) mod_wasted_above5_nmb = (above5s.un_WHZ_category == '-3<=WHZ<-2').sum() sev_wasted_above5_nmb = (above5s.un_WHZ_category == 'WHZ<-3').sum() @@ -1769,6 +1805,9 @@ def apply(self, population): pop_sizes_dict[f'total__{low_bound_mos}_{high_bound_mos}mo'] = total_per_agegrp_nmb # log prevalence & pop size for children above 5y above5s = df.loc[df.is_alive & (df.age_exact_years >= 5)] + if (len(under5s) + len(above5s)) != len(df.loc[df.is_alive]): + warnings.warn("The numbers of persons under and above 5 don't sum to all alive person, when logging at" + "sim initiation.") assert (len(under5s) + len(above5s)) == len(df.loc[df.is_alive]) mod_wasted_above5_nmb = (above5s.un_WHZ_category == '-3<=WHZ<-2').sum() sev_wasted_above5_nmb = (above5s.un_WHZ_category == 'WHZ<-3').sum() From 0822a7521df283cbedce2e8f6e6198cf375afa54 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 15 Jan 2025 15:57:01 +0000 Subject: [PATCH 245/755] scenario_wast_min_model: 2010-2030(incl.), 2K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 7bb52a7b37..048f301831 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -41,7 +41,7 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2011, month=1, day=1), + end_date=Date(year=2031, month=1, day=1), initial_population_size=2_000, number_of_draws=1, runs_per_draw=1, From 3905ee953a1173b1490fa1ccc1210e14ff64b400 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 16 Jan 2025 00:58:30 +0000 Subject: [PATCH 246/755] scenario_wast_min_model: fix draw pars (commented for now) --- .../scenarios/scenario_wasting_minimal_model.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 048f301831..beafcf0cad 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -104,8 +104,7 @@ def draw_parameters(self, draw_number, rng): # s in base_inc_rate_wasting_props_by_agegp], # 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ # s in progression_severe_wasting_monthly_props_by_agegp], - # 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * - # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam[3]) / + # 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / # (1-0.738)) # } # } From 6d15b974788a7e5b6da5bd6cedf2015fa824249e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 20 Jan 2025 23:17:30 +0000 Subject: [PATCH 247/755] wast: assert with message instead of warning & assert; death due to SAM will not happen yet if rescheduled for later + minor(comments, elif->else) --- src/tlo/methods/wasting.py | 73 ++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 31 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 57da215a18..4a91a6a559 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -535,11 +535,8 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): person_id=person_id, disease_module=self ) - if ((df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') and - (df.at[person_id, 'un_sam_with_complications'])): - warnings.warn(f'{person_id=} has MAM with complications.') assert not ((df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') - and (df.at[person_id, 'un_sam_with_complications'])) + and (df.at[person_id, 'un_sam_with_complications'])), f'{person_id=} has MAM with complications.' def date_of_outcome_for_untreated_wasting(self, whz_category): """ @@ -560,7 +557,7 @@ def date_of_outcome_for_untreated_wasting(self, whz_category): return date_of_outcome # severe wasting (recovery to moderate wasting) ----- - if whz_category == 'WHZ<-3': + elif whz_category == 'WHZ<-3': # determine the duration of severe wasting episode duration_sev_wasting = int(max(p['min_days_duration_of_wasting'], p['duration_of_untreated_sev_wasting'])) # Allocate a date of outcome (death, progression, or recovery) @@ -710,7 +707,7 @@ def do_when_am_treatment(self, person_id, intervention): df.at[person_id, 'un_am_tx_start_date'] = self.sim.date # Reset tx discharge date df.at[person_id, 'un_am_discharge_date'] = pd.NaT - # Cancel natural death with due to tx + # Cancel natural death due to SAM with tx df.at[person_id, 'un_sam_death_date'] = pd.NaT if intervention == 'SFP': @@ -898,11 +895,12 @@ def apply(self, person_id): if not df.at[person_id, 'is_alive']: return - # # Check if this person should still die from SAM: + # # Check if this person should still die from SAM and it should happen now not in future: if ( pd.isnull(df.at[person_id, 'un_am_recovery_date']) and not (df.at[person_id, 'un_am_discharge_date'] > df.at[person_id, 'un_am_tx_start_date']) and - not pd.isnull(df.at[person_id, 'un_sam_death_date']) + not pd.isnull(df.at[person_id, 'un_sam_death_date']) and + df.at[person_id, 'un_sam_death_date'] <= self.sim.date ): if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': warnings.warn(f"{person_id=} dying due to SAM while \n{df.at[person_id, 'un_clinical_acute_malnutrition']=}") @@ -974,10 +972,11 @@ def apply(self, person_id): if not df.at[person_id, 'is_alive']: return + # if not well (i.e. NOT already fully recovered with SAM tx, and send here from follow-up MAM tx) if df.at[person_id, 'un_WHZ_category'] != 'WHZ>=-2': if df.at[person_id, 'un_WHZ_category'] == '-3<=WHZ<-2': recov_opt = f"mod_{df.at[person_id, 'un_clinical_acute_malnutrition']}_tx_full_recov" - elif df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3': + else: # df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3': recov_opt = f"sev_{df.at[person_id, 'un_clinical_acute_malnutrition']}_tx_full_recov" age_group = self.module.age_grps.get(df.loc[person_id].age_years, '5+y') self.module.wasting_length_tracker[age_group][recov_opt].append( @@ -1014,6 +1013,7 @@ def apply(self, person_id): rng = self.module.rng p = self.module.parameters + # if died or recovered in between, should not update to MAM if (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM'): return @@ -1034,12 +1034,21 @@ def apply(self, person_id): if mam_classification == 'mam_by_muac_only': if df.at[person_id, 'un_WHZ_category'] == '-3<=WHZ<-2': recov_opt = "mod_SAM_tx_recov_to_MAM" - elif df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3': + else: # df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3': recov_opt = "sev_SAM_tx_recov_to_MAM" age_group = self.module.age_grps.get(df.loc[person_id].age_years, '5+y') - self.module.wasting_length_tracker[age_group][recov_opt].append( - (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days - ) + wasted_days = (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days + + def get_tx_length(in_person_id): + if df.at[in_person_id, 'un_sam_with_complications']: + tx_length = p['tx_length_weeks_InpatientSAM'] + else: # SAM without complications + tx_length = p['tx_length_weeks_OutpatientSAM'] + return tx_length + + assert wasted_days >= get_tx_length(person_id), \ + f" The {person_id=} is wasted less than tx_length= {get_tx_length(person_id)} weeks when {recov_opt=}." + self.module.wasting_length_tracker[age_group][recov_opt].append(wasted_days) df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' @@ -1572,6 +1581,7 @@ def __init__(self, module): def apply(self, population): df = self.sim.population.props + p = self.module.parameters # ----- INCIDENCE LOG ---------------- # Convert the list of timestamps into a number of timestamps @@ -1581,12 +1591,10 @@ def apply(self, population): for age_grp in self.module.wasting_incident_case_tracker.keys(): for state in self.module.wasting_states: inc_df.loc[age_grp, state] = len(self.module.wasting_incident_case_tracker[age_grp][state]) - if not all(date >= self.date_last_run for - date in self.module.wasting_incident_case_tracker[age_grp][state]): - warnings.warn(f"Some incident cases trying to be logged on {self.sim.date=} from the day of last" - f"log {self.date_last_run=} or before.") assert all(date >= self.date_last_run for - date in self.module.wasting_incident_case_tracker[age_grp][state]) + date in self.module.wasting_incident_case_tracker[age_grp][state]), \ + f"Some incident cases trying to be logged on {self.sim.date=} from the day of last log "\ + f"{self.date_last_run=} or before." logger.info(key='wasting_incidence_count', data=inc_df.to_dict()) @@ -1606,22 +1614,25 @@ def apply(self, population): len(self.module.wasting_length_tracker[age_grp][recov_opt])) else: length_df.loc[age_grp, recov_opt] = 0 - if np.isnan(length_df.loc[age_grp, recov_opt]): - warnings.warn(f'There is an empty length for {age_grp=}, {recov_opt=}.') - assert not np.isnan(length_df.loc[age_grp, recov_opt]) + assert not np.isnan(length_df.loc[age_grp, recov_opt]),\ + f'There is an empty length for {age_grp=}, {recov_opt=}.' if recov_opt == 'mod_nat_recov': - if not all(length >= 81 for length in self.module.wasting_length_tracker[age_grp][recov_opt]): - warnings.warn(f'{self.module.wasting_length_tracker[age_grp][recov_opt]=} ' - f'contains length < 3 weeks; {age_grp=}, {recov_opt=}') + assert all(length >= p['duration_of_untreated_mod_wasting'] for length in + self.module.wasting_length_tracker[age_grp][recov_opt]),\ + f"{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < "\ + f"{p['duration_of_untreated_mod_wasting']=}; {age_grp=}, {recov_opt=}" elif recov_opt in ['mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', 'sev_SAM_tx_full_recov', 'mod_SAM_tx_recov_to_MAM', 'sev_SAM_tx_recov_to_MAM']: - if not all(length >= 21 for length in self.module.wasting_length_tracker[age_grp][recov_opt]): - warnings.warn(f'{self.module.wasting_length_tracker[age_grp][recov_opt]=} ' - f'contains length < 3 weeks; {age_grp=}, {recov_opt=}') - else: - if recov_opt not in ['mod_not_yet_recovered', 'sev_not_yet_recovered']: - warnings.warn(f'\nInvalid {recov_opt=}.') - assert recov_opt in ['mod_not_yet_recovered', 'sev_not_yet_recovered'] + min_tx_length = min(p['tx_length_weeks_SuppFeedingMAM'], p['tx_length_weeks_OutpatientSAM'], + p['tx_length_weeks_InpatientSAM']) + assert all(length >= min_tx_length for length in + self.module.wasting_length_tracker[age_grp][recov_opt]),\ + f'{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < '\ + f'{min_tx_length} weeks; {age_grp=}, {recov_opt=}' + + assert recov_opt in ['mod_nat_recov', 'mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', + 'sev_SAM_tx_full_recov', 'mod_SAM_tx_recov_to_MAM', 'sev_SAM_tx_recov_to_MAM', + 'mod_not_yet_recovered', 'sev_not_yet_recovered'], f'\nInvalid {recov_opt=}.' # Reset the tracker From 0bd293aa394c646a0621cc2f9f52a11e219e0cfa Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 22 Jan 2025 22:06:06 +0000 Subject: [PATCH 248/755] scenario_wast_min_model: comment currently unused import --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index beafcf0cad..a3dad5879d 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -9,7 +9,7 @@ tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py """ -import itertools +# import itertools import warnings from tlo import Date, logging From 003c857f0a3f77316b9a93f211d60500c592d9c9 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 22 Jan 2025 22:43:10 +0000 Subject: [PATCH 249/755] wast & test_wast: warnings -> asserts w\ comment; events cancellations; test with equip avail 'all' --- src/tlo/methods/wasting.py | 221 +++++++++++++++++++++++++------------ tests/test_wasting.py | 28 ++++- 2 files changed, 170 insertions(+), 79 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 4a91a6a559..078475720d 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -7,7 +7,6 @@ import numpy as np import pandas as pd -import warnings from scipy.stats import norm from tlo import DateOffset, Module, Parameter, Property, Types, logging @@ -204,6 +203,13 @@ class Wasting(Module, GenericFirstAppointmentsMixin): ' is currently on; set to not_applicable if well hence no treatment required', categories=['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care'] + [ 'none', 'not_applicable']), + # Properties to help cancel events + 'un_nat_recov_to_cancel': Property(Types.LIST, 'list of dates of scheduled natural recovery to be ' + 'canceled for the person'), + 'un_progression_to_cancel': Property(Types.LIST, 'list of dates of scheduled progression to severe ' + 'wasting to be canceled for the person'), + 'un_recov_with_tx_to_cancel': Property(Types.LIST, 'list of dates of scheduled recovery with tx ' + 'to be canceled for the person'), } def __init__(self, name=None, resourcefilepath=None): @@ -281,6 +287,13 @@ def initialise_population(self, population): # df.loc[df.is_alive, 'un_am_discharge_date'] = pd.NaT # df.loc[df.is_alive, 'un_am_tx_start_date'] = pd.NaT df.loc[df.is_alive, 'un_am_treatment_type'] = 'not_applicable' + df.loc[df.is_alive, 'un_nat_recov_to_cancel'] = \ + df.loc[df.is_alive, 'un_nat_recov_to_cancel'].apply(lambda x: []) + df.loc[df.is_alive, 'un_progression_to_cancel'] = \ + df.loc[df.is_alive, 'un_progression_to_cancel'].apply(lambda x: []) + df.loc[df.is_alive, 'un_recov_with_tx_to_cancel'] = \ + df.loc[df.is_alive, 'un_recov_with_tx_to_cancel'].apply(lambda x: []) + # initialise wasting linear models. self.wasting_models = WastingModels(self) @@ -348,6 +361,10 @@ def on_birth(self, mother_id, child_id): # df.loc[df.is_alive, 'un_am_discharge_date'] = pd.NaT # df.loc[df.is_alive, 'un_am_tx_start_date'] = pd.NaT df.at[child_id, 'un_am_treatment_type'] = 'not_applicable' + df.at[child_id, 'un_nat_recov_to_cancel'] = [] + df.at[child_id, 'un_progression_to_cancel'] = [] + df.at[child_id, 'un_recov_with_tx_to_cancel'] = [] + def get_prob_severe_wasting_among_wasted(self, agegp: str) -> Union[float, int]: """ @@ -703,12 +720,19 @@ def do_when_am_treatment(self, person_id, intervention): """ df = self.sim.population.props p = self.parameters + # Set the date when the treatment is provided: df.at[person_id, 'un_am_tx_start_date'] = self.sim.date # Reset tx discharge date df.at[person_id, 'un_am_discharge_date'] = pd.NaT # Cancel natural death due to SAM with tx df.at[person_id, 'un_sam_death_date'] = pd.NaT + # Cancel progression to sev wasting if scheduled + progress_event_tuple = next((event_tuple for event_tuple in self.sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], Wasting_ProgressionToSevere_Event)), None) + if progress_event_tuple: + progress_date = progress_event_tuple[0] + df.at[person_id, 'un_progression_to_cancel'].append(progress_date) if intervention == 'SFP': df.at[person_id, 'un_am_discharge_date'] = \ @@ -793,7 +817,7 @@ def apply(self, population): # # # INCIDENCE OF MODERATE WASTING # # # # # # # # # # # # # # # # # # # # # # Determine who will be onset with wasting among those who are not currently wasted ------------- not_wasted_or_treated = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == 'WHZ>=-2') & - (df.un_am_tx_start_date != pd.NaT)] + (df.un_am_tx_start_date.isna())] incidence_of_wasting = self.module.wasting_models.wasting_incidence_lm.predict(not_wasted_or_treated, rng=rng) mod_wasting_new_cases = not_wasted_or_treated.loc[incidence_of_wasting] mod_wasting_new_cases_idx = mod_wasting_new_cases.index @@ -822,10 +846,9 @@ def apply(self, population): ) for person_id in mod_wasting_new_cases_idx[progression_severe_wasting]: - # schedule severe wasting WHZ < -3 onset after duration of moderate wasting + # schedule severe wasting WHZ < -3 onset after duration of untreated moderate wasting self.sim.schedule_event( - event=Wasting_ProgressionToSevere_Event( - module=self.module, person_id=person_id), date=outcome_date + event=Wasting_ProgressionToSevere_Event(module=self.module, person_id=person_id), date=outcome_date ) # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # @@ -858,26 +881,29 @@ def apply(self, person_id): ): return - else: - # # # INCIDENCE OF SEVERE WASTING # # # # # # # # # # # # # # # # # # # # # - # Continue with progression to severe if not treated/recovered - # update properties - # - WHZ - df.at[person_id, 'un_WHZ_category'] = 'WHZ<-3' - # - MUAC, oedema, clinical state of acute malnutrition, complications, death - self.module.clinical_signs_acute_malnutrition(person_id) - - # ------------------------------------------------------------------------------------------- - # Add this severe wasting incident case to the tracker - age_group = Wasting_IncidencePoll.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') - self.module.wasting_incident_case_tracker[age_group]['WHZ<-3'].append(self.sim.date) + if self.sim.date in df.at[person_id, 'un_progression_to_cancel']: + df.at[person_id, 'un_progression_to_cancel'].remove(self.sim.date) + return - if pd.isnull(df.at[person_id, 'un_sam_death_date']): - # # # SEVERE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # # - # Schedule recovery from severe wasting for those not dying due to SAM - outcome_date = self.module.date_of_outcome_for_untreated_wasting(whz_category='WHZ<-3') - self.sim.schedule_event(event=Wasting_NaturalRecovery_Event( - module=self.module, person_id=person_id), date=outcome_date) + # # # INCIDENCE OF SEVERE WASTING # # # # # # # # # # # # # # # # # # # # # + # Continue with progression to severe if not treated/recovered + # update properties + # - WHZ + df.at[person_id, 'un_WHZ_category'] = 'WHZ<-3' + # - MUAC, oedema, clinical state of acute malnutrition, complications, death + self.module.clinical_signs_acute_malnutrition(person_id) + + # ------------------------------------------------------------------------------------------- + # Add this severe wasting incident case to the tracker + age_group = Wasting_IncidencePoll.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') + self.module.wasting_incident_case_tracker[age_group]['WHZ<-3'].append(self.sim.date) + + if pd.isnull(df.at[person_id, 'un_sam_death_date']): + # # # SEVERE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # # + # Schedule recovery from severe wasting for those not dying due to SAM + outcome_date = self.module.date_of_outcome_for_untreated_wasting(whz_category='WHZ<-3') + self.sim.schedule_event(event=Wasting_NaturalRecovery_Event( + module=self.module, person_id=person_id), date=outcome_date) class Wasting_SevereAcuteMalnutritionDeath_Event(Event, IndividualScopeEventMixin): @@ -902,9 +928,8 @@ def apply(self, person_id): not pd.isnull(df.at[person_id, 'un_sam_death_date']) and df.at[person_id, 'un_sam_death_date'] <= self.sim.date ): - if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': - warnings.warn(f"{person_id=} dying due to SAM while \n{df.at[person_id, 'un_clinical_acute_malnutrition']=}") - assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' + assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM',\ + f"{person_id=} dying due to SAM while \n{df.at[person_id, 'un_clinical_acute_malnutrition']=}" # Cause the death to happen immediately df.at[person_id, 'un_sam_death_date'] = self.sim.date self.sim.modules['Demography'].do_death( @@ -927,6 +952,7 @@ def __init__(self, module, person_id): def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe + p = self.module.parameters if ( (not df.at[person_id, 'is_alive']) or @@ -935,14 +961,21 @@ def apply(self, person_id): ): return + if self.sim.date in df.at[person_id, 'un_nat_recov_to_cancel']: + df.at[person_id, 'un_nat_recov_to_cancel'].remove(self.sim.date) + return + whz = df.at[person_id, 'un_WHZ_category'] if whz == '-3<=WHZ<-2': # improve WHZ df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished age_group = self.module.age_grps.get(df.loc[person_id].age_years, '5+y') - self.module.wasting_length_tracker[age_group]['mod_nat_recov'].append( - (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days - ) + wasted_days = (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days + assert wasted_days >= p['duration_of_untreated_mod_wasting'],\ + (f" The {person_id=} is wasted for {wasted_days=} which is less than " + f"{p['duration_of_untreated_mod_wasting']=} days when naturally recovers from mod. wasting at the " + f"{age_group=}.") + self.module.wasting_length_tracker[age_group]['mod_nat_recov'].append(wasted_days) else: # whz == 'WHZ<-3' @@ -956,6 +989,14 @@ def apply(self, person_id): if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well': df.at[person_id, 'un_am_recovery_date'] = self.sim.date df.at[person_id, 'un_sam_death_date'] = pd.NaT + recov_with_tx_event_tuple = \ + next((event_tuple for event_tuple in self.sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], (Wasting_ClinicalAcuteMalnutritionRecovery_Event, + Wasting_UpdateToMAM_Event) + )), None) + if recov_with_tx_event_tuple: + recov_with_tx_date = recov_with_tx_event_tuple[0] + df.at[person_id, 'un_recov_with_tx_to_cancel'].append(recov_with_tx_date) class Wasting_ClinicalAcuteMalnutritionRecovery_Event(Event, IndividualScopeEventMixin): @@ -968,6 +1009,7 @@ def __init__(self, module, person_id): def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe + p = self.module.parameters if not df.at[person_id, 'is_alive']: return @@ -979,9 +1021,20 @@ def apply(self, person_id): else: # df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3': recov_opt = f"sev_{df.at[person_id, 'un_clinical_acute_malnutrition']}_tx_full_recov" age_group = self.module.age_grps.get(df.loc[person_id].age_years, '5+y') - self.module.wasting_length_tracker[age_group][recov_opt].append( - (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days - ) + wasted_days = (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days + + def get_tx_length(in_person_id): + if df.at[in_person_id, 'un_sam_with_complications']: + tx_length = p['tx_length_weeks_InpatientSAM'] + elif df.at[in_person_id, 'un_clinical_acute_malnutrition'] == 'SAM': + tx_length = p['tx_length_weeks_OutpatientSAM'] + else: # df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM': + tx_length = p['tx_length_weeks_SuppFeedingMAM'] + return tx_length + + assert wasted_days >= get_tx_length(person_id),\ + f" The {person_id=} is wasted less than tx_length= {get_tx_length(person_id)} weeks when {recov_opt=}." + self.module.wasting_length_tracker[age_group][recov_opt].append(wasted_days) df.at[person_id, 'un_am_recovery_date'] = self.sim.date df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished @@ -997,6 +1050,11 @@ def apply(self, person_id): self.sim.modules["SymptomManager"].clear_symptoms( person_id=person_id, disease_module=self.module ) + recov_event_tuple = next((event_tuple for event_tuple in self.sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], Wasting_NaturalRecovery_Event)), None) + if recov_event_tuple: + nat_recov_date = recov_event_tuple[0] + df.at[person_id, 'un_nat_recov_to_cancel'].append(nat_recov_date) class Wasting_UpdateToMAM_Event(Event, IndividualScopeEventMixin): @@ -1019,7 +1077,8 @@ def apply(self, person_id): # For cases with normal WHZ and other acute malnutrition signs: # oedema, or low MUAC - do not change the WHZ - if df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2': + whz = df.at[person_id, 'un_WHZ_category'] + if whz == 'WHZ>=-2': # MAM by MUAC only df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' # TODO: I think this changes the proportions below as some of the cases will be issued here @@ -1032,9 +1091,9 @@ def apply(self, person_id): p['proportion_mam_with_-3<=WHZ<-2_and_normal_MUAC']]) if mam_classification == 'mam_by_muac_only': - if df.at[person_id, 'un_WHZ_category'] == '-3<=WHZ<-2': + if whz == '-3<=WHZ<-2': recov_opt = "mod_SAM_tx_recov_to_MAM" - else: # df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3': + else: # whz == 'WHZ<-3': recov_opt = "sev_SAM_tx_recov_to_MAM" age_group = self.module.age_grps.get(df.loc[person_id].age_years, '5+y') wasted_days = (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days @@ -1049,14 +1108,40 @@ def get_tx_length(in_person_id): assert wasted_days >= get_tx_length(person_id), \ f" The {person_id=} is wasted less than tx_length= {get_tx_length(person_id)} weeks when {recov_opt=}." self.module.wasting_length_tracker[age_group][recov_opt].append(wasted_days) + + # wasting (WHZ) recovers to normal, therefore if natural recovery was scheduled + # (from moderate or severe wasting), it will be canceled + recov_event_tuple = next((event_tuple for event_tuple in self.sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], Wasting_NaturalRecovery_Event)), None) + if recov_event_tuple: + nat_recov_date = recov_event_tuple[0] + df.at[person_id, 'un_nat_recov_to_cancel'].append(nat_recov_date) df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' if mam_classification == 'mam_by_muac_and_whz': + # wasting (WHZ) recovers to moderate, therefore if natural recovery from severe wasting was scheduled, + # it will be cancelled, but if natural recovery from moderate wasting was scheduled, it will not be + # cancelled + if whz == 'WHZ<-3': + recov_event_tuple = next((event_tuple for event_tuple in self.sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], Wasting_NaturalRecovery_Event)), None) + if recov_event_tuple: + nat_recov_date = recov_event_tuple[0] + df.at[person_id, 'un_nat_recov_to_cancel'].append(nat_recov_date) df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' if mam_classification == 'mam_by_whz_only': + # wasting (WHZ) recovers to moderate, therefore if natural recovery from severe wasting was scheduled, + # it will be cancelled, but if natural recovery from moderate wasting was scheduled, it will not be + # cancelled + if whz == 'WHZ<-3': + recov_event_tuple = next((event_tuple for event_tuple in self.sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], Wasting_NaturalRecovery_Event)), None) + if recov_event_tuple: + nat_recov_date = recov_event_tuple[0] + df.at[person_id, 'un_nat_recov_to_cancel'].append(nat_recov_date) df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' @@ -1665,46 +1750,38 @@ def apply(self, population): (self.sim.date - mod_wasted_whole_ys_agegrp['un_last_wasting_date_of_onset']).dt.days sev_wasted_whole_ys_agegrp['wasting_length'] = \ (self.sim.date - sev_wasted_whole_ys_agegrp['un_last_wasting_date_of_onset']).dt.days - print_lengths = False if len(mod_wasted_whole_ys_agegrp) > 0: - if np.isnan(mod_wasted_whole_ys_agegrp['wasting_length']).any(): - print_lengths = True - warnings.warn("There is at least one NaN length.") - if not all(length > 0 for length in mod_wasted_whole_ys_agegrp['wasting_length']): - print_lengths = True - warnings.warn("There is at least one zero length.") - if print_lengths: - warnings.warn(f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") - assert not np.isnan(mod_wasted_whole_ys_agegrp['wasting_length']).any() - assert all(length > 0 for length in mod_wasted_whole_ys_agegrp['wasting_length']) + assert not np.isnan(mod_wasted_whole_ys_agegrp['wasting_length']).any(),\ + ("There is at least one NaN length.\n" + f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") + assert all(length > 0 for length in mod_wasted_whole_ys_agegrp['wasting_length']),\ + ("There is at least one zero length.\n" + f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") length_df.loc[age_grp, 'mod_not_yet_recovered'] = ( - sum(mod_wasted_whole_ys_agegrp['wasting_length']) / len(mod_wasted_whole_ys_agegrp['wasting_length']) + sum(mod_wasted_whole_ys_agegrp['wasting_length']) / + len(mod_wasted_whole_ys_agegrp['wasting_length']) ) else: length_df.loc[age_grp, 'mod_not_yet_recovered'] = 0 - if np.isnan(length_df.loc[age_grp, 'mod_not_yet_recovered']): - warnings.warn(f"The avg {length_df.loc[age_grp, 'mod_not_yet_recovered']=} for {age_grp=} is empty.") - assert not np.isnan(length_df.loc[age_grp, 'mod_not_yet_recovered']) + assert not np.isnan(length_df.loc[age_grp, 'mod_not_yet_recovered']), \ + f"The avg {length_df.loc[age_grp, 'mod_not_yet_recovered']=} for {age_grp=} is empty." if len(sev_wasted_whole_ys_agegrp) > 0: - if np.isnan(mod_wasted_whole_ys_agegrp['wasting_length']).any(): - print_lengths = True - warnings.warn("There is at least one NaN length.") - if not all(length > 0 for length in mod_wasted_whole_ys_agegrp['wasting_length']): - print_lengths = True - warnings.warn("There is at least one zero length.") - if print_lengths: - warnings.warn(f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") - assert not np.isnan(sev_wasted_whole_ys_agegrp['wasting_length']).any() - assert all(length > 0 for length in sev_wasted_whole_ys_agegrp['wasting_length']) + assert not np.isnan(sev_wasted_whole_ys_agegrp['wasting_length']).any(), \ + ("There is at least one NaN length.\n" + f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") + + assert all(length > 0 for length in sev_wasted_whole_ys_agegrp['wasting_length']), \ + ("There is at least one zero length.\n" + f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") length_df.loc[age_grp, 'sev_not_yet_recovered'] = ( - sum(sev_wasted_whole_ys_agegrp['wasting_length']) / len(sev_wasted_whole_ys_agegrp['wasting_length']) + sum(sev_wasted_whole_ys_agegrp['wasting_length']) / + len(sev_wasted_whole_ys_agegrp['wasting_length']) ) else: length_df.loc[age_grp, 'sev_not_yet_recovered'] = 0 - if np.isnan(length_df.loc[age_grp, 'sev_not_yet_recovered']): - warnings.warn(f"The avg {length_df.loc[age_grp, 'sev_not_yet_recovered']=} for {age_grp=} is empty.") - assert not np.isnan(length_df.loc[age_grp, 'sev_not_yet_recovered']) + assert not np.isnan(length_df.loc[age_grp, 'sev_not_yet_recovered']), \ + f"The avg {length_df.loc[age_grp, 'sev_not_yet_recovered']=} for {age_grp=} is empty." logger.info(key='wasting_length_avg', data=length_df.to_dict()) @@ -1745,10 +1822,9 @@ def apply(self, population): pop_sizes_dict[f'total__{low_bound_mos}_{high_bound_mos}mo'] = total_per_agegrp_nmb # log prevalence & pop size for children above 5y above5s = df.loc[df.is_alive & (df.age_exact_years >= 5)] - if (len(under5s) + len(above5s)) != len(df.loc[df.is_alive]): - warnings.warn("The numbers of persons under and above 5 don't sum to all alive person, when logging on" - f"{self.sim.date=}.") - assert (len(under5s) + len(above5s)) == len(df.loc[df.is_alive]) + assert (len(under5s) + len(above5s)) == len(df.loc[df.is_alive]), \ + ("The numbers of persons under and above 5 don't sum to all alive person, when logging on" + f"{self.sim.date=}.") mod_wasted_above5_nmb = (above5s.un_WHZ_category == '-3<=WHZ<-2').sum() sev_wasted_above5_nmb = (above5s.un_WHZ_category == 'WHZ<-3').sum() wasting_prev_dict['mod__5y+'] = mod_wasted_above5_nmb / len(above5s) @@ -1816,10 +1892,9 @@ def apply(self, population): pop_sizes_dict[f'total__{low_bound_mos}_{high_bound_mos}mo'] = total_per_agegrp_nmb # log prevalence & pop size for children above 5y above5s = df.loc[df.is_alive & (df.age_exact_years >= 5)] - if (len(under5s) + len(above5s)) != len(df.loc[df.is_alive]): - warnings.warn("The numbers of persons under and above 5 don't sum to all alive person, when logging at" - "sim initiation.") - assert (len(under5s) + len(above5s)) == len(df.loc[df.is_alive]) + assert (len(under5s) + len(above5s)) == len(df.loc[df.is_alive]), \ + ("The numbers of persons under and above 5 don't sum to all alive person, when logging at" + "sim initiation.") mod_wasted_above5_nmb = (above5s.un_WHZ_category == '-3<=WHZ<-2').sum() sev_wasted_above5_nmb = (above5s.un_WHZ_category == 'WHZ<-3').sum() wasting_prev_dict['mod__5y+'] = mod_wasted_above5_nmb / len(above5s) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 0a82b11464..17a5f96ca5 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -62,7 +62,8 @@ def get_sim(tmpdir): enhanced_lifestyle.Lifestyle(resourcefilepath=resourcefilepath), healthsystem.HealthSystem(resourcefilepath=resourcefilepath, disable=False, - cons_availability='all'), + cons_availability='all', + equip_availability='all'), symptommanager.SymptomManager(resourcefilepath=resourcefilepath), healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resourcefilepath), healthburden.HealthBurden(resourcefilepath=resourcefilepath), @@ -398,7 +399,7 @@ def test_recovery_severe_acute_malnutrition_without_complications(tmpdir): # set progress to severe wasting at 100% as well, hence no natural recovery from moderate wasting wmodule.wasting_models.severe_wasting_progression_lm = LinearModel.multiplicative() - # set complete recovery from wasting to zero. We want those with SAM to recover to MAM with tx + # set complete recovery from SAM to zero. We want those with SAM to recover to MAM with tx wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) # set prob of death after tx at 0% (hence recovery to MAM at 100%) @@ -525,6 +526,7 @@ def test_recovery_severe_acute_malnutrition_with_complications(tmpdir): # Manually set this individual properties to have severe acute malnutrition df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' + df.loc[person_id, 'un_last_wasting_date_of_onset'] = sim.date # ensure the individual has complications due to SAM wmodule.parameters['prob_complications_in_SAM'] = 1.0 # assign diagnosis @@ -571,12 +573,12 @@ def test_recovery_severe_acute_malnutrition_with_complications(tmpdir): ] assert 1 == len(hsi_event_scheduled) - # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + # Run the created instance of HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM)][0] sam_ev.run(squeeze_factor=0.0) - # Check death is scheduled, but was canceled due to tx + # Check scheduled death was canceled due to tx person = df.loc[person_id] assert pd.isnull(person['un_sam_death_date']) @@ -707,8 +709,9 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): sim.event_queue.queue = [] # clear the queue wmodule = sim.modules['Wasting'] + p = wmodule.parameters # set prob of death after tx at 0% (hence recovery to MAM at 100%) - wmodule.parameters['prob_death_after_SAMcare'] = 0.0 + p['prob_death_after_SAMcare'] = 0.0 # increase wasting incidence rate to 100% and reduce rate of progress to severe wasting to zero. We don't want # individuals to progress to SAM as we are testing for MAM natural recovery @@ -741,10 +744,23 @@ def test_nat_hist_cure_if_recovery_scheduled(tmpdir): recov_event = recov_event_tuple[1] assert date_of_scheduled_recov > sim.date - # Run a Cure Event + # Run a Cure Event after the length of the treatment + def get_tx_length(in_person_id): + if df.at[in_person_id, 'un_sam_with_complications']: + tx_length = p['tx_length_weeks_InpatientSAM'] + elif df.at[in_person_id, 'un_clinical_acute_malnutrition'] == 'SAM': + tx_length = p['tx_length_weeks_OutpatientSAM'] + else: # df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM': + tx_length = p['tx_length_weeks_SuppFeedingMAM'] + return tx_length + sim.date = sim.date + DateOffset(weeks=get_tx_length(person_id)) + assert sim.date < date_of_scheduled_recov cure_event = Wasting_ClinicalAcuteMalnutritionRecovery_Event(person_id=person_id, module=sim.modules['Wasting']) cure_event.apply(person_id=person_id) + # Check the natural recovery was cancelled with the cure: + assert date_of_scheduled_recov in df.at[person_id, 'un_nat_recov_to_cancel'] + # Check that the person is not wasted and is alive still: person = df.loc[person_id] assert person['is_alive'] From 4846f12612c1c1b5063458bd8cc4bac499c436bf Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 22 Jan 2025 22:48:34 +0000 Subject: [PATCH 250/755] scenario_wast_min_model: 2010-2030(incl.), 30K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index a3dad5879d..95aa761a46 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=2_000, + initial_population_size=30_000, number_of_draws=1, runs_per_draw=1, ) From 9fd728f4c9845012b8cdf0e224a0f4d162a3f1f4 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 22 Jan 2025 23:12:13 +0000 Subject: [PATCH 251/755] scenario_wast_min_model: 2010-2030(incl.), 2K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 95aa761a46..a3dad5879d 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + initial_population_size=2_000, number_of_draws=1, runs_per_draw=1, ) From 62d2454c98712209919e21832c82a388fa836588 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 23 Jan 2025 11:00:02 +0000 Subject: [PATCH 252/755] debugging--scenario_wast_min_model: 4K pop, wast: debugging prints --- .../scenario_wasting_minimal_model.py | 2 +- src/tlo/methods/wasting.py | 377 ++++++++++++++++++ 2 files changed, 378 insertions(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index a3dad5879d..386300aba6 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=2_000, + initial_population_size=4_000, number_of_draws=1, runs_per_draw=1, ) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 078475720d..2b50d9ee4a 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -243,6 +243,8 @@ def __init__(self, name=None, resourcefilepath=None): self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} + self.person_of_interest_id = 5 # debugging + def read_parameters(self, data_folder): """ :param data_folder: path of a folder supplied to the Simulation containing data files. Typically, @@ -329,6 +331,9 @@ def initialise_population(self, population): # # # # and, in SAM cases, determine presence of complications and eventually schedule death # # # # self.clinical_signs_acute_malnutrition(index_under5) + print(f"{self.person_of_interest_id=}") + print("--------------------------------------") + def initialise_simulation(self, sim): """Prepares for simulation. Schedules: * the first growth monitoring to happen straight away, scheduled monthly to detect new cases for treatment. @@ -340,6 +345,8 @@ def initialise_simulation(self, sim): sim.schedule_event(Wasting_InitiateGrowthMonitoring(self), sim.date) sim.schedule_event(Wasting_IncidencePoll(self), sim.date + DateOffset(months=3)) sim.schedule_event(Wasting_LoggingEvent(self), sim.date + DateOffset(years=1) - DateOffset(days=1)) + # sim.schedule_event(PrintPersonPropertiesEventIfUpdated(self, self.person_of_interest_id), + # sim.date + DateOffset(days=1)) def on_birth(self, mother_id, child_id): """Initialise properties for a newborn individual. @@ -674,9 +681,19 @@ def do_at_generic_first_appt( schedule_hsi_event: HSIEventScheduler, **kwargs, ) -> None: + + do_prints = False + if person_id == self.person_of_interest_id: + do_prints = True + print(f"NON-EMERGENCY APPT on {self.sim.date=}") + if (individual_properties["age_years"] >= 5) or \ (individual_properties["un_am_treatment_type"] in ['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']): + if do_prints: + print("individual not under 5, or currently treated, hence the appt not going through") + print(f'{individual_properties["age_years"]=}, {individual_properties["un_am_treatment_type"]=}') + print("----------------------------------") return # p = self.parameters @@ -684,14 +701,21 @@ def do_at_generic_first_appt( # get the clinical states clinical_am = individual_properties['un_clinical_acute_malnutrition'] complications = individual_properties['un_sam_with_complications'] + if do_prints: + print(f"{clinical_am=}, {complications=}") # No interventions if well if clinical_am == 'well': + if do_prints: + print("person is well, hence no outcomes from the appt") + print("---------------------------------------------") return # Interventions for MAM elif clinical_am == 'MAM': # schedule HSI for supplementary feeding program for MAM + if do_prints: + print("SFP for MAM scheduled for today") schedule_hsi_event( hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), priority=0, topen=self.sim.date) @@ -701,6 +725,8 @@ def do_at_generic_first_appt( # Interventions for uncomplicated SAM if not complications: # schedule HSI for supplementary feeding program for MAM + if do_prints: + print("OTP for SAM w\out complications scheduled for today") schedule_hsi_event( hsi_event=HSI_Wasting_OutpatientTherapeuticProgramme_SAM(module=self, person_id=person_id), priority=0, topen=self.sim.date) @@ -708,10 +734,15 @@ def do_at_generic_first_appt( # Interventions for complicated SAM if complications: # schedule HSI for supplementary feeding program for MAM + if do_prints: + print("ITC for SAM w\ complications scheduled for today") schedule_hsi_event( hsi_event=HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM(module=self, person_id=person_id), priority=0, topen=self.sim.date) + if do_prints: + print("----------------end of non-ermerg appt-----------------------------") + def do_when_am_treatment(self, person_id, intervention): """ This function will apply the linear model of recovery based on intervention given @@ -721,6 +752,10 @@ def do_when_am_treatment(self, person_id, intervention): df = self.sim.population.props p = self.parameters + do_prints = False + if person_id == self.person_of_interest_id: + do_prints = True + print(f"{self.person_of_interest_id=} RECEIVING TX on {self.sim.date=}") # Set the date when the treatment is provided: df.at[person_id, 'un_am_tx_start_date'] = self.sim.date # Reset tx discharge date @@ -733,6 +768,9 @@ def do_when_am_treatment(self, person_id, intervention): if progress_event_tuple: progress_date = progress_event_tuple[0] df.at[person_id, 'un_progression_to_cancel'].append(progress_date) + if do_prints: + print(f"progression to sev wasting on {progress_date=} is cancelled due to tx") + print(f"{df.at[person_id, 'un_progression_to_cancel']=}") if intervention == 'SFP': df.at[person_id, 'un_am_discharge_date'] = \ @@ -744,6 +782,8 @@ def do_when_am_treatment(self, person_id, intervention): if mam_full_recovery: # schedule recovery date + if do_prints: + print(f"scheduled full recovery from MAM with SFP at {df.at[person_id, 'un_am_discharge_date']=}") self.sim.schedule_event( event=Wasting_ClinicalAcuteMalnutritionRecovery_Event(module=self, person_id=person_id), date=(df.at[person_id, 'un_am_discharge_date']) @@ -751,6 +791,9 @@ def do_when_am_treatment(self, person_id, intervention): # cancel progression date (in ProgressionEvent) else: # remained MAM + if do_prints: + print("remained MAM with SFP") + print("---------------------------------------------------") return elif intervention in ['OTP', 'ITC']: @@ -765,6 +808,8 @@ def do_when_am_treatment(self, person_id, intervention): if sam_full_recovery: df.at[person_id, 'un_am_discharge_date'] = outcome_date # schedule full recovery + if do_prints: + print(f"scheduled full recovery from SAM with {intervention=} at {outcome_date=}") self.sim.schedule_event( event=Wasting_ClinicalAcuteMalnutritionRecovery_Event(module=self, person_id=person_id), date=outcome_date @@ -777,6 +822,8 @@ def do_when_am_treatment(self, person_id, intervention): self.parameters['prob_death_after_SAMcare'] ]) if outcome == 'death': + if do_prints: + print(f"death due to SAM with {intervention=} at {outcome_date=}") self.sim.schedule_event( event=Wasting_SevereAcuteMalnutritionDeath_Event(module=self, person_id=person_id), date=outcome_date @@ -784,12 +831,58 @@ def do_when_am_treatment(self, person_id, intervention): df.at[person_id, 'un_sam_death_date'] = outcome_date else: # recovery to MAM and follow-up treatment for MAM df.at[person_id, 'un_am_discharge_date'] = outcome_date + if do_prints: + print(f"recovery to MAM with {intervention=} scheduled at {outcome_date=} and sent for follow-up MAM tx") self.sim.schedule_event(event=Wasting_UpdateToMAM_Event(module=self, person_id=person_id), date=outcome_date) self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), priority=0, topen=outcome_date) + if do_prints: + print("---------------------------------------------------") + +class PrintPersonPropertiesEventIfUpdated(RegularEvent, PopulationScopeEventMixin): + def __init__(self, module, person_id): + super().__init__(module, frequency=DateOffset(months=1)) + self.person_id = person_id + self.old_person_properties = None + self.old_person_scheduled_events = None + self.old_person_scheduled_hs_events = None + + def apply(self, population): + df = population.props + + print(f"{df.at[self.person_id, 'age_exact_years']=}, {df.at[self.person_id, 'is_alive']=}") + + # new_person_properties = df.loc[self.person_id] + # new_person_scheduled_events = self.sim.find_events_for_person(self.person_id) + # new_person_scheduled_hs_events = self.sim.modules['HealthSystem'].find_events_for_person(self.person_id) + # + # print(f"{self.sim.date=}") + # if self.sim.date == Date(year=2010, month=1, day=1): + # pd.set_option('display.max_columns', None) + # print(f"Properties of person {self.person_id} at initiation:\n {new_person_properties.to_string()}") + # self.old_person_properties = new_person_properties + # print(f"Scheduled events for person {self.person_id}:\n {new_person_scheduled_events}") + # self.old_person_scheduled_events = new_person_scheduled_events + # print(f"HealthSystem events for person {self.person_id}:\n {new_person_scheduled_hs_events}") + # self.old_person_scheduled_hs_events = new_person_scheduled_hs_events + # + # else: + # if not self.old_person_properties.equals(new_person_properties): + # changed_columns = new_person_properties[ + # (new_person_properties != self.old_person_properties) & + # ~(new_person_properties.isna() & self.old_person_properties.isna()) + # ] + # print(f"Properties of person {self.person_id} that have changed:\n {changed_columns.to_string()}") + # self.old_person_properties = new_person_properties + # if self.old_person_scheduled_events != new_person_scheduled_events: + # print(f"Scheduled events for person {self.person_id} changed to:\n {new_person_scheduled_events}") + # self.old_person_scheduled_events = new_person_scheduled_events + # if self.old_person_scheduled_hs_events != new_person_scheduled_hs_events: + # print(f"Scheduled events for person {self.person_id} changed to:\n {new_person_scheduled_hs_events}") + # self.old_person_scheduled_hs_events = new_person_scheduled_hs_events class Wasting_IncidencePoll(RegularEvent, PopulationScopeEventMixin): """ @@ -828,13 +921,27 @@ def apply(self, population): df.loc[mod_wasting_new_cases_idx, 'un_WHZ_category'] = '-3<=WHZ<-2' # ------------------------------------------------------------------------------------------- # Add these incident cases to the tracker + do_prints = False for person_id in mod_wasting_new_cases_idx: age_group = Wasting_IncidencePoll.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') self.module.wasting_incident_case_tracker[age_group]['-3<=WHZ<-2'].append(self.sim.date) + if person_id == self.module.person_of_interest_id: + do_prints = True + print(f"WASTING INCIDENCE on {self.sim.date=}") + print(f"{mod_wasting_new_cases_idx=}, {age_group=}") # Update properties related to clinical acute malnutrition # (MUAC, oedema, clinical state of acute malnutrition and if SAM complications and death; # clear symptoms if not SAM) self.module.clinical_signs_acute_malnutrition(mod_wasting_new_cases_idx) + if do_prints: + print(f"assigned am indicators:\n" + f" {df.at[self.module.person_of_interest_id, 'un_WHZ_category']=}, " + f"{df.at[self.module.person_of_interest_id, 'un_am_nutritional_oedema']=},\n" + f" {df.at[self.module.person_of_interest_id, 'un_am_MUAC_category']=}") + print("am status determined and if SAM, complications and death determined:\n" + f" {df.at[self.module.person_of_interest_id, 'un_clinical_acute_malnutrition']=}, " + f"{df.at[self.module.person_of_interest_id, 'un_sam_with_complications']=},\n" + f" {df.at[self.module.person_of_interest_id, 'un_sam_death_date']=}") # ------------------------------------------------------------------------------------------- outcome_date = self.module.date_of_outcome_for_untreated_wasting(whz_category='-3<=WHZ<-2') @@ -844,20 +951,29 @@ def apply(self, population): progression_severe_wasting = self.module.wasting_models.severe_wasting_progression_lm.predict( df.loc[mod_wasting_new_cases_idx], rng=rng, squeeze_single_row_output=False ) + if do_prints: + print(f"{outcome_date=},\n {progression_severe_wasting=}") for person_id in mod_wasting_new_cases_idx[progression_severe_wasting]: # schedule severe wasting WHZ < -3 onset after duration of untreated moderate wasting self.sim.schedule_event( event=Wasting_ProgressionToSevere_Event(module=self.module, person_id=person_id), date=outcome_date ) + if person_id == self.module.person_of_interest_id: + print(f"scheduled progression to sev wast at {outcome_date=}") # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # Schedule recovery from moderate wasting for those not progressing to severe wasting --------- for person_id in mod_wasting_new_cases_idx[~progression_severe_wasting]: + if person_id == self.module.person_of_interest_id: + print(f"scheduled natural recover to no wast at {outcome_date=}") # schedule recovery after duration of moderate wasting self.sim.schedule_event(event=Wasting_NaturalRecovery_Event( module=self.module, person_id=person_id), date=outcome_date) + if do_prints: + print("---------------------------------") + class Wasting_ProgressionToSevere_Event(Event, IndividualScopeEventMixin): """ @@ -872,6 +988,11 @@ def __init__(self, module, person_id): def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe + do_prints = False + if person_id == self.module.person_of_interest_id: + do_prints = True + print(f"PROGRESSION TO SEV WAST on {self.sim.date=}") + if ( (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'age_exact_years'] >= 5) or @@ -879,10 +1000,26 @@ def apply(self, person_id): (df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[person_id, 'un_am_tx_start_date'] < self.sim.date) ): + if do_prints: + print("not going through because") + if not df.at[person_id, 'is_alive']: + print("is already dead") + if df.at[person_id, 'age_exact_years'] >= 5: + print(f"is not under 5, {df.at[person_id, 'age_exact_years']=}") + if df.at[person_id, 'un_WHZ_category'] != '-3<=WHZ<-2': + print(f"not moderately wasted, {df.at[person_id, 'un_WHZ_category']=} ") + if (df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[person_id, 'un_am_tx_start_date'] < + self.sim.date): + print("is currently treated") + print("----------------------------------") return if self.sim.date in df.at[person_id, 'un_progression_to_cancel']: df.at[person_id, 'un_progression_to_cancel'].remove(self.sim.date) + if do_prints: + print("Progression to severe wasting canceled as person received tx and recovered (fully or to MAM) " + "before this day.") + print("----------------------------------") return # # # INCIDENCE OF SEVERE WASTING # # # # # # # # # # # # # # # # # # # # # @@ -892,11 +1029,21 @@ def apply(self, person_id): df.at[person_id, 'un_WHZ_category'] = 'WHZ<-3' # - MUAC, oedema, clinical state of acute malnutrition, complications, death self.module.clinical_signs_acute_malnutrition(person_id) + if do_prints: + print(f"assigned am indicators:\n {df.at[self.module.person_of_interest_id, 'un_WHZ_category']=}, " + f"{df.at[self.module.person_of_interest_id, 'un_am_nutritional_oedema']=}, " + f"{df.at[self.module.person_of_interest_id, 'un_am_MUAC_category']=}") + print("determined am status and if SAM complications and death:\n" + f"{df.at[self.module.person_of_interest_id, 'un_clinical_acute_malnutrition']=}, " + f"{df.at[self.module.person_of_interest_id, 'un_sam_with_complications']=}, " + f"{df.at[self.module.person_of_interest_id, 'un_sam_death_date']=}") # ------------------------------------------------------------------------------------------- # Add this severe wasting incident case to the tracker age_group = Wasting_IncidencePoll.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') self.module.wasting_incident_case_tracker[age_group]['WHZ<-3'].append(self.sim.date) + if do_prints: + print(f"{age_group=}") if pd.isnull(df.at[person_id, 'un_sam_death_date']): # # # SEVERE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # # @@ -904,6 +1051,14 @@ def apply(self, person_id): outcome_date = self.module.date_of_outcome_for_untreated_wasting(whz_category='WHZ<-3') self.sim.schedule_event(event=Wasting_NaturalRecovery_Event( module=self.module, person_id=person_id), date=outcome_date) + if do_prints: + print(f"natural recovery to mod wasting schuduled on {outcome_date=}") + else: + if do_prints: + print("death due to SAM scheduled earlier") + + if do_prints: + print("---------------------------------------------") class Wasting_SevereAcuteMalnutritionDeath_Event(Event, IndividualScopeEventMixin): @@ -917,8 +1072,16 @@ def __init__(self, module, person_id): def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe + do_prints = False + if person_id == self.module.person_of_interest_id: + do_prints = True + print(f"DEATH DUE TO SAM on {self.sim.date=}") + # The event should not run if the person is not currently alive or doesn't have SAM if not df.at[person_id, 'is_alive']: + if do_prints: + print("not going through as the person is already dead") + print("----------------------------------") return # # Check if this person should still die from SAM and it should happen now not in future: @@ -930,6 +1093,9 @@ def apply(self, person_id): ): assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM',\ f"{person_id=} dying due to SAM while \n{df.at[person_id, 'un_clinical_acute_malnutrition']=}" + if do_prints: + print("death still happening,\n ie recovery date = NaT & not (discharge_date > tx_start_date) " + "& death_date != NaT and is <= sim.date)") # Cause the death to happen immediately df.at[person_id, 'un_sam_death_date'] = self.sim.date self.sim.modules['Demography'].do_death( @@ -938,6 +1104,21 @@ def apply(self, person_id): originating_module=self.module) else: df.at[person_id, 'un_sam_death_date'] = pd.NaT + if do_prints: + print("death is not happening because") + if not pd.isnull(df.at[person_id, 'un_am_recovery_date']): + print("the person already recovered and didn't get wasted again since") + if df.at[person_id, 'un_am_discharge_date'] > df.at[person_id, 'un_am_tx_start_date']: + print("discharge_date is set, hence the person should recover due to tx, not to die") + if pd.isnull(df.at[person_id, 'un_sam_death_date']): + print("the death was canceled due to tx") + if df.at[person_id, 'un_sam_death_date'] > self.sim.date: + print("the death was canceled due to tx, but scheduled for later as will die with tx anyway") + + if do_prints: + print(f"{df.at[person_id, 'un_am_recovery_date']=}, {df.at[person_id, 'un_am_discharge_date']=},\n" + f"{df.at[person_id, 'un_am_tx_start_date']=}, {pd.isnull(df.at[person_id, 'un_sam_death_date'])=}") + print("------------------------------------------------------") class Wasting_NaturalRecovery_Event(Event, IndividualScopeEventMixin): @@ -954,17 +1135,39 @@ def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe p = self.module.parameters + do_prints = False + if person_id == self.module.person_of_interest_id: + do_prints = True + print(f"NATURAL RECOVERY on {self.sim.date=}") + if ( (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2') or (not pd.isnull(df.at[person_id, 'un_sam_death_date'])) ): + if do_prints: + print("Natural recovery not going through because") + if not df.at[person_id, 'is_alive']: + print("the person is already dead") + if df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2': + print(f"the person is not wasted, {df.at[person_id, 'un_WHZ_category']=}") + if not pd.isnull(df.at[person_id, 'un_sam_death_date']): + print(f"death due to SAM is scheduled, {df.at[person_id, 'un_sam_death_date']=}") + print("----------------------------------") return if self.sim.date in df.at[person_id, 'un_nat_recov_to_cancel']: df.at[person_id, 'un_nat_recov_to_cancel'].remove(self.sim.date) + if do_prints: + print("Natural recovery canceled as person recovered from wasting due to tx before this day.") + print(f"{df.at[person_id, 'un_nat_recov_to_cancel']=}") + print("----------------------------------") return + if do_prints: + print("Natural recovery going through. The person is alive, still wasted, death due to SAM wasn't " + "scheduled, and is not treated yet, hence natural recovery not canceled.") + whz = df.at[person_id, 'un_WHZ_category'] if whz == '-3<=WHZ<-2': # improve WHZ @@ -976,15 +1179,30 @@ def apply(self, person_id): f"{p['duration_of_untreated_mod_wasting']=} days when naturally recovers from mod. wasting at the " f"{age_group=}.") self.module.wasting_length_tracker[age_group]['mod_nat_recov'].append(wasted_days) + if do_prints: + print(f"from mod wasting, {age_group=}, {wasted_days=}") else: # whz == 'WHZ<-3' # improve WHZ df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' # moderate wasting + age_group = self.module.age_grps.get(df.loc[person_id].age_years, '5+y') + wasted_days = (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days + if do_prints: + print(f"from sev wasting, {age_group=}, {wasted_days=}") # update MUAC, oedema, clinical state of acute malnutrition and if SAM complications and death, # clear symptoms if not SAM self.module.clinical_signs_acute_malnutrition(person_id) + if do_prints: + print(f"assigned am indicators:\n" + f" {df.at[self.module.person_of_interest_id, 'un_WHZ_category']=}, " + f"{df.at[self.module.person_of_interest_id, 'un_am_nutritional_oedema']=},\n" + f" {df.at[self.module.person_of_interest_id, 'un_am_MUAC_category']=}") + print("determined am status and if SAM complications and death:\n" + f" {df.at[self.module.person_of_interest_id, 'un_clinical_acute_malnutrition']=}, " + f"{df.at[self.module.person_of_interest_id, 'un_sam_with_complications']=},\n" + f" {df.at[self.module.person_of_interest_id, 'un_sam_death_date']=}") # set recovery date if recovered if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well': df.at[person_id, 'un_am_recovery_date'] = self.sim.date @@ -997,6 +1215,16 @@ def apply(self, person_id): if recov_with_tx_event_tuple: recov_with_tx_date = recov_with_tx_event_tuple[0] df.at[person_id, 'un_recov_with_tx_to_cancel'].append(recov_with_tx_date) + if do_prints: + print(f"recovery with tx on {recov_with_tx_date=} is cancelled as already recovered now") + + if do_prints: + print(f"as the state is updated to well, {df.at[person_id, 'un_am_recovery_date']=} should be " + f"{self.sim.date=} and\n" + f" {df.at[person_id, 'un_sam_death_date']=} should be NaT") + + if do_prints: + print("---------------------------------------") class Wasting_ClinicalAcuteMalnutritionRecovery_Event(Event, IndividualScopeEventMixin): @@ -1011,7 +1239,15 @@ def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe p = self.module.parameters + do_prints = False + if person_id == self.module.person_of_interest_id: + do_prints = True + print(f"FULL RECOVERY WITH TX on {self.sim.date=}") + if not df.at[person_id, 'is_alive']: + if do_prints: + print("not going through, already dead") + print("----------------------------------") return # if not well (i.e. NOT already fully recovered with SAM tx, and send here from follow-up MAM tx) @@ -1036,6 +1272,9 @@ def get_tx_length(in_person_id): f" The {person_id=} is wasted less than tx_length= {get_tx_length(person_id)} weeks when {recov_opt=}." self.module.wasting_length_tracker[age_group][recov_opt].append(wasted_days) + if do_prints: + print(f"{recov_opt=}, {age_group=}, {wasted_days=} >= tx_length= {get_tx_length(person_id)} weeks") + df.at[person_id, 'un_am_recovery_date'] = self.sim.date df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' @@ -1055,7 +1294,17 @@ def get_tx_length(in_person_id): if recov_event_tuple: nat_recov_date = recov_event_tuple[0] df.at[person_id, 'un_nat_recov_to_cancel'].append(nat_recov_date) + if do_prints: + print(f"natural recovery on {nat_recov_date=} is cancelled as already recovered now") + print(f"{df.at[person_id, 'un_nat_recov_to_cancel']=}") + else: + if do_prints: + print("no natural recovery scheduled, hence no need to cancel any " + f"{df.at[person_id, 'un_nat_recov_to_cancel']=}") + if do_prints: + print("recovered to well with all properties being set and SAM symptoms removed") + print("-------------------------------------------------") class Wasting_UpdateToMAM_Event(Event, IndividualScopeEventMixin): """ @@ -1071,8 +1320,20 @@ def apply(self, person_id): rng = self.module.rng p = self.module.parameters + do_prints = False + if person_id == self.module.person_of_interest_id: + do_prints = True + print(f"RECOVERY TO MAM WITH TX on {self.sim.date=}") + # if died or recovered in between, should not update to MAM if (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM'): + if do_prints: + print("not going through because") + if not df.at[person_id, 'is_alive']: + print("is already dead") + if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': + print(f"not having SAM, {df.at[person_id, 'un_clinical_acute_malnutrition']=}") + print("----------------------------------") return # For cases with normal WHZ and other acute malnutrition signs: @@ -1116,9 +1377,15 @@ def get_tx_length(in_person_id): if recov_event_tuple: nat_recov_date = recov_event_tuple[0] df.at[person_id, 'un_nat_recov_to_cancel'].append(nat_recov_date) + if do_prints: + print(f"natural recovery from {whz=} on {nat_recov_date=} is cancelled as wasting already " + f"recovered to normal now") df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' + if do_prints: + print(f"{recov_opt=}, {age_group=}, {wasted_days=} >= tx_length= {get_tx_length(person_id)} weeks") + if mam_classification == 'mam_by_muac_and_whz': # wasting (WHZ) recovers to moderate, therefore if natural recovery from severe wasting was scheduled, # it will be cancelled, but if natural recovery from moderate wasting was scheduled, it will not be @@ -1129,6 +1396,9 @@ def get_tx_length(in_person_id): if recov_event_tuple: nat_recov_date = recov_event_tuple[0] df.at[person_id, 'un_nat_recov_to_cancel'].append(nat_recov_date) + if do_prints: + print(f"natural recovery from {whz=} on {nat_recov_date=} is cancelled as wasting already " + f"recovered to moderate now") df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' @@ -1137,11 +1407,16 @@ def get_tx_length(in_person_id): # it will be cancelled, but if natural recovery from moderate wasting was scheduled, it will not be # cancelled if whz == 'WHZ<-3': + if do_prints: + print("wasting recovered to moderate") recov_event_tuple = next((event_tuple for event_tuple in self.sim.find_events_for_person(person_id) if isinstance(event_tuple[1], Wasting_NaturalRecovery_Event)), None) if recov_event_tuple: nat_recov_date = recov_event_tuple[0] df.at[person_id, 'un_nat_recov_to_cancel'].append(nat_recov_date) + if do_prints: + print(f"natural recovery from {whz=} on {nat_recov_date=} is cancelled as wasting already " + f"recovered to moderate now") df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' @@ -1158,6 +1433,11 @@ def get_tx_length(in_person_id): person_id=person_id, disease_module=self.module ) + if do_prints: + print(f"wast indicators updated to {df.at[person_id, 'un_WHZ_category']=}," + f"{df.at[person_id, 'un_am_MUAC_category']=}, and no oedema => MAM") + print("------------------------------------------------") + class Wasting_InitiateGrowthMonitoring(Event, PopulationScopeEventMixin): # TODO: will be updated for children 1-5 (monitoring for 0-1 will be integrated in epi module) @@ -1248,6 +1528,11 @@ def apply(self, person_id, squeeze_factor): rng = self.module.rng p = self.module.parameters + do_prints = False + if person_id == self.module.person_of_interest_id: + do_prints = True + print(f"GROWTH MONITORING on {self.sim.date=}") + # TODO: Will they be monitored during the treatment? Can we assume, that after the treatment they will be # always properly checked (all measurements and oedema checked), or should be the assumed "treatment outcome" # be also based on equipment availability and probability of checking oedema? Maybe they should be sent for @@ -1260,6 +1545,13 @@ def apply(self, person_id, squeeze_factor): if (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'age_exact_years'] >= 5): # or # df.at[person_id, 'un_am_treatment_type'].isin(['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']): + if do_prints: + print("not going through because") + if not df.at[person_id, 'is_alive']: + print("already dead") + if df.at[person_id, 'age_exact_years'] >= 5: + print("not under 5") + print("----------------------------------") return def schedule_next_monitoring(): @@ -1270,19 +1562,30 @@ def get_monitoring_frequency_days(age): return p['growth_monitoring_frequency_days'][1] person_monitoring_frequency = get_monitoring_frequency_days(df.at[person_id, 'age_exact_years']) + if do_prints: + print(f"{df.at[person_id, 'age_exact_years']=}, {person_monitoring_frequency=}") if (df.at[person_id, 'age_exact_years'] + (person_monitoring_frequency / 365.25)) < 5: # schedule next growth monitoring + if do_prints: + print("next growth monitoring scheduled at " + f"{(self.sim.date + pd.DateOffset(days=person_monitoring_frequency))=}") self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_GrowthMonitoring(module=self.module, person_id=person_id), topen=self.sim.date + pd.DateOffset(days=person_monitoring_frequency), tclose=None, priority=2 ) + else: + if do_prints: + print("no more growth monitoring scheduled as the age will be above 5") # TODO: as stated above, for now we schedule next monitoring for all children, even those sent for treatment schedule_next_monitoring() if not self.attendance: + if do_prints: + print("does not attend to this growth monitoring appt") + print("-----------------------------------------") return available_equipment = [] @@ -1291,6 +1594,8 @@ def get_monitoring_frequency_days(age): if available: available_equipment.append(equip) self.add_equipment(set(available_equipment)) + if do_prints: + print(f"{available_equipment=}") def schedule_tx_by_diagnosis(hsi_event): self.sim.modules['HealthSystem'].schedule_hsi_event( @@ -1305,6 +1610,8 @@ def schedule_tx_by_diagnosis(hsi_event): # based on performed measurements (depends on whether oedema is checked, and what equipment is available) if oedema_checked and df.at[person_id, 'un_am_nutritional_oedema']: diagnosis = 'SAM' + if do_prints: + print(f"oedema checked and observed its presence => {diagnosis=}") else: if 'MUAC tape' in available_equipment: # all equip available and used @@ -1312,6 +1619,9 @@ def schedule_tx_by_diagnosis(hsi_event): ['Height Pole (Stadiometer)', 'Weighing scale']): if oedema_checked: diagnosis = df.at[person_id, 'un_clinical_acute_malnutrition'] + if do_prints: + print(f"oedema checked and all equip available, hence {diagnosis=} in line with actual " + f"state {df.at[person_id, 'un_clinical_acute_malnutrition']=}") else: whz = df.at[person_id, 'un_WHZ_category'] muac = df.at[person_id, 'un_am_MUAC_category'] @@ -1321,8 +1631,13 @@ def schedule_tx_by_diagnosis(hsi_event): diagnosis = 'SAM' else: diagnosis = 'MAM' + if do_prints: + print(f"oedema not checked but all equip available, hence {diagnosis=} based on {whz=} and " + f"{muac=},\n" + f" not on actual state {df.at[person_id, 'un_clinical_acute_malnutrition']=}") # MUAC measurement is solely used for diagnosis else: + print("WARNING: full availability of equip assumed, we should have never get here") muac = df.at[person_id, 'un_am_MUAC_category'] if muac == '>=125mm': diagnosis = 'well' @@ -1332,6 +1647,7 @@ def schedule_tx_by_diagnosis(hsi_event): diagnosis = 'MAM' else: # MUAC tape not available + print("WARNING: full availability of equip assumed, we should have never get here") # WHZ score is solely used for diagnosis if all(item in available_equipment for item in ['Height Pole (Stadiometer)', 'Weighing scale']): @@ -1350,14 +1666,26 @@ def schedule_tx_by_diagnosis(hsi_event): diagnosis = 'well' if diagnosis == 'well': + if do_prints: + print("diagnosed as being well, hence ntg else going on") + print("---------------------------------") return elif diagnosis == 'MAM': + if do_prints: + print("MAM diagnosed, send for SFP") schedule_tx_by_diagnosis(HSI_Wasting_SupplementaryFeedingProgramme_MAM) elif (diagnosis == 'SAM') and (not complications): + if do_prints: + print("SAM w\out complications diagnosed, send for OTP") schedule_tx_by_diagnosis(HSI_Wasting_OutpatientTherapeuticProgramme_SAM) else: # (diagnosis == 'SAM') and complications: + if do_prints: + print("SAM w\ complications diagnosed, send for ITC") schedule_tx_by_diagnosis(HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM) + if do_prints: + print("-------------------------------------------") + def did_not_run(self): logger.debug(key="HSI_Wasting_GrowthMonitoring", data="HSI_Wasting_GrowthMonitoring: did not run" @@ -1389,7 +1717,15 @@ def apply(self, person_id, squeeze_factor): df = self.sim.population.props # p = self.module.parameters + do_prints = False + if person_id == self.module.person_of_interest_id: + do_prints = True + print(f"SFP APPT on {self.sim.date=}") + if not df.at[person_id, 'is_alive']: + if do_prints: + print("is dead, hence not going through") + print("------------------------------") return # Do here whatever happens to an individual during this health system interaction event @@ -1405,10 +1741,19 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data='consumables are available') # Log that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'CSB++' + if do_prints: + print("consumables available") self.module.do_when_am_treatment(person_id, intervention='SFP') else: logger.debug(key='debug', data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") + if do_prints: + print("consumables not available, SFP tx not scheduled, should be picked up with next growth monitoring" + "if not naturally recovered in between or could be picked up with non-emergency appt if will " + "progress to SAM in between") + + if do_prints: + print("-----------------------------------------------") def did_not_run(self): logger.debug(key='debug', data=f'{self.TREATMENT_ID}: did not run') @@ -1439,7 +1784,15 @@ def apply(self, person_id, squeeze_factor): df = self.sim.population.props # p = self.module.parameters + do_prints = False + if person_id == self.module.person_of_interest_id: + do_prints = True + print(f"OTP APPT on {self.sim.date=}") + if not df.at[person_id, 'is_alive']: + if do_prints: + print("dead already, appt not going through") + print("--------------OTP 1-------------------") return # Do here whatever happens to an individual during this health @@ -1459,10 +1812,18 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data='consumables are available.') # Log that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' + if do_prints: + print("consumables available") self.module.do_when_am_treatment(person_id, intervention='OTP') else: logger.debug(key='debug', data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") + if do_prints: + print("consumables not available, OTP tx not scheduled, should be picked up with next growth monitoring" + " or non-emergency appt if not naturally recovered in between") + + if do_prints: + print("----------------------OTP 2-------------------------") def did_not_run(self): logger.debug(key='debug', data=f'{self.TREATMENT_ID}: did not run') @@ -1489,8 +1850,16 @@ def apply(self, person_id, squeeze_factor): df = self.sim.population.props # p = self.module.parameters + do_prints = False + if person_id == self.module.person_of_interest_id: + do_prints = True + print(f"ITC APPT on {self.sim.date=}") + # Stop the person from dying of acute malnutrition (if they were going to die) if not df.at[person_id, 'is_alive']: + if do_prints: + print("not going through because is already dead") + print("----------------------------------") return # Make request for some consumables @@ -1506,10 +1875,18 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data='consumables available, so use it.') # Log that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'inpatient_care' + if do_prints: + print("consumables available") self.module.do_when_am_treatment(person_id, intervention='ITC') else: logger.debug(key='debug', data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") + if do_prints: + print("consumables not available, ITC tx not scheduled, should be picked up with next growth monitoring" + " or non-emergency appt if not naturally recovered in between") + + if do_prints: + print("-----------------------------------------------") def did_not_run(self): logger.debug(key='debug', data=f'{self.TREATMENT_ID}: did not run') From 067fe949b4cd79b6452e256b36cd710b03f62757 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 23 Jan 2025 11:05:58 +0000 Subject: [PATCH 253/755] debugging--scenario_wast_min_model: 8K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 386300aba6..aeac258a06 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=8_000, number_of_draws=1, runs_per_draw=1, ) From a9ebf68e2687bcf4665347dad7ad52e3c5001ad4 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 23 Jan 2025 11:16:16 +0000 Subject: [PATCH 254/755] debugging Myriad--scenario_wast_min_model: 2010 only, 2K pop --- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index aeac258a06..97d752612c 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -41,8 +41,8 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2031, month=1, day=1), - initial_population_size=8_000, + end_date=Date(year=2011, month=1, day=1), + initial_population_size=2_000, number_of_draws=1, runs_per_draw=1, ) From 03df72f5110863e38f21ebfeb74eefa09348e308 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 23 Jan 2025 19:27:44 +0000 Subject: [PATCH 255/755] debugging--RF_Wast: decrease full recovery w\ tx, increase natural & tx death due to SAM; scenario_wast_min_model: no demography logging --- resources/ResourceFile_Wasting.csv | 4 ++-- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 225463d864..1376e2500e 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:76d261eae1759a64cdf80e3af4aa82900048759462775da599e070e357b9f9d7 -size 3608 +oid sha256:6880f21971ba88b3e753b9bd83934df7f0900b4104ed4c38cfe4b73f1021169d +size 3659 diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 97d752612c..95f0423219 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -52,7 +52,7 @@ def log_configuration(self): 'filename': 'wasting_analysis__minimal_model', 'directory': './outputs/wasting_analysis', "custom_levels": { # Customise the output of specific loggers - "tlo.methods.demography": logging.INFO, + # "tlo.methods.demography": logging.INFO, # TODO: BACK after debugging "tlo.methods.population": logging.INFO, "tlo.methods.wasting": logging.INFO, '*': logging.WARNING From 8da60181f2b71f9d896650f249e76afe6c2739cf Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 23 Jan 2025 19:28:07 +0000 Subject: [PATCH 256/755] wast: update a debugging print --- src/tlo/methods/wasting.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 2b50d9ee4a..2a8ea8cff1 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -688,11 +688,15 @@ def do_at_generic_first_appt( print(f"NON-EMERGENCY APPT on {self.sim.date=}") if (individual_properties["age_years"] >= 5) or \ - (individual_properties["un_am_treatment_type"] in - ['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']): + (individual_properties["un_am_treatment_type"] in + ['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']): if do_prints: - print("individual not under 5, or currently treated, hence the appt not going through") - print(f'{individual_properties["age_years"]=}, {individual_properties["un_am_treatment_type"]=}') + print("not going through because") + if individual_properties["age_years"] >= 5: + print(f'person not under 5, {individual_properties["age_years"]=}') + if individual_properties["un_am_treatment_type"] in \ + ['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']: + print(f',person currently treated, {individual_properties["un_am_treatment_type"]=}') print("----------------------------------") return From 1fdda515f968cbe708762b8ae2560bed99b832d4 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 23 Jan 2025 19:30:18 +0000 Subject: [PATCH 257/755] scenario_wast_min_model: 2010-2030(incl), 10K pop --- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 95f0423219..229ef3fff9 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -41,8 +41,8 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2011, month=1, day=1), - initial_population_size=2_000, + end_date=Date(year=2031, month=1, day=1), + initial_population_size=10_000, number_of_draws=1, runs_per_draw=1, ) From 02a28334d580a44792dcc28fd0395c58dd6c4448 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 23 Jan 2025 23:03:26 +0000 Subject: [PATCH 258/755] debugging-wast: prints for person dying due to SAM while has MAM (10K pop sim) --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 2a8ea8cff1..2932a9b694 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -243,7 +243,7 @@ def __init__(self, name=None, resourcefilepath=None): self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} - self.person_of_interest_id = 5 # debugging + self.person_of_interest_id = 14238 # debugging def read_parameters(self, data_folder): """ From 01787ce62efcf086e88f468c08da0c0f4fdb1b27 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 23 Jan 2025 23:36:38 +0000 Subject: [PATCH 259/755] scenario_wat_min_model: 5K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 229ef3fff9..d1c06c5ea2 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=10_000, + initial_population_size=5_000, number_of_draws=1, runs_per_draw=1, ) From 9d3e9fae3f9c5e551316153bd9419b8dd1fbab55 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 23 Jan 2025 23:47:54 +0000 Subject: [PATCH 260/755] scenario_wast_min_model: 1y-long sim, 2K pop --- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index d1c06c5ea2..95f0423219 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -41,8 +41,8 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2031, month=1, day=1), - initial_population_size=5_000, + end_date=Date(year=2011, month=1, day=1), + initial_population_size=2_000, number_of_draws=1, runs_per_draw=1, ) From 199e657766b4b0c9ab91841b5b2cd8cb210c1696 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 24 Jan 2025 23:58:32 +0000 Subject: [PATCH 261/755] wast: a hack to avoid double generic non-emergency first appt /undo once issue #1581 resolved --- src/tlo/methods/wasting.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 2932a9b694..055c8aebab 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -210,6 +210,9 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'wasting to be canceled for the person'), 'un_recov_with_tx_to_cancel': Property(Types.LIST, 'list of dates of scheduled recovery with tx ' 'to be canceled for the person'), + # Property to avoid double non-emergency appt on the same date + 'un_last_nonemergency_appt_date': Property(Types.DATE, 'last date of generic non-emergency first ' + 'appointment'), } def __init__(self, name=None, resourcefilepath=None): @@ -295,6 +298,7 @@ def initialise_population(self, population): df.loc[df.is_alive, 'un_progression_to_cancel'].apply(lambda x: []) df.loc[df.is_alive, 'un_recov_with_tx_to_cancel'] = \ df.loc[df.is_alive, 'un_recov_with_tx_to_cancel'].apply(lambda x: []) + # df.loc[df.is_alive, 'un_last_nonemergency_appt_date']= pd.NaT # initialise wasting linear models. @@ -371,6 +375,7 @@ def on_birth(self, mother_id, child_id): df.at[child_id, 'un_nat_recov_to_cancel'] = [] df.at[child_id, 'un_progression_to_cancel'] = [] df.at[child_id, 'un_recov_with_tx_to_cancel'] = [] + # df.at[child_id, 'un_last_nonemergency_appt_date']= pd.NaT def get_prob_severe_wasting_among_wasted(self, agegp: str) -> Union[float, int]: @@ -682,6 +687,9 @@ def do_at_generic_first_appt( **kwargs, ) -> None: + df = self.sim.population.props + # p = self.parameters + do_prints = False if person_id == self.person_of_interest_id: do_prints = True @@ -689,7 +697,8 @@ def do_at_generic_first_appt( if (individual_properties["age_years"] >= 5) or \ (individual_properties["un_am_treatment_type"] in - ['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']): + ['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']) or \ + (self.sim.date == df.at[person_id, 'un_last_nonemergency_appt_date']): if do_prints: print("not going through because") if individual_properties["age_years"] >= 5: @@ -697,10 +706,12 @@ def do_at_generic_first_appt( if individual_properties["un_am_treatment_type"] in \ ['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']: print(f',person currently treated, {individual_properties["un_am_treatment_type"]=}') + if self.sim.date == df.at[person_id, 'un_last_nonemergency_appt_date']: + print('the non-emerg. appt did went through today already') print("----------------------------------") return - # p = self.parameters + df.at[person_id, 'un_last_nonemergency_appt_date'] = self.sim.date # get the clinical states clinical_am = individual_properties['un_clinical_acute_malnutrition'] From 2b0d5eddff671812ccc18d5da54288ecbeeba35d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 25 Jan 2025 00:05:58 +0000 Subject: [PATCH 262/755] scenario_wast_min_model: 2010-2030(incl), 10K pop --- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 95f0423219..229ef3fff9 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -41,8 +41,8 @@ def __init__(self): super().__init__( seed=0, start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2011, month=1, day=1), - initial_population_size=2_000, + end_date=Date(year=2031, month=1, day=1), + initial_population_size=10_000, number_of_draws=1, runs_per_draw=1, ) From 68a839e0a484cd7f49ce048992c2c7b0f61622dc Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 25 Jan 2025 00:23:21 +0000 Subject: [PATCH 263/755] debugging-scenario_wast_min_model & wast: 2010-2030(incl), 5K pop, prints of person dying due to SAM while has MAM for 5K sim --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- src/tlo/methods/wasting.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 229ef3fff9..d1c06c5ea2 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=10_000, + initial_population_size=5_000, number_of_draws=1, runs_per_draw=1, ) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 055c8aebab..dc199c4642 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -246,7 +246,7 @@ def __init__(self, name=None, resourcefilepath=None): self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} - self.person_of_interest_id = 14238 # debugging + self.person_of_interest_id = 6193 # debugging def read_parameters(self, data_folder): """ From 56f9b6c603d9383e6ed88f3ee609f191352fafb0 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 26 Jan 2025 19:22:11 +0000 Subject: [PATCH 264/755] debugging-wast: print if a non emerg. appt tries to run again on the same date it already did for any person --- src/tlo/methods/wasting.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index dc199c4642..a5907a8fa3 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -709,6 +709,8 @@ def do_at_generic_first_appt( if self.sim.date == df.at[person_id, 'un_last_nonemergency_appt_date']: print('the non-emerg. appt did went through today already') print("----------------------------------") + if self.sim.date == df.at[person_id, 'un_last_nonemergency_appt_date']: + print(f"A non-emerg. appt tried to run again on the same date {self.sim.date=} for the {person_id=}.") return df.at[person_id, 'un_last_nonemergency_appt_date'] = self.sim.date From 94315036f2f0cec0278edc92fbd7df1bc8407f6b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 25 Jan 2025 00:05:58 +0000 Subject: [PATCH 265/755] scenario_wast_min_model: 2010-2030(incl), 10K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index d1c06c5ea2..229ef3fff9 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=5_000, + initial_population_size=10_000, number_of_draws=1, runs_per_draw=1, ) From bc02dec6cf61b6093821f763790f58e3e19d5856 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 26 Jan 2025 19:31:24 +0000 Subject: [PATCH 266/755] scenario_wast_min_model: 2010-2030(incl), 30K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 229ef3fff9..b581d68ff5 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=10_000, + initial_population_size=30_000, number_of_draws=1, runs_per_draw=1, ) From 0509d416d545f31cb10dbaa878f815814c710027 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 26 Jan 2025 22:31:33 +0000 Subject: [PATCH 267/755] scenario_wast_min_model & wast: debug wasting logs of non-emerg. appts that run more than once on the same date --- .../scenarios/scenario_wasting_minimal_model.py | 5 +++-- src/tlo/methods/wasting.py | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index b581d68ff5..91229342c2 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -52,9 +52,10 @@ def log_configuration(self): 'filename': 'wasting_analysis__minimal_model', 'directory': './outputs/wasting_analysis', "custom_levels": { # Customise the output of specific loggers - # "tlo.methods.demography": logging.INFO, # TODO: BACK after debugging + # "tlo.methods.demography": logging.INFO, + # TODO: the above BACK for final calibration of population (no needed for wasting itself) "tlo.methods.population": logging.INFO, - "tlo.methods.wasting": logging.INFO, + "tlo.methods.wasting": logging.DEBUG, '*': logging.WARNING } } diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index a5907a8fa3..ad6e8c5980 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -710,7 +710,11 @@ def do_at_generic_first_appt( print('the non-emerg. appt did went through today already') print("----------------------------------") if self.sim.date == df.at[person_id, 'un_last_nonemergency_appt_date']: - print(f"A non-emerg. appt tried to run again on the same date {self.sim.date=} for the {person_id=}.") + logger.debug( + key="non-emergency", + data=f"A non-emerg. appt runs again on the same date {self.sim.date=} for the {person_id=}. " + "All DOs related to wasting are cancelled, but other module's DOs might be issued repeatedly." + ) return df.at[person_id, 'un_last_nonemergency_appt_date'] = self.sim.date From ea450ba7549bb88cde05be14c5a9e813e0b20b9a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 27 Jan 2025 00:00:20 +0000 Subject: [PATCH 268/755] debugging-wast: person_of_interest_id updated --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index ad6e8c5980..72b46b7167 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -246,7 +246,7 @@ def __init__(self, name=None, resourcefilepath=None): self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} - self.person_of_interest_id = 6193 # debugging + self.person_of_interest_id = 31279 # debugging def read_parameters(self, data_folder): """ From 2deceb6103aeeaae3d86cbf512b11b93bb2058ec Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 27 Jan 2025 13:22:27 +0000 Subject: [PATCH 269/755] wast: non-emerg appt run only if wasting symptoms among symptoms; minor (comment/prints updates) --- src/tlo/methods/wasting.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 72b46b7167..4a712302e9 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -3,7 +3,7 @@ import copy from pathlib import Path -from typing import TYPE_CHECKING, Any, Dict, Union +from typing import TYPE_CHECKING, Any, Dict, List, Union import numpy as np import pandas as pd @@ -682,6 +682,7 @@ def wasting_clinical_symptoms(self, person_id): def do_at_generic_first_appt( self, person_id: int, + symptoms: List[str], individual_properties: IndividualProperties, schedule_hsi_event: HSIEventScheduler, **kwargs, @@ -695,19 +696,22 @@ def do_at_generic_first_appt( do_prints = True print(f"NON-EMERGENCY APPT on {self.sim.date=}") - if (individual_properties["age_years"] >= 5) or \ + if (self.wasting_symptom not in symptoms) or \ + (individual_properties["age_years"] >= 5) or \ (individual_properties["un_am_treatment_type"] in ['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']) or \ (self.sim.date == df.at[person_id, 'un_last_nonemergency_appt_date']): if do_prints: print("not going through because") + if self.wasting_symptom not in symptoms: + print(f"wasting symptom(s) not among this person's {symptoms=}") if individual_properties["age_years"] >= 5: - print(f'person not under 5, {individual_properties["age_years"]=}') - if individual_properties["un_am_treatment_type"] in \ + print(f"person not under 5, {individual_properties['age_years']=}") + if individual_properties['un_am_treatment_type'] in \ ['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']: - print(f',person currently treated, {individual_properties["un_am_treatment_type"]=}') + print(f",person currently treated, {individual_properties['un_am_treatment_type']=}") if self.sim.date == df.at[person_id, 'un_last_nonemergency_appt_date']: - print('the non-emerg. appt did went through today already') + print("the non-emerg. appt did went through today already") print("----------------------------------") if self.sim.date == df.at[person_id, 'un_last_nonemergency_appt_date']: logger.debug( @@ -1105,7 +1109,7 @@ def apply(self, person_id): print("----------------------------------") return - # # Check if this person should still die from SAM and it should happen now not in future: + # # Check if this person should still die from SAM and that it should happen now not in the future: if ( pd.isnull(df.at[person_id, 'un_am_recovery_date']) and not (df.at[person_id, 'un_am_discharge_date'] > df.at[person_id, 'un_am_tx_start_date']) and From 431f23a926d3b18b3f31b20599d347e9d05fb683 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 27 Jan 2025 13:56:16 +0000 Subject: [PATCH 270/755] wast: run non-emerg appt also if wasting symptoms not among symptoms (but just once) + print symptoms --- src/tlo/methods/wasting.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 4a712302e9..01247629a4 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -695,16 +695,14 @@ def do_at_generic_first_appt( if person_id == self.person_of_interest_id: do_prints = True print(f"NON-EMERGENCY APPT on {self.sim.date=}") + print(f"{symptoms=}") - if (self.wasting_symptom not in symptoms) or \ - (individual_properties["age_years"] >= 5) or \ + if (individual_properties["age_years"] >= 5) or \ (individual_properties["un_am_treatment_type"] in ['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']) or \ (self.sim.date == df.at[person_id, 'un_last_nonemergency_appt_date']): if do_prints: print("not going through because") - if self.wasting_symptom not in symptoms: - print(f"wasting symptom(s) not among this person's {symptoms=}") if individual_properties["age_years"] >= 5: print(f"person not under 5, {individual_properties['age_years']=}") if individual_properties['un_am_treatment_type'] in \ From 5f585ac5fe7db06e2908ff7321a531a43d9237b5 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 27 Jan 2025 14:13:59 +0000 Subject: [PATCH 271/755] wast: minor (debug log updated; prints updated) --- src/tlo/methods/wasting.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 01247629a4..a4238350fd 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -715,7 +715,7 @@ def do_at_generic_first_appt( logger.debug( key="non-emergency", data=f"A non-emerg. appt runs again on the same date {self.sim.date=} for the {person_id=}. " - "All DOs related to wasting are cancelled, but other module's DOs might be issued repeatedly." + "All DOs related to wasting are cancelled." ) return @@ -1771,9 +1771,9 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") if do_prints: - print("consumables not available, SFP tx not scheduled, should be picked up with next growth monitoring" - "if not naturally recovered in between or could be picked up with non-emergency appt if will " - "progress to SAM in between") + print("consumables not available, SFP tx not scheduled, should be picked up with next\n" + "growth monitoring if not naturally recovered in between or could be picked up\n" + "with non-emergency appt") if do_prints: print("-----------------------------------------------") @@ -1842,8 +1842,9 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") if do_prints: - print("consumables not available, OTP tx not scheduled, should be picked up with next growth monitoring" - " or non-emergency appt if not naturally recovered in between") + print("consumables not available, OTP tx not scheduled, should be picked up with next\n" + "growth monitoring or non-emergency appt if not naturally recovered or died in\n" + "between") if do_prints: print("----------------------OTP 2-------------------------") @@ -1905,8 +1906,9 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") if do_prints: - print("consumables not available, ITC tx not scheduled, should be picked up with next growth monitoring" - " or non-emergency appt if not naturally recovered in between") + print("consumables not available, ITC tx not scheduled, should be picked up with next\n" + "growth monitoring or non-emergency appt if not naturally recovered or died in\n" + "between") if do_prints: print("-----------------------------------------------") From 249935bb30219b522961c5f1e382e80192c1e10a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 28 Jan 2025 17:24:15 +0000 Subject: [PATCH 272/755] RF_Wasting: BACK death and recovery rates to allow test run properly --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 1376e2500e..225463d864 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6880f21971ba88b3e753b9bd83934df7f0900b4104ed4c38cfe4b73f1021169d -size 3659 +oid sha256:76d261eae1759a64cdf80e3af4aa82900048759462775da599e070e357b9f9d7 +size 3608 From 188c47f8689a2fc46234654d23297dc079c4fbf2 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 28 Jan 2025 22:56:54 +0000 Subject: [PATCH 273/755] wast: nat recov to follow the same path as recov w\ tx --- src/tlo/methods/wasting.py | 424 ++++++++++++++++--------------------- 1 file changed, 185 insertions(+), 239 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index a4238350fd..4199d63064 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -204,12 +204,12 @@ class Wasting(Module, GenericFirstAppointmentsMixin): categories=['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care'] + [ 'none', 'not_applicable']), # Properties to help cancel events - 'un_nat_recov_to_cancel': Property(Types.LIST, 'list of dates of scheduled natural recovery to be ' + 'un_recov_to_mam_to_cancel': Property(Types.LIST, 'list of dates of scheduled natural recovery to be ' 'canceled for the person'), + 'un_full_recov_to_cancel': Property(Types.LIST, 'list of dates of scheduled recovery with tx ' + 'to be canceled for the person'), 'un_progression_to_cancel': Property(Types.LIST, 'list of dates of scheduled progression to severe ' 'wasting to be canceled for the person'), - 'un_recov_with_tx_to_cancel': Property(Types.LIST, 'list of dates of scheduled recovery with tx ' - 'to be canceled for the person'), # Property to avoid double non-emergency appt on the same date 'un_last_nonemergency_appt_date': Property(Types.DATE, 'last date of generic non-emergency first ' 'appointment'), @@ -232,11 +232,13 @@ def __init__(self, name=None, resourcefilepath=None): _agrp: copy.deepcopy(blank_inc_counter) for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} self.wasting_incident_case_tracker = copy.deepcopy(self.wasting_incident_case_tracker_blank) - self.recovery_options = ['mod_nat_recov', + self.recovery_options = ['mod_MAM_nat_full_recov', + 'mod_SAM_nat_full_recov', 'mod_SAM_nat_recov_to_MAM', + 'sev_SAM_nat_full_recov', 'sev_SAM_nat_recov_to_MAM', 'mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', 'mod_SAM_tx_recov_to_MAM', - 'mod_not_yet_recovered', 'sev_SAM_tx_full_recov', 'sev_SAM_tx_recov_to_MAM', + 'mod_not_yet_recovered', 'sev_not_yet_recovered'] blank_length_counter = dict( zip(self.recovery_options, [list() for _ in self.recovery_options])) @@ -292,15 +294,14 @@ def initialise_population(self, population): # df.loc[df.is_alive, 'un_am_discharge_date'] = pd.NaT # df.loc[df.is_alive, 'un_am_tx_start_date'] = pd.NaT df.loc[df.is_alive, 'un_am_treatment_type'] = 'not_applicable' - df.loc[df.is_alive, 'un_nat_recov_to_cancel'] = \ - df.loc[df.is_alive, 'un_nat_recov_to_cancel'].apply(lambda x: []) + df.loc[df.is_alive, 'un_recov_to_mam_to_cancel'] = \ + df.loc[df.is_alive, 'un_recov_to_mam_to_cancel'].apply(lambda x: []) + df.loc[df.is_alive, 'un_full_recov_to_cancel'] = \ + df.loc[df.is_alive, 'un_full_recov_to_cancel'].apply(lambda x: []) df.loc[df.is_alive, 'un_progression_to_cancel'] = \ df.loc[df.is_alive, 'un_progression_to_cancel'].apply(lambda x: []) - df.loc[df.is_alive, 'un_recov_with_tx_to_cancel'] = \ - df.loc[df.is_alive, 'un_recov_with_tx_to_cancel'].apply(lambda x: []) # df.loc[df.is_alive, 'un_last_nonemergency_appt_date']= pd.NaT - # initialise wasting linear models. self.wasting_models = WastingModels(self) @@ -372,12 +373,11 @@ def on_birth(self, mother_id, child_id): # df.loc[df.is_alive, 'un_am_discharge_date'] = pd.NaT # df.loc[df.is_alive, 'un_am_tx_start_date'] = pd.NaT df.at[child_id, 'un_am_treatment_type'] = 'not_applicable' - df.at[child_id, 'un_nat_recov_to_cancel'] = [] + df.at[child_id, 'un_recov_to_mam_to_cancel'] = [] + df.at[child_id, 'un_full_recov_to_cancel'] = [] df.at[child_id, 'un_progression_to_cancel'] = [] - df.at[child_id, 'un_recov_with_tx_to_cancel'] = [] # df.at[child_id, 'un_last_nonemergency_appt_date']= pd.NaT - def get_prob_severe_wasting_among_wasted(self, agegp: str) -> Union[float, int]: """ This function will calculate the WHZ scores by categories and return probability of severe wasting @@ -639,7 +639,7 @@ def report_daly_values(self): experienced by persons in the previous month. Only rows for alive-persons must be returned. The names of the series of columns is taken to be the label of the cause of this disability. It will be recorded by the healthburden module as _. - :return: + :return: current daly values for everyone alive """ # Dict to hold the DALY weights daly_wts = dict() @@ -662,7 +662,7 @@ def report_daly_values(self): df.un_am_nutritional_oedema] = daly_wts['mod_wasting_with_oedema'] return total_daly_values - def wasting_clinical_symptoms(self, person_id): + def wasting_clinical_symptoms(self, person_id) -> None: """ assign clinical symptoms to new acute malnutrition cases :param person_id: @@ -766,7 +766,7 @@ def do_at_generic_first_appt( if do_prints: print("----------------end of non-ermerg appt-----------------------------") - def do_when_am_treatment(self, person_id, intervention): + def do_when_am_treatment(self, person_id, intervention) -> None: """ This function will apply the linear model of recovery based on intervention given :param person_id: @@ -779,21 +779,15 @@ def do_when_am_treatment(self, person_id, intervention): if person_id == self.person_of_interest_id: do_prints = True print(f"{self.person_of_interest_id=} RECEIVING TX on {self.sim.date=}") + + # Progression to severe wasting is cancelled due to the tx + self.cancel_event(person_id, event_type=Wasting_ProgressionToSevere_Event, due_to='tx', do_prints=do_prints) # Set the date when the treatment is provided: df.at[person_id, 'un_am_tx_start_date'] = self.sim.date # Reset tx discharge date df.at[person_id, 'un_am_discharge_date'] = pd.NaT # Cancel natural death due to SAM with tx df.at[person_id, 'un_sam_death_date'] = pd.NaT - # Cancel progression to sev wasting if scheduled - progress_event_tuple = next((event_tuple for event_tuple in self.sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], Wasting_ProgressionToSevere_Event)), None) - if progress_event_tuple: - progress_date = progress_event_tuple[0] - df.at[person_id, 'un_progression_to_cancel'].append(progress_date) - if do_prints: - print(f"progression to sev wasting on {progress_date=} is cancelled due to tx") - print(f"{df.at[person_id, 'un_progression_to_cancel']=}") if intervention == 'SFP': df.at[person_id, 'un_am_discharge_date'] = \ @@ -808,7 +802,7 @@ def do_when_am_treatment(self, person_id, intervention): if do_prints: print(f"scheduled full recovery from MAM with SFP at {df.at[person_id, 'un_am_discharge_date']=}") self.sim.schedule_event( - event=Wasting_ClinicalAcuteMalnutritionRecovery_Event(module=self, person_id=person_id), + event=Wasting_FullRecovery_Event(module=self, person_id=person_id), date=(df.at[person_id, 'un_am_discharge_date']) ) # cancel progression date (in ProgressionEvent) @@ -834,7 +828,7 @@ def do_when_am_treatment(self, person_id, intervention): if do_prints: print(f"scheduled full recovery from SAM with {intervention=} at {outcome_date=}") self.sim.schedule_event( - event=Wasting_ClinicalAcuteMalnutritionRecovery_Event(module=self, person_id=person_id), + event=Wasting_FullRecovery_Event(module=self, person_id=person_id), date=outcome_date ) @@ -856,7 +850,7 @@ def do_when_am_treatment(self, person_id, intervention): df.at[person_id, 'un_am_discharge_date'] = outcome_date if do_prints: print(f"recovery to MAM with {intervention=} scheduled at {outcome_date=} and sent for follow-up MAM tx") - self.sim.schedule_event(event=Wasting_UpdateToMAM_Event(module=self, person_id=person_id), + self.sim.schedule_event(event=Wasting_RecoveryToMAM_Event(module=self, person_id=person_id), date=outcome_date) self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), @@ -865,6 +859,59 @@ def do_when_am_treatment(self, person_id, intervention): if do_prints: print("---------------------------------------------------") + def cancel_event(self, person_id, event_type, due_to, do_prints: bool) -> None: + """ + This function will add dates of recovery and/or progression events that need to be canceled. + :param person_id: + :param event_type: which event type to cancel + :param due_to: due to what event are they cancelled + :param do_prints: prints for person_of_interest only + """ + + df = self.sim.population.props + + event_tuples = [event_tuple for event_tuple in self.sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], event_type)] + if event_tuples: + dates = [event_tuple[0] for event_tuple in event_tuples] + for date in dates: + if event_type == Wasting_RecoveryToMAM_Event: + df.at[person_id, 'un_recov_to_mam_to_cancel'].append(date) + elif event_type == Wasting_FullRecovery_Event: + df.at[person_id, 'un_full_recov_to_cancel'].append(date) + elif event_type == Wasting_ProgressionToSevere_Event: + df.at[person_id, 'un_progression_to_cancel'].append(date) + if do_prints: + print(f"an event {event_type} for " + f"clinical_am={df.at[person_id, 'un_clinical_acute_malnutrition']}, " + f"complications={df.at[person_id, 'un_sam_with_complications']} on {date=}\n" + f" is cancelled {due_to=} event") + today_rm = False + if event_type == due_to: + if event_type == Wasting_RecoveryToMAM_Event: + df.at[person_id, 'un_recov_to_mam_to_cancel'].remove(self.sim.date) + today_rm = True + elif event_type == Wasting_FullRecovery_Event: + df.at[person_id, 'un_full_recov_to_cancel'].remove(self.sim.date) + today_rm = True + elif event_type == Wasting_ProgressionToSevere_Event: + df.at[person_id, 'un_progression_to_cancel'].remove(self.sim.date) + today_rm = True + if do_prints and today_rm: + print(f"{self.sim.date=} is rm from the cancelled days") + else: + if do_prints: + print(f"no {event_type} scheduled, hence no need to cancel any") + + if do_prints: + if event_type == Wasting_RecoveryToMAM_Event: + print(f"{df.at[person_id, 'un_recov_to_mam_to_cancel']=}") + elif event_type == Wasting_FullRecovery_Event: + print(f"{df.at[person_id, 'un_full_recov_to_cancel']=}") + elif event_type == Wasting_ProgressionToSevere_Event: + print(f"{df.at[person_id, 'un_progression_to_cancel']=}") + + class PrintPersonPropertiesEventIfUpdated(RegularEvent, PopulationScopeEventMixin): def __init__(self, module, person_id): super().__init__(module, frequency=DateOffset(months=1)) @@ -986,13 +1033,22 @@ def apply(self, population): print(f"scheduled progression to sev wast at {outcome_date=}") # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # - # Schedule recovery from moderate wasting for those not progressing to severe wasting --------- + # Schedule recovery for those not progressing to severe wasting --------- for person_id in mod_wasting_new_cases_idx[~progression_severe_wasting]: - if person_id == self.module.person_of_interest_id: - print(f"scheduled natural recover to no wast at {outcome_date=}") - # schedule recovery after duration of moderate wasting - self.sim.schedule_event(event=Wasting_NaturalRecovery_Event( - module=self.module, person_id=person_id), date=outcome_date) + if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM': + # schedule full recovery after duration of moderate wasting + self.sim.schedule_event(event=Wasting_FullRecovery_Event( + module=self.module, person_id=person_id), date=outcome_date) + if person_id == self.module.person_of_interest_id: + print(f"scheduled natural full recovery at {outcome_date=} as the person has MAM: " + f"{df.at[person_id, 'un_clinical_acute_malnutrition']=}") + else: # == SAM + # schedule recovery to MAM after duration of moderate wasting + self.sim.schedule_event(event=Wasting_RecoveryToMAM_Event( + module=self.module, person_id=person_id), date=outcome_date) + if person_id == self.module.person_of_interest_id: + print(f"scheduled recovery to MAM at {outcome_date=} as the person has SAM: " + f"{df.at[person_id, 'un_clinical_acute_malnutrition']=}") if do_prints: print("---------------------------------") @@ -1070,12 +1126,12 @@ def apply(self, person_id): if pd.isnull(df.at[person_id, 'un_sam_death_date']): # # # SEVERE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # # - # Schedule recovery from severe wasting for those not dying due to SAM + # Schedule recovery tom MAM from SAM for those not dying due to SAM outcome_date = self.module.date_of_outcome_for_untreated_wasting(whz_category='WHZ<-3') - self.sim.schedule_event(event=Wasting_NaturalRecovery_Event( + self.sim.schedule_event(event=Wasting_RecoveryToMAM_Event( module=self.module, person_id=person_id), date=outcome_date) if do_prints: - print(f"natural recovery to mod wasting schuduled on {outcome_date=}") + print(f"natural recovery to MAM scheduled on {outcome_date=}") else: if do_prints: print("death due to SAM scheduled earlier") @@ -1143,12 +1199,9 @@ def apply(self, person_id): f"{df.at[person_id, 'un_am_tx_start_date']=}, {pd.isnull(df.at[person_id, 'un_sam_death_date'])=}") print("------------------------------------------------------") - -class Wasting_NaturalRecovery_Event(Event, IndividualScopeEventMixin): +class Wasting_FullRecovery_Event(Event, IndividualScopeEventMixin): """ - This event improves wasting by 1 SD, based on home care/improvement without interventions. - MUAC, oedema, clinical state of acute malnutrition, and if SAM complications are updated, - and symptoms cleared if not SAM. + This event sets acute malnutrition signs back to well state. """ def __init__(self, module, person_id): @@ -1158,114 +1211,16 @@ def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe p = self.module.parameters - do_prints = False - if person_id == self.module.person_of_interest_id: - do_prints = True - print(f"NATURAL RECOVERY on {self.sim.date=}") - - if ( - (not df.at[person_id, 'is_alive']) or - (df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2') or - (not pd.isnull(df.at[person_id, 'un_sam_death_date'])) - ): - if do_prints: - print("Natural recovery not going through because") - if not df.at[person_id, 'is_alive']: - print("the person is already dead") - if df.at[person_id, 'un_WHZ_category'] == 'WHZ>=-2': - print(f"the person is not wasted, {df.at[person_id, 'un_WHZ_category']=}") - if not pd.isnull(df.at[person_id, 'un_sam_death_date']): - print(f"death due to SAM is scheduled, {df.at[person_id, 'un_sam_death_date']=}") - print("----------------------------------") - return - - if self.sim.date in df.at[person_id, 'un_nat_recov_to_cancel']: - df.at[person_id, 'un_nat_recov_to_cancel'].remove(self.sim.date) - if do_prints: - print("Natural recovery canceled as person recovered from wasting due to tx before this day.") - print(f"{df.at[person_id, 'un_nat_recov_to_cancel']=}") - print("----------------------------------") - return - - if do_prints: - print("Natural recovery going through. The person is alive, still wasted, death due to SAM wasn't " - "scheduled, and is not treated yet, hence natural recovery not canceled.") - - whz = df.at[person_id, 'un_WHZ_category'] - if whz == '-3<=WHZ<-2': - # improve WHZ - df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished - age_group = self.module.age_grps.get(df.loc[person_id].age_years, '5+y') - wasted_days = (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days - assert wasted_days >= p['duration_of_untreated_mod_wasting'],\ - (f" The {person_id=} is wasted for {wasted_days=} which is less than " - f"{p['duration_of_untreated_mod_wasting']=} days when naturally recovers from mod. wasting at the " - f"{age_group=}.") - self.module.wasting_length_tracker[age_group]['mod_nat_recov'].append(wasted_days) - if do_prints: - print(f"from mod wasting, {age_group=}, {wasted_days=}") - + if pd.isnull(df.at[person_id, 'un_am_tx_start_date']): + recov_how = 'nat' else: - # whz == 'WHZ<-3' - # improve WHZ - df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' # moderate wasting - age_group = self.module.age_grps.get(df.loc[person_id].age_years, '5+y') - wasted_days = (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days - if do_prints: - print(f"from sev wasting, {age_group=}, {wasted_days=}") - - # update MUAC, oedema, clinical state of acute malnutrition and if SAM complications and death, - # clear symptoms if not SAM - self.module.clinical_signs_acute_malnutrition(person_id) - if do_prints: - print(f"assigned am indicators:\n" - f" {df.at[self.module.person_of_interest_id, 'un_WHZ_category']=}, " - f"{df.at[self.module.person_of_interest_id, 'un_am_nutritional_oedema']=},\n" - f" {df.at[self.module.person_of_interest_id, 'un_am_MUAC_category']=}") - print("determined am status and if SAM complications and death:\n" - f" {df.at[self.module.person_of_interest_id, 'un_clinical_acute_malnutrition']=}, " - f"{df.at[self.module.person_of_interest_id, 'un_sam_with_complications']=},\n" - f" {df.at[self.module.person_of_interest_id, 'un_sam_death_date']=}") - # set recovery date if recovered - if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well': - df.at[person_id, 'un_am_recovery_date'] = self.sim.date - df.at[person_id, 'un_sam_death_date'] = pd.NaT - recov_with_tx_event_tuple = \ - next((event_tuple for event_tuple in self.sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], (Wasting_ClinicalAcuteMalnutritionRecovery_Event, - Wasting_UpdateToMAM_Event) - )), None) - if recov_with_tx_event_tuple: - recov_with_tx_date = recov_with_tx_event_tuple[0] - df.at[person_id, 'un_recov_with_tx_to_cancel'].append(recov_with_tx_date) - if do_prints: - print(f"recovery with tx on {recov_with_tx_date=} is cancelled as already recovered now") - - if do_prints: - print(f"as the state is updated to well, {df.at[person_id, 'un_am_recovery_date']=} should be " - f"{self.sim.date=} and\n" - f" {df.at[person_id, 'un_sam_death_date']=} should be NaT") - - if do_prints: - print("---------------------------------------") - - -class Wasting_ClinicalAcuteMalnutritionRecovery_Event(Event, IndividualScopeEventMixin): - """ - This event sets wasting properties back to normal state. - """ - - def __init__(self, module, person_id): - super().__init__(module, person_id=person_id) - - def apply(self, person_id): - df = self.sim.population.props # shortcut to the dataframe - p = self.module.parameters + recov_how = 'tx' do_prints = False if person_id == self.module.person_of_interest_id: do_prints = True - print(f"FULL RECOVERY WITH TX on {self.sim.date=}") + print(f"FULL RECOVERY {recov_how=} on {self.sim.date=}") + print(f"{df.at[person_id, 'un_am_tx_start_date']=}") if not df.at[person_id, 'is_alive']: if do_prints: @@ -1273,36 +1228,51 @@ def apply(self, person_id): print("----------------------------------") return + # as person fully recovers from acute malnutrition, any other scheduled recovery events will be cancelled + self.module.cancel_event(person_id, event_type=Wasting_FullRecovery_Event, due_to=Wasting_FullRecovery_Event, + do_prints=do_prints) + self.module.cancel_event(person_id, event_type=Wasting_RecoveryToMAM_Event, due_to=Wasting_FullRecovery_Event, + do_prints=do_prints) + # if not well (i.e. NOT already fully recovered with SAM tx, and send here from follow-up MAM tx) if df.at[person_id, 'un_WHZ_category'] != 'WHZ>=-2': if df.at[person_id, 'un_WHZ_category'] == '-3<=WHZ<-2': - recov_opt = f"mod_{df.at[person_id, 'un_clinical_acute_malnutrition']}_tx_full_recov" + recov_opt = f"mod_{df.at[person_id, 'un_clinical_acute_malnutrition']}_{recov_how}_full_recov" else: # df.at[person_id, 'un_WHZ_category'] == 'WHZ<-3': - recov_opt = f"sev_{df.at[person_id, 'un_clinical_acute_malnutrition']}_tx_full_recov" + recov_opt = f"sev_{df.at[person_id, 'un_clinical_acute_malnutrition']}_{recov_how}_full_recov" age_group = self.module.age_grps.get(df.loc[person_id].age_years, '5+y') wasted_days = (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days - def get_tx_length(in_person_id): - if df.at[in_person_id, 'un_sam_with_complications']: - tx_length = p['tx_length_weeks_InpatientSAM'] - elif df.at[in_person_id, 'un_clinical_acute_malnutrition'] == 'SAM': - tx_length = p['tx_length_weeks_OutpatientSAM'] - else: # df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM': - tx_length = p['tx_length_weeks_SuppFeedingMAM'] - return tx_length - - assert wasted_days >= get_tx_length(person_id),\ - f" The {person_id=} is wasted less than tx_length= {get_tx_length(person_id)} weeks when {recov_opt=}." + def get_min_length(in_recov_how, in_person_id, in_whz): + if in_recov_how == 'tx': + if df.at[in_person_id, 'un_sam_with_complications']: + min_length = p['tx_length_weeks_InpatientSAM'] * 7 + elif df.at[in_person_id, 'un_clinical_acute_malnutrition'] == 'SAM': + min_length = p['tx_length_weeks_OutpatientSAM'] * 7 + else: # df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM': + min_length = p['tx_length_weeks_SuppFeedingMAM'] * 7 + else: # in_recov_how == 'nat' + if in_whz == '-3<=WHZ<-2': + min_length = p['duration_of_untreated_mod_wasting'] + else: # in_whz == 'WHZ<=-3' + min_length = p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] + return min_length + + whz = df.at[person_id, 'un_WHZ_category'] + assert wasted_days >= get_min_length(recov_how, person_id, whz),\ + (f" The {person_id=} is wasted less than min_length= {get_min_length(recov_how, person_id, whz)} days " + f"when {recov_opt=}.") self.module.wasting_length_tracker[age_group][recov_opt].append(wasted_days) if do_prints: - print(f"{recov_opt=}, {age_group=}, {wasted_days=} >= tx_length= {get_tx_length(person_id)} weeks") + print(f"{recov_opt=}, {age_group=}, {wasted_days=} >= min_length= " + f"{get_min_length(recov_how, person_id, whz)} days") df.at[person_id, 'un_am_recovery_date'] = self.sim.date - df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished - df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' - df.at[person_id, 'un_am_nutritional_oedema'] = False - df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' + df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # normal WHZ + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' # well-nourished + df.at[person_id, 'un_am_nutritional_oedema'] = False # no oedema + df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' # normal MUAC df.at[person_id, 'un_sam_with_complications'] = False df.at[person_id, 'un_sam_death_date'] = pd.NaT df.at[person_id, 'un_am_tx_start_date'] = pd.NaT @@ -1312,27 +1282,14 @@ def get_tx_length(in_person_id): self.sim.modules["SymptomManager"].clear_symptoms( person_id=person_id, disease_module=self.module ) - recov_event_tuple = next((event_tuple for event_tuple in self.sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], Wasting_NaturalRecovery_Event)), None) - if recov_event_tuple: - nat_recov_date = recov_event_tuple[0] - df.at[person_id, 'un_nat_recov_to_cancel'].append(nat_recov_date) - if do_prints: - print(f"natural recovery on {nat_recov_date=} is cancelled as already recovered now") - print(f"{df.at[person_id, 'un_nat_recov_to_cancel']=}") - else: - if do_prints: - print("no natural recovery scheduled, hence no need to cancel any " - f"{df.at[person_id, 'un_nat_recov_to_cancel']=}") if do_prints: print("recovered to well with all properties being set and SAM symptoms removed") print("-------------------------------------------------") -class Wasting_UpdateToMAM_Event(Event, IndividualScopeEventMixin): +class Wasting_RecoveryToMAM_Event(Event, IndividualScopeEventMixin): """ - This event updates the properties for those cases that remained/improved from SAM to MAM following - treatment + This event updates the clinical signs of acute malnutrition for those cases that improved from SAM to MAM. """ def __init__(self, module, person_id): @@ -1343,10 +1300,15 @@ def apply(self, person_id): rng = self.module.rng p = self.module.parameters + if pd.isnull(df.at[person_id, 'un_am_tx_start_date']): + recov_how = 'nat' + else: + recov_how = 'tx' + do_prints = False if person_id == self.module.person_of_interest_id: do_prints = True - print(f"RECOVERY TO MAM WITH TX on {self.sim.date=}") + print(f"RECOVERY TO MAM {recov_how=} on {self.sim.date=}") # if died or recovered in between, should not update to MAM if (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM'): @@ -1359,6 +1321,10 @@ def apply(self, person_id): print("----------------------------------") return + # as person recovered from SAM to MAM, any other scheduled recovery to MAM events will be cancelled + self.module.cancel_event(person_id, event_type=Wasting_RecoveryToMAM_Event, due_to=Wasting_RecoveryToMAM_Event, + do_prints=do_prints) + # For cases with normal WHZ and other acute malnutrition signs: # oedema, or low MUAC - do not change the WHZ whz = df.at[person_id, 'un_WHZ_category'] @@ -1376,70 +1342,43 @@ def apply(self, person_id): if mam_classification == 'mam_by_muac_only': if whz == '-3<=WHZ<-2': - recov_opt = "mod_SAM_tx_recov_to_MAM" + recov_opt = f"mod_SAM_{recov_how}_recov_to_MAM" else: # whz == 'WHZ<-3': - recov_opt = "sev_SAM_tx_recov_to_MAM" + recov_opt = f"sev_SAM_{recov_how}_recov_to_MAM" age_group = self.module.age_grps.get(df.loc[person_id].age_years, '5+y') wasted_days = (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days - def get_tx_length(in_person_id): - if df.at[in_person_id, 'un_sam_with_complications']: - tx_length = p['tx_length_weeks_InpatientSAM'] - else: # SAM without complications - tx_length = p['tx_length_weeks_OutpatientSAM'] - return tx_length - - assert wasted_days >= get_tx_length(person_id), \ - f" The {person_id=} is wasted less than tx_length= {get_tx_length(person_id)} weeks when {recov_opt=}." + def get_min_length(in_recov_how, in_person_id, in_whz): + if in_recov_how == 'tx': + if df.at[in_person_id, 'un_sam_with_complications']: + min_length = p['tx_length_weeks_InpatientSAM'] * 7 + else: # SAM without complications + min_length = p['tx_length_weeks_OutpatientSAM'] * 7 + else: # in_recov_how == 'nat' + if in_whz == '-3<=WHZ<-2': + min_length = p['duration_of_untreated_mod_wasting'] + else: # in_whz == 'WHZ<=-3' + min_length = p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] + return min_length + + + assert wasted_days >= get_min_length(recov_how, person_id, whz), \ + (f" The {person_id=} is wasted less than minimal expected length= " + f"{get_min_length(recov_how, person_id, whz)} days when {recov_opt=}.") self.module.wasting_length_tracker[age_group][recov_opt].append(wasted_days) - # wasting (WHZ) recovers to normal, therefore if natural recovery was scheduled - # (from moderate or severe wasting), it will be canceled - recov_event_tuple = next((event_tuple for event_tuple in self.sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], Wasting_NaturalRecovery_Event)), None) - if recov_event_tuple: - nat_recov_date = recov_event_tuple[0] - df.at[person_id, 'un_nat_recov_to_cancel'].append(nat_recov_date) - if do_prints: - print(f"natural recovery from {whz=} on {nat_recov_date=} is cancelled as wasting already " - f"recovered to normal now") df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' if do_prints: - print(f"{recov_opt=}, {age_group=}, {wasted_days=} >= tx_length= {get_tx_length(person_id)} weeks") + print(f"{recov_opt=}, {age_group=}, {wasted_days=} >= min_length= " + f"{get_min_length(recov_how, person_id, whz)} days") if mam_classification == 'mam_by_muac_and_whz': - # wasting (WHZ) recovers to moderate, therefore if natural recovery from severe wasting was scheduled, - # it will be cancelled, but if natural recovery from moderate wasting was scheduled, it will not be - # cancelled - if whz == 'WHZ<-3': - recov_event_tuple = next((event_tuple for event_tuple in self.sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], Wasting_NaturalRecovery_Event)), None) - if recov_event_tuple: - nat_recov_date = recov_event_tuple[0] - df.at[person_id, 'un_nat_recov_to_cancel'].append(nat_recov_date) - if do_prints: - print(f"natural recovery from {whz=} on {nat_recov_date=} is cancelled as wasting already " - f"recovered to moderate now") df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' if mam_classification == 'mam_by_whz_only': - # wasting (WHZ) recovers to moderate, therefore if natural recovery from severe wasting was scheduled, - # it will be cancelled, but if natural recovery from moderate wasting was scheduled, it will not be - # cancelled - if whz == 'WHZ<-3': - if do_prints: - print("wasting recovered to moderate") - recov_event_tuple = next((event_tuple for event_tuple in self.sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], Wasting_NaturalRecovery_Event)), None) - if recov_event_tuple: - nat_recov_date = recov_event_tuple[0] - df.at[person_id, 'un_nat_recov_to_cancel'].append(nat_recov_date) - if do_prints: - print(f"natural recovery from {whz=} on {nat_recov_date=} is cancelled as wasting already " - f"recovered to moderate now") df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' @@ -1447,6 +1386,7 @@ def get_tx_length(in_person_id): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' df.at[person_id, 'un_am_nutritional_oedema'] = False df.at[person_id, 'un_sam_with_complications'] = False + df.at[person_id, 'un_sam_death_date'] = pd.NaT # death is canceled if was scheduled df.at[person_id, 'un_am_tx_start_date'] = pd.NaT # Start without treatment, treatment will be applied with HSI if care sought df.at[person_id, 'un_am_treatment_type'] = 'none' @@ -2103,24 +2043,30 @@ def apply(self, population): length_df.loc[age_grp, recov_opt] = 0 assert not np.isnan(length_df.loc[age_grp, recov_opt]),\ f'There is an empty length for {age_grp=}, {recov_opt=}.' - if recov_opt == 'mod_nat_recov': + if recov_opt in ['mod_MAM_nat_full_recov', 'mod_SAM_nat_full_recov', 'mod_SAM_nat_recov_to_MAM']: assert all(length >= p['duration_of_untreated_mod_wasting'] for length in self.module.wasting_length_tracker[age_grp][recov_opt]),\ f"{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < "\ f"{p['duration_of_untreated_mod_wasting']=}; {age_grp=}, {recov_opt=}" - elif recov_opt in ['mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', 'sev_SAM_tx_full_recov', - 'mod_SAM_tx_recov_to_MAM', 'sev_SAM_tx_recov_to_MAM']: - min_tx_length = min(p['tx_length_weeks_SuppFeedingMAM'], p['tx_length_weeks_OutpatientSAM'], - p['tx_length_weeks_InpatientSAM']) + elif recov_opt in ['sev_SAM_nat_full_recov', 'sev_SAM_nat_recov_to_MAM']: + assert all(length >= + (p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting']) for + length in self.module.wasting_length_tracker[age_grp][recov_opt]),\ + f"{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < "\ + f"duration of (mod + sev wast): {p['duration_of_untreated_mod_wasting']} days;"\ + f"{age_grp=}, {recov_opt=}" + elif recov_opt in ['mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', 'mod_SAM_tx_recov_to_MAM', + 'sev_SAM_tx_full_recov', 'sev_SAM_tx_recov_to_MAM']: + if recov_opt == 'mod_MAM_tx_full_recov': + min_tx_length = p['tx_length_weeks_SuppFeedingMAM'] + else: + min_tx_length = min(p['tx_length_weeks_OutpatientSAM'], p['tx_length_weeks_InpatientSAM']) assert all(length >= min_tx_length for length in - self.module.wasting_length_tracker[age_grp][recov_opt]),\ - f'{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < '\ - f'{min_tx_length} weeks; {age_grp=}, {recov_opt=}' - - assert recov_opt in ['mod_nat_recov', 'mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', - 'sev_SAM_tx_full_recov', 'mod_SAM_tx_recov_to_MAM', 'sev_SAM_tx_recov_to_MAM', - 'mod_not_yet_recovered', 'sev_not_yet_recovered'], f'\nInvalid {recov_opt=}.' + self.module.wasting_length_tracker[age_grp][recov_opt]), \ + f'{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < ' \ + f'{min_tx_length=} weeks; {age_grp=}, {recov_opt=}' + assert recov_opt in self.module.recovery_options, f'\nInvalid {recov_opt=}.' # Reset the tracker self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) From 5a38d2da283fe53f04422ea414687442648bd7df Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 28 Jan 2025 22:59:33 +0000 Subject: [PATCH 274/755] Revert "RF_Wasting: BACK death and recovery rates to allow test run properly" This reverts commit 249935bb30219b522961c5f1e382e80192c1e10a. --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 225463d864..1376e2500e 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:76d261eae1759a64cdf80e3af4aa82900048759462775da599e070e357b9f9d7 -size 3608 +oid sha256:6880f21971ba88b3e753b9bd83934df7f0900b4104ed4c38cfe4b73f1021169d +size 3659 From f69b1d5e736f071a80eb5db83c7e00006f302bd3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 28 Jan 2025 23:50:00 +0000 Subject: [PATCH 275/755] wast: removal of date from to_cancel only if included --- src/tlo/methods/wasting.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 4199d63064..271f2c6eb5 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -889,16 +889,21 @@ def cancel_event(self, person_id, event_type, due_to, do_prints: bool) -> None: today_rm = False if event_type == due_to: if event_type == Wasting_RecoveryToMAM_Event: - df.at[person_id, 'un_recov_to_mam_to_cancel'].remove(self.sim.date) - today_rm = True + if self.sim.date in df.at[person_id, 'un_recov_to_mam_to_cancel']: + # TODO: why smt it is there, smt it is not? + df.at[person_id, 'un_recov_to_mam_to_cancel'].remove(self.sim.date) + today_rm = True elif event_type == Wasting_FullRecovery_Event: - df.at[person_id, 'un_full_recov_to_cancel'].remove(self.sim.date) - today_rm = True - elif event_type == Wasting_ProgressionToSevere_Event: - df.at[person_id, 'un_progression_to_cancel'].remove(self.sim.date) - today_rm = True - if do_prints and today_rm: - print(f"{self.sim.date=} is rm from the cancelled days") + if self.sim.date in df.at[person_id, 'un_full_recov_to_cancel']: + df.at[person_id, 'un_full_recov_to_cancel'].remove(self.sim.date) + today_rm = True + if do_prints: + print(f"{event_type=}, {due_to=}, {dates=}, {self.sim.date=}") + if today_rm: + print(f"{self.sim.date=} removed from to_cancel dates") + elif event_type != Wasting_ProgressionToSevere_Event: + print(f"{self.sim.date=} not included in to_cancel dates, hence no need to remove it") + else: if do_prints: print(f"no {event_type} scheduled, hence no need to cancel any") From 70ac3a5f1aa4cd3353b7ad9ecb1e42533f8aa1a5 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 29 Jan 2025 00:28:16 +0000 Subject: [PATCH 276/755] wast: assertion message updated --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 271f2c6eb5..b6562a814d 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1368,7 +1368,7 @@ def get_min_length(in_recov_how, in_person_id, in_whz): assert wasted_days >= get_min_length(recov_how, person_id, whz), \ - (f" The {person_id=} is wasted less than minimal expected length= " + (f" The {person_id=} is wasted {wasted_days=} < minimal expected length= " f"{get_min_length(recov_how, person_id, whz)} days when {recov_opt=}.") self.module.wasting_length_tracker[age_group][recov_opt].append(wasted_days) From 5269b35b69b278002b56fec19ed115b8165adedc Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 29 Jan 2025 00:28:32 +0000 Subject: [PATCH 277/755] debugging-wast: person_of_interest_id = 7212 --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index b6562a814d..83467d4000 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -248,7 +248,7 @@ def __init__(self, name=None, resourcefilepath=None): self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} - self.person_of_interest_id = 31279 # debugging + self.person_of_interest_id = 7212 # debugging def read_parameters(self, data_folder): """ From 57fcd40e814b083f86bac7f20ffd0a2e14432046 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 29 Jan 2025 11:51:36 +0000 Subject: [PATCH 278/755] wast: recovery cancellation fixed --- src/tlo/methods/wasting.py | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 83467d4000..dcc8ecb430 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -781,7 +781,8 @@ def do_when_am_treatment(self, person_id, intervention) -> None: print(f"{self.person_of_interest_id=} RECEIVING TX on {self.sim.date=}") # Progression to severe wasting is cancelled due to the tx - self.cancel_event(person_id, event_type=Wasting_ProgressionToSevere_Event, due_to='tx', do_prints=do_prints) + self.cancel_future_event(person_id, event_type=Wasting_ProgressionToSevere_Event, + due_to='tx', do_prints=do_prints) # Set the date when the treatment is provided: df.at[person_id, 'un_am_tx_start_date'] = self.sim.date # Reset tx discharge date @@ -859,7 +860,7 @@ def do_when_am_treatment(self, person_id, intervention) -> None: if do_prints: print("---------------------------------------------------") - def cancel_event(self, person_id, event_type, due_to, do_prints: bool) -> None: + def cancel_future_event(self, person_id, event_type, due_to, do_prints: bool) -> None: """ This function will add dates of recovery and/or progression events that need to be canceled. :param person_id: @@ -898,7 +899,7 @@ def cancel_event(self, person_id, event_type, due_to, do_prints: bool) -> None: df.at[person_id, 'un_full_recov_to_cancel'].remove(self.sim.date) today_rm = True if do_prints: - print(f"{event_type=}, {due_to=}, {dates=}, {self.sim.date=}") + print(f"{event_type=}; {due_to=}; {dates=}; {self.sim.date=}") if today_rm: print(f"{self.sim.date=} removed from to_cancel dates") elif event_type != Wasting_ProgressionToSevere_Event: @@ -1229,15 +1230,22 @@ def apply(self, person_id): if not df.at[person_id, 'is_alive']: if do_prints: - print("not going through, already dead") + print("not going through, because the person is already dead") + print("----------------------------------") + return + + if self.sim.date in df.at[person_id, 'un_full_recov_to_cancel']: + df.at[person_id, 'un_full_recov_to_cancel'].remove(self.sim.date) + if do_prints: + print("not going through, because the recovery was cancelled") print("----------------------------------") return # as person fully recovers from acute malnutrition, any other scheduled recovery events will be cancelled - self.module.cancel_event(person_id, event_type=Wasting_FullRecovery_Event, due_to=Wasting_FullRecovery_Event, - do_prints=do_prints) - self.module.cancel_event(person_id, event_type=Wasting_RecoveryToMAM_Event, due_to=Wasting_FullRecovery_Event, - do_prints=do_prints) + self.module.cancel_future_event(person_id, event_type=Wasting_FullRecovery_Event, + due_to=Wasting_FullRecovery_Event, do_prints=do_prints) + self.module.cancel_future_event(person_id, event_type=Wasting_RecoveryToMAM_Event, + due_to=Wasting_FullRecovery_Event, do_prints=do_prints) # if not well (i.e. NOT already fully recovered with SAM tx, and send here from follow-up MAM tx) if df.at[person_id, 'un_WHZ_category'] != 'WHZ>=-2': @@ -1326,9 +1334,16 @@ def apply(self, person_id): print("----------------------------------") return + if self.sim.date in df.at[person_id, 'un_recov_to_mam_to_cancel']: + df.at[person_id, 'un_recov_to_mam_to_cancel'].remove(self.sim.date) + if do_prints: + print("not going through, because the recovery was cancelled") + print("----------------------------------") + return + # as person recovered from SAM to MAM, any other scheduled recovery to MAM events will be cancelled - self.module.cancel_event(person_id, event_type=Wasting_RecoveryToMAM_Event, due_to=Wasting_RecoveryToMAM_Event, - do_prints=do_prints) + self.module.cancel_future_event(person_id, event_type=Wasting_RecoveryToMAM_Event, + due_to=Wasting_RecoveryToMAM_Event, do_prints=do_prints) # For cases with normal WHZ and other acute malnutrition signs: # oedema, or low MUAC - do not change the WHZ From 4c2d18d407d850c19e75f71d2d2bc160190778c4 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 29 Jan 2025 15:54:30 +0000 Subject: [PATCH 279/755] RF_Wasting: BACK death and recovery rates to get more reasonable outcomes --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 1376e2500e..225463d864 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6880f21971ba88b3e753b9bd83934df7f0900b4104ed4c38cfe4b73f1021169d -size 3659 +oid sha256:76d261eae1759a64cdf80e3af4aa82900048759462775da599e070e357b9f9d7 +size 3608 From e788cc0a40cb54b318f8d7c8f9637dcf3077836d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 29 Jan 2025 16:02:28 +0000 Subject: [PATCH 280/755] scenario_wast_min_model: 20K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 91229342c2..2816c0771d 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + initial_population_size=20_000, number_of_draws=1, runs_per_draw=1, ) From 3d0a38d85d229866e4986e2f63b1375ed90e8703 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 29 Jan 2025 16:24:01 +0000 Subject: [PATCH 281/755] scenario_wast_min_model: 4K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 2816c0771d..febd5f2ff0 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=20_000, + initial_population_size=4_000, number_of_draws=1, runs_per_draw=1, ) From 57663493bbc7c9af378292e84e33520099ae2835 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 29 Jan 2025 17:40:26 +0000 Subject: [PATCH 282/755] scenario_wast_min_model: 30K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index febd5f2ff0..91229342c2 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=1, runs_per_draw=1, ) From 01ece2475951c54aa6067360f041ca48013d7394 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 29 Jan 2025 17:44:29 +0000 Subject: [PATCH 283/755] wast: prints updated --- src/tlo/methods/wasting.py | 49 ++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index dcc8ecb430..ae1d576036 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -811,7 +811,7 @@ def do_when_am_treatment(self, person_id, intervention) -> None: # remained MAM if do_prints: print("remained MAM with SFP") - print("---------------------------------------------------") + print("------------------MAM tx -> remained MAM end---------------------------------") return elif intervention in ['OTP', 'ITC']: @@ -858,7 +858,7 @@ def do_when_am_treatment(self, person_id, intervention) -> None: priority=0, topen=outcome_date) if do_prints: - print("---------------------------------------------------") + print("---------------------------tx end------------------------") def cancel_future_event(self, person_id, event_type, due_to, do_prints: bool) -> None: """ @@ -889,21 +889,33 @@ def cancel_future_event(self, person_id, event_type, due_to, do_prints: bool) -> f" is cancelled {due_to=} event") today_rm = False if event_type == due_to: - if event_type == Wasting_RecoveryToMAM_Event: + if due_to == Wasting_RecoveryToMAM_Event: if self.sim.date in df.at[person_id, 'un_recov_to_mam_to_cancel']: # TODO: why smt it is there, smt it is not? df.at[person_id, 'un_recov_to_mam_to_cancel'].remove(self.sim.date) today_rm = True - elif event_type == Wasting_FullRecovery_Event: + elif due_to == Wasting_FullRecovery_Event: if self.sim.date in df.at[person_id, 'un_full_recov_to_cancel']: df.at[person_id, 'un_full_recov_to_cancel'].remove(self.sim.date) today_rm = True - if do_prints: - print(f"{event_type=}; {due_to=}; {dates=}; {self.sim.date=}") - if today_rm: - print(f"{self.sim.date=} removed from to_cancel dates") - elif event_type != Wasting_ProgressionToSevere_Event: - print(f"{self.sim.date=} not included in to_cancel dates, hence no need to remove it") + if do_prints: + print(f"{event_type=}; {due_to=};\n" + f" {dates=}; {self.sim.date=}") + if today_rm: + print(f"{self.sim.date=} removed from to_cancel dates") + else: + print(f"{self.sim.date=} not included in to_cancel dates, hence no need to remove it") + elif (event_type == Wasting_ProgressionToSevere_Event) and (due_to == 'tx'): + if self.sim.date in df.at[person_id, 'un_progression_to_cancel']: + df.at[person_id, 'un_progression_to_cancel'].remove(self.sim.date) + today_rm = True + if do_prints: + print(f"{event_type=}; {due_to=};\n" + f" {dates=}; {self.sim.date=}") + if today_rm: + print(f"{self.sim.date=} removed from to_cancel dates") + else: + print(f"{self.sim.date=} not included in to_cancel dates, hence no need to remove it") else: if do_prints: @@ -1115,13 +1127,14 @@ def apply(self, person_id): # - MUAC, oedema, clinical state of acute malnutrition, complications, death self.module.clinical_signs_acute_malnutrition(person_id) if do_prints: - print(f"assigned am indicators:\n {df.at[self.module.person_of_interest_id, 'un_WHZ_category']=}, " - f"{df.at[self.module.person_of_interest_id, 'un_am_nutritional_oedema']=}, " - f"{df.at[self.module.person_of_interest_id, 'un_am_MUAC_category']=}") + print("assigned am indicators:\n" + f" {df.at[self.module.person_of_interest_id, 'un_WHZ_category']=}, " + f"{df.at[self.module.person_of_interest_id, 'un_am_nutritional_oedema']=},\n" + f" {df.at[self.module.person_of_interest_id, 'un_am_MUAC_category']=}") print("determined am status and if SAM complications and death:\n" - f"{df.at[self.module.person_of_interest_id, 'un_clinical_acute_malnutrition']=}, " - f"{df.at[self.module.person_of_interest_id, 'un_sam_with_complications']=}, " - f"{df.at[self.module.person_of_interest_id, 'un_sam_death_date']=}") + f" {df.at[self.module.person_of_interest_id, 'un_clinical_acute_malnutrition']=}, " + f"{df.at[self.module.person_of_interest_id, 'un_sam_with_complications']=},\n" + f" {df.at[self.module.person_of_interest_id, 'un_sam_death_date']=}") # ------------------------------------------------------------------------------------------- # Add this severe wasting incident case to the tracker @@ -1775,7 +1788,7 @@ def apply(self, person_id, squeeze_factor): if not df.at[person_id, 'is_alive']: if do_prints: print("dead already, appt not going through") - print("--------------OTP 1-------------------") + print("--------------OTP end1-------------------") return # Do here whatever happens to an individual during this health @@ -1807,7 +1820,7 @@ def apply(self, person_id, squeeze_factor): "between") if do_prints: - print("----------------------OTP 2-------------------------") + print("----------------------OTP end2-------------------------") def did_not_run(self): logger.debug(key='debug', data=f'{self.TREATMENT_ID}: did not run') From 06944956698960284de000353a4814e055d58017 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 29 Jan 2025 17:45:20 +0000 Subject: [PATCH 284/755] debugging-wast: person_of_interest_id == 33272 for 30K pop sim --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index ae1d576036..cd3b5c9890 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -248,7 +248,7 @@ def __init__(self, name=None, resourcefilepath=None): self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} - self.person_of_interest_id = 7212 # debugging + self.person_of_interest_id = 33272 # debugging def read_parameters(self, data_folder): """ From e4b044b83b4e2b129b37a7826028f8ac28b2e04e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 29 Jan 2025 16:02:28 +0000 Subject: [PATCH 285/755] scenario_wast_min_model: 20K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 91229342c2..2816c0771d 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + initial_population_size=20_000, number_of_draws=1, runs_per_draw=1, ) From bafed10110512d22b776f22818956a919ac2306f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 30 Jan 2025 05:29:02 +0000 Subject: [PATCH 286/755] wast: fix wasting length asserts (correct min wasting length calc) --- src/tlo/methods/wasting.py | 89 +++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index cd3b5c9890..10afc4c1f6 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -235,9 +235,9 @@ def __init__(self, name=None, resourcefilepath=None): self.recovery_options = ['mod_MAM_nat_full_recov', 'mod_SAM_nat_full_recov', 'mod_SAM_nat_recov_to_MAM', 'sev_SAM_nat_full_recov', 'sev_SAM_nat_recov_to_MAM', - 'mod_MAM_tx_full_recov', - 'mod_SAM_tx_full_recov', 'mod_SAM_tx_recov_to_MAM', - 'sev_SAM_tx_full_recov', 'sev_SAM_tx_recov_to_MAM', + 'mod_MAM_tx/nat_full_recov', + 'mod_SAM_tx_full_recov', 'mod_SAM_tx/nat_recov_to_MAM', + 'sev_SAM_tx_full_recov', 'sev_SAM_tx/nat_recov_to_MAM', 'mod_not_yet_recovered', 'sev_not_yet_recovered'] blank_length_counter = dict( @@ -1233,7 +1233,10 @@ def apply(self, person_id): if pd.isnull(df.at[person_id, 'un_am_tx_start_date']): recov_how = 'nat' else: - recov_how = 'tx' + if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM': + recov_how = 'tx' + else: + recov_how = 'tx/nat' do_prints = False if person_id == self.module.person_of_interest_id: @@ -1270,23 +1273,25 @@ def apply(self, person_id): wasted_days = (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days def get_min_length(in_recov_how, in_person_id, in_whz): - if in_recov_how == 'tx': - if df.at[in_person_id, 'un_sam_with_complications']: - min_length = p['tx_length_weeks_InpatientSAM'] * 7 - elif df.at[in_person_id, 'un_clinical_acute_malnutrition'] == 'SAM': - min_length = p['tx_length_weeks_OutpatientSAM'] * 7 - else: # df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM': - min_length = p['tx_length_weeks_SuppFeedingMAM'] * 7 + if in_whz == '-3<=WHZ<-2': + min_length_nat = p['duration_of_untreated_mod_wasting'] + else: # in_whz == 'WHZ<=-3' + min_length_nat = p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] + if df.at[in_person_id, 'un_sam_with_complications']: + min_length_tx = p['tx_length_weeks_InpatientSAM'] * 7 + else: # SAM without complications + min_length_tx = p['tx_length_weeks_OutpatientSAM'] * 7 + if in_recov_how == 'tx/nat': + min_length = min(min_length_tx, min_length_nat) + elif in_recov_how == 'tx': + min_length = min_length_tx else: # in_recov_how == 'nat' - if in_whz == '-3<=WHZ<-2': - min_length = p['duration_of_untreated_mod_wasting'] - else: # in_whz == 'WHZ<=-3' - min_length = p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] + min_length = min_length_nat return min_length whz = df.at[person_id, 'un_WHZ_category'] assert wasted_days >= get_min_length(recov_how, person_id, whz),\ - (f" The {person_id=} is wasted less than min_length= {get_min_length(recov_how, person_id, whz)} days " + (f" The {person_id=} is {wasted_days=} < minimal expected length= {get_min_length(recov_how, person_id, whz)} days " f"when {recov_opt=}.") self.module.wasting_length_tracker[age_group][recov_opt].append(wasted_days) @@ -1329,7 +1334,7 @@ def apply(self, person_id): if pd.isnull(df.at[person_id, 'un_am_tx_start_date']): recov_how = 'nat' else: - recov_how = 'tx' + recov_how = 'tx/nat' do_prints = False if person_id == self.module.person_of_interest_id: @@ -1382,16 +1387,18 @@ def apply(self, person_id): wasted_days = (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days def get_min_length(in_recov_how, in_person_id, in_whz): - if in_recov_how == 'tx': + if in_whz == '-3<=WHZ<-2': + min_length_nat = p['duration_of_untreated_mod_wasting'] + else: # in_whz == 'WHZ<=-3' + min_length_nat = p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] + if in_recov_how == 'tx/nat': if df.at[in_person_id, 'un_sam_with_complications']: - min_length = p['tx_length_weeks_InpatientSAM'] * 7 + min_length_tx = p['tx_length_weeks_InpatientSAM'] * 7 else: # SAM without complications - min_length = p['tx_length_weeks_OutpatientSAM'] * 7 + min_length_tx = p['tx_length_weeks_OutpatientSAM'] * 7 + min_length = min(min_length_tx, min_length_nat) else: # in_recov_how == 'nat' - if in_whz == '-3<=WHZ<-2': - min_length = p['duration_of_untreated_mod_wasting'] - else: # in_whz == 'WHZ<=-3' - min_length = p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] + min_length = min_length_nat return min_length @@ -2058,7 +2065,7 @@ def apply(self, population): logger.info(key='wasting_incidence_count', data=inc_df.to_dict()) - # Reset the tracker and the date_last_run + # Reset the incidence tracker and the date_last_run self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) self.date_last_run = self.sim.date @@ -2088,21 +2095,33 @@ def apply(self, population): f"{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < "\ f"duration of (mod + sev wast): {p['duration_of_untreated_mod_wasting']} days;"\ f"{age_grp=}, {recov_opt=}" - elif recov_opt in ['mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', 'mod_SAM_tx_recov_to_MAM', - 'sev_SAM_tx_full_recov', 'sev_SAM_tx_recov_to_MAM']: - if recov_opt == 'mod_MAM_tx_full_recov': - min_tx_length = p['tx_length_weeks_SuppFeedingMAM'] - else: - min_tx_length = min(p['tx_length_weeks_OutpatientSAM'], p['tx_length_weeks_InpatientSAM']) - assert all(length >= min_tx_length for length in + elif recov_opt in ['mod_MAM_tx/nat_full_recov', 'mod_SAM_tx_full_recov', 'mod_SAM_tx/nat_recov_to_MAM', + 'sev_SAM_tx_full_recov', 'sev_SAM_tx/nat_recov_to_MAM']: + if recov_opt == 'mod_MAM_tx/nat_full_recov': + min_length = min( + (p['tx_length_weeks_SuppFeedingMAM'] * 7), p['duration_of_untreated_mod_wasting'] + ) + elif recov_opt in ['mod_SAM_tx_full_recov', 'sev_SAM_tx_full_recov']: + min_length = min(p['tx_length_weeks_OutpatientSAM'], p['tx_length_weeks_InpatientSAM']) * 7 + elif recov_opt == 'mod_SAM_tx/nat_recov_to_MAM': + min_length = min( + (p['tx_length_weeks_OutpatientSAM'] * 7), (p['tx_length_weeks_InpatientSAM'] * 7), + p['duration_of_untreated_mod_wasting'] + ) + else: # recov_opt == 'sev_SAM_tx/nat_recov_to_MAM' + min_length = min( + (p['tx_length_weeks_OutpatientSAM'] * 7), (p['tx_length_weeks_InpatientSAM'] * 7), + (p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting']) + ) + assert all(length >= min_length for length in self.module.wasting_length_tracker[age_grp][recov_opt]), \ f'{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < ' \ - f'{min_tx_length=} weeks; {age_grp=}, {recov_opt=}' + f'{min_length=} days; {age_grp=}, {recov_opt=}' assert recov_opt in self.module.recovery_options, f'\nInvalid {recov_opt=}.' - # Reset the tracker - self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) + # Reset the length tracker + self.module.wasting_length_tracker = copy.deepcopy(self.module.wasting_length_tracker_blank) under5s = df.loc[df.is_alive & (df.age_exact_years < 5)] above5s = df.loc[df.is_alive & (df.age_exact_years >= 5)] From 28dee2343294f2256f8c644664eb9816701f5abf Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 30 Jan 2025 05:42:07 +0000 Subject: [PATCH 287/755] wast: fix warnings --- src/tlo/methods/wasting.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 10afc4c1f6..be3403ca37 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -2146,9 +2146,11 @@ def apply(self, population): sev_wasted_whole_ys_agegrp = above5s[( above5s.un_WHZ_category == 'WHZ<-3' )] - mod_wasted_whole_ys_agegrp['wasting_length'] = \ + mod_wasted_whole_ys_agegrp = mod_wasted_whole_ys_agegrp.copy() + mod_wasted_whole_ys_agegrp.loc[:, 'wasting_length'] = \ (self.sim.date - mod_wasted_whole_ys_agegrp['un_last_wasting_date_of_onset']).dt.days - sev_wasted_whole_ys_agegrp['wasting_length'] = \ + sev_wasted_whole_ys_agegrp = sev_wasted_whole_ys_agegrp.copy() + sev_wasted_whole_ys_agegrp.loc[:, 'wasting_length'] = \ (self.sim.date - sev_wasted_whole_ys_agegrp['un_last_wasting_date_of_onset']).dt.days if len(mod_wasted_whole_ys_agegrp) > 0: assert not np.isnan(mod_wasted_whole_ys_agegrp['wasting_length']).any(),\ From 3708ef5c6d491e91ee6fe557d9fd8f69c559d3ce Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 30 Jan 2025 05:44:57 +0000 Subject: [PATCH 288/755] scenario_wast_min_model: 30K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 2816c0771d..91229342c2 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=20_000, + initial_population_size=30_000, number_of_draws=1, runs_per_draw=1, ) From 4bb166511331232e25c48adf5b0a83c1997dccd1 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 30 Jan 2025 06:04:15 +0000 Subject: [PATCH 289/755] scenario_wast_min_model: 20K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 91229342c2..2816c0771d 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + initial_population_size=20_000, number_of_draws=1, runs_per_draw=1, ) From 48ec5ac353e20d6183cfed6d8453aeaede9fdd40 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 30 Jan 2025 06:05:24 +0000 Subject: [PATCH 290/755] debugging-wast: person_of_interest_id == 21987 for 20K pop sim --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index be3403ca37..ed76ff605e 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -248,7 +248,7 @@ def __init__(self, name=None, resourcefilepath=None): self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} - self.person_of_interest_id = 33272 # debugging + self.person_of_interest_id = 21987 # debugging def read_parameters(self, data_folder): """ From 6f33e5c048c161d96546bc1d1cd4674c8724cca5 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 30 Jan 2025 06:11:22 +0000 Subject: [PATCH 291/755] scenario_wast_min_model: BACK demography logs --- .../scenarios/scenario_wasting_minimal_model.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 2816c0771d..3bf08bfd76 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -52,8 +52,7 @@ def log_configuration(self): 'filename': 'wasting_analysis__minimal_model', 'directory': './outputs/wasting_analysis', "custom_levels": { # Customise the output of specific loggers - # "tlo.methods.demography": logging.INFO, - # TODO: the above BACK for final calibration of population (no needed for wasting itself) + "tlo.methods.demography": logging.INFO, "tlo.methods.population": logging.INFO, "tlo.methods.wasting": logging.DEBUG, '*': logging.WARNING From 192ab07e5ea5e0169eee585984647e693825fb5f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 30 Jan 2025 06:19:48 +0000 Subject: [PATCH 292/755] scenario_wast_min_model: 10K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 3bf08bfd76..c2a9bd73b7 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=20_000, + initial_population_size=10_000, number_of_draws=1, runs_per_draw=1, ) From 3feb6a419cf38b40da9d248ccc756d301bef00fe Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 30 Jan 2025 06:45:02 +0000 Subject: [PATCH 293/755] scenario_wast_min_model: 30K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index c2a9bd73b7..3e1072d48a 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=10_000, + initial_population_size=30_000, number_of_draws=1, runs_per_draw=1, ) From 3179b1232c09c4b90e519c400fea4b34f6b26130 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 30 Jan 2025 11:57:37 +0000 Subject: [PATCH 294/755] RF_Wast: update inc rates according to [Maleta et al 2003] --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 225463d864..44c1e9e08e 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:76d261eae1759a64cdf80e3af4aa82900048759462775da599e070e357b9f9d7 -size 3608 +oid sha256:57e851f33e596f9149411238e2c08fdfb9fae7b8ad71f340567971516cf06305 +size 3626 From 1848d1657da0a7700c9654e3ac326dcf03785e09 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 30 Jan 2025 12:00:56 +0000 Subject: [PATCH 295/755] wast: not allow new inc if has MAM/SAM --- src/tlo/methods/wasting.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index ed76ff605e..984bedc44d 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -764,7 +764,7 @@ def do_at_generic_first_appt( priority=0, topen=self.sim.date) if do_prints: - print("----------------end of non-ermerg appt-----------------------------") + print("----------------end of non-ermerg appt-----------------------------") def do_when_am_treatment(self, person_id, intervention) -> None: """ @@ -997,10 +997,10 @@ def apply(self, population): # # # INCIDENCE OF MODERATE WASTING # # # # # # # # # # # # # # # # # # # # # # Determine who will be onset with wasting among those who are not currently wasted ------------- - not_wasted_or_treated = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_WHZ_category == 'WHZ>=-2') & - (df.un_am_tx_start_date.isna())] - incidence_of_wasting = self.module.wasting_models.wasting_incidence_lm.predict(not_wasted_or_treated, rng=rng) - mod_wasting_new_cases = not_wasted_or_treated.loc[incidence_of_wasting] + not_am_or_treated = df.loc[df.is_alive & (df.age_exact_years < 5) & + (df.un_clinical_acute_malnutrition == 'well') & (df.un_am_tx_start_date.isna())] + incidence_of_wasting = self.module.wasting_models.wasting_incidence_lm.predict(not_am_or_treated, rng=rng) + mod_wasting_new_cases = not_am_or_treated.loc[incidence_of_wasting] mod_wasting_new_cases_idx = mod_wasting_new_cases.index # update the properties for new cases of wasted children df.loc[mod_wasting_new_cases_idx, 'un_ever_wasted'] = True From 3ff055f2d77e60924106c3f485cac3eddaf173bf Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 30 Jan 2025 12:01:25 +0000 Subject: [PATCH 296/755] scenario_wast_min_model: 4K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 3e1072d48a..6743a6faa5 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + initial_population_size=4_000, number_of_draws=1, runs_per_draw=1, ) From 658cc7598f7d7307299a11682064119254743544 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 30 Jan 2025 12:48:38 +0000 Subject: [PATCH 297/755] scenario_wast_min_model: 10K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 6743a6faa5..c2a9bd73b7 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=10_000, number_of_draws=1, runs_per_draw=1, ) From c7d521831c2717cd4191e17098911264a118707e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 30 Jan 2025 12:57:25 +0000 Subject: [PATCH 298/755] scenario_wast_min_model: 20K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index c2a9bd73b7..3bf08bfd76 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=10_000, + initial_population_size=20_000, number_of_draws=1, runs_per_draw=1, ) From 7c887fc6ff286cd2d46c34335a9b043577c8f0ea Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 31 Jan 2025 11:55:49 +0000 Subject: [PATCH 299/755] scenario_wast_min_model & wast: pop_size = 30K, person_of_interest = 33272 for 30K sim --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- src/tlo/methods/wasting.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 3bf08bfd76..3e1072d48a 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=20_000, + initial_population_size=30_000, number_of_draws=1, runs_per_draw=1, ) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 984bedc44d..e1bb2ab9c5 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -248,7 +248,7 @@ def __init__(self, name=None, resourcefilepath=None): self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} - self.person_of_interest_id = 21987 # debugging + self.person_of_interest_id = 33272 # debugging def read_parameters(self, data_folder): """ From 84064ecd12538a0528c0926dee80f80631261c6c Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 31 Jan 2025 17:34:58 +0000 Subject: [PATCH 300/755] scenario_wast_min_model: multiple draws --- .../scenario_wasting_minimal_model.py | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 3e1072d48a..31dd7bd1ae 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -9,7 +9,7 @@ tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py """ -# import itertools +import itertools import warnings from tlo import Date, logging @@ -43,7 +43,7 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=30_000, - number_of_draws=1, + number_of_draws=5*5*5*4, runs_per_draw=1, ) @@ -79,35 +79,35 @@ def modules(self): stunting.Stunting(resourcefilepath=self.resources), wasting.Wasting(resourcefilepath=self.resources)] - def draw_parameters(self, draw_number, rng): - # Using default parameters in all cases - return {} - # def draw_parameters(self, draw_number, rng): - # base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] - # mod_wast_incidence__coef = [1, 5, 10, 15, 20] - # base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] - # progression_to_sev_wast__coef = [1, 5, 10, 15, 20] - # progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] - # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] - # - # pars_combinations = list(itertools.product( - # base_death_rate_untreated_sam__draws, - # mod_wast_incidence__coef, - # progression_to_sev_wast__coef, - # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam - # )) - # return { - # 'Wasting': { - # 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], - # 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ - # s in base_inc_rate_wasting_props_by_agegp], - # 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ - # s in progression_severe_wasting_monthly_props_by_agegp], - # 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / - # (1-0.738)) - # } - # } + # # Using default parameters in all cases + # return {} + + def draw_parameters(self, draw_number, rng): + base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] + mod_wast_incidence__coef = [0.1, 0.3, 0.5, 0.7, 0.9] + base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] + progression_to_sev_wast__coef = [1, 5, 10, 15, 20] + progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] + + pars_combinations = list(itertools.product( + base_death_rate_untreated_sam__draws, + mod_wast_incidence__coef, + progression_to_sev_wast__coef, + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam + )) + return { + 'Wasting': { + 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], + 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ + s in base_inc_rate_wasting_props_by_agegp], + 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ + s in progression_severe_wasting_monthly_props_by_agegp], + 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / + (1-0.738)) + } + } if __name__ == '__main__': From 6ad506bf38810f7b8bb40bb1a97436421978e0f8 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 31 Jan 2025 18:45:30 +0000 Subject: [PATCH 301/755] wast: added prints of some parameters set --- src/tlo/methods/wasting.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index e1bb2ab9c5..5f0d10dde5 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -269,6 +269,17 @@ def read_parameters(self, data_folder): ) # Adjust monthly severe wasting incidence to the duration of untreated moderate wasting p = self.parameters + print(f"\nPARAMETERS:") + print(f"{p['base_death_rate_untreated_SAM']=}") + print(f"mod_wast_incidence__coef={p['base_inc_rate_wasting_by_agegp'][0]/0.0023}") + print(f"progression_to_sev_wast__coef={p['progression_severe_wasting_monthly_by_agegp'][0]/0.0027}") + print("prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam=" + f"{p['prob_death_after_SAMcare']*(1-0.738)/p['base_death_rate_untreated_SAM']}") + print("-----------") + print(f"{p['base_inc_rate_wasting_by_agegp']=}") + print(f"{p['progression_severe_wasting_monthly_by_agegp']=}") + print(f"{p['prob_death_after_SAMcare']=}") + p['progression_severe_wasting_by_agegp'] = \ [s/30*p['duration_of_untreated_mod_wasting'] for s in p['progression_severe_wasting_monthly_by_agegp']] From 28dc6d4e757add1d92c2d5ee0eadb8e125d1a79a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 31 Jan 2025 18:48:19 +0000 Subject: [PATCH 302/755] wast: person_of_interest=7744 --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 5f0d10dde5..8b91bcd9df 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -248,7 +248,7 @@ def __init__(self, name=None, resourcefilepath=None): self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} - self.person_of_interest_id = 33272 # debugging + self.person_of_interest_id = 7744 # debugging def read_parameters(self, data_folder): """ From 83dee2f1f01eaf6cd602de21f14cba44e4885dc6 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 31 Jan 2025 22:03:10 +0000 Subject: [PATCH 303/755] wast: no growth monitoring if currently on tx, only scheduled next monitoring --- src/tlo/methods/wasting.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 8b91bcd9df..0953e26cd8 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1560,7 +1560,7 @@ def apply(self, person_id, squeeze_factor): # or # df.at[person_id, 'un_am_treatment_type'].isin(['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']): if do_prints: - print("not going through because") + print("not going through and no more monitoring scheduled because") if not df.at[person_id, 'is_alive']: print("already dead") if df.at[person_id, 'age_exact_years'] >= 5: @@ -1596,6 +1596,14 @@ def get_monitoring_frequency_days(age): # TODO: as stated above, for now we schedule next monitoring for all children, even those sent for treatment schedule_next_monitoring() + # but if they are currently treated, the growth monitoring will not go through + # TODO: later will be scheduled for monitoring within the tx to use the resources + if (df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[person_id, 'un_am_tx_start_date'] < + self.sim.date): + if do_prints: + print("not going through because is currently treated") + return + if not self.attendance: if do_prints: print("does not attend to this growth monitoring appt") From 597030c109efeb6370fb44fceb5693c01a670c70 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 4 Feb 2025 19:02:00 +0000 Subject: [PATCH 304/755] wast: person_of_interest=3219 --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 0953e26cd8..2e24b0a12c 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -248,7 +248,7 @@ def __init__(self, name=None, resourcefilepath=None): self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} - self.person_of_interest_id = 7744 # debugging + self.person_of_interest_id = 3219 # debugging def read_parameters(self, data_folder): """ From 683ac4076458fac378255fb071920126bbb847a1 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 4 Feb 2025 20:25:15 +0000 Subject: [PATCH 305/755] debugging-scenario_wast_min_model: pars set to get assertion error for person_id=3219 --- .../scenario_wasting_minimal_model.py | 58 +++++++++++-------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 31dd7bd1ae..3fb28065fb 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -43,7 +43,7 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=30_000, - number_of_draws=5*5*5*4, + number_of_draws=1, runs_per_draw=1, ) @@ -79,37 +79,45 @@ def modules(self): stunting.Stunting(resourcefilepath=self.resources), wasting.Wasting(resourcefilepath=self.resources)] - # def draw_parameters(self, draw_number, rng): - # # Using default parameters in all cases - # return {} - def draw_parameters(self, draw_number, rng): - base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] - mod_wast_incidence__coef = [0.1, 0.3, 0.5, 0.7, 0.9] - base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] - progression_to_sev_wast__coef = [1, 5, 10, 15, 20] - progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] - - pars_combinations = list(itertools.product( - base_death_rate_untreated_sam__draws, - mod_wast_incidence__coef, - progression_to_sev_wast__coef, - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam - )) + # Using default parameters in all cases return { 'Wasting': { - 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], - 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ - s in base_inc_rate_wasting_props_by_agegp], - 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ - s in progression_severe_wasting_monthly_props_by_agegp], - 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / - (1-0.738)) + 'base_death_rate_untreated_SAM': 0.17, + 'base_inc_rate_wasting_by_agegp': [0.0023, 0.0099, 0.0189, 0.0102, 0.003, 0.002], + 'progression_severe_wasting_monthly_by_agegp': [0.0027, 0.0036, 0.0079, 0.0053, 0.0025, 0.002], + 'prob_death_after_SAMcare': 0.324427480916031 } } + # def draw_parameters(self, draw_number, rng): + # base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] + # mod_wast_incidence__coef = [0.1, 0.3, 0.5, 0.7, 0.9] + # base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] + # progression_to_sev_wast__coef = [1, 5, 10, 15, 20] + # progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] + # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] + # + # pars_combinations = list(itertools.product( + # base_death_rate_untreated_sam__draws, + # mod_wast_incidence__coef, + # progression_to_sev_wast__coef, + # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam + # )) + # return { + # 'Wasting': { + # 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], + # 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ + # s in base_inc_rate_wasting_props_by_agegp], + # 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ + # s in progression_severe_wasting_monthly_props_by_agegp], + # 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / + # (1-0.738)) + # } + # } + + if __name__ == '__main__': from tlo.cli import scenario_run From f6fe44a46c772cfcd06cb882160033d7c2ab2d63 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 4 Feb 2025 22:18:48 +0000 Subject: [PATCH 306/755] debugging-scenario_wast_min_model: pars set to default, should get assertion error for person_id=3219 in 6min --- .../scenarios/scenario_wasting_minimal_model.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 3fb28065fb..146f5fdeb4 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -9,7 +9,7 @@ tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py """ -import itertools +# import itertools import warnings from tlo import Date, logging @@ -82,12 +82,12 @@ def modules(self): def draw_parameters(self, draw_number, rng): # Using default parameters in all cases return { - 'Wasting': { - 'base_death_rate_untreated_SAM': 0.17, - 'base_inc_rate_wasting_by_agegp': [0.0023, 0.0099, 0.0189, 0.0102, 0.003, 0.002], - 'progression_severe_wasting_monthly_by_agegp': [0.0027, 0.0036, 0.0079, 0.0053, 0.0025, 0.002], - 'prob_death_after_SAMcare': 0.324427480916031 - } + # 'Wasting': { + # 'base_death_rate_untreated_SAM': 0.17, + # 'base_inc_rate_wasting_by_agegp': [0.0023, 0.0099, 0.0189, 0.0102, 0.003, 0.002], + # 'progression_severe_wasting_monthly_by_agegp': [0.0027, 0.0036, 0.0079, 0.0053, 0.0025, 0.002], + # 'prob_death_after_SAMcare': 0.324427480916031 + # } } From baaa48685e1ea23d8aa47f8f3bdef762ea19df6e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 5 Feb 2025 10:25:30 +0000 Subject: [PATCH 307/755] debugging-wast: print used parameters only when they were updated for the draw --- src/tlo/methods/wasting.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 2e24b0a12c..305a57e7c9 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -267,9 +267,18 @@ def read_parameters(self, data_folder): odds_ratio_health_seeking_in_children=20.0, ) ) - # Adjust monthly severe wasting incidence to the duration of untreated moderate wasting + + def initialise_population(self, population): + """ + Set our property values for the initial population. This method is called by the simulation when creating + the initial population, and is responsible for assigning initial values, for every individual, + of those properties 'owned' by this module, i.e. those declared in the PROPERTIES dictionary above. + + :param population: + """ + df = population.props p = self.parameters - print(f"\nPARAMETERS:") + print("\nPARAMETERS:") print(f"{p['base_death_rate_untreated_SAM']=}") print(f"mod_wast_incidence__coef={p['base_inc_rate_wasting_by_agegp'][0]/0.0023}") print(f"progression_to_sev_wast__coef={p['progression_severe_wasting_monthly_by_agegp'][0]/0.0027}") @@ -280,19 +289,10 @@ def read_parameters(self, data_folder): print(f"{p['progression_severe_wasting_monthly_by_agegp']=}") print(f"{p['prob_death_after_SAMcare']=}") + # Adjust monthly severe wasting incidence to the duration of untreated moderate wasting p['progression_severe_wasting_by_agegp'] = \ [s/30*p['duration_of_untreated_mod_wasting'] for s in p['progression_severe_wasting_monthly_by_agegp']] - def initialise_population(self, population): - """ - Set our property values for the initial population. This method is called by the simulation when creating - the initial population, and is responsible for assigning initial values, for every individual, - of those properties 'owned' by this module, i.e. those declared in the PROPERTIES dictionary above. - - :param population: - """ - df = population.props - # Set initial properties df.loc[df.is_alive, 'un_ever_wasted'] = False df.loc[df.is_alive, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished From 51ebb3b8fbba5a1e6e4c89d4d5a64a3fa4576f82 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 5 Feb 2025 10:27:17 +0000 Subject: [PATCH 308/755] scenario_wast_min_model: multiple pars draws (death and incidence rates) --- .../scenario_wasting_minimal_model.py | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 146f5fdeb4..304ca83353 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -9,7 +9,7 @@ tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py """ -# import itertools +import itertools import warnings from tlo import Date, logging @@ -79,45 +79,45 @@ def modules(self): stunting.Stunting(resourcefilepath=self.resources), wasting.Wasting(resourcefilepath=self.resources)] - def draw_parameters(self, draw_number, rng): - # Using default parameters in all cases - return { - # 'Wasting': { - # 'base_death_rate_untreated_SAM': 0.17, - # 'base_inc_rate_wasting_by_agegp': [0.0023, 0.0099, 0.0189, 0.0102, 0.003, 0.002], - # 'progression_severe_wasting_monthly_by_agegp': [0.0027, 0.0036, 0.0079, 0.0053, 0.0025, 0.002], - # 'prob_death_after_SAMcare': 0.324427480916031 - # } - } - - # def draw_parameters(self, draw_number, rng): - # base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] - # mod_wast_incidence__coef = [0.1, 0.3, 0.5, 0.7, 0.9] - # base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] - # progression_to_sev_wast__coef = [1, 5, 10, 15, 20] - # progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] - # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] - # - # pars_combinations = list(itertools.product( - # base_death_rate_untreated_sam__draws, - # mod_wast_incidence__coef, - # progression_to_sev_wast__coef, - # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam - # )) + # # Using default parameters in all cases # return { # 'Wasting': { - # 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], - # 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ - # s in base_inc_rate_wasting_props_by_agegp], - # 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ - # s in progression_severe_wasting_monthly_props_by_agegp], - # 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / - # (1-0.738)) + # 'base_death_rate_untreated_SAM': 0.17, + # 'base_inc_rate_wasting_by_agegp': [0.0023, 0.0099, 0.0189, 0.0102, 0.003, 0.002], + # 'progression_severe_wasting_monthly_by_agegp': [0.0027, 0.0036, 0.0079, 0.0053, 0.0025, 0.002], + # 'prob_death_after_SAMcare': 0.17 * 0.5 # } # } + def draw_parameters(self, draw_number, rng): + base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] + mod_wast_incidence__coef = [0.1, 0.3, 0.5, 0.7, 0.9] + base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] + progression_to_sev_wast__coef = [1, 5, 10, 15, 20] + progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] + + pars_combinations = list(itertools.product( + base_death_rate_untreated_sam__draws, + mod_wast_incidence__coef, + progression_to_sev_wast__coef, + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam + )) + return { + 'Wasting': { + 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], + 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ + s in base_inc_rate_wasting_props_by_agegp], + 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ + s in progression_severe_wasting_monthly_props_by_agegp], + 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / + (1-0.738)) + } + } + + if __name__ == '__main__': from tlo.cli import scenario_run From a683e9b4419b805d13140a5d1cf5407b2cb8bbb3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 5 Feb 2025 10:39:30 +0000 Subject: [PATCH 309/755] scenario_wast_min_model: 1 draw to replicate task 175 --- .../scenario_wasting_minimal_model.py | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 304ca83353..8abde0f637 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -90,14 +90,13 @@ def modules(self): # } # } - def draw_parameters(self, draw_number, rng): - base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] - mod_wast_incidence__coef = [0.1, 0.3, 0.5, 0.7, 0.9] + base_death_rate_untreated_sam__draws = [0.03] + mod_wast_incidence__coef = [0.7] base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] - progression_to_sev_wast__coef = [1, 5, 10, 15, 20] + progression_to_sev_wast__coef = [15] progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.55] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, @@ -117,6 +116,32 @@ def draw_parameters(self, draw_number, rng): } } + # def draw_parameters(self, draw_number, rng): + # base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] + # mod_wast_incidence__coef = [0.1, 0.3, 0.5, 0.7, 0.9] + # base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] + # progression_to_sev_wast__coef = [1, 5, 10, 15, 20] + # progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] + # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] + # + # pars_combinations = list(itertools.product( + # base_death_rate_untreated_sam__draws, + # mod_wast_incidence__coef, + # progression_to_sev_wast__coef, + # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam + # )) + # return { + # 'Wasting': { + # 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], + # 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ + # s in base_inc_rate_wasting_props_by_agegp], + # 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ + # s in progression_severe_wasting_monthly_props_by_agegp], + # 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / + # (1-0.738)) + # } + # } + if __name__ == '__main__': from tlo.cli import scenario_run From e1f6a28ba262f13b857478ca738fbc52e05dbfa3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 5 Feb 2025 11:18:27 +0000 Subject: [PATCH 310/755] scenario_wast_min_model: fix the indexes in pars draws --- .../scenarios/scenario_wasting_minimal_model.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 8abde0f637..aba407aec2 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -106,12 +106,12 @@ def draw_parameters(self, draw_number, rng): )) return { 'Wasting': { - 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], - 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ + 'base_death_rate_untreated_SAM': pars_combinations[draw_number-1][0], + 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number-1][1] for \ s in base_inc_rate_wasting_props_by_agegp], - 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ + 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number-1][2] for \ s in progression_severe_wasting_monthly_props_by_agegp], - 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / + 'prob_death_after_SAMcare': ((pars_combinations[draw_number-1][0] * pars_combinations[draw_number-1][3]) / (1-0.738)) } } From d31521ec1373cceb38becaa5a11e214eea2ebb3a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 5 Feb 2025 11:19:04 +0000 Subject: [PATCH 311/755] scenario_wast_min_model: update pars to 175 task with indexing bug in mind --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index aba407aec2..2cc5bc6cb0 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -96,7 +96,7 @@ def draw_parameters(self, draw_number, rng): base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] progression_to_sev_wast__coef = [15] progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.55] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.4] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, From 841dd7fc2aca2c761cdaa260178f962e005e384b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 5 Feb 2025 13:40:35 +0000 Subject: [PATCH 312/755] wast: united style of conditions being checked --- src/tlo/methods/wasting.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 305a57e7c9..c9b0c444a7 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -708,21 +708,21 @@ def do_at_generic_first_appt( print(f"NON-EMERGENCY APPT on {self.sim.date=}") print(f"{symptoms=}") - if (individual_properties["age_years"] >= 5) or \ - (individual_properties["un_am_treatment_type"] in - ['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']) or \ - (self.sim.date == df.at[person_id, 'un_last_nonemergency_appt_date']): + if (individual_properties['age_years'] >= 5) or \ + (individual_properties['un_last_wasting_date_of_onset'] < individual_properties['un_am_tx_start_date'] < + self.sim.date) or \ + (self.sim.date == individual_properties['un_last_nonemergency_appt_date']): if do_prints: print("not going through because") if individual_properties["age_years"] >= 5: print(f"person not under 5, {individual_properties['age_years']=}") - if individual_properties['un_am_treatment_type'] in \ - ['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']: - print(f",person currently treated, {individual_properties['un_am_treatment_type']=}") - if self.sim.date == df.at[person_id, 'un_last_nonemergency_appt_date']: + if (individual_properties['un_last_wasting_date_of_onset'] < individual_properties['un_am_tx_start_date'] < + self.sim.date): + print(f"person currently treated, {individual_properties['un_am_treatment_type']=}") + if self.sim.date == individual_properties['un_last_nonemergency_appt_date']: print("the non-emerg. appt did went through today already") print("----------------------------------") - if self.sim.date == df.at[person_id, 'un_last_nonemergency_appt_date']: + if self.sim.date == individual_properties['un_last_nonemergency_appt_date']: logger.debug( key="non-emergency", data=f"A non-emerg. appt runs again on the same date {self.sim.date=} for the {person_id=}. " From 188c388135e55bf87b5e3a48b8de967341f3b31f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 5 Feb 2025 13:44:03 +0000 Subject: [PATCH 313/755] wast: if HSI scheduled via care-seeking, growth monitoring is canceled and vice versa --- src/tlo/methods/wasting.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index c9b0c444a7..e261b7d127 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -730,6 +730,20 @@ def do_at_generic_first_appt( ) return + # or if HSI was already scheduled due to growth monitoring, won't be checked for acute malnutrition again + hsi_event_scheduled = [ + ev + for ev in self.sim.modules["HealthSystem"].find_events_for_person(person_id) + if isinstance(ev[1], (HSI_Wasting_SupplementaryFeedingProgramme_MAM, + HSI_Wasting_OutpatientTherapeuticProgramme_SAM, + HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM)) + ] + if hsi_event_scheduled: + if do_prints: + print(f"not going through because {hsi_event_scheduled=} via growth monitoring") + return + + # track the date of the last non-emergency appt df.at[person_id, 'un_last_nonemergency_appt_date'] = self.sim.date # get the clinical states @@ -1603,6 +1617,18 @@ def get_monitoring_frequency_days(age): if do_prints: print("not going through because is currently treated") return + # or if HSI was already scheduled due to care-seeking, no need to attend the growth monitoring + hsi_event_scheduled = [ + ev + for ev in self.sim.modules["HealthSystem"].find_events_for_person(person_id) + if isinstance(ev[1], (HSI_Wasting_SupplementaryFeedingProgramme_MAM, + HSI_Wasting_OutpatientTherapeuticProgramme_SAM, + HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM)) + ] + if hsi_event_scheduled: + if do_prints: + print(f"not going through because {hsi_event_scheduled=} via care-seeking") + return if not self.attendance: if do_prints: From a1b0c2a28a99f58df8738a6ca4641497912fa3a7 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 5 Feb 2025 17:17:05 +0000 Subject: [PATCH 314/755] scenario_wast_min_model: draw_parameters needs at least two set of draws to work with normal indexing, but then only 1 draw can be called(number_of_draws=1) --- .../scenarios/scenario_wasting_minimal_model.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 2cc5bc6cb0..8513798903 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -91,7 +91,7 @@ def modules(self): # } def draw_parameters(self, draw_number, rng): - base_death_rate_untreated_sam__draws = [0.03] + base_death_rate_untreated_sam__draws = [0.03, 0.03] mod_wast_incidence__coef = [0.7] base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] progression_to_sev_wast__coef = [15] @@ -106,12 +106,12 @@ def draw_parameters(self, draw_number, rng): )) return { 'Wasting': { - 'base_death_rate_untreated_SAM': pars_combinations[draw_number-1][0], - 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number-1][1] for \ + 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], + 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ s in base_inc_rate_wasting_props_by_agegp], - 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number-1][2] for \ + 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ s in progression_severe_wasting_monthly_props_by_agegp], - 'prob_death_after_SAMcare': ((pars_combinations[draw_number-1][0] * pars_combinations[draw_number-1][3]) / + 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / (1-0.738)) } } From fa4629e21d2cb4c357a787c870927351c96798d1 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 5 Feb 2025 17:30:31 +0000 Subject: [PATCH 315/755] scenario_wast_min_model: multiple draws (death and incidence rates) --- .../scenario_wasting_minimal_model.py | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 8513798903..e83a9a08fb 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -90,39 +90,13 @@ def modules(self): # } # } - def draw_parameters(self, draw_number, rng): - base_death_rate_untreated_sam__draws = [0.03, 0.03] - mod_wast_incidence__coef = [0.7] - base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] - progression_to_sev_wast__coef = [15] - progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.4] - - pars_combinations = list(itertools.product( - base_death_rate_untreated_sam__draws, - mod_wast_incidence__coef, - progression_to_sev_wast__coef, - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam - )) - return { - 'Wasting': { - 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], - 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ - s in base_inc_rate_wasting_props_by_agegp], - 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ - s in progression_severe_wasting_monthly_props_by_agegp], - 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / - (1-0.738)) - } - } - # def draw_parameters(self, draw_number, rng): - # base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] - # mod_wast_incidence__coef = [0.1, 0.3, 0.5, 0.7, 0.9] + # base_death_rate_untreated_sam__draws = [0.03, 0.03] + # mod_wast_incidence__coef = [0.7] # base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] - # progression_to_sev_wast__coef = [1, 5, 10, 15, 20] + # progression_to_sev_wast__coef = [15] # progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] - # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] + # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.4] # # pars_combinations = list(itertools.product( # base_death_rate_untreated_sam__draws, @@ -142,6 +116,32 @@ def draw_parameters(self, draw_number, rng): # } # } + def draw_parameters(self, draw_number, rng): + base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] + mod_wast_incidence__coef = [0.1, 0.3, 0.5, 0.7, 0.9] + base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] + progression_to_sev_wast__coef = [1, 5, 10, 15, 20] + progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] + + pars_combinations = list(itertools.product( + base_death_rate_untreated_sam__draws, + mod_wast_incidence__coef, + progression_to_sev_wast__coef, + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam + )) + return { + 'Wasting': { + 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], + 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ + s in base_inc_rate_wasting_props_by_agegp], + 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ + s in progression_severe_wasting_monthly_props_by_agegp], + 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / + (1-0.738)) + } + } + if __name__ == '__main__': from tlo.cli import scenario_run From 88567089c73efb268e23d05cf9a784cc6f4a5a74 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 5 Feb 2025 17:32:19 +0000 Subject: [PATCH 316/755] scenario_wast_min_model: numb of draws = 500 forgotten --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index e83a9a08fb..aa914c4982 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -43,7 +43,7 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=30_000, - number_of_draws=1, + number_of_draws=500, runs_per_draw=1, ) From 20260539eb29726a50d7c35e6148e5931df0ff70 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 6 Feb 2025 01:02:54 +0000 Subject: [PATCH 317/755] scenario_wast_min_model: 4K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index aa914c4982..965720502d 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + initial_population_size=4_000, number_of_draws=500, runs_per_draw=1, ) From 3c8eb8286679b0f77eeba3000fd3c6138a0c5069 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 6 Feb 2025 17:45:21 +0000 Subject: [PATCH 318/755] add_pars_page_ToAllPDFs: created (adds 1st page to output figures pdfs with parameters set for the draw) --- .../add_pars_page_ToAllPDFs.py | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py diff --git a/src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py b/src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py new file mode 100644 index 0000000000..d044816477 --- /dev/null +++ b/src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py @@ -0,0 +1,88 @@ +import itertools +from pathlib import Path +from PyPDF2 import PdfReader, PdfWriter +from reportlab.lib.pagesizes import letter +from reportlab.pdfgen import canvas +from io import BytesIO +import sys +import re + +# Define the parameter values in a dictionary +parameters = { + "base_death_rate_untreated_sam": [0.01, 0.03, 0.05, 0.08, 0.1], + "mod_wast_incidence__coef": [0.1, 0.3, 0.5, 0.7, 0.9], + "progression_to_sev_wast__coef": [1, 5, 10, 15, 20], + "prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam": [0.85, 0.7, 0.55, 0.4] +} + +# Create the parameter combinations +param_names = list(parameters.keys()) +param_values = list(parameters.values()) +pars_combinations = list(itertools.product(*param_values)) + +# Function to create a PDF with parameter values +def create_parameter_page(params): + buffer = BytesIO() + c = canvas.Canvas(buffer, pagesize=(200, 45)) # Smaller page size + c.setFont("Helvetica", 5) # Set font size to 10 + y_position = 35 + for name, value in zip(param_names, params): + c.drawString(10, y_position, f"{name} = {value}") + y_position -= 10 # Move down for the next parameter + c.showPage() + c.save() + buffer.seek(0) + return buffer + +# Base directory path +BASE_PATH = Path("/home/eva/PycharmProjects/TLOmodel/outputs/sejjej5@ucl.ac.uk/wasting/") + +# Function to extract the indices from the file name +def extract_indices(file_name): + match = re.search(r'_(\d+)_(\d+)\.pdf$', file_name) + return (int(match.group(1)), int(match.group(2))) if match else (-1, -1) + +# Process each PDF +def process_pdfs(folder_name): + pdf_dir = BASE_PATH / folder_name + output_dir = pdf_dir / "outputs_with_pars" + output_dir.mkdir(exist_ok=True) + print(f"Processing PDFs in directory: {pdf_dir}") + + pdf_files = list(pdf_dir.glob("*.pdf")) + if not pdf_files: + print("No PDF files found in the directory.") + return + + # Sort the PDF files by the extracted indices + pdf_files.sort(key=lambda x: extract_indices(x.name)) + + for pdf_file, params in zip(pdf_files, itertools.cycle(pars_combinations)): + print(f"Processing file: {pdf_file}") + reader = PdfReader(str(pdf_file)) + writer = PdfWriter() + + # Create the parameter page + parameter_page = create_parameter_page(params) + parameter_reader = PdfReader(parameter_page) + writer.add_page(parameter_reader.pages[0]) + + # Add the original pages + for page in reader.pages: + writer.add_page(page) + + # Save the new PDF with _pars added to the original name + output_pdf = output_dir / f"{pdf_file.stem}_pars.pdf" + with open(output_pdf, "wb") as f: + writer.write(f) + print(f"Saved updated PDF: {output_pdf}") + + print("PDFs have been updated with parameter pages.") + +if __name__ == "__main__": + if len(sys.argv) != 2: + print("Usage: python add_pars_page_ToAllPDFs.py ") + else: + folder_name = sys.argv[1] + process_pdfs(folder_name) + From ff899b47ff696bbf47b1aed90b48b116247210d3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 7 Feb 2025 19:12:25 +0000 Subject: [PATCH 319/755] analysis_Wast: TODO: plot_wasting_length needs to be fixed --- src/scripts/wasting_analyses/analysis_wasting.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index cee335f6e4..a128329666 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -224,10 +224,14 @@ def plot_wasting_length(self): # get age_years, doesn't matter from which dict age_years = list(w_length_df.loc[w_length_df.index[0], 'mod_MAM_tx_full_recov'].keys()) # age_years.remove('5+y') - w_length_df = w_length_df.loc[:, ['mod_nat_recov', 'mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', - 'mod_SAM_tx_recov_to_MAM', 'mod_not_yet_recovered', - 'sev_SAM_tx_full_recov', 'sev_SAM_tx_recov_to_MAM', - 'sev_not_yet_recovered']] + w_length_df = w_length_df.loc[:, ['mod_MAM_nat_full_recov', + 'mod_SAM_nat_full_recov', 'mod_SAM_nat_recov_to_MAM', + 'sev_SAM_nat_full_recov', 'sev_SAM_nat_recov_to_MAM', + 'mod_MAM_tx/nat_full_recov', + 'mod_SAM_tx_full_recov', 'mod_SAM_tx/nat_recov_to_MAM', + 'sev_SAM_tx_full_recov', 'sev_SAM_tx/nat_recov_to_MAM', + 'mod_not_yet_recovered', + 'sev_not_yet_recovered']] for recov_opt in w_length_df.columns: _row_counter = 0 @@ -579,7 +583,7 @@ def plot_all_figs_in_one_pdf(self): # wasting_analyses.plot_wasting_incidence_mod_to_sev_props() # plot wasting length - wasting_analyses.plot_wasting_length() + # wasting_analyses.plot_wasting_length() # plot wasting prevalence wasting_analyses.plot_wasting_prevalence_per_year() From d68b0e948e88e39eb1d8c72beafb8b71cee54419 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 8 Feb 2025 18:28:29 +0000 Subject: [PATCH 320/755] add_pars_page: skip the params combination if a draw missing --- .../wasting_analyses/add_pars_page_ToAllPDFs.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py b/src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py index d044816477..a87c48ec4c 100644 --- a/src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py +++ b/src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py @@ -24,7 +24,7 @@ def create_parameter_page(params): buffer = BytesIO() c = canvas.Canvas(buffer, pagesize=(200, 45)) # Smaller page size - c.setFont("Helvetica", 5) # Set font size to 10 + c.setFont("Helvetica", 5) # Set font and size y_position = 35 for name, value in zip(param_names, params): c.drawString(10, y_position, f"{name} = {value}") @@ -57,7 +57,13 @@ def process_pdfs(folder_name): # Sort the PDF files by the extracted indices pdf_files.sort(key=lambda x: extract_indices(x.name)) - for pdf_file, params in zip(pdf_files, itertools.cycle(pars_combinations)): + # Extract the draw indices from the file names + existing_draws = {extract_indices(pdf_file.name)[0] for pdf_file in pdf_files} + + # Filter out the parameter combinations for the missing draws + filtered_pars_combinations = [params for i, params in enumerate(pars_combinations) if i in existing_draws] + + for pdf_file, params in zip(pdf_files, filtered_pars_combinations): print(f"Processing file: {pdf_file}") reader = PdfReader(str(pdf_file)) writer = PdfWriter() From d462f27513a415aab372028aaa7df1d37b4cb60d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 8 Feb 2025 18:30:00 +0000 Subject: [PATCH 321/755] analysis_wast: calib ys updated; init wast added in prev by year --- .../wasting_analyses/analysis_wasting.py | 52 ++++++++++++++----- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index a128329666..98612f24dc 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -74,15 +74,19 @@ def __init__(self, in_sim_results_folder_path, in_datestamp, in_draw_nmb, in_run cycle = plt.rcParams['axes.prop_cycle'].by_key()['color'] # # define colo(u)rs to use: self.__colors_model = { - 'severe wasting': cycle[0], - 'moderate wasting': cycle[1], - 'SAM': cycle[2], - 'MAM': cycle[3], + 'severe wasting': cycle[0], # #1f77b4 + 'moderate wasting': cycle[1], # #ff7f0e + 'SAM': cycle[2], # #2ca02c + 'MAM': cycle[3], # #d62728 } self.__colors_data = { 'severe wasting': '#82C1EC', 'moderate wasting': '#C71E1E', } + self.__colors_init_data = { + 'severe wasting': '#0E53EA', + 'moderate wasting': '#FFA783', + } def save_fig__store_pdf_file(self, fig, fig_output_name: str) -> None: full_path_and_file_name = self.outcomes_folder_path + f'/{self.draw_nmb}/{self.run_nmb}/' + fig_output_name + \ @@ -290,7 +294,7 @@ def plot_wasting_prevalence_per_year(self): w_prev_calib_data_years_only_df = pd.DataFrame({ 'sev_wast_calib': [0.015, 0.011, 0.006, 0.007], 'mod_wast_calib': [0.025, 0.027, 0.021, 0.019] - }, index=[2010, 2014, 2016, 2020]) + }, index=[2010, 2013, 2015, 2019]) date_range = pd.Index(range(2010, 2031), name='date') w_prev_calib = pd.DataFrame(index=date_range) # filling missing values with 0 @@ -303,19 +307,43 @@ def plot_wasting_prevalence_per_year(self): w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) w_prev_df = w_prev_df.drop(columns='date') - w_prev_plot_df = pd.merge(w_prev_df, w_prev_calib_df, on='date') - columns_to_plot = [['total_sev_under5_prop', 'total_mod_under5_prop'], ['sev_wast_calib', 'mod_wast_calib']] + # Add initial prevalence for the year 2010 + init_prev_2010_only_df = self.__w_logs_dict["wasting_init_prevalence_props"] + init_prev_2010_only_df = init_prev_2010_only_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']].rename( + columns={'total_sev_under5_prop': 'total_init_sev_under5_prop', 'total_mod_under5_prop': 'total_init_mod_under5_prop'} + ) + init_prev_2010_only_df = init_prev_2010_only_df.set_index(init_prev_2010_only_df.date.dt.year) + init_prev_2010_only_df = init_prev_2010_only_df.drop(columns='date') + init_prev_2010_only_df = init_prev_2010_only_df.loc[[2010]] + init_prev_df = pd.DataFrame(index=date_range) + # filling missing values with 0 + init_prev_df = init_prev_df.merge( + init_prev_2010_only_df, left_index=True, right_index=True, how='left' + ).fillna(0) + + w_prev_calib_and_init_df = pd.merge(init_prev_df, w_prev_calib_df, on='date') + w_prev_plot_df = pd.merge(w_prev_df, w_prev_calib_and_init_df, on='date') + columns_to_plot = [ + ['total_init_sev_under5_prop', 'total_init_mod_under5_prop'], + ['total_sev_under5_prop', 'total_mod_under5_prop'], + ['sev_wast_calib', 'mod_wast_calib'], + ] colors_to_plot = { 'total_sev_under5_prop': self.__colors_model['severe wasting'], 'total_mod_under5_prop': self.__colors_model['moderate wasting'], 'sev_wast_calib': self.__colors_data['severe wasting'], - 'mod_wast_calib': self.__colors_data['moderate wasting'] + 'mod_wast_calib': self.__colors_data['moderate wasting'], + 'total_init_sev_under5_prop': self.__colors_init_data['severe wasting'], + 'total_init_mod_under5_prop': self.__colors_init_data['moderate wasting'] + } labels_to_plot = { 'total_sev_under5_prop': 'severe wasting (model)', 'total_mod_under5_prop': 'moderate wasting (model)', 'sev_wast_calib': 'severe wasting (data)', - 'mod_wast_calib': 'moderate wasting (data)' + 'mod_wast_calib': 'moderate wasting (data)', + 'total_init_sev_under5_prop': 'severe wasting (initial data)', + 'total_init_mod_under5_prop': 'moderate wasting (initial data)' } fig, ax = plt.subplots() @@ -352,15 +380,15 @@ def plot_wasting_prevalence_by_age_group(self): 'wasted_calib': [7.0, 13.0, 12.7, 2.4, 2.7, 1.9, 0.0], 'sev_wast_calib': [2.1, 7.1, 4.7, 0.9, 0.7, 0.6, 0.0] }, - 2014: { + 2013: { 'wasted_calib': [5.8, 5.8, 5.4, 3.9, 2.2, 2.0, 0.0], 'sev_wast_calib': [2.6, 2.5, 1.1, 0.8, 0.7, 0.3, 0.0] }, - 2016: { + 2015: { 'wasted_calib': [3.7, 7.7, 6.5, 2.2, 1.9, 2.6, 0.0], 'sev_wast_calib': [1.1, 1.0, 0.7, 1.0, 0.1, 0.5, 0.0] }, - 2020: { + 2019: { 'wasted_calib': [2.5, 2.6, 9.1, 2.0, 1.8, 1.8, 0.0], 'sev_wast_calib': [1.0, 1.0, 2.7, 0.8, 0.2, 0.3, 0.0] } From c162cc20a869029182c3d271719b2de08c3bc8ac Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 8 Feb 2025 18:35:07 +0000 Subject: [PATCH 322/755] scenario_wast_min_model: pars set for task 271 (draw 270) --- .../scenario_wasting_minimal_model.py | 74 +++++++++---------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 965720502d..985971decf 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,8 +42,8 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, - number_of_draws=500, + initial_population_size=30_000, + number_of_draws=1, runs_per_draw=1, ) @@ -81,48 +81,16 @@ def modules(self): # def draw_parameters(self, draw_number, rng): # # Using default parameters in all cases - # return { - # 'Wasting': { - # 'base_death_rate_untreated_SAM': 0.17, - # 'base_inc_rate_wasting_by_agegp': [0.0023, 0.0099, 0.0189, 0.0102, 0.003, 0.002], - # 'progression_severe_wasting_monthly_by_agegp': [0.0027, 0.0036, 0.0079, 0.0053, 0.0025, 0.002], - # 'prob_death_after_SAMcare': 0.17 * 0.5 - # } - # } - - # def draw_parameters(self, draw_number, rng): - # base_death_rate_untreated_sam__draws = [0.03, 0.03] - # mod_wast_incidence__coef = [0.7] - # base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] - # progression_to_sev_wast__coef = [15] - # progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] - # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.4] - # - # pars_combinations = list(itertools.product( - # base_death_rate_untreated_sam__draws, - # mod_wast_incidence__coef, - # progression_to_sev_wast__coef, - # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam - # )) - # return { - # 'Wasting': { - # 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], - # 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ - # s in base_inc_rate_wasting_props_by_agegp], - # 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ - # s in progression_severe_wasting_monthly_props_by_agegp], - # 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / - # (1-0.738)) - # } - # } + # return {} def draw_parameters(self, draw_number, rng): - base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] - mod_wast_incidence__coef = [0.1, 0.3, 0.5, 0.7, 0.9] + # Setting up just one combination to be used + base_death_rate_untreated_sam__draws = [0.05, 0.05] + mod_wast_incidence__coef = [0.7] base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] - progression_to_sev_wast__coef = [1, 5, 10, 15, 20] + progression_to_sev_wast__coef = [10] progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.55] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, @@ -142,6 +110,32 @@ def draw_parameters(self, draw_number, rng): } } + # def draw_parameters(self, draw_number, rng): + # base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] + # mod_wast_incidence__coef = [0.1, 0.3, 0.5, 0.7, 0.9] + # base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] + # progression_to_sev_wast__coef = [1, 5, 10, 15, 20] + # progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] + # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] + # + # pars_combinations = list(itertools.product( + # base_death_rate_untreated_sam__draws, + # mod_wast_incidence__coef, + # progression_to_sev_wast__coef, + # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam + # )) + # return { + # 'Wasting': { + # 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], + # 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ + # s in base_inc_rate_wasting_props_by_agegp], + # 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ + # s in progression_severe_wasting_monthly_props_by_agegp], + # 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / + # (1-0.738)) + # } + # } + if __name__ == '__main__': from tlo.cli import scenario_run From ab2ee64f863b87a252043f306e15e61bacf08bba Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 8 Feb 2025 18:56:01 +0000 Subject: [PATCH 323/755] wast & RF_Wast: attendance in < 1y old should be higher (for now approx. 80%, later should be done during epi appts) --- resources/ResourceFile_Wasting.csv | 4 ++-- src/tlo/methods/wasting.py | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 44c1e9e08e..7c01251781 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:57e851f33e596f9149411238e2c08fdfb9fae7b8ad71f340567971516cf06305 -size 3626 +oid sha256:dfcd911c56c78b95bee34211dad50f5612569149d1b036c9e2093667cb166f7f +size 3706 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index e261b7d127..9d5289906d 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1536,11 +1536,15 @@ def EXPECTED_APPT_FOOTPRINT(self): p = self.module.parameters person_age = self.sim.population.props.loc[self.target].age_exact_years + # TODO: for now assumed general attendence prob for <1 y old, + # later will be excluded and dealt with within epi module def get_attendance_prob(age): - if age <= 2: # TODO: expecting here, that 0-1 will be excluded and dealt with within epi module + if age < 1: return p['growth_monitoring_attendance_prob'][0] - else: + if age <= 2: return p['growth_monitoring_attendance_prob'][1] + else: + return p['growth_monitoring_attendance_prob'][2] # perform growth monitoring if attending self.attendance = rng.random_sample() < get_attendance_prob(person_age) From a386ac58da51e22a1c23cc52d736a430d31d7b72 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 9 Feb 2025 23:36:12 +0000 Subject: [PATCH 324/755] add_pars_page & analysis_wast: outcome figs to go to folders within the outputs folder --- .../wasting_analyses/add_pars_page_ToAllPDFs.py | 6 +++--- src/scripts/wasting_analyses/analysis_wasting.py | 10 ++++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py b/src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py index a87c48ec4c..0d0e7d9884 100644 --- a/src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py +++ b/src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py @@ -43,9 +43,9 @@ def extract_indices(file_name): return (int(match.group(1)), int(match.group(2))) if match else (-1, -1) # Process each PDF -def process_pdfs(folder_name): - pdf_dir = BASE_PATH / folder_name - output_dir = pdf_dir / "outputs_with_pars" +def process_pdfs(in_folder_name): + pdf_dir = BASE_PATH / in_folder_name / "_outcome_figures" + output_dir = BASE_PATH / in_folder_name / "_outputs_with_pars" output_dir.mkdir(exist_ok=True) print(f"Processing PDFs in directory: {pdf_dir}") diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 98612f24dc..6556306ff8 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -548,10 +548,10 @@ def plot_modal_gbd_deaths_by_gender(self): self.save_fig__store_pdf_file(fig, fig_output_name) # plt.show() - def plot_all_figs_in_one_pdf(self): + def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): - output_file_path = Path(self.outcomes_folder_path + '/wasting_all_figures__' + self.datestamp + - f'_{self.draw_nmb}_{self.run_nmb}' + '.pdf') + output_file_path = \ + in_outcome_figs_folder / f'wasting_all_figures__{self.datestamp}_{self.draw_nmb}_{self.run_nmb}.pdf' # Remove the existing output file if it exists to ensure a clean start if os.path.exists(output_file_path): os.remove(output_file_path) @@ -626,7 +626,9 @@ def plot_all_figs_in_one_pdf(self): wasting_analyses.plot_modal_gbd_deaths_by_gender() # save all figures in one pdf - wasting_analyses.plot_all_figs_in_one_pdf() + outcome_figs_folder = Path(sim_results_folder_path + '/_outcome_figures') + outcome_figs_folder.mkdir(parents=True, exist_ok=True) + wasting_analyses.plot_all_figs_in_one_pdf(outcome_figs_folder) time_end = time.time() print(f"... finished in (s): {(time_end - time_start)}") From bc0e1f965ffa13d7232c1abc2aa8bd83c13f7aa2 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 9 Feb 2025 23:37:46 +0000 Subject: [PATCH 325/755] analysis_wast: initial prev (not exactly data) --- src/scripts/wasting_analyses/analysis_wasting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 6556306ff8..6d04263cac 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -342,8 +342,8 @@ def plot_wasting_prevalence_per_year(self): 'total_mod_under5_prop': 'moderate wasting (model)', 'sev_wast_calib': 'severe wasting (data)', 'mod_wast_calib': 'moderate wasting (data)', - 'total_init_sev_under5_prop': 'severe wasting (initial data)', - 'total_init_mod_under5_prop': 'moderate wasting (initial data)' + 'total_init_sev_under5_prop': 'severe wasting (initial)', + 'total_init_mod_under5_prop': 'moderate wasting (initial)' } fig, ax = plt.subplots() From 589b1a1af2843a5db59c39bc03c5747d6d2a26ef Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 13 Feb 2025 11:21:25 +0000 Subject: [PATCH 326/755] wast, scenario_w_min_model & RF_Wast: LMs of prev & inci corrected; inc rate -> base * rr for agegps; minor; progress. rate for 5+ set to 0; (pars description updated, pars prints updated) --- resources/ResourceFile_Wasting.csv | 4 +- .../scenario_wasting_minimal_model.py | 9 +- src/tlo/methods/wasting.py | 86 +++++++++++-------- 3 files changed, 54 insertions(+), 45 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 7c01251781..46b52f6791 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dfcd911c56c78b95bee34211dad50f5612569149d1b036c9e2093667cb166f7f -size 3706 +oid sha256:3a6245f7d99e632ab6350f2962666feb31f8b396faf5b25817411315ac3fae69 +size 3909 diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 985971decf..7704f5e70b 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -86,9 +86,9 @@ def modules(self): def draw_parameters(self, draw_number, rng): # Setting up just one combination to be used base_death_rate_untreated_sam__draws = [0.05, 0.05] - mod_wast_incidence__coef = [0.7] - base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] - progression_to_sev_wast__coef = [10] + mod_wast_incidence__coef = [1.0] + base_overall_mod_wast_inc_rate = 0.0023 + progression_to_sev_wast__coef = [1.0] progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.55] @@ -101,8 +101,7 @@ def draw_parameters(self, draw_number, rng): return { 'Wasting': { 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], - 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ - s in base_inc_rate_wasting_props_by_agegp], + 'base_overall_inc_rate_wasting': base_overall_mod_wast_inc_rate * pars_combinations[draw_number][1] , 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ s in progression_severe_wasting_monthly_props_by_agegp], 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 9d5289906d..52fd2a04ca 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -89,8 +89,11 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'or_wasting_SGA_and_preterm': Parameter( Types.REAL, 'odds ratio of wasting if born preterm and small for gestational age'), # incidence - 'base_inc_rate_wasting_by_agegp': Parameter( - Types.LIST, 'List with baseline incidence rate of moderate wasting by age group'), + 'base_overall_inc_rate_wasting': Parameter( + Types.REAL, 'base moderate wasting incidence rate (reference age group 0-5 months old)'), + 'rr_inc_rate_wasting_by_agegp': Parameter( + Types.LIST, 'list with relative risks of moderate wasting incidence rate by age group, reference ' + 'group 0-5 months old'), 'rr_wasting_preterm_and_AGA': Parameter( Types.REAL, 'relative risk of wasting if born preterm and adequate for gestational age'), 'rr_wasting_SGA_and_term': Parameter( @@ -113,9 +116,10 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'duration_sam_to_death': Parameter( Types.REAL, 'duration of SAM till death if supposed to die due to SAM (days)'), 'base_death_rate_untreated_SAM': Parameter( - Types.REAL, 'base death rate due to untreated SAM for age group of children <0.5 months old'), + Types.REAL, 'base death rate due to untreated SAM (reference age group <0.5 months old)'), 'rr_death_rate_by_agegp': Parameter( - Types.LIST, 'list with relative risks of death due to untreated SAM by age gp, reference gp <0.5 months'), + Types.LIST, 'list with relative risks of death due to untreated SAM by age group, reference ' + 'group <0.5 months old'), # MUAC distributions 'proportion_WHZ<-3_with_MUAC<115mm': Parameter( Types.REAL, 'proportion of individuals with severe wasting who have MUAC < 115 mm'), @@ -280,18 +284,21 @@ def initialise_population(self, population): p = self.parameters print("\nPARAMETERS:") print(f"{p['base_death_rate_untreated_SAM']=}") - print(f"mod_wast_incidence__coef={p['base_inc_rate_wasting_by_agegp'][0]/0.0023}") + print(f"mod_wast_incidence__coef={p['base_overall_inc_rate_wasting']/0.0023}") print(f"progression_to_sev_wast__coef={p['progression_severe_wasting_monthly_by_agegp'][0]/0.0027}") print("prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam=" f"{p['prob_death_after_SAMcare']*(1-0.738)/p['base_death_rate_untreated_SAM']}") print("-----------") - print(f"{p['base_inc_rate_wasting_by_agegp']=}") + print(f"{p['base_overall_inc_rate_wasting']=}") + print("base inc rates by age group: " + f"{[s * p['base_overall_inc_rate_wasting'] for s in p['rr_inc_rate_wasting_by_agegp']]}") print(f"{p['progression_severe_wasting_monthly_by_agegp']=}") print(f"{p['prob_death_after_SAMcare']=}") # Adjust monthly severe wasting incidence to the duration of untreated moderate wasting p['progression_severe_wasting_by_agegp'] = \ [s/30*p['duration_of_untreated_mod_wasting'] for s in p['progression_severe_wasting_monthly_by_agegp']] + print(f"{p['progression_severe_wasting_by_agegp']=}") # Set initial properties df.loc[df.is_alive, 'un_ever_wasted'] = False @@ -327,9 +334,10 @@ def initialise_population(self, population): )] # apply prevalence of wasting and categorise into moderate (-3 <= WHZ < -2) or severe (WHZ < -3) wasting - wasted = self.wasting_models.get_wasting_prevalence(agegp=agegp).predict( - children_of_agegp, self.rng, False - ) + wasted = \ + self.wasting_models.get_wasting_prevalence(agegp=agegp, children_of_agegp=children_of_agegp).predict( + children_of_agegp, self.rng, False + ) probability_of_severe = self.get_prob_severe_wasting_among_wasted(agegp=agegp) for idx in children_of_agegp.index[wasted]: wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], p=[probability_of_severe, @@ -1975,13 +1983,14 @@ def __init__(self, module): # (natural history only, no interventions) self.severe_wasting_progression_lm = LinearModel.multiplicative( Predictor('age_exact_years', - conditions_are_mutually_exclusive=True, conditions_are_exhaustive=False) + conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) .when('<0.5', self.params['progression_severe_wasting_by_agegp'][0]) .when('.between(0.5,1, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][1]) .when('.between(1,2, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][2]) .when('.between(2,3, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][3]) .when('.between(3,4, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][4]) .when('.between(4,5, inclusive="left")', self.params['progression_severe_wasting_by_agegp'][5]) + .when('>=5', 0) ) # get wasting incidence linear model @@ -2004,7 +2013,7 @@ def __init__(self, module): def get_wasting_incidence(self) -> LinearModel: """ - :return: a scaled wasting incidence linear model amongst young children + :return: the scaled multiplicative linear model of wasting incidence rate """ df = self.module.sim.population.props @@ -2012,44 +2021,46 @@ def unscaled_wasting_incidence_lm(intercept: Union[float, int] = 1.0) -> LinearM # linear model to predict the incidence of wasting return LinearModel( LinearModelType.MULTIPLICATIVE, - intercept, + intercept, # base_overall_inc_rate_wasting Predictor('age_exact_years', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=False) - .when('<0.5', self.params['base_inc_rate_wasting_by_agegp'][0]) - .when('.between(0.5,1, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][1]) - .when('.between(1,2, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][2]) - .when('.between(2,3, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][3]) - .when('.between(3,4, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][4]) - .when('.between(4,5, inclusive="left")', self.params['base_inc_rate_wasting_by_agegp'][5]), + .when('<0.5', self.params['rr_inc_rate_wasting_by_agegp'][0]) + .when('.between(0.5,1, inclusive="left")', self.params['rr_inc_rate_wasting_by_agegp'][1]) + .when('.between(1,2, inclusive="left")', self.params['rr_inc_rate_wasting_by_agegp'][2]) + .when('.between(2,3, inclusive="left")', self.params['rr_inc_rate_wasting_by_agegp'][3]) + .when('.between(3,4, inclusive="left")', self.params['rr_inc_rate_wasting_by_agegp'][4]) + .when('.between(4,5, inclusive="left")', self.params['rr_inc_rate_wasting_by_agegp'][5]), Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' '& (nb_late_preterm == False) & (nb_early_preterm == False)', self.params['rr_wasting_SGA_and_term']), Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', + '& ((nb_late_preterm == True) | (nb_early_preterm == True))', self.params['rr_wasting_SGA_and_preterm']), Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") ' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', + '& ((nb_late_preterm == True) | (nb_early_preterm == True))', self.params['rr_wasting_preterm_and_AGA']), Predictor('li_wealth').apply( lambda x: 1 if x == 1 else (x - 1) ** (self.params['rr_wasting_wealth_level'])), ) - unscaled_lm = unscaled_wasting_incidence_lm() - target_mean = self.params['base_inc_rate_wasting_by_agegp'][2] # base inc rate for 12-23mo old - actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1) & - (df.un_WHZ_category != 'WHZ>=-2')]).mean() - - scaled_intercept = 1.0 * (target_mean / actual_mean) \ - if (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else 1.0 + # target: base inc rate (i.e. inc rate of reference group 1-5mo old) + target_mean = self.params['base_overall_inc_rate_wasting'] + unscaled_lm = unscaled_wasting_incidence_lm(intercept=target_mean) + not_am_or_treated_ref_agegp = df.loc[df.is_alive & (df.un_clinical_acute_malnutrition == 'well') & + (df.un_am_tx_start_date.isna()) & (df.age_exact_years < 0.5)] + actual_mean = unscaled_lm.predict(not_am_or_treated_ref_agegp).mean() + scaled_intercept = target_mean * (target_mean / actual_mean) if \ + (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else target_mean scaled_wasting_incidence_lm = unscaled_wasting_incidence_lm(intercept=scaled_intercept) + return scaled_wasting_incidence_lm - def get_wasting_prevalence(self, agegp: str) -> LinearModel: + def get_wasting_prevalence(self, agegp: str, children_of_agegp: pd.DataFrame) -> LinearModel: """ :param agegp: children's age group - :return: a scaled wasting prevalence linear model amongst young children less than 5 years + :param children_of_agegp: df with children in the age group + :return: the scaled logistic linear model of wasting prevalence, i.e., odds of wasting among the specific agegp """ - df = self.module.sim.population.props def unscaled_wasting_prevalence_lm(intercept: Union[float, int]) -> LinearModel: return LinearModel( @@ -2065,19 +2076,18 @@ def unscaled_wasting_prevalence_lm(intercept: Union[float, int]) -> LinearModel: '& (nb_late_preterm == False) & (nb_early_preterm == False)', self.params['or_wasting_SGA_and_term']), Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', + '& ((nb_late_preterm == True) | (nb_early_preterm == True))', self.params['or_wasting_SGA_and_preterm']), Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") ' - '& (nb_late_preterm == True) | (nb_early_preterm == True)', + '& ((nb_late_preterm == True) | (nb_early_preterm == True))', self.params['or_wasting_preterm_and_AGA']) ) - get_odds_wasting = self.module.get_odds_wasting(agegp=agegp) - unscaled_lm = unscaled_wasting_prevalence_lm(intercept=get_odds_wasting) - target_mean = self.module.get_odds_wasting(agegp='12_23mo') - actual_mean = unscaled_lm.predict(df.loc[df.is_alive & (df.age_years == 1)]).mean() - scaled_intercept = get_odds_wasting * (target_mean / actual_mean) if \ - (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else get_odds_wasting + target_mean = self.module.get_odds_wasting(agegp=agegp) + unscaled_lm = unscaled_wasting_prevalence_lm(intercept=target_mean) + actual_mean = unscaled_lm.predict(children_of_agegp).mean() + scaled_intercept = target_mean * (target_mean / actual_mean) if \ + (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else target_mean scaled_wasting_prevalence_lm = unscaled_wasting_prevalence_lm(intercept=scaled_intercept) return scaled_wasting_prevalence_lm From a69ebc49752816977996c185ec665c4b0028498e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 13 Feb 2025 15:01:53 +0000 Subject: [PATCH 327/755] wast & RF_Wast: intial prevalences of WHZ < -2 and WHZ < -3 updated by DHS 2010 data --- resources/ResourceFile_Wasting.csv | 4 +- src/tlo/methods/wasting.py | 60 ++++++++++++++---------------- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 46b52f6791..7100b24072 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3a6245f7d99e632ab6350f2962666feb31f8b396faf5b25817411315ac3fae69 -size 3909 +oid sha256:e9e180924221c441642d932579a8982a9de81ca8177fe13d662ab6b087dec2a8 +size 4400 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 52fd2a04ca..8522fe5dbf 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -60,19 +60,11 @@ class Wasting(Module, GenericFirstAppointmentsMixin): } PARAMETERS = { - # prevalence of wasting by age group - 'prev_WHZ_distribution_age_0_5mo': Parameter( - Types.LIST, 'distribution of WHZ among less than 6 months of age in 2015'), - 'prev_WHZ_distribution_age_6_11mo': Parameter( - Types.LIST, 'distribution of WHZ among 6 months and 1 year of age in 2015'), - 'prev_WHZ_distribution_age_12_23mo': Parameter( - Types.LIST, 'distribution of WHZ among 1 year olds in 2015'), - 'prev_WHZ_distribution_age_24_35mo': Parameter( - Types.LIST, 'distribution of WHZ among 2 year olds in 2015'), - 'prev_WHZ_distribution_age_36_47mo': Parameter( - Types.LIST, 'distribution of WHZ among 3 year olds in 2015'), - 'prev_WHZ_distribution_age_48_59mo': Parameter( - Types.LIST, 'distribution of WHZ among 4 year olds in 2015'), + # initial prevalence of wasting by age group + 'prev_init_any_by_agegp': Parameter( + Types.LIST, 'initial any wasting (WHZ < -2) prevalence in 2010 by age groups'), + 'prev_init_sev_by_agegp': Parameter( + Types.LIST, 'initial severe wasting (WHZ < -3) prevalence in 2010 by age groups'), # effect of risk factors on wasting prevalence 'or_wasting_hhwealth_Q5': Parameter( Types.REAL, 'odds ratio of wasting if household wealth is poorest Q5, ref group Q1'), @@ -250,10 +242,15 @@ def __init__(self, name=None, resourcefilepath=None): _agrp: copy.deepcopy(blank_length_counter) for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} self.wasting_length_tracker = copy.deepcopy(self.wasting_length_tracker_blank) - self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} - self.person_of_interest_id = 3219 # debugging + # define age groups + self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} + self.age_gps_range_mo = [] + for low_bound_mos, high_bound_mos in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months + agegp_i = f'{low_bound_mos}_{high_bound_mos}mo' + self.age_gps_range_mo.append(agegp_i) + def read_parameters(self, data_folder): """ :param data_folder: path of a folder supplied to the Simulation containing data files. Typically, @@ -399,37 +396,36 @@ def on_birth(self, mother_id, child_id): def get_prob_severe_wasting_among_wasted(self, agegp: str) -> Union[float, int]: """ - This function will calculate the WHZ scores by categories and return probability of severe wasting - for those with wasting status - :param agegp: age grouped in months - :return: probability of severe wasting among all wasting cases + This function will return the probability of severe wasting for those with wasting status within the agegp + :param agegp: age group defined be range in months + :return: probability of severe wasting among all wasting cases in the agegp """ - # generate random numbers from N(mean, sd) - mean, stdev = self.parameters[f'prev_WHZ_distribution_age_{agegp}'] - whz_normal_distribution = norm(loc=mean, scale=stdev) + # determine age group + i = self.age_gps_range_mo.index(agegp) - # get probability of any wasting: WHZ < -2 - probability_less_than_minus2sd = 1 - whz_normal_distribution.sf(-2) + # get probability of any wasting (WHZ < -2) for the age group + probability_less_than_minus2sd = self.parameters['prev_init_any_by_agegp'][i] # get probability of severe wasting: WHZ < -3 - probability_less_than_minus3sd = 1 - whz_normal_distribution.sf(-3) + probability_less_than_minus3sd = self.parameters['prev_init_sev_by_agegp'][i] + print(f"orig init prev sev wast: {agegp=}, {probability_less_than_minus3sd=}") # make WHZ < -2 as the 100% and get the adjusted probability of severe wasting within overall wasting - # return the probability of severe wasting among all wasting cases + # return the probability of severe wasting among all wasting cases for the agegp return probability_less_than_minus3sd / probability_less_than_minus2sd + def get_odds_wasting(self, agegp: str) -> Union[float, int]: """ This function will calculate the WHZ scores by categories and return odds of wasting :param agegp: age grouped in months - :return: odds of wasting among all children under 5 + :return: odds of wasting among all children of the agegp """ - # generate random numbers from N(mean, sd) - mean, stdev = self.parameters[f'prev_WHZ_distribution_age_{agegp}'] - whz_normal_distribution = norm(loc=mean, scale=stdev) + # determine age group + i = self.age_gps_range_mo.index(agegp) - # get probability of any wasting: WHZ < -2 - probability_less_than_minus2sd = 1 - whz_normal_distribution.sf(-2) + # get probability of any wasting (WHZ < -2) for the age group + probability_less_than_minus2sd = self.parameters['prev_init_any_by_agegp'][i] # convert probability of wasting to odds and return the odds of wasting return probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) From 9e98844f4cdac9b2250694a30ebb3b2e2cb1482e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 13 Feb 2025 15:08:59 +0000 Subject: [PATCH 328/755] RF_Wast: minor (a note updated) --- resources/ResourceFile_Wasting.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 7100b24072..928b39213b 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e9e180924221c441642d932579a8982a9de81ca8177fe13d662ab6b087dec2a8 -size 4400 +oid sha256:839d84a046f7ab83ca67b9cc272d9886adb8b0f0ff04c04c8b102d9bc7498122 +size 4376 From 12d64a1d4da14f04d1683c573ae122429562af1f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 13 Feb 2025 15:19:12 +0000 Subject: [PATCH 329/755] scenario_wast_min_model: 6 draws (diff. death rates due to (un)treated SAM) --- .../scenarios/scenario_wasting_minimal_model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 7704f5e70b..1897cf276f 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -43,7 +43,7 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=30_000, - number_of_draws=1, + number_of_draws=6, runs_per_draw=1, ) @@ -85,12 +85,12 @@ def modules(self): def draw_parameters(self, draw_number, rng): # Setting up just one combination to be used - base_death_rate_untreated_sam__draws = [0.05, 0.05] + base_death_rate_untreated_sam__draws = [0.17, 0.1] mod_wast_incidence__coef = [1.0] base_overall_mod_wast_inc_rate = 0.0023 progression_to_sev_wast__coef = [1.0] progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.55] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.5, 0.7, 0.9] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, From da9a04f57af25082846ab4f5d99429a77440dbd1 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 13 Feb 2025 15:33:15 +0000 Subject: [PATCH 330/755] scenario_wast_min_model: 4K pop // 2025-02-13 --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 1897cf276f..f6c30c3f5b 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + initial_population_size=4_000, number_of_draws=6, runs_per_draw=1, ) From 253139307ac9b2088aac7c41dec5486bdb6c30fa Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 14 Feb 2025 11:48:35 +0000 Subject: [PATCH 331/755] analysis_wast: minor (comments, var names, fnc description) --- .../wasting_analyses/analysis_wasting.py | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 6d04263cac..afed6fa8d8 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -291,6 +291,7 @@ def plot_wasting_prevalence_per_year(self): """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of children wasted divide by the total number of children less than 5 years""" + ## Prevalence at some years - data (2010 are the data used to draw initial prevalence) w_prev_calib_data_years_only_df = pd.DataFrame({ 'sev_wast_calib': [0.015, 0.011, 0.006, 0.007], 'mod_wast_calib': [0.025, 0.027, 0.021, 0.019] @@ -302,26 +303,27 @@ def plot_wasting_prevalence_per_year(self): w_prev_calib_data_years_only_df, left_index=True, right_index=True, how='left' ).fillna(0) + ## Prevalence at the end of years - model w_prev_df = self.__w_logs_dict["wasting_prevalence_props"] w_prev_df = w_prev_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']] w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) w_prev_df = w_prev_df.drop(columns='date') - # Add initial prevalence for the year 2010 - init_prev_2010_only_df = self.__w_logs_dict["wasting_init_prevalence_props"] - init_prev_2010_only_df = init_prev_2010_only_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']].rename( + ## Initial prevalence at the beginning of 2010 - model + init_w_prev_2010_only_df = self.__w_logs_dict["wasting_init_prevalence_props"] + init_w_prev_2010_only_df = init_w_prev_2010_only_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']].rename( columns={'total_sev_under5_prop': 'total_init_sev_under5_prop', 'total_mod_under5_prop': 'total_init_mod_under5_prop'} ) - init_prev_2010_only_df = init_prev_2010_only_df.set_index(init_prev_2010_only_df.date.dt.year) - init_prev_2010_only_df = init_prev_2010_only_df.drop(columns='date') - init_prev_2010_only_df = init_prev_2010_only_df.loc[[2010]] - init_prev_df = pd.DataFrame(index=date_range) + init_w_prev_2010_only_df = init_w_prev_2010_only_df.set_index(init_w_prev_2010_only_df.date.dt.year) + init_w_prev_2010_only_df = init_w_prev_2010_only_df.drop(columns='date') + init_w_prev_2010_only_df = init_w_prev_2010_only_df.loc[[2010]] + init_w_prev_df = pd.DataFrame(index=date_range) # filling missing values with 0 - init_prev_df = init_prev_df.merge( - init_prev_2010_only_df, left_index=True, right_index=True, how='left' + init_w_prev_df = init_w_prev_df.merge( + init_w_prev_2010_only_df, left_index=True, right_index=True, how='left' ).fillna(0) - w_prev_calib_and_init_df = pd.merge(init_prev_df, w_prev_calib_df, on='date') + w_prev_calib_and_init_df = pd.merge(init_w_prev_df, w_prev_calib_df, on='date') w_prev_plot_df = pd.merge(w_prev_df, w_prev_calib_and_init_df, on='date') columns_to_plot = [ ['total_init_sev_under5_prop', 'total_init_mod_under5_prop'], @@ -521,7 +523,7 @@ def add_wasting_initial_prevalence_by_age_group(self): self.fig_files.append('wasting_initial_prevalence_per_each_age_group__' + self.datestamp + '.pdf') def plot_modal_gbd_deaths_by_gender(self): - """ compare modal and GBD deaths by gender """ + """ compare model and GBD deaths 2010-2014 & 2015-2019 """ death_compare = \ compare_number_of_deaths(self.__log_file_path, resources_path) fig, ax = plt.subplots(figsize=(10, 6)) @@ -597,7 +599,7 @@ def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): # Analyse each draw # for now, we always have just one run, run 0 run_nmb = 0 - for draw_nmb in range(len(folders)): + for draw_nmb in range(0, len(folders)): print(f"Analysing {draw_nmb=} ...") time_start = time.time() From 304b203e9a9db9d38b05d408914d7caac8aad002 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 14 Feb 2025 14:49:18 +0000 Subject: [PATCH 332/755] analysis_wast: prev by agegp at intiation - compare model & data --- .../wasting_analyses/analysis_wasting.py | 76 +++++++++++++++---- 1 file changed, 60 insertions(+), 16 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index afed6fa8d8..11b7dcd2e1 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -463,7 +463,7 @@ def create_plotting_data(df, df_name): ax.set_title(f"Wasting prevalence in children 0-59 months per each age group in {year_calib}") ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) ax.set_xticklabels(order_x_axis) - ax.set_ylim([0, 0.14]) + ax.set_ylim([0, 0.168]) ax.legend() # Adjust the layout to make space for the footnote @@ -482,35 +482,79 @@ def create_plotting_data(df, df_name): def plot_wasting_initial_prevalence_by_age_group(self): """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of children wasted in a particular age-group divided by the total number of children per that age-group""" + + # Initial prevalence at the beginning of 2010 - model w_prev_df = self.__w_logs_dict["wasting_init_prevalence_props"] w_prev_df = w_prev_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) w_prev_df = w_prev_df.drop(columns='date') - plotting = {'severe wasting': {}, 'moderate wasting': {}} + + # 2010 prevalence calibration data + data_2010 = { + 'wasted_calib': [7.0, 13.0, 12.7, 2.4, 2.7, 1.9, 0.0], + 'sev_wast_calib': [2.1, 7.1, 4.7, 0.9, 0.7, 0.6, 0.0] + } + data_2010['mod_wast_calib'] = \ + [(w - s)/100 for w, s in zip(data_2010['wasted_calib'], data_2010['sev_wast_calib'])] + data_2010['sev_wast_calib'] = \ + [s/100 for s in data_2010['sev_wast_calib']] + + # Prepare plotting data + plotting_model = {'severe wasting': {}, 'moderate wasting': {}} for col in w_prev_df.columns: prefix, age_group = col.split('__') if prefix == 'sev': - plotting['severe wasting'][age_group] = w_prev_df[col].values[0] + plotting_model['severe wasting'][age_group] = w_prev_df[col].values[0] elif prefix == 'mod': - plotting['moderate wasting'][age_group] = w_prev_df[col].values[0] - plotting = pd.DataFrame(plotting) + plotting_model['moderate wasting'][age_group] = w_prev_df[col].values[0] + plotting_model = pd.DataFrame(plotting_model) + + plotting_calib = {'severe wasting': {}, 'moderate wasting': {}} + age_groups = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] + for i, age_group in enumerate(age_groups): + plotting_calib['severe wasting'][age_group] = data_2010['sev_wast_calib'][i] + plotting_calib['moderate wasting'][age_group] = data_2010['mod_wast_calib'][i] + plotting_calib = pd.DataFrame(plotting_calib) + order_x_axis = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] - # Assert all age groups are included - assert set(plotting.index) == set(order_x_axis), "age groups are not in line with the order_x_axis." - plotting = plotting.reindex(order_x_axis) + plotting_model = plotting_model.reindex(order_x_axis) + plotting_calib = plotting_calib.reindex(order_x_axis) # Plot wasting prevalence fig, ax = plt.subplots(figsize=(10, 6)) - plotting.squeeze().plot(kind='bar', stacked=True, - ax=ax, - ylabel='proportion', - xlabel='age group', - ylim=[0, 0.14]) - ax.set_title(r"Wasting prevalence in children 0-59 months per each age group $\bf{at}$ $\bf{initiation}$") + bar_width = 0.35 + # Set positions of bars on x-axis + r1 = range(len(plotting_model)) + r2 = [x + bar_width for x in r1] + + # Plot the first set of bars (model data) + ax.bar(r1, plotting_model['severe wasting'], + color=self.__colors_model['severe wasting'], width=bar_width, + label='severe wasting (model)') + ax.bar(r1, plotting_model['moderate wasting'], bottom=plotting_model['severe wasting'], + color=self.__colors_model['moderate wasting'], width=bar_width, + label='moderate wasting (model)') + + # Plot the second set of bars (calibration data) + ax.bar(r2, plotting_calib['severe wasting'], + color=self.__colors_data['severe wasting'], width=bar_width, + label='severe wasting (data)') + ax.bar(r2, plotting_calib['moderate wasting'], bottom=plotting_calib['severe wasting'], + color=self.__colors_data['moderate wasting'], width=bar_width, + label='moderate wasting (data)') + + ax.set_xlabel('age group') + ax.set_ylabel('proportion') + ax.set_title(r"Wasting prevalence in children 0-59 months per each age group $\bf{at}$ $\bf{initiation}$ (2010)") + ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) + ax.set_xticklabels(order_x_axis) + ax.set_ylim([0, 0.168]) + ax.legend() + # Adjust the layout to make space for the footnote - plt.subplots_adjust(top=0.35) # Adjust the bottom margin + plt.subplots_adjust(top=0.15) # Adjust the top margin # Add footnote - fig.figure.text(0.44, 0.9, + fig.figure.text(0.43, 0.95, "proportion = number of wasted children in the age group " "/ total number of children in the age group", ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) From fac0271f35902d7eacc000a02da6b016a4d5a87d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 14 Feb 2025 23:21:33 +0000 Subject: [PATCH 333/755] RF_Wast, scenario_wast_mini_model: inci rates updated with bathtub model calibrated values; 30K pop, 15 draws (death rates) --- resources/ResourceFile_Wasting.csv | 4 ++-- .../scenarios/scenario_wasting_minimal_model.py | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 928b39213b..4091242d37 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:839d84a046f7ab83ca67b9cc272d9886adb8b0f0ff04c04c8b102d9bc7498122 -size 4376 +oid sha256:9ef3730d120e7484d9a3f0786d299cde5c8975412aa1a73b60a70e94bb4a3a30 +size 4375 diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index f6c30c3f5b..aed370fbae 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,8 +42,8 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, - number_of_draws=6, + initial_population_size=30_000, + number_of_draws=15, runs_per_draw=1, ) @@ -85,12 +85,12 @@ def modules(self): def draw_parameters(self, draw_number, rng): # Setting up just one combination to be used - base_death_rate_untreated_sam__draws = [0.17, 0.1] + base_death_rate_untreated_sam__draws = [0.17, 0.1, 0.08] mod_wast_incidence__coef = [1.0] - base_overall_mod_wast_inc_rate = 0.0023 + base_overall_mod_wast_inc_rate = 0.0475 progression_to_sev_wast__coef = [1.0] - progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.5, 0.7, 0.9] + progression_severe_wasting_monthly_props_by_agegp = [0.0200, 0.0691, 0.0470, 0.0090, 0.0065, 0.0058] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.3, 0.4, 0.5, 0.7, 0.9] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, From e689ebe538383d5f670318e601f0bd7487c553bb Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 14 Feb 2025 23:22:13 +0000 Subject: [PATCH 334/755] wast: LoggingEvents descriptions updated --- src/tlo/methods/wasting.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 8522fe5dbf..1bba78bd1a 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -2091,9 +2091,12 @@ def unscaled_wasting_prevalence_lm(intercept: Union[float, int]) -> LinearModel: class Wasting_LoggingEvent(RegularEvent, PopulationScopeEventMixin): """ - This Event logs the number of incident cases that have occurred since the previous logging event. - Analysis scripts expect that the frequency of this logging event is once per year. - """ + This Event logs the number of incident cases that have occurred since the previous logging event, the average length + of wasting cases at recovery point since the previous logging, the prevalence proportions at the time of logging, + and population sizes at the time of logging. + Analysis scripts expect that the frequency of this logging event is once per year. Logs are expected to happen on + the last day of each year. + """ def __init__(self, module): # This event to occur every year @@ -2308,9 +2311,8 @@ def apply(self, population): class Wasting_InitLoggingEvent(Event, PopulationScopeEventMixin): """ - This Event logs the number of incident cases that have occurred since the previous logging event. - Analysis scripts expect that the frequency of this logging event is once per year. - """ + This Event logs initial prevalence proportions of moderate and severe wasting, and initial population sizes. + """ def __init__(self, module): # This event to occur every year From a7089b86ac7249d8f7ff0946a00ff5b1b4a4db90 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 17 Feb 2025 18:44:18 +0000 Subject: [PATCH 335/755] scenario_wast_min_model: pars set for draw 4 (task 5) --- .../scenarios/scenario_wasting_minimal_model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index aed370fbae..49c26485ab 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -43,7 +43,7 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=30_000, - number_of_draws=15, + number_of_draws=1, runs_per_draw=1, ) @@ -85,12 +85,12 @@ def modules(self): def draw_parameters(self, draw_number, rng): # Setting up just one combination to be used - base_death_rate_untreated_sam__draws = [0.17, 0.1, 0.08] + base_death_rate_untreated_sam__draws = [0.17, 0.17] mod_wast_incidence__coef = [1.0] base_overall_mod_wast_inc_rate = 0.0475 progression_to_sev_wast__coef = [1.0] progression_severe_wasting_monthly_props_by_agegp = [0.0200, 0.0691, 0.0470, 0.0090, 0.0065, 0.0058] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.3, 0.4, 0.5, 0.7, 0.9] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.9] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, From 04d2ff9e872926168f182bc0c9fe80852ca3d477 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 17 Feb 2025 18:55:50 +0000 Subject: [PATCH 336/755] scenario_wast_min_model: multiple draws (inci rates, death rates) // 2025-02-17 (4K pop sims) --- .../scenarios/scenario_wasting_minimal_model.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 49c26485ab..7f1da1bc78 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,8 +42,8 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, - number_of_draws=1, + initial_population_size=4_000, + number_of_draws=315, runs_per_draw=1, ) @@ -85,12 +85,12 @@ def modules(self): def draw_parameters(self, draw_number, rng): # Setting up just one combination to be used - base_death_rate_untreated_sam__draws = [0.17, 0.17] - mod_wast_incidence__coef = [1.0] + base_death_rate_untreated_sam__draws = [0.05, 0.03, 0.01] + mod_wast_incidence__coef = [1.0, 0.8, 0.6, 0.4, 0.2, 0.1, 0.05] base_overall_mod_wast_inc_rate = 0.0475 - progression_to_sev_wast__coef = [1.0] + progression_to_sev_wast__coef = [1.0, 3, 5] progression_severe_wasting_monthly_props_by_agegp = [0.0200, 0.0691, 0.0470, 0.0090, 0.0065, 0.0058] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.9] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.3, 0.4, 0.5, 0.7, 0.9] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, From 490e078ffdbcaa9e74082e62e1ff31329964acf3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 17 Feb 2025 18:55:50 +0000 Subject: [PATCH 337/755] RF_Wast, wast: calibrated inc rates corrected (bug in calculations in bathtub model) --- resources/ResourceFile_Wasting.csv | 4 ++-- src/tlo/methods/wasting.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 4091242d37..3102766246 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9ef3730d120e7484d9a3f0786d299cde5c8975412aa1a73b60a70e94bb4a3a30 -size 4375 +oid sha256:294333a6ce4cadff4e351d6eb986a5b131093e309f2f63a1742e01df18a2dfb0 +size 4428 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 1bba78bd1a..8d25f164ca 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -281,8 +281,8 @@ def initialise_population(self, population): p = self.parameters print("\nPARAMETERS:") print(f"{p['base_death_rate_untreated_SAM']=}") - print(f"mod_wast_incidence__coef={p['base_overall_inc_rate_wasting']/0.0023}") - print(f"progression_to_sev_wast__coef={p['progression_severe_wasting_monthly_by_agegp'][0]/0.0027}") + print(f"mod_wast_incidence__coef={p['base_overall_inc_rate_wasting']/0.019}") + print(f"progression_to_sev_wast__coef={p['progression_severe_wasting_monthly_by_agegp'][0]/0.0144}") print("prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam=" f"{p['prob_death_after_SAMcare']*(1-0.738)/p['base_death_rate_untreated_SAM']}") print("-----------") From a75ad5fae190253f7a5ff7c3fb3e5007e44469d9 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 18 Feb 2025 00:31:15 +0000 Subject: [PATCH 338/755] scenario_wast_min_model: 30K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 7f1da1bc78..40a422b304 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=315, runs_per_draw=1, ) From b60cbf80adefadf49a88a9b1494bd5c546f8938f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 18 Feb 2025 00:31:33 +0000 Subject: [PATCH 339/755] wast: rm print --- src/tlo/methods/wasting.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 8d25f164ca..cbde3c9ffe 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -408,7 +408,6 @@ def get_prob_severe_wasting_among_wasted(self, agegp: str) -> Union[float, int]: # get probability of severe wasting: WHZ < -3 probability_less_than_minus3sd = self.parameters['prev_init_sev_by_agegp'][i] - print(f"orig init prev sev wast: {agegp=}, {probability_less_than_minus3sd=}") # make WHZ < -2 as the 100% and get the adjusted probability of severe wasting within overall wasting # return the probability of severe wasting among all wasting cases for the agegp From 92fe2bde2264cc9b29639979ff6da8107e12fa3b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 18 Feb 2025 01:56:01 +0000 Subject: [PATCH 340/755] debugging-wast, scenario_wast_min_model: prints for person_id = 28304 (1 draw, 30K pop) --- .../scenarios/scenario_wasting_minimal_model.py | 10 +++++----- src/tlo/methods/wasting.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 40a422b304..5bd95bcd61 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -43,7 +43,7 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=30_000, - number_of_draws=315, + number_of_draws=1, runs_per_draw=1, ) @@ -85,12 +85,12 @@ def modules(self): def draw_parameters(self, draw_number, rng): # Setting up just one combination to be used - base_death_rate_untreated_sam__draws = [0.05, 0.03, 0.01] - mod_wast_incidence__coef = [1.0, 0.8, 0.6, 0.4, 0.2, 0.1, 0.05] + base_death_rate_untreated_sam__draws = [0.01, 0.01] + mod_wast_incidence__coef = [0.8] base_overall_mod_wast_inc_rate = 0.0475 - progression_to_sev_wast__coef = [1.0, 3, 5] + progression_to_sev_wast__coef = [5] progression_severe_wasting_monthly_props_by_agegp = [0.0200, 0.0691, 0.0470, 0.0090, 0.0065, 0.0058] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.3, 0.4, 0.5, 0.7, 0.9] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.9] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index cbde3c9ffe..42572d381c 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -242,7 +242,7 @@ def __init__(self, name=None, resourcefilepath=None): _agrp: copy.deepcopy(blank_length_counter) for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} self.wasting_length_tracker = copy.deepcopy(self.wasting_length_tracker_blank) - self.person_of_interest_id = 3219 # debugging + self.person_of_interest_id = 28304 # debugging # define age groups self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} From 788a9f5c1b6625292530c80e62b80034345880c8 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 18 Feb 2025 19:10:36 +0000 Subject: [PATCH 341/755] wast: prints updated for current inci rates draws --- src/tlo/methods/wasting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 42572d381c..08fa786bfc 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -281,8 +281,8 @@ def initialise_population(self, population): p = self.parameters print("\nPARAMETERS:") print(f"{p['base_death_rate_untreated_SAM']=}") - print(f"mod_wast_incidence__coef={p['base_overall_inc_rate_wasting']/0.019}") - print(f"progression_to_sev_wast__coef={p['progression_severe_wasting_monthly_by_agegp'][0]/0.0144}") + print(f"mod_wast_incidence__coef={p['base_overall_inc_rate_wasting']/0.0475}") + print(f"progression_to_sev_wast__coef={p['progression_severe_wasting_monthly_by_agegp'][0]/0.0200}") print("prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam=" f"{p['prob_death_after_SAMcare']*(1-0.738)/p['base_death_rate_untreated_SAM']}") print("-----------") From cefbaef3c2881dbdada55c3d24088a35ee1f6c58 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 18 Feb 2025 23:03:29 +0000 Subject: [PATCH 342/755] test_wast: new test--test_sam_by_oedema_misdiagnosis --- tests/test_wasting.py | 64 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 17a5f96ca5..2050372217 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -906,3 +906,67 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): death_event.apply(person_id=person_id) person = df.loc[person_id] assert person['is_alive'] + +def test_sam_by_oedema_misdiagnosis(tmpdir): + """ Test when person is having SAM only by oedema, if the attendance to growth monitoring is 100%, + probability of oedema_check is 0%, death rate due to untreated SAM is 0%: + On the first day of simulation, the growth monitoring should be initialised. It should diagnose the person as having MAM and send them for SFP treatment. Then, when + HSI_SFP runs, it should recognise the person as being misdiagnosed and reschedule them for appropriate tx. """ + + dur = pd.DateOffset(days=1) + popsize = 1000 + sim = get_sim(tmpdir) + wmodule = sim.modules['Wasting'] + p = wmodule.parameters + + # Set growth monitoring attendance at 100% + p['growth_monitoring_attendance_prob'] = [1.0, 1.0, 1.0] + # Set the probability of oedema being checked at 0% + p['oedema_check_prob'] = 0.0 + # Set death rate for untreated SAM at 0% + p['base_death_rate_untreated_SAM'] = 0.0 + # Set probability of complications in SAM at 0% + p['prob_complications_in_SAM'] = 0.0 + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + print(f"\n{person_id=}") + + # Manually set this individual properties to have SAM only by oedema + df.loc[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' + df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' + df.loc[person_id, 'un_am_nutritional_oedema'] = True + wmodule.clinical_acute_malnutrition_state(person_id, df) + + # Check actual acute malnutrition status + assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' + assert not df.loc[person_id, 'un_sam_with_complications'] + + # Check after the first day, SFP event is scheduled (as the person should be misdiagnosed due to oedema not being checked) + print(f"{sim.date=}") + sfp_event_scheduled = [ + ev[1] for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) + if isinstance(ev[1], HSI_Wasting_SupplementaryFeedingProgramme_MAM) + ] + assert len(sfp_event_scheduled) == 1 + # and no OTP event scheduled + otp_event_scheduled = [ + ev[1] for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) + if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + ] + assert len(otp_event_scheduled) == 0 + + # Run the created instance of SFP event + sfp_event_scheduled[0].run(squeeze_factor=0.0) + # and check they are re-schedule for an appropriate tx + otp_event_scheduled = [ + ev[1] for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) + if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM) + ] + assert len(otp_event_scheduled) == 1 From df0a5e27481db62dda3e6dff89323d750187ac1f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 24 Feb 2025 02:31:54 +0000 Subject: [PATCH 343/755] wast & RF_Wast: pars/properties names and descriptions in line with draft paper, oedema_check_prob par added; prints updated; asserts module --- resources/ResourceFile_Wasting.csv | 4 +- src/tlo/methods/wasting.py | 64 ++++++++++++++++++------------ 2 files changed, 40 insertions(+), 28 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 3102766246..b3111fd479 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:294333a6ce4cadff4e351d6eb986a5b131093e309f2f63a1742e01df18a2dfb0 -size 4428 +oid sha256:a649010add088cfcfc41acff9451b4f7507e56cd4a8ed88f99f498c40b7191d3 +size 4435 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 08fa786bfc..50083ff839 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -74,18 +74,18 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.REAL, 'odds ratio of wasting if household wealth is middle Q3, ref group Q1'), 'or_wasting_hhwealth_Q2': Parameter( Types.REAL, 'odds ratio of wasting if household wealth is richer Q2, ref group Q1'), - 'or_wasting_preterm_and_AGA': Parameter( - Types.REAL, 'odds ratio of wasting if born preterm and adequate for gestational age'), + 'or_wasting_AGA_and_preterm': Parameter( + Types.REAL, 'odds ratio of wasting if born adequate for gestational age and preterm'), 'or_wasting_SGA_and_term': Parameter( - Types.REAL, 'odds ratio of wasting if born term and small for gestational age'), + Types.REAL, 'odds ratio of wasting if born small for gestational age and term'), 'or_wasting_SGA_and_preterm': Parameter( - Types.REAL, 'odds ratio of wasting if born preterm and small for gestational age'), + Types.REAL, 'odds ratio of wasting if born small for gestational age and preterm'), # incidence 'base_overall_inc_rate_wasting': Parameter( - Types.REAL, 'base moderate wasting incidence rate (reference age group 0-5 months old)'), + Types.REAL, 'base overall monthly moderate wasting incidence rate ' + '(ref age group <0.5 years old)'), 'rr_inc_rate_wasting_by_agegp': Parameter( - Types.LIST, 'list with relative risks of moderate wasting incidence rate by age group, reference ' - 'group 0-5 months old'), + Types.LIST, 'relative risk of moderate wasting incidence rate by age group'), 'rr_wasting_preterm_and_AGA': Parameter( Types.REAL, 'relative risk of wasting if born preterm and adequate for gestational age'), 'rr_wasting_SGA_and_term': Parameter( @@ -96,17 +96,17 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.REAL, 'relative risk of wasting per 1 unit decrease in wealth level'), # progression 'min_days_duration_of_wasting': Parameter( - Types.REAL, 'minimum duration in days of wasting (MAM and SAM)'), + Types.REAL, 'minimum limit for moderate and severe wasting duration episode (days)'), 'duration_of_untreated_mod_wasting': Parameter( Types.REAL, 'duration of untreated moderate wasting (days)'), 'duration_of_untreated_sev_wasting': Parameter( Types.REAL, 'duration of untreated severe wasting (days)'), 'progression_severe_wasting_monthly_by_agegp': Parameter( - Types.LIST, 'list with progression rates to severe wasting by age group'), + Types.LIST, 'monthly progression rate to severe wasting by age group'), 'prob_complications_in_SAM': Parameter( - Types.REAL, 'probability of medical complications in SAM '), + Types.REAL, 'probability of medical complications in a SAM episode'), 'duration_sam_to_death': Parameter( - Types.REAL, 'duration of SAM till death if supposed to die due to SAM (days)'), + Types.REAL, 'duration of SAM till death if supposed to die due to untreated SAM (days)'), 'base_death_rate_untreated_SAM': Parameter( Types.REAL, 'base death rate due to untreated SAM (reference age group <0.5 months old)'), 'rr_death_rate_by_agegp': Parameter( @@ -138,16 +138,18 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'mean and standard deviation of a normal distribution of MUAC measurements for WHZ >= -2'), # nutritional oedema 'prevalence_nutritional_oedema': Parameter( - Types.REAL, 'prevalence of nutritional oedema in children under 5 in Malawi'), + Types.REAL, 'prevalence of nutritional oedema'), 'proportion_WHZ<-2_with_oedema': Parameter( Types.REAL, 'proportion of individuals with wasting (moderate or severe) who have oedema'), 'proportion_oedema_with_WHZ<-2': Parameter( Types.REAL, 'proportion of individuals with oedema who are wasted (moderately or severely)'), # detection - 'growth_monitoring_frequency_days': Parameter( - Types.LIST, 'growth monitoring frequency (days), for children [1–2, 2–5] years old'), - 'growth_monitoring_attendance_prob': Parameter( - Types.LIST, 'probability to attend the growth monitoring, for children [1–2, 2–5] years old'), + 'growth_monitoring_frequency_days_agecat': Parameter( + Types.LIST, 'growth monitoring frequency (days) for age categories '), + 'growth_monitoring_attendance_prob_agecat': Parameter( + Types.LIST, 'probability to attend the growth monitoring for age categories'), + 'oedema_check_prob': Parameter( + Types.REAL, 'probablity of oedema being checked when acute malnutrition examined'), # recovery due to treatment/interventions 'recovery_rate_with_soy_RUSF': Parameter( Types.REAL, 'probability of recovery from wasting following treatment with soy RUSF'), @@ -189,16 +191,17 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'cut-offs', categories=['<115mm', '[115-125)mm', '>=125mm']), 'un_sam_with_complications': Property(Types.BOOL, 'medical complications in SAM episode'), - 'un_sam_death_date': Property(Types.DATE, 'death date from severe acute malnutrition'), - 'un_am_recovery_date': Property(Types.DATE, 'recovery date from last acute malnutrition episode ' - '(MAM/SAM)'), - 'un_am_discharge_date': Property(Types.DATE, 'planned discharge date from last treatment of MAM/SAM ' - 'when recovery will happen if not yet recovered'), + 'un_sam_death_date': Property(Types.DATE, 'if alive, scheduled death date from SAM if not recovers ' + 'with treatment; if not alive, date of death due to SAM'), + 'un_am_recovery_date': Property(Types.DATE, 'recovery date from last acute malnutrition episode'), + # Properties related to treatment 'un_am_tx_start_date': Property(Types.DATE, 'treatment start date, if currently on treatment'), 'un_am_treatment_type': Property(Types.CATEGORICAL, 'treatment type for acute malnutrition the person' ' is currently on; set to not_applicable if well hence no treatment required', categories=['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care'] + [ 'none', 'not_applicable']), + 'un_am_discharge_date': Property(Types.DATE, 'planned discharge date from current treatment ' + 'when recovery will happen if not yet recovered'), # Properties to help cancel events 'un_recov_to_mam_to_cancel': Property(Types.LIST, 'list of dates of scheduled natural recovery to be ' 'canceled for the person'), @@ -283,8 +286,9 @@ def initialise_population(self, population): print(f"{p['base_death_rate_untreated_SAM']=}") print(f"mod_wast_incidence__coef={p['base_overall_inc_rate_wasting']/0.0475}") print(f"progression_to_sev_wast__coef={p['progression_severe_wasting_monthly_by_agegp'][0]/0.0200}") - print("prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam=" - f"{p['prob_death_after_SAMcare']*(1-0.738)/p['base_death_rate_untreated_SAM']}") + if p['base_death_rate_untreated_SAM'] != 0: + print("prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam=" + f"{p['prob_death_after_SAMcare']*(1-0.738)/p['base_death_rate_untreated_SAM']}") print("-----------") print(f"{p['base_overall_inc_rate_wasting']=}") print("base inc rates by age group: " @@ -878,7 +882,8 @@ def do_when_am_treatment(self, person_id, intervention) -> None: else: # recovery to MAM and follow-up treatment for MAM df.at[person_id, 'un_am_discharge_date'] = outcome_date if do_prints: - print(f"recovery to MAM with {intervention=} scheduled at {outcome_date=} and sent for follow-up MAM tx") + print(f"recovery to MAM with {intervention=} scheduled at {outcome_date=} " + "and sent for follow-up MAM tx") self.sim.schedule_event(event=Wasting_RecoveryToMAM_Event(module=self, person_id=person_id), date=outcome_date) self.sim.modules['HealthSystem'].schedule_hsi_event( @@ -1109,6 +1114,7 @@ class Wasting_ProgressionToSevere_Event(Event, IndividualScopeEventMixin): def __init__(self, module, person_id): super().__init__(module, person_id=person_id) + assert isinstance(module, Wasting) def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe @@ -1194,6 +1200,7 @@ class Wasting_SevereAcuteMalnutritionDeath_Event(Event, IndividualScopeEventMixi def __init__(self, module, person_id): super().__init__(module, person_id=person_id) + assert isinstance(module, Wasting) def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe @@ -1253,6 +1260,7 @@ class Wasting_FullRecovery_Event(Event, IndividualScopeEventMixin): def __init__(self, module, person_id): super().__init__(module, person_id=person_id) + assert isinstance(module, Wasting) def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe @@ -1353,6 +1361,7 @@ class Wasting_RecoveryToMAM_Event(Event, IndividualScopeEventMixin): def __init__(self, module, person_id): super().__init__(module, person_id=person_id) + assert isinstance(module, Wasting) def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe @@ -1659,7 +1668,7 @@ def schedule_tx_by_diagnosis(hsi_event): ) complications = df.at[person_id, 'un_sam_with_complications'] - oedema_checked = rng.random_sample() < 0.1 # TODO: find correct value & add as parameter p[''] + oedema_checked = rng.random_sample() < p['oedema_check_prob'] # DIAGNOSIS # based on performed measurements (depends on whether oedema is checked, and what equipment is available) @@ -2075,7 +2084,7 @@ def unscaled_wasting_prevalence_lm(intercept: Union[float, int]) -> LinearModel: self.params['or_wasting_SGA_and_preterm']), Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") ' '& ((nb_late_preterm == True) | (nb_early_preterm == True))', - self.params['or_wasting_preterm_and_AGA']) + self.params['or_wasting_AGA_and_preterm']) ) target_mean = self.module.get_odds_wasting(agegp=agegp) @@ -2101,6 +2110,8 @@ def __init__(self, module): # This event to occur every year self.repeat = 12 super().__init__(module, frequency=DateOffset(months=self.repeat)) + assert isinstance(module, Wasting) + self.date_last_run = self.sim.date def apply(self, population): @@ -2316,6 +2327,7 @@ class Wasting_InitLoggingEvent(Event, PopulationScopeEventMixin): def __init__(self, module): # This event to occur every year super().__init__(module) + assert isinstance(module, Wasting) def apply(self, population): df = self.sim.population.props From 134f280b156a58b35cfbd3c16ba516efa8cf125b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 24 Feb 2025 16:40:30 +0000 Subject: [PATCH 344/755] wast & RF_Wast: monitoring by 3 age categories (<1, [1, 2], (2, 5) --- resources/ResourceFile_Wasting.csv | 4 ++-- src/tlo/methods/wasting.py | 14 ++++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index b3111fd479..254eee6286 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a649010add088cfcfc41acff9451b4f7507e56cd4a8ed88f99f498c40b7191d3 -size 4435 +oid sha256:026ec8e69ce709a3b5d07634a02de85f2f39aa87f82d038fcf9b231742b9bdb3 +size 4584 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 50083ff839..32b186cd75 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1510,10 +1510,13 @@ def apply(self, population): # and ~df.un_am_treatment_type.isin(['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']) def get_monitoring_frequency_days(age): - if age <= 2: # TODO: expecting here, that 0-1 will be excluded and dealt with within epi module + # TODO: 0-1 to be dealt with within epi module + if age < 1: return p['growth_monitoring_frequency_days'][0] - else: + elif age <= 2: return p['growth_monitoring_frequency_days'][1] + else: + return p['growth_monitoring_frequency_days'][2] # schedule monitoring within age-dependent frequency for person_id in index_under5: @@ -1600,10 +1603,13 @@ def apply(self, person_id, squeeze_factor): def schedule_next_monitoring(): def get_monitoring_frequency_days(age): - if age <= 2: # TODO: expecting here, that 0-1 will be excluded and dealt with within epi module + # TODO: 0-1 to be dealt with within epi module + if age < 1: return p['growth_monitoring_frequency_days'][0] - else: + elif age <= 2: return p['growth_monitoring_frequency_days'][1] + else: + return p['growth_monitoring_frequency_days'][2] person_monitoring_frequency = get_monitoring_frequency_days(df.at[person_id, 'age_exact_years']) if do_prints: From a598a040cfccdc5520cbfcd98a72b989790079f1 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 3 Mar 2025 16:11:21 +0000 Subject: [PATCH 345/755] wast: par names and descriptions in line with draft paper --- src/tlo/methods/wasting.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 32b186cd75..60dd30aefc 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -86,14 +86,17 @@ class Wasting(Module, GenericFirstAppointmentsMixin): '(ref age group <0.5 years old)'), 'rr_inc_rate_wasting_by_agegp': Parameter( Types.LIST, 'relative risk of moderate wasting incidence rate by age group'), - 'rr_wasting_preterm_and_AGA': Parameter( - Types.REAL, 'relative risk of wasting if born preterm and adequate for gestational age'), + 'rr_wasting_AGA_and_preterm': Parameter( + Types.REAL, 'relative risk of moderate wasting incidence if born adequate for gestational age ' + 'and preterm'), 'rr_wasting_SGA_and_term': Parameter( - Types.REAL, 'relative risk of wasting if born term and small for gestational age'), + Types.REAL, 'relative risk of moderate wasting incidence if born small for gestational age ' + 'and term'), 'rr_wasting_SGA_and_preterm': Parameter( - Types.REAL, 'relative risk of wasting if born preterm and small for gestational age'), + Types.REAL, 'relative risk of moderate wasting incidence if born small for gestational age ' + 'and preterm'), 'rr_wasting_wealth_level': Parameter( - Types.REAL, 'relative risk of wasting per 1 unit decrease in wealth level'), + Types.REAL, 'relative risk of moderate wasting incidence per 1 unit decrease in wealth level'), # progression 'min_days_duration_of_wasting': Parameter( Types.REAL, 'minimum limit for moderate and severe wasting duration episode (days)'), @@ -2048,7 +2051,7 @@ def unscaled_wasting_incidence_lm(intercept: Union[float, int] = 1.0) -> LinearM self.params['rr_wasting_SGA_and_preterm']), Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") ' '& ((nb_late_preterm == True) | (nb_early_preterm == True))', - self.params['rr_wasting_preterm_and_AGA']), + self.params['rr_wasting_AGA_and_preterm']), Predictor('li_wealth').apply( lambda x: 1 if x == 1 else (x - 1) ** (self.params['rr_wasting_wealth_level'])), ) From 2dcf1bd7d6039a883ad71fb0baad91fe56d1f212 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 3 Mar 2025 17:20:49 +0000 Subject: [PATCH 346/755] RF_Wast & wast: tx lengths updated according to guideline for CMAM and other REFs; follow-up SFP if remains MAM with SFP; follow-up SFP after full recovery with OTP and ITC; and sent for SFP if recovery to MAM --- resources/ResourceFile_Wasting.csv | 2 +- src/tlo/methods/wasting.py | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 254eee6286..5d29499f3f 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:026ec8e69ce709a3b5d07634a02de85f2f39aa87f82d038fcf9b231742b9bdb3 +oid sha256:ad3c8ba36b024361a579a15e94c067778c4bffeb8b7367c1c68d7a4ac8291316 size 4584 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 60dd30aefc..56b01b0cbd 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -826,15 +826,15 @@ def do_when_am_treatment(self, person_id, intervention) -> None: df.at[person_id, 'un_sam_death_date'] = pd.NaT if intervention == 'SFP': - df.at[person_id, 'un_am_discharge_date'] = \ - self.sim.date + DateOffset(weeks=p['tx_length_weeks_SuppFeedingMAM']) + outcome_date = self.sim.date + DateOffset(weeks=p['tx_length_weeks_SuppFeedingMAM']) mam_full_recovery = self.wasting_models.acute_malnutrition_recovery_mam_lm.predict( df.loc[[person_id]], self.rng ) if mam_full_recovery: - # schedule recovery date + # set discharge date and schedule recovery + df.at[person_id, 'un_am_discharge_date'] = outcome_date if do_prints: print(f"scheduled full recovery from MAM with SFP at {df.at[person_id, 'un_am_discharge_date']=}") self.sim.schedule_event( @@ -843,7 +843,10 @@ def do_when_am_treatment(self, person_id, intervention) -> None: ) # cancel progression date (in ProgressionEvent) else: - # remained MAM + # remained MAM, send for another SFP + self.sim.modules['HealthSystem'].schedule_hsi_event( + hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), + priority=0, topen=outcome_date) if do_prints: print("remained MAM with SFP") print("------------------MAM tx -> remained MAM end---------------------------------") @@ -861,12 +864,18 @@ def do_when_am_treatment(self, person_id, intervention) -> None: if sam_full_recovery: df.at[person_id, 'un_am_discharge_date'] = outcome_date # schedule full recovery - if do_prints: - print(f"scheduled full recovery from SAM with {intervention=} at {outcome_date=}") self.sim.schedule_event( event=Wasting_FullRecovery_Event(module=self, person_id=person_id), date=outcome_date ) + # send for follow-up treatment for MAM + self.sim.modules['HealthSystem'].schedule_hsi_event( + hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), + priority=0, topen=outcome_date + ) + if do_prints: + print(f"scheduled full recovery from SAM with {intervention=} at {outcome_date=} and sent for" + "follow-up MAM tx") else: outcome = self.rng.choice(['recovery_to_mam', 'death'], @@ -882,11 +891,11 @@ def do_when_am_treatment(self, person_id, intervention) -> None: date=outcome_date ) df.at[person_id, 'un_sam_death_date'] = outcome_date - else: # recovery to MAM and follow-up treatment for MAM + else: # recovery to MAM and send for treatment for MAM df.at[person_id, 'un_am_discharge_date'] = outcome_date if do_prints: print(f"recovery to MAM with {intervention=} scheduled at {outcome_date=} " - "and sent for follow-up MAM tx") + "and sent for MAM tx") self.sim.schedule_event(event=Wasting_RecoveryToMAM_Event(module=self, person_id=person_id), date=outcome_date) self.sim.modules['HealthSystem'].schedule_hsi_event( From ebf08e277b8530e281b3324b714a3a04362be306 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 3 Mar 2025 17:21:56 +0000 Subject: [PATCH 347/755] wast: next growth monitoring, make sure not in negative nmb of days --- src/tlo/methods/wasting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 56b01b0cbd..bb3f3a760c 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1532,7 +1532,8 @@ def get_monitoring_frequency_days(age): # schedule monitoring within age-dependent frequency for person_id in index_under5: - next_event_days = rng.randint(0, (get_monitoring_frequency_days(df.at[person_id, 'age_exact_years']) - 2)) + next_event_days = \ + rng.randint(0, max(0, (get_monitoring_frequency_days(df.at[person_id, 'age_exact_years']) - 2))) if (df.at[person_id, 'age_exact_years'] + (next_event_days / 365.25)) < 5: self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_GrowthMonitoring(module=self.module, person_id=person_id), From 3cf48a672ce6be239dd1aa3290df85f8bf587dcc Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 3 Mar 2025 17:31:53 +0000 Subject: [PATCH 348/755] wast: record used equipment during tx assessment --- src/tlo/methods/wasting.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index bb3f3a760c..2796f27672 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1811,9 +1811,12 @@ def apply(self, person_id, squeeze_factor): print("------------------------------") return - # Do here whatever happens to an individual during this health system interaction event + # Do here whatever happens to an individual during the admission for the treatment # ~~~~~~~~~~~~~~~~~~~~~~ - # Make request for some consumables + # Perform measurements (height/length), weight, MUAC + self.add_equipment({'Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape'}) + + # Make request for consumables consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] # individual items item_code1 = pd.unique(consumables.loc[consumables['Items'] == @@ -1878,10 +1881,12 @@ def apply(self, person_id, squeeze_factor): print("--------------OTP end1-------------------") return - # Do here whatever happens to an individual during this health - # system interaction event + # Do here whatever happens to an individual during the admission for the treatment # ~~~~~~~~~~~~~~~~~~~~~~ - # Make request for some consumables + # Perform measurements (height/length), weight, MUAC + self.add_equipment({'Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape'}) + + # Make request for consumables consumables = self.sim.modules['HealthSystem'].parameters[ 'item_and_package_code_lookups'] @@ -1946,7 +1951,12 @@ def apply(self, person_id, squeeze_factor): print("----------------------------------") return - # Make request for some consumables + # Do here whatever happens to an individual during the admission for the treatment + # ~~~~~~~~~~~~~~~~~~~~~~ + # Perform measurements (height/length, weight, MUAC) + self.add_equipment({'Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape'}) + + # Make request for consumables consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] # individual items @@ -1954,7 +1964,7 @@ def apply(self, person_id, squeeze_factor): consumables.loc[consumables['Items'] == 'SAM theraputic foods', 'Item_Code'])[0] item_code2 = pd.unique(consumables.loc[consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] - # # check availability of consumables + # check availability of consumables if self.get_consumables(item_code1) and self.get_consumables(item_code2): logger.debug(key='debug', data='consumables available, so use it.') # Log that the treatment is provided: From 9a3d06bb6b3cc38cb9ed9072b274ca063dbfe8e0 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 3 Mar 2025 17:42:21 +0000 Subject: [PATCH 349/755] wast: assert module is Wasting in apply (tx classes) --- src/tlo/methods/wasting.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 2796f27672..6c1a9b6099 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1783,7 +1783,6 @@ class HSI_Wasting_SupplementaryFeedingProgramme_MAM(HSI_Event, IndividualScopeEv def __init__(self, module, person_id): super().__init__(module, person_id=person_id) - assert isinstance(module, Wasting) # Get a blank footprint and then edit to define call on resources # of this treatment event @@ -1797,6 +1796,8 @@ def __init__(self, module, person_id): self.ALERT_OTHER_DISEASES = [] def apply(self, person_id, squeeze_factor): + assert isinstance(self.module, Wasting) + df = self.sim.population.props # p = self.module.parameters @@ -1853,7 +1854,6 @@ class HSI_Wasting_OutpatientTherapeuticProgramme_SAM(HSI_Event, IndividualScopeE def __init__(self, module, person_id): super().__init__(module, person_id=person_id) - assert isinstance(module, Wasting) # Get a blank footprint and then edit to define call on resources # of this treatment event @@ -1867,6 +1867,8 @@ def __init__(self, module, person_id): self.ALERT_OTHER_DISEASES = [] def apply(self, person_id, squeeze_factor): + assert isinstance(self.module, Wasting) + df = self.sim.population.props # p = self.module.parameters @@ -1926,7 +1928,6 @@ class HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM(HSI_Event, IndividualS def __init__(self, module, person_id): super().__init__(module, person_id=person_id) - assert isinstance(module, Wasting) # Define the necessary information for an HSI self.TREATMENT_ID = 'Undernutrition_Feeding_Inpatient' @@ -1936,6 +1937,8 @@ def __init__(self, module, person_id): self.BEDDAYS_FOOTPRINT = self.make_beddays_footprint({'general_bed': 7}) def apply(self, person_id, squeeze_factor): + assert isinstance(self.module, Wasting) + df = self.sim.population.props # p = self.module.parameters From fe16bb186c4e758a3850f0e1195a2bc00b1ed358 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 4 Mar 2025 16:14:09 +0000 Subject: [PATCH 350/755] wast & RF_Wast: initiate growth monitoring from day 1 for newborns; frequency updated to 53 days for < 1y old --- resources/ResourceFile_Wasting.csv | 2 +- src/tlo/methods/wasting.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 5d29499f3f..06493fd293 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad3c8ba36b024361a579a15e94c067778c4bffeb8b7367c1c68d7a4ac8291316 +oid sha256:49cdb369cda6e17172dc9d99e3eb15136f98b592ce1070f83afd54e1c0e1fef0 size 4584 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 6c1a9b6099..2428f97ee5 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -401,6 +401,12 @@ def on_birth(self, mother_id, child_id): df.at[child_id, 'un_progression_to_cancel'] = [] # df.at[child_id, 'un_last_nonemergency_appt_date']= pd.NaT + # initiate growth monitoring from day 1 + self.sim.modules['HealthSystem'].schedule_hsi_event( + hsi_event=HSI_Wasting_GrowthMonitoring(module=self, person_id=child_id), + priority=2, topen=self.sim.date + pd.DateOffset(days=1) + ) + def get_prob_severe_wasting_among_wasted(self, agegp: str) -> Union[float, int]: """ This function will return the probability of severe wasting for those with wasting status within the agegp From 175976f45ed269e3182a836439adf3619bbf1fb3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 4 Mar 2025 16:36:49 +0000 Subject: [PATCH 351/755] wast: oedema_check_prob rm-ed as oedema would be obvious hence so no need to focus on checking it --- src/tlo/methods/wasting.py | 93 ++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 54 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 2428f97ee5..91d200c9c2 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -151,8 +151,6 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.LIST, 'growth monitoring frequency (days) for age categories '), 'growth_monitoring_attendance_prob_agecat': Parameter( Types.LIST, 'probability to attend the growth monitoring for age categories'), - 'oedema_check_prob': Parameter( - Types.REAL, 'probablity of oedema being checked when acute malnutrition examined'), # recovery due to treatment/interventions 'recovery_rate_with_soy_RUSF': Parameter( Types.REAL, 'probability of recovery from wasting following treatment with soy RUSF'), @@ -1693,66 +1691,53 @@ def schedule_tx_by_diagnosis(hsi_event): ) complications = df.at[person_id, 'un_sam_with_complications'] - oedema_checked = rng.random_sample() < p['oedema_check_prob'] # DIAGNOSIS - # based on performed measurements (depends on whether oedema is checked, and what equipment is available) - if oedema_checked and df.at[person_id, 'un_am_nutritional_oedema']: + # oedema is assumed to be quite obvious if present + # in addition, based on performed measurements (depending on what equipment is available) + if df.at[person_id, 'un_am_nutritional_oedema']: diagnosis = 'SAM' if do_prints: - print(f"oedema checked and observed its presence => {diagnosis=}") + print(f"oedema present => {diagnosis=}") else: - if 'MUAC tape' in available_equipment: - # all equip available and used - if all(item in available_equipment for item in - ['Height Pole (Stadiometer)', 'Weighing scale']): - if oedema_checked: - diagnosis = df.at[person_id, 'un_clinical_acute_malnutrition'] - if do_prints: - print(f"oedema checked and all equip available, hence {diagnosis=} in line with actual " - f"state {df.at[person_id, 'un_clinical_acute_malnutrition']=}") - else: - whz = df.at[person_id, 'un_WHZ_category'] - muac = df.at[person_id, 'un_am_MUAC_category'] - if whz == 'WHZ>=-2' and muac == '>=125mm': - diagnosis = 'well' - elif whz == 'WHZ<-3' or muac == '<115mm': - diagnosis = 'SAM' - else: - diagnosis = 'MAM' - if do_prints: - print(f"oedema not checked but all equip available, hence {diagnosis=} based on {whz=} and " - f"{muac=},\n" - f" not on actual state {df.at[person_id, 'un_clinical_acute_malnutrition']=}") - # MUAC measurement is solely used for diagnosis + # all equip available and used for diagnosis + if all(item in available_equipment for item in + ['Height Pole (Stadiometer)', 'Weighing scale']): + diagnosis = df.at[person_id, 'un_clinical_acute_malnutrition'] + if do_prints: + print(f"oedema not present, all equip available, hence {diagnosis=} is the actual am state: " + f"{df.at[person_id, 'un_clinical_acute_malnutrition']=}") + # MUAC measurement is solely used for diagnosis, as Height Pole and/or Weighing scale not available + elif 'MUAC tape' in available_equipment: + # TODO: rm print + print("debugging-WARNING: full availability of equip assumed, we should have never get here") + muac = df.at[person_id, 'un_am_MUAC_category'] + if muac == '>=125mm': + diagnosis = 'well' + elif muac == '<115mm': + diagnosis = 'SAM' else: - print("WARNING: full availability of equip assumed, we should have never get here") - muac = df.at[person_id, 'un_am_MUAC_category'] - if muac == '>=125mm': - diagnosis = 'well' - elif muac == '<115mm': - diagnosis = 'SAM' - else: - diagnosis = 'MAM' - - else: # MUAC tape not available - print("WARNING: full availability of equip assumed, we should have never get here") - # WHZ score is solely used for diagnosis - if all(item in available_equipment for item in + diagnosis = 'MAM' + if do_prints: + print("oedema not present, MUAC tape available but heigh pole and/pr weighing scale not, hence " + f"{diagnosis=} based on {muac=}, not on actual state " + f"{df.at[person_id, 'un_clinical_acute_malnutrition']=}") + # WHZ score is solely used for diagnosis + elif all(item in available_equipment for item in ['Height Pole (Stadiometer)', 'Weighing scale']): - whz = df.at[person_id, 'un_WHZ_category'] - if whz == 'WHZ>=-2': - diagnosis = 'well' - elif whz == 'WHZ<-3': - diagnosis = 'SAM' - else: - diagnosis = 'MAM' - # WHZ score nor MUAC measurement available, hence diagnosis based solely on presence of oedema + # TODO: rm print + print("debugging-WARNING: full availability of equip assumed, we should have never get here") + whz = df.at[person_id, 'un_WHZ_category'] + if whz == 'WHZ>=-2': + diagnosis = 'well' + elif whz == 'WHZ<-3': + diagnosis = 'SAM' else: - if df.at[person_id, 'un_am_nutritional_oedema']: - diagnosis = 'SAM' - else: - diagnosis = 'well' + diagnosis = 'MAM' + # WHZ score nor MUAC measurement available, hence diagnosis based solely on presence of oedema and oedema is + # not present + else: + diagnosis = 'well' if diagnosis == 'well': if do_prints: From 93344c1d521b28a3969865a7eef285ab87e769a6 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 4 Mar 2025 16:46:39 +0000 Subject: [PATCH 352/755] wast: update TODOs (newborns already scheduled for monitoring, ...) --- src/tlo/methods/wasting.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 91d200c9c2..d71498bae7 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1496,10 +1496,8 @@ def get_min_length(in_recov_how, in_person_id, in_whz): class Wasting_InitiateGrowthMonitoring(Event, PopulationScopeEventMixin): - # TODO: will be updated for children 1-5 (monitoring for 0-1 will be integrated in epi module) - # For now, children are only monitored if in population when sim. initiated, but when new child born, it is not - # scheduled for monitoring at all yet, it needs to be done in the epi module, or if better, done in epi for 0-1, - # and scheduled to be done in here from when they are 1y old + # TODO: maybe will be updated to integrate monitoring of < 1y old in epi module, and on birth schedule to be + # monitored within wasting module only when > 1y old """ Event that schedules HSI_Wasting_GrowthMonitoring for all under-5 children for a random day within the age-dependent frequency. @@ -1521,12 +1519,12 @@ def apply(self, population): rng = self.module.rng p = self.module.parameters - # TODO: including treated children? + # TODO: including treated children? (until there is growth monitoring with tx and scheduled post-tx, yes) index_under5 = df.index[df.is_alive & (df.age_exact_years < 5)] # and ~df.un_am_treatment_type.isin(['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']) def get_monitoring_frequency_days(age): - # TODO: 0-1 to be dealt with within epi module + # TODO: maybe in future 0-1 to be dealt with within epi module if age < 1: return p['growth_monitoring_frequency_days'][0] elif age <= 2: @@ -1568,8 +1566,8 @@ def EXPECTED_APPT_FOOTPRINT(self): p = self.module.parameters person_age = self.sim.population.props.loc[self.target].age_exact_years - # TODO: for now assumed general attendence prob for <1 y old, - # later will be excluded and dealt with within epi module + # TODO: for now assumed general attendance prob for <1 y old, + # later may be excluded from here and be dealt with within epi module def get_attendance_prob(age): if age < 1: return p['growth_monitoring_attendance_prob'][0] @@ -1603,8 +1601,8 @@ def apply(self, person_id, squeeze_factor): # after treatment monitoring, where the assumed "treatment outcome" will be determined and follow-up treatment # based on that? - The easiest way (currently coded) is assuming that after treatment all measurements are # done, hence correctly diagnosed. The growth monitoring is scheduled for them as usual, ie, for instance, for - # a child 2-5 old, if they were sent for treatment via growth monitoring, they will be on treatment 3 or 4 - # weeks, but next monitoring will be done in ~5 months after the treatment. - Or we could schedule for the + # a child 2-5 old, if they were sent for treatment via growth monitoring, they will be on tx for adequate nmb + # of weeks, but next monitoring will be done in ~5 months after the treatment. - Or we could schedule for the # treated children a monitoring sooner after the treatment. if (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'age_exact_years'] >= 5): # or @@ -1620,7 +1618,7 @@ def apply(self, person_id, squeeze_factor): def schedule_next_monitoring(): def get_monitoring_frequency_days(age): - # TODO: 0-1 to be dealt with within epi module + # TODO: in future maybe 0-1 to be dealt with within epi module if age < 1: return p['growth_monitoring_frequency_days'][0] elif age <= 2: @@ -1650,7 +1648,7 @@ def get_monitoring_frequency_days(age): schedule_next_monitoring() # but if they are currently treated, the growth monitoring will not go through - # TODO: later will be scheduled for monitoring within the tx to use the resources + # TODO: later could be scheduled for monitoring within the tx to use the resources if (df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[person_id, 'un_am_tx_start_date'] < self.sim.date): if do_prints: From a9b2eca81cbd3644b6a7b2a2072e59ebc3f9356e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 4 Mar 2025 16:50:46 +0000 Subject: [PATCH 353/755] RF_Wast & test wast: oedema check rm-ed --- resources/ResourceFile_Wasting.csv | 4 +- tests/test_wasting.py | 64 ------------------------------ 2 files changed, 2 insertions(+), 66 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 06493fd293..7ac5bd1cbb 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:49cdb369cda6e17172dc9d99e3eb15136f98b592ce1070f83afd54e1c0e1fef0 -size 4584 +oid sha256:8561ddff6bb3cc68382da271473b644e3e8d150133ca5c4e5564a797c50e1a01 +size 4525 diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 2050372217..17a5f96ca5 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -906,67 +906,3 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): death_event.apply(person_id=person_id) person = df.loc[person_id] assert person['is_alive'] - -def test_sam_by_oedema_misdiagnosis(tmpdir): - """ Test when person is having SAM only by oedema, if the attendance to growth monitoring is 100%, - probability of oedema_check is 0%, death rate due to untreated SAM is 0%: - On the first day of simulation, the growth monitoring should be initialised. It should diagnose the person as having MAM and send them for SFP treatment. Then, when - HSI_SFP runs, it should recognise the person as being misdiagnosed and reschedule them for appropriate tx. """ - - dur = pd.DateOffset(days=1) - popsize = 1000 - sim = get_sim(tmpdir) - wmodule = sim.modules['Wasting'] - p = wmodule.parameters - - # Set growth monitoring attendance at 100% - p['growth_monitoring_attendance_prob'] = [1.0, 1.0, 1.0] - # Set the probability of oedema being checked at 0% - p['oedema_check_prob'] = 0.0 - # Set death rate for untreated SAM at 0% - p['base_death_rate_untreated_SAM'] = 0.0 - # Set probability of complications in SAM at 0% - p['prob_complications_in_SAM'] = 0.0 - - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - - # Get person to use: - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - print(f"\n{person_id=}") - - # Manually set this individual properties to have SAM only by oedema - df.loc[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' - df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' - df.loc[person_id, 'un_am_nutritional_oedema'] = True - wmodule.clinical_acute_malnutrition_state(person_id, df) - - # Check actual acute malnutrition status - assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' - assert not df.loc[person_id, 'un_sam_with_complications'] - - # Check after the first day, SFP event is scheduled (as the person should be misdiagnosed due to oedema not being checked) - print(f"{sim.date=}") - sfp_event_scheduled = [ - ev[1] for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) - if isinstance(ev[1], HSI_Wasting_SupplementaryFeedingProgramme_MAM) - ] - assert len(sfp_event_scheduled) == 1 - # and no OTP event scheduled - otp_event_scheduled = [ - ev[1] for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) - if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM) - ] - assert len(otp_event_scheduled) == 0 - - # Run the created instance of SFP event - sfp_event_scheduled[0].run(squeeze_factor=0.0) - # and check they are re-schedule for an appropriate tx - otp_event_scheduled = [ - ev[1] for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) - if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM) - ] - assert len(otp_event_scheduled) == 1 From 2397d5d9f7569026f0d17e13c37209acf631ba25 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 4 Mar 2025 16:59:38 +0000 Subject: [PATCH 354/755] RF_Wast & wast: par names updated --- resources/ResourceFile_Wasting.csv | 4 ++-- src/tlo/methods/wasting.py | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 7ac5bd1cbb..2c96bfc38f 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8561ddff6bb3cc68382da271473b644e3e8d150133ca5c4e5564a797c50e1a01 -size 4525 +oid sha256:0201936eabd6676c3a3c424a5ab902d09404629c4d4bd094ce766e6aabd63e83 +size 4539 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index d71498bae7..da29060cc2 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1526,11 +1526,11 @@ def apply(self, population): def get_monitoring_frequency_days(age): # TODO: maybe in future 0-1 to be dealt with within epi module if age < 1: - return p['growth_monitoring_frequency_days'][0] + return p['growth_monitoring_frequency_days_agecat'][0] elif age <= 2: - return p['growth_monitoring_frequency_days'][1] + return p['growth_monitoring_frequency_days_agecat'][1] else: - return p['growth_monitoring_frequency_days'][2] + return p['growth_monitoring_frequency_days_agecat'][2] # schedule monitoring within age-dependent frequency for person_id in index_under5: @@ -1570,11 +1570,11 @@ def EXPECTED_APPT_FOOTPRINT(self): # later may be excluded from here and be dealt with within epi module def get_attendance_prob(age): if age < 1: - return p['growth_monitoring_attendance_prob'][0] + return p['growth_monitoring_attendance_prob_agecat'][0] if age <= 2: - return p['growth_monitoring_attendance_prob'][1] + return p['growth_monitoring_attendance_prob_agecat'][1] else: - return p['growth_monitoring_attendance_prob'][2] + return p['growth_monitoring_attendance_prob_agecat'][2] # perform growth monitoring if attending self.attendance = rng.random_sample() < get_attendance_prob(person_age) @@ -1620,11 +1620,11 @@ def schedule_next_monitoring(): def get_monitoring_frequency_days(age): # TODO: in future maybe 0-1 to be dealt with within epi module if age < 1: - return p['growth_monitoring_frequency_days'][0] + return p['growth_monitoring_frequency_days_agecat'][0] elif age <= 2: - return p['growth_monitoring_frequency_days'][1] + return p['growth_monitoring_frequency_days_agecat'][1] else: - return p['growth_monitoring_frequency_days'][2] + return p['growth_monitoring_frequency_days_agecat'][2] person_monitoring_frequency = get_monitoring_frequency_days(df.at[person_id, 'age_exact_years']) if do_prints: From f81099f7083da72442fdd7bd0ab50debd6dca998 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 4 Mar 2025 21:48:36 +0000 Subject: [PATCH 355/755] wast: fix assert of wasting length, and add tolerance of 1 day to all asserts of wasting lengths --- src/tlo/methods/wasting.py | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index da29060cc2..2f2acc8677 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1329,17 +1329,24 @@ def get_min_length(in_recov_how, in_person_id, in_whz): min_length_nat = p['duration_of_untreated_mod_wasting'] else: # in_whz == 'WHZ<=-3' min_length_nat = p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] - if df.at[in_person_id, 'un_sam_with_complications']: + + # MAM + if df.at[in_person_id, 'un_clinical_acute_malnutrition'] == 'MAM': + min_length_tx = p['tx_length_weeks_SuppFeedingMAM'] * 7 + # SAM with complications + elif df.at[in_person_id, 'un_sam_with_complications']: min_length_tx = p['tx_length_weeks_InpatientSAM'] * 7 - else: # SAM without complications + # SAM without complications + else: min_length_tx = p['tx_length_weeks_OutpatientSAM'] * 7 + if in_recov_how == 'tx/nat': min_length = min(min_length_tx, min_length_nat) elif in_recov_how == 'tx': min_length = min_length_tx else: # in_recov_how == 'nat' min_length = min_length_nat - return min_length + return min_length - 1 whz = df.at[person_id, 'un_WHZ_category'] assert wasted_days >= get_min_length(recov_how, person_id, whz),\ @@ -1452,7 +1459,7 @@ def get_min_length(in_recov_how, in_person_id, in_whz): min_length = min(min_length_tx, min_length_nat) else: # in_recov_how == 'nat' min_length = min_length_nat - return min_length + return min_length - 1 assert wasted_days >= get_min_length(recov_how, person_id, whz), \ @@ -2173,35 +2180,37 @@ def apply(self, population): assert not np.isnan(length_df.loc[age_grp, recov_opt]),\ f'There is an empty length for {age_grp=}, {recov_opt=}.' if recov_opt in ['mod_MAM_nat_full_recov', 'mod_SAM_nat_full_recov', 'mod_SAM_nat_recov_to_MAM']: - assert all(length >= p['duration_of_untreated_mod_wasting'] for length in + assert all(length >= (p['duration_of_untreated_mod_wasting'] - 1) for length in self.module.wasting_length_tracker[age_grp][recov_opt]),\ f"{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < "\ - f"{p['duration_of_untreated_mod_wasting']=}; {age_grp=}, {recov_opt=}" + f"{(p['duration_of_untreated_mod_wasting'] - 1)=}; {age_grp=}, {recov_opt=}" elif recov_opt in ['sev_SAM_nat_full_recov', 'sev_SAM_nat_recov_to_MAM']: assert all(length >= - (p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting']) for + (p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] - 2) for length in self.module.wasting_length_tracker[age_grp][recov_opt]),\ - f"{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < "\ - f"duration of (mod + sev wast): {p['duration_of_untreated_mod_wasting']} days;"\ - f"{age_grp=}, {recov_opt=}" + (f"{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < duration of " + "(mod + sev wast - 2): " + f"{(p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] - 2)=} " + f"days; {age_grp=}, {recov_opt=}") elif recov_opt in ['mod_MAM_tx/nat_full_recov', 'mod_SAM_tx_full_recov', 'mod_SAM_tx/nat_recov_to_MAM', 'sev_SAM_tx_full_recov', 'sev_SAM_tx/nat_recov_to_MAM']: if recov_opt == 'mod_MAM_tx/nat_full_recov': min_length = min( (p['tx_length_weeks_SuppFeedingMAM'] * 7), p['duration_of_untreated_mod_wasting'] - ) + ) - 1 elif recov_opt in ['mod_SAM_tx_full_recov', 'sev_SAM_tx_full_recov']: - min_length = min(p['tx_length_weeks_OutpatientSAM'], p['tx_length_weeks_InpatientSAM']) * 7 + min_length = \ + (min(p['tx_length_weeks_OutpatientSAM'], p['tx_length_weeks_InpatientSAM']) * 7) - 1 elif recov_opt == 'mod_SAM_tx/nat_recov_to_MAM': min_length = min( (p['tx_length_weeks_OutpatientSAM'] * 7), (p['tx_length_weeks_InpatientSAM'] * 7), p['duration_of_untreated_mod_wasting'] - ) + ) - 1 else: # recov_opt == 'sev_SAM_tx/nat_recov_to_MAM' min_length = min( (p['tx_length_weeks_OutpatientSAM'] * 7), (p['tx_length_weeks_InpatientSAM'] * 7), (p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting']) - ) + ) - 1 assert all(length >= min_length for length in self.module.wasting_length_tracker[age_grp][recov_opt]), \ f'{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < ' \ From bc94f5ebb98c08e49847e3f1b97d0dc48fc30c8a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 4 Mar 2025 22:12:37 +0000 Subject: [PATCH 356/755] scenario_wast_min_model: 4K pop, 216 draws, incidence rates updated --- .../scenarios/scenario_wasting_minimal_model.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 5bd95bcd61..1bf537566e 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,8 +42,8 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, - number_of_draws=1, + initial_population_size=4_000, + number_of_draws=216, runs_per_draw=1, ) @@ -85,12 +85,12 @@ def modules(self): def draw_parameters(self, draw_number, rng): # Setting up just one combination to be used - base_death_rate_untreated_sam__draws = [0.01, 0.01] - mod_wast_incidence__coef = [0.8] - base_overall_mod_wast_inc_rate = 0.0475 - progression_to_sev_wast__coef = [5] - progression_severe_wasting_monthly_props_by_agegp = [0.0200, 0.0691, 0.0470, 0.0090, 0.0065, 0.0058] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.9] + base_death_rate_untreated_sam__draws = [0.1, 0.05, 0.03, 0.01] + mod_wast_incidence__coef = [1.0, 0.7, 0.4, 0.2, 0.1, 0.05] + base_overall_mod_wast_inc_rate = 0.019 + progression_to_sev_wast__coef = [1, 3, 5] + progression_severe_wasting_monthly_props_by_agegp = [0.0144, 0.0510, 0.0331, 0.0061, 0.0047, 0.0041] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.3, 0.6, 0.9] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, From 74b27b5bf1a36e311166ce1c2a7de598efb45378 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 4 Mar 2025 22:15:11 +0000 Subject: [PATCH 357/755] wast: pars prints updated --- src/tlo/methods/wasting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 2f2acc8677..c273f63e02 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -285,8 +285,8 @@ def initialise_population(self, population): p = self.parameters print("\nPARAMETERS:") print(f"{p['base_death_rate_untreated_SAM']=}") - print(f"mod_wast_incidence__coef={p['base_overall_inc_rate_wasting']/0.0475}") - print(f"progression_to_sev_wast__coef={p['progression_severe_wasting_monthly_by_agegp'][0]/0.0200}") + print(f"mod_wast_incidence__coef={p['base_overall_inc_rate_wasting']/0.019}") + print(f"progression_to_sev_wast__coef={p['progression_severe_wasting_monthly_by_agegp'][0]/0.0144}") if p['base_death_rate_untreated_SAM'] != 0: print("prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam=" f"{p['prob_death_after_SAMcare']*(1-0.738)/p['base_death_rate_untreated_SAM']}") From 047e089131d8468d19aee5d9635c6dac6a875964 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 4 Mar 2025 22:38:38 +0000 Subject: [PATCH 358/755] scenario_wast_min_model: 30K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 1bf537566e..8a6ada6df4 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=216, runs_per_draw=1, ) From 2445159b89cdc8d6436134409134c54c789e69c7 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 5 Mar 2025 00:50:13 +0000 Subject: [PATCH 359/755] scenario_wast_min_model & wast: 4K pop, pars set for draw 57; prints for person_id = 4118 --- .../scenarios/scenario_wasting_minimal_model.py | 12 ++++++------ src/tlo/methods/wasting.py | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 8a6ada6df4..e595590082 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,8 +42,8 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, - number_of_draws=216, + initial_population_size=4_000, + number_of_draws=1, runs_per_draw=1, ) @@ -85,12 +85,12 @@ def modules(self): def draw_parameters(self, draw_number, rng): # Setting up just one combination to be used - base_death_rate_untreated_sam__draws = [0.1, 0.05, 0.03, 0.01] - mod_wast_incidence__coef = [1.0, 0.7, 0.4, 0.2, 0.1, 0.05] + base_death_rate_untreated_sam__draws = [0.05, 0.05] + mod_wast_incidence__coef = [1.0] base_overall_mod_wast_inc_rate = 0.019 - progression_to_sev_wast__coef = [1, 3, 5] + progression_to_sev_wast__coef = [3] progression_severe_wasting_monthly_props_by_agegp = [0.0144, 0.0510, 0.0331, 0.0061, 0.0047, 0.0041] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.3, 0.6, 0.9] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.3] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index c273f63e02..5d83726a0b 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -246,7 +246,7 @@ def __init__(self, name=None, resourcefilepath=None): _agrp: copy.deepcopy(blank_length_counter) for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} self.wasting_length_tracker = copy.deepcopy(self.wasting_length_tracker_blank) - self.person_of_interest_id = 28304 # debugging + self.person_of_interest_id = 4118 # debugging # define age groups self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} From 8d2f91f1d3cda71b5de005bb4d6a034df2b6ac11 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 5 Mar 2025 01:14:55 +0000 Subject: [PATCH 360/755] scenario_wast_min_model: pars set for draw 56 (for 4K pop sim) --- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index e595590082..610a098fef 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -88,9 +88,9 @@ def draw_parameters(self, draw_number, rng): base_death_rate_untreated_sam__draws = [0.05, 0.05] mod_wast_incidence__coef = [1.0] base_overall_mod_wast_inc_rate = 0.019 - progression_to_sev_wast__coef = [3] + progression_to_sev_wast__coef = [1] progression_severe_wasting_monthly_props_by_agegp = [0.0144, 0.0510, 0.0331, 0.0061, 0.0047, 0.0041] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.3] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.9] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, From fc0b3be4f4fea2eaedb11f2ef384fe6f1501a113 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 5 Mar 2025 19:02:00 +0000 Subject: [PATCH 361/755] wast: cancel (in addition to natural progression) nat recovery w\ tx, outcomes fully driven by tx; simplify cancel_future_event fnc --- src/tlo/methods/wasting.py | 164 +++++++++++-------------------------- 1 file changed, 48 insertions(+), 116 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 5d83726a0b..1c54aef53f 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -233,11 +233,11 @@ def __init__(self, name=None, resourcefilepath=None): self.wasting_incident_case_tracker = copy.deepcopy(self.wasting_incident_case_tracker_blank) self.recovery_options = ['mod_MAM_nat_full_recov', - 'mod_SAM_nat_full_recov', 'mod_SAM_nat_recov_to_MAM', - 'sev_SAM_nat_full_recov', 'sev_SAM_nat_recov_to_MAM', - 'mod_MAM_tx/nat_full_recov', - 'mod_SAM_tx_full_recov', 'mod_SAM_tx/nat_recov_to_MAM', - 'sev_SAM_tx_full_recov', 'sev_SAM_tx/nat_recov_to_MAM', + 'mod_SAM_nat_recov_to_MAM', + 'sev_SAM_nat_recov_to_MAM', + 'mod_MAM_tx_full_recov', + 'mod_SAM_tx_full_recov', 'mod_SAM_tx_recov_to_MAM', + 'sev_SAM_tx_full_recov', 'sev_SAM_tx_recov_to_MAM', 'mod_not_yet_recovered', 'sev_not_yet_recovered'] blank_length_counter = dict( @@ -819,9 +819,11 @@ def do_when_am_treatment(self, person_id, intervention) -> None: do_prints = True print(f"{self.person_of_interest_id=} RECEIVING TX on {self.sim.date=}") - # Progression to severe wasting is cancelled due to the tx - self.cancel_future_event(person_id, event_type=Wasting_ProgressionToSevere_Event, - due_to='tx', do_prints=do_prints) + # natural progression or recovery is cancelled with the tx and the outcome is fully driven by tx + self.cancel_future_event(person_id, event_type=Wasting_ProgressionToSevere_Event, do_prints=do_prints) + self.cancel_future_event(person_id, event_type=Wasting_FullRecovery_Event, do_prints=do_prints) + self.cancel_future_event(person_id, event_type=Wasting_RecoveryToMAM_Event, do_prints=do_prints) + # Set the date when the treatment is provided: df.at[person_id, 'un_am_tx_start_date'] = self.sim.date # Reset tx discharge date @@ -845,7 +847,6 @@ def do_when_am_treatment(self, person_id, intervention) -> None: event=Wasting_FullRecovery_Event(module=self, person_id=person_id), date=(df.at[person_id, 'un_am_discharge_date']) ) - # cancel progression date (in ProgressionEvent) else: # remained MAM, send for another SFP self.sim.modules['HealthSystem'].schedule_hsi_event( @@ -853,7 +854,7 @@ def do_when_am_treatment(self, person_id, intervention) -> None: priority=0, topen=outcome_date) if do_prints: print("remained MAM with SFP") - print("------------------MAM tx -> remained MAM end---------------------------------") + print(f"sent for another SFP on {outcome_date=}") return elif intervention in ['OTP', 'ITC']: @@ -906,15 +907,11 @@ def do_when_am_treatment(self, person_id, intervention) -> None: hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), priority=0, topen=outcome_date) - if do_prints: - print("---------------------------tx end------------------------") - - def cancel_future_event(self, person_id, event_type, due_to, do_prints: bool) -> None: + def cancel_future_event(self, person_id, event_type, do_prints: bool) -> None: """ This function will add dates of recovery and/or progression events that need to be canceled. :param person_id: :param event_type: which event type to cancel - :param due_to: due to what event are they cancelled :param do_prints: prints for person_of_interest only """ @@ -924,59 +921,23 @@ def cancel_future_event(self, person_id, event_type, due_to, do_prints: bool) -> if isinstance(event_tuple[1], event_type)] if event_tuples: dates = [event_tuple[0] for event_tuple in event_tuples] + event_type_map = { + Wasting_RecoveryToMAM_Event: 'un_recov_to_mam_to_cancel', + Wasting_FullRecovery_Event: 'un_full_recov_to_cancel', + Wasting_ProgressionToSevere_Event: 'un_progression_to_cancel' + } + for date in dates: - if event_type == Wasting_RecoveryToMAM_Event: - df.at[person_id, 'un_recov_to_mam_to_cancel'].append(date) - elif event_type == Wasting_FullRecovery_Event: - df.at[person_id, 'un_full_recov_to_cancel'].append(date) - elif event_type == Wasting_ProgressionToSevere_Event: - df.at[person_id, 'un_progression_to_cancel'].append(date) + df.at[person_id, event_type_map[event_type]].append(date) if do_prints: - print(f"an event {event_type} for " + print(f"a natural history {event_type=} for " f"clinical_am={df.at[person_id, 'un_clinical_acute_malnutrition']}, " f"complications={df.at[person_id, 'un_sam_with_complications']} on {date=}\n" - f" is cancelled {due_to=} event") - today_rm = False - if event_type == due_to: - if due_to == Wasting_RecoveryToMAM_Event: - if self.sim.date in df.at[person_id, 'un_recov_to_mam_to_cancel']: - # TODO: why smt it is there, smt it is not? - df.at[person_id, 'un_recov_to_mam_to_cancel'].remove(self.sim.date) - today_rm = True - elif due_to == Wasting_FullRecovery_Event: - if self.sim.date in df.at[person_id, 'un_full_recov_to_cancel']: - df.at[person_id, 'un_full_recov_to_cancel'].remove(self.sim.date) - today_rm = True - if do_prints: - print(f"{event_type=}; {due_to=};\n" - f" {dates=}; {self.sim.date=}") - if today_rm: - print(f"{self.sim.date=} removed from to_cancel dates") - else: - print(f"{self.sim.date=} not included in to_cancel dates, hence no need to remove it") - elif (event_type == Wasting_ProgressionToSevere_Event) and (due_to == 'tx'): - if self.sim.date in df.at[person_id, 'un_progression_to_cancel']: - df.at[person_id, 'un_progression_to_cancel'].remove(self.sim.date) - today_rm = True - if do_prints: - print(f"{event_type=}; {due_to=};\n" - f" {dates=}; {self.sim.date=}") - if today_rm: - print(f"{self.sim.date=} removed from to_cancel dates") - else: - print(f"{self.sim.date=} not included in to_cancel dates, hence no need to remove it") - + " is cancelled due to tx, the health outcome will be driven by the tx") + print(f"the {event_type_map[event_type]}: {df.at[person_id, event_type_map[event_type]]}") else: if do_prints: - print(f"no {event_type} scheduled, hence no need to cancel any") - - if do_prints: - if event_type == Wasting_RecoveryToMAM_Event: - print(f"{df.at[person_id, 'un_recov_to_mam_to_cancel']=}") - elif event_type == Wasting_FullRecovery_Event: - print(f"{df.at[person_id, 'un_full_recov_to_cancel']=}") - elif event_type == Wasting_ProgressionToSevere_Event: - print(f"{df.at[person_id, 'un_progression_to_cancel']=}") + print(f"{event_type=} not scheduled, hence no need to cancel any") class PrintPersonPropertiesEventIfUpdated(RegularEvent, PopulationScopeEventMixin): @@ -1164,8 +1125,7 @@ def apply(self, person_id): if self.sim.date in df.at[person_id, 'un_progression_to_cancel']: df.at[person_id, 'un_progression_to_cancel'].remove(self.sim.date) if do_prints: - print("Progression to severe wasting canceled as person received tx and recovered (fully or to MAM) " - "before this day.") + print("Natural progression to severe wasting cancelled as person received tx.") print("----------------------------------") return @@ -1285,10 +1245,7 @@ def apply(self, person_id): if pd.isnull(df.at[person_id, 'un_am_tx_start_date']): recov_how = 'nat' else: - if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM': - recov_how = 'tx' - else: - recov_how = 'tx/nat' + recov_how = 'tx' do_prints = False if person_id == self.module.person_of_interest_id: @@ -1305,16 +1262,10 @@ def apply(self, person_id): if self.sim.date in df.at[person_id, 'un_full_recov_to_cancel']: df.at[person_id, 'un_full_recov_to_cancel'].remove(self.sim.date) if do_prints: - print("not going through, because the recovery was cancelled") + print("not going through, because the natural recovery was cancelled, the outcome will be driven by tx") print("----------------------------------") return - # as person fully recovers from acute malnutrition, any other scheduled recovery events will be cancelled - self.module.cancel_future_event(person_id, event_type=Wasting_FullRecovery_Event, - due_to=Wasting_FullRecovery_Event, do_prints=do_prints) - self.module.cancel_future_event(person_id, event_type=Wasting_RecoveryToMAM_Event, - due_to=Wasting_FullRecovery_Event, do_prints=do_prints) - # if not well (i.e. NOT already fully recovered with SAM tx, and send here from follow-up MAM tx) if df.at[person_id, 'un_WHZ_category'] != 'WHZ>=-2': if df.at[person_id, 'un_WHZ_category'] == '-3<=WHZ<-2': @@ -1328,7 +1279,7 @@ def get_min_length(in_recov_how, in_person_id, in_whz): if in_whz == '-3<=WHZ<-2': min_length_nat = p['duration_of_untreated_mod_wasting'] else: # in_whz == 'WHZ<=-3' - min_length_nat = p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] + min_length_nat = p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] - 1 # MAM if df.at[in_person_id, 'un_clinical_acute_malnutrition'] == 'MAM': @@ -1340,9 +1291,7 @@ def get_min_length(in_recov_how, in_person_id, in_whz): else: min_length_tx = p['tx_length_weeks_OutpatientSAM'] * 7 - if in_recov_how == 'tx/nat': - min_length = min(min_length_tx, min_length_nat) - elif in_recov_how == 'tx': + if in_recov_how == 'tx': min_length = min_length_tx else: # in_recov_how == 'nat' min_length = min_length_nat @@ -1394,7 +1343,7 @@ def apply(self, person_id): if pd.isnull(df.at[person_id, 'un_am_tx_start_date']): recov_how = 'nat' else: - recov_how = 'tx/nat' + recov_how = 'tx' do_prints = False if person_id == self.module.person_of_interest_id: @@ -1415,14 +1364,10 @@ def apply(self, person_id): if self.sim.date in df.at[person_id, 'un_recov_to_mam_to_cancel']: df.at[person_id, 'un_recov_to_mam_to_cancel'].remove(self.sim.date) if do_prints: - print("not going through, because the recovery was cancelled") + print("not going through, because the natural recovery was cancelled, the outcome will be driven by tx") print("----------------------------------") return - # as person recovered from SAM to MAM, any other scheduled recovery to MAM events will be cancelled - self.module.cancel_future_event(person_id, event_type=Wasting_RecoveryToMAM_Event, - due_to=Wasting_RecoveryToMAM_Event, do_prints=do_prints) - # For cases with normal WHZ and other acute malnutrition signs: # oedema, or low MUAC - do not change the WHZ whz = df.at[person_id, 'un_WHZ_category'] @@ -1447,20 +1392,16 @@ def apply(self, person_id): wasted_days = (self.sim.date - df.at[person_id, 'un_last_wasting_date_of_onset']).days def get_min_length(in_recov_how, in_person_id, in_whz): - if in_whz == '-3<=WHZ<-2': - min_length_nat = p['duration_of_untreated_mod_wasting'] - else: # in_whz == 'WHZ<=-3' - min_length_nat = p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] - if in_recov_how == 'tx/nat': + if in_recov_how == 'tx': if df.at[in_person_id, 'un_sam_with_complications']: - min_length_tx = p['tx_length_weeks_InpatientSAM'] * 7 + return (p['tx_length_weeks_InpatientSAM'] * 7) - 1 else: # SAM without complications - min_length_tx = p['tx_length_weeks_OutpatientSAM'] * 7 - min_length = min(min_length_tx, min_length_nat) + return (p['tx_length_weeks_OutpatientSAM'] * 7) - 1 else: # in_recov_how == 'nat' - min_length = min_length_nat - return min_length - 1 - + if in_whz == '-3<=WHZ<-2': + return p['duration_of_untreated_mod_wasting'] - 1 + else: # in_whz == 'WHZ<=-3' + return p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] - 2 assert wasted_days >= get_min_length(recov_how, person_id, whz), \ (f" The {person_id=} is wasted {wasted_days=} < minimal expected length= " @@ -1486,7 +1427,7 @@ def get_min_length(in_recov_how, in_person_id, in_whz): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' df.at[person_id, 'un_am_nutritional_oedema'] = False df.at[person_id, 'un_sam_with_complications'] = False - df.at[person_id, 'un_sam_death_date'] = pd.NaT # death is canceled if was scheduled + df.at[person_id, 'un_sam_death_date'] = pd.NaT # death is cancelled if was scheduled df.at[person_id, 'un_am_tx_start_date'] = pd.NaT # Start without treatment, treatment will be applied with HSI if care sought df.at[person_id, 'un_am_treatment_type'] = 'none' @@ -1660,6 +1601,7 @@ def get_monitoring_frequency_days(age): self.sim.date): if do_prints: print("not going through because is currently treated") + print("-----------------------------------------") return # or if HSI was already scheduled due to care-seeking, no need to attend the growth monitoring hsi_event_scheduled = [ @@ -2179,12 +2121,13 @@ def apply(self, population): length_df.loc[age_grp, recov_opt] = 0 assert not np.isnan(length_df.loc[age_grp, recov_opt]),\ f'There is an empty length for {age_grp=}, {recov_opt=}.' - if recov_opt in ['mod_MAM_nat_full_recov', 'mod_SAM_nat_full_recov', 'mod_SAM_nat_recov_to_MAM']: + + if recov_opt in ['mod_MAM_nat_full_recov', 'mod_SAM_nat_recov_to_MAM']: assert all(length >= (p['duration_of_untreated_mod_wasting'] - 1) for length in self.module.wasting_length_tracker[age_grp][recov_opt]),\ f"{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < "\ f"{(p['duration_of_untreated_mod_wasting'] - 1)=}; {age_grp=}, {recov_opt=}" - elif recov_opt in ['sev_SAM_nat_full_recov', 'sev_SAM_nat_recov_to_MAM']: + elif recov_opt in ['sev_SAM_nat_recov_to_MAM']: assert all(length >= (p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] - 2) for length in self.module.wasting_length_tracker[age_grp][recov_opt]),\ @@ -2192,25 +2135,14 @@ def apply(self, population): "(mod + sev wast - 2): " f"{(p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] - 2)=} " f"days; {age_grp=}, {recov_opt=}") - elif recov_opt in ['mod_MAM_tx/nat_full_recov', 'mod_SAM_tx_full_recov', 'mod_SAM_tx/nat_recov_to_MAM', - 'sev_SAM_tx_full_recov', 'sev_SAM_tx/nat_recov_to_MAM']: - if recov_opt == 'mod_MAM_tx/nat_full_recov': - min_length = min( - (p['tx_length_weeks_SuppFeedingMAM'] * 7), p['duration_of_untreated_mod_wasting'] - ) - 1 - elif recov_opt in ['mod_SAM_tx_full_recov', 'sev_SAM_tx_full_recov']: + elif recov_opt in ['mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', 'mod_SAM_tx_recov_to_MAM', + 'sev_SAM_tx_full_recov', 'sev_SAM_tx_recov_to_MAM']: + if recov_opt == 'mod_MAM_tx_full_recov': + min_length = (p['tx_length_weeks_SuppFeedingMAM'] * 7) - 1 + else: min_length = \ (min(p['tx_length_weeks_OutpatientSAM'], p['tx_length_weeks_InpatientSAM']) * 7) - 1 - elif recov_opt == 'mod_SAM_tx/nat_recov_to_MAM': - min_length = min( - (p['tx_length_weeks_OutpatientSAM'] * 7), (p['tx_length_weeks_InpatientSAM'] * 7), - p['duration_of_untreated_mod_wasting'] - ) - 1 - else: # recov_opt == 'sev_SAM_tx/nat_recov_to_MAM' - min_length = min( - (p['tx_length_weeks_OutpatientSAM'] * 7), (p['tx_length_weeks_InpatientSAM'] * 7), - (p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting']) - ) - 1 + assert all(length >= min_length for length in self.module.wasting_length_tracker[age_grp][recov_opt]), \ f'{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < ' \ From 2717fed37857ea07d6a461feae6b0893d5851dc8 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 5 Mar 2025 19:14:31 +0000 Subject: [PATCH 362/755] scenario_wast_min_model: 4K pop, 216 draws // 5 Mar --- .../scenarios/scenario_wasting_minimal_model.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 610a098fef..1bf537566e 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -43,7 +43,7 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=4_000, - number_of_draws=1, + number_of_draws=216, runs_per_draw=1, ) @@ -85,12 +85,12 @@ def modules(self): def draw_parameters(self, draw_number, rng): # Setting up just one combination to be used - base_death_rate_untreated_sam__draws = [0.05, 0.05] - mod_wast_incidence__coef = [1.0] + base_death_rate_untreated_sam__draws = [0.1, 0.05, 0.03, 0.01] + mod_wast_incidence__coef = [1.0, 0.7, 0.4, 0.2, 0.1, 0.05] base_overall_mod_wast_inc_rate = 0.019 - progression_to_sev_wast__coef = [1] + progression_to_sev_wast__coef = [1, 3, 5] progression_severe_wasting_monthly_props_by_agegp = [0.0144, 0.0510, 0.0331, 0.0061, 0.0047, 0.0041] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.9] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.3, 0.6, 0.9] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, From a5e3f0c6e57628d0eb9ea56f4ad8f70e8b80d5f7 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 6 Mar 2025 00:24:36 +0000 Subject: [PATCH 363/755] analysis_wast: colours for MAM and SAM updated to match colours in paper draft; rename: plot_modal_gbd_deaths_by_gender -> plot_model_gbd_deaths --- src/scripts/wasting_analyses/analysis_wasting.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 11b7dcd2e1..f2c955c55b 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -76,8 +76,8 @@ def __init__(self, in_sim_results_folder_path, in_datestamp, in_draw_nmb, in_run self.__colors_model = { 'severe wasting': cycle[0], # #1f77b4 'moderate wasting': cycle[1], # #ff7f0e - 'SAM': cycle[2], # #2ca02c - 'MAM': cycle[3], # #d62728 + 'SAM': '#B372B7', + 'MAM': '#D1BCD2', } self.__colors_data = { 'severe wasting': '#82C1EC', @@ -566,7 +566,7 @@ def plot_wasting_initial_prevalence_by_age_group(self): def add_wasting_initial_prevalence_by_age_group(self): self.fig_files.append('wasting_initial_prevalence_per_each_age_group__' + self.datestamp + '.pdf') - def plot_modal_gbd_deaths_by_gender(self): + def plot_model_gbd_deaths(self): """ compare model and GBD deaths 2010-2014 & 2015-2019 """ death_compare = \ compare_number_of_deaths(self.__log_file_path, resources_path) @@ -669,7 +669,7 @@ def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): wasting_analyses.plot_wasting_prevalence_by_age_group() # plot wasting deaths by gender as compared to GBD deaths - wasting_analyses.plot_modal_gbd_deaths_by_gender() + wasting_analyses.plot_model_gbd_deaths() # save all figures in one pdf outcome_figs_folder = Path(sim_results_folder_path + '/_outcome_figures') From 98dc0f90d7f75f6cb85c03906b860ee4f4b2820b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 6 Mar 2025 01:07:36 +0000 Subject: [PATCH 364/755] analysis_wast: rm doubled variable; make clear when var is Path or String of the path --- .../wasting_analyses/analysis_wasting.py | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index f2c955c55b..d52f8c9057 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -30,18 +30,18 @@ class WastingAnalyses: This class looks at plotting all important outputs from the wasting module """ - def __init__(self, in_sim_results_folder_path, in_datestamp, in_draw_nmb, in_run_nmb,in_png=False): - self.outcomes_folder_path = in_sim_results_folder_path + def __init__(self, sim_results_folder_path_str, in_datestamp, in_draw_nmb, in_run_nmb, in_png=False): + self.outcomes_folder_path = sim_results_folder_path_str self.datestamp = in_datestamp self.draw_nmb = in_draw_nmb self.run_nmb = in_run_nmb self.png = in_png, """bool indicating whether we want to save all figures not only as pdf, but also as png""" - sim_results_folder_path_draw_x_run_0 = in_sim_results_folder_path + f'/{draw_nmb}/{run_nmb}/' + sim_results_folder_draw_x_run_0_path_str = sim_results_folder_path_str + f'/{draw_nmb}/{run_nmb}/' sim_results_file_name_prefix = scenario_filename sim_results_file_name_extension = '.log.gz' gz_results_file_path = \ - Path(glob.glob(os.path.join(sim_results_folder_path_draw_x_run_0, + Path(glob.glob(os.path.join(sim_results_folder_draw_x_run_0_path_str, f"{sim_results_file_name_prefix}*{sim_results_file_name_extension}"))[0]) # Path to the decompressed .log file @@ -626,17 +626,14 @@ def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): # Path to the resource files used by the disease and intervention methods resources_path = Path("./resources") - # Find sim_results_folder associated with a given batch_file (and get most recent [-1]) - sim_results_folder = get_scenario_outputs(scenario_filename, outputs_path)[-1] - sim_results_parent_folder_name = str(sim_results_folder.parent) - sim_results_folder_name = sim_results_folder.name + # Find sim_results_folder_path associated with a given batch_file (and get most recent [-1]) + sim_results_folder_path = get_scenario_outputs(scenario_filename, outputs_path)[-1] + sim_results_folder_name = sim_results_folder_path.name # Get the datestamp assert sim_results_folder_name.startswith(scenario_filename + '-'),\ "The scenario output name does not correspond with the set scenario_filename." datestamp = sim_results_folder_name[(len(scenario_filename) + 1):] - # Path to the results folder - sim_results_folder_path = sim_results_parent_folder_name + '/' + sim_results_folder_name folders = [name for name in os.listdir(sim_results_folder_path) if \ os.path.isdir(os.path.join(sim_results_folder_path, name))] @@ -648,7 +645,7 @@ def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): time_start = time.time() # initialise the wasting class - wasting_analyses = WastingAnalyses(sim_results_folder_path, datestamp, draw_nmb, run_nmb) + wasting_analyses = WastingAnalyses(str(sim_results_folder_path), datestamp, draw_nmb, run_nmb) # plot wasting incidence wasting_analyses.plot_wasting_incidence() @@ -672,7 +669,7 @@ def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): wasting_analyses.plot_model_gbd_deaths() # save all figures in one pdf - outcome_figs_folder = Path(sim_results_folder_path + '/_outcome_figures') + outcome_figs_folder = sim_results_folder_path / '_outcome_figures' outcome_figs_folder.mkdir(parents=True, exist_ok=True) wasting_analyses.plot_all_figs_in_one_pdf(outcome_figs_folder) From 900f0537b31a37ce96d0b5d77bcff761eb68fe99 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 6 Mar 2025 21:38:35 +0000 Subject: [PATCH 365/755] wast: death earlier than recovery/progression --- src/tlo/methods/wasting.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 1c54aef53f..8fdf4f16d5 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -626,8 +626,9 @@ def date_of_death_for_untreated_sam(self): """ p = self.parameters - duration_sam_to_death = int(min(p['duration_of_untreated_mod_wasting'], p['duration_of_untreated_sev_wasting'], - p['duration_sam_to_death'])) + duration_sam_to_death = int(min(p['duration_of_untreated_mod_wasting'] - 1, + p['duration_of_untreated_sev_wasting'] - 1, + p['duration_sam_to_death'])) date_of_death = self.sim.date + DateOffset(days=duration_sam_to_death) return date_of_death From 2ac6613503ba74dcb1f5e0357ada7d952712fbce Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 6 Mar 2025 22:01:34 +0000 Subject: [PATCH 366/755] analysis_wast: incidence limited to 0 (when sev wast rm-ed from mod wast); warning if any incidence not within the 0-1 range --- src/scripts/wasting_analyses/analysis_wasting.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index d52f8c9057..fa90cd2c8f 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -139,10 +139,14 @@ def plot_wasting_incidence(self): plotting[state] = \ w_inc_df.apply(lambda row: row[state][age], axis=1) # remove sev cases from mod cases (all sev cases went through mod state) - plotting["-3<=WHZ<-2"] = plotting["-3<=WHZ<-2"] - plotting["WHZ<-3"] + plotting["-3<=WHZ<-2"] = plotting.apply(lambda row: max(row["-3<=WHZ<-2"] - row["WHZ<-3"], 0), axis=1) # calculate props within the age group plotting = plotting.div(age_gps_total_pop_sizes_df[age], axis=0) plotting = plotting.rename(columns=self.__wasting_types_desc) + # check for invalid values + if (plotting < 0).any().any() or (plotting > 1).any().any(): + print(f"Warning plot_wasting_incidence: Invalid values detected in plotting data for age group {age}:") + print(plotting) ax = plotting.plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], From 21ee9b27042cce11ea37217ded3ef5681fbf5b0c Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 6 Mar 2025 22:02:19 +0000 Subject: [PATCH 367/755] add_pars_page: PEP 8 --- src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py b/src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py index 0d0e7d9884..5790429adc 100644 --- a/src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py +++ b/src/scripts/wasting_analyses/add_pars_page_ToAllPDFs.py @@ -1,11 +1,11 @@ import itertools +import re +import sys +from io import BytesIO from pathlib import Path + from PyPDF2 import PdfReader, PdfWriter -from reportlab.lib.pagesizes import letter from reportlab.pdfgen import canvas -from io import BytesIO -import sys -import re # Define the parameter values in a dictionary parameters = { From 648ad56c00837ff5deb8e26b524c8492a61d530e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 6 Mar 2025 22:10:55 +0000 Subject: [PATCH 368/755] analysis_wast: incidence is annual! --- src/scripts/wasting_analyses/analysis_wasting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index fa90cd2c8f..1ca4b68685 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -150,7 +150,7 @@ def plot_wasting_incidence(self): ax = plotting.plot(kind='bar', stacked=True, ax=axes[_row_counter, _col_counter], - title=f"incidence of wasting in {age} old")#, + title=f"{age} old")#, #ylim=[0, 1]) show_legend = (_row_counter == 1 and _col_counter == 2) # show_x_axis_label = (_row_counter == 0 and _col_counter == 2) @@ -168,6 +168,7 @@ def plot_wasting_incidence(self): _row_counter += 1 _col_counter = -1 _col_counter += 1 # increment column counter + fig.suptitle('Annual incidence of wasting among the age group', fontsize=12, weight='bold') fig.tight_layout() fig_output_name = ('wasting_incidence__' + self.datestamp) self.save_fig__store_pdf_file(fig, fig_output_name) From f26e2a26c3cfe033b5a95864bee6c14791ed5fa9 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 9 Mar 2025 15:01:39 +0000 Subject: [PATCH 369/755] wast: use avg numb days in month instead of 30 --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 8fdf4f16d5..fa2a0ba573 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -299,7 +299,7 @@ def initialise_population(self, population): # Adjust monthly severe wasting incidence to the duration of untreated moderate wasting p['progression_severe_wasting_by_agegp'] = \ - [s/30*p['duration_of_untreated_mod_wasting'] for s in p['progression_severe_wasting_monthly_by_agegp']] + [s/30.4375*p['duration_of_untreated_mod_wasting'] for s in p['progression_severe_wasting_monthly_by_agegp']] print(f"{p['progression_severe_wasting_by_agegp']=}") # Set initial properties From d448d72d37c016952d2ae3bf538e5920a8b493d4 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 17 Mar 2025 23:46:49 +0000 Subject: [PATCH 370/755] wast: if total pop size of the age gp = 0, then pop sizes of mod and sev wasted within the age gp = 0 --- src/tlo/methods/wasting.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index fa2a0ba573..9b277ca8fe 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -2231,6 +2231,9 @@ def apply(self, population): high_bound_age_in_years = (1 + high_bound_mos) / 12.0 total_per_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, inclusive='left')).sum() + # add total pop size of the age group to the dataframe + pop_sizes_dict[f'total__{low_bound_mos}_{high_bound_mos}mo'] = total_per_agegrp_nmb + if total_per_agegrp_nmb > 0: # get those children who are wasted mod_wasted_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, @@ -2244,15 +2247,17 @@ def apply(self, population): mod_wasted_agegrp_nmb / total_per_agegrp_nmb wasting_prev_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = \ sev_wasted_agegrp_nmb / total_per_agegrp_nmb + # add pop sizes to the dataframe + pop_sizes_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = mod_wasted_agegrp_nmb + pop_sizes_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = sev_wasted_agegrp_nmb else: # add zero moderate and severe wasting prevalence to the dictionary wasting_prev_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = 0 wasting_prev_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = 0 + # add zero pop sizes to the dataframe + pop_sizes_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = 0 + pop_sizes_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = 0 - # add pop sizes to the dataframe - pop_sizes_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = mod_wasted_agegrp_nmb - pop_sizes_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = sev_wasted_agegrp_nmb - pop_sizes_dict[f'total__{low_bound_mos}_{high_bound_mos}mo'] = total_per_agegrp_nmb # log prevalence & pop size for children above 5y above5s = df.loc[df.is_alive & (df.age_exact_years >= 5)] assert (len(under5s) + len(above5s)) == len(df.loc[df.is_alive]), \ From eb4175cc13561257596c22ffbc7dbb263af5ecd3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 18 Mar 2025 16:25:55 +0000 Subject: [PATCH 371/755] scenario_wast_min_model & wast: progression props updated with bathtub v3 calibrated values --- .../scenarios/scenario_wasting_minimal_model.py | 8 ++++---- src/tlo/methods/wasting.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 1bf537566e..6178991777 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -43,7 +43,7 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=4_000, - number_of_draws=216, + number_of_draws=240, runs_per_draw=1, ) @@ -86,10 +86,10 @@ def modules(self): def draw_parameters(self, draw_number, rng): # Setting up just one combination to be used base_death_rate_untreated_sam__draws = [0.1, 0.05, 0.03, 0.01] - mod_wast_incidence__coef = [1.0, 0.7, 0.4, 0.2, 0.1, 0.05] + mod_wast_incidence__coef = [1.0, 0.6, 0.4, 0.2] base_overall_mod_wast_inc_rate = 0.019 - progression_to_sev_wast__coef = [1, 3, 5] - progression_severe_wasting_monthly_props_by_agegp = [0.0144, 0.0510, 0.0331, 0.0061, 0.0047, 0.0041] + progression_to_sev_wast__coef = [1.0, 1.5, 2.0, 2.3, 2.5] + progression_severe_wasting_monthly_props_by_agegp = [0.3082, 0.8614, 0.4229, 0.4337, 0.2508, 0.3321] prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.3, 0.6, 0.9] pars_combinations = list(itertools.product( diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 9b277ca8fe..203fcfe8d5 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -286,7 +286,7 @@ def initialise_population(self, population): print("\nPARAMETERS:") print(f"{p['base_death_rate_untreated_SAM']=}") print(f"mod_wast_incidence__coef={p['base_overall_inc_rate_wasting']/0.019}") - print(f"progression_to_sev_wast__coef={p['progression_severe_wasting_monthly_by_agegp'][0]/0.0144}") + print(f"progression_to_sev_wast__coef={p['progression_severe_wasting_monthly_by_agegp'][0]/0.3082}") if p['base_death_rate_untreated_SAM'] != 0: print("prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam=" f"{p['prob_death_after_SAMcare']*(1-0.738)/p['base_death_rate_untreated_SAM']}") From 601fb2985408be1b9e91fb477d7023285295227e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 18 Mar 2025 16:41:35 +0000 Subject: [PATCH 372/755] scenario_wast_min_model: old commented code rm-ed --- .../scenario_wasting_minimal_model.py | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 6178991777..fcc7f85e71 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -109,33 +109,6 @@ def draw_parameters(self, draw_number, rng): } } - # def draw_parameters(self, draw_number, rng): - # base_death_rate_untreated_sam__draws = [0.01, 0.03, 0.05, 0.08, 0.1] - # mod_wast_incidence__coef = [0.1, 0.3, 0.5, 0.7, 0.9] - # base_inc_rate_wasting_props_by_agegp = [0.0023,0.0099,0.0189,0.0102,0.003, 0.002] - # progression_to_sev_wast__coef = [1, 5, 10, 15, 20] - # progression_severe_wasting_monthly_props_by_agegp = [0.0027,0.0036,0.0079,0.0053,0.0025,0.002] - # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.85, 0.7, 0.55, 0.4] - # - # pars_combinations = list(itertools.product( - # base_death_rate_untreated_sam__draws, - # mod_wast_incidence__coef, - # progression_to_sev_wast__coef, - # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam - # )) - # return { - # 'Wasting': { - # 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], - # 'base_inc_rate_wasting_by_agegp': [s * pars_combinations[draw_number][1] for \ - # s in base_inc_rate_wasting_props_by_agegp], - # 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ - # s in progression_severe_wasting_monthly_props_by_agegp], - # 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / - # (1-0.738)) - # } - # } - - if __name__ == '__main__': from tlo.cli import scenario_run From 3538bfb5451250ce068530aa4d3e6324815f97c7 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 18 Mar 2025 16:42:37 +0000 Subject: [PATCH 373/755] scenario_wast_min_model: old comment rm-ed --- .../wasting_analyses/scenarios/scenario_wasting_minimal_model.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index fcc7f85e71..3992624ce6 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -84,7 +84,6 @@ def modules(self): # return {} def draw_parameters(self, draw_number, rng): - # Setting up just one combination to be used base_death_rate_untreated_sam__draws = [0.1, 0.05, 0.03, 0.01] mod_wast_incidence__coef = [1.0, 0.6, 0.4, 0.2] base_overall_mod_wast_inc_rate = 0.019 From b3339f552d6517dd8ec142fffa247c04e955ea36 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 19 Mar 2025 23:29:42 +0000 Subject: [PATCH 374/755] RF_Wast: progression props updated with bathtub v3 calibrated values --- resources/ResourceFile_Wasting.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 2c96bfc38f..5b4c061030 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0201936eabd6676c3a3c424a5ab902d09404629c4d4bd094ce766e6aabd63e83 +oid sha256:d567a4786bae1181f537b5e290a16f5a07074e93e8a47a54d8ab6a0c5f7d590c size 4539 From 258b9852ca308750ca8849a88520a5be4e1c777b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 19 Mar 2025 23:32:43 +0000 Subject: [PATCH 375/755] wast & RF_Wast: init prevalence with no risk factors only based on age category --- resources/ResourceFile_Wasting.csv | 4 +- src/tlo/methods/wasting.py | 219 +++++++++++------------------ 2 files changed, 83 insertions(+), 140 deletions(-) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting.csv index 5b4c061030..3d55060897 100644 --- a/resources/ResourceFile_Wasting.csv +++ b/resources/ResourceFile_Wasting.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d567a4786bae1181f537b5e290a16f5a07074e93e8a47a54d8ab6a0c5f7d590c -size 4539 +oid sha256:069a15115d9e4ffaeac19bb93ae8dc0a4245c30de7bbe183f008d63b965df7b3 +size 4304 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 203fcfe8d5..36ff89fd97 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -65,21 +65,6 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.LIST, 'initial any wasting (WHZ < -2) prevalence in 2010 by age groups'), 'prev_init_sev_by_agegp': Parameter( Types.LIST, 'initial severe wasting (WHZ < -3) prevalence in 2010 by age groups'), - # effect of risk factors on wasting prevalence - 'or_wasting_hhwealth_Q5': Parameter( - Types.REAL, 'odds ratio of wasting if household wealth is poorest Q5, ref group Q1'), - 'or_wasting_hhwealth_Q4': Parameter( - Types.REAL, 'odds ratio of wasting if household wealth is poorer Q4, ref group Q1'), - 'or_wasting_hhwealth_Q3': Parameter( - Types.REAL, 'odds ratio of wasting if household wealth is middle Q3, ref group Q1'), - 'or_wasting_hhwealth_Q2': Parameter( - Types.REAL, 'odds ratio of wasting if household wealth is richer Q2, ref group Q1'), - 'or_wasting_AGA_and_preterm': Parameter( - Types.REAL, 'odds ratio of wasting if born adequate for gestational age and preterm'), - 'or_wasting_SGA_and_term': Parameter( - Types.REAL, 'odds ratio of wasting if born small for gestational age and term'), - 'or_wasting_SGA_and_preterm': Parameter( - Types.REAL, 'odds ratio of wasting if born small for gestational age and preterm'), # incidence 'base_overall_inc_rate_wasting': Parameter( Types.REAL, 'base overall monthly moderate wasting incidence rate ' @@ -325,39 +310,39 @@ def initialise_population(self, population): # initialise wasting linear models. self.wasting_models = WastingModels(self) - # Assign wasting categories in young children at initiation - for low_bound_mos, high_bound_mos in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months - low_bound_age_in_years = low_bound_mos / 12.0 - high_bound_age_in_years = (1 + high_bound_mos) / 12.0 - # linear model external variables - agegp = f'{low_bound_mos}_{high_bound_mos}mo' - children_of_agegp = df.loc[df.is_alive & df.age_exact_years.between( - low_bound_age_in_years, high_bound_age_in_years, inclusive='left' - )] - - # apply prevalence of wasting and categorise into moderate (-3 <= WHZ < -2) or severe (WHZ < -3) wasting - wasted = \ - self.wasting_models.get_wasting_prevalence(agegp=agegp, children_of_agegp=children_of_agegp).predict( - children_of_agegp, self.rng, False - ) - probability_of_severe = self.get_prob_severe_wasting_among_wasted(agegp=agegp) - for idx in children_of_agegp.index[wasted]: - wasted_category = self.rng.choice(['WHZ<-3', '-3<=WHZ<-2'], p=[probability_of_severe, - 1 - probability_of_severe]) - df.at[idx, 'un_WHZ_category'] = wasted_category - df.at[idx, 'un_last_wasting_date_of_onset'] = self.sim.date - df.at[idx, 'un_ever_wasted'] = True - - index_under5 = df.index[df.is_alive & (df.age_exact_years < 5)] + # Assign wasting categories in children under 5 at initiation + under5s = df.loc[df.is_alive & (df.age_exact_years < 5)] + under5s_index = under5s.index + # apply prevalence of wasting and categorise into moderate (-3 <= WHZ < -2) or severe (WHZ < -3) wasting + init_wasting_bool = self.wasting_models.init_wasting_prevalence_lm.predict( + under5s, rng=self.rng, squeeze_single_row_output=False + ) + wasted = under5s.loc[init_wasting_bool] + wasted_index = wasted.index + df.loc[wasted_index, 'un_last_wasting_date_of_onset'] = self.sim.date + df.loc[wasted_index, 'un_ever_wasted'] = True + init_sev_wasting_bool = self.wasting_models.init_severe_wasting_among_wasted_lm.predict( + wasted, rng=self.rng, squeeze_single_row_output=False + ) + df.loc[init_sev_wasting_bool.index, 'un_WHZ_category'] = np.where( + init_sev_wasting_bool, 'WHZ<-3', '-3<=WHZ<-2' + ) + # calculate approximation of probability of having normal WHZ in children under 5 to be used later self.prob_normal_whz = \ - len(index_under5.intersection(df.index[df.un_WHZ_category == 'WHZ>=-2'])) / len(index_under5) + len(under5s_index.intersection(df.index[df.un_WHZ_category == 'WHZ>=-2'])) / len(under5s_index) # ----------------------------------------------------------------------------------------------------- # # # # # Give MUAC category, presence of oedema, and determine acute malnutrition state # # # # # # # # and, in SAM cases, determine presence of complications and eventually schedule death # # # # - self.clinical_signs_acute_malnutrition(index_under5) - - print(f"{self.person_of_interest_id=}") + self.clinical_signs_acute_malnutrition(under5s_index) + + print(f"\n{self.person_of_interest_id=}") + print("###########") + print(f"initial wasting: {df.loc[self.person_of_interest_id, 'un_WHZ_category']}") + print(f"initial MUAC: {df.loc[self.person_of_interest_id, 'un_am_MUAC_category']}") + print(f"initial oedema: {df.loc[self.person_of_interest_id, 'un_am_nutritional_oedema']}") + print(f"initial complicaions: {df.loc[self.person_of_interest_id, 'un_sam_with_complications']}") + print(f"initial am status: {df.loc[self.person_of_interest_id, 'un_clinical_acute_malnutrition']}") print("--------------------------------------") def initialise_simulation(self, sim): @@ -405,41 +390,6 @@ def on_birth(self, mother_id, child_id): priority=2, topen=self.sim.date + pd.DateOffset(days=1) ) - def get_prob_severe_wasting_among_wasted(self, agegp: str) -> Union[float, int]: - """ - This function will return the probability of severe wasting for those with wasting status within the agegp - :param agegp: age group defined be range in months - :return: probability of severe wasting among all wasting cases in the agegp - """ - # determine age group - i = self.age_gps_range_mo.index(agegp) - - # get probability of any wasting (WHZ < -2) for the age group - probability_less_than_minus2sd = self.parameters['prev_init_any_by_agegp'][i] - - # get probability of severe wasting: WHZ < -3 - probability_less_than_minus3sd = self.parameters['prev_init_sev_by_agegp'][i] - - # make WHZ < -2 as the 100% and get the adjusted probability of severe wasting within overall wasting - # return the probability of severe wasting among all wasting cases for the agegp - return probability_less_than_minus3sd / probability_less_than_minus2sd - - - def get_odds_wasting(self, agegp: str) -> Union[float, int]: - """ - This function will calculate the WHZ scores by categories and return odds of wasting - :param agegp: age grouped in months - :return: odds of wasting among all children of the agegp - """ - # determine age group - i = self.age_gps_range_mo.index(agegp) - - # get probability of any wasting (WHZ < -2) for the age group - probability_less_than_minus2sd = self.parameters['prev_init_any_by_agegp'][i] - - # convert probability of wasting to odds and return the odds of wasting - return probability_less_than_minus2sd / (1 - probability_less_than_minus2sd) - def muac_cutoff_by_WHZ(self, idx, whz): """ Proportion of MUAC < 115 mm in WHZ < -3 and -3 <= WHZ < -2, @@ -1010,8 +960,8 @@ def apply(self, population): # Determine who will be onset with wasting among those who are not currently wasted ------------- not_am_or_treated = df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_clinical_acute_malnutrition == 'well') & (df.un_am_tx_start_date.isna())] - incidence_of_wasting = self.module.wasting_models.wasting_incidence_lm.predict(not_am_or_treated, rng=rng) - mod_wasting_new_cases = not_am_or_treated.loc[incidence_of_wasting] + incidence_of_wasting_bool = self.module.wasting_models.wasting_incidence_lm.predict(not_am_or_treated, rng=rng) + mod_wasting_new_cases = not_am_or_treated.loc[incidence_of_wasting_bool] mod_wasting_new_cases_idx = mod_wasting_new_cases.index # update the properties for new cases of wasted children df.loc[mod_wasting_new_cases_idx, 'un_ever_wasted'] = True @@ -1047,13 +997,13 @@ def apply(self, population): # # # PROGRESS TO SEVERE WASTING # # # # # # # # # # # # # # # # # # # Determine those that will progress to severe wasting (WHZ < -3) and schedule progression event --------- - progression_severe_wasting = self.module.wasting_models.severe_wasting_progression_lm.predict( + progression_severe_wasting_bool = self.module.wasting_models.severe_wasting_progression_lm.predict( df.loc[mod_wasting_new_cases_idx], rng=rng, squeeze_single_row_output=False ) if do_prints: - print(f"{outcome_date=},\n {progression_severe_wasting=}") + print(f"{outcome_date=},\n {progression_severe_wasting_bool=}") - for person_id in mod_wasting_new_cases_idx[progression_severe_wasting]: + for person_id in mod_wasting_new_cases_idx[progression_severe_wasting_bool]: # schedule severe wasting WHZ < -3 onset after duration of untreated moderate wasting self.sim.schedule_event( event=Wasting_ProgressionToSevere_Event(module=self.module, person_id=person_id), date=outcome_date @@ -1063,7 +1013,7 @@ def apply(self, population): # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # Schedule recovery for those not progressing to severe wasting --------- - for person_id in mod_wasting_new_cases_idx[~progression_severe_wasting]: + for person_id in mod_wasting_new_cases_idx[~progression_severe_wasting_bool]: if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM': # schedule full recovery after duration of moderate wasting self.sim.schedule_event(event=Wasting_FullRecovery_Event( @@ -1469,7 +1419,7 @@ def apply(self, population): p = self.module.parameters # TODO: including treated children? (until there is growth monitoring with tx and scheduled post-tx, yes) - index_under5 = df.index[df.is_alive & (df.age_exact_years < 5)] + under5_idx = df.index[df.is_alive & (df.age_exact_years < 5)] # and ~df.un_am_treatment_type.isin(['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']) def get_monitoring_frequency_days(age): @@ -1482,7 +1432,7 @@ def get_monitoring_frequency_days(age): return p['growth_monitoring_frequency_days_agecat'][2] # schedule monitoring within age-dependent frequency - for person_id in index_under5: + for person_id in under5_idx: next_event_days = \ rng.randint(0, max(0, (get_monitoring_frequency_days(df.at[person_id, 'age_exact_years']) - 2))) if (df.at[person_id, 'age_exact_years'] + (next_event_days / 365.25)) < 5: @@ -1938,22 +1888,40 @@ def __init__(self, module): self.rng = module.rng self.params = module.parameters - # a linear model to predict the probability of individual's recovery from moderate acute malnutrition - self.acute_malnutrition_recovery_mam_lm = LinearModel.multiplicative( - Predictor('un_am_treatment_type', + # Linear model for the probability of initial wasting (age-dependent only) + self.init_wasting_prevalence_lm = LinearModel.multiplicative( + Predictor('age_exact_years', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) - .when('soy_RUSF', self.params['recovery_rate_with_soy_RUSF']) - .when('CSB++', self.params['recovery_rate_with_CSB++']) + .when('<0.5', self.params['prev_init_any_by_agegp'][0]) + .when('.between(0.5,1, inclusive="left")', self.params['prev_init_any_by_agegp'][1]) + .when('.between(1,2, inclusive="left")', self.params['prev_init_any_by_agegp'][2]) + .when('.between(2,3, inclusive="left")', self.params['prev_init_any_by_agegp'][3]) + .when('.between(3,4, inclusive="left")', self.params['prev_init_any_by_agegp'][4]) + .when('.between(4,5, inclusive="left")', self.params['prev_init_any_by_agegp'][5]) + .when('>=5', 0) ) - # a linear model to predict the probability of individual's recovery from severe acute malnutrition - self.acute_malnutrition_recovery_sam_lm = LinearModel.multiplicative( - Predictor('un_am_treatment_type', + self.init_severe_wasting_among_wasted_lm = LinearModel.multiplicative( + Predictor('age_exact_years', conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) - .when('standard_RUTF', self.params['recovery_rate_with_standard_RUTF']) - .when('inpatient_care', self.params['recovery_rate_with_inpatient_care']) + .when('<0.5', + self.params['prev_init_sev_by_agegp'][0]/self.params['prev_init_any_by_agegp'][0]) + .when('.between(0.5,1, inclusive="left")', + self.params['prev_init_sev_by_agegp'][1]/self.params['prev_init_any_by_agegp'][1]) + .when('.between(1,2, inclusive="left")', + self.params['prev_init_sev_by_agegp'][2]/self.params['prev_init_any_by_agegp'][2]) + .when('.between(2,3, inclusive="left")', + self.params['prev_init_sev_by_agegp'][3]/self.params['prev_init_any_by_agegp'][3]) + .when('.between(3,4, inclusive="left")', + self.params['prev_init_sev_by_agegp'][4]/self.params['prev_init_any_by_agegp'][4]) + .when('.between(4,5, inclusive="left")', + self.params['prev_init_sev_by_agegp'][5]/self.params['prev_init_any_by_agegp'][5]) + .when('>=5', 0) ) + # Get wasting incidence linear model + self.wasting_incidence_lm = self.get_wasting_incidence() + # Linear model for the probability of progression to severe wasting (age-dependent only) # (natural history only, no interventions) self.severe_wasting_progression_lm = LinearModel.multiplicative( @@ -1968,10 +1936,7 @@ def __init__(self, module): .when('>=5', 0) ) - # get wasting incidence linear model - self.wasting_incidence_lm = self.get_wasting_incidence() - - # Linear model for the probability of death due to SAM + # Linear model for the probability of death due to untreated SAM self.death_due_to_sam_lm = LinearModel( LinearModelType.MULTIPLICATIVE, self.params['base_death_rate_untreated_SAM'], @@ -1986,6 +1951,22 @@ def __init__(self, module): Predictor().when('un_clinical_acute_malnutrition != "SAM"', 0), ) + # Linear model to predict the probability of individual's recovery from moderate acute malnutrition w\ tx + self.acute_malnutrition_recovery_mam_lm = LinearModel.multiplicative( + Predictor('un_am_treatment_type', + conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) + .when('soy_RUSF', self.params['recovery_rate_with_soy_RUSF']) + .when('CSB++', self.params['recovery_rate_with_CSB++']) + ) + + # Linear model to predict the probability of individual's recovery from severe acute malnutrition w\ tx + self.acute_malnutrition_recovery_sam_lm = LinearModel.multiplicative( + Predictor('un_am_treatment_type', + conditions_are_mutually_exclusive=True, conditions_are_exhaustive=True) + .when('standard_RUTF', self.params['recovery_rate_with_standard_RUTF']) + .when('inpatient_care', self.params['recovery_rate_with_inpatient_care']) + ) + def get_wasting_incidence(self) -> LinearModel: """ :return: the scaled multiplicative linear model of wasting incidence rate @@ -2030,44 +2011,6 @@ def unscaled_wasting_incidence_lm(intercept: Union[float, int] = 1.0) -> LinearM return scaled_wasting_incidence_lm - def get_wasting_prevalence(self, agegp: str, children_of_agegp: pd.DataFrame) -> LinearModel: - """ - :param agegp: children's age group - :param children_of_agegp: df with children in the age group - :return: the scaled logistic linear model of wasting prevalence, i.e., odds of wasting among the specific agegp - """ - - def unscaled_wasting_prevalence_lm(intercept: Union[float, int]) -> LinearModel: - return LinearModel( - LinearModelType.LOGISTIC, - intercept, # baseline odds: get_odds_wasting(agegp=agegp) - Predictor('li_wealth', - conditions_are_mutually_exclusive=True, conditions_are_exhaustive=False) - .when(2, self.params['or_wasting_hhwealth_Q2']) - .when(3, self.params['or_wasting_hhwealth_Q3']) - .when(4, self.params['or_wasting_hhwealth_Q4']) - .when(5, self.params['or_wasting_hhwealth_Q5']), - Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& (nb_late_preterm == False) & (nb_early_preterm == False)', - self.params['or_wasting_SGA_and_term']), - Predictor().when('(nb_size_for_gestational_age == "small_for_gestational_age") ' - '& ((nb_late_preterm == True) | (nb_early_preterm == True))', - self.params['or_wasting_SGA_and_preterm']), - Predictor().when('(nb_size_for_gestational_age == "average_for_gestational_age") ' - '& ((nb_late_preterm == True) | (nb_early_preterm == True))', - self.params['or_wasting_AGA_and_preterm']) - ) - - target_mean = self.module.get_odds_wasting(agegp=agegp) - unscaled_lm = unscaled_wasting_prevalence_lm(intercept=target_mean) - actual_mean = unscaled_lm.predict(children_of_agegp).mean() - scaled_intercept = target_mean * (target_mean / actual_mean) if \ - (target_mean != 0 and actual_mean != 0 and ~np.isnan(actual_mean)) else target_mean - scaled_wasting_prevalence_lm = unscaled_wasting_prevalence_lm(intercept=scaled_intercept) - - return scaled_wasting_prevalence_lm - - class Wasting_LoggingEvent(RegularEvent, PopulationScopeEventMixin): """ This Event logs the number of incident cases that have occurred since the previous logging event, the average length From 333e020576126a2283b964a8a0a46b1ecc0134c9 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 19 Mar 2025 23:38:50 +0000 Subject: [PATCH 376/755] scenario_wast_min_model: 30K pop, 216 draws with the new progress rates --- .../scenarios/scenario_wasting_minimal_model.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 3992624ce6..6978850ea0 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,8 +42,8 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, - number_of_draws=240, + initial_population_size=30_000, + number_of_draws=216, runs_per_draw=1, ) @@ -85,9 +85,9 @@ def modules(self): def draw_parameters(self, draw_number, rng): base_death_rate_untreated_sam__draws = [0.1, 0.05, 0.03, 0.01] - mod_wast_incidence__coef = [1.0, 0.6, 0.4, 0.2] + mod_wast_incidence__coef = [1.0, 0.6, 0.2] base_overall_mod_wast_inc_rate = 0.019 - progression_to_sev_wast__coef = [1.0, 1.5, 2.0, 2.3, 2.5] + progression_to_sev_wast__coef = [0.25, 0.5, 1.0, 1.5, 2.0, 2.3] progression_severe_wasting_monthly_props_by_agegp = [0.3082, 0.8614, 0.4229, 0.4337, 0.2508, 0.3321] prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.3, 0.6, 0.9] From e1e2e41fcca0e0467b253ef051e8b1ae6a71f975 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 20 Mar 2025 11:01:11 +0000 Subject: [PATCH 377/755] scenario_wast_min_model: 4K pop // Mar 20 --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 6978850ea0..9d6c0f8e65 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + initial_population_size=4_000, number_of_draws=216, runs_per_draw=1, ) From fee68d6bbdea2976d8c361dbb905983b84e4fcb0 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 20 Mar 2025 12:52:44 +0000 Subject: [PATCH 378/755] wast: prints (if person of interest not born say so and note when born) --- src/tlo/methods/wasting.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 36ff89fd97..bc34288424 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -338,11 +338,14 @@ def initialise_population(self, population): print(f"\n{self.person_of_interest_id=}") print("###########") - print(f"initial wasting: {df.loc[self.person_of_interest_id, 'un_WHZ_category']}") - print(f"initial MUAC: {df.loc[self.person_of_interest_id, 'un_am_MUAC_category']}") - print(f"initial oedema: {df.loc[self.person_of_interest_id, 'un_am_nutritional_oedema']}") - print(f"initial complicaions: {df.loc[self.person_of_interest_id, 'un_sam_with_complications']}") - print(f"initial am status: {df.loc[self.person_of_interest_id, 'un_clinical_acute_malnutrition']}") + if self.person_of_interest_id in df.index: + print(f"initial wasting: {df.loc[self.person_of_interest_id, 'un_WHZ_category']}") + print(f"initial MUAC: {df.loc[self.person_of_interest_id, 'un_am_MUAC_category']}") + print(f"initial oedema: {df.loc[self.person_of_interest_id, 'un_am_nutritional_oedema']}") + print(f"initial complicaions: {df.loc[self.person_of_interest_id, 'un_sam_with_complications']}") + print(f"initial am status: {df.loc[self.person_of_interest_id, 'un_clinical_acute_malnutrition']}") + else: + print("person_of_interest not born yet") print("--------------------------------------") def initialise_simulation(self, sim): @@ -390,6 +393,10 @@ def on_birth(self, mother_id, child_id): priority=2, topen=self.sim.date + pd.DateOffset(days=1) ) + if child_id == self.person_of_interest_id: + print(f"person_of_interest born {self.sim.date=}") + print("-------") + def muac_cutoff_by_WHZ(self, idx, whz): """ Proportion of MUAC < 115 mm in WHZ < -3 and -3 <= WHZ < -2, From 962a46ce4ec0ae4b2c905e540747a3bc6f5171d7 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 20 Mar 2025 14:31:21 +0000 Subject: [PATCH 379/755] debugging-wast & scenario_wast_min_model: p. of inter. = 5315, draw 10 (job 11) --- .../scenarios/scenario_wasting_minimal_model.py | 6 +++--- src/tlo/methods/wasting.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 9d6c0f8e65..36960729ee 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -43,7 +43,7 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=4_000, - number_of_draws=216, + number_of_draws=1, runs_per_draw=1, ) @@ -87,9 +87,9 @@ def draw_parameters(self, draw_number, rng): base_death_rate_untreated_sam__draws = [0.1, 0.05, 0.03, 0.01] mod_wast_incidence__coef = [1.0, 0.6, 0.2] base_overall_mod_wast_inc_rate = 0.019 - progression_to_sev_wast__coef = [0.25, 0.5, 1.0, 1.5, 2.0, 2.3] + progression_to_sev_wast__coef = [1.5] #[0.25, 0.5, 1.0, 1.5, 2.0, 2.3] progression_severe_wasting_monthly_props_by_agegp = [0.3082, 0.8614, 0.4229, 0.4337, 0.2508, 0.3321] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.3, 0.6, 0.9] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.6] #[0.3, 0.6, 0.9] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index bc34288424..a40c28e180 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -231,7 +231,7 @@ def __init__(self, name=None, resourcefilepath=None): _agrp: copy.deepcopy(blank_length_counter) for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} self.wasting_length_tracker = copy.deepcopy(self.wasting_length_tracker_blank) - self.person_of_interest_id = 4118 # debugging + self.person_of_interest_id = 5315 # debugging # define age groups self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} From 81127d1072b0204d83436021669f4d40f9b8ea97 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 21 Mar 2025 11:40:57 +0000 Subject: [PATCH 380/755] wast: discharge healthy person from follow-up SFP through full recovery; minor (print) --- src/tlo/methods/wasting.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index a40c28e180..5330e5d317 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -791,10 +791,14 @@ def do_when_am_treatment(self, person_id, intervention) -> None: if intervention == 'SFP': outcome_date = self.sim.date + DateOffset(weeks=p['tx_length_weeks_SuppFeedingMAM']) - - mam_full_recovery = self.wasting_models.acute_malnutrition_recovery_mam_lm.predict( - df.loc[[person_id]], self.rng - ) + # follow-up SFP in a recovered person leads to discharge through "full recovery" + if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well': + mam_full_recovery = True + # otherwise, it is decided probabilistically whether the person fully recovers or remains MAM + else: + mam_full_recovery = self.wasting_models.acute_malnutrition_recovery_mam_lm.predict( + df.loc[[person_id]], self.rng + ) if mam_full_recovery: # set discharge date and schedule recovery @@ -837,7 +841,7 @@ def do_when_am_treatment(self, person_id, intervention) -> None: priority=0, topen=outcome_date ) if do_prints: - print(f"scheduled full recovery from SAM with {intervention=} at {outcome_date=} and sent for" + print(f"scheduled full recovery from SAM with {intervention=} at {outcome_date=} and sent for " "follow-up MAM tx") else: From bbe76ab8894e2d283af2442caf6184ce10ab0b0d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 21 Mar 2025 11:42:37 +0000 Subject: [PATCH 381/755] wast & test_wast: cannot become wasted if recovered in last 14 days --- src/tlo/methods/wasting.py | 36 +++++++++++++++++++++++++++++++----- tests/test_wasting.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 5330e5d317..4dd6bf9230 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -968,11 +968,37 @@ def apply(self, population): rng = self.module.rng # # # INCIDENCE OF MODERATE WASTING # # # # # # # # # # # # # # # # # # # # # - # Determine who will be onset with wasting among those who are not currently wasted ------------- - not_am_or_treated = df.loc[df.is_alive & (df.age_exact_years < 5) & - (df.un_clinical_acute_malnutrition == 'well') & (df.un_am_tx_start_date.isna())] - incidence_of_wasting_bool = self.module.wasting_models.wasting_incidence_lm.predict(not_am_or_treated, rng=rng) - mod_wasting_new_cases = not_am_or_treated.loc[incidence_of_wasting_bool] + if self.module.person_of_interest_id in df.index: + print("\nINCIDENCE") + # Determine who will be onset with wasting among those who + # currently do not have acute malnutrition, are not being treated, and did not recover in the last 14 days + not_am_or_treated_or_recently_recovered =\ + df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_clinical_acute_malnutrition == 'well') & + (df.un_am_tx_start_date.isna()) & + (df.un_am_recovery_date.isna() | (df.un_am_recovery_date < self.sim.date - pd.DateOffset(days=14)))] + if self.module.person_of_interest_id not in not_am_or_treated_or_recently_recovered.index: + print("person of interest cannot become wasted, because ") + if not df.at[self.module.person_of_interest_id, 'is_alive']: + print("is dead") + elif df.at[self.module.person_of_interest_id, 'age_exact_years'] >= 5: + print("is 5+ ys old") + elif not df.at[self.module.person_of_interest_id, 'un_clinical_acute_malnutrition'] == 'well': + print("has acute malnutrition") + elif not pd.isna(df.at[self.module.person_of_interest_id, 'un_am_tx_start_date']): + print("is currently treated") + elif (not pd.isna(df.at[self.module.person_of_interest_id, 'un_am_recovery_date']) and + (df.at[self.module.person_of_interest_id, 'un_am_recovery_date'] >= + self.sim.date - pd.DateOffset(days=14))): + print("recovered in last 14 days") + else: + print(f"{df.at[self.module.person_of_interest_id, 'un_am_recovery_date']=}") + print("smt strange happening - do investigate!") + else: + print("person of interest can become wasted") + + incidence_of_wasting_bool = \ + self.module.wasting_models.wasting_incidence_lm.predict(not_am_or_treated_or_recently_recovered, rng=rng) + mod_wasting_new_cases = not_am_or_treated_or_recently_recovered.loc[incidence_of_wasting_bool] mod_wasting_new_cases_idx = mod_wasting_new_cases.index # update the properties for new cases of wasted children df.loc[mod_wasting_new_cases_idx, 'un_ever_wasted'] = True diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 17a5f96ca5..e5a55fd1cf 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -906,3 +906,37 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): death_event.apply(person_id=person_id) person = df.loc[person_id] assert person['is_alive'] + +def test_no_wasting_after_recent_recovery(tmpdir): + """ Test that a person who recovered from wasting 5 days ago does not become wasted again. """ + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + wmodule = sim.modules['Wasting'] + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + + # Manually set this individual properties to be well and recovered 5 days ago + df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' + df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' + df.loc[person_id, 'un_am_nutritional_oedema'] = False + df.loc[person_id, 'un_clinical_acute_malnutrition'] = 'well' + df.loc[person_id, 'un_am_recovery_date'] = sim.date - pd.DateOffset(days=5) + + # Set incidence of wasting at 100% + wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() + + # Run Wasting Polling event + polling = Wasting_IncidencePoll(module=wmodule) + polling.apply(sim.population) + + # Check properties of this individual: should still be well + person = df.loc[person_id] + assert person['un_clinical_acute_malnutrition'] == 'well' From 92dd40f0ab63ce847be61ebd238c206e4a7d60af Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 21 Mar 2025 11:58:06 +0000 Subject: [PATCH 382/755] scenario_wast_min_model: back 216 draws, 4K pop // Mar 21 --- .../scenarios/scenario_wasting_minimal_model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 36960729ee..9d6c0f8e65 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -43,7 +43,7 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=4_000, - number_of_draws=1, + number_of_draws=216, runs_per_draw=1, ) @@ -87,9 +87,9 @@ def draw_parameters(self, draw_number, rng): base_death_rate_untreated_sam__draws = [0.1, 0.05, 0.03, 0.01] mod_wast_incidence__coef = [1.0, 0.6, 0.2] base_overall_mod_wast_inc_rate = 0.019 - progression_to_sev_wast__coef = [1.5] #[0.25, 0.5, 1.0, 1.5, 2.0, 2.3] + progression_to_sev_wast__coef = [0.25, 0.5, 1.0, 1.5, 2.0, 2.3] progression_severe_wasting_monthly_props_by_agegp = [0.3082, 0.8614, 0.4229, 0.4337, 0.2508, 0.3321] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.6] #[0.3, 0.6, 0.9] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.3, 0.6, 0.9] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, From 0c869d3281d33826004b882e78593057ec15f7d3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 21 Mar 2025 23:49:33 +0000 Subject: [PATCH 383/755] analysis_wast: update font sizes, and order of plots as in final pdf --- .../wasting_analyses/analysis_wasting.py | 192 +++++++++--------- 1 file changed, 99 insertions(+), 93 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 1ca4b68685..cd4039aff8 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -22,6 +22,8 @@ # ####### TO SET ####################################################################################################### scenario_filename = 'wasting_analysis__minimal_model' outputs_path = Path("./outputs/sejjej5@ucl.ac.uk/wasting") +legend_fontsize = 12 +title_fontsize = 16 ######################################################################################################################## @@ -155,7 +157,7 @@ def plot_wasting_incidence(self): show_legend = (_row_counter == 1 and _col_counter == 2) # show_x_axis_label = (_row_counter == 0 and _col_counter == 2) if show_legend: - ax.legend(loc='center') + ax.legend(loc='center', fontsize=legend_fontsize) ax.set_title('') else: ax.get_legend().remove() @@ -168,7 +170,7 @@ def plot_wasting_incidence(self): _row_counter += 1 _col_counter = -1 _col_counter += 1 # increment column counter - fig.suptitle('Annual incidence of wasting among the age group', fontsize=12, weight='bold') + fig.suptitle('Annual incidence of wasting among the age group', fontsize=title_fontsize) #, weight='bold') fig.tight_layout() fig_output_name = ('wasting_incidence__' + self.datestamp) self.save_fig__store_pdf_file(fig, fig_output_name) @@ -366,15 +368,102 @@ def plot_wasting_prevalence_per_year(self): bottom += w_prev_plot_df[col] ax.set_xticks(pos) ax.set_xticklabels(w_prev_plot_df.index, rotation=90) - ax.set_title("Wasting prevalence in children 0-59 months per year") + ax.set_title("Wasting prevalence in children 0-59 months per year", fontsize=title_fontsize-6) ax.set_ylabel('proportion of wasted children in the year') ax.set_xlabel('year') - ax.legend() + ax.set_ylim([0, 0.131]) + ax.legend(fontsize=legend_fontsize-4) plt.tight_layout() fig_output_name = ('wasting_prevalence_per_year__' + self.datestamp) self.save_fig__store_pdf_file(fig, fig_output_name) # plt.show() + def plot_wasting_initial_prevalence_by_age_group(self): + """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of + children wasted in a particular age-group divided by the total number of children per that age-group""" + + # Initial prevalence at the beginning of 2010 - model + w_prev_df = self.__w_logs_dict["wasting_init_prevalence_props"] + w_prev_df = w_prev_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) + w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) + w_prev_df = w_prev_df.drop(columns='date') + + # 2010 prevalence calibration data + data_2010 = { + 'wasted_calib': [7.0, 13.0, 12.7, 2.4, 2.7, 1.9, 0.0], + 'sev_wast_calib': [2.1, 7.1, 4.7, 0.9, 0.7, 0.6, 0.0] + } + data_2010['mod_wast_calib'] = \ + [(w - s)/100 for w, s in zip(data_2010['wasted_calib'], data_2010['sev_wast_calib'])] + data_2010['sev_wast_calib'] = \ + [s/100 for s in data_2010['sev_wast_calib']] + + # Prepare plotting data + plotting_model = {'severe wasting': {}, 'moderate wasting': {}} + for col in w_prev_df.columns: + prefix, age_group = col.split('__') + if prefix == 'sev': + plotting_model['severe wasting'][age_group] = w_prev_df[col].values[0] + elif prefix == 'mod': + plotting_model['moderate wasting'][age_group] = w_prev_df[col].values[0] + plotting_model = pd.DataFrame(plotting_model) + + plotting_calib = {'severe wasting': {}, 'moderate wasting': {}} + age_groups = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] + for i, age_group in enumerate(age_groups): + plotting_calib['severe wasting'][age_group] = data_2010['sev_wast_calib'][i] + plotting_calib['moderate wasting'][age_group] = data_2010['mod_wast_calib'][i] + plotting_calib = pd.DataFrame(plotting_calib) + + order_x_axis = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] + plotting_model = plotting_model.reindex(order_x_axis) + plotting_calib = plotting_calib.reindex(order_x_axis) + + # Plot wasting prevalence + fig, ax = plt.subplots(figsize=(10, 6)) + bar_width = 0.35 + # Set positions of bars on x-axis + r1 = range(len(plotting_model)) + r2 = [x + bar_width for x in r1] + + # Plot the first set of bars (model data) + ax.bar(r1, plotting_model['severe wasting'], + color=self.__colors_model['severe wasting'], width=bar_width, + label='severe wasting (model)') + ax.bar(r1, plotting_model['moderate wasting'], bottom=plotting_model['severe wasting'], + color=self.__colors_model['moderate wasting'], width=bar_width, + label='moderate wasting (model)') + + # Plot the second set of bars (calibration data) + ax.bar(r2, plotting_calib['severe wasting'], + color=self.__colors_data['severe wasting'], width=bar_width, + label='severe wasting (data)') + ax.bar(r2, plotting_calib['moderate wasting'], bottom=plotting_calib['severe wasting'], + color=self.__colors_data['moderate wasting'], width=bar_width, + label='moderate wasting (data)') + + ax.set_xlabel('age group') + ax.set_ylabel('proportion') + ax.set_title( + r"Wasting prevalence in children 0-59 months per each age group $\bf{at}$ $\bf{initiation}$ (2010)", + fontsize=title_fontsize-1) + ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) + ax.set_xticklabels(order_x_axis) + ax.set_ylim([0, 0.16]) + ax.legend(fontsize=legend_fontsize) + + # Adjust the layout to make space for the footnote + plt.subplots_adjust(top=0.15) # Adjust the top margin + # Add footnote + fig.figure.text(0.43, 0.95, + "proportion = number of wasted children in the age group " + "/ total number of children in the age group", + ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) + plt.tight_layout() + fig_output_name = ('wasting_initial_prevalence_per_each_age_group__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) + # plt.show() + def plot_wasting_prevalence_by_age_group(self): """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of children wasted in a particular age-group divided by the total number of children per that age-group""" @@ -465,11 +554,12 @@ def create_plotting_data(df, df_name): ax.set_xlabel('age group') ax.set_ylabel('proportion') - ax.set_title(f"Wasting prevalence in children 0-59 months per each age group in {year_calib}") + ax.set_title(f"Wasting prevalence in children 0-59 months per each age group in {year_calib}", + fontsize=title_fontsize-1) ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) ax.set_xticklabels(order_x_axis) - ax.set_ylim([0, 0.168]) - ax.legend() + ax.set_ylim([0, 0.16]) + ax.legend(fontsize=legend_fontsize) # Adjust the layout to make space for the footnote plt.subplots_adjust(top=0.15) # Adjust the bottom margin @@ -484,90 +574,6 @@ def create_plotting_data(df, df_name): self.save_fig__store_pdf_file(fig, fig_output_name) # plt.show() - def plot_wasting_initial_prevalence_by_age_group(self): - """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of - children wasted in a particular age-group divided by the total number of children per that age-group""" - - # Initial prevalence at the beginning of 2010 - model - w_prev_df = self.__w_logs_dict["wasting_init_prevalence_props"] - w_prev_df = w_prev_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) - w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) - w_prev_df = w_prev_df.drop(columns='date') - - # 2010 prevalence calibration data - data_2010 = { - 'wasted_calib': [7.0, 13.0, 12.7, 2.4, 2.7, 1.9, 0.0], - 'sev_wast_calib': [2.1, 7.1, 4.7, 0.9, 0.7, 0.6, 0.0] - } - data_2010['mod_wast_calib'] = \ - [(w - s)/100 for w, s in zip(data_2010['wasted_calib'], data_2010['sev_wast_calib'])] - data_2010['sev_wast_calib'] = \ - [s/100 for s in data_2010['sev_wast_calib']] - - # Prepare plotting data - plotting_model = {'severe wasting': {}, 'moderate wasting': {}} - for col in w_prev_df.columns: - prefix, age_group = col.split('__') - if prefix == 'sev': - plotting_model['severe wasting'][age_group] = w_prev_df[col].values[0] - elif prefix == 'mod': - plotting_model['moderate wasting'][age_group] = w_prev_df[col].values[0] - plotting_model = pd.DataFrame(plotting_model) - - plotting_calib = {'severe wasting': {}, 'moderate wasting': {}} - age_groups = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] - for i, age_group in enumerate(age_groups): - plotting_calib['severe wasting'][age_group] = data_2010['sev_wast_calib'][i] - plotting_calib['moderate wasting'][age_group] = data_2010['mod_wast_calib'][i] - plotting_calib = pd.DataFrame(plotting_calib) - - order_x_axis = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] - plotting_model = plotting_model.reindex(order_x_axis) - plotting_calib = plotting_calib.reindex(order_x_axis) - - # Plot wasting prevalence - fig, ax = plt.subplots(figsize=(10, 6)) - bar_width = 0.35 - # Set positions of bars on x-axis - r1 = range(len(plotting_model)) - r2 = [x + bar_width for x in r1] - - # Plot the first set of bars (model data) - ax.bar(r1, plotting_model['severe wasting'], - color=self.__colors_model['severe wasting'], width=bar_width, - label='severe wasting (model)') - ax.bar(r1, plotting_model['moderate wasting'], bottom=plotting_model['severe wasting'], - color=self.__colors_model['moderate wasting'], width=bar_width, - label='moderate wasting (model)') - - # Plot the second set of bars (calibration data) - ax.bar(r2, plotting_calib['severe wasting'], - color=self.__colors_data['severe wasting'], width=bar_width, - label='severe wasting (data)') - ax.bar(r2, plotting_calib['moderate wasting'], bottom=plotting_calib['severe wasting'], - color=self.__colors_data['moderate wasting'], width=bar_width, - label='moderate wasting (data)') - - ax.set_xlabel('age group') - ax.set_ylabel('proportion') - ax.set_title(r"Wasting prevalence in children 0-59 months per each age group $\bf{at}$ $\bf{initiation}$ (2010)") - ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) - ax.set_xticklabels(order_x_axis) - ax.set_ylim([0, 0.168]) - ax.legend() - - # Adjust the layout to make space for the footnote - plt.subplots_adjust(top=0.15) # Adjust the top margin - # Add footnote - fig.figure.text(0.43, 0.95, - "proportion = number of wasted children in the age group " - "/ total number of children in the age group", - ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) - plt.tight_layout() - fig_output_name = ('wasting_initial_prevalence_per_each_age_group__' + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name) - # plt.show() - def add_wasting_initial_prevalence_by_age_group(self): self.fig_files.append('wasting_initial_prevalence_per_each_age_group__' + self.datestamp + '.pdf') @@ -584,10 +590,10 @@ def plot_model_gbd_deaths(self): ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, yerr=[plotting.GBD_lower, plotting.GBD_upper], fmt='o', color='#000', label="GBD") - ax.set_title('Direct deaths due to severe acute malnutrition') + ax.set_title('Direct deaths due to severe acute malnutrition', fontsize=title_fontsize-1) ax.set_xlabel("time period") ax.set_ylabel("number of deaths") - ax.legend(loc=2) + ax.legend(loc='upper center', fontsize=legend_fontsize) fig.tight_layout() # Adjust the layout to make space for the footnote plt.subplots_adjust(bottom=0.15) # Adjust the bottom margin From d97dcddecb262851b9544fc0934dfd6330c1b79b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 25 Mar 2025 23:50:08 +0000 Subject: [PATCH 384/755] analysis_wast: plot init overall prev (only 2010), unite colors for initial wasting (in overall & by age group plots), update output name for plot of deaths --- .../wasting_analyses/analysis_wasting.py | 158 +++++++++++++----- 1 file changed, 114 insertions(+), 44 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index cd4039aff8..8ff3d5636d 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -294,28 +294,22 @@ def plot_wasting_length(self): self.save_fig__store_pdf_file(fig, fig_output_name) # plt.show(`) - def plot_wasting_prevalence_per_year(self): - """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of - children wasted divide by the total number of children less than 5 years""" + def plot_wasting_initial_overall_prevalence(self): + """ plot wasting prevalence of all age groups for the year 2010. Proportions are obtained by getting a total + number of children wasted (moderately and severely) divided by the total number of children less than 5 years""" - ## Prevalence at some years - data (2010 are the data used to draw initial prevalence) + ## Prevalence at 2010, ie data from the same source used to draw initial prevalence by age group w_prev_calib_data_years_only_df = pd.DataFrame({ - 'sev_wast_calib': [0.015, 0.011, 0.006, 0.007], - 'mod_wast_calib': [0.025, 0.027, 0.021, 0.019] - }, index=[2010, 2013, 2015, 2019]) - date_range = pd.Index(range(2010, 2031), name='date') + 'sev_wast_calib': [0.015], + 'mod_wast_calib': [0.025] + }, index=[2010]) + date_range = pd.Index([2010], name='date') w_prev_calib = pd.DataFrame(index=date_range) # filling missing values with 0 w_prev_calib_df = w_prev_calib.merge( w_prev_calib_data_years_only_df, left_index=True, right_index=True, how='left' ).fillna(0) - ## Prevalence at the end of years - model - w_prev_df = self.__w_logs_dict["wasting_prevalence_props"] - w_prev_df = w_prev_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']] - w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) - w_prev_df = w_prev_df.drop(columns='date') - ## Initial prevalence at the beginning of 2010 - model init_w_prev_2010_only_df = self.__w_logs_dict["wasting_init_prevalence_props"] init_w_prev_2010_only_df = init_w_prev_2010_only_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']].rename( @@ -331,50 +325,43 @@ def plot_wasting_prevalence_per_year(self): ).fillna(0) w_prev_calib_and_init_df = pd.merge(init_w_prev_df, w_prev_calib_df, on='date') - w_prev_plot_df = pd.merge(w_prev_df, w_prev_calib_and_init_df, on='date') columns_to_plot = [ ['total_init_sev_under5_prop', 'total_init_mod_under5_prop'], - ['total_sev_under5_prop', 'total_mod_under5_prop'], ['sev_wast_calib', 'mod_wast_calib'], - ] + ] colors_to_plot = { - 'total_sev_under5_prop': self.__colors_model['severe wasting'], - 'total_mod_under5_prop': self.__colors_model['moderate wasting'], + 'total_init_sev_under5_prop': self.__colors_init_data['severe wasting'], + 'total_init_mod_under5_prop': self.__colors_init_data['moderate wasting'], 'sev_wast_calib': self.__colors_data['severe wasting'], 'mod_wast_calib': self.__colors_data['moderate wasting'], - 'total_init_sev_under5_prop': self.__colors_init_data['severe wasting'], - 'total_init_mod_under5_prop': self.__colors_init_data['moderate wasting'] - } labels_to_plot = { - 'total_sev_under5_prop': 'severe wasting (model)', - 'total_mod_under5_prop': 'moderate wasting (model)', + 'total_init_sev_under5_prop': 'severe wasting (initial)', + 'total_init_mod_under5_prop': 'moderate wasting (initial)', 'sev_wast_calib': 'severe wasting (data)', 'mod_wast_calib': 'moderate wasting (data)', - 'total_init_sev_under5_prop': 'severe wasting (initial)', - 'total_init_mod_under5_prop': 'moderate wasting (initial)' } fig, ax = plt.subplots() bar_spots = len(columns_to_plot) - bar_width = 0.8 / bar_spots - pos = np.arange(len(w_prev_plot_df)) + bar_width = 0.3 / bar_spots + pos = np.arange(len(w_prev_calib_and_init_df)) dodge_offsets = np.linspace(-bar_spots * bar_width / 2, bar_spots * bar_width / 2, bar_spots, endpoint=False) for columns, offset in zip(columns_to_plot, dodge_offsets): bottom = 0 for col in ([columns] if isinstance(columns, str) else columns): - ax.bar(pos + offset, w_prev_plot_df[col], bottom=bottom, width=bar_width, align='edge', + ax.bar(pos + offset, w_prev_calib_and_init_df[col], bottom=bottom, width=bar_width, align='edge', label=labels_to_plot[col], color=colors_to_plot[col]) - bottom += w_prev_plot_df[col] + bottom += w_prev_calib_and_init_df[col] ax.set_xticks(pos) - ax.set_xticklabels(w_prev_plot_df.index, rotation=90) - ax.set_title("Wasting prevalence in children 0-59 months per year", fontsize=title_fontsize-6) + ax.set_xticklabels(w_prev_calib_and_init_df.index, rotation=90) + ax.set_title(r"Overall wasting prevalence $\bf{at}$ $\bf{initiation}$ (2010)", fontsize=title_fontsize-1) ax.set_ylabel('proportion of wasted children in the year') ax.set_xlabel('year') ax.set_ylim([0, 0.131]) - ax.legend(fontsize=legend_fontsize-4) + ax.legend(fontsize=legend_fontsize) plt.tight_layout() - fig_output_name = ('wasting_prevalence_per_year__' + self.datestamp) + fig_output_name = ('wasting_initial_overall_prevalence__' + self.datestamp) self.save_fig__store_pdf_file(fig, fig_output_name) # plt.show() @@ -428,11 +415,11 @@ def plot_wasting_initial_prevalence_by_age_group(self): # Plot the first set of bars (model data) ax.bar(r1, plotting_model['severe wasting'], - color=self.__colors_model['severe wasting'], width=bar_width, - label='severe wasting (model)') + color=self.__colors_init_data['severe wasting'], width=bar_width, + label='severe wasting (initial)') ax.bar(r1, plotting_model['moderate wasting'], bottom=plotting_model['severe wasting'], - color=self.__colors_model['moderate wasting'], width=bar_width, - label='moderate wasting (model)') + color=self.__colors_init_data['moderate wasting'], width=bar_width, + label='moderate wasting (initial)') # Plot the second set of bars (calibration data) ax.bar(r2, plotting_calib['severe wasting'], @@ -464,6 +451,90 @@ def plot_wasting_initial_prevalence_by_age_group(self): self.save_fig__store_pdf_file(fig, fig_output_name) # plt.show() + def plot_wasting_prevalence_per_year(self): + """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of + children wasted divide by the total number of children less than 5 years""" + + ## Prevalence at some years - data (2010 are the data used to draw initial prevalence) + w_prev_calib_data_years_only_df = pd.DataFrame({ + 'sev_wast_calib': [0.015, 0.011, 0.006, 0.007], + 'mod_wast_calib': [0.025, 0.027, 0.021, 0.019] + }, index=[2010, 2013, 2015, 2019]) + date_range = pd.Index(range(2010, 2031), name='date') + w_prev_calib = pd.DataFrame(index=date_range) + # filling missing values with 0 + w_prev_calib_df = w_prev_calib.merge( + w_prev_calib_data_years_only_df, left_index=True, right_index=True, how='left' + ).fillna(0) + + ## Prevalence at the end of years - model + w_prev_df = self.__w_logs_dict["wasting_prevalence_props"] + w_prev_df = w_prev_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']] + w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) + w_prev_df = w_prev_df.drop(columns='date') + + ## Initial prevalence at the beginning of 2010 - model + init_w_prev_2010_only_df = self.__w_logs_dict["wasting_init_prevalence_props"] + init_w_prev_2010_only_df = init_w_prev_2010_only_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']].rename( + columns={'total_sev_under5_prop': 'total_init_sev_under5_prop', 'total_mod_under5_prop': 'total_init_mod_under5_prop'} + ) + init_w_prev_2010_only_df = init_w_prev_2010_only_df.set_index(init_w_prev_2010_only_df.date.dt.year) + init_w_prev_2010_only_df = init_w_prev_2010_only_df.drop(columns='date') + init_w_prev_2010_only_df = init_w_prev_2010_only_df.loc[[2010]] + init_w_prev_df = pd.DataFrame(index=date_range) + # filling missing values with 0 + init_w_prev_df = init_w_prev_df.merge( + init_w_prev_2010_only_df, left_index=True, right_index=True, how='left' + ).fillna(0) + + w_prev_calib_and_init_df = pd.merge(init_w_prev_df, w_prev_calib_df, on='date') + w_prev_plot_df = pd.merge(w_prev_df, w_prev_calib_and_init_df, on='date') + columns_to_plot = [ + ['total_init_sev_under5_prop', 'total_init_mod_under5_prop'], + ['total_sev_under5_prop', 'total_mod_under5_prop'], + ['sev_wast_calib', 'mod_wast_calib'], + ] + colors_to_plot = { + 'total_sev_under5_prop': self.__colors_model['severe wasting'], + 'total_mod_under5_prop': self.__colors_model['moderate wasting'], + 'sev_wast_calib': self.__colors_data['severe wasting'], + 'mod_wast_calib': self.__colors_data['moderate wasting'], + 'total_init_sev_under5_prop': self.__colors_init_data['severe wasting'], + 'total_init_mod_under5_prop': self.__colors_init_data['moderate wasting'] + + } + labels_to_plot = { + 'total_sev_under5_prop': 'severe wasting (model)', + 'total_mod_under5_prop': 'moderate wasting (model)', + 'sev_wast_calib': 'severe wasting (data)', + 'mod_wast_calib': 'moderate wasting (data)', + 'total_init_sev_under5_prop': 'severe wasting (initial)', + 'total_init_mod_under5_prop': 'moderate wasting (initial)' + } + + fig, ax = plt.subplots() + bar_spots = len(columns_to_plot) + bar_width = 0.8 / bar_spots + pos = np.arange(len(w_prev_plot_df)) + dodge_offsets = np.linspace(-bar_spots * bar_width / 2, bar_spots * bar_width / 2, bar_spots, endpoint=False) + for columns, offset in zip(columns_to_plot, dodge_offsets): + bottom = 0 + for col in ([columns] if isinstance(columns, str) else columns): + ax.bar(pos + offset, w_prev_plot_df[col], bottom=bottom, width=bar_width, align='edge', + label=labels_to_plot[col], color=colors_to_plot[col]) + bottom += w_prev_plot_df[col] + ax.set_xticks(pos) + ax.set_xticklabels(w_prev_plot_df.index, rotation=90) + ax.set_title("Wasting prevalence in children 0-59 months per year", fontsize=title_fontsize-6) + ax.set_ylabel('proportion of wasted children in the year') + ax.set_xlabel('year') + ax.set_ylim([0, 0.131]) + ax.legend(fontsize=legend_fontsize-4) + plt.tight_layout() + fig_output_name = ('wasting_prevalence_per_year__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) + # plt.show() + def plot_wasting_prevalence_by_age_group(self): """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of children wasted in a particular age-group divided by the total number of children per that age-group""" @@ -601,7 +672,7 @@ def plot_model_gbd_deaths(self): fig.figure.text(0.5, 0.02, "Model output against Global Burden of Diseases (GBD) study data", ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) - fig_output_name = ('modal_gbd_deaths_by_gender__' + self.datestamp) + fig_output_name = ('model_gbd_deaths__' + self.datestamp) self.save_fig__store_pdf_file(fig, fig_output_name) # plt.show() @@ -667,13 +738,12 @@ def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): # plot wasting length # wasting_analyses.plot_wasting_length() - # plot wasting prevalence - wasting_analyses.plot_wasting_prevalence_per_year() - - # plot wasting initial prevalence by age group + # plot initial wasting prevalence + wasting_analyses.plot_wasting_initial_overall_prevalence() wasting_analyses.plot_wasting_initial_prevalence_by_age_group() - # plot wasting prevalence by age group + # plot prevalence through simulation + wasting_analyses.plot_wasting_prevalence_per_year() wasting_analyses.plot_wasting_prevalence_by_age_group() # plot wasting deaths by gender as compared to GBD deaths From 90d7b84985eb7a374fdb3bbdf499aa5f288775a5 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 26 Mar 2025 00:07:06 +0000 Subject: [PATCH 385/755] analysis_wast: deaths are not plotted by gender anymore --- src/scripts/wasting_analyses/analysis_wasting.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 8ff3d5636d..c17701ee4c 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -62,10 +62,6 @@ def __init__(self, sim_results_folder_path_str, in_datestamp, in_draw_nmb, in_ru # '2010-01-01', 'scaling_factor' # ] - # gender description - self.__gender_desc = {'M': 'Males', - 'F': 'Females'} - # wasting types description self.__wasting_types_desc = {'WHZ<-3': 'severe wasting', '-3<=WHZ<-2': 'moderate wasting', @@ -746,7 +742,7 @@ def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): wasting_analyses.plot_wasting_prevalence_per_year() wasting_analyses.plot_wasting_prevalence_by_age_group() - # plot wasting deaths by gender as compared to GBD deaths + # plot wasting deaths as compared to GBD deaths wasting_analyses.plot_model_gbd_deaths() # save all figures in one pdf From bf2b894ba31273548eb9d7b834aab5c4ce7e0cba Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 26 Mar 2025 01:06:41 +0000 Subject: [PATCH 386/755] wast: minor (comments) --- src/tlo/methods/wasting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 4dd6bf9230..fa3023009c 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -313,7 +313,7 @@ def initialise_population(self, population): # Assign wasting categories in children under 5 at initiation under5s = df.loc[df.is_alive & (df.age_exact_years < 5)] under5s_index = under5s.index - # apply prevalence of wasting and categorise into moderate (-3 <= WHZ < -2) or severe (WHZ < -3) wasting + # apply prevalence of wasting init_wasting_bool = self.wasting_models.init_wasting_prevalence_lm.predict( under5s, rng=self.rng, squeeze_single_row_output=False ) @@ -321,6 +321,7 @@ def initialise_population(self, population): wasted_index = wasted.index df.loc[wasted_index, 'un_last_wasting_date_of_onset'] = self.sim.date df.loc[wasted_index, 'un_ever_wasted'] = True + # categorise into moderate (-3 <= WHZ < -2) or severe (WHZ < -3) wasting init_sev_wasting_bool = self.wasting_models.init_severe_wasting_among_wasted_lm.predict( wasted, rng=self.rng, squeeze_single_row_output=False ) From 8feef23c5866fabf99174d50642cfbc19874e910 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 26 Mar 2025 02:53:39 +0000 Subject: [PATCH 387/755] scenario_wast_min_model: params draw updated; 4K, 216 draws --- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 9d6c0f8e65..f107b70d63 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -87,9 +87,9 @@ def draw_parameters(self, draw_number, rng): base_death_rate_untreated_sam__draws = [0.1, 0.05, 0.03, 0.01] mod_wast_incidence__coef = [1.0, 0.6, 0.2] base_overall_mod_wast_inc_rate = 0.019 - progression_to_sev_wast__coef = [0.25, 0.5, 1.0, 1.5, 2.0, 2.3] + progression_to_sev_wast__coef = [0.5, 0.75, 1.0, 1.5, 2.0, 2.3] progression_severe_wasting_monthly_props_by_agegp = [0.3082, 0.8614, 0.4229, 0.4337, 0.2508, 0.3321] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.3, 0.6, 0.9] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.1, 0.4, 0.7] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, From e7b9ac11f7eb6c410cb8908ee0ac0d40c360acfb Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 26 Mar 2025 02:56:37 +0000 Subject: [PATCH 388/755] wast: natural recovery/progression scheduled when recovered to MAM; prints only if person of interest born --- src/tlo/methods/wasting.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index fa3023009c..fb51213729 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -977,7 +977,8 @@ def apply(self, population): df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_clinical_acute_malnutrition == 'well') & (df.un_am_tx_start_date.isna()) & (df.un_am_recovery_date.isna() | (df.un_am_recovery_date < self.sim.date - pd.DateOffset(days=14)))] - if self.module.person_of_interest_id not in not_am_or_treated_or_recently_recovered.index: + if (self.module.person_of_interest_id in df.index and + self.module.person_of_interest_id not in not_am_or_treated_or_recently_recovered.index): print("person of interest cannot become wasted, because ") if not df.at[self.module.person_of_interest_id, 'is_alive']: print("is dead") @@ -994,7 +995,7 @@ def apply(self, population): else: print(f"{df.at[self.module.person_of_interest_id, 'un_am_recovery_date']=}") print("smt strange happening - do investigate!") - else: + elif self.module.person_of_interest_id in df.index: print("person of interest can become wasted") incidence_of_wasting_bool = \ @@ -1429,6 +1430,25 @@ def get_min_length(in_recov_how, in_person_id, in_whz): if do_prints: print(f"wast indicators updated to {df.at[person_id, 'un_WHZ_category']=}," f"{df.at[person_id, 'un_am_MUAC_category']=}, and no oedema => MAM") + + outcome_date = self.module.date_of_outcome_for_untreated_wasting(whz_category='-3<=WHZ<-2') + progression_severe_wasting_bool = self.module.wasting_models.severe_wasting_progression_lm.predict( + df.loc[[person_id]], rng=rng + ) + if progression_severe_wasting_bool: + self.sim.schedule_event( + event=Wasting_ProgressionToSevere_Event(module=self.module, person_id=person_id), date=outcome_date + ) + if do_prints: + print("the person will progress to severe wasting if not treated") + else: + # schedule full recovery after duration of moderate wasting + self.sim.schedule_event(event=Wasting_FullRecovery_Event(module=self.module, person_id=person_id), + date=outcome_date) + if do_prints: + print("the person will naturally fully recover if not treated") + + if do_prints: print("------------------------------------------------") From 5df1bf8515e0761311a84e96087663f41efdd69f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 27 Mar 2025 00:21:07 +0000 Subject: [PATCH 389/755] wast: pers. of interest = 31846; added par indicating whether pers. of interest was born or not yet, prints updated using this par, minor update of prints --- src/tlo/methods/wasting.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index fb51213729..4503a5aa7b 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -231,7 +231,8 @@ def __init__(self, name=None, resourcefilepath=None): _agrp: copy.deepcopy(blank_length_counter) for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} self.wasting_length_tracker = copy.deepcopy(self.wasting_length_tracker_blank) - self.person_of_interest_id = 5315 # debugging + self.person_of_interest_id = 31846 # debugging + self.person_of_interest_born_bool = False # define age groups self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} @@ -340,6 +341,7 @@ def initialise_population(self, population): print(f"\n{self.person_of_interest_id=}") print("###########") if self.person_of_interest_id in df.index: + self.person_of_interest_born_bool = True print(f"initial wasting: {df.loc[self.person_of_interest_id, 'un_WHZ_category']}") print(f"initial MUAC: {df.loc[self.person_of_interest_id, 'un_am_MUAC_category']}") print(f"initial oedema: {df.loc[self.person_of_interest_id, 'un_am_nutritional_oedema']}") @@ -395,6 +397,7 @@ def on_birth(self, mother_id, child_id): ) if child_id == self.person_of_interest_id: + self.person_of_interest_born_bool = True print(f"person_of_interest born {self.sim.date=}") print("-------") @@ -969,15 +972,15 @@ def apply(self, population): rng = self.module.rng # # # INCIDENCE OF MODERATE WASTING # # # # # # # # # # # # # # # # # # # # # - if self.module.person_of_interest_id in df.index: - print("\nINCIDENCE") + if self.module.person_of_interest_born_bool: + print("INCIDENCE") # Determine who will be onset with wasting among those who # currently do not have acute malnutrition, are not being treated, and did not recover in the last 14 days not_am_or_treated_or_recently_recovered =\ df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_clinical_acute_malnutrition == 'well') & (df.un_am_tx_start_date.isna()) & (df.un_am_recovery_date.isna() | (df.un_am_recovery_date < self.sim.date - pd.DateOffset(days=14)))] - if (self.module.person_of_interest_id in df.index and + if (self.module.person_of_interest_born_bool and self.module.person_of_interest_id not in not_am_or_treated_or_recently_recovered.index): print("person of interest cannot become wasted, because ") if not df.at[self.module.person_of_interest_id, 'is_alive']: @@ -995,7 +998,7 @@ def apply(self, population): else: print(f"{df.at[self.module.person_of_interest_id, 'un_am_recovery_date']=}") print("smt strange happening - do investigate!") - elif self.module.person_of_interest_id in df.index: + elif self.module.person_of_interest_born_bool: print("person of interest can become wasted") incidence_of_wasting_bool = \ @@ -1068,7 +1071,7 @@ def apply(self, population): print(f"scheduled recovery to MAM at {outcome_date=} as the person has SAM: " f"{df.at[person_id, 'un_clinical_acute_malnutrition']=}") - if do_prints: + if self.module.person_of_interest_born_bool: print("---------------------------------") @@ -1783,8 +1786,8 @@ def apply(self, person_id, squeeze_factor): data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") if do_prints: print("consumables not available, SFP tx not scheduled, should be picked up with next\n" - "growth monitoring if not naturally recovered in between or could be picked up\n" - "with non-emergency appt") + "growth monitoring or non-emergency appt if this is not follow-up tx,\n" + "or if not naturally recovered in between") if do_prints: print("-----------------------------------------------") From 309eec338528b015a85fc33854b2990a58a6132e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 27 Mar 2025 00:22:22 +0000 Subject: [PATCH 390/755] scenario_wast_min_model: 30K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index f107b70d63..0ff796fe0c 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=216, runs_per_draw=1, ) From a246bc2e759a968aca288dd0ba801d766944e629 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 27 Mar 2025 11:26:25 +0000 Subject: [PATCH 391/755] wast: when recovered to MAM with no wasting,then only full recovery no progression in future if untreated --- src/tlo/methods/wasting.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 4503a5aa7b..7eebe567ca 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1438,16 +1438,13 @@ def get_min_length(in_recov_how, in_person_id, in_whz): progression_severe_wasting_bool = self.module.wasting_models.severe_wasting_progression_lm.predict( df.loc[[person_id]], rng=rng ) - if progression_severe_wasting_bool: - self.sim.schedule_event( - event=Wasting_ProgressionToSevere_Event(module=self.module, person_id=person_id), date=outcome_date - ) + + if df.at[person_id, 'un_WHZ_category'] == '-3<=WHZ<-2' and progression_severe_wasting_bool: + self.sim.schedule_event(Wasting_ProgressionToSevere_Event(self.module, person_id), outcome_date) if do_prints: print("the person will progress to severe wasting if not treated") else: - # schedule full recovery after duration of moderate wasting - self.sim.schedule_event(event=Wasting_FullRecovery_Event(module=self.module, person_id=person_id), - date=outcome_date) + self.sim.schedule_event(Wasting_FullRecovery_Event(self.module, person_id), outcome_date) if do_prints: print("the person will naturally fully recover if not treated") From 8586bc8e79876ca8b5436bc486623e0051599f10 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 28 Mar 2025 17:21:45 +0000 Subject: [PATCH 392/755] scenario_wast_min_model: pars set to failed draws (to be rerun with more memory and time requested) --- .../scenarios/scenario_wasting_minimal_model.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 0ff796fe0c..9c047bbee0 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -43,7 +43,7 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=30_000, - number_of_draws=216, + number_of_draws=5, runs_per_draw=1, ) @@ -91,12 +91,15 @@ def draw_parameters(self, draw_number, rng): progression_severe_wasting_monthly_props_by_agegp = [0.3082, 0.8614, 0.4229, 0.4337, 0.2508, 0.3321] prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.1, 0.4, 0.7] - pars_combinations = list(itertools.product( - base_death_rate_untreated_sam__draws, - mod_wast_incidence__coef, - progression_to_sev_wast__coef, - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam - )) + # pars_combinations = list(itertools.product( + # base_death_rate_untreated_sam__draws, + # mod_wast_incidence__coef, + # progression_to_sev_wast__coef, + # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam + # )) + # draws [14, 52, 129, 197, 203] + pars_combinations =[(0.1, 1.0, 2.0, 0.7), (0.1, 0.2, 2.3, 0.4), (0.03, 0.6, 0.75, 0.1), (0.01, 0.6, 2.3, 0.7), + (0.01, 0.2, 0.75, 0.7)] return { 'Wasting': { 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], From 23fdb4f218b77c98909eb70ab661d56fc15e6038 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 28 Mar 2025 17:22:50 +0000 Subject: [PATCH 393/755] Revert "wast: when recovered to MAM with no wasting,then only full recovery no progression in future if untreated" This reverts commit a246bc2e759a968aca288dd0ba801d766944e629. --- src/tlo/methods/wasting.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 7eebe567ca..4503a5aa7b 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1438,13 +1438,16 @@ def get_min_length(in_recov_how, in_person_id, in_whz): progression_severe_wasting_bool = self.module.wasting_models.severe_wasting_progression_lm.predict( df.loc[[person_id]], rng=rng ) - - if df.at[person_id, 'un_WHZ_category'] == '-3<=WHZ<-2' and progression_severe_wasting_bool: - self.sim.schedule_event(Wasting_ProgressionToSevere_Event(self.module, person_id), outcome_date) + if progression_severe_wasting_bool: + self.sim.schedule_event( + event=Wasting_ProgressionToSevere_Event(module=self.module, person_id=person_id), date=outcome_date + ) if do_prints: print("the person will progress to severe wasting if not treated") else: - self.sim.schedule_event(Wasting_FullRecovery_Event(self.module, person_id), outcome_date) + # schedule full recovery after duration of moderate wasting + self.sim.schedule_event(event=Wasting_FullRecovery_Event(module=self.module, person_id=person_id), + date=outcome_date) if do_prints: print("the person will naturally fully recover if not treated") From e09ef3e03abef3b63211bb616a0bad37a1ed46b5 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 27 Mar 2025 11:26:25 +0000 Subject: [PATCH 394/755] wast: when recovered to MAM with no wasting,then only full recovery no progression in future if untreated --- src/tlo/methods/wasting.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 4503a5aa7b..7eebe567ca 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1438,16 +1438,13 @@ def get_min_length(in_recov_how, in_person_id, in_whz): progression_severe_wasting_bool = self.module.wasting_models.severe_wasting_progression_lm.predict( df.loc[[person_id]], rng=rng ) - if progression_severe_wasting_bool: - self.sim.schedule_event( - event=Wasting_ProgressionToSevere_Event(module=self.module, person_id=person_id), date=outcome_date - ) + + if df.at[person_id, 'un_WHZ_category'] == '-3<=WHZ<-2' and progression_severe_wasting_bool: + self.sim.schedule_event(Wasting_ProgressionToSevere_Event(self.module, person_id), outcome_date) if do_prints: print("the person will progress to severe wasting if not treated") else: - # schedule full recovery after duration of moderate wasting - self.sim.schedule_event(event=Wasting_FullRecovery_Event(module=self.module, person_id=person_id), - date=outcome_date) + self.sim.schedule_event(Wasting_FullRecovery_Event(self.module, person_id), outcome_date) if do_prints: print("the person will naturally fully recover if not treated") From e3b58ee17297c79111691bf6737fc6e47890bcb0 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 29 Mar 2025 23:18:24 +0000 Subject: [PATCH 395/755] scenario_wast_min_model: draws with pars close parametrised model, 30K pop, 192 draws --- .../scenario_wasting_minimal_model.py | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 9c047bbee0..c77a3bd0e2 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -43,7 +43,7 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=30_000, - number_of_draws=5, + number_of_draws=192, runs_per_draw=1, ) @@ -84,22 +84,20 @@ def modules(self): # return {} def draw_parameters(self, draw_number, rng): - base_death_rate_untreated_sam__draws = [0.1, 0.05, 0.03, 0.01] - mod_wast_incidence__coef = [1.0, 0.6, 0.2] + base_death_rate_untreated_sam__draws = [0.030, 0.023, 0.017, 0.010] + mod_wast_incidence__coef = [0.7, 0.6, 0.5, 0.4] base_overall_mod_wast_inc_rate = 0.019 - progression_to_sev_wast__coef = [0.5, 0.75, 1.0, 1.5, 2.0, 2.3] + progression_to_sev_wast__coef = [1.0, 1.25, 1.5] progression_severe_wasting_monthly_props_by_agegp = [0.3082, 0.8614, 0.4229, 0.4337, 0.2508, 0.3321] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.1, 0.4, 0.7] - - # pars_combinations = list(itertools.product( - # base_death_rate_untreated_sam__draws, - # mod_wast_incidence__coef, - # progression_to_sev_wast__coef, - # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam - # )) - # draws [14, 52, 129, 197, 203] - pars_combinations =[(0.1, 1.0, 2.0, 0.7), (0.1, 0.2, 2.3, 0.4), (0.03, 0.6, 0.75, 0.1), (0.01, 0.6, 2.3, 0.7), - (0.01, 0.2, 0.75, 0.7)] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.1, 0.17, 0.23, 0.3] + + pars_combinations = list(itertools.product( + base_death_rate_untreated_sam__draws, + mod_wast_incidence__coef, + progression_to_sev_wast__coef, + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam + )) + return { 'Wasting': { 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], From cc1c97e23d8bd978159536fcaa173caaa5607e05 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 31 Mar 2025 13:39:06 +0100 Subject: [PATCH 396/755] analysis_wast: CIs for prevalence by age group by model --- .../wasting_analyses/analysis_wasting.py | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index c17701ee4c..b359e2d76a 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -13,6 +13,7 @@ import pandas as pd from matplotlib import pyplot as plt from PyPDF2 import PdfReader, PdfWriter +from scipy import stats from tlo.analysis.utils import compare_number_of_deaths, get_scenario_outputs, parse_log_file @@ -579,16 +580,16 @@ def plot_wasting_prevalence_by_age_group(self): order_x_axis = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] def create_plotting_data(df, df_name): - plotting = {'severe wasting': {}, 'moderate wasting': {}} + plotting = {'severe wasting': {}, 'moderate wasting': {}, 'any wasting': {}} for col in df.columns: prefix, age_group = col.split('__') if prefix == 'sev': plotting['severe wasting'][age_group] = df[col].values[0] elif prefix == 'mod': plotting['moderate wasting'][age_group] = df[col].values[0] + plotting['any wasting'][age_group] = df[col].values[0] + df[f'sev__{age_group}'].values[0] plotting_df = pd.DataFrame(plotting) - assert set(plotting_df.index) == set( - order_x_axis), f"age groups in {w_prev_calib_data_year_df} are not in line with the order_x_axis." + assert set(plotting_df.index) == set(order_x_axis), f"age groups in {df_name} are not in line with the order_x_axis." plotting_df = plotting_df.reindex(order_x_axis) return plotting_df @@ -596,6 +597,28 @@ def create_plotting_data(df, df_name): plotting_model = create_plotting_data(w_prev_model_year_df, 'w_prev_model_year_df') plotting_calib = create_plotting_data(w_prev_calib_data_year_df, 'w_prev_calib_data_year_df') + # Calculate 95% confidence intervals for model outcomes + pop_sizes_df = self.__w_logs_dict['pop sizes'] + pop_sizes_df = pop_sizes_df.set_index(pop_sizes_df.date.dt.year) + pop_sizes_df = pop_sizes_df.drop(columns='date') + pd.set_option('display.max_columns', None) + model_sample_sizes = pop_sizes_df.loc[year_calib, :].filter(like='total__').rename( + lambda x: x.replace('total__', ''), axis=0 + ).reindex(order_x_axis) + print(f"{model_sample_sizes=}") + + confidence_level = 0.95 + z_score = stats.norm.ppf(1 - (1 - confidence_level) / 2) + + margin_of_error_any_wast = [] + for p, n in zip(plotting_model['any wasting'].reindex(order_x_axis), model_sample_sizes): + margin_of_error_any_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) + + margin_of_error_sev_wast = [] + for p, n in zip(plotting_model['severe wasting'].reindex(order_x_axis), model_sample_sizes): + margin_of_error_sev_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) + + # ##### # Plot wasting prevalence fig, ax = plt.subplots(figsize=(10, 6)) bar_width = 0.35 @@ -611,6 +634,15 @@ def create_plotting_data(df, df_name): color=self.__colors_model['moderate wasting'], width=bar_width, label='moderate wasting (model)') + # Add the confidence intervals + for i, age_group in enumerate(order_x_axis[0:len(order_x_axis)-1]): + ax.errorbar(r1[i], plotting_model['any wasting'][age_group], + yerr=[margin_of_error_any_wast[i]], + capsize=5, fmt='none', color='black') + ax.errorbar(r1[i], plotting_model['severe wasting'][age_group], + yerr=[margin_of_error_sev_wast[i]], + capsize=5, fmt='none', color='black') + # Plot the second set of bars (calibration data) ax.bar(r2, plotting_calib['severe wasting'], color=self.__colors_data['severe wasting'], width=bar_width, From 58052ca0569c753a211f429d919b9033713cfc93 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 31 Mar 2025 13:40:29 +0100 Subject: [PATCH 397/755] analysis_wast: renaming --- src/scripts/wasting_analyses/analysis_wasting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index b359e2d76a..997f356986 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -66,7 +66,7 @@ def __init__(self, sim_results_folder_path_str, in_datestamp, in_draw_nmb, in_ru # wasting types description self.__wasting_types_desc = {'WHZ<-3': 'severe wasting', '-3<=WHZ<-2': 'moderate wasting', - 'WHZ>=-2': 'not undernourished'} + 'WHZ>=-2': 'no wasting'} self.fig_files = [] @@ -689,7 +689,7 @@ def plot_model_gbd_deaths(self): ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, yerr=[plotting.GBD_lower, plotting.GBD_upper], fmt='o', color='#000', label="GBD") - ax.set_title('Direct deaths due to severe acute malnutrition', fontsize=title_fontsize-1) + ax.set_title('Direct average deaths per year due to severe acute malnutrition', fontsize=title_fontsize-1) ax.set_xlabel("time period") ax.set_ylabel("number of deaths") ax.legend(loc='upper center', fontsize=legend_fontsize) From 76487c93a591635e672d5e04cbc2f92b9f7cffe3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 31 Mar 2025 18:07:47 +0100 Subject: [PATCH 398/755] wast: RF_Wast updated into a folder, parameters saved in the folder as parameters.csv --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 7eebe567ca..8bc18b42f6 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -248,7 +248,7 @@ def read_parameters(self, data_folder): """ # Read parameters from the resource file self.load_parameters_from_dataframe( - pd.read_csv(Path(self.resourcefilepath) / 'ResourceFile_Wasting.csv') + pd.read_csv(Path(self.resourcefilepath) / 'ResourceFile_Wasting/parameters.csv') ) # Register wasting symptom (weight loss) in Symptoms Manager with high odds of seeking care From 6926cd4a6c3d13726a79016b79964844a8a1dbff Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 31 Mar 2025 18:42:57 +0100 Subject: [PATCH 399/755] analysis_wast: age_groups defined only once; pop_sizes_model loaded once --- .../wasting_analyses/analysis_wasting.py | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 997f356986..fe7821c00d 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -399,9 +399,8 @@ def plot_wasting_initial_prevalence_by_age_group(self): plotting_calib['moderate wasting'][age_group] = data_2010['mod_wast_calib'][i] plotting_calib = pd.DataFrame(plotting_calib) - order_x_axis = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] - plotting_model = plotting_model.reindex(order_x_axis) - plotting_calib = plotting_calib.reindex(order_x_axis) + plotting_model = plotting_model.reindex(age_groups) + plotting_calib = plotting_calib.reindex(age_groups) # Plot wasting prevalence fig, ax = plt.subplots(figsize=(10, 6)) @@ -432,7 +431,7 @@ def plot_wasting_initial_prevalence_by_age_group(self): r"Wasting prevalence in children 0-59 months per each age group $\bf{at}$ $\bf{initiation}$ (2010)", fontsize=title_fontsize-1) ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) - ax.set_xticklabels(order_x_axis) + ax.set_xticklabels(age_groups) ax.set_ylim([0, 0.16]) ax.legend(fontsize=legend_fontsize) @@ -574,23 +573,29 @@ def plot_wasting_prevalence_by_age_group(self): w_prev_model_df = w_prev_model_df.set_index(w_prev_model_df.date.dt.year) w_prev_model_df = w_prev_model_df.drop(columns='date') + pop_sizes_model_df = self.__w_logs_dict['pop sizes'] + pop_sizes_model_df = pop_sizes_model_df.set_index(pop_sizes_model_df.date.dt.year) + pop_sizes_model_df = pop_sizes_model_df.drop(columns='date') + pop_sizes_model_df = pop_sizes_model_df.filter(like='total__').rename( + lambda x: x.replace('total__', ''), axis=1 + )[age_groups] + for year_calib in w_prev_calib_data_df.index: w_prev_calib_data_year_df = w_prev_calib_data_df.loc[w_prev_calib_data_df.index == year_calib] w_prev_model_year_df = w_prev_model_df.loc[w_prev_model_df.index == year_calib] - order_x_axis = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] def create_plotting_data(df, df_name): plotting = {'severe wasting': {}, 'moderate wasting': {}, 'any wasting': {}} for col in df.columns: - prefix, age_group = col.split('__') + prefix, agegp = col.split('__') if prefix == 'sev': - plotting['severe wasting'][age_group] = df[col].values[0] + plotting['severe wasting'][agegp] = df[col].values[0] elif prefix == 'mod': - plotting['moderate wasting'][age_group] = df[col].values[0] - plotting['any wasting'][age_group] = df[col].values[0] + df[f'sev__{age_group}'].values[0] + plotting['moderate wasting'][agegp] = df[col].values[0] + plotting['any wasting'][agegp] = df[col].values[0] + df[f'sev__{agegp}'].values[0] plotting_df = pd.DataFrame(plotting) - assert set(plotting_df.index) == set(order_x_axis), f"age groups in {df_name} are not in line with the order_x_axis." - plotting_df = plotting_df.reindex(order_x_axis) + assert set(plotting_df.index) == set(age_groups), f"age groups in {df_name} are not in line with the age_groups." + plotting_df = plotting_df.reindex(age_groups) return plotting_df # Create plotting data for both dataframes @@ -598,24 +603,17 @@ def create_plotting_data(df, df_name): plotting_calib = create_plotting_data(w_prev_calib_data_year_df, 'w_prev_calib_data_year_df') # Calculate 95% confidence intervals for model outcomes - pop_sizes_df = self.__w_logs_dict['pop sizes'] - pop_sizes_df = pop_sizes_df.set_index(pop_sizes_df.date.dt.year) - pop_sizes_df = pop_sizes_df.drop(columns='date') - pd.set_option('display.max_columns', None) - model_sample_sizes = pop_sizes_df.loc[year_calib, :].filter(like='total__').rename( - lambda x: x.replace('total__', ''), axis=0 - ).reindex(order_x_axis) - print(f"{model_sample_sizes=}") + sample_sizes_model_year = pop_sizes_model_df.loc[year_calib, :] confidence_level = 0.95 z_score = stats.norm.ppf(1 - (1 - confidence_level) / 2) margin_of_error_any_wast = [] - for p, n in zip(plotting_model['any wasting'].reindex(order_x_axis), model_sample_sizes): + for p, n in zip(plotting_model['any wasting'].reindex(age_groups), sample_sizes_model_year): margin_of_error_any_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) margin_of_error_sev_wast = [] - for p, n in zip(plotting_model['severe wasting'].reindex(order_x_axis), model_sample_sizes): + for p, n in zip(plotting_model['severe wasting'].reindex(age_groups), sample_sizes_model_year): margin_of_error_sev_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) # ##### @@ -635,7 +633,7 @@ def create_plotting_data(df, df_name): label='moderate wasting (model)') # Add the confidence intervals - for i, age_group in enumerate(order_x_axis[0:len(order_x_axis)-1]): + for i, age_group in enumerate(age_groups[0:len(age_groups)-1]): ax.errorbar(r1[i], plotting_model['any wasting'][age_group], yerr=[margin_of_error_any_wast[i]], capsize=5, fmt='none', color='black') @@ -656,7 +654,7 @@ def create_plotting_data(df, df_name): ax.set_title(f"Wasting prevalence in children 0-59 months per each age group in {year_calib}", fontsize=title_fontsize-1) ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) - ax.set_xticklabels(order_x_axis) + ax.set_xticklabels(age_groups) ax.set_ylim([0, 0.16]) ax.legend(fontsize=legend_fontsize) From 46639243059693911f8a60dc7aac08bf16be7811 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 31 Mar 2025 21:49:33 +0100 Subject: [PATCH 400/755] analysis_wast: load calibration data by age group from CSV resource file; TODOs (overall prev into RF and load each used calib prev from there) --- .../wasting_prevalence_and_sample_size.csv | 3 ++ .../wasting_analyses/analysis_wasting.py | 52 ++++++++----------- 2 files changed, 24 insertions(+), 31 deletions(-) create mode 100644 resources/ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv diff --git a/resources/ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv b/resources/ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv new file mode 100644 index 0000000000..c25fb45f27 --- /dev/null +++ b/resources/ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:68dffd9c88a2fd31b0d0cf0f7f319a933072093d884353a95c78089ed6df8840 +size 1286 diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index fe7821c00d..46c258638f 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -373,6 +373,8 @@ def plot_wasting_initial_prevalence_by_age_group(self): w_prev_df = w_prev_df.drop(columns='date') # 2010 prevalence calibration data + # TODO: load data_2010 from the resource file: + # resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' data_2010 = { 'wasted_calib': [7.0, 13.0, 12.7, 2.4, 2.7, 1.9, 0.0], 'sev_wast_calib': [2.1, 7.1, 4.7, 0.9, 0.7, 0.6, 0.0] @@ -452,6 +454,9 @@ def plot_wasting_prevalence_per_year(self): children wasted divide by the total number of children less than 5 years""" ## Prevalence at some years - data (2010 are the data used to draw initial prevalence) + # TODO: add calibration data into the resource file: + # resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' + # and load here and for initial overall prev from the RF w_prev_calib_data_years_only_df = pd.DataFrame({ 'sev_wast_calib': [0.015, 0.011, 0.006, 0.007], 'mod_wast_calib': [0.025, 0.027, 0.021, 0.019] @@ -536,37 +541,22 @@ def plot_wasting_prevalence_by_age_group(self): children wasted in a particular age-group divided by the total number of children per that age-group""" age_groups = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] - columns = [f'mod__{age}' for age in age_groups] + [f'sev__{age}' for age in age_groups] - # data in percent (0% to 100%) - data = { - 2010: { - 'wasted_calib': [7.0, 13.0, 12.7, 2.4, 2.7, 1.9, 0.0], - 'sev_wast_calib': [2.1, 7.1, 4.7, 0.9, 0.7, 0.6, 0.0] - }, - 2013: { - 'wasted_calib': [5.8, 5.8, 5.4, 3.9, 2.2, 2.0, 0.0], - 'sev_wast_calib': [2.6, 2.5, 1.1, 0.8, 0.7, 0.3, 0.0] - }, - 2015: { - 'wasted_calib': [3.7, 7.7, 6.5, 2.2, 1.9, 2.6, 0.0], - 'sev_wast_calib': [1.1, 1.0, 0.7, 1.0, 0.1, 0.5, 0.0] - }, - 2019: { - 'wasted_calib': [2.5, 2.6, 9.1, 2.0, 1.8, 1.8, 0.0], - 'sev_wast_calib': [1.0, 1.0, 2.7, 0.8, 0.2, 0.3, 0.0] - } - } - # recalculate data to proportions (0 to 1) and separate mod wast as (wasted - sev wast) - for year in data: - data[year]['mod_wast_calib'] = \ - [(w - s)/100 for w, s in zip(data[year]['wasted_calib'], data[year]['sev_wast_calib'])] - data[year]['sev_wast_calib'] = \ - [s/100 for s in data[year]['sev_wast_calib']] - data_list = [] - for year in data: - values = data[year]['mod_wast_calib'] + data[year]['sev_wast_calib'] - data_list.append(values) - w_prev_calib_data_df = pd.DataFrame(data_list, columns=columns, index=data.keys()) + + # Load calibration data from CSV file + wasting_data_path = resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' + wasting_data_df = pd.read_csv(wasting_data_path) + + # Recalculate data to proportions (0 to 1) and separate mod wast as (wasted - sev wast) + wasting_data_df['mod_wast_calib'] = \ + (wasting_data_df['prev any wast (%)'] - wasting_data_df['prev severe wast (%)']) / 100 + wasting_data_df['sev_wast_calib'] = wasting_data_df['prev severe wast (%)'] / 100 + + # Pivot the data to get the required format + w_prev_calib_data_df = wasting_data_df.pivot(index='year', columns='age_group (months)', + values=['mod_wast_calib', 'sev_wast_calib']) + w_prev_calib_data_df.columns = [f'{col[0][:3]}__{col[1]}' for col in w_prev_calib_data_df.columns] + + # pop_sizes_calib_data_df = w_prev_model_df = self.__w_logs_dict["wasting_prevalence_props"] w_prev_model_df = w_prev_model_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) From bc06d6444683badeee9cb3723593e30866d65a79 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 31 Mar 2025 22:04:28 +0100 Subject: [PATCH 401/755] wast: ResourceFile_Wasting.csv mv-ed to ResourceFile_Wasting/parameters.csv --- .../parameters.csv} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename resources/{ResourceFile_Wasting.csv => ResourceFile_Wasting/parameters.csv} (100%) diff --git a/resources/ResourceFile_Wasting.csv b/resources/ResourceFile_Wasting/parameters.csv similarity index 100% rename from resources/ResourceFile_Wasting.csv rename to resources/ResourceFile_Wasting/parameters.csv From 90c2565d54e7343ace3b05e270d91fe2302808cd Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 31 Mar 2025 22:06:42 +0100 Subject: [PATCH 402/755] analysis_wast: outdated code rm-ed --- src/scripts/wasting_analyses/analysis_wasting.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 46c258638f..8f28b0e5e7 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -661,9 +661,6 @@ def create_plotting_data(df, df_name): self.save_fig__store_pdf_file(fig, fig_output_name) # plt.show() - def add_wasting_initial_prevalence_by_age_group(self): - self.fig_files.append('wasting_initial_prevalence_per_each_age_group__' + self.datestamp + '.pdf') - def plot_model_gbd_deaths(self): """ compare model and GBD deaths 2010-2014 & 2015-2019 """ death_compare = \ From fb832b949922695542d49e4559dc1476282be443 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 31 Mar 2025 22:55:14 +0100 Subject: [PATCH 403/755] analysis_wast: added CIs for prev by age group for calibration data --- .../wasting_analyses/analysis_wasting.py | 59 +++++++++++++------ 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 8f28b0e5e7..c4d3780078 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -542,29 +542,35 @@ def plot_wasting_prevalence_by_age_group(self): age_groups = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] + # ### Calibration Data # Load calibration data from CSV file - wasting_data_path = resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' - wasting_data_df = pd.read_csv(wasting_data_path) + wasting_calib_data_path = resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' + wasting_calib_data_df = pd.read_csv(wasting_calib_data_path, index_col='year') # Recalculate data to proportions (0 to 1) and separate mod wast as (wasted - sev wast) - wasting_data_df['mod_wast_calib'] = \ - (wasting_data_df['prev any wast (%)'] - wasting_data_df['prev severe wast (%)']) / 100 - wasting_data_df['sev_wast_calib'] = wasting_data_df['prev severe wast (%)'] / 100 + wasting_calib_data_df['mod_wast_calib'] = \ + (wasting_calib_data_df['prev any wast (%)'] - wasting_calib_data_df['prev severe wast (%)']) / 100 + wasting_calib_data_df['sev_wast_calib'] = wasting_calib_data_df['prev severe wast (%)'] / 100 # Pivot the data to get the required format - w_prev_calib_data_df = wasting_data_df.pivot(index='year', columns='age_group (months)', + w_prev_calib_data_df = wasting_calib_data_df.pivot(columns='age_group (months)', values=['mod_wast_calib', 'sev_wast_calib']) w_prev_calib_data_df.columns = [f'{col[0][:3]}__{col[1]}' for col in w_prev_calib_data_df.columns] - # pop_sizes_calib_data_df = + # Load calibration sample sizes from CSV file + sample_sizes_calib_data_df = wasting_calib_data_df.pivot(columns='age_group (months)', values='sample_size') + sample_sizes_calib_data_df = sample_sizes_calib_data_df.reindex(columns=age_groups) + # ### Model Outcomes + # Load modelled prevalence proportions w_prev_model_df = self.__w_logs_dict["wasting_prevalence_props"] w_prev_model_df = w_prev_model_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) w_prev_model_df = w_prev_model_df.set_index(w_prev_model_df.date.dt.year) w_prev_model_df = w_prev_model_df.drop(columns='date') + # Load modelled population sizes pop_sizes_model_df = self.__w_logs_dict['pop sizes'] - pop_sizes_model_df = pop_sizes_model_df.set_index(pop_sizes_model_df.date.dt.year) + pop_sizes_model_df = pop_sizes_model_df.set_index(pop_sizes_model_df.date.dt.year).rename_axis('year') pop_sizes_model_df = pop_sizes_model_df.drop(columns='date') pop_sizes_model_df = pop_sizes_model_df.filter(like='total__').rename( lambda x: x.replace('total__', ''), axis=1 @@ -592,19 +598,27 @@ def create_plotting_data(df, df_name): plotting_model = create_plotting_data(w_prev_model_year_df, 'w_prev_model_year_df') plotting_calib = create_plotting_data(w_prev_calib_data_year_df, 'w_prev_calib_data_year_df') - # Calculate 95% confidence intervals for model outcomes + # Calculate 95% confidence intervals for both + sample_sizes_calib_data_year = sample_sizes_calib_data_df.loc[year_calib, :] sample_sizes_model_year = pop_sizes_model_df.loc[year_calib, :] confidence_level = 0.95 z_score = stats.norm.ppf(1 - (1 - confidence_level) / 2) - margin_of_error_any_wast = [] - for p, n in zip(plotting_model['any wasting'].reindex(age_groups), sample_sizes_model_year): - margin_of_error_any_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) - - margin_of_error_sev_wast = [] - for p, n in zip(plotting_model['severe wasting'].reindex(age_groups), sample_sizes_model_year): - margin_of_error_sev_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) + calib_data_margin_of_error_any_wast = [] + calib_data_margin_of_error_sev_wast = [] + print(f"sample_sizes_calib_data_year:\n{sample_sizes_calib_data_year}") + for p, n in zip(plotting_calib['any wasting'].reindex(age_groups[:-1]), sample_sizes_calib_data_year[:-1]): + calib_data_margin_of_error_any_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) + for p, n in \ + zip(plotting_calib['severe wasting'].reindex(age_groups[:-1]),sample_sizes_calib_data_year[:-1]): + calib_data_margin_of_error_sev_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) + model_margin_of_error_any_wast = [] + model_margin_of_error_sev_wast = [] + for p, n in zip(plotting_model['any wasting'].reindex(age_groups[:-1]), sample_sizes_model_year[:-1]): + model_margin_of_error_any_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) + for p, n in zip(plotting_model['severe wasting'].reindex(age_groups[:-1]), sample_sizes_model_year[:-1]): + model_margin_of_error_sev_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) # ##### # Plot wasting prevalence @@ -625,10 +639,10 @@ def create_plotting_data(df, df_name): # Add the confidence intervals for i, age_group in enumerate(age_groups[0:len(age_groups)-1]): ax.errorbar(r1[i], plotting_model['any wasting'][age_group], - yerr=[margin_of_error_any_wast[i]], + yerr=[model_margin_of_error_any_wast[i]], capsize=5, fmt='none', color='black') ax.errorbar(r1[i], plotting_model['severe wasting'][age_group], - yerr=[margin_of_error_sev_wast[i]], + yerr=[model_margin_of_error_sev_wast[i]], capsize=5, fmt='none', color='black') # Plot the second set of bars (calibration data) @@ -639,6 +653,15 @@ def create_plotting_data(df, df_name): color=self.__colors_data['moderate wasting'], width=bar_width, label='moderate wasting (data)') + # Add the confidence intervals + for i, age_group in enumerate(age_groups[0:len(age_groups)-1]): + ax.errorbar(r2[i], plotting_calib['any wasting'][age_group], + yerr=[calib_data_margin_of_error_any_wast[i]], + capsize=5, fmt='none', color='black') + ax.errorbar(r2[i], plotting_calib['severe wasting'][age_group], + yerr=[calib_data_margin_of_error_sev_wast[i]], + capsize=5, fmt='none', color='black') + ax.set_xlabel('age group') ax.set_ylabel('proportion') ax.set_title(f"Wasting prevalence in children 0-59 months per each age group in {year_calib}", From 039d81cb77d6247f17ed08c75abf2cffc64a146d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 1 Apr 2025 01:01:36 +0100 Subject: [PATCH 404/755] analysis_wast: limit the deaths to calibrate to under 5 years old; unintended print rm-ed --- src/scripts/wasting_analyses/analysis_wasting.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index c4d3780078..a530e77c47 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -607,7 +607,6 @@ def create_plotting_data(df, df_name): calib_data_margin_of_error_any_wast = [] calib_data_margin_of_error_sev_wast = [] - print(f"sample_sizes_calib_data_year:\n{sample_sizes_calib_data_year}") for p, n in zip(plotting_calib['any wasting'].reindex(age_groups[:-1]), sample_sizes_calib_data_year[:-1]): calib_data_margin_of_error_any_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) for p, n in \ @@ -689,15 +688,18 @@ def plot_model_gbd_deaths(self): death_compare = \ compare_number_of_deaths(self.__log_file_path, resources_path) fig, ax = plt.subplots(figsize=(10, 6)) + # cause of death as of GBD 2019 'Protein-energy malnutrition' was labeled as 'Childhood Undernutrition' in + # wasting module plot_df = death_compare.loc[(['2010-2014', '2015-2019'], - slice(None), slice(None), 'Childhood Undernutrition' + slice(None), ['0-4'], 'Childhood Undernutrition' )].groupby('period').sum() plotting = plot_df.loc[['2010-2014', '2015-2019']] ax = plotting['model'].plot.bar(label='Model', ax=ax, rot=0) ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, yerr=[plotting.GBD_lower, plotting.GBD_upper], fmt='o', color='#000', label="GBD") - ax.set_title('Direct average deaths per year due to severe acute malnutrition', fontsize=title_fontsize-1) + + ax.set_title('Average direct deaths per year due to severe acute malnutrition in children under 5', fontsize=title_fontsize-1) ax.set_xlabel("time period") ax.set_ylabel("number of deaths") ax.legend(loc='upper center', fontsize=legend_fontsize) From 3f44e157ad08417bd9fcf1d2a447a86225f392a4 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 1 Apr 2025 22:46:37 +0100 Subject: [PATCH 405/755] analysis_wast: white error bars for severe wasting, black for any wasting --- src/scripts/wasting_analyses/analysis_wasting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index a530e77c47..2eb91de700 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -642,7 +642,7 @@ def create_plotting_data(df, df_name): capsize=5, fmt='none', color='black') ax.errorbar(r1[i], plotting_model['severe wasting'][age_group], yerr=[model_margin_of_error_sev_wast[i]], - capsize=5, fmt='none', color='black') + capsize=5, fmt='none', color='white') # Plot the second set of bars (calibration data) ax.bar(r2, plotting_calib['severe wasting'], @@ -659,7 +659,7 @@ def create_plotting_data(df, df_name): capsize=5, fmt='none', color='black') ax.errorbar(r2[i], plotting_calib['severe wasting'][age_group], yerr=[calib_data_margin_of_error_sev_wast[i]], - capsize=5, fmt='none', color='black') + capsize=5, fmt='none', color='white') ax.set_xlabel('age group') ax.set_ylabel('proportion') From 3ccc9a2eb54b9fa37baff5b9e0d3d9429e9edb41 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 1 Apr 2025 22:47:40 +0100 Subject: [PATCH 406/755] analysis_wast: create csv for calibration outcomes --- .../wasting_analyses/analysis_wasting.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 2eb91de700..3484753751 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -27,6 +27,28 @@ title_fontsize = 16 ######################################################################################################################## +def create_calib_outcome_csv(sim_results_folder_path_str): + """ + Creates a new empty csv file with the header if it doesn't exist yet. + :return: + """ + csv_file_name = str(sim_results_folder_path_str).replace(str(outputs_path), '').lstrip('/') + \ + "_model_calib-data_intersect_bool" + csv_file_path = sim_results_folder_path_str / f"{csv_file_name}.csv" + + if not csv_file_path.exists(): + age_groups = [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)] + calib_ys = [2015, 2019] + wast_type_agegp = [f'{wast_type}_wast__{low_bound}_{high_bound}mo' for wast_type in ['any', 'sev'] for + low_bound, high_bound in age_groups] + year_wast_age_grps = [f'{year}__{wast_age_grp}' for year in calib_ys for wast_age_grp in wast_type_agegp] + sum_year_prev_calib_points = [f'{year}__sum_prev_calib_points' for year in calib_ys] + + with open(csv_file_path, 'w') as csv_file: + csv_file.write( + 'draw,run,' + ','.join(year_wast_age_grps) + ',deaths_2010_2014,deaths_2015_2019,' + + ','.join(sum_year_prev_calib_points) + ',sum_prev_calib_points,sum_all_calib_points\n' + ) class WastingAnalyses: """ @@ -757,6 +779,10 @@ def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): folders = [name for name in os.listdir(sim_results_folder_path) if \ os.path.isdir(os.path.join(sim_results_folder_path, name))] + # Create a csv to write down calibration outputs + # as bool values indicating whether model outcomes and calibration data intersect + create_calib_outcome_csv(sim_results_folder_path) + # Analyse each draw # for now, we always have just one run, run 0 run_nmb = 0 From 0d8aa8800b7e38178de4dc19f8c8e01747c1653e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 4 Apr 2025 13:10:46 +0100 Subject: [PATCH 407/755] analysis_wast: minor (assert print, comment) --- src/scripts/wasting_analyses/analysis_wasting.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 3484753751..8afaedd069 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -612,7 +612,8 @@ def create_plotting_data(df, df_name): plotting['moderate wasting'][agegp] = df[col].values[0] plotting['any wasting'][agegp] = df[col].values[0] + df[f'sev__{agegp}'].values[0] plotting_df = pd.DataFrame(plotting) - assert set(plotting_df.index) == set(age_groups), f"age groups in {df_name} are not in line with the age_groups." + assert set(plotting_df.index) == set(age_groups),\ + f"age groups in {df_name} are not in line with the age_groups." plotting_df = plotting_df.reindex(age_groups) return plotting_df @@ -813,7 +814,7 @@ def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): # plot wasting deaths as compared to GBD deaths wasting_analyses.plot_model_gbd_deaths() - # save all figures in one pdf + # ### Save all figures in one pdf outcome_figs_folder = sim_results_folder_path / '_outcome_figures' outcome_figs_folder.mkdir(parents=True, exist_ok=True) wasting_analyses.plot_all_figs_in_one_pdf(outcome_figs_folder) From 39183f0019e165278f189bfb2c31426402989f2b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 7 Apr 2025 23:12:12 +0100 Subject: [PATCH 408/755] test_wast: test_basic_run-- test MUAC < 115mm causes SAM --- tests/test_wasting.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index e5a55fd1cf..b9020bef8a 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -75,7 +75,7 @@ def get_sim(tmpdir): @pytest.mark.slow def test_basic_run(tmpdir): - """Run the simulation and do some daily checks on dtypes and properties integrity """ + """ Run the simulation and do some daily checks on dtypes and properties integrity. """ class DummyModule(Module): """ A Dummy module that ensure wasting properties are as expected on a daily basis """ METADATA = {Metadata.DISEASE_MODULE} @@ -154,13 +154,13 @@ def check_configuration_of_properties(self, population): assert set() == set_of_person_id_in_current_episode_before_recovery.intersection( set_of_person_id_in_current_episode_before_death) - # WHZ standard deviation of -3, oedema, and MUAC <115mm should cause severe acute malnutrition + # WHZ standard deviation of -3, MUAC <115mm, and oedema should cause severe acute malnutrition whz_index = df.index[df['un_WHZ_category'] == 'WHZ<-3'] - oedema_index = df.index[df['un_am_nutritional_oedema']] muac_index = df.index[df['un_am_MUAC_category'] == '<115mm'] + oedema_index = df.index[df['un_am_nutritional_oedema']] assert (df.loc[whz_index, 'un_clinical_acute_malnutrition'] == "SAM").all() - assert (df.loc[oedema_index, 'un_clinical_acute_malnutrition'] == "SAM").all() assert (df.loc[muac_index, 'un_clinical_acute_malnutrition'] == "SAM").all() + assert (df.loc[oedema_index, 'un_clinical_acute_malnutrition'] == "SAM").all() # all SAM individuals should have symptoms of wasting assert set(under5_sam).issubset(has_symptoms) From c855daaba6d16ae08a7b55fdaa81adbe7d32c66c Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 7 Apr 2025 23:17:25 +0100 Subject: [PATCH 409/755] test_wast: test_basic_run-- resolve warnings --- tests/test_wasting.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index b9020bef8a..d1a947e3b0 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -116,7 +116,7 @@ def check_dtypes(self, population): # Check types of columns df = population.props orig = population.new_row - assert (df.dtypes == orig.dtypes).all() + assert df.dtypes.eq(orig.dtypes).all() def check_configuration_of_properties(self, population): """ check wasting properties on a daily basis to ensure integrity """ @@ -125,12 +125,12 @@ def check_configuration_of_properties(self, population): (df.un_clinical_acute_malnutrition == 'SAM')] # Those that were never wasted, should have normal WHZ score: - assert (df.loc[~df.un_ever_wasted & ~df.date_of_birth.isna(), 'un_WHZ_category'] == 'WHZ>=-2').all() + assert (df.loc[~df.un_ever_wasted & ~df.date_of_birth.isna(), 'un_WHZ_category'].eq('WHZ>=-2')).all() # Those for whom the death date has past should be dead assert not df.loc[(df['un_sam_death_date'] < self.sim.date), 'is_alive'].any() # Those who died due to SAM should have SAM - assert (df.loc[(df['un_sam_death_date']) < self.sim.date, 'un_clinical_acute_malnutrition'] == 'SAM').all() + assert df.loc[(df['un_sam_death_date']) < self.sim.date, 'un_clinical_acute_malnutrition'].eq('SAM').all() # Check that those in a current episode have symptoms of wasting # [caused by the wasting module] but not others (among those alive) @@ -158,9 +158,9 @@ def check_configuration_of_properties(self, population): whz_index = df.index[df['un_WHZ_category'] == 'WHZ<-3'] muac_index = df.index[df['un_am_MUAC_category'] == '<115mm'] oedema_index = df.index[df['un_am_nutritional_oedema']] - assert (df.loc[whz_index, 'un_clinical_acute_malnutrition'] == "SAM").all() - assert (df.loc[muac_index, 'un_clinical_acute_malnutrition'] == "SAM").all() - assert (df.loc[oedema_index, 'un_clinical_acute_malnutrition'] == "SAM").all() + assert df.loc[whz_index, 'un_clinical_acute_malnutrition'].eq("SAM").all() + assert df.loc[muac_index, 'un_clinical_acute_malnutrition'].eq("SAM").all() + assert df.loc[oedema_index, 'un_clinical_acute_malnutrition'].eq("SAM").all() # all SAM individuals should have symptoms of wasting assert set(under5_sam).issubset(has_symptoms) From f0eeb7b3d44a0895adaca83c1b193254f50fd767 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 7 Apr 2025 23:29:37 +0100 Subject: [PATCH 410/755] test_wast: test_wast_incidence-- only well-nourished children can become wasted --- tests/test_wasting.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index d1a947e3b0..be110b634f 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -177,33 +177,38 @@ def check_configuration_of_properties(self, population): def test_wasting_incidence(tmpdir): - """Check Incidence of wasting is happening as expected """ + """ Check incidence of wasting is happening as expected. """ # get simulation object: dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) + # get wasting module + wmodule = sim.modules['Wasting'] sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) - # reset properties of all individuals so that they are not wasted + # Reset properties of all individuals so that they are well-nourished df = sim.population.props - df.loc[df.is_alive, 'un_WHZ_category'] = 'WHZ>=-2' # not undernourished + df.loc[df.is_alive, 'un_WHZ_category'] = 'WHZ>=-2' # not wasted + df.loc[df.is_alive, 'un_am_MUAC_category'] = '>=125mm' + df.loc[df.is_alive, 'un_am_nutritional_oedema'] = False + df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' df.loc[df.is_alive, 'un_ever_wasted'] = False df.loc[df.is_alive, 'un_last_wasting_date_of_onset'] = pd.NaT # Set incidence of wasting at 100% - sim.modules['Wasting'].wasting_models.wasting_incidence_lm = LinearModel.multiplicative() + wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() - # Run polling event: check that all children should now have moderate wasting: - polling = Wasting_IncidencePoll(sim.modules['Wasting']) + # Run polling event: check that all children should now have moderate wasting + polling = Wasting_IncidencePoll(wmodule) polling.apply(sim.population) # Check properties of individuals: should now be moderately wasted under5s = df.loc[df.is_alive & (df['age_years'] < 5)] assert all(under5s['un_ever_wasted']) - assert all(under5s['un_WHZ_category'] == '-3<=WHZ<-2') - assert all(under5s['un_last_wasting_date_of_onset'] == sim.date) + assert (under5s['un_WHZ_category'].eq('-3<=WHZ<-2')).all() + assert (under5s['un_last_wasting_date_of_onset'].eq(sim.date)).all() def test_report_daly_weights(tmpdir): From edc51c2750e7de57e7c482f574e486877ab88590 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 7 Apr 2025 23:43:28 +0100 Subject: [PATCH 411/755] test_wast: test_report_daly_weights-- use the wmodule alias, comments updated --- tests/test_wasting.py | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index be110b634f..49ea3be4c8 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -212,16 +212,19 @@ def test_wasting_incidence(tmpdir): def test_report_daly_weights(tmpdir): - """Check if daly weights reporting is done as expected. Four checks are made: + """ Check if daly weights reporting is done as expected. Four checks are made: 1. For an individual who is well (No weight is expected/must be 0.0) 2. For an individual with moderate wasting and oedema (expected daly weight is 0.051) 3. For an individual with severe wasting and oedema (expected daly weight is 0.172) - 4. For an individual with severe wasting without oedema (expected daly weight is 0.128)""" + 4. For an individual with severe wasting without oedema (expected daly weight is 0.128) """ dur = pd.DateOffset(days=0) popsize = 1 sim = get_sim(tmpdir) sim.modules['Demography'].parameters['max_age_initial'] = 4.9 + # get wasting module + wmodule = sim.modules['Wasting'] + sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) @@ -233,35 +236,35 @@ def test_report_daly_weights(tmpdir): person_id = df.index[0] df.at[person_id, 'is_alive'] = True - # Check daly weight for not undernourished person (weight is 0.0) + # 1. Check daly weight for well-nourished person (weight is 0.0) # Reset diagnostic properties df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' df.loc[person_id, 'un_am_nutritional_oedema'] = False df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' # Verify diagnosis - an individual should be well - sim.modules["Wasting"].clinical_acute_malnutrition_state(person_id, df) + wmodule.clinical_acute_malnutrition_state(person_id, df) assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'well' # Report daly weight for this individual - daly_weights_reported = sim.modules["Wasting"].report_daly_values() + daly_weights_reported = wmodule.report_daly_values() # Verify that individual has no daly weight assert daly_weights_reported.loc[person_id] == 0.0 get_daly_weights = sim.modules['HealthBurden'].get_daly_weight - # Check daly weight for person with moderate wasting and oedema (weight is 0.051) + # 2. Check daly weight for person with moderate wasting and oedema (weight is 0.051) # Reset diagnostic properties df.loc[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' df.loc[person_id, 'un_am_nutritional_oedema'] = True - # Verify diagnosis - an individual should be SAM - sim.modules["Wasting"].clinical_acute_malnutrition_state(person_id, df) + # Verify diagnosis - an individual should have SAM + wmodule.clinical_acute_malnutrition_state(person_id, df) assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' # Report daly weight for this individual - daly_weights_reported = sim.modules["Wasting"].report_daly_values() + daly_weights_reported = wmodule.report_daly_values() # Get daly weight of moderate wasting with oedema daly_wts['mod_wasting_with_oedema'] = get_daly_weights(sequlae_code=461) @@ -269,17 +272,17 @@ def test_report_daly_weights(tmpdir): # Compare the daly weight of this individual with the daly weight obtained from HealthBurden module assert daly_wts['mod_wasting_with_oedema'] == daly_weights_reported.loc[person_id] - # Check daly weight for person with severe wasting and oedema (weight is 0.172) + # 3. Check daly weight for person with severe wasting and oedema (weight is 0.172) # Reset diagnostic properties df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' df.loc[person_id, 'un_am_nutritional_oedema'] = True - # Verify diagnosis - an individual should be SAM - sim.modules["Wasting"].clinical_acute_malnutrition_state(person_id, df) + # Verify diagnosis - an individual should have SAM + wmodule.clinical_acute_malnutrition_state(person_id, df) assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' # Report daly weight for this individual - daly_weights_reported = sim.modules["Wasting"].report_daly_values() + daly_weights_reported = wmodule.report_daly_values() # Get daly weight of severe wasting with oedema daly_wts['sev_wasting_with_oedema'] = get_daly_weights(sequlae_code=463) @@ -287,17 +290,17 @@ def test_report_daly_weights(tmpdir): # Compare the daly weight of this individual with the daly weight obtained from HealthBurden module assert daly_wts['sev_wasting_with_oedema'] == daly_weights_reported.loc[person_id] - # Check daly weight for person with severe wasting without oedema (weight is 0.128) + # 4. Check daly weight for person with severe wasting without oedema (weight is 0.128) # Reset diagnosis df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' df.loc[person_id, 'un_am_nutritional_oedema'] = False - # Verify diagnosis - an individual should be SAM - sim.modules["Wasting"].clinical_acute_malnutrition_state(person_id, df) + # Verify diagnosis - an individual should have SAM + wmodule.clinical_acute_malnutrition_state(person_id, df) assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' # Report daly weight for this individual - daly_weights_reported = sim.modules["Wasting"].report_daly_values() + daly_weights_reported = wmodule.report_daly_values() # Get day weight of severe wasting without oedema daly_wts['sev_wasting_w/o_oedema'] = get_daly_weights(sequlae_code=462) From 4c5731ca5ee86aa6e1038dab41b3708891b7f558 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 8 Apr 2025 14:11:09 +0100 Subject: [PATCH 412/755] test_wast: test_nat_recovery_moderate_wasting-- test both nat. recovery from MAM to well, and SAM to MAM --- tests/test_wasting.py | 141 ++++++++++++++++++++++++++---------------- 1 file changed, 86 insertions(+), 55 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 49ea3be4c8..3dfedd3073 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -309,61 +309,92 @@ def test_report_daly_weights(tmpdir): assert daly_wts['sev_wasting_w/o_oedema'] == daly_weights_reported.loc[person_id] -def test_recovery_moderate_wasting(tmpdir): - """Check natural recovery of moderate wasting """ - dur = pd.DateOffset(days=0) - popsize = 1000 - sim = get_sim(tmpdir) - - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue - - # Get person to use: - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - # make this individual have no wasting - df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' - # confirm wasting property is reset. This individual should have no wasting - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' - - # Set incidence of wasting at 100% - sim.modules['Wasting'].wasting_models.wasting_incidence_lm = LinearModel.multiplicative() - - # Run Wasting Polling event: This event should cause all young children to be moderate wasting - polling = Wasting_IncidencePoll(module=sim.modules['Wasting']) - polling.apply(sim.population) - - # Check properties of this individual: should now be moderately wasted - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_am_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Check that there is a Wasting_NaturalRecovery_Event scheduled - # for this person - recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], Wasting_NaturalRecovery_Event)][0] - date_of_scheduled_recov = recov_event_tuple[0] - recov_event = recov_event_tuple[1] - assert date_of_scheduled_recov > sim.date - - # Run the recovery event: - sim.date = date_of_scheduled_recov - recov_event.apply(person_id=person_id) - - # Check properties of this individual - person = df.loc[person_id] - assert person['un_WHZ_category'] == 'WHZ>=-2' - if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well': - assert person['un_am_recovery_date'] == sim.date - else: - assert pd.isnull(df.at[person_id, 'un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) +def test_nat_recovery_moderate_wasting(tmpdir): + """ Check natural recovery after onset of moderate wasting with MAM diagnosis. """ + for am_state_expected in ['MAM', 'SAM']: + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + # get wasting module + wmodule = sim.modules['Wasting'] + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue + + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + # Reset properties of this individual to be well-nourished + df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not wasted + df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' + df.loc[person_id, 'un_am_nutritional_oedema'] = False + df.loc[person_id, 'un_clinical_acute_malnutrition'] = 'well' # well-nourished + df.loc[person_id, 'un_ever_wasted'] = False + df.loc[person_id, 'un_last_wasting_date_of_onset'] = pd.NaT + + # Set incidence of moderate wasting at 100% + wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() + # Set progression rate to severe wasting at 0% (hence, natural recovery always scheduled) + wmodule.wasting_models.severe_wasting_progression_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) + if am_state_expected == 'MAM': + # Set probability of MUAC < 115mm with moderate wasting, and probability of oedema with moderate wasting + # at 0% in order to have MAM with onset of wasting + wmodule.parameters['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = 0.0 + wmodule.parameters['proportion_WHZ<-2_with_oedema'] = 0.0 + else: # am_state_expected == 'SAM' + # Set probability of oedema with moderate wasting at 100% in order to have SAM with onset of wasting + wmodule.parameters['proportion_WHZ<-2_with_oedema'] = 1.0 + + # Run Wasting Polling event: This event should cause all young children to be moderately wasted + polling = Wasting_IncidencePoll(module=wmodule) + polling.apply(sim.population) + + # Check properties of this individual: should now be moderately wasted with MAM or SAM respectively + person = df.loc[person_id] + assert person['un_ever_wasted'] + assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_last_wasting_date_of_onset'] == sim.date + assert pd.isnull(person['un_am_tx_start_date']) + assert pd.isnull(person['un_am_recovery_date']) + if am_state_expected == 'MAM': + assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM' + else: + assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' + + # Check that there is a natural recovery event scheduled: + # Wasting_FullRecovery_Event if this person has MAM, Wasting_RecoveryToMAM_Event if this person has SAM + if am_state_expected == 'MAM': + recov_event_type = Wasting_FullRecovery_Event + else: # am_state_expected == 'SAM' + recov_event_type = Wasting_RecoveryToMAM_Event + recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], recov_event_type)][0] + date_of_scheduled_recov = recov_event_tuple[0] + recov_event = recov_event_tuple[1] + assert date_of_scheduled_recov > sim.date + + # Run the natural recovery event: + sim.date = date_of_scheduled_recov + recov_event.apply(person_id) + + # Check properties of this individual, if recovered from MAM should be well, if recovered from SAM should be MAM + person = df.loc[person_id] + if am_state_expected == 'MAM': # with moderate wasting + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert person['un_am_MUAC_category'] == '>=125mm' + assert not person['un_am_nutritional_oedema'] + assert person['un_clinical_acute_malnutrition'] == 'well' + assert not person['un_sam_with_complications'] + assert person['un_am_recovery_date'] == sim.date + assert pd.isnull(person['un_sam_death_date']) + else: # am_state_expected == 'SAM' with moderate wasting + assert not person['un_am_nutritional_oedema'] + assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM' + assert not person['un_sam_with_complications'] + assert pd.isnull(person['un_am_recovery_date']) + assert pd.isnull(person['un_sam_death_date']) def test_recovery_severe_acute_malnutrition_without_complications(tmpdir): From 41e9823944ae1620f5b249e2e4b6b2ed23dbecba Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 8 Apr 2025 14:29:44 +0100 Subject: [PATCH 413/755] test_wast: imported event names updated --- tests/test_wasting.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 3dfedd3073..34715c6928 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -27,12 +27,11 @@ from tlo.methods.wasting import ( HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM, HSI_Wasting_OutpatientTherapeuticProgramme_SAM, - Wasting_ClinicalAcuteMalnutritionRecovery_Event, + Wasting_FullRecovery_Event, Wasting_IncidencePoll, - Wasting_NaturalRecovery_Event, Wasting_ProgressionToSevere_Event, + Wasting_RecoveryToMAM_Event, Wasting_SevereAcuteMalnutritionDeath_Event, - Wasting_UpdateToMAM_Event, ) # Path to the resource files used by the disease and intervention methods From 19bb7dd792573d0b198ef29def9116f3029ed091 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 8 Apr 2025 14:31:26 +0100 Subject: [PATCH 414/755] test_wast: ; test_tx_recovery_severe_acute_malnutrition_without_complications-- event name updated, minor(description, comments, wmodule alias) --- tests/test_wasting.py | 41 +++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 24 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 34715c6928..8ce1192291 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -396,19 +396,18 @@ def test_nat_recovery_moderate_wasting(tmpdir): assert pd.isnull(person['un_sam_death_date']) -def test_recovery_severe_acute_malnutrition_without_complications(tmpdir): +def test_tx_recovery_severe_acute_malnutrition_without_complications(tmpdir): """ Check the onset of symptoms with SAM, check recovery to MAM with tx when the progression to severe wasting is certain, hence no natural recovery from moderate wasting, the natural death due to SAM is certain, hence no natural recovery from severe wasting, - and check death canceled and symptoms resolved when recovered to MAM with tx. """ + and check natural death canceled w\ tx and symptoms resolved when recovered to MAM with tx. """ dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) - # get wasting module wmodule = sim.modules['Wasting'] - # set death due to untreated SAM at 100% for all, hence no natural recovery from severe wasting + # Set death due to untreated SAM at 100% for all, hence no natural recovery from severe wasting wmodule.parameters['base_death_rate_untreated_SAM'] = 1.0 wmodule.parameters['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] @@ -428,23 +427,19 @@ def test_recovery_severe_acute_malnutrition_without_complications(tmpdir): df.at[person_id, 'un_sam_with_complications'] = False df.at[person_id, 'un_sam_death_date'] = pd.NaT - # ensure the individual has no complications when SAM occurs + # Ensure the individual has no complications when SAM occurs wmodule.parameters['prob_complications_in_SAM'] = 0.0 - - # set incidence of wasting at 100% + # Set incidence of wasting at 100% wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() - - # set progress to severe wasting at 100% as well, hence no natural recovery from moderate wasting + # Set progress to severe wasting at 100% as well, hence no natural recovery from moderate wasting wmodule.wasting_models.severe_wasting_progression_lm = LinearModel.multiplicative() - - # set complete recovery from SAM to zero. We want those with SAM to recover to MAM with tx + # Set complete recovery from SAM to zero. We want those with SAM to recover to MAM with tx wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) - - # set prob of death after tx at 0% (hence recovery to MAM at 100%) + # Set prob of death after tx at 0% (hence recovery to MAM w\ tx at 100%) wmodule.parameters['prob_death_after_SAMcare'] = 0.0 # Run Wasting Polling event to get new incident cases: - polling = Wasting_IncidencePoll(module=sim.modules['Wasting']) + polling = Wasting_IncidencePoll(module=wmodule) polling.apply(sim.population) # Check properties of this individual: should now be moderately wasted @@ -464,7 +459,7 @@ def test_recovery_severe_acute_malnutrition_without_complications(tmpdir): # Check this individual has symptom (weight loss) caused by Wasting (SAM only) assert 'weight_loss' in sim.modules['SymptomManager'].has_what( - person_id=person_id, disease_module=sim.modules['Wasting'] + person_id=person_id, disease_module=wmodule ) # Check properties of this individual @@ -486,24 +481,22 @@ def test_recovery_severe_acute_malnutrition_without_complications(tmpdir): hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) hsp.run() - # check non-emergency care event is scheduled + # Check non-emergency care event is scheduled assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - - # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought + # run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) - # check HSI event is scheduled + # Check HSI event is scheduled hsi_event_scheduled = [ ev for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM) ] assert 1 == len(hsi_event_scheduled) - - # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + # run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] sam_ev.run(squeeze_factor=0.0) @@ -512,10 +505,10 @@ def test_recovery_severe_acute_malnutrition_without_complications(tmpdir): assert pd.isnull(df.loc[person_id]['un_sam_death_date']) # Check recovery to MAM due to tx is scheduled - assert isinstance(sim.find_events_for_person(person_id)[2][1], Wasting_UpdateToMAM_Event) + assert isinstance(sim.find_events_for_person(person_id)[2][1], Wasting_RecoveryToMAM_Event) # get date of recovery to MAM and the recovery event sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], Wasting_UpdateToMAM_Event)][0] + isinstance(event_tuple[1], Wasting_RecoveryToMAM_Event)][0] date_of_scheduled_recovery_to_mam = sam_recovery_event_tuple[0] sam_recovery_event = sam_recovery_event_tuple[1] assert date_of_scheduled_recovery_to_mam > sim.date @@ -537,7 +530,7 @@ def test_recovery_severe_acute_malnutrition_without_complications(tmpdir): assert pd.isnull(person['un_sam_death_date']) assert person['un_clinical_acute_malnutrition'] == 'MAM' # check they have no symptoms: - assert 0 == len(sim.modules['SymptomManager'].has_what(person_id=person_id, disease_module=sim.modules['Wasting'])) + assert 0 == len(sim.modules['SymptomManager'].has_what(person_id=person_id, disease_module=wmodule)) def test_recovery_severe_acute_malnutrition_with_complications(tmpdir): From 22115b6a42cf8118ef1759a69f5a123f28cc1d65 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 8 Apr 2025 14:44:15 +0100 Subject: [PATCH 415/755] test_wast: ; test_tx_recovery_severe_acute_malnutrition_without_complications-- minor(description, non-necessary alias for 1 use) --- tests/test_wasting.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 8ce1192291..695d7df878 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -397,7 +397,7 @@ def test_nat_recovery_moderate_wasting(tmpdir): def test_tx_recovery_severe_acute_malnutrition_without_complications(tmpdir): - """ Check the onset of symptoms with SAM, check recovery to MAM with tx when + """ Check the onset of symptoms with uncomplicated SAM, check recovery to MAM with tx when the progression to severe wasting is certain, hence no natural recovery from moderate wasting, the natural death due to SAM is certain, hence no natural recovery from severe wasting, and check natural death canceled w\ tx and symptoms resolved when recovered to MAM with tx. """ @@ -443,8 +443,7 @@ def test_tx_recovery_severe_acute_malnutrition_without_complications(tmpdir): polling.apply(sim.population) # Check properties of this individual: should now be moderately wasted - person = df.loc[person_id] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert df.loc[person_id]['un_WHZ_category'] == '-3<=WHZ<-2' # Check that there is a Wasting_ProgressionToSevere_Event scheduled for this person: progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) From c552e59d9cfec3837276f6fdedfb0740202fd563 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 8 Apr 2025 14:53:06 +0100 Subject: [PATCH 416/755] test_wast: ; test_tx_recovery_severe_acute_malnutrition_without_complications -> renamed to: test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications --- tests/test_wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 695d7df878..61692a225b 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -396,7 +396,7 @@ def test_nat_recovery_moderate_wasting(tmpdir): assert pd.isnull(person['un_sam_death_date']) -def test_tx_recovery_severe_acute_malnutrition_without_complications(tmpdir): +def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpdir): """ Check the onset of symptoms with uncomplicated SAM, check recovery to MAM with tx when the progression to severe wasting is certain, hence no natural recovery from moderate wasting, the natural death due to SAM is certain, hence no natural recovery from severe wasting, From e878825df33c684c4781ddc34fe3d28028c423da Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 8 Apr 2025 14:55:41 +0100 Subject: [PATCH 417/755] test_wast: ; test_tx_full_recovery_severe_acute_malnutrition_with_complications-- event name updated, all properties of being well checked after recovery, minor (comments, aliases) --- tests/test_wasting.py | 49 ++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 61692a225b..e0119c862a 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -532,16 +532,16 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd assert 0 == len(sim.modules['SymptomManager'].has_what(person_id=person_id, disease_module=wmodule)) -def test_recovery_severe_acute_malnutrition_with_complications(tmpdir): - """ test individual's recovery from wasting with complications """ +def test_tx_full_recovery_severe_acute_malnutrition_with_complications(tmpdir): + """ Check the onset of symptoms with complicated SAM, check full recovery with tx when + the natural death due to SAM is certain but canceled w\ tx, and symptoms resolved when fully recovered with tx. """ dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) - # get wasting module wmodule = sim.modules['Wasting'] - # set death due to untreated SAM at 100% for all, hence no natural recovery from severe wasting + # Set death due to untreated SAM at 100% for all, hence no natural recovery from severe wasting wmodule.parameters['base_death_rate_untreated_SAM'] = 1.0 wmodule.parameters['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] @@ -553,19 +553,24 @@ def test_recovery_severe_acute_malnutrition_with_complications(tmpdir): df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] - - # Manually set this individual properties to have severe acute malnutrition + # Manually set this individual properties to have SAM df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' df.loc[person_id, 'un_last_wasting_date_of_onset'] = sim.date - # ensure the individual has complications due to SAM + + # Ensure the individual has complications due to SAM wmodule.parameters['prob_complications_in_SAM'] = 1.0 - # assign diagnosis + # Set full recovery rate to 100% so that this individual should fully recover with tx + wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel.multiplicative() + + # Assign diagnosis wmodule.clinical_acute_malnutrition_state(person_id, df) - # by having severe wasting, this individual should be diagnosed as SAM - assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' + # Check properties of this individual: + person = df.loc[person_id] + # should be diagnosed as SAM due to severe wasting + assert person['un_clinical_acute_malnutrition'] == 'SAM' # should have complications - assert df.at[person_id, 'un_sam_with_complications'] + assert person['un_sam_with_complications'] # symptoms should be applied assert person_id in set(sim.modules['SymptomManager'].who_has('weight_loss')) @@ -579,22 +584,17 @@ def test_recovery_severe_acute_malnutrition_with_complications(tmpdir): death_event = death_event_tuple[1] assert date_of_scheduled_death > sim.date - # make full recovery rate to 100% so that this individual should fully recover with tx - wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel.multiplicative() - - # run care seeking event and ensure HSI for complicated SAM is scheduled + # Run care seeking event and ensure HSI for complicated SAM is scheduled hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) hsp.run() - # check non-emergency care event is scheduled assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought + # Run the created instance of HSI_GenericNonEmergencyFirstAppt and check care was sought ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) - # check HSI event for complicated SAM is scheduled hsi_event_scheduled = [ ev @@ -609,14 +609,13 @@ def test_recovery_severe_acute_malnutrition_with_complications(tmpdir): sam_ev.run(squeeze_factor=0.0) # Check scheduled death was canceled due to tx - person = df.loc[person_id] - assert pd.isnull(person['un_sam_death_date']) + assert pd.isnull(df.loc[person_id]['un_sam_death_date']) # Check full recovery due to tx is scheduled - assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_ClinicalAcuteMalnutritionRecovery_Event) + assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_FullRecovery_Event) # get date of full recovery and the recovery event sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if - isinstance(event_tuple[1], Wasting_ClinicalAcuteMalnutritionRecovery_Event)][0] + isinstance(event_tuple[1], Wasting_FullRecovery_Event)][0] date_of_scheduled_full_recovery = sam_recovery_event_tuple[0] sam_recovery_event = sam_recovery_event_tuple[1] assert date_of_scheduled_full_recovery > sim.date @@ -635,12 +634,14 @@ def test_recovery_severe_acute_malnutrition_with_complications(tmpdir): # Check properties of this individual. Should now be well and alive person = df.loc[person_id] assert person['un_WHZ_category'] == 'WHZ>=-2' - assert (person['un_am_MUAC_category'] == '>=125mm') + assert person['un_am_MUAC_category'] == '>=125mm' + assert not person['un_am_nutritional_oedema'] + assert person['un_clinical_acute_malnutrition'] == 'well' assert pd.isnull(person['un_sam_death_date']) assert person['is_alive'] # check they have no symptoms: - assert 0 == len(sim.modules['SymptomManager'].has_what(person_id=person_id, disease_module=sim.modules['Wasting'])) + assert 0 == len(sim.modules['SymptomManager'].has_what(person_id=person_id, disease_module=wmodule)) def test_nat_hist_death(tmpdir): From 2739740d04778012e07ab717710dd2b856e13b10 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 8 Apr 2025 15:07:53 +0100 Subject: [PATCH 418/755] wasting: minor (comments) --- src/tlo/methods/wasting.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 8bc18b42f6..3a81055bb5 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -518,7 +518,7 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): # severe acute malnutrition (SAM): MUAC < 115 mm and/or WHZ < -3 and/or nutritional oedema if (muac == '<115mm') or (whz == 'WHZ<-3') or oedema_presence: df.at[person_id, 'un_clinical_acute_malnutrition'] = 'SAM' - # apply symptoms to all SAM cases + # apply symptoms to the SAM case self.wasting_clinical_symptoms(person_id=person_id) # otherwise moderate acute malnutrition (MAM) @@ -651,14 +651,14 @@ def report_daly_values(self): def wasting_clinical_symptoms(self, person_id) -> None: """ - assign clinical symptoms to new acute malnutrition cases + assign clinical symptoms to the new acute malnutrition case :param person_id: """ df = self.sim.population.props if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': return - # apply wasting symptoms to all SAM cases + # apply wasting symptoms to the new SAM case self.sim.modules["SymptomManager"].change_symptom( person_id=person_id, symptom_string=self.wasting_symptom, From 061ff42fc72da273e479af1e1a47745823ac0b95 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 9 Apr 2025 11:59:44 +0100 Subject: [PATCH 419/755] RF_Wast/pars: death rates for untreated and treated SAM, and mod wast base incidence rate updated to the calibrated values --- resources/ResourceFile_Wasting/parameters.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting/parameters.csv b/resources/ResourceFile_Wasting/parameters.csv index 3d55060897..8c90a4eed6 100644 --- a/resources/ResourceFile_Wasting/parameters.csv +++ b/resources/ResourceFile_Wasting/parameters.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:069a15115d9e4ffaeac19bb93ae8dc0a4245c30de7bbe183f008d63b965df7b3 -size 4304 +oid sha256:dcfb4341b4a2bf174b50990d49ea04ba6b265f70fe850415b08e4412dde9aa4f +size 4674 From 12265c5ac07bc184ef0ddaf819f2232ad020b2c3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 9 Apr 2025 23:08:48 +0100 Subject: [PATCH 420/755] test_wasting: test_nat_death_overwritten_by_tx_death-- test nat death being scheduled and with tx overwritten by death with treatment when all death rates are 100% --- tests/test_wasting.py | 99 +++++++++++++++++++++++++++---------------- 1 file changed, 63 insertions(+), 36 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index e0119c862a..7675007ddf 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -644,58 +644,68 @@ def test_tx_full_recovery_severe_acute_malnutrition_with_complications(tmpdir): assert 0 == len(sim.modules['SymptomManager'].has_what(person_id=person_id, disease_module=wmodule)) -def test_nat_hist_death(tmpdir): - """ Check: Wasting onset --> death """ - """ Check if the risk of death is 100% does everyone with SAM die? """ +def test_nat_death_overwritten_by_tx_death(tmpdir): + """ Check if the risk of death when untreated is 100%, the person is scheduled to die due to natural history. But + with treatment the natural death is cancelled. Check if also chance to fully recover with treatment is 0%, and + risk of death when treated is 100%, the person will die. Tested for uncomplicated SAM.""" dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) + # get wasting module + wmodule = sim.modules['Wasting'] + + # Set death due to untreated SAM at 100% for all, hence no natural recovery from severe wasting, + # hence all SAM cases should die without treatment + wmodule.parameters['base_death_rate_untreated_SAM'] = 1.0 + wmodule.parameters['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) sim.event_queue.queue = [] # clear the queue - # get wasting module - wmodule = sim.modules['Wasting'] - - # Set death rate with tx at 100% - wmodule.parameters['prob_death_after_SAMcare'] = 1.0 - - # make zero recovery rate. reset recovery linear model + # Set full recovery with treatment at 0% wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) + # Set death rate with tx at 100%, hence all SAM cases should die with treatment + wmodule.parameters['prob_death_after_SAMcare'] = 1.0 + # Ensure the individual has no complications when SAM occurs + wmodule.parameters['prob_complications_in_SAM'] = 0.0 - # Get the children to use: + # Get person to use: df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] - - # make an individual diagnosed as SAM by WHZ category. - # We want to make this individual qualify for death + # Manually set this individual properties to have SAM due to severe wasting, hence natural death should be applied df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' + df.loc[person_id, 'un_last_wasting_date_of_onset'] = sim.date - # assign diagnosis + # Assign diagnosis wmodule.clinical_acute_malnutrition_state(person_id, df) - # apply wasting symptoms to this individual - wmodule.wasting_clinical_symptoms(person_id) - - # check symptoms are applied + # Check properties of this individual: + person = df.loc[person_id] + # should be diagnosed as SAM due to severe wasting + assert person['un_clinical_acute_malnutrition'] == 'SAM' + # symptoms should be applied assert person_id in set(sim.modules['SymptomManager'].who_has('weight_loss')) + # natural death should be scheduled + assert not pd.isnull(person['un_sam_death_date']) - # run health seeking behavior and ensure non-emergency event is scheduled + # Get the natural death date + nat_death_date = person['un_sam_death_date'] + + # Run health seeking behavior two days later + sim.date = sim.date + DateOffset(weeks=1) hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) hsp.run() - # check non-emergency care event is scheduled assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought + # Run the created instance of HSI_GenericNonEmergencyFirstAppt ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) - - # check outpatient care event is scheduled + # check outpatient care event is scheduled for uncomplicated SAM hsi_event_scheduled = [ ev for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) @@ -703,24 +713,41 @@ def test_nat_hist_death(tmpdir): ] assert 1 == len(hsi_event_scheduled) - # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] sam_ev.run(squeeze_factor=0.0) - # since there is zero recovery rate, check death event is scheduled + # Check death event is scheduled for another day than natural death was scheduled for since there is no recovery + # with treatment assert isinstance(sim.find_events_for_person(person_id)[0][1], Wasting_SevereAcuteMalnutritionDeath_Event) + assert df.loc[person_id]['un_sam_death_date'] != nat_death_date + + # Load list of all death events scheduled for the person + death_events_list = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if + isinstance(event_tuple[1], Wasting_SevereAcuteMalnutritionDeath_Event)] + + # Run the first scheduled death event (ie natural death), nothing should happen, person should be still alive: + nat_death_event_tuple = death_events_list[0] + assert nat_death_date == nat_death_event_tuple[0] + nat_death_event = nat_death_event_tuple[1] + assert nat_death_date > sim.date + sim.date = nat_death_date + nat_death_event.apply(person_id) + # check properties of this individual: (should be still alive, with death scheduled to another day) + person = df.loc[person_id] + assert person['un_sam_death_date'] != nat_death_date + assert person['is_alive'] - # # Run the acute death event and ensure the person is now dead: - death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], Wasting_SevereAcuteMalnutritionDeath_Event)][0] - date_of_scheduled_death = death_event_tuple[0] - death_event = death_event_tuple[1] - assert date_of_scheduled_death > sim.date - sim.date = date_of_scheduled_death - death_event.apply(person_id=person_id) - - # Check properties of this individual: (should now be dead) + # Run the second scheduled death event (ie death with treatment), ensure the person is now dead: + death_with_tx_event_tuple = death_events_list[1] + death_with_tx_date = death_with_tx_event_tuple[0] + death_with_tx_event = death_with_tx_event_tuple[1] + assert death_with_tx_date != nat_death_date + assert death_with_tx_date > sim.date + sim.date = death_with_tx_date + death_with_tx_event.apply(person_id) + # check properties of this individual: (should now be dead) person = df.loc[person_id] assert not pd.isnull(person['un_sam_death_date']) assert person['un_sam_death_date'] == sim.date From 627a924216749d080fa0c51576f5a42888c8c5fd Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 9 Apr 2025 23:13:52 +0100 Subject: [PATCH 421/755] wast: do not delete death_date if it is not running as it could be natural death date overwritten by date of death with treatment (it is deleted at the start of treatment, and just in case with recovery as well); minor (prints) --- src/tlo/methods/wasting.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 3a81055bb5..c1f869c9be 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -287,6 +287,7 @@ def initialise_population(self, population): p['progression_severe_wasting_by_agegp'] = \ [s/30.4375*p['duration_of_untreated_mod_wasting'] for s in p['progression_severe_wasting_monthly_by_agegp']] print(f"{p['progression_severe_wasting_by_agegp']=}") + print() # Set initial properties df.loc[df.is_alive, 'un_ever_wasted'] = False @@ -553,6 +554,14 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): assert not ((df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') and (df.at[person_id, 'un_sam_with_complications'])), f'{person_id=} has MAM with complications.' + if person_id == self.person_of_interest_id: + print("ACUTE MALNUTRITION STATE ASSIGNED") + print(f"am state: {df.at[person_id, 'un_clinical_acute_malnutrition']}; " + f"complications: {df.at[person_id, 'un_sam_with_complications']}; " + f"death_date: {df.at[person_id, 'un_sam_death_date']}") + print("--------------------------------------") + + def date_of_outcome_for_untreated_wasting(self, whz_category): """ Helper function to determine the duration of the wasting episode to get date of outcome (recovery, progression, @@ -1205,7 +1214,6 @@ def apply(self, person_id): cause='Severe Acute Malnutrition', originating_module=self.module) else: - df.at[person_id, 'un_sam_death_date'] = pd.NaT if do_prints: print("death is not happening because") if not pd.isnull(df.at[person_id, 'un_am_recovery_date']): @@ -1827,7 +1835,7 @@ def apply(self, person_id, squeeze_factor): if not df.at[person_id, 'is_alive']: if do_prints: print("dead already, appt not going through") - print("--------------OTP end1-------------------") + print("---------------------------------") return # Do here whatever happens to an individual during the admission for the treatment @@ -1861,7 +1869,7 @@ def apply(self, person_id, squeeze_factor): "between") if do_prints: - print("----------------------OTP end2-------------------------") + print("-----------------------------------------------") def did_not_run(self): logger.debug(key='debug', data=f'{self.TREATMENT_ID}: did not run') From a97f1f328f666a0989690f56fd7e92359f601204 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 9 Apr 2025 23:32:00 +0100 Subject: [PATCH 422/755] test_wast: use p alias for Wasting module parameters --- tests/test_wasting.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 7675007ddf..ecdcb4bfcf 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -316,6 +316,7 @@ def test_nat_recovery_moderate_wasting(tmpdir): sim = get_sim(tmpdir) # get wasting module wmodule = sim.modules['Wasting'] + p = wmodule.parameters sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) @@ -340,11 +341,11 @@ def test_nat_recovery_moderate_wasting(tmpdir): if am_state_expected == 'MAM': # Set probability of MUAC < 115mm with moderate wasting, and probability of oedema with moderate wasting # at 0% in order to have MAM with onset of wasting - wmodule.parameters['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = 0.0 - wmodule.parameters['proportion_WHZ<-2_with_oedema'] = 0.0 + p['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = 0.0 + p['proportion_WHZ<-2_with_oedema'] = 0.0 else: # am_state_expected == 'SAM' # Set probability of oedema with moderate wasting at 100% in order to have SAM with onset of wasting - wmodule.parameters['proportion_WHZ<-2_with_oedema'] = 1.0 + p['proportion_WHZ<-2_with_oedema'] = 1.0 # Run Wasting Polling event: This event should cause all young children to be moderately wasted polling = Wasting_IncidencePoll(module=wmodule) @@ -406,10 +407,11 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd sim = get_sim(tmpdir) # get wasting module wmodule = sim.modules['Wasting'] + p = wmodule.parameters # Set death due to untreated SAM at 100% for all, hence no natural recovery from severe wasting - wmodule.parameters['base_death_rate_untreated_SAM'] = 1.0 - wmodule.parameters['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] + p['base_death_rate_untreated_SAM'] = 1.0 + p['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) @@ -428,7 +430,7 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd df.at[person_id, 'un_sam_death_date'] = pd.NaT # Ensure the individual has no complications when SAM occurs - wmodule.parameters['prob_complications_in_SAM'] = 0.0 + p['prob_complications_in_SAM'] = 0.0 # Set incidence of wasting at 100% wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() # Set progress to severe wasting at 100% as well, hence no natural recovery from moderate wasting @@ -436,7 +438,7 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd # Set complete recovery from SAM to zero. We want those with SAM to recover to MAM with tx wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) # Set prob of death after tx at 0% (hence recovery to MAM w\ tx at 100%) - wmodule.parameters['prob_death_after_SAMcare'] = 0.0 + p['prob_death_after_SAMcare'] = 0.0 # Run Wasting Polling event to get new incident cases: polling = Wasting_IncidencePoll(module=wmodule) @@ -540,10 +542,11 @@ def test_tx_full_recovery_severe_acute_malnutrition_with_complications(tmpdir): sim = get_sim(tmpdir) # get wasting module wmodule = sim.modules['Wasting'] + p = wmodule.parameters # Set death due to untreated SAM at 100% for all, hence no natural recovery from severe wasting - wmodule.parameters['base_death_rate_untreated_SAM'] = 1.0 - wmodule.parameters['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] + p['base_death_rate_untreated_SAM'] = 1.0 + p['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) @@ -558,7 +561,7 @@ def test_tx_full_recovery_severe_acute_malnutrition_with_complications(tmpdir): df.loc[person_id, 'un_last_wasting_date_of_onset'] = sim.date # Ensure the individual has complications due to SAM - wmodule.parameters['prob_complications_in_SAM'] = 1.0 + p['prob_complications_in_SAM'] = 1.0 # Set full recovery rate to 100% so that this individual should fully recover with tx wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel.multiplicative() @@ -653,11 +656,12 @@ def test_nat_death_overwritten_by_tx_death(tmpdir): sim = get_sim(tmpdir) # get wasting module wmodule = sim.modules['Wasting'] + p = wmodule.parameters # Set death due to untreated SAM at 100% for all, hence no natural recovery from severe wasting, # hence all SAM cases should die without treatment - wmodule.parameters['base_death_rate_untreated_SAM'] = 1.0 - wmodule.parameters['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] + p['base_death_rate_untreated_SAM'] = 1.0 + p['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) @@ -666,9 +670,9 @@ def test_nat_death_overwritten_by_tx_death(tmpdir): # Set full recovery with treatment at 0% wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) # Set death rate with tx at 100%, hence all SAM cases should die with treatment - wmodule.parameters['prob_death_after_SAMcare'] = 1.0 + p['prob_death_after_SAMcare'] = 1.0 # Ensure the individual has no complications when SAM occurs - wmodule.parameters['prob_complications_in_SAM'] = 0.0 + p['prob_complications_in_SAM'] = 0.0 # Get person to use: df = sim.population.props From 847d88405bea51b4ac3ab95b07f7411f9e98f5ac Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 10 Apr 2025 23:16:56 +0100 Subject: [PATCH 423/755] test_wast: test_nat_recovery_moderate_wasting-- minor (comments) --- tests/test_wasting.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index ecdcb4bfcf..a53bbf7b57 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -311,6 +311,7 @@ def test_report_daly_weights(tmpdir): def test_nat_recovery_moderate_wasting(tmpdir): """ Check natural recovery after onset of moderate wasting with MAM diagnosis. """ for am_state_expected in ['MAM', 'SAM']: + dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) @@ -334,9 +335,10 @@ def test_nat_recovery_moderate_wasting(tmpdir): df.loc[person_id, 'un_ever_wasted'] = False df.loc[person_id, 'un_last_wasting_date_of_onset'] = pd.NaT - # Set incidence of moderate wasting at 100% + # Set moderate wasting incidence rate at 100% and rate of progression to severe wasting at 0%. + # (Hence, all children with normal wasting should get onset of moderate wasting and be scheduled for natural + # recovery.) wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() - # Set progression rate to severe wasting at 0% (hence, natural recovery always scheduled) wmodule.wasting_models.severe_wasting_progression_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) if am_state_expected == 'MAM': # Set probability of MUAC < 115mm with moderate wasting, and probability of oedema with moderate wasting From 52f874995761e69f6ef9163a8da7c0b13f36c554 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 10 Apr 2025 23:56:59 +0100 Subject: [PATCH 424/755] test_wast: test_nat_recovery_moderate_wasting-- check no progression to sev wast --- tests/test_wasting.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index a53bbf7b57..5c0a6b4a73 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -377,6 +377,11 @@ def test_nat_recovery_moderate_wasting(tmpdir): recov_event = recov_event_tuple[1] assert date_of_scheduled_recov > sim.date + # Check no progression to sev wasting is scheduled + progress_event_tuple = next((event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], Wasting_ProgressionToSevere_Event)), None) + assert not progress_event_tuple + # Run the natural recovery event: sim.date = date_of_scheduled_recov recov_event.apply(person_id) From 9b355ba1292e68ec14bd8413f609c5605d9396b7 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 11 Apr 2025 00:25:54 +0100 Subject: [PATCH 425/755] test_wast: test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled-- test for MAM and complicated SAM separately --- tests/test_wasting.py | 179 +++++++++++++++++++++++++----------------- 1 file changed, 109 insertions(+), 70 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 5c0a6b4a73..02479ac764 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -765,86 +765,125 @@ def test_nat_death_overwritten_by_tx_death(tmpdir): assert not person['is_alive'] -def test_nat_hist_cure_if_recovery_scheduled(tmpdir): - """ Show that if a cure event is run before when a person was going to recover naturally, it causes the episode - to end earlier. """ +def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): + """ Show that if recovered with a tx event before the person was going to recover naturally from moderate wasting + with moderate or severe acute malnutrition, it causes the episode to end earlier, natural recovery is cancelled. + Test for MAM and complicated SAM. """ - dur = pd.DateOffset(days=0) - popsize = 1000 - sim = get_sim(tmpdir) + for am_state_expected in ['MAM', 'SAM']: - sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) - sim.event_queue.queue = [] # clear the queue + dur = pd.DateOffset(days=0) + popsize = 1000 + sim = get_sim(tmpdir) + # get wasting module + wmodule = sim.modules['Wasting'] + p = wmodule.parameters - wmodule = sim.modules['Wasting'] - p = wmodule.parameters - # set prob of death after tx at 0% (hence recovery to MAM at 100%) - p['prob_death_after_SAMcare'] = 0.0 + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + sim.event_queue.queue = [] # clear the queue - # increase wasting incidence rate to 100% and reduce rate of progress to severe wasting to zero. We don't want - # individuals to progress to SAM as we are testing for MAM natural recovery - wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() - wmodule.wasting_models.severe_wasting_progression_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) + # Set moderate wasting incidence rate at 100% and rate of progression to severe wasting at 0%. + # (Hence, all children with normal wasting should get onset of moderate wasting and be scheduled for natural + # recovery.) + wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() + wmodule.wasting_models.severe_wasting_progression_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) + # Set probs of full recovery from MAM and SAM at 100%, so with tx they always fully recover + wmodule.wasting_models.acute_malnutrition_recovery_mam_lm = LinearModel.multiplicative() + wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel.multiplicative() - # Get person to use: - df = sim.population.props - under5s = df.loc[df.is_alive & (df['age_years'] < 5)] - person_id = under5s.index[0] - assert df.loc[person_id, 'un_WHZ_category'] == 'WHZ>=-2' + # Get person to use: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + # Manually set this individual properties to be well + df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' + df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' + df.loc[person_id, 'un_am_nutritional_oedema'] = False + df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' + df.at[person_id, 'un_sam_with_complications'] = False + df.at[person_id, 'un_sam_death_date'] = pd.NaT - # Run Wasting Polling event to get new incident cases: - polling = Wasting_IncidencePoll(module=sim.modules['Wasting']) - polling.apply(sim.population) + if am_state_expected == 'MAM': + # Set probability of MUAC < 115mm with moderate wasting, and probability of oedema with moderate wasting + # at 0% in order to have MAM with onset of wasting + p['proportion_-3<=WHZ<-2_with_MUAC<115mm'] = 0.0 + p['proportion_WHZ<-2_with_oedema'] = 0.0 + else: # am_state_expected == 'SAM' + # Set probability of oedema with moderate wasting at 100% in order to have SAM with onset of wasting + p['proportion_WHZ<-2_with_oedema'] = 1.0 + # Ensure the individual has always complications when SAM occurs + p['prob_complications_in_SAM'] = 1.0 - # Check properties of this individual: (should now be moderately wasted without progression to severe) - person = df.loc[person_id] - assert person['un_ever_wasted'] - assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date - assert pd.isnull(person['un_am_tx_start_date']) - assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) + # Run Wasting Polling event to get new incident cases: + polling = Wasting_IncidencePoll(module=wmodule) + polling.apply(sim.population) - # Check that there is a Wasting_NaturalRecovery_Event scheduled for this person: - recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], Wasting_NaturalRecovery_Event)][0] - date_of_scheduled_recov = recov_event_tuple[0] - recov_event = recov_event_tuple[1] - assert date_of_scheduled_recov > sim.date + # Check that there is a natural recovery event scheduled: + # Wasting_FullRecovery_Event if this person has MAM, Wasting_RecoveryToMAM_Event if this person has SAM + if am_state_expected == 'MAM': + recov_event_type = Wasting_FullRecovery_Event + else: # am_state_expected == 'SAM' + recov_event_type = Wasting_RecoveryToMAM_Event + nat_recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], recov_event_type)][0] + date_of_scheduled_nat_recov = nat_recov_event_tuple[0] + nat_recov_event = nat_recov_event_tuple[1] - # Run a Cure Event after the length of the treatment - def get_tx_length(in_person_id): - if df.at[in_person_id, 'un_sam_with_complications']: - tx_length = p['tx_length_weeks_InpatientSAM'] - elif df.at[in_person_id, 'un_clinical_acute_malnutrition'] == 'SAM': - tx_length = p['tx_length_weeks_OutpatientSAM'] - else: # df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM': + # Start appropriate treatment + if am_state_expected == 'MAM': + wmodule.do_when_am_treatment(person_id, intervention='SFP') tx_length = p['tx_length_weeks_SuppFeedingMAM'] - return tx_length - sim.date = sim.date + DateOffset(weeks=get_tx_length(person_id)) - assert sim.date < date_of_scheduled_recov - cure_event = Wasting_ClinicalAcuteMalnutritionRecovery_Event(person_id=person_id, module=sim.modules['Wasting']) - cure_event.apply(person_id=person_id) - - # Check the natural recovery was cancelled with the cure: - assert date_of_scheduled_recov in df.at[person_id, 'un_nat_recov_to_cancel'] - - # Check that the person is not wasted and is alive still: - person = df.loc[person_id] - assert person['is_alive'] - assert person['un_WHZ_category'] == 'WHZ>=-2' - assert not pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - - # Run the recovery event that was originally scheduled - this should have no effect - sim.date = date_of_scheduled_recov - recov_event.apply(person_id=person_id) - person = df.loc[person_id] - assert person['is_alive'] - assert person['un_WHZ_category'] == 'WHZ>=-2' - assert not pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) + else: # complicated SAM + wmodule.do_when_am_treatment(person_id, intervention='ITC') + tx_length = p['tx_length_weeks_InpatientSAM'] + assert df.at[person_id, 'un_am_tx_start_date'] == sim.date + + # Check full recovery with tx is scheduled before the natural recovery + full_recov_events = [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], Wasting_FullRecovery_Event)] + assert len(full_recov_events) in [1, 2], "only 1 or 2 full recovery events should be scheduled" + if len(full_recov_events) == 2: # with MAM nat full recovery as well as full recovery with tx + nat_recov_event_tuple = full_recov_events[1] # tx recovery scheduled to happen before recovery with tx + date_of_scheduled_nat_recov_to_confirm = nat_recov_event_tuple[0] + assert date_of_scheduled_nat_recov_to_confirm == date_of_scheduled_nat_recov + tx_recov_event_tuple = full_recov_events[0] + date_of_scheduled_tx_recov = tx_recov_event_tuple[0] + tx_recov_event = tx_recov_event_tuple[1] + assert date_of_scheduled_tx_recov > sim.date + assert date_of_scheduled_tx_recov < date_of_scheduled_nat_recov + + # Run a recovery event due to tx first + sim.date = date_of_scheduled_tx_recov + tx_recov_event.apply(person_id) + # check properties of this individual, should have recovered today, is not wasted, is well-nourished and alive + person = df.loc[person_id] + assert person['un_am_recovery_date'] == sim.date + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert person['un_am_MUAC_category'] == '>=125mm' + assert not person['un_am_nutritional_oedema'] + assert person['un_clinical_acute_malnutrition'] == 'well' + assert person['is_alive'] + assert pd.isnull(person['un_sam_death_date']) + + # Check natural recovery is going to be cancelled + if am_state_expected == 'MAM': + assert date_of_scheduled_nat_recov in df.loc[person_id, 'un_full_recov_to_cancel'] + else: # complicated SAM + assert date_of_scheduled_nat_recov in df.loc[person_id, 'un_recov_to_mam_to_cancel'] + # Run the natural recovery, this should have no effect + sim.date = date_of_scheduled_nat_recov + nat_recov_event.apply(person_id) + # check properties of this individual are still exact the same + person = df.loc[person_id] + assert person['un_am_recovery_date'] == date_of_scheduled_tx_recov + assert date_of_scheduled_tx_recov < sim.date + assert person['un_WHZ_category'] == 'WHZ>=-2' + assert person['un_am_MUAC_category'] == '>=125mm' + assert not person['un_am_nutritional_oedema'] + assert person['un_clinical_acute_malnutrition'] == 'well' + assert person['is_alive'] + assert pd.isnull(person['un_sam_death_date']) def test_nat_hist_cure_if_death_scheduled(tmpdir): From ed669f71e4f27cb9b1a87aa0e47ea09b7c17ec25 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 11 Apr 2025 00:26:16 +0100 Subject: [PATCH 426/755] test_wast: test_nat_death_overwritten_by_tx_death-- minor (description) --- tests/test_wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 02479ac764..928e550930 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -657,7 +657,7 @@ def test_tx_full_recovery_severe_acute_malnutrition_with_complications(tmpdir): def test_nat_death_overwritten_by_tx_death(tmpdir): """ Check if the risk of death when untreated is 100%, the person is scheduled to die due to natural history. But with treatment the natural death is cancelled. Check if also chance to fully recover with treatment is 0%, and - risk of death when treated is 100%, the person will die. Tested for uncomplicated SAM.""" + risk of death when treated is 100%, the person will die. Test for uncomplicated SAM.""" dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) From 67c2db912d06527b9c605a73bf1a796d5554672f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 14 Apr 2025 17:33:37 +0100 Subject: [PATCH 427/755] wast: minor (prints) --- src/tlo/methods/wasting.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index c1f869c9be..0eccb2cc5d 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -555,11 +555,12 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): and (df.at[person_id, 'un_sam_with_complications'])), f'{person_id=} has MAM with complications.' if person_id == self.person_of_interest_id: - print("ACUTE MALNUTRITION STATE ASSIGNED") + print('-----') + print("Acute Malnutrition state ASSIGNED") print(f"am state: {df.at[person_id, 'un_clinical_acute_malnutrition']}; " f"complications: {df.at[person_id, 'un_sam_with_complications']}; " f"death_date: {df.at[person_id, 'un_sam_death_date']}") - print("--------------------------------------") + print("-----") def date_of_outcome_for_untreated_wasting(self, whz_category): @@ -602,7 +603,6 @@ def date_of_death_for_untreated_sam(self): date_of_death = self.sim.date + DateOffset(days=duration_sam_to_death) return date_of_death - def clinical_signs_acute_malnutrition(self, idx): """ When WHZ changed, update other anthropometric indices and clinical signs (MUAC, oedema) that determine the From 302b247054defda8cae21816708edcd20f4a72bc Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 14 Apr 2025 17:58:39 +0100 Subject: [PATCH 428/755] wast: retrieve cons codes and amounts for each tx at sim initialisation --- src/tlo/methods/wasting.py | 63 +++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 0eccb2cc5d..bc3fa96d64 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -366,6 +366,9 @@ def initialise_simulation(self, sim): # sim.schedule_event(PrintPersonPropertiesEventIfUpdated(self, self.person_of_interest_id), # sim.date + DateOffset(days=1)) + # Retrieve the consumables codes and amounts of the consumables used + self.cons_codes = self.get_consumables_for_each_treatment() + def on_birth(self, mother_id, child_id): """Initialise properties for a newborn individual. :param mother_id: the mother for this child @@ -562,6 +565,21 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): f"death_date: {df.at[person_id, 'un_sam_death_date']}") print("-----") + def get_consumables_for_each_treatment(self): + """Get the item_code and amount administrated for all consumables for each treatment.""" + + # ### Get item codes from item names and define number of units per case here + get_item_code = self.sim.modules['HealthSystem'].get_item_code_from_item_name + + _cons_codes = dict() + _cons_codes['SFP'] = {get_item_code("Corn Soya Blend (or Supercereal - CSB++)"): 3000 * 3} + _cons_codes['OTP'] = {get_item_code("Therapeutic spread, sachet 92g/CAR-150"): 20 * 7} + _cons_codes['OTP_opt'] = {get_item_code("SAM medicines"): 1} + _cons_codes['ITC'] = {get_item_code("F-75 therapeutic milk, 102.5 g"): 102.5 * 24, + get_item_code("Therapeutic spread, sachet 92g/CAR-150"): 3 * 4} + _cons_codes['ITC_opt'] = {get_item_code("SAM medicines"): 1} + + return _cons_codes def date_of_outcome_for_untreated_wasting(self, whz_category): """ @@ -1772,16 +1790,10 @@ def apply(self, person_id, squeeze_factor): # Perform measurements (height/length), weight, MUAC self.add_equipment({'Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape'}) - # Make request for consumables - consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] - # individual items - item_code1 = pd.unique(consumables.loc[consumables['Items'] == - 'Corn Soya Blend (or Supercereal - CSB++)', 'Item_Code'])[0] - - # check availability of consumables - if self.get_consumables([item_code1]): + # Check and log availability of consumables + if self.get_consumables(item_codes=self.module.cons_codes['SFP']): logger.debug(key='debug', data='consumables are available') - # Log that the treatment is provided: + # Record that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'CSB++' if do_prints: print("consumables available") @@ -1843,19 +1855,12 @@ def apply(self, person_id, squeeze_factor): # Perform measurements (height/length), weight, MUAC self.add_equipment({'Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape'}) - # Make request for consumables - consumables = self.sim.modules['HealthSystem'].parameters[ - 'item_and_package_code_lookups'] - - # individual items - item_code1 = pd.unique(consumables.loc[consumables['Items'] == - 'SAM theraputic foods', 'Item_Code'])[0] - item_code2 = pd.unique(consumables.loc[consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] - - # check availability of consumables - if self.get_consumables(item_code1) and self.get_consumables(item_code2): + # Check and log availability of consumables + if self.get_consumables( + item_codes=self.module.cons_codes['OTP'], optional_item_codes=self.module.cons_codes['OTP_opt'] + ): logger.debug(key='debug', data='consumables are available.') - # Log that the treatment is provided: + # Record that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' if do_prints: print("consumables available") @@ -1914,18 +1919,12 @@ def apply(self, person_id, squeeze_factor): # Perform measurements (height/length, weight, MUAC) self.add_equipment({'Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape'}) - # Make request for consumables - consumables = self.sim.modules['HealthSystem'].parameters['item_and_package_code_lookups'] - - # individual items - item_code1 = pd.unique( - consumables.loc[consumables['Items'] == 'SAM theraputic foods', 'Item_Code'])[0] - item_code2 = pd.unique(consumables.loc[consumables['Items'] == 'SAM medicines', 'Item_Code'])[0] - - # check availability of consumables - if self.get_consumables(item_code1) and self.get_consumables(item_code2): + # Check and log availability of consumables + if self.get_consumables( + item_codes=self.module.cons_codes['ITC'], optional_item_codes=self.module.cons_codes['ITC_opt'] + ): logger.debug(key='debug', data='consumables available, so use it.') - # Log that the treatment is provided: + # Record that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'inpatient_care' if do_prints: print("consumables available") From 11a168fba391560bdfba1187747349d95841694a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 14 Apr 2025 18:55:25 +0100 Subject: [PATCH 429/755] scripts/costing & consumables_analyses: Sakshi's analysis scripts (reached on 14 Apr) added --- ...analysis_impact_of_consumable_scenarios.py | 1115 ++++++++++ src/scripts/costing/cost_estimation.py | 1902 +++++++++++++++++ .../costing/costing_overview_analysis.py | 371 ++++ 3 files changed, 3388 insertions(+) create mode 100644 src/scripts/consumables_analyses/analysis_impact_of_consumable_scenarios.py create mode 100644 src/scripts/costing/cost_estimation.py create mode 100644 src/scripts/costing/costing_overview_analysis.py diff --git a/src/scripts/consumables_analyses/analysis_impact_of_consumable_scenarios.py b/src/scripts/consumables_analyses/analysis_impact_of_consumable_scenarios.py new file mode 100644 index 0000000000..5b3ee33ba7 --- /dev/null +++ b/src/scripts/consumables_analyses/analysis_impact_of_consumable_scenarios.py @@ -0,0 +1,1115 @@ +"""This file uses the results of the results of running `impact_of_cons_availability_intervention.py` +tob extract summary results for the manuscript - "Rethinking economic evaluation of +system level interventions. +I plan to run the simulation for a short period of 5 years (2020 - 2025) because +holding the consumable availability constant in the short run would be more justifiable +than holding it constant for a long period. +""" + +import argparse +from pathlib import Path +import textwrap +from typing import Tuple + +import numpy as np +import pandas as pd +from matplotlib import pyplot as plt +import matplotlib.colors as mcolors +from matplotlib.ticker import FuncFormatter +from collections import Counter, defaultdict +import seaborn as sns +import squarify + +from tlo.analysis.utils import ( + CAUSE_OF_DEATH_OR_DALY_LABEL_TO_COLOR_MAP, + extract_results, + get_color_cause_of_death_or_daly_label, + make_age_grp_lookup, + order_of_cause_of_death_or_daly_label, + summarize, +) +import pickle + +from tlo import Date +from tlo.analysis.utils import ( + extract_params, + extract_results, + get_scenario_info, + get_scenario_outputs, + load_pickled_dataframes, + make_age_grp_lookup, + make_age_grp_types, + make_calendar_period_lookup, + make_calendar_period_type, + summarize, + write_log_to_excel, + parse_log_file, + COARSE_APPT_TYPE_TO_COLOR_MAP, + SHORT_TREATMENT_ID_TO_COLOR_MAP, + _standardize_short_treatment_id, + bin_hsi_event_details, + compute_mean_across_runs, + get_coarse_appt_type, + get_color_short_treatment_id, + order_of_short_treatment_ids, + plot_stacked_bar_chart, + squarify_neat, + unflatten_flattened_multi_index_in_logging, +) + +outputspath = Path('./outputs') +figurespath = Path(outputspath / 'impact_of_consumable_scenarios_results') +figurespath.mkdir(parents=True, exist_ok=True) # create directory if it doesn't exist +resourcefilepath = Path("./resources") + +# Declare period for which the results will be generated (defined inclusively) + +TARGET_PERIOD = (Date(2015, 1, 1), Date(2019, 12, 31)) + +make_graph_file_name = lambda stub: output_folder / f"{stub.replace('*', '_star_')}.png" # noqa: E731 + +_, age_grp_lookup = make_age_grp_lookup() + +def target_period() -> str: + """Returns the target period as a string of the form YYYY-YYYY""" + return "-".join(str(t.year) for t in TARGET_PERIOD) + +def drop_outside_period(_df): + """Return a dataframe which only includes for which the date is within the limits defined by TARGET_PERIOD""" + return _df.drop(index=_df.index[~_df['date'].between(*TARGET_PERIOD)]) + +def do_bar_plot_with_ci(_df, annotations=None, xticklabels_horizontal_and_wrapped=False): + """Make a vertical bar plot for each row of _df, using the columns to identify the height of the bar and the + extent of the error bar.""" + + yerr = np.array([ + (_df['median'] - _df['lower']).values, + (_df['upper'] - _df['median']).values, + ]) + + xticks = {(i + 0.5): k for i, k in enumerate(_df.index)} + + # Define color mapping based on index values + color_mapping = { + 'Actual': '#1f77b4', + 'Non-therapeutic consumables':'#ff7f0e', + 'Vital medicines': '#2ca02c', + 'Pharmacist-managed':'#d62728', + '75th percentile facility':'#9467bd', + '90th percentile facility':'#8c564b', + 'Best facility': '#e377c2', + 'Best facility (including DHO)': '#7f7f7f', + 'HIV supply chain': '#bcbd22', + 'EPI supply chain': '#17becf', + 'Perfect':'#31a354' + } + + colors = [_df.index[i] in color_mapping for i in range(len(_df.index))] + color_values = [color_mapping.get(idx, '#cccccc') for idx in _df.index] + + fig, ax = plt.subplots() + ax.bar( + xticks.keys(), + _df['median'].values, + yerr=yerr, + alpha=1, + color=color_values, + ecolor='black', + capsize=10, + label=xticks.values() + ) + if annotations: + for xpos, ypos, text in zip(xticks.keys(), _df['upper'].values, annotations): + ax.text(xpos, ypos * 1.05, text, horizontalalignment='center', fontsize=10) + + ax.set_xticks(list(xticks.keys())) + if not xticklabels_horizontal_and_wrapped: + wrapped_labs = ["\n".join(textwrap.wrap(_lab, 20)) for _lab in xticks.values()] + ax.set_xticklabels(wrapped_labs, rotation=45, ha='right', fontsize=10) + else: + wrapped_labs = ["\n".join(textwrap.wrap(_lab, 20)) for _lab in xticks.values()] + ax.set_xticklabels(wrapped_labs, fontsize=10) + + # Set font size for y-tick labels + ax.tick_params(axis='y', labelsize=10) + ax.tick_params(axis='x', labelsize=10) + + ax.grid(axis="y") + ax.spines['top'].set_visible(False) + ax.spines['right'].set_visible(False) + fig.tight_layout() + + return fig, ax + +def do_bar_plot_with_ci_and_heatmap(_df, annotations=None, xticklabels_horizontal_and_wrapped=False, heatmap_values=None, plt_title = 'unnamed_figure'): + """Create a bar plot with CI and a heatmap above it.""" + yerr = np.array([ + (_df['median'] - _df['lower']).values, + (_df['upper'] - _df['median']).values, + ]) + + xticks = {(i + 0.5): k for i, k in enumerate(_df.index)} + + # Define color mapping based on index values + color_mapping = { + 'Actual': '#1f77b4', + 'Non-therapeutic consumables':'#ff7f0e', + 'Vital medicines': '#2ca02c', + 'Pharmacist-managed':'#d62728', + '75th percentile facility':'#9467bd', + '90th percentile facility':'#8c564b', + 'Best facility': '#e377c2', + 'Best facility (including DHO)': '#7f7f7f', + 'HIV supply chain': '#bcbd22', + 'EPI supply chain': '#17becf', + 'Perfect':'#31a354' + } + + color_values = [color_mapping.get(idx, '#cccccc') for idx in _df.index] + + # Create a figure with two axes + fig, (heatmap_ax, ax) = plt.subplots( + nrows=2, ncols=1, gridspec_kw={"height_ratios": [0.3, 2]}, figsize=(10, 7) + ) + + # Heatmap axis + if heatmap_values: + cmap = plt.cm.YlGn + norm = mcolors.Normalize(vmin=min(heatmap_values), vmax=max(heatmap_values)) + heatmap_colors = [cmap(norm(value)) for value in heatmap_values] + + heatmap_ax.bar( + xticks.keys(), + [1] * len(heatmap_values), # Constant height for heatmap bars + color=heatmap_colors, + align='center', + width=0.8 + ) + + # Add data labels to heatmap bars + for xpos, value in zip(xticks.keys(), heatmap_values): + heatmap_ax.text( + xpos, 0.5, f"{value:.2f}", color='black', ha='center', va='center', fontsize= 12, weight='bold' + ) + + heatmap_ax.set_xticks(list(xticks.keys())) + heatmap_ax.set_xticklabels([]) + heatmap_ax.set_yticks([]) + heatmap_ax.set_ylabel('Average consumable \n availability under \n each scenario \n (Baseline = 0.52)', fontsize=10, rotation=0, labelpad=20) + heatmap_ax.spines['top'].set_visible(False) + heatmap_ax.spines['right'].set_visible(False) + heatmap_ax.spines['left'].set_visible(False) + heatmap_ax.spines['bottom'].set_visible(False) + + # Bar plot axis + ax.bar( + xticks.keys(), + _df['median'].values, + yerr=yerr, + alpha=1, + color=color_values, + ecolor='black', + capsize=10 + ) + if annotations: + for xpos, ypos, text in zip(xticks.keys(), _df['upper'].values, annotations): + ax.text(xpos, ypos * 1.05, text, horizontalalignment='center', fontsize=10) + + ax.set_xticks(list(xticks.keys())) + if not xticklabels_horizontal_and_wrapped: + wrapped_labs = ["\n".join(textwrap.wrap(_lab, 20)) for _lab in xticks.values()] + ax.set_xticklabels(wrapped_labs, rotation=45, ha='right', fontsize=10) + else: + wrapped_labs = ["\n".join(textwrap.wrap(_lab, 20)) for _lab in xticks.values()] + ax.set_xticklabels(wrapped_labs, fontsize=10) + + # Set font size for y-tick labels + ax.tick_params(axis='y', labelsize=10) + ax.tick_params(axis='x', labelsize=10) + + ax.grid(axis="y") + ax.spines['top'].set_visible(False) + ax.spines['right'].set_visible(False) + + # Add global title + fig.suptitle(plt_title, fontsize=16, fontweight='bold') + + fig.tight_layout() + + return fig, (heatmap_ax, ax) + +def get_num_dalys(_df): + """Return total number of DALYS (Stacked) by label (total within the TARGET_PERIOD). + Throw error if not a record for every year in the TARGET PERIOD (to guard against inadvertently using + results from runs that crashed mid-way through the simulation. + """ + years_needed = [i.year for i in TARGET_PERIOD] + assert set(_df.year.unique()).issuperset(years_needed), "Some years are not recorded." + return pd.Series( + data=_df + .loc[_df.year.between(*years_needed)] + .drop(columns=['date', 'sex', 'age_range', 'year']) + .sum().sum() + ) + +def get_num_dalys_by_cause(_df): + """Return total number of DALYS (Stacked) by label (total within the TARGET_PERIOD). + Throw error if not a record for every year in the TARGET PERIOD (to guard against inadvertently using + results from runs that crashed mid-way through the simulation. + """ + years_needed = [i.year for i in TARGET_PERIOD] + assert set(_df.year.unique()).issuperset(years_needed), "Some years are not recorded." + return pd.Series( + data=_df + .loc[_df.year.between(*years_needed)] + .drop(columns=['date', 'sex', 'age_range', 'year']) + .sum() + ) + +def get_num_dalys_per_person_year(_df): + """Return total number of DALYS (Stacked) by label (total within the TARGET_PERIOD). + Throw error if not a record for every year in the TARGET PERIOD (to guard against inadvertently using + results from runs that crashed mid-way through the simulation. + """ + years_needed = [i.year for i in TARGET_PERIOD] + assert set(_df.year.unique()).issuperset(years_needed), "Some years are not recorded." + return pd.Series( + data=_df + .loc[_df.year.between(*years_needed)] + .drop(columns=['date', 'sex', 'age_range']) + .groupby('year').sum().sum(axis = 1) + ) + +def get_num_dalys_per_person_year_by_cause(_df): + """Return total number of DALYS (Stacked) by label (total within the TARGET_PERIOD). + Throw error if not a record for every year in the TARGET PERIOD (to guard against inadvertently using + results from runs that crashed mid-way through the simulation. + """ + years_needed = [i.year for i in TARGET_PERIOD] + assert set(_df.year.unique()).issuperset(years_needed), "Some years are not recorded." + return pd.Series( + data=_df + .loc[_df.year.between(*years_needed)] + .drop(columns=['date', 'sex', 'age_range']) + .groupby('year').sum().unstack() + ) +def extract_results_by_person_year(results_folder: Path, + module: str, + key: str, + column: str = None, + index: str = None, + custom_generate_series=None, + ) -> pd.DataFrame: + """Utility function to unpack results. + + Produces a dataframe from extracting information from a log with the column multi-index for the draw/run. + + If the column to be extracted exists in the log, the name of the `column` is provided as `column`. If the resulting + dataframe should be based on another column that exists in the log, this can be provided as 'index'. + + If instead, some work must be done to generate a new column from log, then a function can be provided to do this as + `custom_generate_series`. + + Optionally, with `do_scaling=True`, each element is multiplied by the scaling_factor recorded in the simulation. + + Note that if runs in the batch have failed (such that logs have not been generated), these are dropped silently. + """ + + def get_population_size(_draw, _run): + """Helper function to get the multiplier from the simulation. + Note that if the scaling factor cannot be found a `KeyError` is thrown.""" + return load_pickled_dataframes( + results_folder, _draw, _run, 'tlo.methods.demography' + )['tlo.methods.demography']['population']['total'] + + if custom_generate_series is None: + # If there is no `custom_generate_series` provided, it implies that function required selects the specified + # column from the dataframe. + assert column is not None, "Must specify which column to extract" + else: + assert index is None, "Cannot specify an index if using custom_generate_series" + assert column is None, "Cannot specify a column if using custom_generate_series" + + def generate_series(dataframe: pd.DataFrame) -> pd.Series: + if custom_generate_series is None: + if index is not None: + return dataframe.set_index(index)[column] + else: + return dataframe.reset_index(drop=True)[column] + else: + return custom_generate_series(dataframe) + + # get number of draws and numbers of runs + info = get_scenario_info(results_folder) + + # Collect results from each draw/run + res = dict() + for draw in range(info['number_of_draws']): + for run in range(info['runs_per_draw']): + + draw_run = (draw, run) + + try: + df: pd.DataFrame = load_pickled_dataframes(results_folder, draw, run, module)[module][key] + output_from_eval: pd.Series = generate_series(df) + assert pd.Series == type(output_from_eval), 'Custom command does not generate a pd.Series' + res[draw_run] = output_from_eval.reset_index().drop(columns = ['year']).T / get_population_size(draw, run) + res[draw_run] = res[draw_run].sum(axis =1) + except KeyError: + # Some logs could not be found - probably because this run failed. + res[draw_run] = None + + # Use pd.concat to compile results (skips dict items where the values is None) + _concat = pd.concat(res, axis=1) + _concat.columns.names = ['draw', 'run'] # name the levels of the columns multi-index + return _concat + +def extract_results_by_person_year_by_cause(results_folder: Path, + module: str, + key: str, + column: str = None, + index: str = None, + custom_generate_series=None, + cause: str = None, + ) -> pd.DataFrame: + """Utility function to unpack results. + + Produces a dataframe from extracting information from a log with the column multi-index for the draw/run. + + If the column to be extracted exists in the log, the name of the `column` is provided as `column`. If the resulting + dataframe should be based on another column that exists in the log, this can be provided as 'index'. + + If instead, some work must be done to generate a new column from log, then a function can be provided to do this as + `custom_generate_series`. + + Optionally, with `do_scaling=True`, each element is multiplied by the scaling_factor recorded in the simulation. + + Note that if runs in the batch have failed (such that logs have not been generated), these are dropped silently. + """ + + def get_population_size(_draw, _run): + """Helper function to get the multiplier from the simulation. + Note that if the scaling factor cannot be found a `KeyError` is thrown.""" + return load_pickled_dataframes( + results_folder, _draw, _run, 'tlo.methods.demography' + )['tlo.methods.demography']['population']['total'] + + if custom_generate_series is None: + # If there is no `custom_generate_series` provided, it implies that function required selects the specified + # column from the dataframe. + assert column is not None, "Must specify which column to extract" + else: + assert index is None, "Cannot specify an index if using custom_generate_series" + assert column is None, "Cannot specify a column if using custom_generate_series" + + def generate_series(dataframe: pd.DataFrame) -> pd.Series: + if custom_generate_series is None: + if index is not None: + return dataframe.set_index(index)[column] + else: + return dataframe.reset_index(drop=True)[column] + else: + return custom_generate_series(dataframe) + + # get number of draws and numbers of runs + info = get_scenario_info(results_folder) + + # Collect results from each draw/run + res = dict() + for draw in range(info['number_of_draws']): + for run in range(info['runs_per_draw']): + + draw_run = (draw, run) + + try: + df: pd.DataFrame = load_pickled_dataframes(results_folder, draw, run, module)[module][key] + output_from_eval: pd.Series = generate_series(df) + assert pd.Series == type(output_from_eval), 'Custom command does not generate a pd.Series' + output_from_eval = output_from_eval[output_from_eval.index.get_level_values(0) == cause].droplevel(0) + res[draw_run] = output_from_eval.reset_index().drop(columns = ['year']).T / get_population_size(draw, run) + res[draw_run] = res[draw_run].sum(axis =1) + except KeyError: + # Some logs could not be found - probably because this run failed. + res[draw_run] = None + + # Use pd.concat to compile results (skips dict items where the values is None) + _concat = pd.concat(res, axis=1) + _concat.columns.names = ['draw', 'run'] # name the levels of the columns multi-index + return _concat + +def find_difference_relative_to_comparison(_ser: pd.Series, + comparison: str, + scaled: bool = False, + drop_comparison: bool = True, + ): + """Find the difference in the values in a pd.Series with a multi-index, between the draws (level 0) + within the runs (level 1), relative to where draw = `comparison`. + The comparison is `X - COMPARISON`.""" + return _ser \ + .unstack(level=0) \ + .apply(lambda x: (x - x[comparison]) / (x[comparison] if scaled else 1.0), axis=1) \ + .drop(columns=([comparison] if drop_comparison else [])) \ + .stack() + +# %% Gathering basic information + +# Find results_folder associated with a given batch_file and get most recent +#results_folder = get_scenario_outputs('impact_of_consumable_scenarios.py', outputspath) +results_folder = Path(outputspath / 'sakshi.mohan@york.ac.uk/impact_of_consumables_scenarios-2024-09-12T192454Z/') +#results_folder = Path(outputspath / 'impact_of_consumables_scenarios-2024-09-12T155640Z/') + +# look at one log (so can decide what to extract) +log = load_pickled_dataframes(results_folder) + +# 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) +params_dict = {'default': 'Actual', 'scenario1': 'Non-therapeutic consumables', 'scenario2': 'Vital medicines', + 'scenario3': 'Pharmacist-managed', 'scenario4': 'Level 1b', 'scenario5': 'CHAM', + 'scenario6': '75th percentile facility', 'scenario7': '90th percentile facility', 'scenario8': 'Best facility', + 'scenario9': 'Best facility (including DHO)','scenario10': 'HIV supply chain','scenario11': 'EPI supply chain', + 'scenario12': 'HIV moved to Govt supply chain', 'all': 'Perfect'} +params_dict_df = pd.DataFrame.from_dict(params_dict, orient='index', columns=['name_of_scenario']).reset_index().rename(columns = {'index': 'value'}) +params = params.merge(params_dict_df, on = 'value', how = 'left', validate = '1:1') +scenarios = params['name_of_scenario'] #range(len(params)) # X-axis values representing time periods +drop_scenarios = ['Level 1b', 'CHAM', 'Best facility (including DHO)', 'HIV moved to Govt supply chain'] # Drops scenarios which are no longer considered important for comparison + +# %% Extracting results from run + +# 1. DALYs accrued and averted +################################### +# 1.1 Total DALYs accrued +#------------------------- +# Get total DALYs accrued +num_dalys = extract_results( + results_folder, + module='tlo.methods.healthburden', + key='dalys_stacked', + custom_generate_series=get_num_dalys, + do_scaling=True + ) + +# %% Chart of total number of DALYS +num_dalys_summarized = summarize(num_dalys).loc[0].unstack() +num_dalys_summarized['scenario'] = scenarios.to_list() +num_dalys_summarized = num_dalys_summarized.set_index('scenario') +num_dalys_summarized.to_csv(figurespath/ 'num_dalys_summarized.csv') + +# Plot DALYS accrued (with xtickabels horizontal and wrapped) +name_of_plot = f'Total DALYs accrued, {target_period()}' +chosen_num_dalys_summarized = num_dalys_summarized[~num_dalys_summarized.index.isin(drop_scenarios)] +fig, ax = do_bar_plot_with_ci( + (chosen_num_dalys_summarized / 1e6).clip(lower=0.0), + annotations=[ + f"{round(row['median']/1e6, 1)} \n ({round(row['lower']/1e6, 1)}-{round(row['upper']/1e6, 1)})" + for _, row in chosen_num_dalys_summarized.clip(lower=0.0).iterrows() + ], + xticklabels_horizontal_and_wrapped=False, +) +ax.set_title(name_of_plot) +ax.set_ylim(0, 120) +ax.set_yticks(np.arange(0, 120, 10)) +ax.set_ylabel('Total DALYs accrued \n(Millions)') +fig.tight_layout() +fig.savefig(figurespath / name_of_plot.replace(' ', '_').replace(',', '')) +fig.show() +plt.close(fig) + +# 1.2 Total DALYs averted +#------------------------ +# Get absolute DALYs averted +num_dalys_averted = summarize( + -1.0 * + pd.DataFrame( + find_difference_relative_to_comparison( + num_dalys.loc[0], + comparison= 0) # sets the comparator to 0 which is the Actual scenario + ).T + ).iloc[0].unstack() +num_dalys_averted['scenario'] = scenarios.to_list()[1:12] +num_dalys_averted = num_dalys_averted.set_index('scenario') + +# Get percentage DALYs averted +pc_dalys_averted = 100.0 * summarize( + -1.0 * + pd.DataFrame( + find_difference_relative_to_comparison( + num_dalys.loc[0], + comparison= 0, # sets the comparator to 0 which is the Actual scenario + scaled=True) + ).T +).iloc[0].unstack() +pc_dalys_averted['scenario'] = scenarios.to_list()[1:12] +pc_dalys_averted = pc_dalys_averted.set_index('scenario') + +# %% Chart of number of DALYs averted +# Plot DALYS averted (with xtickabels horizontal and wrapped) +average_availability_under_scenarios = [0.59, 0.59, 0.6, 0.57, 0.63, 0.7, 0.79, 0.91, 1] +name_of_plot = f'Health impact of improved consumable availability\n at level 1 health facilities, {target_period()}' +chosen_num_dalys_averted = num_dalys_averted[~num_dalys_averted.index.isin(drop_scenarios)] +chosen_pc_dalys_averted = pc_dalys_averted[~pc_dalys_averted.index.isin(drop_scenarios)] +fig, (heatmap_ax, ax) = do_bar_plot_with_ci_and_heatmap( + (chosen_num_dalys_averted / 1e6), + annotations=[ + f"{round(row['median'], 1)} % \n ({round(row['lower'], 1)}- \n {round(row['upper'], 1)}) %" + for _, row in chosen_pc_dalys_averted.iterrows() + ], + xticklabels_horizontal_and_wrapped=False, + heatmap_values=average_availability_under_scenarios, + plt_title = name_of_plot +) +#ax.set_title(name_of_plot) +ax.set_ylim(0, 14) +ax.set_yticks(np.arange(0, 14, 2)) +ax.set_ylabel('Additional DALYS Averted \n(Millions)') +fig.tight_layout() +fig.savefig(figurespath / name_of_plot.replace(' ', '_').replace(',', '').replace('\n', '')) +fig.show() +plt.close(fig) + +# 1.2 DALYs by disease area/intervention - for comparison of the magnitude of impact created by consumables interventions +num_dalys_by_cause = extract_results( + results_folder, + module='tlo.methods.healthburden', + key='dalys_stacked', + custom_generate_series=get_num_dalys_by_cause, + do_scaling=True + ) +num_dalys_by_cause_summarized = summarize(num_dalys_by_cause).unstack(level = 0) +num_dalys_by_cause_summarized = num_dalys_by_cause_summarized.reset_index() +num_dalys_by_cause_summarized = num_dalys_by_cause_summarized.rename(columns = {'level_2':'cause', 0: 'DALYs_accrued'}) +num_dalys_by_cause_summarized = num_dalys_by_cause_summarized.pivot(index=['draw','cause'], columns='stat', values='DALYs_accrued') +num_dalys_by_cause_summarized.to_csv(figurespath / 'num_dalys_by_cause_summarized.csv') + +# Get top 10 causes until Actual +num_dalys_by_cause_actual = num_dalys_by_cause_summarized[num_dalys_by_cause_summarized.index.get_level_values(0) == 0] +num_dalys_by_cause_actual = num_dalys_by_cause_actual.sort_values('mean', ascending = False) +num_dalys_by_cause_actual =num_dalys_by_cause_actual[0:10] +top_10_causes_of_dalys = num_dalys_by_cause_actual.index.get_level_values(1).unique() + +# Get DALYs aveterted by cause and plot bar chats +for cause in top_10_causes_of_dalys: + num_dalys_by_cause_pivoted = num_dalys_by_cause[num_dalys_by_cause.index == cause].unstack().reset_index().drop(columns = ['level_2']).set_index(['draw', 'run']) + num_dalys_averted_by_cause = summarize( + -1.0 * + pd.DataFrame( + find_difference_relative_to_comparison( + num_dalys_by_cause_pivoted.squeeze(), + comparison= 0) # sets the comparator to 0 which is the Actual scenario + ).T + ).iloc[0].unstack() + num_dalys_averted_by_cause['scenario'] = scenarios.to_list()[1:12] + num_dalys_averted_by_cause = num_dalys_averted_by_cause.set_index('scenario') + + # Get percentage DALYs averted + pc_dalys_averted_by_cause = 100.0 * summarize( + -1.0 * + pd.DataFrame( + find_difference_relative_to_comparison( + num_dalys_by_cause_pivoted.squeeze(), + comparison= 0, # sets the comparator to 0 which is the Actual scenario + scaled=True) + ).T + ).iloc[0].unstack() + pc_dalys_averted_by_cause['scenario'] = scenarios.to_list()[1:12] + pc_dalys_averted_by_cause = pc_dalys_averted_by_cause.set_index('scenario') + + # Create a plot of DALYs averted by cause + chosen_num_dalys_averted_by_cause = num_dalys_averted_by_cause[~num_dalys_averted_by_cause.index.isin(drop_scenarios)] + chosen_pc_dalys_averted_by_cause = pc_dalys_averted_by_cause[~pc_dalys_averted_by_cause.index.isin(drop_scenarios)] + name_of_plot = f'Additional DALYs averted vs Actual by cause - \n ({cause}), {target_period()}' + fig, ax = do_bar_plot_with_ci( + (chosen_num_dalys_averted_by_cause / 1e6).clip(lower=0.0), + annotations=[ + f"{round(row['mean'], 1)} % \n ({round(row['lower'], 1)}-{round(row['upper'], 1)}) %" + for _, row in chosen_pc_dalys_averted_by_cause.clip(lower=0.0).iterrows() + ], + xticklabels_horizontal_and_wrapped=False, + ) + if chosen_num_dalys_averted_by_cause.upper.max()/1e6 > 2: + y_limit = 8.5 + y_tick_gaps = 1 + else: + y_limit = 2.5 + y_tick_gaps = 0.5 + ax.set_title(name_of_plot) + ax.set_ylim(0, y_limit) + ax.set_yticks(np.arange(0, y_limit, y_tick_gaps)) + ax.set_ylabel(f'Additional DALYs averted \n(Millions)') + fig.tight_layout() + fig.savefig(figurespath / name_of_plot.replace(' ', '_').replace(',', '').replace('/', '_').replace('\n', '')) + #fig.show() + plt.close(fig) + +''' +# PLot DALYs accrued by cause +for cause in top_10_causes_of_dalys: + name_of_plot = f'Total DALYs accrued by cause - \n {cause}, {target_period()}' + chosen_num_dalys_by_cause_summarized = num_dalys_by_cause_summarized[~num_dalys_by_cause_summarized.index.get_level_values(0).isin([4,5])] + chosen_num_dalys_by_cause_summarized = chosen_num_dalys_by_cause_summarized[chosen_num_dalys_by_cause_summarized.index.get_level_values(1) == cause] + fig, ax = do_bar_plot_with_ci( + (chosen_num_dalys_by_cause_summarized / 1e6).clip(lower=0.0), + annotations=[ + f"{round(row['mean'] / 1e6, 1)} \n ({round(row['lower'] / 1e6, 1)}-{round(row['upper'] / 1e6, 1)})" + for _, row in chosen_num_dalys_by_cause_summarized.clip(lower=0.0).iterrows() + ], + xticklabels_horizontal_and_wrapped=False, + ) + ax.set_title(name_of_plot) + if chosen_num_dalys_by_cause_summarized.upper.max()/1e6 > 5: + y_limit = 30 + y_tick_gap = 5 + else: + y_limit = 5 + y_tick_gap = 1 + ax.set_ylim(0, y_limit) + ax.set_yticks(np.arange(0, y_limit, y_tick_gap)) + ax.set_ylabel(f'Total DALYs accrued \n(Millions)') + fig.tight_layout() + fig.savefig(figurespath / name_of_plot.replace(' ', '_').replace(',', '').replace('/', '_').replace('\n', '')) + fig.show() + plt.close(fig) + +# TODO Fix xticklabels in the plots above +''' + +# 1.3 Total DALYs averted per person +#---------------------------------------- +num_dalys_per_person_year = extract_results_by_person_year( + results_folder, + module='tlo.methods.healthburden', + key='dalys_stacked', + custom_generate_series=get_num_dalys_per_person_year, + ) + +num_dalys_averted_per_person_year = summarize( + -1.0 * + pd.DataFrame( + find_difference_relative_to_comparison( + num_dalys_per_person_year.loc[0], + comparison= 0) # sets the comparator to 0 which is the Actual scenario + ).T + ).iloc[0].unstack() +num_dalys_averted_per_person_year['scenario'] = scenarios.to_list()[1:12] +num_dalys_averted_per_person_year = num_dalys_averted_per_person_year.set_index('scenario') + +# Get percentage DALYs averted +pct_dalys_averted_per_person_year = 100.0 * summarize( + -1.0 * + pd.DataFrame( + find_difference_relative_to_comparison( + num_dalys_per_person_year.loc[0], + comparison= 0, # sets the comparator to 0 which is the Actual scenario + scaled=True) + ).T +).iloc[0].unstack() +pct_dalys_averted_per_person_year['scenario'] = scenarios.to_list()[1:12] +pct_dalys_averted_per_person_year = pct_dalys_averted_per_person_year.set_index('scenario') + +# %% Chart of number of DALYs averted +# Plot DALYS averted (with xtickabels horizontal and wrapped) +name_of_plot = f'Additional DALYs Averted Per Person vs Actual, \n {target_period()}' +chosen_num_dalys_averted_per_person_year = num_dalys_averted_per_person_year[~num_dalys_averted_per_person_year.index.isin(drop_scenarios)] +chosen_pct_dalys_averted_per_person_year = pct_dalys_averted_per_person_year[~pct_dalys_averted_per_person_year.index.isin(drop_scenarios)] +fig, ax = do_bar_plot_with_ci( + (chosen_num_dalys_averted_per_person_year).clip(lower=0.0), + annotations=[ + f"{round(row['mean'], 1)} % \n ({round(row['lower'], 1)}- \n {round(row['upper'], 1)}) %" + for _, row in chosen_pct_dalys_averted_per_person_year.clip(lower=0.0).iterrows() + ], + xticklabels_horizontal_and_wrapped=False, +) +ax.set_title(name_of_plot) +ax.set_ylim(0, 1.5) +ax.set_yticks(np.arange(0, 1.5, 0.2)) +ax.set_ylabel('Additional DALYs averted per person') +fig.tight_layout() +fig.savefig(figurespath / name_of_plot.replace(' ', '_').replace(',', '').replace('\n', '')) +fig.show() +plt.close(fig) + +# 1.4 Total DALYs averted per person by cause +#------------------------------------------------- +for cause in top_10_causes_of_dalys: + num_dalys_per_person_year_by_cause = extract_results_by_person_year_by_cause( + results_folder, + module='tlo.methods.healthburden', + key='dalys_stacked', + custom_generate_series=get_num_dalys_per_person_year_by_cause, + cause = cause, + ) + + num_dalys_per_person_year_by_cause_pivoted = num_dalys_per_person_year_by_cause.unstack().reset_index().drop( + columns=['level_2']).set_index(['draw', 'run']) + num_dalys_averted_per_person_year_by_cause = summarize( + -1.0 * + pd.DataFrame( + find_difference_relative_to_comparison( + num_dalys_per_person_year_by_cause.squeeze(), + comparison=0) # sets the comparator to 0 which is the Actual scenario + ).T + ).iloc[0].unstack() + num_dalys_averted_per_person_year_by_cause['scenario'] = scenarios.to_list()[1:12] + num_dalys_averted_per_person_year_by_cause = num_dalys_averted_per_person_year_by_cause.set_index('scenario') + + # Get percentage DALYs averted + pct_dalys_averted_per_person_year_by_cause = 100.0 * summarize( + -1.0 * + pd.DataFrame( + find_difference_relative_to_comparison( + num_dalys_per_person_year_by_cause.squeeze(), + comparison=0, # sets the comparator to 0 which is the Actual scenario + scaled=True) + ).T + ).iloc[0].unstack() + pct_dalys_averted_per_person_year_by_cause['scenario'] = scenarios.to_list()[1:12] + pct_dalys_averted_per_person_year_by_cause = pct_dalys_averted_per_person_year_by_cause.set_index('scenario') + + # Create a plot of DALYs averted by cause + chosen_num_dalys_averted_per_person_year_by_cause = num_dalys_averted_per_person_year_by_cause[ + ~num_dalys_averted_per_person_year_by_cause.index.isin(drop_scenarios)] + chosen_pct_dalys_averted_per_person_year_by_cause = pct_dalys_averted_per_person_year_by_cause[~pct_dalys_averted_per_person_year_by_cause.index.isin(drop_scenarios)] + name_of_plot = f'Additional DALYs averted per person by cause - \n ({cause}), {target_period()}' + fig, ax = do_bar_plot_with_ci( + (chosen_num_dalys_averted_per_person_year_by_cause).clip(lower=0.0), + annotations=[ + f"{round(row['mean'], 1)} % \n ({round(row['lower'], 1)}-{round(row['upper'], 1)}) %" + for _, row in pct_dalys_averted_per_person_year_by_cause.clip(lower=0.0).iterrows() + ], + xticklabels_horizontal_and_wrapped=False, + ) + if chosen_num_dalys_averted_per_person_year_by_cause.upper.max() > 0.4: + y_limit = 0.55 + y_tick_gap = 0.1 + elif chosen_num_dalys_averted_per_person_year_by_cause.upper.max() > 0.18: + y_limit = 0.2 + y_tick_gap = 0.025 + else: + y_limit = 0.15 + y_tick_gap = 0.025 + ax.set_title(name_of_plot) + ax.set_ylim(0, y_limit) + ax.set_yticks(np.arange(0, y_limit, y_tick_gap)) + ax.set_ylabel(f'Additional DALYs averted per person') + fig.tight_layout() + fig.savefig(figurespath / name_of_plot.replace(' ', '_').replace(',', '').replace('/', '_').replace('\n', '')) + #fig.show() + plt.close(fig) + +# 2. Health work time spent v DALYs accrued +############################################# +# DALYs averted per person on the Y-axis; Capacity of cadre used at levels 1a, 1b, and 2 on the Y-axis +# log['tlo.methods.healthsystem.summary']['Capacity_By_OfficerType_And_FacilityLevel']['OfficerType=Pharmacy|FacilityLevel=2'] +def get_capacity_used_by_cadre_and_level(_df): + """Return total number of DALYS (Stacked) by label (total within the TARGET_PERIOD). + Throw error if not a record for every year in the TARGET PERIOD (to guard against inadvertently using + results from runs that crashed mid-way through the simulation. + """ + years_needed = [i.year for i in TARGET_PERIOD] + _df['year'] = _df.date.dt.year + #assert set(_df.year.unique()).issuperset(years_needed), "Some years are not recorded." + string_for_cols_to_drop1 = 'FacilityLevel=0|FacilityLevel=3|FacilityLevel=4|FacilityLevel=5' + string_for_cols_to_drop2 = 'OfficerType=DCSA|OfficerType=Dental|OfficerType=Laboratory|OfficerType=Mental|OfficerType=Nutrition|OfficerType=Radiography' + cols_to_drop1 = _df.columns[_df.columns.str.contains(string_for_cols_to_drop1)] + cols_to_drop2 = _df.columns[_df.columns.str.contains(string_for_cols_to_drop2)] + cols_to_drop = [*cols_to_drop1, *cols_to_drop2, 'year'] + return pd.Series( + data=_df + .loc[_df.year.between(*years_needed)] + .drop(columns= cols_to_drop) + .mean() + ) + +capacity_used = summarize(extract_results( + results_folder, + module='tlo.methods.healthsystem.summary', + key='Capacity_By_OfficerType_And_FacilityLevel', + custom_generate_series=get_capacity_used_by_cadre_and_level, + do_scaling = False, + )) + +#chosen_capacity_used.unstack().reset_index().drop(columns = ['level_2']).pivot(columns ='stat', index = 'draw') +for cadre_level in capacity_used.index: + print(cadre_level) + name_of_plot = f'Capacity used - \n {cadre_level}, {target_period()}' + scenarios_to_drop = capacity_used.columns[capacity_used.columns.get_level_values(0).isin([10])] + chosen_capacity_used = capacity_used.drop(columns = scenarios_to_drop) + chosen_capacity_used = chosen_capacity_used[chosen_capacity_used.index == cadre_level] + chosen_capacity_used = chosen_capacity_used.unstack().reset_index().drop(columns = ['level_2']).pivot(columns ='stat', index = 'draw').droplevel(0,axis = 1) + chosen_capacity_used['scenario'] = [*scenarios.to_list()[0:10], scenarios.to_list()[11]] # [*scenarios.to_list()[0:4],*scenarios.to_list()[6:10]] + #TODO fix above code to be automated + chosen_capacity_used = chosen_capacity_used.set_index('scenario') + fig, ax = do_bar_plot_with_ci( + (chosen_capacity_used), + annotations=[ + f"{round(row['mean'], 2)} \n ({round(row['lower'], 2)}-{round(row['upper'], 2)})" + for _, row in chosen_capacity_used.iterrows() + ], + xticklabels_horizontal_and_wrapped=False, + ) + ax.set_title(name_of_plot) + if chosen_capacity_used.upper.max() > 3: + y_limit = 3.5 + y_tick_gap = 0.5 + else: + y_limit = 2 + y_tick_gap = 0.25 + ax.set_ylim(0, y_limit) + ax.set_yticks(np.arange(0, y_limit, y_tick_gap)) + ax.set_ylabel(f'Capacity used \n (Proportion of capacity available)') + fig.tight_layout() + fig.savefig(figurespath / name_of_plot.replace(' ', '_').replace(',', '').replace('/', '_').replace('\n', '_')) + fig.show() + plt.close(fig) + + +# %% Summarizing input resourcefile data + +# 1. Consumable availability by category and level +#-------------------------------------------------- +tlo_availability_df = pd.read_csv(resourcefilepath / 'healthsystem'/ 'consumables' / "ResourceFile_Consumables_availability_small.csv") + +# Attach district, facility level, program to this dataset +mfl = pd.read_csv(resourcefilepath / "healthsystem" / "organisation" / "ResourceFile_Master_Facilities_List.csv") +districts = set(pd.read_csv(resourcefilepath / 'demography' / 'ResourceFile_Population_2010.csv')['District']) +fac_levels = {'0', '1a', '1b', '2', '3', '4'} +tlo_availability_df = tlo_availability_df.merge(mfl[['District', 'Facility_Level', 'Facility_ID']], + on = ['Facility_ID'], how='left') +# Attach programs +program_item_mapping = pd.read_csv(resourcefilepath / 'healthsystem'/ 'consumables' / 'ResourceFile_Consumables_Item_Designations.csv')[['Item_Code', 'item_category']] +program_item_mapping = program_item_mapping.rename(columns ={'Item_Code': 'item_code'})[program_item_mapping.item_category.notna()] +tlo_availability_df = tlo_availability_df.merge(program_item_mapping,on = ['item_code'], how='left') + +# First a heatmap of current availability +fac_levels = {'0': 'Health Post', '1a': 'Health Centers', '1b': 'Rural/Community \n Hospitals', '2': 'District Hospitals', '3': 'Central Hospitals', '4': 'Mental Hospital'} +chosen_fac_levels_for_plot = ['0', '1a', '1b', '2', '3', '4'] +correct_order_of_levels = ['Health Post', 'Health Centers', 'Rural/Community \n Hospitals', 'District Hospitals', 'Central Hospitals','Mental Hospital'] +df_for_plots = tlo_availability_df[tlo_availability_df.Facility_Level.isin(chosen_fac_levels_for_plot)] +df_for_plots['Facility_Level'] = df_for_plots['Facility_Level'].map(fac_levels) + +scenario_list = [1,2,3,6,7,8,10,11] +chosen_availability_columns = ['available_prop'] + [f'available_prop_scenario{i}' for i in + scenario_list] +scenario_names_dict = {'available_prop': 'Actual', 'available_prop_scenario1': 'General consumables', 'available_prop_scenario2': 'Vital medicines', + 'available_prop_scenario3': 'Pharmacist- managed', 'available_prop_scenario4': 'Level 1b', 'available_prop_scenario5': 'CHAM', + 'available_prop_scenario6': '75th percentile facility', 'available_prop_scenario7': '90th percentile facility', 'available_prop_scenario8': 'Best facility', + 'available_prop_scenario9': 'Best facility (including DHO)','available_prop_scenario10': 'HIV supply chain', 'available_prop_scenario11': 'EPI supply chain', + 'available_prop_scenario12': 'HIV moved to Govt supply chain'} +# recreate the chosen columns list based on the mapping above +chosen_availability_columns = [scenario_names_dict[col] for col in chosen_availability_columns] +df_for_plots = df_for_plots.rename(columns = scenario_names_dict) + +i = 0 +for avail_scenario in chosen_availability_columns: + # Generate a heatmap + # Pivot the DataFrame + aggregated_df = df_for_plots.groupby(['item_category', 'Facility_Level'])[avail_scenario].mean().reset_index() + heatmap_data = aggregated_df.pivot("item_category", "Facility_Level", avail_scenario) + heatmap_data = heatmap_data[correct_order_of_levels] # Maintain the order + + # Calculate the aggregate row and column + aggregate_col= aggregated_df.groupby('Facility_Level')[avail_scenario].mean() + aggregate_col = aggregate_col[correct_order_of_levels] + aggregate_row = aggregated_df.groupby('item_category')[avail_scenario].mean() + overall_aggregate = df_for_plots[avail_scenario].mean() + + # Add aggregate row and column + heatmap_data['Average'] = aggregate_row + aggregate_col['Average'] = overall_aggregate + heatmap_data.loc['Average'] = aggregate_col + + # Generate the heatmap + sns.set(font_scale=1.5) + plt.figure(figsize=(10, 8)) + sns.heatmap(heatmap_data, annot=True, cmap='RdYlGn', cbar_kws={'label': 'Proportion of days on which consumable is available'}) + + # Customize the plot + plt.title(scenarios[i]) + plt.xlabel('Facility Level') + plt.ylabel(f'Disease/Public health \n program') + plt.xticks(rotation=90) + plt.yticks(rotation=0) + + plt.savefig(figurespath /f'consumable_availability_heatmap_{avail_scenario}.png', dpi=300, bbox_inches='tight') + #plt.show() + plt.close() + i = i + 1 + +# TODO Justify the focus on levels 1a and 1b - where do HSIs occur?; at what level is there most misallocation within districts +# TODO get graphs of percentage of successful HSIs under different scenarios for levels 1a and 1b +# TODO is there a way to link consumables directly to DALYs (how many DALYs are lost due to stockouts of specific consumables) +# TODO why are there no appointments at level 1b + +# 2. Consumable demand not met +#----------------------------------------- +# Number of units of item which were needed but not made available for the top 25 items +# TODO ideally this should count the number of treatment IDs but this needs the detailed health system logger +def consumables_availability_figure(results_folder: Path, output_folder: Path, resourcefilepath: Path): + """ 'Figure 3': Usage of consumables in the HealthSystem""" + make_graph_file_name = lambda stub: output_folder / f"Fig3_consumables_availability_figure.png" # noqa: E731 + + def get_counts_of_items_requested(_df): + _df = drop_outside_period(_df) + + counts_of_available = defaultdict(int) + counts_of_not_available = defaultdict(int) + + for _, row in _df.iterrows(): + for item, num in row['Item_Available'].items(): + counts_of_available[item] += num + for item, num in row['Item_NotAvailable'].items(): # eval(row['Item_NotAvailable']) + counts_of_not_available[item] += num + + return pd.concat( + {'Available': pd.Series(counts_of_available), 'Not_Available': pd.Series(counts_of_not_available)}, + axis=1 + ).fillna(0).astype(int).stack() + + cons_req = summarize( + extract_results( + results_folder, + module='tlo.methods.healthsystem.summary', + key='Consumables', + custom_generate_series=get_counts_of_items_requested, + do_scaling=True + ), + only_mean=True, + collapse_columns=True + ) + + cons = cons_req.unstack() + cons_names = pd.read_csv( + resourcefilepath / 'healthsystem' / 'consumables' / 'ResourceFile_Consumables_Items_and_Packages.csv' + )[['Item_Code', 'Items']].set_index('Item_Code').drop_duplicates() + cons_names.index = cons_names.index.astype(str) + cons = cons.merge(cons_names, left_index=True, right_index=True, how='left').set_index('Items') #.astype(int) + cons = cons.assign(total=cons.sum(1)).sort_values('total').drop(columns='total') + + cons.columns = pd.MultiIndex.from_tuples(cons.columns, names=['draw', 'stat', 'var']) + cons_not_available = cons.loc[:, cons.columns.get_level_values(2) == 'Not_Available'] + cons_not_available.mean = cons_not_available.loc[:, cons_not_available.columns.get_level_values(1) == 'mean'] + cons_available = cons.loc[:, cons.columns.get_level_values(2) == 'Available'] + + cons_not_available = cons_not_available.unstack().reset_index() + cons_not_available = cons_not_available.rename(columns={0: 'qty_not_available'}) + +consumables_availability_figure(results_folder, outputspath, resourcefilepath) + +# TODO use squarify_plot to represent which consumables are most used in the system (by short Treatment_ID?) (not quantity but frequency) + +# HSI affected by missing consumables +# We need healthsystem logger for this + +# 3. Number of Health System Interactions +#----------------------------------------- +# HSIs taking place by level in the default scenario +def get_counts_of_hsis(_df): + _df = drop_outside_period(_df) + + # Initialize an empty dictionary to store the total counts + total_hsi_count = {} + + for date, appointment_dict in _df['Number_By_Appt_Type_Code_And_Level'].items(): + print(appointment_dict) + for level, appointments_at_level in appointment_dict.items(): + print(level, appointments_at_level) + total_hsi_count[level] = {} + for appointment_type, count in appointments_at_level.items(): + print(appointment_type, count) + if appointment_type in total_hsi_count: + total_hsi_count[level][appointment_type] += count + else: + total_hsi_count[level][appointment_type] = count + + total_hsi_count_series = pd.Series(total_hsi_count) + for level in ['0', '1a', '1b', '2', '3', '4']: + appointments_at_level = pd.Series(total_hsi_count_series[total_hsi_count_series.index == level].values[0], dtype='int') + # Create a list of tuples with the original index and the new level '1a' + new_index_tuples = [(idx, level) for idx in appointments_at_level.index] + # Create the new MultiIndex + new_index = pd.MultiIndex.from_tuples(new_index_tuples, names=['Appointment', 'Level']) + # Reindex the Series with the new MultiIndex + appointments_at_level_multiindex = appointments_at_level.copy() + appointments_at_level_multiindex.index = new_index + if level == '0': + appointments_all_levels = appointments_at_level_multiindex + else: + appointments_all_levels = pd.concat([appointments_all_levels, appointments_at_level_multiindex], axis = 0) + + return pd.Series(appointments_all_levels).fillna(0).astype(int) + +hsi_count = summarize( + extract_results( + results_folder, + module='tlo.methods.healthsystem.summary', + key='HSI_Event', + custom_generate_series=get_counts_of_hsis, + do_scaling=True + ), + only_mean=True, + collapse_columns=True +) + +hsi = hsi_count.assign(baseline_values=hsi_count[(0, 'mean')]).sort_values('baseline_values').drop(columns='baseline_values') +hsi.columns = pd.MultiIndex.from_tuples(hsi.columns, names=['draw', 'stat']) +#hsi = hsi.unstack().reset_index() +hsi_stacked = hsi.stack().stack().reset_index() +hsi_stacked = hsi_stacked.rename(columns={0: 'hsis_requested'}) + + +# 4.1 Number of Services delivered by long Treatment_ID +#------------------------------------------------------ +def get_counts_of_hsi_by_treatment_id(_df): + """Get the counts of the short TREATMENT_IDs occurring""" + _counts_by_treatment_id = _df \ + .loc[pd.to_datetime(_df['date']).between(*TARGET_PERIOD), 'TREATMENT_ID'] \ + .apply(pd.Series) \ + .sum() \ + .astype(int) + return _counts_by_treatment_id.groupby(level=0).sum() + +counts_of_hsi_by_treatment_id = summarize( + extract_results( + results_folder, + module='tlo.methods.healthsystem.summary', + key='HSI_Event', + custom_generate_series=get_counts_of_hsi_by_treatment_id, + do_scaling=True + ), + only_mean=True, + collapse_columns=True, +) + +counts_of_hsi_by_treatment_id = counts_of_hsi_by_treatment_id.assign(baseline_values=counts_of_hsi_by_treatment_id[(0, 'mean')]).sort_values('baseline_values').drop(columns='baseline_values') +hsi_by_treatment_id = counts_of_hsi_by_treatment_id.unstack().reset_index() +hsi_by_treatment_id = hsi_by_treatment_id.rename(columns={'level_2': 'Treatment_ID', 0: 'qty_of_HSIs'}) + +# hsi[(0,'mean')].sum()/counts_of_hsi_by_treatment_id[(0,'mean')].sum() + +# 4.2 Number of Services delivered by short Treatment ID +#-------------------------------------------------------- +def get_counts_of_hsi_by_short_treatment_id(_df): + """Get the counts of the short TREATMENT_IDs occurring (shortened, up to first underscore)""" + _counts_by_treatment_id = get_counts_of_hsi_by_treatment_id(_df) + _short_treatment_id = _counts_by_treatment_id.index.map(lambda x: x.split('_')[0] + "*") + return _counts_by_treatment_id.groupby(by=_short_treatment_id).sum() + + +counts_of_hsi_by_treatment_id_short = summarize( + extract_results( + results_folder, + module='tlo.methods.healthsystem.summary', + key='HSI_Event', + custom_generate_series=get_counts_of_hsi_by_short_treatment_id, + do_scaling=True + ), + only_mean=True, + collapse_columns=True, +) + +hsi_by_short_treatment_id = counts_of_hsi_by_treatment_id_short.unstack().reset_index() +hsi_by_short_treatment_id = hsi_by_short_treatment_id.rename(columns = {'level_2': 'Short_Treatment_ID', 0: 'qty_of_HSIs'}) + +# Cost of consumables? diff --git a/src/scripts/costing/cost_estimation.py b/src/scripts/costing/cost_estimation.py new file mode 100644 index 0000000000..fa6cfd4669 --- /dev/null +++ b/src/scripts/costing/cost_estimation.py @@ -0,0 +1,1902 @@ +from pathlib import Path + +from tlo import Date +from collections import defaultdict +from typing import Optional, Union, Literal + +import datetime +import textwrap + +import matplotlib.pyplot as plt +import squarify +import numpy as np +import pandas as pd +import ast +import math +import itertools +from itertools import cycle +import matplotlib.container as mpc + +from tlo.analysis.utils import ( + extract_results, + get_scenario_info, + load_pickled_dataframes, + unflatten_flattened_multi_index_in_logging +) + +# Define a timestamp for script outputs +timestamp = datetime.datetime.now().strftime("_%Y_%m_%d_%H_%M") + +# Print the start time of the script +print('Script Start', datetime.datetime.now().strftime('%H:%M')) + +#%% + +# Define a function to discount and summarise costs by cost_category + +def apply_discounting_to_cost_data(_df: pd.DataFrame, + _discount_rate: Union[float, dict[int, float]] = 0, + _initial_year: Optional[int] = None, + _column_for_discounting: str = 'cost') -> pd.DataFrame: + """ + Apply discounting to the specified column over time, using a fixed or year-specific rate. + + Parameters: + ---------- + _df : pd.DataFrame + DataFrame containing a 'year' column and a cost column to be discounted. + + _discount_rate : float or dict of {year: float}, default 0 + Discount rate to apply. Can be: + - A single fixed rate (e.g., 0.03 for 3%) + - A dictionary of year-specific rates {2025: 0.03, 2026: 0.035, ...} + + _initial_year : int, optional + Reference year for discounting. If None, uses the earliest year in the DataFrame. + + _column_for_discounting : str, default 'cost' + Name of the column to apply discounting to. + + Returns: + ------- + pd.DataFrame + A copy of the input DataFrame with the specified column discounted in-place. + """ + + if _initial_year is None: + # Determine the initial year from the dataframe + _initial_year = min(_df['year'].unique()) + + def get_discount_factor(year): + """Compute the cumulative discount factor for a given year.""" + if isinstance(_discount_rate, dict): + # Compute the cumulative discount factor as the product of (1 + discount_rate) for all previous years + discount_factor = 1 + for y in range(_initial_year + 1, year + 1): # only starting from initial year + 1 as the discount factor for initial year should be 1 + discount_factor *= (1 + _discount_rate.get(y, 0)) # Default to 0 if year not in dictionary + return discount_factor + else: + # If a single value is provided, use standard discounting + return (1 + _discount_rate) ** (year - _initial_year) + + # Apply discounting to each row + _df.loc[:, _column_for_discounting] = _df[_column_for_discounting] / _df['year'].apply(get_discount_factor) + + return _df + +def estimate_input_cost_of_scenarios(results_folder: Path, + resourcefilepath: Path , + _draws: Optional[list[int]] = None, + _runs: Optional[list[int]] = None, + summarize: bool = False, + _metric: Literal['mean', 'median'] = 'mean', + _years: Optional[list[int]] = None, + cost_only_used_staff: bool = True, + _discount_rate: Union[float, dict[int, float]] = 0) -> pd.DataFrame: + """ + Estimate health system input costs for a given simulation. + + Parameters: + ---------- + results_folder : Path + Path to the directory containing simulation output files. + resourcefilepath : Path, optional + Path to the resource files + _draws : list, optional + Specific draws to include in the cost estimation. Defaults to all available draws. + _runs : list, optional + Specific runs to include in the cost estimation. Defaults to all runs. + summarize : bool, default False + Whether to summarize the costs across draws/runs with central metric (specified below) and confidence intervals. + _metric : {'mean', 'median'}, default 'mean' + Summary statistic to use if `summarize=True`. + _years : list of int, optional + Years to include in the cost output. If None, all years are included. + cost_only_used_staff : bool, default True + If True, only costs for level-cadre combinations ever used in simulation are included. + _discount_rate : float or dict of {int: float}, default 0 + Discount rate to apply to future costs. Can be a constant or year-specific dictionary. + + Returns: + ------- + pd.DataFrame + A dataframe containing discounted costs disaggregated by category, sub-category, category-specific subgroup, year, draw, and run. + Note that if a discount rate is used, the dataframe will provide cost as the NPV during the first year of the dataframe + """ + + # Useful common functions + def drop_outside_period(_df): + """Return a dataframe which only includes for which the date is within the limits defined by TARGET_PERIOD""" + return _df.drop(index=_df.index[~_df['date'].between(*TARGET_PERIOD)]) + + def melt_model_output_draws_and_runs(_df, id_vars): + multi_index = pd.MultiIndex.from_tuples(_df.columns) + _df.columns = multi_index + melted_df = pd.melt(_df, id_vars=id_vars).rename(columns={'variable_0': 'draw', 'variable_1': 'run'}) + return melted_df + + # Define a relative pathway for relavant folders + path_for_consumable_resourcefiles = resourcefilepath / "healthsystem/consumables" + + # %% Gathering basic information + # Load basic simulation parameters + #------------------------------------- + log = load_pickled_dataframes(results_folder, 0, 0) # read from 1 draw and run + info = get_scenario_info(results_folder) # get basic information about the results + if _draws is None: + _draws = range(0, info['number_of_draws']) + if _runs is None: + _runs = range(0, info['runs_per_draw']) + final_year_of_simulation = max(log['tlo.methods.healthsystem.summary']['hsi_event_counts']['date']).year + first_year_of_simulation = min(log['tlo.methods.healthsystem.summary']['hsi_event_counts']['date']).year + years = list(range(first_year_of_simulation, final_year_of_simulation + 1)) # this is the full period of the simulation but at the end of the function, years not needed for the final cost estimate are dropped + + # Load cost input files + #------------------------ + # Load primary costing resourcefile + workbook_cost = pd.read_excel((resourcefilepath / "costing/ResourceFile_Costing.xlsx"), + sheet_name = None) + + # Extract districts and facility levels from the Master Facility List + mfl = pd.read_csv(resourcefilepath / "healthsystem" / "organisation" / "ResourceFile_Master_Facilities_List.csv") + district_dict = pd.read_csv(resourcefilepath / 'demography' / 'ResourceFile_Population_2010.csv')[['District_Num', 'District']].drop_duplicates() + district_dict = dict(zip(district_dict['District_Num'], district_dict['District'])) + facility_id_levels_dict = dict(zip(mfl['Facility_ID'], mfl['Facility_Level'])) + fac_levels = set(mfl.Facility_Level) + + # Overall cost assumptions + TARGET_PERIOD = (Date(first_year_of_simulation, 1, 1), Date(final_year_of_simulation, 12, 31)) # Declare period for which the results will be generated (defined inclusively) + + # If variable discount rate is provided, use the average across the relevant years for the purpose of annuitization of HR and equipment costs + def calculate_annuitization_rate(_discount_rate, _years): + if isinstance(_discount_rate, (int, float)): + # Single discount rate, return as is + return _discount_rate + elif isinstance(_discount_rate, dict): + # Extract rates for the specified years (default to 0 if year is missing) + rates = [_discount_rate.get(year, 0) for year in _years] + return sum(rates) / len(rates) # Average discount rate + else: + raise ValueError("`_discount_rate` must be either a number (single rate) or a dictionary {year: rate}.") + + annuitization_rate = calculate_annuitization_rate(_discount_rate, _years) + + # Read all cost parameters + #--------------------------------------- + # Read parameters for HR costs + hr_cost_parameters = workbook_cost["human_resources"] + hr_cost_parameters['Facility_Level'] = hr_cost_parameters['Facility_Level'].astype(str) # Store Facility_Level as string + + # Read parameters for consumables costs + # Load consumables cost data + unit_price_consumable = workbook_cost["consumables"] + unit_price_consumable = unit_price_consumable.rename(columns=unit_price_consumable.iloc[0]) + unit_price_consumable = unit_price_consumable[['Item_Code', 'Final_price_per_chosen_unit (USD, 2023)']].reset_index(drop=True).iloc[1:] + unit_price_consumable = unit_price_consumable[unit_price_consumable['Item_Code'].notna()] + + # Load and prepare equipment cost parameters + # Unit costs of equipment + unit_cost_equipment = workbook_cost["equipment"] + unit_cost_equipment = unit_cost_equipment.rename(columns=unit_cost_equipment.iloc[7]).reset_index(drop=True).iloc[8:] + unit_cost_equipment = unit_cost_equipment[unit_cost_equipment['Item_code'].notna()] # drop empty row + # Calculate necessary costs based on HSSP-III assumptions + if _discount_rate == 0: + unit_cost_equipment['replacement_cost_annual'] = unit_cost_equipment.apply(lambda row: row['unit_purchase_cost'] / row['Life span'], axis=1) # straight line depreciation is discount rate is 0 + else: + unit_cost_equipment['replacement_cost_annual'] = unit_cost_equipment.apply(lambda row: row['unit_purchase_cost']/(1+(1-(1+annuitization_rate)**(-row['Life span']+1))/annuitization_rate), axis=1) # Annuitised over the life span of the equipment assuming outlay at the beginning of the year + unit_cost_equipment['service_fee_annual'] = unit_cost_equipment.apply(lambda row: row['unit_purchase_cost'] * 0.8 / 8 if row['unit_purchase_cost'] > 1000 else 0, axis=1) # 80% of the value of the item over 8 years + unit_cost_equipment['spare_parts_annual'] = unit_cost_equipment.apply(lambda row: row['unit_purchase_cost'] * 0.2 / 8 if row['unit_purchase_cost'] > 1000 else 0, axis=1) # 20% of the value of the item over 8 years + unit_cost_equipment['major_corrective_maintenance_cost_annual'] = unit_cost_equipment.apply(lambda row: row['unit_purchase_cost'] * 0.2 * 0.2 / 8 if row['unit_purchase_cost'] < 250000 else 0, axis=1) # 20% of the value of 20% of the items over 8 years + # TODO consider discounting the other components + # Quantity needed for each equipment by facility + unit_cost_equipment = unit_cost_equipment[['Item_code','Equipment_tlo', + 'replacement_cost_annual', 'service_fee_annual', 'spare_parts_annual', 'major_corrective_maintenance_cost_annual', + 'Health Post_prioritised', 'Community_prioritised', 'Health Center_prioritised', 'District_prioritised', 'Central_prioritised']] + unit_cost_equipment = unit_cost_equipment.rename(columns={col: 'Quantity_' + col.replace('_prioritised', '') for col in unit_cost_equipment.columns if col.endswith('_prioritised')}) + unit_cost_equipment = unit_cost_equipment.rename(columns={col: col.replace(' ', '_') for col in unit_cost_equipment.columns}) + + unit_cost_equipment = pd.wide_to_long(unit_cost_equipment, stubnames=['Quantity_'], + i=['Item_code', 'Equipment_tlo', 'replacement_cost_annual', 'service_fee_annual', 'spare_parts_annual', 'major_corrective_maintenance_cost_annual'], + j='Facility_Level', suffix='(\d+|\w+)').reset_index() + facility_level_mapping = {'Health_Post': '0', 'Health_Center': '1a', 'Community': '1b', 'District': '2', 'Central': '3'} + unit_cost_equipment['Facility_Level'] = unit_cost_equipment['Facility_Level'].replace(facility_level_mapping) + unit_cost_equipment = unit_cost_equipment.rename(columns = {'Quantity_': 'Quantity'}) + + # Load and prepare facility operation cost parameters + unit_cost_fac_operations = workbook_cost["facility_operations"] + + # Function to prepare cost dataframe ready to be merged across cross categories + def retain_relevant_column_subset(_df, _category_specific_group): + columns_to_retain = ['draw', 'run', 'year', 'cost_subcategory', 'Facility_Level', _category_specific_group, 'cost'] + if 'cost_category' in _df.columns: + columns_to_retain.append('cost_category') + _df = _df[columns_to_retain] + return _df + def prepare_cost_dataframe(_df, _category_specific_group, _cost_category): + _df = _df.rename(columns = {_category_specific_group: 'cost_subgroup'}) + _df['cost_category'] = _cost_category + return retain_relevant_column_subset(_df, 'cost_subgroup') + + + # CALCULATE ECONOMIC COSTS + #%% + # 1. HR cost + #------------------------ + print("Now estimating HR costs...") + # Define a function to merge unit cost data with model outputs + def merge_cost_and_model_data(cost_df, model_df, varnames): + merged_df = model_df.copy() + for varname in varnames: + new_cost_df = cost_df[cost_df['Parameter_name'] == varname][['OfficerType', 'Facility_Level', 'Value']] + new_cost_df = new_cost_df.rename(columns={"Value": varname}) + if ((new_cost_df['OfficerType'] == 'All').all()) and ((new_cost_df['Facility_Level'] == 'All').all()): + merged_df[varname] = new_cost_df[varname].mean() + elif ((new_cost_df['OfficerType'] == 'All').all()) and ((new_cost_df['Facility_Level'] == 'All').all() == False): + merged_df = pd.merge(merged_df, new_cost_df[['Facility_Level',varname]], on=['Facility_Level'], how="left") + elif ((new_cost_df['OfficerType'] == 'All').all() == False) and ((new_cost_df['Facility_Level'] == 'All').all()): + merged_df = pd.merge(merged_df, new_cost_df[['OfficerType',varname]], on=['OfficerType'], how="left") + else: + merged_df = pd.merge(merged_df, new_cost_df, on=['OfficerType', 'Facility_Level'], how="left") + return merged_df + + # Get available staff count for each year and draw + def get_staff_count_by_facid_and_officer_type(_df: pd.Series) -> pd.Series: + """Summarise the parsed logged-key results for one draw (as dataframe) into a pd.Series.""" + _df = _df.set_axis(_df['date'].dt.year).drop(columns=['date']) + _df.index.name = 'year' + + def change_to_standard_flattened_index_format(col): + parts = col.split("_", 3) # Split by "_" only up to 3 parts + if len(parts) > 2: + return parts[0] + "=" + parts[1] + "|" + parts[2] + "=" + parts[3] # Rejoin with "I" at the second occurrence + return col # If there's no second underscore, return the string as it is + _df.columns = [change_to_standard_flattened_index_format(col) for col in _df.columns] + + return unflatten_flattened_multi_index_in_logging(_df).stack(level=[0, 1]) # expanded flattened axis + + # Staff count by Facility ID + available_staff_count_by_facid_and_officertype = extract_results( + Path(results_folder), + module='tlo.methods.healthsystem.summary', + key='number_of_hcw_staff', + custom_generate_series=get_staff_count_by_facid_and_officer_type, + do_scaling=True, + ) + + # Update above series to get staff count by Facility_Level + available_staff_count_by_facid_and_officertype = available_staff_count_by_facid_and_officertype.reset_index().rename(columns= {'FacilityID': 'Facility_ID', 'Officer': 'OfficerType'}) + available_staff_count_by_facid_and_officertype['Facility_ID'] = pd.to_numeric(available_staff_count_by_facid_and_officertype['Facility_ID']) + available_staff_count_by_facid_and_officertype['Facility_Level'] = available_staff_count_by_facid_and_officertype['Facility_ID'].map(facility_id_levels_dict) + idx = pd.IndexSlice + available_staff_count_by_level_and_officer_type = available_staff_count_by_facid_and_officertype.drop(columns = [idx['Facility_ID']]).groupby([idx['year'], idx['Facility_Level'], idx['OfficerType']]).sum() + available_staff_count_by_level_and_officer_type = melt_model_output_draws_and_runs(available_staff_count_by_level_and_officer_type.reset_index(), id_vars= ['year', 'Facility_Level', 'OfficerType']) + available_staff_count_by_level_and_officer_type['Facility_Level'] = available_staff_count_by_level_and_officer_type['Facility_Level'].astype(str) # make sure facility level is stored as string + available_staff_count_by_level_and_officer_type = available_staff_count_by_level_and_officer_type.drop(available_staff_count_by_level_and_officer_type[available_staff_count_by_level_and_officer_type['Facility_Level'] == '5'].index) # drop headquarters because we're only concerned with staff engaged in service delivery + available_staff_count_by_level_and_officer_type.rename(columns ={'value': 'staff_count'}, inplace=True) + + # Get list of cadres which were utilised in each run to get the count of staff used in the simulation + # Note that we still cost the full staff count for any cadre-Facility_Level combination that was ever used in a run, and + # not the amount of time which was used + def get_capacity_used_by_officer_type_and_facility_level(_df: pd.Series) -> pd.Series: + """Summarise the parsed logged-key results for one draw (as dataframe) into a pd.Series.""" + _df = _df.set_axis(_df['date'].dt.year).drop(columns=['date']) + _df.index.name = 'year' + return unflatten_flattened_multi_index_in_logging(_df).stack(level=[0, 1]) # expanded flattened axis + + annual_capacity_used_by_cadre_and_level = extract_results( + Path(results_folder), + module='tlo.methods.healthsystem.summary', + key='Capacity_By_OfficerType_And_FacilityLevel', + custom_generate_series=get_capacity_used_by_officer_type_and_facility_level, + do_scaling=False, + ) + + # Prepare capacity used dataframe to be multiplied by staff count + average_capacity_used_by_cadre_and_level = annual_capacity_used_by_cadre_and_level.groupby(['OfficerType', 'FacilityLevel']).mean().reset_index(drop=False) + # TODO see if cadre-level combinations should be chosen by year + average_capacity_used_by_cadre_and_level.reset_index(drop=True) # Flatten multi=index column + average_capacity_used_by_cadre_and_level = average_capacity_used_by_cadre_and_level.melt(id_vars=['OfficerType', 'FacilityLevel'], + var_name=['draw', 'run'], + value_name='capacity_used') + list_of_cadre_and_level_combinations_used = average_capacity_used_by_cadre_and_level[average_capacity_used_by_cadre_and_level['capacity_used'] != 0][['OfficerType', 'FacilityLevel', 'draw', 'run']] + print(f"Out of {average_capacity_used_by_cadre_and_level.groupby(['OfficerType', 'FacilityLevel']).size().count()} cadre and level combinations available, {list_of_cadre_and_level_combinations_used.groupby(['OfficerType', 'FacilityLevel']).size().count()} are used across the simulations") + list_of_cadre_and_level_combinations_used = list_of_cadre_and_level_combinations_used.rename(columns = {'FacilityLevel':'Facility_Level'}) + + # Subset scenario staffing level to only include cadre-level combinations used in the simulation + used_staff_count_by_level_and_officer_type = available_staff_count_by_level_and_officer_type.merge(list_of_cadre_and_level_combinations_used, on = ['draw','run','OfficerType', 'Facility_Level'], how = 'right', validate = 'm:m') + used_staff_count_by_level_and_officer_type.rename(columns ={'value': 'staff_count'}, inplace=True) + + if (cost_only_used_staff): + print("The input for 'cost_only_used_staff' implies that only cadre-level combinations which have been used in the run are costed") + staff_size_chosen_for_costing = used_staff_count_by_level_and_officer_type + else: + print("The input for 'cost_only_used_staff' implies that all staff are costed regardless of the cadre-level combinations which have been used in the run are costed") + staff_size_chosen_for_costing = available_staff_count_by_level_and_officer_type + + # Calculate various components of HR cost + # 1.1 Salary cost for health workforce cadres used in the simulation (Staff count X Annual salary) + #--------------------------------------------------------------------------------------------------------------- + salary_for_staff = merge_cost_and_model_data(cost_df = hr_cost_parameters, model_df = staff_size_chosen_for_costing, + varnames = ['salary_usd']) + salary_for_staff['cost'] = salary_for_staff['salary_usd'] * salary_for_staff['staff_count'] + + # 1.2 Pre-service training & recruitment cost to fill gap created by attrition + #--------------------------------------------------------------------------------------------------------------- + preservice_training_cost = merge_cost_and_model_data(cost_df = hr_cost_parameters, model_df = staff_size_chosen_for_costing, + varnames = ['annual_attrition_rate', + 'licensure_exam_passing_rate', 'graduation_rate', + 'absorption_rate_of_students_into_public_workforce', 'proportion_of_workforce_recruited_from_abroad', + 'average_annual_preservice_training_cost_for_cadre', 'preservice_training_duration', 'recruitment_cost_per_person_recruited_usd', + 'average_length_of_tenure_in_the_public_sector']) + + def calculate_npv_past_training_expenses_by_row(row, r = _discount_rate): + # Initialize the NPV for the row + npv = 0 + annual_cost = row['average_annual_preservice_training_cost_for_cadre'] + full_years = int(row['preservice_training_duration']) # Extract integer part of the year + partial_year = row['preservice_training_duration'] - full_years # Fractional part of the year + + # Iterate over each year of the training duration to calculate compounded cost to the present + # Calculate NPV for each full year of training + for t in range(full_years): + npv += annual_cost * (1 + r) ** (t+1+1) # 1 added twice because range(4) is [0,1,2,3] + + # Account for the fractional year at the end if it exists + if partial_year > 0: + npv += annual_cost * partial_year * (1 + r) ** (1+r) + + # Add recruitment cost assuming this happens during the partial year or the year after graduation if partial year == 0 + npv += row['recruitment_cost_per_person_recruited_usd'] * (1+r) + + return npv + + # Calculate NPV for each row using iterrows and store in a new column + npv_values = [] + for index, row in preservice_training_cost.iterrows(): + npv = calculate_npv_past_training_expenses_by_row(row, r=annuitization_rate) + npv_values.append(npv) + + preservice_training_cost['npv_of_training_and_recruitment_cost'] = npv_values + preservice_training_cost['npv_of_training_and_recruitment_cost_per_recruit'] = preservice_training_cost['npv_of_training_and_recruitment_cost'] *\ + (1/(preservice_training_cost['absorption_rate_of_students_into_public_workforce'] + preservice_training_cost['proportion_of_workforce_recruited_from_abroad'])) *\ + (1/preservice_training_cost['graduation_rate']) * (1/preservice_training_cost['licensure_exam_passing_rate']) + if _discount_rate == 0: # if the discount rate is 0, then the pre-service + recruitment cost simply needs to be divided by the number of years in tenure + preservice_training_cost['annuitisation_rate'] = preservice_training_cost['average_length_of_tenure_in_the_public_sector'] + else: + preservice_training_cost['annuitisation_rate'] = 1 + (1 - (1 + annuitization_rate) ** (-preservice_training_cost['average_length_of_tenure_in_the_public_sector'] + 1)) / annuitization_rate + preservice_training_cost['annuitised_training_and_recruitment_cost_per_recruit'] = preservice_training_cost['npv_of_training_and_recruitment_cost_per_recruit']/preservice_training_cost['annuitisation_rate'] + + # Cost per student trained * 1/Rate of absorption from the local and foreign graduates * 1/Graduation rate * attrition rate + # the inverse of attrition rate is the average expected tenure; and the preservice training cost needs to be divided by the average tenure + preservice_training_cost['cost'] = preservice_training_cost['annuitised_training_and_recruitment_cost_per_recruit'] * preservice_training_cost['staff_count'] * preservice_training_cost['annual_attrition_rate'] # not multiplied with attrition rate again because this is already factored into 'Annual_cost_per_staff_recruited' + preservice_training_cost = preservice_training_cost[['draw', 'run', 'year', 'OfficerType', 'Facility_Level', 'cost']] + + # 1.3 In-service training cost to train all staff + #--------------------------------------------------------------------------------------------------------------- + inservice_training_cost = merge_cost_and_model_data(cost_df = hr_cost_parameters, model_df = staff_size_chosen_for_costing, + varnames = ['annual_inservice_training_cost_usd']) + inservice_training_cost['cost'] = inservice_training_cost['staff_count'] * inservice_training_cost['annual_inservice_training_cost_usd'] + inservice_training_cost = inservice_training_cost[['draw', 'run', 'year', 'OfficerType', 'Facility_Level', 'cost']] + # TODO Consider calculating economic cost of HR by multiplying salary times staff count with cadres_utilisation_rate + + # 1.4 Regular mentorship and supportive supervision costs + #--------------------------------------------------------------------------------------------------------------- + mentorship_and_supportive_cost = merge_cost_and_model_data(cost_df = hr_cost_parameters, model_df = staff_size_chosen_for_costing, + varnames = ['annual_mentorship_and_supervision_cost']) + mentorship_and_supportive_cost['cost'] = mentorship_and_supportive_cost['staff_count'] * mentorship_and_supportive_cost['annual_mentorship_and_supervision_cost'] + mentorship_and_supportive_cost = mentorship_and_supportive_cost[['draw', 'run', 'year', 'OfficerType', 'Facility_Level', 'cost']] + # TODO Consider calculating economic cost of HR by multiplying salary times staff count with cadres_utilisation_rate + + # 1.5 Store all HR costs in one standard format dataframe + #--------------------------------------------------------------------------------------------------------------- + # Function to melt and label the cost category + def label_rows_of_cost_dataframe(_df, label_var, label): + _df = _df.reset_index() + _df[label_var] = label + return _df + + # Initialize HR with the salary data + if (cost_only_used_staff): + human_resource_costs = retain_relevant_column_subset(label_rows_of_cost_dataframe(salary_for_staff, 'cost_subcategory', 'salary_for_cadres_used'), 'OfficerType') + # Concatenate additional cost categories + additional_costs = [ + (preservice_training_cost, 'preservice_training_and_recruitment_cost_for_attrited_workers'), + (inservice_training_cost, 'inservice_training_cost_for_cadres_used'), + (mentorship_and_supportive_cost, 'mentorship_and_supportive_cost_for_cadres_used') + ] + else: + human_resource_costs = retain_relevant_column_subset(label_rows_of_cost_dataframe(salary_for_staff, 'cost_subcategory', 'salary_for_all_staff'), 'OfficerType') + # Concatenate additional cost categories + additional_costs = [ + (preservice_training_cost, 'preservice_training_and_recruitment_cost_for_attrited_workers'), + (inservice_training_cost, 'inservice_training_cost_for_all_staff'), + (mentorship_and_supportive_cost, 'mentorship_and_supportive_cost_for_all_staff') + ] + + # Iterate through additional costs, melt and concatenate + for df, label in additional_costs: + labelled_df = retain_relevant_column_subset(label_rows_of_cost_dataframe(df, 'cost_subcategory', label), 'OfficerType') + human_resource_costs = pd.concat([human_resource_costs, labelled_df]) + + human_resource_costs = prepare_cost_dataframe(human_resource_costs, _category_specific_group = 'OfficerType', _cost_category = 'human resources for health') + + # Only preserve the draws and runs requested + if _draws is not None: + human_resource_costs = human_resource_costs[human_resource_costs.draw.isin(_draws)] + if _runs is not None: + human_resource_costs = human_resource_costs[human_resource_costs.run.isin(_runs)] + + # %% + # 2. Consumables cost + #------------------------ + print("Now estimating Consumables costs...") + def get_quantity_of_consumables_dispensed(results_folder): + def get_counts_of_items_requested(_df): + _df = drop_outside_period(_df) + counts_of_used = defaultdict(lambda: defaultdict(int)) + counts_of_not_available = defaultdict(lambda: defaultdict(int)) + + for _, row in _df.iterrows(): + date = row['date'] + for item, num in row['Item_Used'].items(): + counts_of_used[date][item] += num + for item, num in row['Item_NotAvailable'].items(): + counts_of_not_available[date][item] += num + used_df = pd.DataFrame(counts_of_used).fillna(0).astype(int).stack().rename('Used') + not_available_df = pd.DataFrame(counts_of_not_available).fillna(0).astype(int).stack().rename('Not_Available') + + # Combine the two dataframes into one series with MultiIndex (date, item, availability_status) + combined_df = pd.concat([used_df, not_available_df], axis=1).fillna(0).astype(int) + + # Convert to a pd.Series, as expected by the custom_generate_series function + return combined_df.stack() + + cons_req = extract_results( + results_folder, + module='tlo.methods.healthsystem.summary', + key='Consumables', + custom_generate_series=get_counts_of_items_requested, + do_scaling=True) + + cons_dispensed = cons_req.xs("Used", level=2) # only keep actual dispensed amount, i.e. when available + return cons_dispensed + # TODO Extract year of dispensing drugs + + consumables_dispensed = get_quantity_of_consumables_dispensed(results_folder) + consumables_dispensed = consumables_dispensed.reset_index().rename(columns = {'level_0': 'Item_Code', 'level_1': 'year'}) + consumables_dispensed[idx['year']] = pd.to_datetime(consumables_dispensed[idx['year']]).dt.year # Extract only year from date + consumables_dispensed[idx['Item_Code']] = pd.to_numeric(consumables_dispensed[idx['Item_Code']]) + # Make a list of columns in the DataFrame pertaining to quantity dispensed + quantity_columns = consumables_dispensed.columns.to_list() + quantity_columns = [tup for tup in quantity_columns if tup not in [('Item_Code', ''), ('year', '')]] + + # 2.1 Cost of consumables dispensed + #--------------------------------------------------------------------------------------------------------------- + # Multiply number of items needed by cost of consumable + #consumables_dispensed.columns = consumables_dispensed.columns.get_level_values(0).str() + "_" + consumables_dispensed.columns.get_level_values(1) # Flatten multi-level columns for pandas merge + unit_price_consumable.columns = pd.MultiIndex.from_arrays([unit_price_consumable.columns, [''] * len(unit_price_consumable.columns)]) + cost_of_consumables_dispensed = consumables_dispensed.merge(unit_price_consumable, on = idx['Item_Code'], validate = 'm:1', how = 'left') + price_column = 'Final_price_per_chosen_unit (USD, 2023)' + cost_of_consumables_dispensed[quantity_columns] = cost_of_consumables_dispensed[quantity_columns].multiply( + cost_of_consumables_dispensed[price_column], axis=0) + + # 2.2 Cost of consumables stocked (quantity needed for what is dispensed) + #--------------------------------------------------------------------------------------------------------------- + # Stocked amount should be higher than dispensed because of i. excess capacity, ii. theft, iii. expiry + # While there are estimates in the literature of what % these might be, we agreed that it is better to rely upon + # an empirical estimate based on OpenLMIS data + # Estimate the stock to dispensed ratio from OpenLMIS data + lmis_consumable_usage = pd.read_csv(path_for_consumable_resourcefiles / "ResourceFile_Consumables_availability_and_usage.csv") + # TODO Generate a smaller version of this file + # Collapse individual facilities + lmis_consumable_usage_by_item_level_month = lmis_consumable_usage.groupby(['category', 'item_code', 'district', 'fac_type_tlo', 'month'])[['closing_bal', 'dispensed', 'received']].sum() + df = lmis_consumable_usage_by_item_level_month # Drop rows where monthly OpenLMIS data wasn't available + df = df.loc[df.index.get_level_values('month') != "Aggregate"] + # Opening balance in January is the closing balance for the month minus what was received during the month plus what was dispensed + opening_bal_january = df.loc[df.index.get_level_values('month') == 'January', 'closing_bal'] + \ + df.loc[df.index.get_level_values('month') == 'January', 'dispensed'] - \ + df.loc[df.index.get_level_values('month') == 'January', 'received'] + closing_bal_december = df.loc[df.index.get_level_values('month') == 'December', 'closing_bal'] + # the consumable inflow during the year is the opening balance in January + what was received throughout the year - what was transferred to the next year (i.e. closing bal of December) + total_consumables_inflow_during_the_year = df.loc[df.index.get_level_values('month') != 'January', 'received'].groupby(level=[0,1,2,3]).sum() +\ + opening_bal_january.reset_index(level='month', drop=True) -\ + closing_bal_december.reset_index(level='month', drop=True) + total_consumables_outflow_during_the_year = df['dispensed'].groupby(level=[0,1,2,3]).sum() + inflow_to_outflow_ratio = total_consumables_inflow_during_the_year.div(total_consumables_outflow_during_the_year, fill_value=1) + + # Edit outlier ratios + inflow_to_outflow_ratio.loc[inflow_to_outflow_ratio < 1] = 1 # Ratio can't be less than 1 + inflow_to_outflow_ratio.loc[inflow_to_outflow_ratio > inflow_to_outflow_ratio.quantile(0.95)] = inflow_to_outflow_ratio.quantile(0.95) # Trim values greater than the 95th percentile + average_inflow_to_outflow_ratio_ratio = inflow_to_outflow_ratio.mean() # Use average where item-specific ratio is not available + + # Multiply number of items needed by cost of consumable + inflow_to_outflow_ratio_by_consumable = inflow_to_outflow_ratio.groupby(level='item_code').mean() + excess_stock_ratio = inflow_to_outflow_ratio_by_consumable - 1 + excess_stock_ratio = excess_stock_ratio.reset_index().rename(columns = {0: 'excess_stock_proportion_of_dispensed'}) + # TODO Consider whether a more disaggregated version of the ratio dictionary should be applied + cost_of_excess_consumables_stocked = consumables_dispensed.merge(unit_price_consumable, left_on = 'Item_Code', right_on = 'Item_Code', validate = 'm:1', how = 'left') + excess_stock_ratio.columns = pd.MultiIndex.from_arrays([excess_stock_ratio.columns, [''] * len(excess_stock_ratio.columns)]) # TODO convert this into a funciton + cost_of_excess_consumables_stocked = cost_of_excess_consumables_stocked.merge(excess_stock_ratio, left_on = 'Item_Code', right_on = 'item_code', validate = 'm:1', how = 'left') + cost_of_excess_consumables_stocked.loc[cost_of_excess_consumables_stocked.excess_stock_proportion_of_dispensed.isna(), 'excess_stock_proportion_of_dispensed'] = average_inflow_to_outflow_ratio_ratio - 1# TODO disaggregate the average by program + cost_of_excess_consumables_stocked[quantity_columns] = cost_of_excess_consumables_stocked[quantity_columns].multiply(cost_of_excess_consumables_stocked[idx[price_column]], axis=0) + cost_of_excess_consumables_stocked[quantity_columns] = cost_of_excess_consumables_stocked[quantity_columns].multiply(cost_of_excess_consumables_stocked[idx['excess_stock_proportion_of_dispensed']], axis=0) + + # 2.3 Store all consumable costs in one standard format dataframe + #--------------------------------------------------------------------------------------------------------------- + # Function to melt and label the cost category + consumables_dict = pd.read_csv(path_for_consumable_resourcefiles / 'ResourceFile_Consumables_Items_and_Packages.csv', low_memory=False, + encoding="ISO-8859-1")[['Items','Item_Code']] + consumables_dict = dict(zip(consumables_dict['Item_Code'], consumables_dict['Items'])) + def melt_and_label_consumables_cost(_df, label): + multi_index = pd.MultiIndex.from_tuples(_df.columns) + _df.columns = multi_index + # Select 'Item_Code', 'year', and all columns where both levels of the MultiIndex are numeric (these are the (draw,run) columns with cost values) + selected_columns = [col for col in _df.columns if + (col[0] in ['Item_Code', 'year']) or (isinstance(col[0], int) and isinstance(col[1], int))] + _df = _df[selected_columns] # Subset the dataframe with the selected columns + + # reshape dataframe and assign 'draw' and 'run' as the correct column headers + melted_df = pd.melt(_df, id_vars=['year', 'Item_Code']).rename(columns = {'variable_0': 'draw', 'variable_1': 'run'}) + # Replace item_code with consumable_name_tlo + melted_df['consumable'] = melted_df['Item_Code'].map(consumables_dict) + melted_df['cost_subcategory'] = label + melted_df['Facility_Level'] = 'all' #TODO this is temporary until 'tlo.methods.healthsystem.summary' only logs consumable at the aggregate level + melted_df = melted_df.rename(columns = {'value': 'cost'}) + return melted_df + + def disaggregate_separately_managed_medical_supplies_from_consumable_costs(_df, + _consumables_dict, # This is a dictionary mapping codes to names + list_of_unique_medical_products): + reversed_consumables_dict = {value: key for key, value in _consumables_dict.items()} # reverse dictionary to map names to codes + new_df = _df.copy() + new_df['item_code'] = new_df['consumable'].map(reversed_consumables_dict) + cost_of_consumables = new_df[~new_df['item_code'].isin(list_of_unique_medical_products)] + cost_of_separately_managed_medical_supplies = new_df[new_df['item_code'].isin(list_of_unique_medical_products)] + cost_of_separately_managed_medical_supplies['cost_subcategory'] = cost_of_separately_managed_medical_supplies['cost_subcategory'].replace( + {'consumables_dispensed': 'separately_managed_medical_supplies_dispensed', 'consumables_stocked': 'separately_managed_medical_supplies_stocked'}, regex=True) + return cost_of_consumables.drop(columns = 'item_code'), cost_of_separately_managed_medical_supplies.drop(columns = 'item_code') + + separately_managed_medical_supplies = [127, 141, 161] # Oxygen, Blood, IRS + cost_of_consumables_dispensed, cost_of_separately_managed_medical_supplies_dispensed = disaggregate_separately_managed_medical_supplies_from_consumable_costs(_df = retain_relevant_column_subset(melt_and_label_consumables_cost(cost_of_consumables_dispensed, 'cost_of_consumables_dispensed'), 'consumable'), + _consumables_dict = consumables_dict, + list_of_unique_medical_products = separately_managed_medical_supplies) + cost_of_excess_consumables_stocked, cost_of_separately_managed_medical_supplies_excess_stock = disaggregate_separately_managed_medical_supplies_from_consumable_costs(_df = retain_relevant_column_subset(melt_and_label_consumables_cost(cost_of_excess_consumables_stocked, 'cost_of_excess_consumables_stocked'), 'consumable'), + _consumables_dict=consumables_dict, + list_of_unique_medical_products=separately_managed_medical_supplies) + + consumable_costs = pd.concat([cost_of_consumables_dispensed, cost_of_excess_consumables_stocked]) + + # 2.4 Supply chain costs + #--------------------------------------------------------------------------------------------------------------- + # Assume that the cost of procurement, warehousing and distribution is a fixed proportion of consumable purchase costs + # The fixed proportion is based on Resource Mapping Expenditure data from 2018 + resource_mapping_data = workbook_cost["resource_mapping_r7_summary"] + # Make sure values are numeric + expenditure_column = ['EXPENDITURE (USD) (Jul 2018 - Jun 2019)'] + resource_mapping_data[expenditure_column] = resource_mapping_data[expenditure_column].apply(lambda x: pd.to_numeric(x, errors='coerce')) + # The numerator includes Supply chain expenditure for EHP consumables + supply_chain_expenditure = \ + resource_mapping_data[resource_mapping_data['Cost Type'] == 'Supply Chain'][expenditure_column].sum()[0] + # The denominator include all drugs and commodities expenditure, excluding what is recategorised as non-EHP or admin + drug_expenditure_condition = resource_mapping_data['Cost Type'].str.contains('Drugs and Commodities') + excluded_drug_expenditure_condition = (resource_mapping_data[ + 'Calibration_category'] == 'Program Management & Administration') | ( + resource_mapping_data[ + 'Calibration_category'] == 'Non-EHP consumables') + consumables_purchase_expenditure = \ + resource_mapping_data[drug_expenditure_condition][expenditure_column].sum()[0] - \ + resource_mapping_data[drug_expenditure_condition & excluded_drug_expenditure_condition][ + expenditure_column].sum()[0] + supply_chain_cost_proportion = supply_chain_expenditure / consumables_purchase_expenditure + + # Estimate supply chain costs based on the total consumable purchase cost calculated above + # Note that Oxygen, IRS, and Blood costs are already excluded because the unit_cost of these commodities already + # includes the procurement/production, storage and distribution costs + supply_chain_costs = (consumable_costs.groupby(['draw', 'run', 'year'])[ + 'cost'].sum() * supply_chain_cost_proportion).reset_index() + # Assign relevant additional columns to match the format of the rest of consumables costs + supply_chain_costs['Facility_Level'] = 'all' + supply_chain_costs['consumable'] = 'supply chain (all consumables)' + supply_chain_costs['cost_subcategory'] = 'supply_chain' + assert set(supply_chain_costs.columns) == set(consumable_costs.columns) + + # Append supply chain costs to the full consumable cost dataframe + consumable_costs = pd.concat([consumable_costs, supply_chain_costs]) + other_costs = pd.concat([cost_of_separately_managed_medical_supplies_dispensed, cost_of_separately_managed_medical_supplies_excess_stock]) + + consumable_costs = prepare_cost_dataframe(consumable_costs, _category_specific_group = 'consumable', _cost_category = 'medical consumables') + other_costs = prepare_cost_dataframe(other_costs, _category_specific_group = 'consumable', _cost_category = 'medical consumables') + + # Only preserve the draws and runs requested + if _draws is not None: + consumable_costs = consumable_costs[consumable_costs.draw.isin(_draws)] + other_costs = other_costs[other_costs.draw.isin(_draws)] + if _runs is not None: + consumable_costs = consumable_costs[consumable_costs.run.isin(_runs)] + other_costs = other_costs[other_costs.run.isin(_runs)] + + + # %% + # 3. Equipment cost + #-------------------------------------------- + print("Now estimating Medical equipment costs...") + # Total cost of equipment required as per SEL (HSSP-III) only at facility IDs where it has been used in the simulation + # Get list of equipment used in the simulation by district and level + def get_equipment_used_by_district_and_facility(_df: pd.Series) -> pd.Series: + """Summarise the parsed logged-key results for one draw (as dataframe) into a pd.Series.""" + _df = _df.pivot_table(index=['District', 'Facility_Level'], + values='EquipmentEverUsed', + aggfunc='first') + _df.index.name = 'year' + return _df['EquipmentEverUsed'] + + list_of_equipment_used_by_draw_and_run = extract_results( + Path(results_folder), + module='tlo.methods.healthsystem.summary', + key='EquipmentEverUsed_ByFacilityID', + custom_generate_series=get_equipment_used_by_district_and_facility, + do_scaling=False, + ) + for col in list_of_equipment_used_by_draw_and_run.columns: + list_of_equipment_used_by_draw_and_run[col] = list_of_equipment_used_by_draw_and_run[col].apply(ast.literal_eval) + + # Initialize an empty DataFrame + equipment_cost_across_sim = pd.DataFrame() + + # Extract equipment cost for each draw and run + for d in _draws: + for r in _runs: + print(f"Processing draw {d} and run {r} of equipment costs") + # Extract a list of equipment which was used at each facility level within each district + equipment_used = {district: {level: [] for level in fac_levels} for district in list(district_dict.values())} # create a dictionary with a key for each district and facility level + list_of_equipment_used_by_current_draw_and_run = list_of_equipment_used_by_draw_and_run[(d, r)].reset_index() + for dist in list(district_dict.values()): + for level in fac_levels: + equipment_used_subset = list_of_equipment_used_by_current_draw_and_run[(list_of_equipment_used_by_current_draw_and_run['District'] == dist) & (list_of_equipment_used_by_current_draw_and_run['Facility_Level'] == level)] + equipment_used_subset.columns = ['District', 'Facility_Level', 'EquipmentEverUsed'] + equipment_used[dist][level] = set().union(*equipment_used_subset['EquipmentEverUsed']) + equipment_used = pd.concat({ + k: pd.DataFrame.from_dict(v, 'index') for k, v in equipment_used.items()}, + axis=0) + full_list_of_equipment_used = set(equipment_used.values.flatten()) + full_list_of_equipment_used = set(filter(pd.notnull, full_list_of_equipment_used)) + + equipment_df = pd.DataFrame() + equipment_df.index = equipment_used.index + for item in full_list_of_equipment_used: + equipment_df[str(item)] = 0 + for dist_fac_index in equipment_df.index: + equipment_df.loc[equipment_df.index == dist_fac_index, str(item)] = equipment_used[equipment_used.index == dist_fac_index].isin([item]).any(axis=1) + #equipment_df.to_csv('./outputs/equipment_use.csv') + + equipment_df = equipment_df.reset_index().rename(columns = {'level_0' : 'District', 'level_1': 'Facility_Level'}) + equipment_df = pd.melt(equipment_df, id_vars = ['District', 'Facility_Level']).rename(columns = {'variable': 'Item_code', 'value': 'whether_item_was_used'}) + equipment_df['Item_code'] = pd.to_numeric(equipment_df['Item_code']) + # Merge the count of facilities by district and level + equipment_df = equipment_df.merge(mfl[['District', 'Facility_Level','Facility_Count']], on = ['District', 'Facility_Level'], how = 'left') + equipment_df.loc[equipment_df.Facility_Count.isna(), 'Facility_Count'] = 0 + + # Because levels 1b and 2 are collapsed together, we assume that the same equipment is used by level 1b as that recorded for level 2 + def update_itemuse_for_level1b_using_level2_data(_df): + # Create a list of District and Item_code combinations for which use == True + list_of_equipment_used_at_level2 = _df[(_df.Facility_Level == '2') & (_df['whether_item_was_used'] == True)][['District', 'Item_code']] + # Now update the 'whether_item_was_used' for 'Facility_Level' == '1b' to match that of level '2' + _df.loc[ + (_df['Facility_Level'] == '1b') & + (_df[['District', 'Item_code']].apply(tuple, axis=1).isin( + list_of_equipment_used_at_level2.apply(tuple, axis=1))), + 'whether_item_was_used' + ] = True + + return _df + + equipment_df = update_itemuse_for_level1b_using_level2_data(equipment_df) + + # Merge the two datasets to calculate cost + equipment_cost = pd.merge(equipment_df, unit_cost_equipment[['Item_code', 'Equipment_tlo', 'Facility_Level', 'Quantity', 'replacement_cost_annual', 'service_fee_annual', 'spare_parts_annual', 'major_corrective_maintenance_cost_annual']], + on = ['Item_code', 'Facility_Level'], how = 'left', validate = "m:1") + categories_of_equipment_cost = ['replacement_cost', 'service_fee', 'spare_parts', 'major_corrective_maintenance_cost'] + for cost_category in categories_of_equipment_cost: + # Rename unit cost columns + unit_cost_column = cost_category + '_annual_unit' + equipment_cost = equipment_cost.rename(columns = {cost_category + '_annual':unit_cost_column }) + equipment_cost[cost_category + '_annual_total'] = equipment_cost[cost_category + '_annual_unit'] * equipment_cost['whether_item_was_used'] * equipment_cost['Quantity'] * equipment_cost['Facility_Count'] + equipment_cost['year'] = final_year_of_simulation - 1 + if equipment_cost_across_sim.empty: + equipment_cost_across_sim = equipment_cost.groupby(['year', 'Facility_Level', 'Equipment_tlo'])[[item + '_annual_total' for item in categories_of_equipment_cost]].sum() + equipment_cost_across_sim['draw'] = d + equipment_cost_across_sim['run'] = r + else: + equipment_cost_for_current_sim = equipment_cost.groupby(['year', 'Facility_Level', 'Equipment_tlo'])[[item + '_annual_total' for item in categories_of_equipment_cost]].sum() + equipment_cost_for_current_sim['draw'] = d + equipment_cost_for_current_sim['run'] = r + # Concatenate the results + equipment_cost_across_sim = pd.concat([equipment_cost_across_sim, equipment_cost_for_current_sim], axis=0) + + equipment_costs = pd.melt(equipment_cost_across_sim.reset_index(), + id_vars=['draw', 'run', 'Facility_Level', 'Equipment_tlo'], # Columns to keep + value_vars=[col for col in equipment_cost_across_sim.columns if col.endswith('_annual_total')], # Columns to unpivot + var_name='cost_subcategory', # New column name for the 'sub-category' of cost + value_name='cost') # New column name for the values + + # Assume that the annual costs are constant each year of the simulation + equipment_costs = pd.concat([equipment_costs.assign(year=year) for year in years]) + # TODO If the logger is updated to include year, we may wish to calculate equipment costs by year - currently we assume the same annuitised equipment cost each year + equipment_costs = equipment_costs.reset_index(drop=True) + equipment_costs = equipment_costs.rename(columns = {'Equipment_tlo': 'Equipment'}) + equipment_costs = prepare_cost_dataframe(equipment_costs, _category_specific_group = 'Equipment', _cost_category = 'medical equipment') + + # 4. Facility running costs + # Average running costs by facility level and district times the number of facilities in the simulation + # Convert unit_costs to long format + unit_cost_fac_operations = pd.melt( + unit_cost_fac_operations, + id_vars=["Facility_Level"], # Columns to keep as identifiers + var_name="operating_cost_type", # Name for the new 'cost_category' column + value_name="unit_cost" # Name for the new 'cost' column + ) + unit_cost_fac_operations['Facility_Level'] = unit_cost_fac_operations['Facility_Level'].astype(str) + fac_count_by_level = mfl[['Facility_Level', 'Facility_Count']].groupby(['Facility_Level']).sum().reset_index() + + facility_operation_cost = pd.merge(unit_cost_fac_operations, fac_count_by_level, on = 'Facility_Level', how = 'left', validate = 'm:m') + facility_operation_cost['Facility_Count'] = facility_operation_cost['Facility_Count'].fillna(0).astype(int) + facility_operation_cost['cost'] = facility_operation_cost['unit_cost'] * facility_operation_cost['Facility_Count'] + + # Duplicate the same set of facility operation costs for all draws and runs + # Create the Cartesian product of `_draws` and `_runs` + combinations = list(itertools.product(_draws, _runs)) + comb_df = pd.DataFrame(combinations, columns=["draw", "run"]) + facility_operation_cost = facility_operation_cost.merge(comb_df, how="cross") + facility_operation_cost['cost_category'] = 'Facility operating cost' + operating_cost_mapping = {'Electricity': 'utilities_and_maintenance', 'Water': 'utilities_and_maintenance', 'Cleaning':'utilities_and_maintenance', + 'Security':'utilities_and_maintenance', 'Building maintenance': 'building_maintenance', + 'Facility management': 'utilities_and_maintenance', 'Vehicle maintenance': 'vehicle_maintenance', + 'Ambulance fuel': 'fuel_for_ambulance', 'Food for inpatient cases': 'food_for_inpatient_care'} + facility_operation_cost['cost_subcategory'] = facility_operation_cost['operating_cost_type'] + facility_operation_cost['cost_subcategory'] = facility_operation_cost['cost_subcategory'].map(operating_cost_mapping) + # Assume that the annual costs are constant each year of the simulation + facility_operation_cost = pd.concat([facility_operation_cost.assign(year=year) for year in years]) + + # Assume that the annual costs are constant each year of the simulation + facility_operation_cost = prepare_cost_dataframe(facility_operation_cost, _category_specific_group = 'operating_cost_type', _cost_category = 'facility operating cost') + + + # %% + # Store all costs in single dataframe + #-------------------------------------------- + scenario_cost = pd.concat([human_resource_costs, consumable_costs, equipment_costs, other_costs, facility_operation_cost], ignore_index=True) + scenario_cost['cost'] = pd.to_numeric(scenario_cost['cost'], errors='coerce') + + # Summarize costs + if summarize: + groupby_cols = [col for col in scenario_cost.columns if col not in ['run', 'cost']] + # Use the summary metric specific in the inputs + if _metric not in ['mean', 'median']: + raise ValueError(f"Invalid input for _metric: '{_metric}'. " + f"Values need to be one of 'mean' or 'median'") + else: + # Define aggregation function based on _metric input (mean or median) + agg_func = np.mean if _metric == 'mean' else np.median + + scenario_cost = pd.concat( + { + _metric: scenario_cost.groupby(by=groupby_cols, sort=False)['cost'].agg(agg_func), + 'lower': scenario_cost.groupby(by=groupby_cols, sort=False)['cost'].quantile(0.025), + 'upper': scenario_cost.groupby(by=groupby_cols, sort=False)['cost'].quantile(0.975), + }, + axis=1 + ) + + scenario_cost = pd.melt( + scenario_cost.reset_index(), + id_vars=groupby_cols, # Columns to keep + value_vars=[_metric, 'lower', 'upper'], # Columns to unpivot + var_name='stat', # New column name for the 'sub-category' of cost + value_name='cost' + ) + + if _years is None: + return apply_discounting_to_cost_data(_df = scenario_cost, + _discount_rate = _discount_rate, _column_for_discounting = 'cost') + else: + return apply_discounting_to_cost_data(_df = scenario_cost[scenario_cost.year.isin(_years)], + _discount_rate = _discount_rate, + _column_for_discounting = 'cost') + +# Define a function to summarize cost data from +# Note that the dataframe needs to have draw as index and run as columns. if the dataframe is long with draw and run as index, then +# first unstack the dataframe and subsequently apply the summarize function +def summarize_cost_data(_df, + _metric: Literal['mean', 'median'] = 'mean') -> pd.DataFrame: + """ + Summarize cost data across runs by computing central tendency and 95% confidence intervals. + + Parameters: + ---------- + _df : pd.DataFrame + A DataFrame with draw as index and run as columns, where each cell contains a cost value. + - Rows = draw IDs (e.g., 0, 1, 2) + - Columns = run IDs (e.g., 0, 1, 2) + - Values = cost estimates + + _metric : {'mean', 'median'}, default 'mean' + The central summary statistic to compute across runs. + + Returns: + ------- + pd.DataFrame + A pivoted DataFrame with draws as index and a MultiIndex of columns: + (run ID, ['mean' or 'median', 'lower', 'upper']), where: + - 'lower' = 2.5th percentile + - 'upper' = 97.5th percentile + """ + + if _metric not in ['mean', 'median']: + raise ValueError(f"Invalid input for _metric: '{_metric}'. " + f"Values need to be one of 'mean' or 'median'") + + _df = _df.stack() + collapsed_df = _df.groupby(level='draw').agg([ + _metric, + ('lower', lambda x: x.quantile(0.025)), + ('upper', lambda x: x.quantile(0.975)) + ]) + + collapsed_df = collapsed_df.unstack() + collapsed_df.index = collapsed_df.index.set_names('stat', level=0) + collapsed_df = collapsed_df.unstack(level='stat') + return collapsed_df + +# Estimate projected health spending +#################################################### +def estimate_projected_health_spending(resourcefilepath: Path, + results_folder: Path, + _draws: Optional[list[int]] = None, + _runs: Optional[list[int]] = None, + _years: Optional[list[int]] = None, + _discount_rate: float = 0, + _summarize: bool = False, + _metric: Literal['mean', 'median'] = 'mean') -> pd.DataFrame: + """ + Estimate total projected health spending for a simulation period. + + Combines health spending per capita projections (Dieleman et al, 2019) with simulated population estimates to calculate + total health expenditure, optionally applying a discount rate and summarizing across runs. + + Parameters: + ---------- + resourcefilepath : Path + Path to the folder containing the costing resource Excel files. + results_folder : Path + Path to the simulation results folder. + _draws : list or range, optional + Draws to include. If None, all available draws are used. + _runs : list or range, optional + Runs to include. If None, all available runs are used. + _years : list of int, optional + Years to include. If None, includes the full simulation period. + _discount_rate : float, default 0 + Discount rate applied to future costs. + _summarize : bool, default False + Whether to summarize output across runs using mean/median and 95% confidence intervals. + _metric : {'mean', 'median'}, default 'mean' + Central tendency metric used if summarizing. + + Returns: + ------- + pd.DataFrame + If `_summarize=True`, returns a DataFrame with: + - Index = draw + - Columns = 'mean'/'median', 'lower', 'upper' ROI values + + If `_summarize=False`, returns a DataFrame with: + - Index = draw + - Columns = run + - Values = discounted total health spending for the selected years + """ + + # %% Gathering basic information + # Load basic simulation parameters + #------------------------------------- + log = load_pickled_dataframes(results_folder, 0, 0) # read from 1 draw and run + info = get_scenario_info(results_folder) # get basic information about the results + if _draws is None: + _draws = range(0, info['number_of_draws']) + if _runs is None: + _runs = range(0, info['runs_per_draw']) + final_year_of_simulation = max(log['tlo.methods.healthsystem.summary']['hsi_event_counts']['date']).year + first_year_of_simulation = min(log['tlo.methods.healthsystem.summary']['hsi_event_counts']['date']).year + if _years == None: + _years = list(range(first_year_of_simulation, final_year_of_simulation + 1)) + + # Load health spending per capita projections + #---------------------------------------- + # Load health spending projections + workbook_cost = pd.read_excel((resourcefilepath / "costing/ResourceFile_Costing.xlsx"), + sheet_name=None) + health_spending_per_capita = workbook_cost["health_spending_projections"] + # Assign the fourth row as column names + health_spending_per_capita.columns = health_spending_per_capita.iloc[1] + health_spending_per_capita = health_spending_per_capita.iloc[2:].reset_index(drop=True) + health_spending_per_capita = health_spending_per_capita[ + health_spending_per_capita.year.isin(list(range(2015, 2041)))] + total_health_spending_per_capita_mean = health_spending_per_capita[['year', 'total_mean']].set_index('year') + total_health_spending_per_capita_mean.columns = pd.MultiIndex.from_tuples([('total_mean', '')]) + + # Load population projections + # ---------------------------------------- + def get_total_population(_df): + years_needed = [min(_years), max(_years)] # we only consider the population for the malaria scale-up period + # because those are the years relevant for malaria scale-up costing + _df['year'] = pd.to_datetime(_df['date']).dt.year + _df = _df[['year', 'total']] + assert set(_df.year.unique()).issuperset(years_needed), "Some years are not recorded." + return pd.Series(_df.loc[_df.year.between(*years_needed)].set_index('year')['total']) + + total_population_by_year = extract_results( + results_folder, + module='tlo.methods.demography', + key='population', + custom_generate_series=get_total_population, + do_scaling=True + ) + population_columns = total_population_by_year.columns + + # Estimate total health spending + projected_health_spending = pd.merge(total_health_spending_per_capita_mean, + total_population_by_year, + left_index=True, right_index=True,how='inner') + projected_health_spending = projected_health_spending.apply(pd.to_numeric, errors='coerce') + projected_health_spending[population_columns] = projected_health_spending[population_columns].multiply( + projected_health_spending['total_mean'], axis=0) + projected_health_spending = projected_health_spending[population_columns] + + # Apply discount rate + # Reformat dataframe to apply discounting function + projected_health_spending.columns.names = ['draw', 'run'] + projected_health_spending = projected_health_spending.stack(level=['draw', 'run']).reset_index() + projected_health_spending.columns = ['year', 'draw', 'run', 'total_spending'] + + # Initial year and discount rate + initial_year = min(projected_health_spending['year'].unique()) + projected_health_spending_discounted = apply_discounting_to_cost_data( + projected_health_spending, _discount_rate= _discount_rate, + _column_for_discounting='total_spending', _initial_year = initial_year) + projected_health_spending_discounted = projected_health_spending_discounted.groupby(['draw', 'run'])['total_spending'].sum() + + if _summarize == True: + if _metric == 'mean': + # Calculate the mean and 95% confidence intervals for each group + projected_health_spending_discounted = projected_health_spending_discounted.groupby(level="draw").agg( + mean=np.mean, + lower=lambda x: np.percentile(x, 2.5), + upper=lambda x: np.percentile(x, 97.5) + ) + + elif _metric == 'median': + # Calculate the mean and 95% confidence intervals for each group + projected_health_spending_discounted = projected_health_spending_discounted.groupby(level="draw").agg( + median=np.median, + lower=lambda x: np.percentile(x, 2.5), + upper=lambda x: np.percentile(x, 97.5) + ) + + else: + raise ValueError(f"Invalid input for _metric: '{_metric}'. " + f"Values need to be one of 'mean' or 'median'") + # Flatten the resulting DataFrame into a single-level MultiIndex Series + projected_health_spending_discounted = projected_health_spending_discounted.stack().rename_axis(["draw", "stat"]).rename("value") + + return projected_health_spending_discounted.unstack() + +# Plot costs +#################################################### +# 1. Stacked bar plot (Total cost + Cost categories) +#---------------------------------------------------- +def do_stacked_bar_plot_of_cost_by_category(_df: pd.DataFrame, + _cost_category: Literal['all', 'human resources for health', 'medical consumables', + 'medical equipment', 'facility operating cost'] = 'all', + _disaggregate_by_subgroup: bool = False, + _year: list[int] = 'all', + _draws: Optional[list[int]] = None, + _scenario_dict: Optional[dict[int,str]] = None, + show_title: bool = True, + _outputfilepath: Optional[Path] = None, + _add_figname_suffix: str = ''): + """ + Create and save a stacked bar chart of costs by category, subcategory or subgroup. + + Parameters: + ---------- + _df : pd.DataFrame + DataFrame with cost results, including columns: + ['draw', 'year', 'cost_category', 'cost_subcategory', 'cost_subgroup', + 'cost', 'stat'] — typically produced by `estimate_input_cost_of_scenarios`. + + _cost_category : str, default 'all' + If 'all', compares high-level categories (e.g., HR, consumables, equipment, facilty operations). + Otherwise, filters to a specific category and optionally disaggregates. + + _disaggregate_by_subgroup : bool, default False + If True and a single `_cost_category` is selected, breaks down costs by `cost_subgroup`. + + _year : str or list of int, default 'all' + Year or years to include. Can be: + - 'all' to include all available years + - a single year or multiple years as a list: [2025] + + _draws : list of int, optional + If specified, only includes the specified draws. + + _scenario_dict : dict, required + Dictionary mapping draw numbers to scenario names, used for x-axis labels. + + show_title : bool, default True + Whether to display the chart title. + + _outputfilepath : Path, optional + Folder to save the plot. File will be saved as a PNG using `_cost_category` + and `_add_figname_suffix` in the filename. + + _add_figname_suffix : str, default '' + Optional string to append to the saved figure's filename + + Returns: + ------- + None + The chart is saved to disk as a PNG. + """ + # Subset and Pivot the data to have 'Cost Sub-category' as columns + # Check what's the correct central metric to use (either 'mean' or 'median') + central_metric = [stat for stat in _df.stat.unique() if stat not in ['lower', 'upper']][0] + + # Make a copy of the dataframe to avoid modifying the original + _df_central = _df[_df.stat == central_metric].copy() + _df_lower = _df[_df.stat == 'lower'].copy() + _df_upper = _df[_df.stat == 'upper'].copy() + + # Subset the dataframes to keep the s=relevant categories for the plot + dfs = {"_df_central": _df_central, "_df_lower": _df_lower, "_df_upper": _df_upper} # create a dict of dataframes + for name, df in dfs.items(): + dfs[name] = df.copy() # Choose the dataframe to modify + # Convert 'cost' to millions + dfs[name]['cost'] = dfs[name]['cost'] / 1e6 + # Subset data + if _draws is not None: + dfs[name] = dfs[name][dfs[name].draw.isin(_draws)] + if _year != 'all': + dfs[name] = dfs[name][dfs[name]['year'].isin(_year)] + if _cost_category != 'all': + dfs[name] = dfs[name][dfs[name]['cost_category'] == _cost_category] + + # Extract the updated DataFrames back from the dictionary + _df_central, _df_lower, _df_upper = dfs["_df_central"], dfs["_df_lower"], dfs["_df_upper"] + + if _cost_category == 'all': + if (_disaggregate_by_subgroup == True): + raise ValueError(f"Invalid input for _disaggregate_by_subgroup: '{_disaggregate_by_subgroup}'. " + f"Value can be True only when plotting a specific _cost_category") + else: + pivot_central = _df_central.pivot_table(index='draw', columns='cost_category', values='cost', aggfunc='sum') + pivot_lower = _df_lower.pivot_table(index='draw', columns='cost_category', values='cost', aggfunc='sum') + pivot_upper = _df_upper.pivot_table(index='draw', columns='cost_category', values='cost', aggfunc='sum') + else: + if (_disaggregate_by_subgroup == True): + for name, df in dfs.items(): + dfs[name] = df.copy() # Choose the dataframe to modify + # If sub-groups are more than 10 in number, then disaggregate the top 10 and group the rest into an 'other' category + if (len(dfs[name]['cost_subgroup'].unique()) > 10): + # Calculate total cost per subgroup + subgroup_totals = dfs[name].groupby('cost_subgroup')['cost'].sum() + # Identify the top 10 subgroups by cost + top_10_subgroups = subgroup_totals.nlargest(10).index.tolist() + # Label the remaining subgroups as 'other' + dfs[name]['cost_subgroup'] = dfs[name]['cost_subgroup'].apply( + lambda x: x if x in top_10_subgroups else 'All other items' + ) + + # Extract the updated DataFrames back from the dictionary + _df_central, _df_lower, _df_upper = dfs["_df_central"], dfs["_df_lower"], dfs["_df_upper"] + + pivot_central = _df_central.pivot_table(index='draw', columns='cost_subgroup', + values='cost', aggfunc='sum') + pivot_lower = _df_lower.pivot_table(index='draw', columns='cost_subgroup', + values='cost', aggfunc='sum') + pivot_upper = _df_upper.pivot_table(index='draw', columns='cost_subgroup', + values='cost', aggfunc='sum') + + plt_name_suffix = '_by_subgroup' + else: + pivot_central = _df_central.pivot_table(index='draw', columns='cost_subcategory', values='cost', aggfunc='sum') + pivot_lower = _df_lower.pivot_table(index='draw', columns='cost_subcategory', values='cost', aggfunc='sum') + pivot_upper = _df_upper.pivot_table(index='draw', columns='cost_subcategory', values='cost', aggfunc='sum') + plt_name_suffix = '' + + # Sort pivot_df columns in ascending order by total cost + sorted_columns = pivot_central.sum(axis=0).sort_values().index + pivot_central = pivot_central[sorted_columns] + pivot_lower = pivot_lower[sorted_columns] + pivot_upper = pivot_upper[sorted_columns] + + # Error bars + lower_bounds = pivot_central.sum(axis=1) - pivot_lower.sum(axis=1) + lower_bounds[lower_bounds<0] = 0 + upper_bounds = pivot_upper.sum(axis=1) - pivot_central.sum(axis=1) + + if _cost_category == 'all': + # Predefined color mapping for cost categories + color_mapping = { + 'human resources for health': '#1f77b4', # Muted blue + 'medical consumables': '#ff7f0e', # Muted orange + 'medical equipment': '#2ca02c', # Muted green + 'other': '#d62728', # Muted red + 'facility operating cost': '#9467bd', # Muted purple + } + # Default color for unexpected categories + default_color = 'gray' + plt_name_suffix = '' + + # Define custom colors for the bars + if _cost_category == 'all': + column_colors = [color_mapping.get(col, default_color) for col in sorted_columns] + # Plot the stacked bar chart with set colours + ax = pivot_central.plot(kind='bar', stacked=True, figsize=(10, 6), color=column_colors) + + # Add error bars + x_pos = np.arange(len(pivot_central.index)) + total_central = pivot_central.sum(axis=1) + error_bars = [lower_bounds, upper_bounds] + ax.errorbar(x_pos, total_central, yerr=error_bars, fmt='o', color='black', capsize=5) + + else: + # Plot the stacked bar chart without set colours + ax = pivot_central.plot(kind='bar', stacked=True, figsize=(10, 6)) + + # Add error bars + x_pos = np.arange(len(pivot_central.index)) + total_central = pivot_central.sum(axis=1) + error_bars = [lower_bounds, upper_bounds] + ax.errorbar(x_pos, total_central, yerr=error_bars, fmt='o', color='black', capsize=5) + + # Add data labels such that the stacked block has a superimposed white label is the value is >=2% of the Y-axis limit + # and a black label adjusted to the right of the bar (for visibility) if the value is <2% + # Get max y-limit for threshold + max_y = ax.get_ylim()[1] + threshold = max_y * 0.02 # 2% of ylim + + for container in ax.containers: + if isinstance(container, mpc.BarContainer): # Ensure we're working with bars, not error bars + for rect in container: + height = rect.get_height() + if height > 0: # Avoid labeling zero-height bars + x = rect.get_x() + rect.get_width() / 2 # Center of bar + y = rect.get_y() + height / 2 # Middle of segment + + if height < threshold: # Small segment -> place label outside + ax.annotate( + f'{round(height, 1)}', + xy=(x, rect.get_y() + height), # Arrow start + xytext=(x + 0.3, rect.get_y() + height + threshold), # Offset text + arrowprops=dict(arrowstyle="->", color='black', lw=0.8), + fontsize='small', ha='left', va='center', color='black' + ) + else: # Large segment -> label inside + ax.text(x, y, f'{round(height, 1)}', ha='center', va='center', fontsize='small', color='white') + + # Set custom x-tick labels if _scenario_dict is provided + if _scenario_dict: + labels = [_scenario_dict.get(label, label) for label in pivot_central.index] + else: + labels = pivot_central.index.astype(str) + + # Wrap x-tick labels for readability + wrapped_labels = [textwrap.fill(str(label), 20) for label in labels] + ax.set_xticklabels(wrapped_labels, rotation=45, ha='right', fontsize='small') + + # Period included for plot title and name + if _year == 'all': + period = (f"{min(_df_central['year'].unique())} - {max(_df_central['year'].unique())}") + elif (len(_year) == 1): + period = (f"{_year[0]}") + else: + period = (f"{min(_year)} - {max(_year)}") + + # Save plot + plt.xlabel('Scenario') + plt.ylabel('Cost (2023 USD), millions') + + # Arrange the legend in the same ascending order + handles, labels = plt.gca().get_legend_handles_labels() + plt.legend(handles[::-1], labels[::-1], bbox_to_anchor=(1.05, 0.7), loc='center left', fontsize='small') + + # Extend the y-axis by 25% + max_y = ax.get_ylim()[1] + ax.set_ylim(0, max_y*1.25) + + # Save the plot with tight layout + plt.tight_layout(pad=2.0) # Ensure there is enough space for the legend + plt.subplots_adjust(right=0.8) # Adjust to ensure legend doesn't overlap + + # Add gridlines and border + plt.grid(visible=True, which='major', linestyle='--', linewidth=0.5, color='gray') + #plt.rcParams['figure.facecolor'] = 'white' + plt.rcParams['figure.edgecolor'] = 'gray' + plt.rcParams['figure.frameon'] = True + + if show_title != False: + plt.title(f'Costs by Scenario \n (Cost Category = {_cost_category} ; Period = {period})') + plt.savefig(_outputfilepath / f'stacked_bar_chart_{_cost_category}_{period}{plt_name_suffix}{_add_figname_suffix}.png', dpi=100, + bbox_inches='tight') + plt.close() + +# 2. Line plots of total costs +#---------------------------------------------------- +# TODO: Check why line plot get save without a file name +def do_line_plot_of_cost(_df: pd.DataFrame, + _cost_category: Literal['all', 'human resources for health', 'medical consumables', + 'medical equipment', 'facility operating cost'] = 'all', + _year: list[int] ='all', + _draws: Optional[list[int]] = None, + disaggregate_by: Optional[Literal['cost_category', 'cost_subcategory', 'cost_subgroup']] = None, + _y_lim: Optional[float] = None, + show_title: bool = True, + _outputfilepath: Optional[Path] = None)-> None: + """ + Plot and save a line chart of cost trends over time by category or subcategory. + + Parameters: + ---------- + _df : pd.DataFrame + A cost summary DataFrame (usually from `estimate_input_cost_of_scenarios`) + containing columns like ['year', 'draw', 'cost', 'stat', 'cost_category', etc.]. + + _cost_category : str, default 'all' + If 'all', plots total cost across all categories. Otherwise, filters to a specific category. + + _year : str or list of int, default 'all' + Year(s) to include. Can be: + - 'all' to include all + - a single year or multiple years as a list: [2025] + + _draws : list of int, optional + If specified, filters to those draws. Required if `disaggregate_by` is set. + + disaggregate_by : {'cost_category', 'cost_subcategory', 'cost_subgroup'}, optional + Controls disaggregation on the plot + Note: If disaggregating, `_draws` must contain **only one draw**. + + _y_lim : float, optional + Custom upper limit for the y-axis. If None, uses automatic scaling. + + show_title : bool, default True + Whether to show the plot title. + + _outputfilepath : Path, optional + Directory where the plot image will be saved. Filename is auto-generated based on inputs. + + Returns: + ------- + None + Saves a PNG chart to `_outputfilepath`. + """ + + # Check what's the correct central metric to use (either 'mean' or 'median') + central_metric = [stat for stat in _df.stat.unique() if stat not in ['lower', 'upper']][0] + + # Validate disaggregation options + valid_disaggregations = ['cost_category', 'cost_subcategory', 'cost_subgroup'] + if disaggregate_by not in valid_disaggregations and disaggregate_by is not None: + raise ValueError(f"Invalid disaggregation option: {disaggregate_by}. Choose from {valid_disaggregations}.") + + # + if ((_draws is None) or (len(_draws) > 1)) & (disaggregate_by is not None): + raise ValueError(f"The disaggregate_by option only works if only one draw is plotted, for exmaple _draws = [0]") + + # Filter the dataframe by draws, if specified + subset_df = _df if _draws is None else _df[_df.draw.isin(_draws)] + + # Filter by year if specified + if _year != 'all': + subset_df = subset_df[subset_df['year'].isin(_year)] + + # Handle scenarios based on `_cost_category` and `disaggregate_by` conditions + if _cost_category == 'all': + if disaggregate_by == 'cost_subgroup': + raise ValueError("Cannot disaggregate by 'cost_subgroup' when `_cost_category='all'` due to data size.") + else: + # Filter subset_df by specific cost category if specified + subset_df = subset_df[subset_df['cost_category'] == _cost_category] + + # Set grouping columns based on the disaggregation level + if disaggregate_by == 'cost_category': + groupby_columns = ['year', 'cost_category'] + elif disaggregate_by == 'cost_subcategory': + groupby_columns = ['year', 'cost_subcategory'] + elif disaggregate_by == 'cost_subgroup': + # If disaggregating by 'cost_subgroup' and there are more than 10 subgroups, limit to the top 10 + "Other" + if len(subset_df['cost_subgroup'].unique()) > 10: + # Calculate total cost per subgroup + subgroup_totals = subset_df[subset_df.stat == central_metric].groupby('cost_subgroup')['cost'].sum() + # Identify the top 10 subgroups by cost + top_10_subgroups = subgroup_totals.nlargest(10).index.tolist() + # Reassign smaller subgroups to an "Other" category + subset_df['cost_subgroup'] = subset_df['cost_subgroup'].apply( + lambda x: x if x in top_10_subgroups else 'Other' + ) + groupby_columns = ['year', 'cost_subgroup'] + else: + groupby_columns = ['year'] + + # Extract central, lower, and upper values for the plot + central_values = subset_df[subset_df.stat == central_metric].groupby(groupby_columns)['cost'].sum() / 1e6 + lower_values = subset_df[subset_df.stat == 'lower'].groupby(groupby_columns)['cost'].sum() / 1e6 + upper_values = subset_df[subset_df.stat == 'upper'].groupby(groupby_columns)['cost'].sum() / 1e6 + + # Prepare to store lines and labels for the legend + lines = [] + labels = [] + + # Define a list of colors + if disaggregate_by == 'cost_category': + color_mapping = { + 'human resources for health': '#1f77b4', # Muted blue + 'medical consumables': '#ff7f0e', # Muted orange + 'medical equipment': '#2ca02c', # Muted green + 'other': '#d62728', # Muted red + 'facility operating cost': '#9467bd', # Muted purple + } + # Default color for unexpected categories + default_color = 'gray' + else: + # Define a list of colors to rotate through + colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'orange', 'purple', 'brown', 'gray'] # Add more colors as needed + color_cycle = iter(colors) # Create an iterator from the color list + + # Plot each line for the disaggregated values + if disaggregate_by: + for disaggregate_value in central_values.index.get_level_values(disaggregate_by).unique(): + # Get central, lower, and upper values for each disaggregated group + value_central = central_values.xs(disaggregate_value, level=disaggregate_by) + value_lower = lower_values.xs(disaggregate_value, level=disaggregate_by) + value_upper = upper_values.xs(disaggregate_value, level=disaggregate_by) + + if disaggregate_by == 'cost_category': + color = color_mapping.get(disaggregate_value, default_color) + else: + # Get the next color from the cycle + color = next(color_cycle) + + # Plot line for central and shaded region for 95% CI + line, = plt.plot(value_central.index, value_central, marker='o', linestyle='-', color=color, label=f'{disaggregate_value} - {central_metric}') + plt.fill_between(value_central.index, value_lower, value_upper, color=color, alpha=0.2) + + # Append to lines and labels for sorting later + lines.append(line) + labels.append(disaggregate_value) + else: + line, = plt.plot(central_values.index, central_values, marker='o', linestyle='-', color='b', label=central_metric) + plt.fill_between(central_values.index, lower_values, upper_values, color='b', alpha=0.2) + + # Append to lines and labels for sorting later + lines.append(line) + labels.append(central_metric) + + # Sort the legend based on total costs + total_costs = {label: central_values.xs(label, level=disaggregate_by).sum() for label in labels} + sorted_labels = sorted(total_costs.keys(), key=lambda x: total_costs[x]) + + # Reorder lines based on sorted labels + handles = [lines[labels.index(label)] for label in sorted_labels] + + # Define period for plot title + if _year == 'all': + period = f"{min(subset_df['year'].unique())} - {max(subset_df['year'].unique())}" + elif len(_year) == 1: + period = str(_year[0]) + else: + period = f"{min(_year)} - {max(_year)}" + + # Set labels, legend, and title + # Set y-axis limit if provided + if _y_lim is not None: + plt.ylim(0, _y_lim) + + # Add gridlines and border + plt.grid(visible=True, which='major', linestyle='--', linewidth=0.5, color='gray') + plt.xlabel('Year') + plt.ylabel('Cost (2023 USD), millions') + plt.legend(handles[::-1], sorted_labels[::-1], loc='upper right', bbox_to_anchor=(0.98, 0.98), framealpha=0.6) + if (show_title != False): + plot_title = f'Total input cost \n (Category = {_cost_category}, Period = {period})' + plt.title(plot_title) + + # Save plot with a proper filename + if disaggregate_by is None: + filename_suffix = "" + else: + filename_suffix = f"_by_{disaggregate_by}" + + draw_suffix = 'all' if _draws is None else str(_draws) + filename = f'trend_{_cost_category}_{period}{filename_suffix}_draw-{draw_suffix}.png' + plt.savefig(_outputfilepath / filename, dpi=100, bbox_inches='tight') + plt.close() + +# Treemap by category subgroup +#----------------------------------------------------------------------------------------------- +def create_summary_treemap_by_cost_subgroup(_df: pd.DataFrame, + _cost_category: Literal['human resources for health', 'medical consumables', + 'medical equipment', 'facility operating cost'], + _draw: Optional[list[int]] = None, + _year: list[int] = 'all', + _color_map: Optional[dict[str, str]] = None, + _label_fontsize: int = 10, + show_title: bool = True, + _outputfilepath: Optional[Path] = None) -> None: + """ + Generate and save a treemap visualizing cost composition by subgroup within a cost category. + + Parameters: + ---------- + _df : pd.DataFrame + DataFrame of costs with columns: ['cost_category', 'cost_subgroup', 'draw', 'year', 'cost']. + Typically output from `estimate_input_cost_of_scenarios`. + + _cost_category : str, required + The high-level cost category to visualize (e.g., 'human resources for health', + 'medical consumables', 'medical equipment', 'facility operating cost'). + + _draw : int, optional + Specific draw to visualize. If None, uses the full dataset. + + _year : str or list of int, default 'all' + Year or list of years to include in the treemap. If 'all', includes all available years. + + _color_map : dict, optional + Dictionary mapping cost subgroups to specific colors. If None, a default colormap is used. + eg. _color_map = {'First-line ART regimen: adult':'#1f77b4', + 'Test, HIV EIA Elisa': '#ff7f0e', + 'VL Test': '#2ca02c'} + + _label_fontsize : int, default 10 + Font size used for labels inside treemap tiles. + + show_title : bool, default True + Whether to display a plot title. + + _outputfilepath : Path, optional + Directory where the treemap image should be saved. + + Returns: + ------- + None + Saves the treemap as a PNG file named `treemap_{category}_{draw}_{period}.png`. + """ + # Function to wrap text to fit within treemap rectangles + def wrap_text(text, width=15): + return "\n".join(textwrap.wrap(text, width)) + + valid_cost_categories = ['human resources for health', 'medical consumables', + 'medical equipment', 'facility operating cost'] + if _cost_category == None: + raise ValueError(f"Specify one of the following as _cost_category - {valid_cost_categories})") + elif _cost_category not in valid_cost_categories: + raise ValueError(f"Invalid input for _cost_category: '{_cost_category}'. " + f"Specify one of the following - {valid_cost_categories})") + else: + _df = _df[_df['cost_category'] == _cost_category] + + if _draw != None: + _df = _df[_df.draw == _draw] + + # Remove non-specific subgroup for consumables + if _cost_category == 'medical consumables': + _df = _df[~(_df.cost_subgroup == 'supply chain (all consumables)')] + + # Create summary dataframe for treemap + _df = _df.groupby('cost_subgroup')['cost'].sum().reset_index() + _df = _df.sort_values(by="cost", ascending=False) + top_10 = _df.iloc[:10] + + if (len(_df['cost_subgroup'].unique()) > 10): + # Step 2: Group all other consumables into "Other" + other_cost = _df.iloc[10:]["cost"].sum() + top_10 = pd.concat([top_10, pd.DataFrame([{"cost_subgroup": "Other", "cost": other_cost}])], ignore_index=True) + + # Prepare data for the treemap + total_cost = top_10["cost"].sum() + top_10["proportion"] = top_10["cost"]/total_cost + sizes = top_10["cost"] + + # Handle color map + if _color_map is None: + # Generate automatic colors if no color map is provided + auto_colors = plt.cm.Paired.colors + color_cycle = cycle(auto_colors) # Cycle through the automatic colors + color_map = {subgroup: next(color_cycle) for subgroup in top_10["cost_subgroup"]} + else: + # Use the provided color map, fallback to a default color for missing subgroups + fallback_color = '#cccccc' + color_map = {subgroup: _color_map.get(subgroup, fallback_color) for subgroup in top_10["cost_subgroup"]} + + # Get colors for each subgroup + colors = [color_map[subgroup] for subgroup in top_10["cost_subgroup"]] + + # Exclude labels for small proportions + labels = [ + f"{wrap_text(name)}\n${round(cost, 1)}m\n({round(prop * 100, 1)}%)" + if prop >= 0.01 else "" + for name, cost, prop in zip(top_10["cost_subgroup"], top_10["cost"] / 1e6, top_10["proportion"]) + ] + # Period included for plot title and name + if _year == 'all': + period = (f"{min(_df['year'].unique())} - {max(_df['year'].unique())}") + elif (len(_year) == 1): + period = (f"{_year[0]}") + else: + period = (f"{min(_year)} - {max(_year)}") + + # Plot the treemap + plt.figure(figsize=(12, 8)) + squarify.plot(sizes=sizes, label=labels, alpha=0.8, color=colors, text_kwargs={'fontsize': _label_fontsize}) + plt.axis("off") + if (show_title != False): + plt.title(f'{_cost_category} ; Period = {period}') + + plt.savefig(_outputfilepath / f'treemap_{_cost_category}_[{_draw}]_{period}.png', + dpi=100, + bbox_inches='tight') + plt.close() + +# Plot ROI +def generate_multiple_scenarios_roi_plot( _monetary_value_of_incremental_health: pd.DataFrame, + _incremental_input_cost: pd.DataFrame, + _outputfilepath: Path, + _draws: list[int], + _scenario_dict: dict[int, str], + _metric: str = 'mean', + _y_axis_lim: Optional[float] = None, + _plot_vertical_lines_at: Optional[list[int]] = None, + _projected_health_spending: Optional[float] = None, + _draw_colors: Optional[dict[int, str]] = None, + _value_of_life_suffix: str = '', + _year_suffix: str = '', + show_title_and_legend: Optional[bool] = True) -> None: + """ + Generate and save ROI plots for multiple scenarios, showing returns over a range of implementation costs. + + Parameters: + ---------- + _monetary_value_of_incremental_health : pd.DataFrame + DataFrame with index (draw, run), containing monetary values of health benefits. + This can be estimated as (_num_dalys_averted_by_scenario * _chosen_value_of_life_year).clip(lower=0.0) + + _incremental_input_cost : pd.DataFrame + DataFrame with index (draw, run), containing incremental costs for each scenario. + + _outputfilepath : Path + Path to the output folder where plots will be saved. + + _draws : list of int, required + List of draw indices to include in the plot. + + _scenario_dict : dict of {int: str}, required + Mapping from draw index to scenario name, used for plot labeling. + + _metric : {'mean', 'median'}, default 'mean' + Central tendency to use when summarizing ROI across runs. + + _y_axis_lim : float, optional + Y-axis upper limit. If None, scales based on the maximum ROI value. + + _plot_vertical_lines_at : list of int, optional + If specified, vertical dashed lines are drawn at these implementation cost values (in USD). + Annotates ROI ratio across scenarios at those points. + + _projected_health_spending : float, optional + Used to annotate x-axis values as % of total projected health spending + Can be estimated using the function estimate_projected_health_spending, but a single value will need to be taken + eg. mean value for the baseline scenario. + + _draw_colors : dict of {int: str}, optional + Custom colors to use for each scenario/draw. + + _value_of_life_suffix : str, default '' + Suffix added to the filename to reflect the assumed value of life (e.g., DALY monetization label). + + _year_suffix : str, default '' + Optional suffix to add to the filename or plot title to indicate year range. + + show_title_and_legend : bool, default True + Whether to include the plot title and legend. + + Returns: + ------- + None + Saves a PNG file visualizing ROI vs. implementation cost for each scenario. + """ + if _metric not in ['mean', 'median']: + raise ValueError(f"Invalid input for _metric: '{_metric}'. " + f"Values need to be one of 'mean' or 'median'") + + # Default color mapping if not provided + if _draw_colors is None: + _draw_colors = {draw: color for draw, color in zip(_draws, plt.cm.tab10.colors[:len(_draws)])} + + # Calculate maximum ability to pay for implementation + _monetary_value_of_incremental_health = _monetary_value_of_incremental_health[_monetary_value_of_incremental_health.index.get_level_values('draw').isin(_draws)] + _incremental_input_cost = _incremental_input_cost[_incremental_input_cost.index.get_level_values('draw').isin(_draws)] + max_ability_to_pay_for_implementation = (_monetary_value_of_incremental_health - _incremental_input_cost).clip(lower=0.0) # monetary value - change in costs + + # Create a figure and axis to plot all draws together + fig, ax = plt.subplots(figsize=(10, 6)) + + # Store ROI values for specific costs + max_roi = [] + roi_at_costs = {cost: [] for cost in (_plot_vertical_lines_at or [])} + + # Iterate over each draw in monetary_value_of_incremental_health + for draw_index, row in _monetary_value_of_incremental_health.iterrows(): + print("Plotting ROI for draw ", draw_index) + # Initialize an empty DataFrame to store values for each 'run' + all_run_values = pd.DataFrame() + + # Create an array of implementation costs ranging from 0 to the max value of max ability to pay for the current draw + implementation_costs = np.linspace(0, max_ability_to_pay_for_implementation.loc[draw_index].max(), 50) + # Add fixed values for ROI ratio calculation + additional_costs = np.array([1_000_000_000, 3_000_000_000]) + implementation_costs = np.sort(np.unique(np.concatenate([implementation_costs, additional_costs]))) + + # Retrieve the corresponding row from incremental_scenario_cost for the same draw + incremental_scenario_cost_row = _incremental_input_cost.loc[draw_index] + + # Calculate the values for each individual run + for run in incremental_scenario_cost_row.index: # Assuming 'run' columns are labeled by numbers + # Calculate the total costs for the current run + total_costs = implementation_costs + incremental_scenario_cost_row[run] + + # Initialize run_values as an empty series with the same index as total_costs + run_values = pd.Series(index=total_costs, dtype=float) + + # For negative total_costs, set corresponding run_values to infinity + run_values[total_costs < 0] = np.inf + + # For non-negative total_costs, calculate the metric and clip at 0 + non_negative_mask = total_costs >= 0 + run_values[non_negative_mask] = np.clip( + (row[run] - total_costs[non_negative_mask]) / total_costs[non_negative_mask], + 0, + None + ) + + # Create a DataFrame with index as (draw_index, run) and columns as implementation costs + run_values = run_values.values # remove index and convert to array + run_df = pd.DataFrame([run_values], index=pd.MultiIndex.from_tuples([(draw_index, run)], names=['draw', 'run']), + columns=implementation_costs) + + # Append the run DataFrame to all_run_values + all_run_values = pd.concat([all_run_values, run_df]) + + # Replace inf with NaN temporarily to handle quantile calculation correctly + temp_data = all_run_values.replace([np.inf, -np.inf], np.nan) + + collapsed_data = temp_data.groupby(level='draw').agg([ + _metric, + ('lower', lambda x: x.quantile(0.025)), + ('upper', lambda x: x.quantile(0.975)) + ]) + + # Revert the NaNs back to inf + collapsed_data = collapsed_data.replace([np.nan], np.inf) + + collapsed_data = collapsed_data.unstack() + collapsed_data.index = collapsed_data.index.set_names('implementation_cost', level=0) + collapsed_data.index = collapsed_data.index.set_names('stat', level=1) + collapsed_data = collapsed_data.reset_index().rename(columns = {0: 'roi'}) + + # Divide rows by the sum of implementation costs and incremental input cost + central_values = collapsed_data[collapsed_data['stat'] == _metric][['implementation_cost', 'roi']] + lower_values = collapsed_data[collapsed_data['stat'] == 'lower'][['implementation_cost', 'roi']] + upper_values = collapsed_data[collapsed_data['stat'] == 'upper'][['implementation_cost', 'roi']] + + # Plot central line and confidence interval + ax.plot( + implementation_costs / 1e6, + central_values['roi'], + label=f'{_scenario_dict[draw_index]}', + color=_draw_colors.get(draw_index, 'black'), + ) + ax.fill_between( + implementation_costs / 1e6, + lower_values['roi'], + upper_values['roi'], + alpha=0.2, + color=_draw_colors.get(draw_index, 'black'), + ) + + max_val = central_values[~np.isinf(central_values['roi'])]['roi'].max() + max_roi.append(max_val) + + # Capture ROI at specific costs + if _plot_vertical_lines_at: + for cost in _plot_vertical_lines_at: + roi_value = collapsed_data[ + (collapsed_data.implementation_cost == cost) & + (collapsed_data.stat == _metric) + ]['roi'] + if not roi_value.empty: + roi_at_costs[cost].append(roi_value.iloc[0]) + + # Calculate and annotate ROI ratios + if _plot_vertical_lines_at: + for cost in _plot_vertical_lines_at: + if cost in roi_at_costs: + ratio = max(roi_at_costs[cost]) / min(roi_at_costs[cost]) + ax.axvline(x=cost / 1e6, color='black', linestyle='--', linewidth=1) + ax.text(cost / 1e6 + ax.get_xlim()[1] * 0.011, ax.get_ylim()[1] * 0.75, + f'At ${cost / 1e6:.0f}M, ratio of ROI curves = {round(ratio, 2)}', + color='black', fontsize=10, rotation=90, verticalalignment='top') + + # Define fixed x-tick positions with a gap of 2000 + step_size = (ax.get_xlim()[1] - 0)/5 + xticks = np.arange(0, ax.get_xlim()[1] + 1, int(round(step_size, -3))) # From 0 to max x-limit with 5 steps + # Get labels + xtick_labels = [f'{tick:,.0f}' for tick in xticks] # Default labels for all ticks + + # Replace specific x-ticks with % of health spending values + if _projected_health_spending: + xtick_labels[1] = f'{xticks[1]:,.0f}\n({xticks[1] / (_projected_health_spending / 1e6) :.2%} of \n projected total \n health spend)' + for i, tick in enumerate(xticks): + if (i != 0) & (i != 1): # Replace for 4000 + xtick_labels[i] = f'{tick:,.0f}\n({tick / (_projected_health_spending/1e6) :.2%})' + + # Update the x-ticks and labels + ax.set_xticks(xticks) + ax.set_xticklabels(xtick_labels, fontsize=10) + + # Set y-axis limit + if _y_axis_lim == None: + ax.set_ylim(0, max(max_roi) * 1.25) + else: + ax.set_ylim(0, _y_axis_lim) + ax.set_xlim(left = 0) + + plt.xlabel('Implementation cost, USD millions') + plt.ylabel('Return on Investment') + + # Show legend and title + if (show_title_and_legend != False): + plt.title(f'Return on Investment at different levels of implementation cost{_year_suffix}') + plt.legend() + + # Add gridlines and border + plt.grid(False) + fig.patch.set_facecolor("white") # White background for the entire figure + + # Save + plt.savefig(_outputfilepath / f'draws_{_draws}_ROI_at_{_value_of_life_suffix}_{_year_suffix}.png', dpi=100, + bbox_inches='tight') + plt.close() + +def tabulated_roi_estimates(_monetary_value_of_incremental_health: pd.DataFrame, + _incremental_input_cost: pd.DataFrame, + _draws: Optional[list[int]] = None, + _metric: Literal['mean', 'median'] = 'mean') -> pd.DataFrame: + """ + Compute ROI estimates in tabular form for multiple scenarios and implementation costs. + + For each draw, calculates ROI at various hypothetical implementation cost levels. + ROI is defined as: (monetary value of health gain - total cost) / total cost. + + Parameters: + ---------- + _monetary_value_of_incremental_health : pd.DataFrame + DataFrame indexed by [draw, run], with estimated monetary values of health gain. + + _incremental_input_cost : pd.DataFrame + DataFrame indexed by [draw, run], with estimated incremental scenario costs. + + _draws : list of int + Draw indices to include in the tabulation. + + _metric : {'mean', 'median'}, default 'mean' + Summary statistic to compute across runs. Also includes 2.5th and 97.5th percentiles. + + Returns: + ------- + pd.DataFrame + Long-format DataFrame with: + - 'implementation_cost' (in USD) + - 'stat' ('mean', 'lower', 'upper') + - 'roi' (return on investment) + + Includes results for all requested draws and implementation cost levels - the implementation cost levels + used are based on max_ability_to_pay_for_implementation calculated within the function - at this level + of incremental scenario cost + implementation cost, ROI should be 0. + """ + + # Calculate maximum ability to pay for implementation + _monetary_value_of_incremental_health = _monetary_value_of_incremental_health[_monetary_value_of_incremental_health.index.get_level_values('draw').isin(_draws)] + _incremental_input_cost = _incremental_input_cost[_incremental_input_cost.index.get_level_values('draw').isin(_draws)] + max_ability_to_pay_for_implementation = (_monetary_value_of_incremental_health - _incremental_input_cost).clip(lower=0.0) # monetary value - change in costs + + roi_df = pd.DataFrame() + + # Create an array of implementation costs ranging from 0 to the max value of max ability to pay for the current draw + max_ability_to_pay_for_implementation_rounded_value = math.ceil(max_ability_to_pay_for_implementation.max().max() / 1_000_000_000) * 1_000_000_000 + implementation_costs = np.linspace(0, max_ability_to_pay_for_implementation_rounded_value, 20) + implementation_costs = np.ceil(implementation_costs / 1_000_000_000) * 1_000_000_000 # Round each to nearest billion + + # Iterate over each draw in monetary_value_of_incremental_health + for draw_index, row in _monetary_value_of_incremental_health.iterrows(): + print("Tablulating ROI for draw ", draw_index) + # Initialize an empty DataFrame to store values for each 'run' + all_run_values = pd.DataFrame() + + # Retrieve the corresponding row from incremental_scenario_cost for the same draw + incremental_scenario_cost_row = _incremental_input_cost.loc[draw_index] + + # Calculate the values for each individual run + for run in incremental_scenario_cost_row.index: # Assuming 'run' columns are labeled by numbers + # Calculate the total costs for the current run + total_costs = implementation_costs + incremental_scenario_cost_row[run] + + # Initialize run_values as an empty series with the same index as total_costs + run_values = pd.Series(index=total_costs, dtype=float) + + # For negative total_costs, set corresponding run_values to infinity + run_values[total_costs < 0] = np.inf + + # For non-negative total_costs, calculate the metric and clip at 0 + non_negative_mask = total_costs >= 0 + run_values[non_negative_mask] = (row[run] - total_costs[non_negative_mask]) / total_costs[non_negative_mask] + + # Create a DataFrame with index as (draw_index, run) and columns as implementation costs + run_values = run_values.values # remove index and convert to array + run_df = pd.DataFrame([run_values], index=pd.MultiIndex.from_tuples([(draw_index, run)], names=['draw', 'run']), + columns=implementation_costs) + + # Append the run DataFrame to all_run_values + all_run_values = pd.concat([all_run_values, run_df]) + + # Replace inf with NaN temporarily to handle quantile calculation correctly + temp_data = all_run_values.replace([np.inf, -np.inf], np.nan) + + collapsed_data = temp_data.groupby(level='draw').agg([ + _metric, + ('lower', lambda x: x.quantile(0.025)), + ('upper', lambda x: x.quantile(0.975)) + ]) + + # Revert the NaNs back to inf + collapsed_data = collapsed_data.replace([np.nan], np.inf) + + collapsed_data = collapsed_data.unstack() + collapsed_data.index = collapsed_data.index.set_names('implementation_cost', level=0) + collapsed_data.index = collapsed_data.index.set_names('stat', level=1) + collapsed_data = collapsed_data.reset_index().rename(columns = {0: 'roi'}) + + if roi_df.empty: + roi_df = collapsed_data + else: + roi_df = pd.concat([roi_df, collapsed_data], ignore_index=True) + return roi_df diff --git a/src/scripts/costing/costing_overview_analysis.py b/src/scripts/costing/costing_overview_analysis.py new file mode 100644 index 0000000000..a2bd46ad2d --- /dev/null +++ b/src/scripts/costing/costing_overview_analysis.py @@ -0,0 +1,371 @@ +"""Produce outputs for cost overview paper. +The draft version of the paper uses outputs from scenario_impact_of_healthsystem.py, used to model HSS scenarios for +FCDO and Global Fund. + +with reduced consumables logging +/Users/tmangal/PycharmProjects/TLOmodel/outputs/t.mangal@imperial.ac.uk/hss_elements-2024-11-12T172311Z +""" + +from pathlib import Path +from tlo import Date + +import datetime +import os +import textwrap + +import matplotlib.pyplot as plt +import seaborn as sns +import numpy as np +import pandas as pd +from itertools import cycle +import jinja2 # This is for the latex table + +from tlo.analysis.utils import ( + extract_params, + get_scenario_info, + get_scenario_outputs, + load_pickled_dataframes, +) + +from scripts.costing.cost_estimation import (estimate_input_cost_of_scenarios, + summarize_cost_data, + do_stacked_bar_plot_of_cost_by_category, + do_line_plot_of_cost, + create_summary_treemap_by_cost_subgroup, + estimate_projected_health_spending) + +# Define a timestamp for script outputs +timestamp = datetime.datetime.now().strftime("_%Y_%m_%d_%H_%M") + +# Print the start time of the script +print('Script Start', datetime.datetime.now().strftime('%H:%M')) + +# Create folders to store results +resourcefilepath = Path("./resources") +outputfilepath = Path('./outputs/t.mangal@imperial.ac.uk') +figurespath = Path('./outputs/costing/overview/') +if not os.path.exists(figurespath): + os.makedirs(figurespath) + +# Load result files +# ------------------------------------------------------------------------------------------------------------------ +results_folder = get_scenario_outputs('htm_and_hss_runs-2025-01-16T135243Z.py', outputfilepath)[0] # January 2025 runs + +# Check can read results from draw=0, run=0 +log = load_pickled_dataframes(results_folder, 0, 0) # look at one log (so can decide what to extract) +params = extract_params(results_folder) +info = get_scenario_info(results_folder) + +# Declare default parameters for cost analysis +# ------------------------------------------------------------------------------------------------------------------ +# Period relevant for costing +TARGET_PERIOD = (Date(2023, 1, 1), Date(2030, 12, 31)) # This is the period that is costed +relevant_period_for_costing = [i.year for i in TARGET_PERIOD] +list_of_relevant_years_for_costing = list(range(relevant_period_for_costing[0], relevant_period_for_costing[1] + 1)) +list_of_years_for_plot = list(range(2023, 2031)) +number_of_years_costed = relevant_period_for_costing[1] - 2023 + 1 + +# Scenarios +cost_scenarios = {0: "Actual", 3: "Expanded HRH", 5: "Improved consumable availability", + 8: "Expanded HRH + Improved consumable availability"} + +# Costing parameters +discount_rate = 0.03 +discount_rate_lomas = {2023: 0.0036, 2024: 0.0040, 2025: 0.0039, 2026: 0.0042, 2027: 0.0042, 2028: 0.0041, + 2029: 0.0041, 2030: 0.0040}# get the list of discount rates from 2023 until 2030 + +# Estimate standard input costs of scenario +# ----------------------------------------------------------------------------------------------------------------------- +# Standard 3% discount rate +input_costs = estimate_input_cost_of_scenarios(results_folder, resourcefilepath, _draws = [0, 3, 5, 8], + _years=list_of_relevant_years_for_costing, cost_only_used_staff=True, + _discount_rate = discount_rate, summarize = True) + +# Undiscounted costs +input_costs_undiscounted = estimate_input_cost_of_scenarios(results_folder, resourcefilepath, _draws = [0, 3, 5, 8], + _years=list_of_relevant_years_for_costing, cost_only_used_staff=True, + _discount_rate = 0, summarize = True) + +# Cost with variable discount rate based on Lomas et al (2021) +input_costs_variable_discounting = estimate_input_cost_of_scenarios(results_folder, resourcefilepath, _draws = [0, 3, 5, 8], + _years=list_of_relevant_years_for_costing, cost_only_used_staff=True, + _discount_rate = discount_rate_lomas, summarize = True) + +# Get overall estimates for main text +# ----------------------------------------------------------------------------------------------------------------------- +cost_by_draw = input_costs.groupby(['draw', 'stat'])['cost'].sum() +undiscounted_cost_by_draw = input_costs_undiscounted.groupby(['draw', 'stat'])['cost'].sum() + +# Abstract +print(f"Under current system capacity, total healthcare delivery costs for 2023–2030 were estimated at \$" + f"{cost_by_draw[0,'mean']/1e9:,.2f} billion [95\% confidence interval (CI), \${cost_by_draw[0,'lower']/1e9:,.2f}b - \${cost_by_draw[0,'upper']/1e9:,.2f}b], averaging \$" + f"{undiscounted_cost_by_draw[0,'mean']/1e6/number_of_years_costed:,.2f} million [\${undiscounted_cost_by_draw[0,'lower']/1e6/number_of_years_costed:,.2f}m - \${undiscounted_cost_by_draw[0,'upper']/1e6/number_of_years_costed:,.2f}m] annually.") +# Results 1 +print(f"The total cost of healthcare delivery in Malawi between 2023 and 2030 was estimated to be " + f"\${cost_by_draw[0,'mean']/1e9:,.2f} billion [95\% confidence interval (CI), \${cost_by_draw[0,'lower']/1e9:,.2f}b - \${cost_by_draw[0,'upper']/1e9:,.2f}b], under the actual scenario, and increased to " + f"\${cost_by_draw[5,'mean']/1e9:,.2f} billion [\${cost_by_draw[5,'lower']/1e9:,.2f}b - \${cost_by_draw[5,'upper']/1e9:,.2f}b] under the improved consumable availability scenario, " + f"followed by \${cost_by_draw[3,'mean']/1e9:,.2f} billion [\${cost_by_draw[3,'lower']/1e9:,.2f}b - \${cost_by_draw[3,'upper']/1e9:,.2f}b] under the expanded HRH scenario and finally " + f"\${cost_by_draw[8,'mean']/1e9:,.2f} billion [\${cost_by_draw[8,'lower']/1e9:,.2f}b - \${cost_by_draw[8,'upper']/1e9:,.2f}b] under the expanded HRH + improved consumable availability scenario.") +# Results 2 +print(f"This translates to an average annual cost of " + f"\${undiscounted_cost_by_draw[0,'mean']/1e6/number_of_years_costed:,.2f} million [\${undiscounted_cost_by_draw[0,'lower']/1e6/number_of_years_costed:,.2f}m - \${undiscounted_cost_by_draw[0,'upper']/1e6/number_of_years_costed:,.2f}m], under the actual scenario, " + f"\${undiscounted_cost_by_draw[5,'mean']/1e6/number_of_years_costed:,.2f} million [\${undiscounted_cost_by_draw[5,'lower']/1e6/number_of_years_costed:,.2f}m - \${undiscounted_cost_by_draw[5,'upper']/1e6/number_of_years_costed:,.2f}m] under the improved consumable availability scenario, followed by " + f"\${undiscounted_cost_by_draw[3,'mean']/1e6/number_of_years_costed:,.2f} million [\${undiscounted_cost_by_draw[3,'lower']/1e6/number_of_years_costed:,.2f}m - \${undiscounted_cost_by_draw[3,'upper']/1e6/number_of_years_costed:,.2f}m] under the expanded HRH scenario and finally " + f"\${undiscounted_cost_by_draw[8,'mean']/1e6/number_of_years_costed:,.2f} million [\${undiscounted_cost_by_draw[8,'lower']/1e6/number_of_years_costed:,.2f}m - \${undiscounted_cost_by_draw[8,'upper']/1e6/number_of_years_costed:,.2f}m] under the expanded HRH + improved consumable availability scenario.") +# Results 3 +consumable_cost_by_draw = input_costs[(input_costs.cost_category == 'medical consumables') & (input_costs.stat == 'mean')].groupby(['draw'])['cost'].sum() +print(f"Notably, improving consumable availability alone increases the cost of medical consumables by just " + f"{(consumable_cost_by_draw[5]/consumable_cost_by_draw[0] - 1) * 100:.2f}\% " + f"because the limited health workforce (HRH) restricts the number of feasible appointments and, consequently, the quantity of consumables dispensed. " + f"In contrast, expanding HRH alone raises consumable costs by " + f"{(consumable_cost_by_draw[3]/consumable_cost_by_draw[0] - 1) * 100:.2f}\%" + f". When both HRH and consumable availability are expanded together, consumable costs increase by " + f"{(consumable_cost_by_draw[8]/consumable_cost_by_draw[0] - 1) * 100:.2f}\% " + f"compared to the actual scenario.") +# Results 4 +cost_of_hiv_testing = input_costs[(input_costs.cost_subgroup == 'Test, HIV EIA Elisa') & (input_costs.stat == 'mean')].groupby(['draw'])['cost'].sum() +print(f"For instance, the cost of HIV testing consumables increases by {(cost_of_hiv_testing[3]/cost_of_hiv_testing[0] - 1)*100:.2f}\% under the expanded HRH scenario and by " + f"{(cost_of_hiv_testing[8]/cost_of_hiv_testing[0] - 1)*100:.2f}\% under the combined expanded HRH and improved consumable availability scenario, " + f"while showing almost no change under the scenario with improved consumable availability alone") + +# Get figures for overview paper +# ----------------------------------------------------------------------------------------------------------------------- +# Figure 2: Estimated costs by cost category +do_stacked_bar_plot_of_cost_by_category(_df = input_costs, _cost_category = 'all', _disaggregate_by_subgroup = False, + _year = list_of_relevant_years_for_costing,show_title = False, + _outputfilepath = figurespath, _scenario_dict = cost_scenarios) + +revised_consumable_subcategories = {'cost_of_separately_managed_medical_supplies_dispensed':'cost_of_consumables_dispensed', 'cost_of_excess_separately_managed_medical_supplies_stocked': 'cost_of_excess_consumables_stocked', 'supply_chain':'supply_chain'} +input_costs_new = input_costs.copy() +input_costs_new['cost_subcategory'] = input_costs_new['cost_subcategory'].map(revised_consumable_subcategories).fillna(input_costs_new['cost_subcategory']) + +# Figure 3: Estimated costs by cost sub-category +do_stacked_bar_plot_of_cost_by_category(_df = input_costs_new, _cost_category = 'medical consumables', _disaggregate_by_subgroup = False, + _year = list_of_years_for_plot, show_title = False, + _outputfilepath = figurespath, _scenario_dict = cost_scenarios) +do_stacked_bar_plot_of_cost_by_category(_df = input_costs, _cost_category = 'human resources for health', _disaggregate_by_subgroup = False, + _year = list_of_years_for_plot, show_title = False, + _outputfilepath = figurespath, _scenario_dict = cost_scenarios) +do_stacked_bar_plot_of_cost_by_category(_df = input_costs, _cost_category = 'medical equipment', _disaggregate_by_subgroup = False, + _year = list_of_years_for_plot, show_title = False, + _outputfilepath = figurespath, _scenario_dict = cost_scenarios) +do_stacked_bar_plot_of_cost_by_category(_df = input_costs, _cost_category = 'facility operating cost', _disaggregate_by_subgroup = False, + _year = list_of_years_for_plot, show_title = False, + _outputfilepath = figurespath, _scenario_dict = cost_scenarios) + + +# Figure 4: Estimated costs by year +do_line_plot_of_cost(_df = input_costs_undiscounted, _cost_category='all', + _year=list_of_years_for_plot, _draws= [0], + disaggregate_by= 'cost_category', + _y_lim = 400, + show_title = False, + _outputfilepath = figurespath) +do_line_plot_of_cost(_df = input_costs_undiscounted, _cost_category='all', + _year=list_of_years_for_plot, _draws= [3], + disaggregate_by= 'cost_category', + _y_lim = 400, + show_title = False, + _outputfilepath = figurespath) +do_line_plot_of_cost(_df = input_costs_undiscounted, _cost_category='all', + _year=list_of_years_for_plot, _draws= [5], + disaggregate_by= 'cost_category', + _y_lim = 400, + show_title = False, + _outputfilepath = figurespath) +do_line_plot_of_cost(_df = input_costs_undiscounted, _cost_category='all', + _year=list_of_years_for_plot, _draws= [8], + disaggregate_by= 'cost_category', + _y_lim = 400, + show_title = False, + _outputfilepath = figurespath) + +# Figure D1: Total cost by scenario assuming 0% discount rate +do_stacked_bar_plot_of_cost_by_category(_df = input_costs_undiscounted, + _cost_category = 'all', + _year=list_of_years_for_plot, + _disaggregate_by_subgroup = False, + _outputfilepath = figurespath, + _scenario_dict = cost_scenarios, + _add_figname_suffix = '_UNDISCOUNTED') + +# Figure D2: Total cost by scenario assuming variable discount rates +do_stacked_bar_plot_of_cost_by_category(_df = input_costs_variable_discounting, + _cost_category = 'all', + _year=list_of_years_for_plot, + _disaggregate_by_subgroup = False, + _outputfilepath = figurespath, + _scenario_dict = cost_scenarios, + _add_figname_suffix = '_VARIABLE_DISCOUNTING') + + +# Figure F1-F4: Cost by cost sub-group +cost_categories = ['human resources for health', 'medical consumables', + 'medical equipment', 'facility operating cost'] +draws = input_costs.draw.unique().tolist() +colourmap_for_consumables = {'First-line ART regimen: adult':'#1f77b4', + 'Test, HIV EIA Elisa': '#ff7f0e', + 'VL Test': '#2ca02c', + 'Depot-Medroxyprogesterone Acetate 150 mg - 3 monthly': '#d62728', + 'Oxygen, 1000 liters, primarily with oxygen cylinders': '#9467bd', + 'Phenobarbital, 100 mg': '#8c564b', + 'Rotavirus vaccine': '#e377c2', + 'Carbamazepine 200mg_1000_CMST': '#7f7f7f', + 'Infant resuscitator, clear plastic + mask + bag_each_CMST': '#bcbd22', + 'Dietary supplements (country-specific)': '#17becf', + 'Tenofovir (TDF)/Emtricitabine (FTC), tablet, 300/200 mg': '#2b8cbe', + 'Pneumococcal vaccine': '#fdae61', + 'Pentavalent vaccine (DPT, Hep B, Hib)': '#d73027', + 'male circumcision kit, consumables (10 procedures)_1_IDA': '#756bb1', + 'Jadelle (implant), box of 2_CMST': '#ffdd44', + 'Urine analysis': '#66c2a5'} + +for _cat in cost_categories: + for _d in draws: + if _cat == 'medical consumables': + create_summary_treemap_by_cost_subgroup(_df = input_costs, _year = list_of_years_for_plot, + _cost_category = _cat, _draw = _d, _color_map=colourmap_for_consumables, + show_title= False, _label_fontsize= 8, _outputfilepath=figurespath) + else: + create_summary_treemap_by_cost_subgroup(_df=input_costs, _year=list_of_years_for_plot, + _cost_category=_cat, _draw=_d, show_title= False, + _label_fontsize= 8.5, _outputfilepath=figurespath) + + +# Get tables for overview paper +# ----------------------------------------------------------------------------------------------------------------------- +# Group data and aggregate cost for each draw and stat +def generate_detail_cost_table(_groupby_var, _groupby_var_name, _longtable = False): + edited_input_costs = input_costs.copy() + edited_input_costs[_groupby_var] = edited_input_costs[_groupby_var].replace('_', ' ', regex=True) + edited_input_costs[_groupby_var] = edited_input_costs[_groupby_var].replace('%', '\%', regex=True) + edited_input_costs[_groupby_var] = edited_input_costs[_groupby_var].replace('&', '\&', regex=True) + + grouped_costs = edited_input_costs.groupby(['cost_category', _groupby_var, 'draw', 'stat'])['cost'].sum() + # Format the 'cost' values before creating the LaTeX table + grouped_costs = grouped_costs.apply(lambda x: f"{float(x):,.0f}") + # Remove underscores from all column values + + # Create a pivot table to restructure the data for LaTeX output + pivot_data = {} + for draw in [0, 3, 5, 8]: + draw_data = grouped_costs.xs(draw, level='draw').unstack(fill_value=0) # Unstack to get 'stat' as columns + # Concatenate 'mean' with 'lower-upper' in the required format + pivot_data[draw] = draw_data['mean'].astype(str) + ' [' + \ + draw_data['lower'].astype(str) + '-' + \ + draw_data['upper'].astype(str) + ']' + + # Combine draw data into a single DataFrame + table_data = pd.concat([pivot_data[0], pivot_data[3], pivot_data[5], pivot_data[8]], axis=1, keys=['draw=0', 'draw=3', 'draw=5', 'draw=8']).reset_index() + + # Rename columns for clarity + table_data.columns = ['Cost Category', _groupby_var_name, 'Actual', 'Expanded HRH', 'Improved consumable availability', 'Expanded HRH +\n Improved consumable availability'] + + # Replace '\n' with '\\' for LaTeX line breaks + #table_data['Real World'] = table_data['Real World'].apply(lambda x: x.replace("\n", "\\\\")) + #table_data['Perfect Health System'] = table_data['Perfect Health System'].apply(lambda x: x.replace("\n", "\\\\")) + + # Convert to LaTeX format with horizontal lines after every row + latex_table = table_data.to_latex( + longtable=_longtable, # Use the longtable environment for large tables + column_format='|R{3cm}|R{3cm}|R{2.2cm}|R{2.2cm}|R{2.2cm}|R{2.2cm}|', + caption=f"Summarized Costs by Category and {_groupby_var_name}", + label=f"tab:cost_by_{_groupby_var}", + position="h", + index=False, + escape=False, # Prevent escaping special characters like \n + header=True + ) + + # Add \hline after the header and after every row for horizontal lines + latex_table = latex_table.replace("\\\\", "\\\\ \\hline") # Add \hline after each row + #latex_table = latex_table.replace("_", " ") # Add \hline after each row + + # Specify the file path to save + latex_file_path = figurespath / f'cost_by_{_groupby_var}.tex' + + # Write to a file + with open(latex_file_path, 'w') as latex_file: + latex_file.write(latex_table) + + # Print latex for reference + print(latex_table) + +# Table F1: Cost by cost subcategory +generate_detail_cost_table(_groupby_var = 'cost_subcategory', _groupby_var_name = 'Cost Subcategory', _longtable = True) +# Table F2: Cost by cost subgroup +generate_detail_cost_table(_groupby_var = 'cost_subgroup', _groupby_var_name = 'Category Subgroup', _longtable = True) + +# Figure E1: Consumable inflow to outflow ratio figure +# ----------------------------------------------------------------------------------------------------------------------- +path_for_consumable_resourcefiles = resourcefilepath / "healthsystem/consumables" +# Estimate the stock to dispensed ratio from OpenLMIS data +lmis_consumable_usage = pd.read_csv(path_for_consumable_resourcefiles / "ResourceFile_Consumables_availability_and_usage.csv") +# Collapse individual facilities +lmis_consumable_usage_by_item_level_month = lmis_consumable_usage.groupby(['category', 'item_code', 'district', 'fac_type_tlo', 'month'])[['closing_bal', 'dispensed', 'received']].sum() +df = lmis_consumable_usage_by_item_level_month # Drop rows where monthly OpenLMIS data wasn't available +df = df.loc[df.index.get_level_values('month') != "Aggregate"] +opening_bal_january = df.loc[df.index.get_level_values('month') == 'January', 'closing_bal'] + \ + df.loc[df.index.get_level_values('month') == 'January', 'dispensed'] - \ + df.loc[df.index.get_level_values('month') == 'January', 'received'] +closing_bal_december = df.loc[df.index.get_level_values('month') == 'December', 'closing_bal'] +total_consumables_inflow_during_the_year = df.loc[df.index.get_level_values('month') != 'January', 'received'].groupby(level=[0,1,2,3]).sum() +\ + opening_bal_january.reset_index(level='month', drop=True) -\ + closing_bal_december.reset_index(level='month', drop=True) +total_consumables_outflow_during_the_year = df['dispensed'].groupby(level=[0,1,2,3]).sum() +inflow_to_outflow_ratio = total_consumables_inflow_during_the_year.div(total_consumables_outflow_during_the_year, fill_value=1) + +# Edit outlier ratios +inflow_to_outflow_ratio.loc[inflow_to_outflow_ratio < 1] = 1 # Ratio can't be less than 1 +inflow_to_outflow_ratio.loc[inflow_to_outflow_ratio > inflow_to_outflow_ratio.quantile(0.95)] = inflow_to_outflow_ratio.quantile(0.95) # Trim values greater than the 95th percentile +#average_inflow_to_outflow_ratio_ratio = inflow_to_outflow_ratio.mean() +inflow_to_outflow_ratio = inflow_to_outflow_ratio.reset_index().rename(columns = {0:'inflow_to_outflow_ratio'}) + +# Clean category names for plot +clean_category_names = {'cancer': 'Cancer', 'cardiometabolicdisorders': 'Cardiometabolic Disorders', + 'contraception': 'Contraception', 'general': 'General', 'hiv': 'HIV', 'malaria': 'Malaria', + 'ncds': 'Non-communicable Diseases', 'neonatal_health': 'Neonatal Health', + 'other_childhood_illnesses': 'Other Childhood Illnesses', 'reproductive_health': 'Reproductive Health', + 'road_traffic_injuries': 'Road Traffic Injuries', 'tb': 'Tuberculosis', + 'undernutrition': 'Undernutrition'} +inflow_to_outflow_ratio['category'] = inflow_to_outflow_ratio['category'].map(clean_category_names) + + +def plot_inflow_to_outflow_ratio(_df, groupby_var, _outputfilepath): + # Plot the bar plot with gray bars + plt.figure(figsize=(10, 6)) + sns.barplot(data=_df, x=groupby_var, y='inflow_to_outflow_ratio', errorbar=None, color="gray") + + # Add points representing the distribution of individual values + sns.stripplot(data=_df, x=groupby_var, y='inflow_to_outflow_ratio', color='black', size=5, alpha=0.2) + + # Wrap x-axis labels ONLY if they are strings and longer than 15 characters + labels = [] + for label in _df[groupby_var].unique(): + if isinstance(label, str) and len(label) > 15: + labels.append(textwrap.fill(label, width=15)) + else: + labels.append(label) + plt.xticks(ticks=range(len(labels)), labels=labels, rotation=90, ha='center') + + # Set labels and title + plt.xlabel(groupby_var) + plt.ylabel('Inflow to Outflow Ratio') + + # Show and save plot + plt.tight_layout() + plt.savefig(_outputfilepath / f'inflow_to_outflow_ratio_by_{groupby_var}.png') + plt.close() + +plot_inflow_to_outflow_ratio(inflow_to_outflow_ratio, 'fac_type_tlo', _outputfilepath = figurespath) +plot_inflow_to_outflow_ratio(inflow_to_outflow_ratio, 'district', _outputfilepath = figurespath) +plot_inflow_to_outflow_ratio(inflow_to_outflow_ratio, 'item_code', _outputfilepath = figurespath) +plot_inflow_to_outflow_ratio(inflow_to_outflow_ratio, 'category', _outputfilepath = figurespath) + +print(f"Inflow to Outflow ratio by consumable varies from " + f"{round(min(inflow_to_outflow_ratio.groupby('item_code')['inflow_to_outflow_ratio'].mean()),2)} " + f"to {round(max(inflow_to_outflow_ratio.groupby('item_code')['inflow_to_outflow_ratio'].mean()),2)}") + +inflow_to_outflow_ratio_by_item = inflow_to_outflow_ratio.groupby('item_code')['inflow_to_outflow_ratio'].mean().reset_index().rename(columns = {0: 'inflow_to_outflow_ratio'}) +inflow_to_outflow_ratio_by_item[inflow_to_outflow_ratio_by_item.inflow_to_outflow_ratio == min(inflow_to_outflow_ratio_by_item.inflow_to_outflow_ratio)]['item_code'] +inflow_to_outflow_ratio_by_item[inflow_to_outflow_ratio_by_item.inflow_to_outflow_ratio == max(inflow_to_outflow_ratio_by_item.inflow_to_outflow_ratio)]['item_code'] From df4fe416dc7f781a82b06566bdfdb782775bfac7 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 18 Apr 2025 10:32:02 +0100 Subject: [PATCH 430/755] analysis_wast: fig of deaths only after burn-in period --- .../wasting_analyses/analysis_wasting.py | 39 +++++++++++++++++-- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index 8afaedd069..fe20014fed 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -706,7 +706,7 @@ def create_plotting_data(df, df_name): self.save_fig__store_pdf_file(fig, fig_output_name) # plt.show() - def plot_model_gbd_deaths(self): + def plot_model_gbd_deaths_incl_burnin_period(self): """ compare model and GBD deaths 2010-2014 & 2015-2019 """ death_compare = \ compare_number_of_deaths(self.__log_file_path, resources_path) @@ -733,7 +733,39 @@ def plot_model_gbd_deaths(self): fig.figure.text(0.5, 0.02, "Model output against Global Burden of Diseases (GBD) study data", ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) - fig_output_name = ('model_gbd_deaths__' + self.datestamp) + fig_output_name = ('model_gbd_deaths_incl_burnin__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) + # plt.show() + + def plot_model_gbd_deaths_excl_burnin_period(self): + """ compare model and GBD deaths 2015-2019 """ + death_compare = \ + compare_number_of_deaths(self.__log_file_path, resources_path) + fig, ax = plt.subplots(figsize=(10, 6)) + # cause of death as of GBD 2019 'Protein-energy malnutrition' was labeled as 'Childhood Undernutrition' in + # wasting module + plot_df = death_compare.loc[(['2015-2019'], + slice(None), ['0-4'], 'Childhood Undernutrition' + )].groupby('period').sum() + plotting = plot_df.loc[['2015-2019']] + ax = plotting['model'].plot.bar(label='Model', ax=ax, rot=0) + ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, + yerr=[plotting.GBD_lower, plotting.GBD_upper], + fmt='o', color='#000', label="GBD") + + ax.set_title('Average direct deaths per year due to severe acute malnutrition in children under 5', + fontsize=title_fontsize - 1) + ax.set_xlabel("time period") + ax.set_ylabel("number of deaths") + ax.legend(loc='upper right', fontsize=legend_fontsize) + fig.tight_layout() + # Adjust the layout to make space for the footnote + plt.subplots_adjust(bottom=0.15) # Adjust the bottom margin + # Add footnote + fig.figure.text(0.5, 0.02, + "Model output against Global Burden of Diseases (GBD) study data", + ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) + fig_output_name = ('model_gbd_deaths_excl_burnin__' + self.datestamp) self.save_fig__store_pdf_file(fig, fig_output_name) # plt.show() @@ -812,7 +844,8 @@ def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): wasting_analyses.plot_wasting_prevalence_by_age_group() # plot wasting deaths as compared to GBD deaths - wasting_analyses.plot_model_gbd_deaths() + # wasting_analyses.plot_model_gbd_deaths_incl_burnin_period() + wasting_analyses.plot_model_gbd_deaths_excl_burnin_period() # ### Save all figures in one pdf outcome_figs_folder = sim_results_folder_path / '_outcome_figures' From 272f59fd15f63c531f00960f28ee9e0df0d88987 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Apr 2025 15:54:24 +0100 Subject: [PATCH 431/755] test_wast: minor (a comment updated) --- tests/test_wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 928e550930..691094a7b4 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -492,7 +492,7 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd # Check non-emergency care event is scheduled assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - # run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought + # run the created instance of HSI_GenericNonEmergencyFirstAppt and check care was sought ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) From b13e7405228a6facb7b7f744d49450a7024af19c Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Apr 2025 16:33:40 +0100 Subject: [PATCH 432/755] test_wast: test_recovery_before_death_scheduled-- test for uncomplicated SAM; after progression to sev wast, should recover to MAM; death scheduled after natural recovery since OTP tx length > duration of sev wast; update event names; use p and wmodule aliases --- tests/test_wasting.py | 91 +++++++++++++++++++++++++------------------ 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 691094a7b4..a301565f9e 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -886,33 +886,37 @@ def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): assert pd.isnull(person['un_sam_death_date']) -def test_nat_hist_cure_if_death_scheduled(tmpdir): - """Show that if a cure event is run before when a person was going to die, it causes the episode to end without - the person dying.""" +def test_recovery_before_death_scheduled(tmpdir): + """ Show that if a recovery event is run before when a person was going to die, it causes the episode to end without + the person dying. """ dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) - # get wasting module wmodule = sim.modules['Wasting'] + p = wmodule.parameters - # set death due to untreated SAM at 0% for all, hence always scheduled natural recovery from severe wasting - wmodule.parameters['base_death_rate_untreated_SAM'] = 0.0 - wmodule.parameters['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] + # Set death due to untreated SAM at 0% for all, hence always scheduled natural recovery from SAM + p['base_death_rate_untreated_SAM'] = 0.0 + p['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date + dur) sim.event_queue.queue = [] # clear the queue - # increase to 100% wasting incidence, progress to severe wasting, and death rate after SAM care, - # set full recovery with SAM care at 0% (and as 100% death rate after SAM care, no recovery to MAM) + + # Set moderate wasting incidence, progression to severe wasting, and death rate after SAM care at 100% wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() wmodule.wasting_models.severe_wasting_progression_lm = LinearModel.multiplicative() + p['prob_death_after_SAMcare'] = 1.0 + # Set full recovery with SAM care at 0% (and as 100% death rate after SAM care, no recovery to MAM), + # hence they will always die with SAM care wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) - wmodule.parameters['prob_death_after_SAMcare'] = 1.0 + # Ensure the individual has no complications when SAM occurs + p['prob_complications_in_SAM'] = 0.0 - # Get person to use: + # Get person to use df = sim.population.props under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] @@ -925,18 +929,19 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): df.at[person_id, 'un_sam_death_date'] = pd.NaT # Run Wasting Polling event to get new incident cases: - polling = Wasting_IncidencePoll(module=sim.modules['Wasting']) + polling = Wasting_IncidencePoll(module=wmodule) polling.apply(sim.population) - # Check properties of this individual: (should now be moderately wasted with a scheduled progression to severe date) + # Check properties of this individual: should now be moderately wasted person = df.loc[person_id] assert person['un_ever_wasted'] assert person['un_WHZ_category'] == '-3<=WHZ<-2' + assert person['un_clinical_acute_malnutrition'] != 'well' + assert not df.at[person_id, 'un_sam_with_complications'] assert person['un_last_wasting_date_of_onset'] == sim.date assert pd.isnull(person['un_am_tx_start_date']) assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) - + assert pd.isnull(person['un_sam_death_date']) # no death due to untreated SAM # Check that there is a Wasting_ProgressionToSevere_Event scheduled for this person progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if isinstance(event_tuple[1], Wasting_ProgressionToSevere_Event)][0] @@ -948,29 +953,33 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): sim.date = date_of_scheduled_progression progression_event.apply(person_id=person_id) - # Check properties of this individual: (should now be severely wasted and without a scheduled death date) + # Check properties of this individual: should now be severely wasted person = df.loc[person_id] assert person['un_ever_wasted'] assert person['un_WHZ_category'] == 'WHZ<-3' assert person['un_clinical_acute_malnutrition'] == 'SAM' + assert not df.at[person_id, 'un_sam_with_complications'] assert pd.isnull(person['un_am_tx_start_date']) assert pd.isnull(person['un_am_recovery_date']) - assert pd.isnull(person['un_sam_death_date']) + # since there is no natural death, no death date should be scheduled, + assert pd.isnull(person['un_sam_death_date']) # no death due to untreated SAM + # Check that there is a natural recovery to MAM scheduled + assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_RecoveryToMAM_Event) - # run health seeking behavior and ensure non-emergency event is scheduled + # Run health seeking behavior and ensure non-emergency event is scheduled hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) hsp.run() - # check non-emergency care event is scheduled + # Check non-emergency care event is scheduled assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - # Run the created instance of HSI_GenericFirstApptAtFacilityLevel0 and check care was sought + # Run the created instance of HSI_GenericNonEmergencyFirstAppt and check care was sought ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) - # check outpatient care event is scheduled + # Check outpatient care event is scheduled hsi_event_scheduled = [ ev for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) @@ -978,42 +987,48 @@ def test_nat_hist_cure_if_death_scheduled(tmpdir): ] assert 1 == len(hsi_event_scheduled) - # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] sam_ev.run(squeeze_factor=0.0) - # since there is no natural death, natural recovery should be scheduled, and - # since there is zero recovery rate with tx, death event after care should be scheduled - print(f"{sim.find_events_for_person(person_id)=}") - assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_NaturalRecovery_Event) or \ - isinstance(sim.find_events_for_person(person_id)[2][1], Wasting_NaturalRecovery_Event) - assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_SevereAcuteMalnutritionDeath_Event) or \ - isinstance(sim.find_events_for_person(person_id)[2][1], Wasting_SevereAcuteMalnutritionDeath_Event) + # Check death event is scheduled since there is zero recovery rate with treatment + assert isinstance(sim.find_events_for_person(person_id)[2][1], Wasting_SevereAcuteMalnutritionDeath_Event) - # Check a date of death is scheduled. it should be any date in the future: + # Check a date of scheduled death + # we assume OTC tx to be longer than natural recovery from sev. wasting, + # (if decided in future to change this assumption, the test will need to be updated) + assert p['tx_length_weeks_OutpatientSAM'] * 7 > p['duration_of_untreated_sev_wasting'] + # hence the death should be scheduled before the natural recovery death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if isinstance(event_tuple[1], Wasting_SevereAcuteMalnutritionDeath_Event)][0] date_of_scheduled_death = death_event_tuple[0] death_event = death_event_tuple[1] + nat_recov_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) + if isinstance(event_tuple[1], Wasting_RecoveryToMAM_Event)][0] + date_of_scheduled_nat_recov = nat_recov_event_tuple[0] assert date_of_scheduled_death > sim.date + assert date_of_scheduled_death > date_of_scheduled_nat_recov - # Run a Cure Event now - cure_event = Wasting_ClinicalAcuteMalnutritionRecovery_Event(person_id=person_id, module=sim.modules['Wasting']) - cure_event.apply(person_id=person_id) + # Run a full recovery event (it is not scheduled though) + full_recov_event = Wasting_FullRecovery_Event(person_id=person_id, module=wmodule) + full_recov_event.apply(person_id=person_id) - # Check that the person is not wasted and is alive still: + # Check that the person is fully recovered and is still alive person = df.loc[person_id] - assert person['is_alive'] assert person['un_WHZ_category'] == 'WHZ>=-2' - assert not pd.isnull(person['un_am_recovery_date']) + assert person['un_am_MUAC_category'] == '>=125mm' + assert not person['un_am_nutritional_oedema'] + assert person['un_clinical_acute_malnutrition'] == 'well' + assert not person['un_sam_with_complications'] + assert person['un_am_recovery_date'] == sim.date assert pd.isnull(person['un_sam_death_date']) + assert person['is_alive'] # Run the death event that was originally scheduled - this should have no effect and the person should not die sim.date = date_of_scheduled_death death_event.apply(person_id=person_id) - person = df.loc[person_id] - assert person['is_alive'] + assert df.loc[person_id]['is_alive'] def test_no_wasting_after_recent_recovery(tmpdir): """ Test that a person who recovered from wasting 5 days ago does not become wasted again. """ From b5c5a8c5e17640ab95e613adbafb5e31eebde1ff Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Apr 2025 16:41:05 +0100 Subject: [PATCH 433/755] test_wast: a minor simplification --- tests/test_wasting.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index a301565f9e..f0045cb8a5 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -1061,5 +1061,4 @@ def test_no_wasting_after_recent_recovery(tmpdir): polling.apply(sim.population) # Check properties of this individual: should still be well - person = df.loc[person_id] - assert person['un_clinical_acute_malnutrition'] == 'well' + assert df.loc[person_id]['un_clinical_acute_malnutrition'] == 'well' From 154560eaeba3fa790da7a20b56ac6a6d8c75a904 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Apr 2025 16:43:09 +0100 Subject: [PATCH 434/755] Revert "scripts/costing & consumables_analyses: Sakshi's analysis scripts (reached on 14 Apr) added" This reverts commit 11a168fba391560bdfba1187747349d95841694a. --- ...analysis_impact_of_consumable_scenarios.py | 1115 ---------- src/scripts/costing/cost_estimation.py | 1902 ----------------- .../costing/costing_overview_analysis.py | 371 ---- 3 files changed, 3388 deletions(-) delete mode 100644 src/scripts/consumables_analyses/analysis_impact_of_consumable_scenarios.py delete mode 100644 src/scripts/costing/cost_estimation.py delete mode 100644 src/scripts/costing/costing_overview_analysis.py diff --git a/src/scripts/consumables_analyses/analysis_impact_of_consumable_scenarios.py b/src/scripts/consumables_analyses/analysis_impact_of_consumable_scenarios.py deleted file mode 100644 index 5b3ee33ba7..0000000000 --- a/src/scripts/consumables_analyses/analysis_impact_of_consumable_scenarios.py +++ /dev/null @@ -1,1115 +0,0 @@ -"""This file uses the results of the results of running `impact_of_cons_availability_intervention.py` -tob extract summary results for the manuscript - "Rethinking economic evaluation of -system level interventions. -I plan to run the simulation for a short period of 5 years (2020 - 2025) because -holding the consumable availability constant in the short run would be more justifiable -than holding it constant for a long period. -""" - -import argparse -from pathlib import Path -import textwrap -from typing import Tuple - -import numpy as np -import pandas as pd -from matplotlib import pyplot as plt -import matplotlib.colors as mcolors -from matplotlib.ticker import FuncFormatter -from collections import Counter, defaultdict -import seaborn as sns -import squarify - -from tlo.analysis.utils import ( - CAUSE_OF_DEATH_OR_DALY_LABEL_TO_COLOR_MAP, - extract_results, - get_color_cause_of_death_or_daly_label, - make_age_grp_lookup, - order_of_cause_of_death_or_daly_label, - summarize, -) -import pickle - -from tlo import Date -from tlo.analysis.utils import ( - extract_params, - extract_results, - get_scenario_info, - get_scenario_outputs, - load_pickled_dataframes, - make_age_grp_lookup, - make_age_grp_types, - make_calendar_period_lookup, - make_calendar_period_type, - summarize, - write_log_to_excel, - parse_log_file, - COARSE_APPT_TYPE_TO_COLOR_MAP, - SHORT_TREATMENT_ID_TO_COLOR_MAP, - _standardize_short_treatment_id, - bin_hsi_event_details, - compute_mean_across_runs, - get_coarse_appt_type, - get_color_short_treatment_id, - order_of_short_treatment_ids, - plot_stacked_bar_chart, - squarify_neat, - unflatten_flattened_multi_index_in_logging, -) - -outputspath = Path('./outputs') -figurespath = Path(outputspath / 'impact_of_consumable_scenarios_results') -figurespath.mkdir(parents=True, exist_ok=True) # create directory if it doesn't exist -resourcefilepath = Path("./resources") - -# Declare period for which the results will be generated (defined inclusively) - -TARGET_PERIOD = (Date(2015, 1, 1), Date(2019, 12, 31)) - -make_graph_file_name = lambda stub: output_folder / f"{stub.replace('*', '_star_')}.png" # noqa: E731 - -_, age_grp_lookup = make_age_grp_lookup() - -def target_period() -> str: - """Returns the target period as a string of the form YYYY-YYYY""" - return "-".join(str(t.year) for t in TARGET_PERIOD) - -def drop_outside_period(_df): - """Return a dataframe which only includes for which the date is within the limits defined by TARGET_PERIOD""" - return _df.drop(index=_df.index[~_df['date'].between(*TARGET_PERIOD)]) - -def do_bar_plot_with_ci(_df, annotations=None, xticklabels_horizontal_and_wrapped=False): - """Make a vertical bar plot for each row of _df, using the columns to identify the height of the bar and the - extent of the error bar.""" - - yerr = np.array([ - (_df['median'] - _df['lower']).values, - (_df['upper'] - _df['median']).values, - ]) - - xticks = {(i + 0.5): k for i, k in enumerate(_df.index)} - - # Define color mapping based on index values - color_mapping = { - 'Actual': '#1f77b4', - 'Non-therapeutic consumables':'#ff7f0e', - 'Vital medicines': '#2ca02c', - 'Pharmacist-managed':'#d62728', - '75th percentile facility':'#9467bd', - '90th percentile facility':'#8c564b', - 'Best facility': '#e377c2', - 'Best facility (including DHO)': '#7f7f7f', - 'HIV supply chain': '#bcbd22', - 'EPI supply chain': '#17becf', - 'Perfect':'#31a354' - } - - colors = [_df.index[i] in color_mapping for i in range(len(_df.index))] - color_values = [color_mapping.get(idx, '#cccccc') for idx in _df.index] - - fig, ax = plt.subplots() - ax.bar( - xticks.keys(), - _df['median'].values, - yerr=yerr, - alpha=1, - color=color_values, - ecolor='black', - capsize=10, - label=xticks.values() - ) - if annotations: - for xpos, ypos, text in zip(xticks.keys(), _df['upper'].values, annotations): - ax.text(xpos, ypos * 1.05, text, horizontalalignment='center', fontsize=10) - - ax.set_xticks(list(xticks.keys())) - if not xticklabels_horizontal_and_wrapped: - wrapped_labs = ["\n".join(textwrap.wrap(_lab, 20)) for _lab in xticks.values()] - ax.set_xticklabels(wrapped_labs, rotation=45, ha='right', fontsize=10) - else: - wrapped_labs = ["\n".join(textwrap.wrap(_lab, 20)) for _lab in xticks.values()] - ax.set_xticklabels(wrapped_labs, fontsize=10) - - # Set font size for y-tick labels - ax.tick_params(axis='y', labelsize=10) - ax.tick_params(axis='x', labelsize=10) - - ax.grid(axis="y") - ax.spines['top'].set_visible(False) - ax.spines['right'].set_visible(False) - fig.tight_layout() - - return fig, ax - -def do_bar_plot_with_ci_and_heatmap(_df, annotations=None, xticklabels_horizontal_and_wrapped=False, heatmap_values=None, plt_title = 'unnamed_figure'): - """Create a bar plot with CI and a heatmap above it.""" - yerr = np.array([ - (_df['median'] - _df['lower']).values, - (_df['upper'] - _df['median']).values, - ]) - - xticks = {(i + 0.5): k for i, k in enumerate(_df.index)} - - # Define color mapping based on index values - color_mapping = { - 'Actual': '#1f77b4', - 'Non-therapeutic consumables':'#ff7f0e', - 'Vital medicines': '#2ca02c', - 'Pharmacist-managed':'#d62728', - '75th percentile facility':'#9467bd', - '90th percentile facility':'#8c564b', - 'Best facility': '#e377c2', - 'Best facility (including DHO)': '#7f7f7f', - 'HIV supply chain': '#bcbd22', - 'EPI supply chain': '#17becf', - 'Perfect':'#31a354' - } - - color_values = [color_mapping.get(idx, '#cccccc') for idx in _df.index] - - # Create a figure with two axes - fig, (heatmap_ax, ax) = plt.subplots( - nrows=2, ncols=1, gridspec_kw={"height_ratios": [0.3, 2]}, figsize=(10, 7) - ) - - # Heatmap axis - if heatmap_values: - cmap = plt.cm.YlGn - norm = mcolors.Normalize(vmin=min(heatmap_values), vmax=max(heatmap_values)) - heatmap_colors = [cmap(norm(value)) for value in heatmap_values] - - heatmap_ax.bar( - xticks.keys(), - [1] * len(heatmap_values), # Constant height for heatmap bars - color=heatmap_colors, - align='center', - width=0.8 - ) - - # Add data labels to heatmap bars - for xpos, value in zip(xticks.keys(), heatmap_values): - heatmap_ax.text( - xpos, 0.5, f"{value:.2f}", color='black', ha='center', va='center', fontsize= 12, weight='bold' - ) - - heatmap_ax.set_xticks(list(xticks.keys())) - heatmap_ax.set_xticklabels([]) - heatmap_ax.set_yticks([]) - heatmap_ax.set_ylabel('Average consumable \n availability under \n each scenario \n (Baseline = 0.52)', fontsize=10, rotation=0, labelpad=20) - heatmap_ax.spines['top'].set_visible(False) - heatmap_ax.spines['right'].set_visible(False) - heatmap_ax.spines['left'].set_visible(False) - heatmap_ax.spines['bottom'].set_visible(False) - - # Bar plot axis - ax.bar( - xticks.keys(), - _df['median'].values, - yerr=yerr, - alpha=1, - color=color_values, - ecolor='black', - capsize=10 - ) - if annotations: - for xpos, ypos, text in zip(xticks.keys(), _df['upper'].values, annotations): - ax.text(xpos, ypos * 1.05, text, horizontalalignment='center', fontsize=10) - - ax.set_xticks(list(xticks.keys())) - if not xticklabels_horizontal_and_wrapped: - wrapped_labs = ["\n".join(textwrap.wrap(_lab, 20)) for _lab in xticks.values()] - ax.set_xticklabels(wrapped_labs, rotation=45, ha='right', fontsize=10) - else: - wrapped_labs = ["\n".join(textwrap.wrap(_lab, 20)) for _lab in xticks.values()] - ax.set_xticklabels(wrapped_labs, fontsize=10) - - # Set font size for y-tick labels - ax.tick_params(axis='y', labelsize=10) - ax.tick_params(axis='x', labelsize=10) - - ax.grid(axis="y") - ax.spines['top'].set_visible(False) - ax.spines['right'].set_visible(False) - - # Add global title - fig.suptitle(plt_title, fontsize=16, fontweight='bold') - - fig.tight_layout() - - return fig, (heatmap_ax, ax) - -def get_num_dalys(_df): - """Return total number of DALYS (Stacked) by label (total within the TARGET_PERIOD). - Throw error if not a record for every year in the TARGET PERIOD (to guard against inadvertently using - results from runs that crashed mid-way through the simulation. - """ - years_needed = [i.year for i in TARGET_PERIOD] - assert set(_df.year.unique()).issuperset(years_needed), "Some years are not recorded." - return pd.Series( - data=_df - .loc[_df.year.between(*years_needed)] - .drop(columns=['date', 'sex', 'age_range', 'year']) - .sum().sum() - ) - -def get_num_dalys_by_cause(_df): - """Return total number of DALYS (Stacked) by label (total within the TARGET_PERIOD). - Throw error if not a record for every year in the TARGET PERIOD (to guard against inadvertently using - results from runs that crashed mid-way through the simulation. - """ - years_needed = [i.year for i in TARGET_PERIOD] - assert set(_df.year.unique()).issuperset(years_needed), "Some years are not recorded." - return pd.Series( - data=_df - .loc[_df.year.between(*years_needed)] - .drop(columns=['date', 'sex', 'age_range', 'year']) - .sum() - ) - -def get_num_dalys_per_person_year(_df): - """Return total number of DALYS (Stacked) by label (total within the TARGET_PERIOD). - Throw error if not a record for every year in the TARGET PERIOD (to guard against inadvertently using - results from runs that crashed mid-way through the simulation. - """ - years_needed = [i.year for i in TARGET_PERIOD] - assert set(_df.year.unique()).issuperset(years_needed), "Some years are not recorded." - return pd.Series( - data=_df - .loc[_df.year.between(*years_needed)] - .drop(columns=['date', 'sex', 'age_range']) - .groupby('year').sum().sum(axis = 1) - ) - -def get_num_dalys_per_person_year_by_cause(_df): - """Return total number of DALYS (Stacked) by label (total within the TARGET_PERIOD). - Throw error if not a record for every year in the TARGET PERIOD (to guard against inadvertently using - results from runs that crashed mid-way through the simulation. - """ - years_needed = [i.year for i in TARGET_PERIOD] - assert set(_df.year.unique()).issuperset(years_needed), "Some years are not recorded." - return pd.Series( - data=_df - .loc[_df.year.between(*years_needed)] - .drop(columns=['date', 'sex', 'age_range']) - .groupby('year').sum().unstack() - ) -def extract_results_by_person_year(results_folder: Path, - module: str, - key: str, - column: str = None, - index: str = None, - custom_generate_series=None, - ) -> pd.DataFrame: - """Utility function to unpack results. - - Produces a dataframe from extracting information from a log with the column multi-index for the draw/run. - - If the column to be extracted exists in the log, the name of the `column` is provided as `column`. If the resulting - dataframe should be based on another column that exists in the log, this can be provided as 'index'. - - If instead, some work must be done to generate a new column from log, then a function can be provided to do this as - `custom_generate_series`. - - Optionally, with `do_scaling=True`, each element is multiplied by the scaling_factor recorded in the simulation. - - Note that if runs in the batch have failed (such that logs have not been generated), these are dropped silently. - """ - - def get_population_size(_draw, _run): - """Helper function to get the multiplier from the simulation. - Note that if the scaling factor cannot be found a `KeyError` is thrown.""" - return load_pickled_dataframes( - results_folder, _draw, _run, 'tlo.methods.demography' - )['tlo.methods.demography']['population']['total'] - - if custom_generate_series is None: - # If there is no `custom_generate_series` provided, it implies that function required selects the specified - # column from the dataframe. - assert column is not None, "Must specify which column to extract" - else: - assert index is None, "Cannot specify an index if using custom_generate_series" - assert column is None, "Cannot specify a column if using custom_generate_series" - - def generate_series(dataframe: pd.DataFrame) -> pd.Series: - if custom_generate_series is None: - if index is not None: - return dataframe.set_index(index)[column] - else: - return dataframe.reset_index(drop=True)[column] - else: - return custom_generate_series(dataframe) - - # get number of draws and numbers of runs - info = get_scenario_info(results_folder) - - # Collect results from each draw/run - res = dict() - for draw in range(info['number_of_draws']): - for run in range(info['runs_per_draw']): - - draw_run = (draw, run) - - try: - df: pd.DataFrame = load_pickled_dataframes(results_folder, draw, run, module)[module][key] - output_from_eval: pd.Series = generate_series(df) - assert pd.Series == type(output_from_eval), 'Custom command does not generate a pd.Series' - res[draw_run] = output_from_eval.reset_index().drop(columns = ['year']).T / get_population_size(draw, run) - res[draw_run] = res[draw_run].sum(axis =1) - except KeyError: - # Some logs could not be found - probably because this run failed. - res[draw_run] = None - - # Use pd.concat to compile results (skips dict items where the values is None) - _concat = pd.concat(res, axis=1) - _concat.columns.names = ['draw', 'run'] # name the levels of the columns multi-index - return _concat - -def extract_results_by_person_year_by_cause(results_folder: Path, - module: str, - key: str, - column: str = None, - index: str = None, - custom_generate_series=None, - cause: str = None, - ) -> pd.DataFrame: - """Utility function to unpack results. - - Produces a dataframe from extracting information from a log with the column multi-index for the draw/run. - - If the column to be extracted exists in the log, the name of the `column` is provided as `column`. If the resulting - dataframe should be based on another column that exists in the log, this can be provided as 'index'. - - If instead, some work must be done to generate a new column from log, then a function can be provided to do this as - `custom_generate_series`. - - Optionally, with `do_scaling=True`, each element is multiplied by the scaling_factor recorded in the simulation. - - Note that if runs in the batch have failed (such that logs have not been generated), these are dropped silently. - """ - - def get_population_size(_draw, _run): - """Helper function to get the multiplier from the simulation. - Note that if the scaling factor cannot be found a `KeyError` is thrown.""" - return load_pickled_dataframes( - results_folder, _draw, _run, 'tlo.methods.demography' - )['tlo.methods.demography']['population']['total'] - - if custom_generate_series is None: - # If there is no `custom_generate_series` provided, it implies that function required selects the specified - # column from the dataframe. - assert column is not None, "Must specify which column to extract" - else: - assert index is None, "Cannot specify an index if using custom_generate_series" - assert column is None, "Cannot specify a column if using custom_generate_series" - - def generate_series(dataframe: pd.DataFrame) -> pd.Series: - if custom_generate_series is None: - if index is not None: - return dataframe.set_index(index)[column] - else: - return dataframe.reset_index(drop=True)[column] - else: - return custom_generate_series(dataframe) - - # get number of draws and numbers of runs - info = get_scenario_info(results_folder) - - # Collect results from each draw/run - res = dict() - for draw in range(info['number_of_draws']): - for run in range(info['runs_per_draw']): - - draw_run = (draw, run) - - try: - df: pd.DataFrame = load_pickled_dataframes(results_folder, draw, run, module)[module][key] - output_from_eval: pd.Series = generate_series(df) - assert pd.Series == type(output_from_eval), 'Custom command does not generate a pd.Series' - output_from_eval = output_from_eval[output_from_eval.index.get_level_values(0) == cause].droplevel(0) - res[draw_run] = output_from_eval.reset_index().drop(columns = ['year']).T / get_population_size(draw, run) - res[draw_run] = res[draw_run].sum(axis =1) - except KeyError: - # Some logs could not be found - probably because this run failed. - res[draw_run] = None - - # Use pd.concat to compile results (skips dict items where the values is None) - _concat = pd.concat(res, axis=1) - _concat.columns.names = ['draw', 'run'] # name the levels of the columns multi-index - return _concat - -def find_difference_relative_to_comparison(_ser: pd.Series, - comparison: str, - scaled: bool = False, - drop_comparison: bool = True, - ): - """Find the difference in the values in a pd.Series with a multi-index, between the draws (level 0) - within the runs (level 1), relative to where draw = `comparison`. - The comparison is `X - COMPARISON`.""" - return _ser \ - .unstack(level=0) \ - .apply(lambda x: (x - x[comparison]) / (x[comparison] if scaled else 1.0), axis=1) \ - .drop(columns=([comparison] if drop_comparison else [])) \ - .stack() - -# %% Gathering basic information - -# Find results_folder associated with a given batch_file and get most recent -#results_folder = get_scenario_outputs('impact_of_consumable_scenarios.py', outputspath) -results_folder = Path(outputspath / 'sakshi.mohan@york.ac.uk/impact_of_consumables_scenarios-2024-09-12T192454Z/') -#results_folder = Path(outputspath / 'impact_of_consumables_scenarios-2024-09-12T155640Z/') - -# look at one log (so can decide what to extract) -log = load_pickled_dataframes(results_folder) - -# 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) -params_dict = {'default': 'Actual', 'scenario1': 'Non-therapeutic consumables', 'scenario2': 'Vital medicines', - 'scenario3': 'Pharmacist-managed', 'scenario4': 'Level 1b', 'scenario5': 'CHAM', - 'scenario6': '75th percentile facility', 'scenario7': '90th percentile facility', 'scenario8': 'Best facility', - 'scenario9': 'Best facility (including DHO)','scenario10': 'HIV supply chain','scenario11': 'EPI supply chain', - 'scenario12': 'HIV moved to Govt supply chain', 'all': 'Perfect'} -params_dict_df = pd.DataFrame.from_dict(params_dict, orient='index', columns=['name_of_scenario']).reset_index().rename(columns = {'index': 'value'}) -params = params.merge(params_dict_df, on = 'value', how = 'left', validate = '1:1') -scenarios = params['name_of_scenario'] #range(len(params)) # X-axis values representing time periods -drop_scenarios = ['Level 1b', 'CHAM', 'Best facility (including DHO)', 'HIV moved to Govt supply chain'] # Drops scenarios which are no longer considered important for comparison - -# %% Extracting results from run - -# 1. DALYs accrued and averted -################################### -# 1.1 Total DALYs accrued -#------------------------- -# Get total DALYs accrued -num_dalys = extract_results( - results_folder, - module='tlo.methods.healthburden', - key='dalys_stacked', - custom_generate_series=get_num_dalys, - do_scaling=True - ) - -# %% Chart of total number of DALYS -num_dalys_summarized = summarize(num_dalys).loc[0].unstack() -num_dalys_summarized['scenario'] = scenarios.to_list() -num_dalys_summarized = num_dalys_summarized.set_index('scenario') -num_dalys_summarized.to_csv(figurespath/ 'num_dalys_summarized.csv') - -# Plot DALYS accrued (with xtickabels horizontal and wrapped) -name_of_plot = f'Total DALYs accrued, {target_period()}' -chosen_num_dalys_summarized = num_dalys_summarized[~num_dalys_summarized.index.isin(drop_scenarios)] -fig, ax = do_bar_plot_with_ci( - (chosen_num_dalys_summarized / 1e6).clip(lower=0.0), - annotations=[ - f"{round(row['median']/1e6, 1)} \n ({round(row['lower']/1e6, 1)}-{round(row['upper']/1e6, 1)})" - for _, row in chosen_num_dalys_summarized.clip(lower=0.0).iterrows() - ], - xticklabels_horizontal_and_wrapped=False, -) -ax.set_title(name_of_plot) -ax.set_ylim(0, 120) -ax.set_yticks(np.arange(0, 120, 10)) -ax.set_ylabel('Total DALYs accrued \n(Millions)') -fig.tight_layout() -fig.savefig(figurespath / name_of_plot.replace(' ', '_').replace(',', '')) -fig.show() -plt.close(fig) - -# 1.2 Total DALYs averted -#------------------------ -# Get absolute DALYs averted -num_dalys_averted = summarize( - -1.0 * - pd.DataFrame( - find_difference_relative_to_comparison( - num_dalys.loc[0], - comparison= 0) # sets the comparator to 0 which is the Actual scenario - ).T - ).iloc[0].unstack() -num_dalys_averted['scenario'] = scenarios.to_list()[1:12] -num_dalys_averted = num_dalys_averted.set_index('scenario') - -# Get percentage DALYs averted -pc_dalys_averted = 100.0 * summarize( - -1.0 * - pd.DataFrame( - find_difference_relative_to_comparison( - num_dalys.loc[0], - comparison= 0, # sets the comparator to 0 which is the Actual scenario - scaled=True) - ).T -).iloc[0].unstack() -pc_dalys_averted['scenario'] = scenarios.to_list()[1:12] -pc_dalys_averted = pc_dalys_averted.set_index('scenario') - -# %% Chart of number of DALYs averted -# Plot DALYS averted (with xtickabels horizontal and wrapped) -average_availability_under_scenarios = [0.59, 0.59, 0.6, 0.57, 0.63, 0.7, 0.79, 0.91, 1] -name_of_plot = f'Health impact of improved consumable availability\n at level 1 health facilities, {target_period()}' -chosen_num_dalys_averted = num_dalys_averted[~num_dalys_averted.index.isin(drop_scenarios)] -chosen_pc_dalys_averted = pc_dalys_averted[~pc_dalys_averted.index.isin(drop_scenarios)] -fig, (heatmap_ax, ax) = do_bar_plot_with_ci_and_heatmap( - (chosen_num_dalys_averted / 1e6), - annotations=[ - f"{round(row['median'], 1)} % \n ({round(row['lower'], 1)}- \n {round(row['upper'], 1)}) %" - for _, row in chosen_pc_dalys_averted.iterrows() - ], - xticklabels_horizontal_and_wrapped=False, - heatmap_values=average_availability_under_scenarios, - plt_title = name_of_plot -) -#ax.set_title(name_of_plot) -ax.set_ylim(0, 14) -ax.set_yticks(np.arange(0, 14, 2)) -ax.set_ylabel('Additional DALYS Averted \n(Millions)') -fig.tight_layout() -fig.savefig(figurespath / name_of_plot.replace(' ', '_').replace(',', '').replace('\n', '')) -fig.show() -plt.close(fig) - -# 1.2 DALYs by disease area/intervention - for comparison of the magnitude of impact created by consumables interventions -num_dalys_by_cause = extract_results( - results_folder, - module='tlo.methods.healthburden', - key='dalys_stacked', - custom_generate_series=get_num_dalys_by_cause, - do_scaling=True - ) -num_dalys_by_cause_summarized = summarize(num_dalys_by_cause).unstack(level = 0) -num_dalys_by_cause_summarized = num_dalys_by_cause_summarized.reset_index() -num_dalys_by_cause_summarized = num_dalys_by_cause_summarized.rename(columns = {'level_2':'cause', 0: 'DALYs_accrued'}) -num_dalys_by_cause_summarized = num_dalys_by_cause_summarized.pivot(index=['draw','cause'], columns='stat', values='DALYs_accrued') -num_dalys_by_cause_summarized.to_csv(figurespath / 'num_dalys_by_cause_summarized.csv') - -# Get top 10 causes until Actual -num_dalys_by_cause_actual = num_dalys_by_cause_summarized[num_dalys_by_cause_summarized.index.get_level_values(0) == 0] -num_dalys_by_cause_actual = num_dalys_by_cause_actual.sort_values('mean', ascending = False) -num_dalys_by_cause_actual =num_dalys_by_cause_actual[0:10] -top_10_causes_of_dalys = num_dalys_by_cause_actual.index.get_level_values(1).unique() - -# Get DALYs aveterted by cause and plot bar chats -for cause in top_10_causes_of_dalys: - num_dalys_by_cause_pivoted = num_dalys_by_cause[num_dalys_by_cause.index == cause].unstack().reset_index().drop(columns = ['level_2']).set_index(['draw', 'run']) - num_dalys_averted_by_cause = summarize( - -1.0 * - pd.DataFrame( - find_difference_relative_to_comparison( - num_dalys_by_cause_pivoted.squeeze(), - comparison= 0) # sets the comparator to 0 which is the Actual scenario - ).T - ).iloc[0].unstack() - num_dalys_averted_by_cause['scenario'] = scenarios.to_list()[1:12] - num_dalys_averted_by_cause = num_dalys_averted_by_cause.set_index('scenario') - - # Get percentage DALYs averted - pc_dalys_averted_by_cause = 100.0 * summarize( - -1.0 * - pd.DataFrame( - find_difference_relative_to_comparison( - num_dalys_by_cause_pivoted.squeeze(), - comparison= 0, # sets the comparator to 0 which is the Actual scenario - scaled=True) - ).T - ).iloc[0].unstack() - pc_dalys_averted_by_cause['scenario'] = scenarios.to_list()[1:12] - pc_dalys_averted_by_cause = pc_dalys_averted_by_cause.set_index('scenario') - - # Create a plot of DALYs averted by cause - chosen_num_dalys_averted_by_cause = num_dalys_averted_by_cause[~num_dalys_averted_by_cause.index.isin(drop_scenarios)] - chosen_pc_dalys_averted_by_cause = pc_dalys_averted_by_cause[~pc_dalys_averted_by_cause.index.isin(drop_scenarios)] - name_of_plot = f'Additional DALYs averted vs Actual by cause - \n ({cause}), {target_period()}' - fig, ax = do_bar_plot_with_ci( - (chosen_num_dalys_averted_by_cause / 1e6).clip(lower=0.0), - annotations=[ - f"{round(row['mean'], 1)} % \n ({round(row['lower'], 1)}-{round(row['upper'], 1)}) %" - for _, row in chosen_pc_dalys_averted_by_cause.clip(lower=0.0).iterrows() - ], - xticklabels_horizontal_and_wrapped=False, - ) - if chosen_num_dalys_averted_by_cause.upper.max()/1e6 > 2: - y_limit = 8.5 - y_tick_gaps = 1 - else: - y_limit = 2.5 - y_tick_gaps = 0.5 - ax.set_title(name_of_plot) - ax.set_ylim(0, y_limit) - ax.set_yticks(np.arange(0, y_limit, y_tick_gaps)) - ax.set_ylabel(f'Additional DALYs averted \n(Millions)') - fig.tight_layout() - fig.savefig(figurespath / name_of_plot.replace(' ', '_').replace(',', '').replace('/', '_').replace('\n', '')) - #fig.show() - plt.close(fig) - -''' -# PLot DALYs accrued by cause -for cause in top_10_causes_of_dalys: - name_of_plot = f'Total DALYs accrued by cause - \n {cause}, {target_period()}' - chosen_num_dalys_by_cause_summarized = num_dalys_by_cause_summarized[~num_dalys_by_cause_summarized.index.get_level_values(0).isin([4,5])] - chosen_num_dalys_by_cause_summarized = chosen_num_dalys_by_cause_summarized[chosen_num_dalys_by_cause_summarized.index.get_level_values(1) == cause] - fig, ax = do_bar_plot_with_ci( - (chosen_num_dalys_by_cause_summarized / 1e6).clip(lower=0.0), - annotations=[ - f"{round(row['mean'] / 1e6, 1)} \n ({round(row['lower'] / 1e6, 1)}-{round(row['upper'] / 1e6, 1)})" - for _, row in chosen_num_dalys_by_cause_summarized.clip(lower=0.0).iterrows() - ], - xticklabels_horizontal_and_wrapped=False, - ) - ax.set_title(name_of_plot) - if chosen_num_dalys_by_cause_summarized.upper.max()/1e6 > 5: - y_limit = 30 - y_tick_gap = 5 - else: - y_limit = 5 - y_tick_gap = 1 - ax.set_ylim(0, y_limit) - ax.set_yticks(np.arange(0, y_limit, y_tick_gap)) - ax.set_ylabel(f'Total DALYs accrued \n(Millions)') - fig.tight_layout() - fig.savefig(figurespath / name_of_plot.replace(' ', '_').replace(',', '').replace('/', '_').replace('\n', '')) - fig.show() - plt.close(fig) - -# TODO Fix xticklabels in the plots above -''' - -# 1.3 Total DALYs averted per person -#---------------------------------------- -num_dalys_per_person_year = extract_results_by_person_year( - results_folder, - module='tlo.methods.healthburden', - key='dalys_stacked', - custom_generate_series=get_num_dalys_per_person_year, - ) - -num_dalys_averted_per_person_year = summarize( - -1.0 * - pd.DataFrame( - find_difference_relative_to_comparison( - num_dalys_per_person_year.loc[0], - comparison= 0) # sets the comparator to 0 which is the Actual scenario - ).T - ).iloc[0].unstack() -num_dalys_averted_per_person_year['scenario'] = scenarios.to_list()[1:12] -num_dalys_averted_per_person_year = num_dalys_averted_per_person_year.set_index('scenario') - -# Get percentage DALYs averted -pct_dalys_averted_per_person_year = 100.0 * summarize( - -1.0 * - pd.DataFrame( - find_difference_relative_to_comparison( - num_dalys_per_person_year.loc[0], - comparison= 0, # sets the comparator to 0 which is the Actual scenario - scaled=True) - ).T -).iloc[0].unstack() -pct_dalys_averted_per_person_year['scenario'] = scenarios.to_list()[1:12] -pct_dalys_averted_per_person_year = pct_dalys_averted_per_person_year.set_index('scenario') - -# %% Chart of number of DALYs averted -# Plot DALYS averted (with xtickabels horizontal and wrapped) -name_of_plot = f'Additional DALYs Averted Per Person vs Actual, \n {target_period()}' -chosen_num_dalys_averted_per_person_year = num_dalys_averted_per_person_year[~num_dalys_averted_per_person_year.index.isin(drop_scenarios)] -chosen_pct_dalys_averted_per_person_year = pct_dalys_averted_per_person_year[~pct_dalys_averted_per_person_year.index.isin(drop_scenarios)] -fig, ax = do_bar_plot_with_ci( - (chosen_num_dalys_averted_per_person_year).clip(lower=0.0), - annotations=[ - f"{round(row['mean'], 1)} % \n ({round(row['lower'], 1)}- \n {round(row['upper'], 1)}) %" - for _, row in chosen_pct_dalys_averted_per_person_year.clip(lower=0.0).iterrows() - ], - xticklabels_horizontal_and_wrapped=False, -) -ax.set_title(name_of_plot) -ax.set_ylim(0, 1.5) -ax.set_yticks(np.arange(0, 1.5, 0.2)) -ax.set_ylabel('Additional DALYs averted per person') -fig.tight_layout() -fig.savefig(figurespath / name_of_plot.replace(' ', '_').replace(',', '').replace('\n', '')) -fig.show() -plt.close(fig) - -# 1.4 Total DALYs averted per person by cause -#------------------------------------------------- -for cause in top_10_causes_of_dalys: - num_dalys_per_person_year_by_cause = extract_results_by_person_year_by_cause( - results_folder, - module='tlo.methods.healthburden', - key='dalys_stacked', - custom_generate_series=get_num_dalys_per_person_year_by_cause, - cause = cause, - ) - - num_dalys_per_person_year_by_cause_pivoted = num_dalys_per_person_year_by_cause.unstack().reset_index().drop( - columns=['level_2']).set_index(['draw', 'run']) - num_dalys_averted_per_person_year_by_cause = summarize( - -1.0 * - pd.DataFrame( - find_difference_relative_to_comparison( - num_dalys_per_person_year_by_cause.squeeze(), - comparison=0) # sets the comparator to 0 which is the Actual scenario - ).T - ).iloc[0].unstack() - num_dalys_averted_per_person_year_by_cause['scenario'] = scenarios.to_list()[1:12] - num_dalys_averted_per_person_year_by_cause = num_dalys_averted_per_person_year_by_cause.set_index('scenario') - - # Get percentage DALYs averted - pct_dalys_averted_per_person_year_by_cause = 100.0 * summarize( - -1.0 * - pd.DataFrame( - find_difference_relative_to_comparison( - num_dalys_per_person_year_by_cause.squeeze(), - comparison=0, # sets the comparator to 0 which is the Actual scenario - scaled=True) - ).T - ).iloc[0].unstack() - pct_dalys_averted_per_person_year_by_cause['scenario'] = scenarios.to_list()[1:12] - pct_dalys_averted_per_person_year_by_cause = pct_dalys_averted_per_person_year_by_cause.set_index('scenario') - - # Create a plot of DALYs averted by cause - chosen_num_dalys_averted_per_person_year_by_cause = num_dalys_averted_per_person_year_by_cause[ - ~num_dalys_averted_per_person_year_by_cause.index.isin(drop_scenarios)] - chosen_pct_dalys_averted_per_person_year_by_cause = pct_dalys_averted_per_person_year_by_cause[~pct_dalys_averted_per_person_year_by_cause.index.isin(drop_scenarios)] - name_of_plot = f'Additional DALYs averted per person by cause - \n ({cause}), {target_period()}' - fig, ax = do_bar_plot_with_ci( - (chosen_num_dalys_averted_per_person_year_by_cause).clip(lower=0.0), - annotations=[ - f"{round(row['mean'], 1)} % \n ({round(row['lower'], 1)}-{round(row['upper'], 1)}) %" - for _, row in pct_dalys_averted_per_person_year_by_cause.clip(lower=0.0).iterrows() - ], - xticklabels_horizontal_and_wrapped=False, - ) - if chosen_num_dalys_averted_per_person_year_by_cause.upper.max() > 0.4: - y_limit = 0.55 - y_tick_gap = 0.1 - elif chosen_num_dalys_averted_per_person_year_by_cause.upper.max() > 0.18: - y_limit = 0.2 - y_tick_gap = 0.025 - else: - y_limit = 0.15 - y_tick_gap = 0.025 - ax.set_title(name_of_plot) - ax.set_ylim(0, y_limit) - ax.set_yticks(np.arange(0, y_limit, y_tick_gap)) - ax.set_ylabel(f'Additional DALYs averted per person') - fig.tight_layout() - fig.savefig(figurespath / name_of_plot.replace(' ', '_').replace(',', '').replace('/', '_').replace('\n', '')) - #fig.show() - plt.close(fig) - -# 2. Health work time spent v DALYs accrued -############################################# -# DALYs averted per person on the Y-axis; Capacity of cadre used at levels 1a, 1b, and 2 on the Y-axis -# log['tlo.methods.healthsystem.summary']['Capacity_By_OfficerType_And_FacilityLevel']['OfficerType=Pharmacy|FacilityLevel=2'] -def get_capacity_used_by_cadre_and_level(_df): - """Return total number of DALYS (Stacked) by label (total within the TARGET_PERIOD). - Throw error if not a record for every year in the TARGET PERIOD (to guard against inadvertently using - results from runs that crashed mid-way through the simulation. - """ - years_needed = [i.year for i in TARGET_PERIOD] - _df['year'] = _df.date.dt.year - #assert set(_df.year.unique()).issuperset(years_needed), "Some years are not recorded." - string_for_cols_to_drop1 = 'FacilityLevel=0|FacilityLevel=3|FacilityLevel=4|FacilityLevel=5' - string_for_cols_to_drop2 = 'OfficerType=DCSA|OfficerType=Dental|OfficerType=Laboratory|OfficerType=Mental|OfficerType=Nutrition|OfficerType=Radiography' - cols_to_drop1 = _df.columns[_df.columns.str.contains(string_for_cols_to_drop1)] - cols_to_drop2 = _df.columns[_df.columns.str.contains(string_for_cols_to_drop2)] - cols_to_drop = [*cols_to_drop1, *cols_to_drop2, 'year'] - return pd.Series( - data=_df - .loc[_df.year.between(*years_needed)] - .drop(columns= cols_to_drop) - .mean() - ) - -capacity_used = summarize(extract_results( - results_folder, - module='tlo.methods.healthsystem.summary', - key='Capacity_By_OfficerType_And_FacilityLevel', - custom_generate_series=get_capacity_used_by_cadre_and_level, - do_scaling = False, - )) - -#chosen_capacity_used.unstack().reset_index().drop(columns = ['level_2']).pivot(columns ='stat', index = 'draw') -for cadre_level in capacity_used.index: - print(cadre_level) - name_of_plot = f'Capacity used - \n {cadre_level}, {target_period()}' - scenarios_to_drop = capacity_used.columns[capacity_used.columns.get_level_values(0).isin([10])] - chosen_capacity_used = capacity_used.drop(columns = scenarios_to_drop) - chosen_capacity_used = chosen_capacity_used[chosen_capacity_used.index == cadre_level] - chosen_capacity_used = chosen_capacity_used.unstack().reset_index().drop(columns = ['level_2']).pivot(columns ='stat', index = 'draw').droplevel(0,axis = 1) - chosen_capacity_used['scenario'] = [*scenarios.to_list()[0:10], scenarios.to_list()[11]] # [*scenarios.to_list()[0:4],*scenarios.to_list()[6:10]] - #TODO fix above code to be automated - chosen_capacity_used = chosen_capacity_used.set_index('scenario') - fig, ax = do_bar_plot_with_ci( - (chosen_capacity_used), - annotations=[ - f"{round(row['mean'], 2)} \n ({round(row['lower'], 2)}-{round(row['upper'], 2)})" - for _, row in chosen_capacity_used.iterrows() - ], - xticklabels_horizontal_and_wrapped=False, - ) - ax.set_title(name_of_plot) - if chosen_capacity_used.upper.max() > 3: - y_limit = 3.5 - y_tick_gap = 0.5 - else: - y_limit = 2 - y_tick_gap = 0.25 - ax.set_ylim(0, y_limit) - ax.set_yticks(np.arange(0, y_limit, y_tick_gap)) - ax.set_ylabel(f'Capacity used \n (Proportion of capacity available)') - fig.tight_layout() - fig.savefig(figurespath / name_of_plot.replace(' ', '_').replace(',', '').replace('/', '_').replace('\n', '_')) - fig.show() - plt.close(fig) - - -# %% Summarizing input resourcefile data - -# 1. Consumable availability by category and level -#-------------------------------------------------- -tlo_availability_df = pd.read_csv(resourcefilepath / 'healthsystem'/ 'consumables' / "ResourceFile_Consumables_availability_small.csv") - -# Attach district, facility level, program to this dataset -mfl = pd.read_csv(resourcefilepath / "healthsystem" / "organisation" / "ResourceFile_Master_Facilities_List.csv") -districts = set(pd.read_csv(resourcefilepath / 'demography' / 'ResourceFile_Population_2010.csv')['District']) -fac_levels = {'0', '1a', '1b', '2', '3', '4'} -tlo_availability_df = tlo_availability_df.merge(mfl[['District', 'Facility_Level', 'Facility_ID']], - on = ['Facility_ID'], how='left') -# Attach programs -program_item_mapping = pd.read_csv(resourcefilepath / 'healthsystem'/ 'consumables' / 'ResourceFile_Consumables_Item_Designations.csv')[['Item_Code', 'item_category']] -program_item_mapping = program_item_mapping.rename(columns ={'Item_Code': 'item_code'})[program_item_mapping.item_category.notna()] -tlo_availability_df = tlo_availability_df.merge(program_item_mapping,on = ['item_code'], how='left') - -# First a heatmap of current availability -fac_levels = {'0': 'Health Post', '1a': 'Health Centers', '1b': 'Rural/Community \n Hospitals', '2': 'District Hospitals', '3': 'Central Hospitals', '4': 'Mental Hospital'} -chosen_fac_levels_for_plot = ['0', '1a', '1b', '2', '3', '4'] -correct_order_of_levels = ['Health Post', 'Health Centers', 'Rural/Community \n Hospitals', 'District Hospitals', 'Central Hospitals','Mental Hospital'] -df_for_plots = tlo_availability_df[tlo_availability_df.Facility_Level.isin(chosen_fac_levels_for_plot)] -df_for_plots['Facility_Level'] = df_for_plots['Facility_Level'].map(fac_levels) - -scenario_list = [1,2,3,6,7,8,10,11] -chosen_availability_columns = ['available_prop'] + [f'available_prop_scenario{i}' for i in - scenario_list] -scenario_names_dict = {'available_prop': 'Actual', 'available_prop_scenario1': 'General consumables', 'available_prop_scenario2': 'Vital medicines', - 'available_prop_scenario3': 'Pharmacist- managed', 'available_prop_scenario4': 'Level 1b', 'available_prop_scenario5': 'CHAM', - 'available_prop_scenario6': '75th percentile facility', 'available_prop_scenario7': '90th percentile facility', 'available_prop_scenario8': 'Best facility', - 'available_prop_scenario9': 'Best facility (including DHO)','available_prop_scenario10': 'HIV supply chain', 'available_prop_scenario11': 'EPI supply chain', - 'available_prop_scenario12': 'HIV moved to Govt supply chain'} -# recreate the chosen columns list based on the mapping above -chosen_availability_columns = [scenario_names_dict[col] for col in chosen_availability_columns] -df_for_plots = df_for_plots.rename(columns = scenario_names_dict) - -i = 0 -for avail_scenario in chosen_availability_columns: - # Generate a heatmap - # Pivot the DataFrame - aggregated_df = df_for_plots.groupby(['item_category', 'Facility_Level'])[avail_scenario].mean().reset_index() - heatmap_data = aggregated_df.pivot("item_category", "Facility_Level", avail_scenario) - heatmap_data = heatmap_data[correct_order_of_levels] # Maintain the order - - # Calculate the aggregate row and column - aggregate_col= aggregated_df.groupby('Facility_Level')[avail_scenario].mean() - aggregate_col = aggregate_col[correct_order_of_levels] - aggregate_row = aggregated_df.groupby('item_category')[avail_scenario].mean() - overall_aggregate = df_for_plots[avail_scenario].mean() - - # Add aggregate row and column - heatmap_data['Average'] = aggregate_row - aggregate_col['Average'] = overall_aggregate - heatmap_data.loc['Average'] = aggregate_col - - # Generate the heatmap - sns.set(font_scale=1.5) - plt.figure(figsize=(10, 8)) - sns.heatmap(heatmap_data, annot=True, cmap='RdYlGn', cbar_kws={'label': 'Proportion of days on which consumable is available'}) - - # Customize the plot - plt.title(scenarios[i]) - plt.xlabel('Facility Level') - plt.ylabel(f'Disease/Public health \n program') - plt.xticks(rotation=90) - plt.yticks(rotation=0) - - plt.savefig(figurespath /f'consumable_availability_heatmap_{avail_scenario}.png', dpi=300, bbox_inches='tight') - #plt.show() - plt.close() - i = i + 1 - -# TODO Justify the focus on levels 1a and 1b - where do HSIs occur?; at what level is there most misallocation within districts -# TODO get graphs of percentage of successful HSIs under different scenarios for levels 1a and 1b -# TODO is there a way to link consumables directly to DALYs (how many DALYs are lost due to stockouts of specific consumables) -# TODO why are there no appointments at level 1b - -# 2. Consumable demand not met -#----------------------------------------- -# Number of units of item which were needed but not made available for the top 25 items -# TODO ideally this should count the number of treatment IDs but this needs the detailed health system logger -def consumables_availability_figure(results_folder: Path, output_folder: Path, resourcefilepath: Path): - """ 'Figure 3': Usage of consumables in the HealthSystem""" - make_graph_file_name = lambda stub: output_folder / f"Fig3_consumables_availability_figure.png" # noqa: E731 - - def get_counts_of_items_requested(_df): - _df = drop_outside_period(_df) - - counts_of_available = defaultdict(int) - counts_of_not_available = defaultdict(int) - - for _, row in _df.iterrows(): - for item, num in row['Item_Available'].items(): - counts_of_available[item] += num - for item, num in row['Item_NotAvailable'].items(): # eval(row['Item_NotAvailable']) - counts_of_not_available[item] += num - - return pd.concat( - {'Available': pd.Series(counts_of_available), 'Not_Available': pd.Series(counts_of_not_available)}, - axis=1 - ).fillna(0).astype(int).stack() - - cons_req = summarize( - extract_results( - results_folder, - module='tlo.methods.healthsystem.summary', - key='Consumables', - custom_generate_series=get_counts_of_items_requested, - do_scaling=True - ), - only_mean=True, - collapse_columns=True - ) - - cons = cons_req.unstack() - cons_names = pd.read_csv( - resourcefilepath / 'healthsystem' / 'consumables' / 'ResourceFile_Consumables_Items_and_Packages.csv' - )[['Item_Code', 'Items']].set_index('Item_Code').drop_duplicates() - cons_names.index = cons_names.index.astype(str) - cons = cons.merge(cons_names, left_index=True, right_index=True, how='left').set_index('Items') #.astype(int) - cons = cons.assign(total=cons.sum(1)).sort_values('total').drop(columns='total') - - cons.columns = pd.MultiIndex.from_tuples(cons.columns, names=['draw', 'stat', 'var']) - cons_not_available = cons.loc[:, cons.columns.get_level_values(2) == 'Not_Available'] - cons_not_available.mean = cons_not_available.loc[:, cons_not_available.columns.get_level_values(1) == 'mean'] - cons_available = cons.loc[:, cons.columns.get_level_values(2) == 'Available'] - - cons_not_available = cons_not_available.unstack().reset_index() - cons_not_available = cons_not_available.rename(columns={0: 'qty_not_available'}) - -consumables_availability_figure(results_folder, outputspath, resourcefilepath) - -# TODO use squarify_plot to represent which consumables are most used in the system (by short Treatment_ID?) (not quantity but frequency) - -# HSI affected by missing consumables -# We need healthsystem logger for this - -# 3. Number of Health System Interactions -#----------------------------------------- -# HSIs taking place by level in the default scenario -def get_counts_of_hsis(_df): - _df = drop_outside_period(_df) - - # Initialize an empty dictionary to store the total counts - total_hsi_count = {} - - for date, appointment_dict in _df['Number_By_Appt_Type_Code_And_Level'].items(): - print(appointment_dict) - for level, appointments_at_level in appointment_dict.items(): - print(level, appointments_at_level) - total_hsi_count[level] = {} - for appointment_type, count in appointments_at_level.items(): - print(appointment_type, count) - if appointment_type in total_hsi_count: - total_hsi_count[level][appointment_type] += count - else: - total_hsi_count[level][appointment_type] = count - - total_hsi_count_series = pd.Series(total_hsi_count) - for level in ['0', '1a', '1b', '2', '3', '4']: - appointments_at_level = pd.Series(total_hsi_count_series[total_hsi_count_series.index == level].values[0], dtype='int') - # Create a list of tuples with the original index and the new level '1a' - new_index_tuples = [(idx, level) for idx in appointments_at_level.index] - # Create the new MultiIndex - new_index = pd.MultiIndex.from_tuples(new_index_tuples, names=['Appointment', 'Level']) - # Reindex the Series with the new MultiIndex - appointments_at_level_multiindex = appointments_at_level.copy() - appointments_at_level_multiindex.index = new_index - if level == '0': - appointments_all_levels = appointments_at_level_multiindex - else: - appointments_all_levels = pd.concat([appointments_all_levels, appointments_at_level_multiindex], axis = 0) - - return pd.Series(appointments_all_levels).fillna(0).astype(int) - -hsi_count = summarize( - extract_results( - results_folder, - module='tlo.methods.healthsystem.summary', - key='HSI_Event', - custom_generate_series=get_counts_of_hsis, - do_scaling=True - ), - only_mean=True, - collapse_columns=True -) - -hsi = hsi_count.assign(baseline_values=hsi_count[(0, 'mean')]).sort_values('baseline_values').drop(columns='baseline_values') -hsi.columns = pd.MultiIndex.from_tuples(hsi.columns, names=['draw', 'stat']) -#hsi = hsi.unstack().reset_index() -hsi_stacked = hsi.stack().stack().reset_index() -hsi_stacked = hsi_stacked.rename(columns={0: 'hsis_requested'}) - - -# 4.1 Number of Services delivered by long Treatment_ID -#------------------------------------------------------ -def get_counts_of_hsi_by_treatment_id(_df): - """Get the counts of the short TREATMENT_IDs occurring""" - _counts_by_treatment_id = _df \ - .loc[pd.to_datetime(_df['date']).between(*TARGET_PERIOD), 'TREATMENT_ID'] \ - .apply(pd.Series) \ - .sum() \ - .astype(int) - return _counts_by_treatment_id.groupby(level=0).sum() - -counts_of_hsi_by_treatment_id = summarize( - extract_results( - results_folder, - module='tlo.methods.healthsystem.summary', - key='HSI_Event', - custom_generate_series=get_counts_of_hsi_by_treatment_id, - do_scaling=True - ), - only_mean=True, - collapse_columns=True, -) - -counts_of_hsi_by_treatment_id = counts_of_hsi_by_treatment_id.assign(baseline_values=counts_of_hsi_by_treatment_id[(0, 'mean')]).sort_values('baseline_values').drop(columns='baseline_values') -hsi_by_treatment_id = counts_of_hsi_by_treatment_id.unstack().reset_index() -hsi_by_treatment_id = hsi_by_treatment_id.rename(columns={'level_2': 'Treatment_ID', 0: 'qty_of_HSIs'}) - -# hsi[(0,'mean')].sum()/counts_of_hsi_by_treatment_id[(0,'mean')].sum() - -# 4.2 Number of Services delivered by short Treatment ID -#-------------------------------------------------------- -def get_counts_of_hsi_by_short_treatment_id(_df): - """Get the counts of the short TREATMENT_IDs occurring (shortened, up to first underscore)""" - _counts_by_treatment_id = get_counts_of_hsi_by_treatment_id(_df) - _short_treatment_id = _counts_by_treatment_id.index.map(lambda x: x.split('_')[0] + "*") - return _counts_by_treatment_id.groupby(by=_short_treatment_id).sum() - - -counts_of_hsi_by_treatment_id_short = summarize( - extract_results( - results_folder, - module='tlo.methods.healthsystem.summary', - key='HSI_Event', - custom_generate_series=get_counts_of_hsi_by_short_treatment_id, - do_scaling=True - ), - only_mean=True, - collapse_columns=True, -) - -hsi_by_short_treatment_id = counts_of_hsi_by_treatment_id_short.unstack().reset_index() -hsi_by_short_treatment_id = hsi_by_short_treatment_id.rename(columns = {'level_2': 'Short_Treatment_ID', 0: 'qty_of_HSIs'}) - -# Cost of consumables? diff --git a/src/scripts/costing/cost_estimation.py b/src/scripts/costing/cost_estimation.py deleted file mode 100644 index fa6cfd4669..0000000000 --- a/src/scripts/costing/cost_estimation.py +++ /dev/null @@ -1,1902 +0,0 @@ -from pathlib import Path - -from tlo import Date -from collections import defaultdict -from typing import Optional, Union, Literal - -import datetime -import textwrap - -import matplotlib.pyplot as plt -import squarify -import numpy as np -import pandas as pd -import ast -import math -import itertools -from itertools import cycle -import matplotlib.container as mpc - -from tlo.analysis.utils import ( - extract_results, - get_scenario_info, - load_pickled_dataframes, - unflatten_flattened_multi_index_in_logging -) - -# Define a timestamp for script outputs -timestamp = datetime.datetime.now().strftime("_%Y_%m_%d_%H_%M") - -# Print the start time of the script -print('Script Start', datetime.datetime.now().strftime('%H:%M')) - -#%% - -# Define a function to discount and summarise costs by cost_category - -def apply_discounting_to_cost_data(_df: pd.DataFrame, - _discount_rate: Union[float, dict[int, float]] = 0, - _initial_year: Optional[int] = None, - _column_for_discounting: str = 'cost') -> pd.DataFrame: - """ - Apply discounting to the specified column over time, using a fixed or year-specific rate. - - Parameters: - ---------- - _df : pd.DataFrame - DataFrame containing a 'year' column and a cost column to be discounted. - - _discount_rate : float or dict of {year: float}, default 0 - Discount rate to apply. Can be: - - A single fixed rate (e.g., 0.03 for 3%) - - A dictionary of year-specific rates {2025: 0.03, 2026: 0.035, ...} - - _initial_year : int, optional - Reference year for discounting. If None, uses the earliest year in the DataFrame. - - _column_for_discounting : str, default 'cost' - Name of the column to apply discounting to. - - Returns: - ------- - pd.DataFrame - A copy of the input DataFrame with the specified column discounted in-place. - """ - - if _initial_year is None: - # Determine the initial year from the dataframe - _initial_year = min(_df['year'].unique()) - - def get_discount_factor(year): - """Compute the cumulative discount factor for a given year.""" - if isinstance(_discount_rate, dict): - # Compute the cumulative discount factor as the product of (1 + discount_rate) for all previous years - discount_factor = 1 - for y in range(_initial_year + 1, year + 1): # only starting from initial year + 1 as the discount factor for initial year should be 1 - discount_factor *= (1 + _discount_rate.get(y, 0)) # Default to 0 if year not in dictionary - return discount_factor - else: - # If a single value is provided, use standard discounting - return (1 + _discount_rate) ** (year - _initial_year) - - # Apply discounting to each row - _df.loc[:, _column_for_discounting] = _df[_column_for_discounting] / _df['year'].apply(get_discount_factor) - - return _df - -def estimate_input_cost_of_scenarios(results_folder: Path, - resourcefilepath: Path , - _draws: Optional[list[int]] = None, - _runs: Optional[list[int]] = None, - summarize: bool = False, - _metric: Literal['mean', 'median'] = 'mean', - _years: Optional[list[int]] = None, - cost_only_used_staff: bool = True, - _discount_rate: Union[float, dict[int, float]] = 0) -> pd.DataFrame: - """ - Estimate health system input costs for a given simulation. - - Parameters: - ---------- - results_folder : Path - Path to the directory containing simulation output files. - resourcefilepath : Path, optional - Path to the resource files - _draws : list, optional - Specific draws to include in the cost estimation. Defaults to all available draws. - _runs : list, optional - Specific runs to include in the cost estimation. Defaults to all runs. - summarize : bool, default False - Whether to summarize the costs across draws/runs with central metric (specified below) and confidence intervals. - _metric : {'mean', 'median'}, default 'mean' - Summary statistic to use if `summarize=True`. - _years : list of int, optional - Years to include in the cost output. If None, all years are included. - cost_only_used_staff : bool, default True - If True, only costs for level-cadre combinations ever used in simulation are included. - _discount_rate : float or dict of {int: float}, default 0 - Discount rate to apply to future costs. Can be a constant or year-specific dictionary. - - Returns: - ------- - pd.DataFrame - A dataframe containing discounted costs disaggregated by category, sub-category, category-specific subgroup, year, draw, and run. - Note that if a discount rate is used, the dataframe will provide cost as the NPV during the first year of the dataframe - """ - - # Useful common functions - def drop_outside_period(_df): - """Return a dataframe which only includes for which the date is within the limits defined by TARGET_PERIOD""" - return _df.drop(index=_df.index[~_df['date'].between(*TARGET_PERIOD)]) - - def melt_model_output_draws_and_runs(_df, id_vars): - multi_index = pd.MultiIndex.from_tuples(_df.columns) - _df.columns = multi_index - melted_df = pd.melt(_df, id_vars=id_vars).rename(columns={'variable_0': 'draw', 'variable_1': 'run'}) - return melted_df - - # Define a relative pathway for relavant folders - path_for_consumable_resourcefiles = resourcefilepath / "healthsystem/consumables" - - # %% Gathering basic information - # Load basic simulation parameters - #------------------------------------- - log = load_pickled_dataframes(results_folder, 0, 0) # read from 1 draw and run - info = get_scenario_info(results_folder) # get basic information about the results - if _draws is None: - _draws = range(0, info['number_of_draws']) - if _runs is None: - _runs = range(0, info['runs_per_draw']) - final_year_of_simulation = max(log['tlo.methods.healthsystem.summary']['hsi_event_counts']['date']).year - first_year_of_simulation = min(log['tlo.methods.healthsystem.summary']['hsi_event_counts']['date']).year - years = list(range(first_year_of_simulation, final_year_of_simulation + 1)) # this is the full period of the simulation but at the end of the function, years not needed for the final cost estimate are dropped - - # Load cost input files - #------------------------ - # Load primary costing resourcefile - workbook_cost = pd.read_excel((resourcefilepath / "costing/ResourceFile_Costing.xlsx"), - sheet_name = None) - - # Extract districts and facility levels from the Master Facility List - mfl = pd.read_csv(resourcefilepath / "healthsystem" / "organisation" / "ResourceFile_Master_Facilities_List.csv") - district_dict = pd.read_csv(resourcefilepath / 'demography' / 'ResourceFile_Population_2010.csv')[['District_Num', 'District']].drop_duplicates() - district_dict = dict(zip(district_dict['District_Num'], district_dict['District'])) - facility_id_levels_dict = dict(zip(mfl['Facility_ID'], mfl['Facility_Level'])) - fac_levels = set(mfl.Facility_Level) - - # Overall cost assumptions - TARGET_PERIOD = (Date(first_year_of_simulation, 1, 1), Date(final_year_of_simulation, 12, 31)) # Declare period for which the results will be generated (defined inclusively) - - # If variable discount rate is provided, use the average across the relevant years for the purpose of annuitization of HR and equipment costs - def calculate_annuitization_rate(_discount_rate, _years): - if isinstance(_discount_rate, (int, float)): - # Single discount rate, return as is - return _discount_rate - elif isinstance(_discount_rate, dict): - # Extract rates for the specified years (default to 0 if year is missing) - rates = [_discount_rate.get(year, 0) for year in _years] - return sum(rates) / len(rates) # Average discount rate - else: - raise ValueError("`_discount_rate` must be either a number (single rate) or a dictionary {year: rate}.") - - annuitization_rate = calculate_annuitization_rate(_discount_rate, _years) - - # Read all cost parameters - #--------------------------------------- - # Read parameters for HR costs - hr_cost_parameters = workbook_cost["human_resources"] - hr_cost_parameters['Facility_Level'] = hr_cost_parameters['Facility_Level'].astype(str) # Store Facility_Level as string - - # Read parameters for consumables costs - # Load consumables cost data - unit_price_consumable = workbook_cost["consumables"] - unit_price_consumable = unit_price_consumable.rename(columns=unit_price_consumable.iloc[0]) - unit_price_consumable = unit_price_consumable[['Item_Code', 'Final_price_per_chosen_unit (USD, 2023)']].reset_index(drop=True).iloc[1:] - unit_price_consumable = unit_price_consumable[unit_price_consumable['Item_Code'].notna()] - - # Load and prepare equipment cost parameters - # Unit costs of equipment - unit_cost_equipment = workbook_cost["equipment"] - unit_cost_equipment = unit_cost_equipment.rename(columns=unit_cost_equipment.iloc[7]).reset_index(drop=True).iloc[8:] - unit_cost_equipment = unit_cost_equipment[unit_cost_equipment['Item_code'].notna()] # drop empty row - # Calculate necessary costs based on HSSP-III assumptions - if _discount_rate == 0: - unit_cost_equipment['replacement_cost_annual'] = unit_cost_equipment.apply(lambda row: row['unit_purchase_cost'] / row['Life span'], axis=1) # straight line depreciation is discount rate is 0 - else: - unit_cost_equipment['replacement_cost_annual'] = unit_cost_equipment.apply(lambda row: row['unit_purchase_cost']/(1+(1-(1+annuitization_rate)**(-row['Life span']+1))/annuitization_rate), axis=1) # Annuitised over the life span of the equipment assuming outlay at the beginning of the year - unit_cost_equipment['service_fee_annual'] = unit_cost_equipment.apply(lambda row: row['unit_purchase_cost'] * 0.8 / 8 if row['unit_purchase_cost'] > 1000 else 0, axis=1) # 80% of the value of the item over 8 years - unit_cost_equipment['spare_parts_annual'] = unit_cost_equipment.apply(lambda row: row['unit_purchase_cost'] * 0.2 / 8 if row['unit_purchase_cost'] > 1000 else 0, axis=1) # 20% of the value of the item over 8 years - unit_cost_equipment['major_corrective_maintenance_cost_annual'] = unit_cost_equipment.apply(lambda row: row['unit_purchase_cost'] * 0.2 * 0.2 / 8 if row['unit_purchase_cost'] < 250000 else 0, axis=1) # 20% of the value of 20% of the items over 8 years - # TODO consider discounting the other components - # Quantity needed for each equipment by facility - unit_cost_equipment = unit_cost_equipment[['Item_code','Equipment_tlo', - 'replacement_cost_annual', 'service_fee_annual', 'spare_parts_annual', 'major_corrective_maintenance_cost_annual', - 'Health Post_prioritised', 'Community_prioritised', 'Health Center_prioritised', 'District_prioritised', 'Central_prioritised']] - unit_cost_equipment = unit_cost_equipment.rename(columns={col: 'Quantity_' + col.replace('_prioritised', '') for col in unit_cost_equipment.columns if col.endswith('_prioritised')}) - unit_cost_equipment = unit_cost_equipment.rename(columns={col: col.replace(' ', '_') for col in unit_cost_equipment.columns}) - - unit_cost_equipment = pd.wide_to_long(unit_cost_equipment, stubnames=['Quantity_'], - i=['Item_code', 'Equipment_tlo', 'replacement_cost_annual', 'service_fee_annual', 'spare_parts_annual', 'major_corrective_maintenance_cost_annual'], - j='Facility_Level', suffix='(\d+|\w+)').reset_index() - facility_level_mapping = {'Health_Post': '0', 'Health_Center': '1a', 'Community': '1b', 'District': '2', 'Central': '3'} - unit_cost_equipment['Facility_Level'] = unit_cost_equipment['Facility_Level'].replace(facility_level_mapping) - unit_cost_equipment = unit_cost_equipment.rename(columns = {'Quantity_': 'Quantity'}) - - # Load and prepare facility operation cost parameters - unit_cost_fac_operations = workbook_cost["facility_operations"] - - # Function to prepare cost dataframe ready to be merged across cross categories - def retain_relevant_column_subset(_df, _category_specific_group): - columns_to_retain = ['draw', 'run', 'year', 'cost_subcategory', 'Facility_Level', _category_specific_group, 'cost'] - if 'cost_category' in _df.columns: - columns_to_retain.append('cost_category') - _df = _df[columns_to_retain] - return _df - def prepare_cost_dataframe(_df, _category_specific_group, _cost_category): - _df = _df.rename(columns = {_category_specific_group: 'cost_subgroup'}) - _df['cost_category'] = _cost_category - return retain_relevant_column_subset(_df, 'cost_subgroup') - - - # CALCULATE ECONOMIC COSTS - #%% - # 1. HR cost - #------------------------ - print("Now estimating HR costs...") - # Define a function to merge unit cost data with model outputs - def merge_cost_and_model_data(cost_df, model_df, varnames): - merged_df = model_df.copy() - for varname in varnames: - new_cost_df = cost_df[cost_df['Parameter_name'] == varname][['OfficerType', 'Facility_Level', 'Value']] - new_cost_df = new_cost_df.rename(columns={"Value": varname}) - if ((new_cost_df['OfficerType'] == 'All').all()) and ((new_cost_df['Facility_Level'] == 'All').all()): - merged_df[varname] = new_cost_df[varname].mean() - elif ((new_cost_df['OfficerType'] == 'All').all()) and ((new_cost_df['Facility_Level'] == 'All').all() == False): - merged_df = pd.merge(merged_df, new_cost_df[['Facility_Level',varname]], on=['Facility_Level'], how="left") - elif ((new_cost_df['OfficerType'] == 'All').all() == False) and ((new_cost_df['Facility_Level'] == 'All').all()): - merged_df = pd.merge(merged_df, new_cost_df[['OfficerType',varname]], on=['OfficerType'], how="left") - else: - merged_df = pd.merge(merged_df, new_cost_df, on=['OfficerType', 'Facility_Level'], how="left") - return merged_df - - # Get available staff count for each year and draw - def get_staff_count_by_facid_and_officer_type(_df: pd.Series) -> pd.Series: - """Summarise the parsed logged-key results for one draw (as dataframe) into a pd.Series.""" - _df = _df.set_axis(_df['date'].dt.year).drop(columns=['date']) - _df.index.name = 'year' - - def change_to_standard_flattened_index_format(col): - parts = col.split("_", 3) # Split by "_" only up to 3 parts - if len(parts) > 2: - return parts[0] + "=" + parts[1] + "|" + parts[2] + "=" + parts[3] # Rejoin with "I" at the second occurrence - return col # If there's no second underscore, return the string as it is - _df.columns = [change_to_standard_flattened_index_format(col) for col in _df.columns] - - return unflatten_flattened_multi_index_in_logging(_df).stack(level=[0, 1]) # expanded flattened axis - - # Staff count by Facility ID - available_staff_count_by_facid_and_officertype = extract_results( - Path(results_folder), - module='tlo.methods.healthsystem.summary', - key='number_of_hcw_staff', - custom_generate_series=get_staff_count_by_facid_and_officer_type, - do_scaling=True, - ) - - # Update above series to get staff count by Facility_Level - available_staff_count_by_facid_and_officertype = available_staff_count_by_facid_and_officertype.reset_index().rename(columns= {'FacilityID': 'Facility_ID', 'Officer': 'OfficerType'}) - available_staff_count_by_facid_and_officertype['Facility_ID'] = pd.to_numeric(available_staff_count_by_facid_and_officertype['Facility_ID']) - available_staff_count_by_facid_and_officertype['Facility_Level'] = available_staff_count_by_facid_and_officertype['Facility_ID'].map(facility_id_levels_dict) - idx = pd.IndexSlice - available_staff_count_by_level_and_officer_type = available_staff_count_by_facid_and_officertype.drop(columns = [idx['Facility_ID']]).groupby([idx['year'], idx['Facility_Level'], idx['OfficerType']]).sum() - available_staff_count_by_level_and_officer_type = melt_model_output_draws_and_runs(available_staff_count_by_level_and_officer_type.reset_index(), id_vars= ['year', 'Facility_Level', 'OfficerType']) - available_staff_count_by_level_and_officer_type['Facility_Level'] = available_staff_count_by_level_and_officer_type['Facility_Level'].astype(str) # make sure facility level is stored as string - available_staff_count_by_level_and_officer_type = available_staff_count_by_level_and_officer_type.drop(available_staff_count_by_level_and_officer_type[available_staff_count_by_level_and_officer_type['Facility_Level'] == '5'].index) # drop headquarters because we're only concerned with staff engaged in service delivery - available_staff_count_by_level_and_officer_type.rename(columns ={'value': 'staff_count'}, inplace=True) - - # Get list of cadres which were utilised in each run to get the count of staff used in the simulation - # Note that we still cost the full staff count for any cadre-Facility_Level combination that was ever used in a run, and - # not the amount of time which was used - def get_capacity_used_by_officer_type_and_facility_level(_df: pd.Series) -> pd.Series: - """Summarise the parsed logged-key results for one draw (as dataframe) into a pd.Series.""" - _df = _df.set_axis(_df['date'].dt.year).drop(columns=['date']) - _df.index.name = 'year' - return unflatten_flattened_multi_index_in_logging(_df).stack(level=[0, 1]) # expanded flattened axis - - annual_capacity_used_by_cadre_and_level = extract_results( - Path(results_folder), - module='tlo.methods.healthsystem.summary', - key='Capacity_By_OfficerType_And_FacilityLevel', - custom_generate_series=get_capacity_used_by_officer_type_and_facility_level, - do_scaling=False, - ) - - # Prepare capacity used dataframe to be multiplied by staff count - average_capacity_used_by_cadre_and_level = annual_capacity_used_by_cadre_and_level.groupby(['OfficerType', 'FacilityLevel']).mean().reset_index(drop=False) - # TODO see if cadre-level combinations should be chosen by year - average_capacity_used_by_cadre_and_level.reset_index(drop=True) # Flatten multi=index column - average_capacity_used_by_cadre_and_level = average_capacity_used_by_cadre_and_level.melt(id_vars=['OfficerType', 'FacilityLevel'], - var_name=['draw', 'run'], - value_name='capacity_used') - list_of_cadre_and_level_combinations_used = average_capacity_used_by_cadre_and_level[average_capacity_used_by_cadre_and_level['capacity_used'] != 0][['OfficerType', 'FacilityLevel', 'draw', 'run']] - print(f"Out of {average_capacity_used_by_cadre_and_level.groupby(['OfficerType', 'FacilityLevel']).size().count()} cadre and level combinations available, {list_of_cadre_and_level_combinations_used.groupby(['OfficerType', 'FacilityLevel']).size().count()} are used across the simulations") - list_of_cadre_and_level_combinations_used = list_of_cadre_and_level_combinations_used.rename(columns = {'FacilityLevel':'Facility_Level'}) - - # Subset scenario staffing level to only include cadre-level combinations used in the simulation - used_staff_count_by_level_and_officer_type = available_staff_count_by_level_and_officer_type.merge(list_of_cadre_and_level_combinations_used, on = ['draw','run','OfficerType', 'Facility_Level'], how = 'right', validate = 'm:m') - used_staff_count_by_level_and_officer_type.rename(columns ={'value': 'staff_count'}, inplace=True) - - if (cost_only_used_staff): - print("The input for 'cost_only_used_staff' implies that only cadre-level combinations which have been used in the run are costed") - staff_size_chosen_for_costing = used_staff_count_by_level_and_officer_type - else: - print("The input for 'cost_only_used_staff' implies that all staff are costed regardless of the cadre-level combinations which have been used in the run are costed") - staff_size_chosen_for_costing = available_staff_count_by_level_and_officer_type - - # Calculate various components of HR cost - # 1.1 Salary cost for health workforce cadres used in the simulation (Staff count X Annual salary) - #--------------------------------------------------------------------------------------------------------------- - salary_for_staff = merge_cost_and_model_data(cost_df = hr_cost_parameters, model_df = staff_size_chosen_for_costing, - varnames = ['salary_usd']) - salary_for_staff['cost'] = salary_for_staff['salary_usd'] * salary_for_staff['staff_count'] - - # 1.2 Pre-service training & recruitment cost to fill gap created by attrition - #--------------------------------------------------------------------------------------------------------------- - preservice_training_cost = merge_cost_and_model_data(cost_df = hr_cost_parameters, model_df = staff_size_chosen_for_costing, - varnames = ['annual_attrition_rate', - 'licensure_exam_passing_rate', 'graduation_rate', - 'absorption_rate_of_students_into_public_workforce', 'proportion_of_workforce_recruited_from_abroad', - 'average_annual_preservice_training_cost_for_cadre', 'preservice_training_duration', 'recruitment_cost_per_person_recruited_usd', - 'average_length_of_tenure_in_the_public_sector']) - - def calculate_npv_past_training_expenses_by_row(row, r = _discount_rate): - # Initialize the NPV for the row - npv = 0 - annual_cost = row['average_annual_preservice_training_cost_for_cadre'] - full_years = int(row['preservice_training_duration']) # Extract integer part of the year - partial_year = row['preservice_training_duration'] - full_years # Fractional part of the year - - # Iterate over each year of the training duration to calculate compounded cost to the present - # Calculate NPV for each full year of training - for t in range(full_years): - npv += annual_cost * (1 + r) ** (t+1+1) # 1 added twice because range(4) is [0,1,2,3] - - # Account for the fractional year at the end if it exists - if partial_year > 0: - npv += annual_cost * partial_year * (1 + r) ** (1+r) - - # Add recruitment cost assuming this happens during the partial year or the year after graduation if partial year == 0 - npv += row['recruitment_cost_per_person_recruited_usd'] * (1+r) - - return npv - - # Calculate NPV for each row using iterrows and store in a new column - npv_values = [] - for index, row in preservice_training_cost.iterrows(): - npv = calculate_npv_past_training_expenses_by_row(row, r=annuitization_rate) - npv_values.append(npv) - - preservice_training_cost['npv_of_training_and_recruitment_cost'] = npv_values - preservice_training_cost['npv_of_training_and_recruitment_cost_per_recruit'] = preservice_training_cost['npv_of_training_and_recruitment_cost'] *\ - (1/(preservice_training_cost['absorption_rate_of_students_into_public_workforce'] + preservice_training_cost['proportion_of_workforce_recruited_from_abroad'])) *\ - (1/preservice_training_cost['graduation_rate']) * (1/preservice_training_cost['licensure_exam_passing_rate']) - if _discount_rate == 0: # if the discount rate is 0, then the pre-service + recruitment cost simply needs to be divided by the number of years in tenure - preservice_training_cost['annuitisation_rate'] = preservice_training_cost['average_length_of_tenure_in_the_public_sector'] - else: - preservice_training_cost['annuitisation_rate'] = 1 + (1 - (1 + annuitization_rate) ** (-preservice_training_cost['average_length_of_tenure_in_the_public_sector'] + 1)) / annuitization_rate - preservice_training_cost['annuitised_training_and_recruitment_cost_per_recruit'] = preservice_training_cost['npv_of_training_and_recruitment_cost_per_recruit']/preservice_training_cost['annuitisation_rate'] - - # Cost per student trained * 1/Rate of absorption from the local and foreign graduates * 1/Graduation rate * attrition rate - # the inverse of attrition rate is the average expected tenure; and the preservice training cost needs to be divided by the average tenure - preservice_training_cost['cost'] = preservice_training_cost['annuitised_training_and_recruitment_cost_per_recruit'] * preservice_training_cost['staff_count'] * preservice_training_cost['annual_attrition_rate'] # not multiplied with attrition rate again because this is already factored into 'Annual_cost_per_staff_recruited' - preservice_training_cost = preservice_training_cost[['draw', 'run', 'year', 'OfficerType', 'Facility_Level', 'cost']] - - # 1.3 In-service training cost to train all staff - #--------------------------------------------------------------------------------------------------------------- - inservice_training_cost = merge_cost_and_model_data(cost_df = hr_cost_parameters, model_df = staff_size_chosen_for_costing, - varnames = ['annual_inservice_training_cost_usd']) - inservice_training_cost['cost'] = inservice_training_cost['staff_count'] * inservice_training_cost['annual_inservice_training_cost_usd'] - inservice_training_cost = inservice_training_cost[['draw', 'run', 'year', 'OfficerType', 'Facility_Level', 'cost']] - # TODO Consider calculating economic cost of HR by multiplying salary times staff count with cadres_utilisation_rate - - # 1.4 Regular mentorship and supportive supervision costs - #--------------------------------------------------------------------------------------------------------------- - mentorship_and_supportive_cost = merge_cost_and_model_data(cost_df = hr_cost_parameters, model_df = staff_size_chosen_for_costing, - varnames = ['annual_mentorship_and_supervision_cost']) - mentorship_and_supportive_cost['cost'] = mentorship_and_supportive_cost['staff_count'] * mentorship_and_supportive_cost['annual_mentorship_and_supervision_cost'] - mentorship_and_supportive_cost = mentorship_and_supportive_cost[['draw', 'run', 'year', 'OfficerType', 'Facility_Level', 'cost']] - # TODO Consider calculating economic cost of HR by multiplying salary times staff count with cadres_utilisation_rate - - # 1.5 Store all HR costs in one standard format dataframe - #--------------------------------------------------------------------------------------------------------------- - # Function to melt and label the cost category - def label_rows_of_cost_dataframe(_df, label_var, label): - _df = _df.reset_index() - _df[label_var] = label - return _df - - # Initialize HR with the salary data - if (cost_only_used_staff): - human_resource_costs = retain_relevant_column_subset(label_rows_of_cost_dataframe(salary_for_staff, 'cost_subcategory', 'salary_for_cadres_used'), 'OfficerType') - # Concatenate additional cost categories - additional_costs = [ - (preservice_training_cost, 'preservice_training_and_recruitment_cost_for_attrited_workers'), - (inservice_training_cost, 'inservice_training_cost_for_cadres_used'), - (mentorship_and_supportive_cost, 'mentorship_and_supportive_cost_for_cadres_used') - ] - else: - human_resource_costs = retain_relevant_column_subset(label_rows_of_cost_dataframe(salary_for_staff, 'cost_subcategory', 'salary_for_all_staff'), 'OfficerType') - # Concatenate additional cost categories - additional_costs = [ - (preservice_training_cost, 'preservice_training_and_recruitment_cost_for_attrited_workers'), - (inservice_training_cost, 'inservice_training_cost_for_all_staff'), - (mentorship_and_supportive_cost, 'mentorship_and_supportive_cost_for_all_staff') - ] - - # Iterate through additional costs, melt and concatenate - for df, label in additional_costs: - labelled_df = retain_relevant_column_subset(label_rows_of_cost_dataframe(df, 'cost_subcategory', label), 'OfficerType') - human_resource_costs = pd.concat([human_resource_costs, labelled_df]) - - human_resource_costs = prepare_cost_dataframe(human_resource_costs, _category_specific_group = 'OfficerType', _cost_category = 'human resources for health') - - # Only preserve the draws and runs requested - if _draws is not None: - human_resource_costs = human_resource_costs[human_resource_costs.draw.isin(_draws)] - if _runs is not None: - human_resource_costs = human_resource_costs[human_resource_costs.run.isin(_runs)] - - # %% - # 2. Consumables cost - #------------------------ - print("Now estimating Consumables costs...") - def get_quantity_of_consumables_dispensed(results_folder): - def get_counts_of_items_requested(_df): - _df = drop_outside_period(_df) - counts_of_used = defaultdict(lambda: defaultdict(int)) - counts_of_not_available = defaultdict(lambda: defaultdict(int)) - - for _, row in _df.iterrows(): - date = row['date'] - for item, num in row['Item_Used'].items(): - counts_of_used[date][item] += num - for item, num in row['Item_NotAvailable'].items(): - counts_of_not_available[date][item] += num - used_df = pd.DataFrame(counts_of_used).fillna(0).astype(int).stack().rename('Used') - not_available_df = pd.DataFrame(counts_of_not_available).fillna(0).astype(int).stack().rename('Not_Available') - - # Combine the two dataframes into one series with MultiIndex (date, item, availability_status) - combined_df = pd.concat([used_df, not_available_df], axis=1).fillna(0).astype(int) - - # Convert to a pd.Series, as expected by the custom_generate_series function - return combined_df.stack() - - cons_req = extract_results( - results_folder, - module='tlo.methods.healthsystem.summary', - key='Consumables', - custom_generate_series=get_counts_of_items_requested, - do_scaling=True) - - cons_dispensed = cons_req.xs("Used", level=2) # only keep actual dispensed amount, i.e. when available - return cons_dispensed - # TODO Extract year of dispensing drugs - - consumables_dispensed = get_quantity_of_consumables_dispensed(results_folder) - consumables_dispensed = consumables_dispensed.reset_index().rename(columns = {'level_0': 'Item_Code', 'level_1': 'year'}) - consumables_dispensed[idx['year']] = pd.to_datetime(consumables_dispensed[idx['year']]).dt.year # Extract only year from date - consumables_dispensed[idx['Item_Code']] = pd.to_numeric(consumables_dispensed[idx['Item_Code']]) - # Make a list of columns in the DataFrame pertaining to quantity dispensed - quantity_columns = consumables_dispensed.columns.to_list() - quantity_columns = [tup for tup in quantity_columns if tup not in [('Item_Code', ''), ('year', '')]] - - # 2.1 Cost of consumables dispensed - #--------------------------------------------------------------------------------------------------------------- - # Multiply number of items needed by cost of consumable - #consumables_dispensed.columns = consumables_dispensed.columns.get_level_values(0).str() + "_" + consumables_dispensed.columns.get_level_values(1) # Flatten multi-level columns for pandas merge - unit_price_consumable.columns = pd.MultiIndex.from_arrays([unit_price_consumable.columns, [''] * len(unit_price_consumable.columns)]) - cost_of_consumables_dispensed = consumables_dispensed.merge(unit_price_consumable, on = idx['Item_Code'], validate = 'm:1', how = 'left') - price_column = 'Final_price_per_chosen_unit (USD, 2023)' - cost_of_consumables_dispensed[quantity_columns] = cost_of_consumables_dispensed[quantity_columns].multiply( - cost_of_consumables_dispensed[price_column], axis=0) - - # 2.2 Cost of consumables stocked (quantity needed for what is dispensed) - #--------------------------------------------------------------------------------------------------------------- - # Stocked amount should be higher than dispensed because of i. excess capacity, ii. theft, iii. expiry - # While there are estimates in the literature of what % these might be, we agreed that it is better to rely upon - # an empirical estimate based on OpenLMIS data - # Estimate the stock to dispensed ratio from OpenLMIS data - lmis_consumable_usage = pd.read_csv(path_for_consumable_resourcefiles / "ResourceFile_Consumables_availability_and_usage.csv") - # TODO Generate a smaller version of this file - # Collapse individual facilities - lmis_consumable_usage_by_item_level_month = lmis_consumable_usage.groupby(['category', 'item_code', 'district', 'fac_type_tlo', 'month'])[['closing_bal', 'dispensed', 'received']].sum() - df = lmis_consumable_usage_by_item_level_month # Drop rows where monthly OpenLMIS data wasn't available - df = df.loc[df.index.get_level_values('month') != "Aggregate"] - # Opening balance in January is the closing balance for the month minus what was received during the month plus what was dispensed - opening_bal_january = df.loc[df.index.get_level_values('month') == 'January', 'closing_bal'] + \ - df.loc[df.index.get_level_values('month') == 'January', 'dispensed'] - \ - df.loc[df.index.get_level_values('month') == 'January', 'received'] - closing_bal_december = df.loc[df.index.get_level_values('month') == 'December', 'closing_bal'] - # the consumable inflow during the year is the opening balance in January + what was received throughout the year - what was transferred to the next year (i.e. closing bal of December) - total_consumables_inflow_during_the_year = df.loc[df.index.get_level_values('month') != 'January', 'received'].groupby(level=[0,1,2,3]).sum() +\ - opening_bal_january.reset_index(level='month', drop=True) -\ - closing_bal_december.reset_index(level='month', drop=True) - total_consumables_outflow_during_the_year = df['dispensed'].groupby(level=[0,1,2,3]).sum() - inflow_to_outflow_ratio = total_consumables_inflow_during_the_year.div(total_consumables_outflow_during_the_year, fill_value=1) - - # Edit outlier ratios - inflow_to_outflow_ratio.loc[inflow_to_outflow_ratio < 1] = 1 # Ratio can't be less than 1 - inflow_to_outflow_ratio.loc[inflow_to_outflow_ratio > inflow_to_outflow_ratio.quantile(0.95)] = inflow_to_outflow_ratio.quantile(0.95) # Trim values greater than the 95th percentile - average_inflow_to_outflow_ratio_ratio = inflow_to_outflow_ratio.mean() # Use average where item-specific ratio is not available - - # Multiply number of items needed by cost of consumable - inflow_to_outflow_ratio_by_consumable = inflow_to_outflow_ratio.groupby(level='item_code').mean() - excess_stock_ratio = inflow_to_outflow_ratio_by_consumable - 1 - excess_stock_ratio = excess_stock_ratio.reset_index().rename(columns = {0: 'excess_stock_proportion_of_dispensed'}) - # TODO Consider whether a more disaggregated version of the ratio dictionary should be applied - cost_of_excess_consumables_stocked = consumables_dispensed.merge(unit_price_consumable, left_on = 'Item_Code', right_on = 'Item_Code', validate = 'm:1', how = 'left') - excess_stock_ratio.columns = pd.MultiIndex.from_arrays([excess_stock_ratio.columns, [''] * len(excess_stock_ratio.columns)]) # TODO convert this into a funciton - cost_of_excess_consumables_stocked = cost_of_excess_consumables_stocked.merge(excess_stock_ratio, left_on = 'Item_Code', right_on = 'item_code', validate = 'm:1', how = 'left') - cost_of_excess_consumables_stocked.loc[cost_of_excess_consumables_stocked.excess_stock_proportion_of_dispensed.isna(), 'excess_stock_proportion_of_dispensed'] = average_inflow_to_outflow_ratio_ratio - 1# TODO disaggregate the average by program - cost_of_excess_consumables_stocked[quantity_columns] = cost_of_excess_consumables_stocked[quantity_columns].multiply(cost_of_excess_consumables_stocked[idx[price_column]], axis=0) - cost_of_excess_consumables_stocked[quantity_columns] = cost_of_excess_consumables_stocked[quantity_columns].multiply(cost_of_excess_consumables_stocked[idx['excess_stock_proportion_of_dispensed']], axis=0) - - # 2.3 Store all consumable costs in one standard format dataframe - #--------------------------------------------------------------------------------------------------------------- - # Function to melt and label the cost category - consumables_dict = pd.read_csv(path_for_consumable_resourcefiles / 'ResourceFile_Consumables_Items_and_Packages.csv', low_memory=False, - encoding="ISO-8859-1")[['Items','Item_Code']] - consumables_dict = dict(zip(consumables_dict['Item_Code'], consumables_dict['Items'])) - def melt_and_label_consumables_cost(_df, label): - multi_index = pd.MultiIndex.from_tuples(_df.columns) - _df.columns = multi_index - # Select 'Item_Code', 'year', and all columns where both levels of the MultiIndex are numeric (these are the (draw,run) columns with cost values) - selected_columns = [col for col in _df.columns if - (col[0] in ['Item_Code', 'year']) or (isinstance(col[0], int) and isinstance(col[1], int))] - _df = _df[selected_columns] # Subset the dataframe with the selected columns - - # reshape dataframe and assign 'draw' and 'run' as the correct column headers - melted_df = pd.melt(_df, id_vars=['year', 'Item_Code']).rename(columns = {'variable_0': 'draw', 'variable_1': 'run'}) - # Replace item_code with consumable_name_tlo - melted_df['consumable'] = melted_df['Item_Code'].map(consumables_dict) - melted_df['cost_subcategory'] = label - melted_df['Facility_Level'] = 'all' #TODO this is temporary until 'tlo.methods.healthsystem.summary' only logs consumable at the aggregate level - melted_df = melted_df.rename(columns = {'value': 'cost'}) - return melted_df - - def disaggregate_separately_managed_medical_supplies_from_consumable_costs(_df, - _consumables_dict, # This is a dictionary mapping codes to names - list_of_unique_medical_products): - reversed_consumables_dict = {value: key for key, value in _consumables_dict.items()} # reverse dictionary to map names to codes - new_df = _df.copy() - new_df['item_code'] = new_df['consumable'].map(reversed_consumables_dict) - cost_of_consumables = new_df[~new_df['item_code'].isin(list_of_unique_medical_products)] - cost_of_separately_managed_medical_supplies = new_df[new_df['item_code'].isin(list_of_unique_medical_products)] - cost_of_separately_managed_medical_supplies['cost_subcategory'] = cost_of_separately_managed_medical_supplies['cost_subcategory'].replace( - {'consumables_dispensed': 'separately_managed_medical_supplies_dispensed', 'consumables_stocked': 'separately_managed_medical_supplies_stocked'}, regex=True) - return cost_of_consumables.drop(columns = 'item_code'), cost_of_separately_managed_medical_supplies.drop(columns = 'item_code') - - separately_managed_medical_supplies = [127, 141, 161] # Oxygen, Blood, IRS - cost_of_consumables_dispensed, cost_of_separately_managed_medical_supplies_dispensed = disaggregate_separately_managed_medical_supplies_from_consumable_costs(_df = retain_relevant_column_subset(melt_and_label_consumables_cost(cost_of_consumables_dispensed, 'cost_of_consumables_dispensed'), 'consumable'), - _consumables_dict = consumables_dict, - list_of_unique_medical_products = separately_managed_medical_supplies) - cost_of_excess_consumables_stocked, cost_of_separately_managed_medical_supplies_excess_stock = disaggregate_separately_managed_medical_supplies_from_consumable_costs(_df = retain_relevant_column_subset(melt_and_label_consumables_cost(cost_of_excess_consumables_stocked, 'cost_of_excess_consumables_stocked'), 'consumable'), - _consumables_dict=consumables_dict, - list_of_unique_medical_products=separately_managed_medical_supplies) - - consumable_costs = pd.concat([cost_of_consumables_dispensed, cost_of_excess_consumables_stocked]) - - # 2.4 Supply chain costs - #--------------------------------------------------------------------------------------------------------------- - # Assume that the cost of procurement, warehousing and distribution is a fixed proportion of consumable purchase costs - # The fixed proportion is based on Resource Mapping Expenditure data from 2018 - resource_mapping_data = workbook_cost["resource_mapping_r7_summary"] - # Make sure values are numeric - expenditure_column = ['EXPENDITURE (USD) (Jul 2018 - Jun 2019)'] - resource_mapping_data[expenditure_column] = resource_mapping_data[expenditure_column].apply(lambda x: pd.to_numeric(x, errors='coerce')) - # The numerator includes Supply chain expenditure for EHP consumables - supply_chain_expenditure = \ - resource_mapping_data[resource_mapping_data['Cost Type'] == 'Supply Chain'][expenditure_column].sum()[0] - # The denominator include all drugs and commodities expenditure, excluding what is recategorised as non-EHP or admin - drug_expenditure_condition = resource_mapping_data['Cost Type'].str.contains('Drugs and Commodities') - excluded_drug_expenditure_condition = (resource_mapping_data[ - 'Calibration_category'] == 'Program Management & Administration') | ( - resource_mapping_data[ - 'Calibration_category'] == 'Non-EHP consumables') - consumables_purchase_expenditure = \ - resource_mapping_data[drug_expenditure_condition][expenditure_column].sum()[0] - \ - resource_mapping_data[drug_expenditure_condition & excluded_drug_expenditure_condition][ - expenditure_column].sum()[0] - supply_chain_cost_proportion = supply_chain_expenditure / consumables_purchase_expenditure - - # Estimate supply chain costs based on the total consumable purchase cost calculated above - # Note that Oxygen, IRS, and Blood costs are already excluded because the unit_cost of these commodities already - # includes the procurement/production, storage and distribution costs - supply_chain_costs = (consumable_costs.groupby(['draw', 'run', 'year'])[ - 'cost'].sum() * supply_chain_cost_proportion).reset_index() - # Assign relevant additional columns to match the format of the rest of consumables costs - supply_chain_costs['Facility_Level'] = 'all' - supply_chain_costs['consumable'] = 'supply chain (all consumables)' - supply_chain_costs['cost_subcategory'] = 'supply_chain' - assert set(supply_chain_costs.columns) == set(consumable_costs.columns) - - # Append supply chain costs to the full consumable cost dataframe - consumable_costs = pd.concat([consumable_costs, supply_chain_costs]) - other_costs = pd.concat([cost_of_separately_managed_medical_supplies_dispensed, cost_of_separately_managed_medical_supplies_excess_stock]) - - consumable_costs = prepare_cost_dataframe(consumable_costs, _category_specific_group = 'consumable', _cost_category = 'medical consumables') - other_costs = prepare_cost_dataframe(other_costs, _category_specific_group = 'consumable', _cost_category = 'medical consumables') - - # Only preserve the draws and runs requested - if _draws is not None: - consumable_costs = consumable_costs[consumable_costs.draw.isin(_draws)] - other_costs = other_costs[other_costs.draw.isin(_draws)] - if _runs is not None: - consumable_costs = consumable_costs[consumable_costs.run.isin(_runs)] - other_costs = other_costs[other_costs.run.isin(_runs)] - - - # %% - # 3. Equipment cost - #-------------------------------------------- - print("Now estimating Medical equipment costs...") - # Total cost of equipment required as per SEL (HSSP-III) only at facility IDs where it has been used in the simulation - # Get list of equipment used in the simulation by district and level - def get_equipment_used_by_district_and_facility(_df: pd.Series) -> pd.Series: - """Summarise the parsed logged-key results for one draw (as dataframe) into a pd.Series.""" - _df = _df.pivot_table(index=['District', 'Facility_Level'], - values='EquipmentEverUsed', - aggfunc='first') - _df.index.name = 'year' - return _df['EquipmentEverUsed'] - - list_of_equipment_used_by_draw_and_run = extract_results( - Path(results_folder), - module='tlo.methods.healthsystem.summary', - key='EquipmentEverUsed_ByFacilityID', - custom_generate_series=get_equipment_used_by_district_and_facility, - do_scaling=False, - ) - for col in list_of_equipment_used_by_draw_and_run.columns: - list_of_equipment_used_by_draw_and_run[col] = list_of_equipment_used_by_draw_and_run[col].apply(ast.literal_eval) - - # Initialize an empty DataFrame - equipment_cost_across_sim = pd.DataFrame() - - # Extract equipment cost for each draw and run - for d in _draws: - for r in _runs: - print(f"Processing draw {d} and run {r} of equipment costs") - # Extract a list of equipment which was used at each facility level within each district - equipment_used = {district: {level: [] for level in fac_levels} for district in list(district_dict.values())} # create a dictionary with a key for each district and facility level - list_of_equipment_used_by_current_draw_and_run = list_of_equipment_used_by_draw_and_run[(d, r)].reset_index() - for dist in list(district_dict.values()): - for level in fac_levels: - equipment_used_subset = list_of_equipment_used_by_current_draw_and_run[(list_of_equipment_used_by_current_draw_and_run['District'] == dist) & (list_of_equipment_used_by_current_draw_and_run['Facility_Level'] == level)] - equipment_used_subset.columns = ['District', 'Facility_Level', 'EquipmentEverUsed'] - equipment_used[dist][level] = set().union(*equipment_used_subset['EquipmentEverUsed']) - equipment_used = pd.concat({ - k: pd.DataFrame.from_dict(v, 'index') for k, v in equipment_used.items()}, - axis=0) - full_list_of_equipment_used = set(equipment_used.values.flatten()) - full_list_of_equipment_used = set(filter(pd.notnull, full_list_of_equipment_used)) - - equipment_df = pd.DataFrame() - equipment_df.index = equipment_used.index - for item in full_list_of_equipment_used: - equipment_df[str(item)] = 0 - for dist_fac_index in equipment_df.index: - equipment_df.loc[equipment_df.index == dist_fac_index, str(item)] = equipment_used[equipment_used.index == dist_fac_index].isin([item]).any(axis=1) - #equipment_df.to_csv('./outputs/equipment_use.csv') - - equipment_df = equipment_df.reset_index().rename(columns = {'level_0' : 'District', 'level_1': 'Facility_Level'}) - equipment_df = pd.melt(equipment_df, id_vars = ['District', 'Facility_Level']).rename(columns = {'variable': 'Item_code', 'value': 'whether_item_was_used'}) - equipment_df['Item_code'] = pd.to_numeric(equipment_df['Item_code']) - # Merge the count of facilities by district and level - equipment_df = equipment_df.merge(mfl[['District', 'Facility_Level','Facility_Count']], on = ['District', 'Facility_Level'], how = 'left') - equipment_df.loc[equipment_df.Facility_Count.isna(), 'Facility_Count'] = 0 - - # Because levels 1b and 2 are collapsed together, we assume that the same equipment is used by level 1b as that recorded for level 2 - def update_itemuse_for_level1b_using_level2_data(_df): - # Create a list of District and Item_code combinations for which use == True - list_of_equipment_used_at_level2 = _df[(_df.Facility_Level == '2') & (_df['whether_item_was_used'] == True)][['District', 'Item_code']] - # Now update the 'whether_item_was_used' for 'Facility_Level' == '1b' to match that of level '2' - _df.loc[ - (_df['Facility_Level'] == '1b') & - (_df[['District', 'Item_code']].apply(tuple, axis=1).isin( - list_of_equipment_used_at_level2.apply(tuple, axis=1))), - 'whether_item_was_used' - ] = True - - return _df - - equipment_df = update_itemuse_for_level1b_using_level2_data(equipment_df) - - # Merge the two datasets to calculate cost - equipment_cost = pd.merge(equipment_df, unit_cost_equipment[['Item_code', 'Equipment_tlo', 'Facility_Level', 'Quantity', 'replacement_cost_annual', 'service_fee_annual', 'spare_parts_annual', 'major_corrective_maintenance_cost_annual']], - on = ['Item_code', 'Facility_Level'], how = 'left', validate = "m:1") - categories_of_equipment_cost = ['replacement_cost', 'service_fee', 'spare_parts', 'major_corrective_maintenance_cost'] - for cost_category in categories_of_equipment_cost: - # Rename unit cost columns - unit_cost_column = cost_category + '_annual_unit' - equipment_cost = equipment_cost.rename(columns = {cost_category + '_annual':unit_cost_column }) - equipment_cost[cost_category + '_annual_total'] = equipment_cost[cost_category + '_annual_unit'] * equipment_cost['whether_item_was_used'] * equipment_cost['Quantity'] * equipment_cost['Facility_Count'] - equipment_cost['year'] = final_year_of_simulation - 1 - if equipment_cost_across_sim.empty: - equipment_cost_across_sim = equipment_cost.groupby(['year', 'Facility_Level', 'Equipment_tlo'])[[item + '_annual_total' for item in categories_of_equipment_cost]].sum() - equipment_cost_across_sim['draw'] = d - equipment_cost_across_sim['run'] = r - else: - equipment_cost_for_current_sim = equipment_cost.groupby(['year', 'Facility_Level', 'Equipment_tlo'])[[item + '_annual_total' for item in categories_of_equipment_cost]].sum() - equipment_cost_for_current_sim['draw'] = d - equipment_cost_for_current_sim['run'] = r - # Concatenate the results - equipment_cost_across_sim = pd.concat([equipment_cost_across_sim, equipment_cost_for_current_sim], axis=0) - - equipment_costs = pd.melt(equipment_cost_across_sim.reset_index(), - id_vars=['draw', 'run', 'Facility_Level', 'Equipment_tlo'], # Columns to keep - value_vars=[col for col in equipment_cost_across_sim.columns if col.endswith('_annual_total')], # Columns to unpivot - var_name='cost_subcategory', # New column name for the 'sub-category' of cost - value_name='cost') # New column name for the values - - # Assume that the annual costs are constant each year of the simulation - equipment_costs = pd.concat([equipment_costs.assign(year=year) for year in years]) - # TODO If the logger is updated to include year, we may wish to calculate equipment costs by year - currently we assume the same annuitised equipment cost each year - equipment_costs = equipment_costs.reset_index(drop=True) - equipment_costs = equipment_costs.rename(columns = {'Equipment_tlo': 'Equipment'}) - equipment_costs = prepare_cost_dataframe(equipment_costs, _category_specific_group = 'Equipment', _cost_category = 'medical equipment') - - # 4. Facility running costs - # Average running costs by facility level and district times the number of facilities in the simulation - # Convert unit_costs to long format - unit_cost_fac_operations = pd.melt( - unit_cost_fac_operations, - id_vars=["Facility_Level"], # Columns to keep as identifiers - var_name="operating_cost_type", # Name for the new 'cost_category' column - value_name="unit_cost" # Name for the new 'cost' column - ) - unit_cost_fac_operations['Facility_Level'] = unit_cost_fac_operations['Facility_Level'].astype(str) - fac_count_by_level = mfl[['Facility_Level', 'Facility_Count']].groupby(['Facility_Level']).sum().reset_index() - - facility_operation_cost = pd.merge(unit_cost_fac_operations, fac_count_by_level, on = 'Facility_Level', how = 'left', validate = 'm:m') - facility_operation_cost['Facility_Count'] = facility_operation_cost['Facility_Count'].fillna(0).astype(int) - facility_operation_cost['cost'] = facility_operation_cost['unit_cost'] * facility_operation_cost['Facility_Count'] - - # Duplicate the same set of facility operation costs for all draws and runs - # Create the Cartesian product of `_draws` and `_runs` - combinations = list(itertools.product(_draws, _runs)) - comb_df = pd.DataFrame(combinations, columns=["draw", "run"]) - facility_operation_cost = facility_operation_cost.merge(comb_df, how="cross") - facility_operation_cost['cost_category'] = 'Facility operating cost' - operating_cost_mapping = {'Electricity': 'utilities_and_maintenance', 'Water': 'utilities_and_maintenance', 'Cleaning':'utilities_and_maintenance', - 'Security':'utilities_and_maintenance', 'Building maintenance': 'building_maintenance', - 'Facility management': 'utilities_and_maintenance', 'Vehicle maintenance': 'vehicle_maintenance', - 'Ambulance fuel': 'fuel_for_ambulance', 'Food for inpatient cases': 'food_for_inpatient_care'} - facility_operation_cost['cost_subcategory'] = facility_operation_cost['operating_cost_type'] - facility_operation_cost['cost_subcategory'] = facility_operation_cost['cost_subcategory'].map(operating_cost_mapping) - # Assume that the annual costs are constant each year of the simulation - facility_operation_cost = pd.concat([facility_operation_cost.assign(year=year) for year in years]) - - # Assume that the annual costs are constant each year of the simulation - facility_operation_cost = prepare_cost_dataframe(facility_operation_cost, _category_specific_group = 'operating_cost_type', _cost_category = 'facility operating cost') - - - # %% - # Store all costs in single dataframe - #-------------------------------------------- - scenario_cost = pd.concat([human_resource_costs, consumable_costs, equipment_costs, other_costs, facility_operation_cost], ignore_index=True) - scenario_cost['cost'] = pd.to_numeric(scenario_cost['cost'], errors='coerce') - - # Summarize costs - if summarize: - groupby_cols = [col for col in scenario_cost.columns if col not in ['run', 'cost']] - # Use the summary metric specific in the inputs - if _metric not in ['mean', 'median']: - raise ValueError(f"Invalid input for _metric: '{_metric}'. " - f"Values need to be one of 'mean' or 'median'") - else: - # Define aggregation function based on _metric input (mean or median) - agg_func = np.mean if _metric == 'mean' else np.median - - scenario_cost = pd.concat( - { - _metric: scenario_cost.groupby(by=groupby_cols, sort=False)['cost'].agg(agg_func), - 'lower': scenario_cost.groupby(by=groupby_cols, sort=False)['cost'].quantile(0.025), - 'upper': scenario_cost.groupby(by=groupby_cols, sort=False)['cost'].quantile(0.975), - }, - axis=1 - ) - - scenario_cost = pd.melt( - scenario_cost.reset_index(), - id_vars=groupby_cols, # Columns to keep - value_vars=[_metric, 'lower', 'upper'], # Columns to unpivot - var_name='stat', # New column name for the 'sub-category' of cost - value_name='cost' - ) - - if _years is None: - return apply_discounting_to_cost_data(_df = scenario_cost, - _discount_rate = _discount_rate, _column_for_discounting = 'cost') - else: - return apply_discounting_to_cost_data(_df = scenario_cost[scenario_cost.year.isin(_years)], - _discount_rate = _discount_rate, - _column_for_discounting = 'cost') - -# Define a function to summarize cost data from -# Note that the dataframe needs to have draw as index and run as columns. if the dataframe is long with draw and run as index, then -# first unstack the dataframe and subsequently apply the summarize function -def summarize_cost_data(_df, - _metric: Literal['mean', 'median'] = 'mean') -> pd.DataFrame: - """ - Summarize cost data across runs by computing central tendency and 95% confidence intervals. - - Parameters: - ---------- - _df : pd.DataFrame - A DataFrame with draw as index and run as columns, where each cell contains a cost value. - - Rows = draw IDs (e.g., 0, 1, 2) - - Columns = run IDs (e.g., 0, 1, 2) - - Values = cost estimates - - _metric : {'mean', 'median'}, default 'mean' - The central summary statistic to compute across runs. - - Returns: - ------- - pd.DataFrame - A pivoted DataFrame with draws as index and a MultiIndex of columns: - (run ID, ['mean' or 'median', 'lower', 'upper']), where: - - 'lower' = 2.5th percentile - - 'upper' = 97.5th percentile - """ - - if _metric not in ['mean', 'median']: - raise ValueError(f"Invalid input for _metric: '{_metric}'. " - f"Values need to be one of 'mean' or 'median'") - - _df = _df.stack() - collapsed_df = _df.groupby(level='draw').agg([ - _metric, - ('lower', lambda x: x.quantile(0.025)), - ('upper', lambda x: x.quantile(0.975)) - ]) - - collapsed_df = collapsed_df.unstack() - collapsed_df.index = collapsed_df.index.set_names('stat', level=0) - collapsed_df = collapsed_df.unstack(level='stat') - return collapsed_df - -# Estimate projected health spending -#################################################### -def estimate_projected_health_spending(resourcefilepath: Path, - results_folder: Path, - _draws: Optional[list[int]] = None, - _runs: Optional[list[int]] = None, - _years: Optional[list[int]] = None, - _discount_rate: float = 0, - _summarize: bool = False, - _metric: Literal['mean', 'median'] = 'mean') -> pd.DataFrame: - """ - Estimate total projected health spending for a simulation period. - - Combines health spending per capita projections (Dieleman et al, 2019) with simulated population estimates to calculate - total health expenditure, optionally applying a discount rate and summarizing across runs. - - Parameters: - ---------- - resourcefilepath : Path - Path to the folder containing the costing resource Excel files. - results_folder : Path - Path to the simulation results folder. - _draws : list or range, optional - Draws to include. If None, all available draws are used. - _runs : list or range, optional - Runs to include. If None, all available runs are used. - _years : list of int, optional - Years to include. If None, includes the full simulation period. - _discount_rate : float, default 0 - Discount rate applied to future costs. - _summarize : bool, default False - Whether to summarize output across runs using mean/median and 95% confidence intervals. - _metric : {'mean', 'median'}, default 'mean' - Central tendency metric used if summarizing. - - Returns: - ------- - pd.DataFrame - If `_summarize=True`, returns a DataFrame with: - - Index = draw - - Columns = 'mean'/'median', 'lower', 'upper' ROI values - - If `_summarize=False`, returns a DataFrame with: - - Index = draw - - Columns = run - - Values = discounted total health spending for the selected years - """ - - # %% Gathering basic information - # Load basic simulation parameters - #------------------------------------- - log = load_pickled_dataframes(results_folder, 0, 0) # read from 1 draw and run - info = get_scenario_info(results_folder) # get basic information about the results - if _draws is None: - _draws = range(0, info['number_of_draws']) - if _runs is None: - _runs = range(0, info['runs_per_draw']) - final_year_of_simulation = max(log['tlo.methods.healthsystem.summary']['hsi_event_counts']['date']).year - first_year_of_simulation = min(log['tlo.methods.healthsystem.summary']['hsi_event_counts']['date']).year - if _years == None: - _years = list(range(first_year_of_simulation, final_year_of_simulation + 1)) - - # Load health spending per capita projections - #---------------------------------------- - # Load health spending projections - workbook_cost = pd.read_excel((resourcefilepath / "costing/ResourceFile_Costing.xlsx"), - sheet_name=None) - health_spending_per_capita = workbook_cost["health_spending_projections"] - # Assign the fourth row as column names - health_spending_per_capita.columns = health_spending_per_capita.iloc[1] - health_spending_per_capita = health_spending_per_capita.iloc[2:].reset_index(drop=True) - health_spending_per_capita = health_spending_per_capita[ - health_spending_per_capita.year.isin(list(range(2015, 2041)))] - total_health_spending_per_capita_mean = health_spending_per_capita[['year', 'total_mean']].set_index('year') - total_health_spending_per_capita_mean.columns = pd.MultiIndex.from_tuples([('total_mean', '')]) - - # Load population projections - # ---------------------------------------- - def get_total_population(_df): - years_needed = [min(_years), max(_years)] # we only consider the population for the malaria scale-up period - # because those are the years relevant for malaria scale-up costing - _df['year'] = pd.to_datetime(_df['date']).dt.year - _df = _df[['year', 'total']] - assert set(_df.year.unique()).issuperset(years_needed), "Some years are not recorded." - return pd.Series(_df.loc[_df.year.between(*years_needed)].set_index('year')['total']) - - total_population_by_year = extract_results( - results_folder, - module='tlo.methods.demography', - key='population', - custom_generate_series=get_total_population, - do_scaling=True - ) - population_columns = total_population_by_year.columns - - # Estimate total health spending - projected_health_spending = pd.merge(total_health_spending_per_capita_mean, - total_population_by_year, - left_index=True, right_index=True,how='inner') - projected_health_spending = projected_health_spending.apply(pd.to_numeric, errors='coerce') - projected_health_spending[population_columns] = projected_health_spending[population_columns].multiply( - projected_health_spending['total_mean'], axis=0) - projected_health_spending = projected_health_spending[population_columns] - - # Apply discount rate - # Reformat dataframe to apply discounting function - projected_health_spending.columns.names = ['draw', 'run'] - projected_health_spending = projected_health_spending.stack(level=['draw', 'run']).reset_index() - projected_health_spending.columns = ['year', 'draw', 'run', 'total_spending'] - - # Initial year and discount rate - initial_year = min(projected_health_spending['year'].unique()) - projected_health_spending_discounted = apply_discounting_to_cost_data( - projected_health_spending, _discount_rate= _discount_rate, - _column_for_discounting='total_spending', _initial_year = initial_year) - projected_health_spending_discounted = projected_health_spending_discounted.groupby(['draw', 'run'])['total_spending'].sum() - - if _summarize == True: - if _metric == 'mean': - # Calculate the mean and 95% confidence intervals for each group - projected_health_spending_discounted = projected_health_spending_discounted.groupby(level="draw").agg( - mean=np.mean, - lower=lambda x: np.percentile(x, 2.5), - upper=lambda x: np.percentile(x, 97.5) - ) - - elif _metric == 'median': - # Calculate the mean and 95% confidence intervals for each group - projected_health_spending_discounted = projected_health_spending_discounted.groupby(level="draw").agg( - median=np.median, - lower=lambda x: np.percentile(x, 2.5), - upper=lambda x: np.percentile(x, 97.5) - ) - - else: - raise ValueError(f"Invalid input for _metric: '{_metric}'. " - f"Values need to be one of 'mean' or 'median'") - # Flatten the resulting DataFrame into a single-level MultiIndex Series - projected_health_spending_discounted = projected_health_spending_discounted.stack().rename_axis(["draw", "stat"]).rename("value") - - return projected_health_spending_discounted.unstack() - -# Plot costs -#################################################### -# 1. Stacked bar plot (Total cost + Cost categories) -#---------------------------------------------------- -def do_stacked_bar_plot_of_cost_by_category(_df: pd.DataFrame, - _cost_category: Literal['all', 'human resources for health', 'medical consumables', - 'medical equipment', 'facility operating cost'] = 'all', - _disaggregate_by_subgroup: bool = False, - _year: list[int] = 'all', - _draws: Optional[list[int]] = None, - _scenario_dict: Optional[dict[int,str]] = None, - show_title: bool = True, - _outputfilepath: Optional[Path] = None, - _add_figname_suffix: str = ''): - """ - Create and save a stacked bar chart of costs by category, subcategory or subgroup. - - Parameters: - ---------- - _df : pd.DataFrame - DataFrame with cost results, including columns: - ['draw', 'year', 'cost_category', 'cost_subcategory', 'cost_subgroup', - 'cost', 'stat'] — typically produced by `estimate_input_cost_of_scenarios`. - - _cost_category : str, default 'all' - If 'all', compares high-level categories (e.g., HR, consumables, equipment, facilty operations). - Otherwise, filters to a specific category and optionally disaggregates. - - _disaggregate_by_subgroup : bool, default False - If True and a single `_cost_category` is selected, breaks down costs by `cost_subgroup`. - - _year : str or list of int, default 'all' - Year or years to include. Can be: - - 'all' to include all available years - - a single year or multiple years as a list: [2025] - - _draws : list of int, optional - If specified, only includes the specified draws. - - _scenario_dict : dict, required - Dictionary mapping draw numbers to scenario names, used for x-axis labels. - - show_title : bool, default True - Whether to display the chart title. - - _outputfilepath : Path, optional - Folder to save the plot. File will be saved as a PNG using `_cost_category` - and `_add_figname_suffix` in the filename. - - _add_figname_suffix : str, default '' - Optional string to append to the saved figure's filename - - Returns: - ------- - None - The chart is saved to disk as a PNG. - """ - # Subset and Pivot the data to have 'Cost Sub-category' as columns - # Check what's the correct central metric to use (either 'mean' or 'median') - central_metric = [stat for stat in _df.stat.unique() if stat not in ['lower', 'upper']][0] - - # Make a copy of the dataframe to avoid modifying the original - _df_central = _df[_df.stat == central_metric].copy() - _df_lower = _df[_df.stat == 'lower'].copy() - _df_upper = _df[_df.stat == 'upper'].copy() - - # Subset the dataframes to keep the s=relevant categories for the plot - dfs = {"_df_central": _df_central, "_df_lower": _df_lower, "_df_upper": _df_upper} # create a dict of dataframes - for name, df in dfs.items(): - dfs[name] = df.copy() # Choose the dataframe to modify - # Convert 'cost' to millions - dfs[name]['cost'] = dfs[name]['cost'] / 1e6 - # Subset data - if _draws is not None: - dfs[name] = dfs[name][dfs[name].draw.isin(_draws)] - if _year != 'all': - dfs[name] = dfs[name][dfs[name]['year'].isin(_year)] - if _cost_category != 'all': - dfs[name] = dfs[name][dfs[name]['cost_category'] == _cost_category] - - # Extract the updated DataFrames back from the dictionary - _df_central, _df_lower, _df_upper = dfs["_df_central"], dfs["_df_lower"], dfs["_df_upper"] - - if _cost_category == 'all': - if (_disaggregate_by_subgroup == True): - raise ValueError(f"Invalid input for _disaggregate_by_subgroup: '{_disaggregate_by_subgroup}'. " - f"Value can be True only when plotting a specific _cost_category") - else: - pivot_central = _df_central.pivot_table(index='draw', columns='cost_category', values='cost', aggfunc='sum') - pivot_lower = _df_lower.pivot_table(index='draw', columns='cost_category', values='cost', aggfunc='sum') - pivot_upper = _df_upper.pivot_table(index='draw', columns='cost_category', values='cost', aggfunc='sum') - else: - if (_disaggregate_by_subgroup == True): - for name, df in dfs.items(): - dfs[name] = df.copy() # Choose the dataframe to modify - # If sub-groups are more than 10 in number, then disaggregate the top 10 and group the rest into an 'other' category - if (len(dfs[name]['cost_subgroup'].unique()) > 10): - # Calculate total cost per subgroup - subgroup_totals = dfs[name].groupby('cost_subgroup')['cost'].sum() - # Identify the top 10 subgroups by cost - top_10_subgroups = subgroup_totals.nlargest(10).index.tolist() - # Label the remaining subgroups as 'other' - dfs[name]['cost_subgroup'] = dfs[name]['cost_subgroup'].apply( - lambda x: x if x in top_10_subgroups else 'All other items' - ) - - # Extract the updated DataFrames back from the dictionary - _df_central, _df_lower, _df_upper = dfs["_df_central"], dfs["_df_lower"], dfs["_df_upper"] - - pivot_central = _df_central.pivot_table(index='draw', columns='cost_subgroup', - values='cost', aggfunc='sum') - pivot_lower = _df_lower.pivot_table(index='draw', columns='cost_subgroup', - values='cost', aggfunc='sum') - pivot_upper = _df_upper.pivot_table(index='draw', columns='cost_subgroup', - values='cost', aggfunc='sum') - - plt_name_suffix = '_by_subgroup' - else: - pivot_central = _df_central.pivot_table(index='draw', columns='cost_subcategory', values='cost', aggfunc='sum') - pivot_lower = _df_lower.pivot_table(index='draw', columns='cost_subcategory', values='cost', aggfunc='sum') - pivot_upper = _df_upper.pivot_table(index='draw', columns='cost_subcategory', values='cost', aggfunc='sum') - plt_name_suffix = '' - - # Sort pivot_df columns in ascending order by total cost - sorted_columns = pivot_central.sum(axis=0).sort_values().index - pivot_central = pivot_central[sorted_columns] - pivot_lower = pivot_lower[sorted_columns] - pivot_upper = pivot_upper[sorted_columns] - - # Error bars - lower_bounds = pivot_central.sum(axis=1) - pivot_lower.sum(axis=1) - lower_bounds[lower_bounds<0] = 0 - upper_bounds = pivot_upper.sum(axis=1) - pivot_central.sum(axis=1) - - if _cost_category == 'all': - # Predefined color mapping for cost categories - color_mapping = { - 'human resources for health': '#1f77b4', # Muted blue - 'medical consumables': '#ff7f0e', # Muted orange - 'medical equipment': '#2ca02c', # Muted green - 'other': '#d62728', # Muted red - 'facility operating cost': '#9467bd', # Muted purple - } - # Default color for unexpected categories - default_color = 'gray' - plt_name_suffix = '' - - # Define custom colors for the bars - if _cost_category == 'all': - column_colors = [color_mapping.get(col, default_color) for col in sorted_columns] - # Plot the stacked bar chart with set colours - ax = pivot_central.plot(kind='bar', stacked=True, figsize=(10, 6), color=column_colors) - - # Add error bars - x_pos = np.arange(len(pivot_central.index)) - total_central = pivot_central.sum(axis=1) - error_bars = [lower_bounds, upper_bounds] - ax.errorbar(x_pos, total_central, yerr=error_bars, fmt='o', color='black', capsize=5) - - else: - # Plot the stacked bar chart without set colours - ax = pivot_central.plot(kind='bar', stacked=True, figsize=(10, 6)) - - # Add error bars - x_pos = np.arange(len(pivot_central.index)) - total_central = pivot_central.sum(axis=1) - error_bars = [lower_bounds, upper_bounds] - ax.errorbar(x_pos, total_central, yerr=error_bars, fmt='o', color='black', capsize=5) - - # Add data labels such that the stacked block has a superimposed white label is the value is >=2% of the Y-axis limit - # and a black label adjusted to the right of the bar (for visibility) if the value is <2% - # Get max y-limit for threshold - max_y = ax.get_ylim()[1] - threshold = max_y * 0.02 # 2% of ylim - - for container in ax.containers: - if isinstance(container, mpc.BarContainer): # Ensure we're working with bars, not error bars - for rect in container: - height = rect.get_height() - if height > 0: # Avoid labeling zero-height bars - x = rect.get_x() + rect.get_width() / 2 # Center of bar - y = rect.get_y() + height / 2 # Middle of segment - - if height < threshold: # Small segment -> place label outside - ax.annotate( - f'{round(height, 1)}', - xy=(x, rect.get_y() + height), # Arrow start - xytext=(x + 0.3, rect.get_y() + height + threshold), # Offset text - arrowprops=dict(arrowstyle="->", color='black', lw=0.8), - fontsize='small', ha='left', va='center', color='black' - ) - else: # Large segment -> label inside - ax.text(x, y, f'{round(height, 1)}', ha='center', va='center', fontsize='small', color='white') - - # Set custom x-tick labels if _scenario_dict is provided - if _scenario_dict: - labels = [_scenario_dict.get(label, label) for label in pivot_central.index] - else: - labels = pivot_central.index.astype(str) - - # Wrap x-tick labels for readability - wrapped_labels = [textwrap.fill(str(label), 20) for label in labels] - ax.set_xticklabels(wrapped_labels, rotation=45, ha='right', fontsize='small') - - # Period included for plot title and name - if _year == 'all': - period = (f"{min(_df_central['year'].unique())} - {max(_df_central['year'].unique())}") - elif (len(_year) == 1): - period = (f"{_year[0]}") - else: - period = (f"{min(_year)} - {max(_year)}") - - # Save plot - plt.xlabel('Scenario') - plt.ylabel('Cost (2023 USD), millions') - - # Arrange the legend in the same ascending order - handles, labels = plt.gca().get_legend_handles_labels() - plt.legend(handles[::-1], labels[::-1], bbox_to_anchor=(1.05, 0.7), loc='center left', fontsize='small') - - # Extend the y-axis by 25% - max_y = ax.get_ylim()[1] - ax.set_ylim(0, max_y*1.25) - - # Save the plot with tight layout - plt.tight_layout(pad=2.0) # Ensure there is enough space for the legend - plt.subplots_adjust(right=0.8) # Adjust to ensure legend doesn't overlap - - # Add gridlines and border - plt.grid(visible=True, which='major', linestyle='--', linewidth=0.5, color='gray') - #plt.rcParams['figure.facecolor'] = 'white' - plt.rcParams['figure.edgecolor'] = 'gray' - plt.rcParams['figure.frameon'] = True - - if show_title != False: - plt.title(f'Costs by Scenario \n (Cost Category = {_cost_category} ; Period = {period})') - plt.savefig(_outputfilepath / f'stacked_bar_chart_{_cost_category}_{period}{plt_name_suffix}{_add_figname_suffix}.png', dpi=100, - bbox_inches='tight') - plt.close() - -# 2. Line plots of total costs -#---------------------------------------------------- -# TODO: Check why line plot get save without a file name -def do_line_plot_of_cost(_df: pd.DataFrame, - _cost_category: Literal['all', 'human resources for health', 'medical consumables', - 'medical equipment', 'facility operating cost'] = 'all', - _year: list[int] ='all', - _draws: Optional[list[int]] = None, - disaggregate_by: Optional[Literal['cost_category', 'cost_subcategory', 'cost_subgroup']] = None, - _y_lim: Optional[float] = None, - show_title: bool = True, - _outputfilepath: Optional[Path] = None)-> None: - """ - Plot and save a line chart of cost trends over time by category or subcategory. - - Parameters: - ---------- - _df : pd.DataFrame - A cost summary DataFrame (usually from `estimate_input_cost_of_scenarios`) - containing columns like ['year', 'draw', 'cost', 'stat', 'cost_category', etc.]. - - _cost_category : str, default 'all' - If 'all', plots total cost across all categories. Otherwise, filters to a specific category. - - _year : str or list of int, default 'all' - Year(s) to include. Can be: - - 'all' to include all - - a single year or multiple years as a list: [2025] - - _draws : list of int, optional - If specified, filters to those draws. Required if `disaggregate_by` is set. - - disaggregate_by : {'cost_category', 'cost_subcategory', 'cost_subgroup'}, optional - Controls disaggregation on the plot - Note: If disaggregating, `_draws` must contain **only one draw**. - - _y_lim : float, optional - Custom upper limit for the y-axis. If None, uses automatic scaling. - - show_title : bool, default True - Whether to show the plot title. - - _outputfilepath : Path, optional - Directory where the plot image will be saved. Filename is auto-generated based on inputs. - - Returns: - ------- - None - Saves a PNG chart to `_outputfilepath`. - """ - - # Check what's the correct central metric to use (either 'mean' or 'median') - central_metric = [stat for stat in _df.stat.unique() if stat not in ['lower', 'upper']][0] - - # Validate disaggregation options - valid_disaggregations = ['cost_category', 'cost_subcategory', 'cost_subgroup'] - if disaggregate_by not in valid_disaggregations and disaggregate_by is not None: - raise ValueError(f"Invalid disaggregation option: {disaggregate_by}. Choose from {valid_disaggregations}.") - - # - if ((_draws is None) or (len(_draws) > 1)) & (disaggregate_by is not None): - raise ValueError(f"The disaggregate_by option only works if only one draw is plotted, for exmaple _draws = [0]") - - # Filter the dataframe by draws, if specified - subset_df = _df if _draws is None else _df[_df.draw.isin(_draws)] - - # Filter by year if specified - if _year != 'all': - subset_df = subset_df[subset_df['year'].isin(_year)] - - # Handle scenarios based on `_cost_category` and `disaggregate_by` conditions - if _cost_category == 'all': - if disaggregate_by == 'cost_subgroup': - raise ValueError("Cannot disaggregate by 'cost_subgroup' when `_cost_category='all'` due to data size.") - else: - # Filter subset_df by specific cost category if specified - subset_df = subset_df[subset_df['cost_category'] == _cost_category] - - # Set grouping columns based on the disaggregation level - if disaggregate_by == 'cost_category': - groupby_columns = ['year', 'cost_category'] - elif disaggregate_by == 'cost_subcategory': - groupby_columns = ['year', 'cost_subcategory'] - elif disaggregate_by == 'cost_subgroup': - # If disaggregating by 'cost_subgroup' and there are more than 10 subgroups, limit to the top 10 + "Other" - if len(subset_df['cost_subgroup'].unique()) > 10: - # Calculate total cost per subgroup - subgroup_totals = subset_df[subset_df.stat == central_metric].groupby('cost_subgroup')['cost'].sum() - # Identify the top 10 subgroups by cost - top_10_subgroups = subgroup_totals.nlargest(10).index.tolist() - # Reassign smaller subgroups to an "Other" category - subset_df['cost_subgroup'] = subset_df['cost_subgroup'].apply( - lambda x: x if x in top_10_subgroups else 'Other' - ) - groupby_columns = ['year', 'cost_subgroup'] - else: - groupby_columns = ['year'] - - # Extract central, lower, and upper values for the plot - central_values = subset_df[subset_df.stat == central_metric].groupby(groupby_columns)['cost'].sum() / 1e6 - lower_values = subset_df[subset_df.stat == 'lower'].groupby(groupby_columns)['cost'].sum() / 1e6 - upper_values = subset_df[subset_df.stat == 'upper'].groupby(groupby_columns)['cost'].sum() / 1e6 - - # Prepare to store lines and labels for the legend - lines = [] - labels = [] - - # Define a list of colors - if disaggregate_by == 'cost_category': - color_mapping = { - 'human resources for health': '#1f77b4', # Muted blue - 'medical consumables': '#ff7f0e', # Muted orange - 'medical equipment': '#2ca02c', # Muted green - 'other': '#d62728', # Muted red - 'facility operating cost': '#9467bd', # Muted purple - } - # Default color for unexpected categories - default_color = 'gray' - else: - # Define a list of colors to rotate through - colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'orange', 'purple', 'brown', 'gray'] # Add more colors as needed - color_cycle = iter(colors) # Create an iterator from the color list - - # Plot each line for the disaggregated values - if disaggregate_by: - for disaggregate_value in central_values.index.get_level_values(disaggregate_by).unique(): - # Get central, lower, and upper values for each disaggregated group - value_central = central_values.xs(disaggregate_value, level=disaggregate_by) - value_lower = lower_values.xs(disaggregate_value, level=disaggregate_by) - value_upper = upper_values.xs(disaggregate_value, level=disaggregate_by) - - if disaggregate_by == 'cost_category': - color = color_mapping.get(disaggregate_value, default_color) - else: - # Get the next color from the cycle - color = next(color_cycle) - - # Plot line for central and shaded region for 95% CI - line, = plt.plot(value_central.index, value_central, marker='o', linestyle='-', color=color, label=f'{disaggregate_value} - {central_metric}') - plt.fill_between(value_central.index, value_lower, value_upper, color=color, alpha=0.2) - - # Append to lines and labels for sorting later - lines.append(line) - labels.append(disaggregate_value) - else: - line, = plt.plot(central_values.index, central_values, marker='o', linestyle='-', color='b', label=central_metric) - plt.fill_between(central_values.index, lower_values, upper_values, color='b', alpha=0.2) - - # Append to lines and labels for sorting later - lines.append(line) - labels.append(central_metric) - - # Sort the legend based on total costs - total_costs = {label: central_values.xs(label, level=disaggregate_by).sum() for label in labels} - sorted_labels = sorted(total_costs.keys(), key=lambda x: total_costs[x]) - - # Reorder lines based on sorted labels - handles = [lines[labels.index(label)] for label in sorted_labels] - - # Define period for plot title - if _year == 'all': - period = f"{min(subset_df['year'].unique())} - {max(subset_df['year'].unique())}" - elif len(_year) == 1: - period = str(_year[0]) - else: - period = f"{min(_year)} - {max(_year)}" - - # Set labels, legend, and title - # Set y-axis limit if provided - if _y_lim is not None: - plt.ylim(0, _y_lim) - - # Add gridlines and border - plt.grid(visible=True, which='major', linestyle='--', linewidth=0.5, color='gray') - plt.xlabel('Year') - plt.ylabel('Cost (2023 USD), millions') - plt.legend(handles[::-1], sorted_labels[::-1], loc='upper right', bbox_to_anchor=(0.98, 0.98), framealpha=0.6) - if (show_title != False): - plot_title = f'Total input cost \n (Category = {_cost_category}, Period = {period})' - plt.title(plot_title) - - # Save plot with a proper filename - if disaggregate_by is None: - filename_suffix = "" - else: - filename_suffix = f"_by_{disaggregate_by}" - - draw_suffix = 'all' if _draws is None else str(_draws) - filename = f'trend_{_cost_category}_{period}{filename_suffix}_draw-{draw_suffix}.png' - plt.savefig(_outputfilepath / filename, dpi=100, bbox_inches='tight') - plt.close() - -# Treemap by category subgroup -#----------------------------------------------------------------------------------------------- -def create_summary_treemap_by_cost_subgroup(_df: pd.DataFrame, - _cost_category: Literal['human resources for health', 'medical consumables', - 'medical equipment', 'facility operating cost'], - _draw: Optional[list[int]] = None, - _year: list[int] = 'all', - _color_map: Optional[dict[str, str]] = None, - _label_fontsize: int = 10, - show_title: bool = True, - _outputfilepath: Optional[Path] = None) -> None: - """ - Generate and save a treemap visualizing cost composition by subgroup within a cost category. - - Parameters: - ---------- - _df : pd.DataFrame - DataFrame of costs with columns: ['cost_category', 'cost_subgroup', 'draw', 'year', 'cost']. - Typically output from `estimate_input_cost_of_scenarios`. - - _cost_category : str, required - The high-level cost category to visualize (e.g., 'human resources for health', - 'medical consumables', 'medical equipment', 'facility operating cost'). - - _draw : int, optional - Specific draw to visualize. If None, uses the full dataset. - - _year : str or list of int, default 'all' - Year or list of years to include in the treemap. If 'all', includes all available years. - - _color_map : dict, optional - Dictionary mapping cost subgroups to specific colors. If None, a default colormap is used. - eg. _color_map = {'First-line ART regimen: adult':'#1f77b4', - 'Test, HIV EIA Elisa': '#ff7f0e', - 'VL Test': '#2ca02c'} - - _label_fontsize : int, default 10 - Font size used for labels inside treemap tiles. - - show_title : bool, default True - Whether to display a plot title. - - _outputfilepath : Path, optional - Directory where the treemap image should be saved. - - Returns: - ------- - None - Saves the treemap as a PNG file named `treemap_{category}_{draw}_{period}.png`. - """ - # Function to wrap text to fit within treemap rectangles - def wrap_text(text, width=15): - return "\n".join(textwrap.wrap(text, width)) - - valid_cost_categories = ['human resources for health', 'medical consumables', - 'medical equipment', 'facility operating cost'] - if _cost_category == None: - raise ValueError(f"Specify one of the following as _cost_category - {valid_cost_categories})") - elif _cost_category not in valid_cost_categories: - raise ValueError(f"Invalid input for _cost_category: '{_cost_category}'. " - f"Specify one of the following - {valid_cost_categories})") - else: - _df = _df[_df['cost_category'] == _cost_category] - - if _draw != None: - _df = _df[_df.draw == _draw] - - # Remove non-specific subgroup for consumables - if _cost_category == 'medical consumables': - _df = _df[~(_df.cost_subgroup == 'supply chain (all consumables)')] - - # Create summary dataframe for treemap - _df = _df.groupby('cost_subgroup')['cost'].sum().reset_index() - _df = _df.sort_values(by="cost", ascending=False) - top_10 = _df.iloc[:10] - - if (len(_df['cost_subgroup'].unique()) > 10): - # Step 2: Group all other consumables into "Other" - other_cost = _df.iloc[10:]["cost"].sum() - top_10 = pd.concat([top_10, pd.DataFrame([{"cost_subgroup": "Other", "cost": other_cost}])], ignore_index=True) - - # Prepare data for the treemap - total_cost = top_10["cost"].sum() - top_10["proportion"] = top_10["cost"]/total_cost - sizes = top_10["cost"] - - # Handle color map - if _color_map is None: - # Generate automatic colors if no color map is provided - auto_colors = plt.cm.Paired.colors - color_cycle = cycle(auto_colors) # Cycle through the automatic colors - color_map = {subgroup: next(color_cycle) for subgroup in top_10["cost_subgroup"]} - else: - # Use the provided color map, fallback to a default color for missing subgroups - fallback_color = '#cccccc' - color_map = {subgroup: _color_map.get(subgroup, fallback_color) for subgroup in top_10["cost_subgroup"]} - - # Get colors for each subgroup - colors = [color_map[subgroup] for subgroup in top_10["cost_subgroup"]] - - # Exclude labels for small proportions - labels = [ - f"{wrap_text(name)}\n${round(cost, 1)}m\n({round(prop * 100, 1)}%)" - if prop >= 0.01 else "" - for name, cost, prop in zip(top_10["cost_subgroup"], top_10["cost"] / 1e6, top_10["proportion"]) - ] - # Period included for plot title and name - if _year == 'all': - period = (f"{min(_df['year'].unique())} - {max(_df['year'].unique())}") - elif (len(_year) == 1): - period = (f"{_year[0]}") - else: - period = (f"{min(_year)} - {max(_year)}") - - # Plot the treemap - plt.figure(figsize=(12, 8)) - squarify.plot(sizes=sizes, label=labels, alpha=0.8, color=colors, text_kwargs={'fontsize': _label_fontsize}) - plt.axis("off") - if (show_title != False): - plt.title(f'{_cost_category} ; Period = {period}') - - plt.savefig(_outputfilepath / f'treemap_{_cost_category}_[{_draw}]_{period}.png', - dpi=100, - bbox_inches='tight') - plt.close() - -# Plot ROI -def generate_multiple_scenarios_roi_plot( _monetary_value_of_incremental_health: pd.DataFrame, - _incremental_input_cost: pd.DataFrame, - _outputfilepath: Path, - _draws: list[int], - _scenario_dict: dict[int, str], - _metric: str = 'mean', - _y_axis_lim: Optional[float] = None, - _plot_vertical_lines_at: Optional[list[int]] = None, - _projected_health_spending: Optional[float] = None, - _draw_colors: Optional[dict[int, str]] = None, - _value_of_life_suffix: str = '', - _year_suffix: str = '', - show_title_and_legend: Optional[bool] = True) -> None: - """ - Generate and save ROI plots for multiple scenarios, showing returns over a range of implementation costs. - - Parameters: - ---------- - _monetary_value_of_incremental_health : pd.DataFrame - DataFrame with index (draw, run), containing monetary values of health benefits. - This can be estimated as (_num_dalys_averted_by_scenario * _chosen_value_of_life_year).clip(lower=0.0) - - _incremental_input_cost : pd.DataFrame - DataFrame with index (draw, run), containing incremental costs for each scenario. - - _outputfilepath : Path - Path to the output folder where plots will be saved. - - _draws : list of int, required - List of draw indices to include in the plot. - - _scenario_dict : dict of {int: str}, required - Mapping from draw index to scenario name, used for plot labeling. - - _metric : {'mean', 'median'}, default 'mean' - Central tendency to use when summarizing ROI across runs. - - _y_axis_lim : float, optional - Y-axis upper limit. If None, scales based on the maximum ROI value. - - _plot_vertical_lines_at : list of int, optional - If specified, vertical dashed lines are drawn at these implementation cost values (in USD). - Annotates ROI ratio across scenarios at those points. - - _projected_health_spending : float, optional - Used to annotate x-axis values as % of total projected health spending - Can be estimated using the function estimate_projected_health_spending, but a single value will need to be taken - eg. mean value for the baseline scenario. - - _draw_colors : dict of {int: str}, optional - Custom colors to use for each scenario/draw. - - _value_of_life_suffix : str, default '' - Suffix added to the filename to reflect the assumed value of life (e.g., DALY monetization label). - - _year_suffix : str, default '' - Optional suffix to add to the filename or plot title to indicate year range. - - show_title_and_legend : bool, default True - Whether to include the plot title and legend. - - Returns: - ------- - None - Saves a PNG file visualizing ROI vs. implementation cost for each scenario. - """ - if _metric not in ['mean', 'median']: - raise ValueError(f"Invalid input for _metric: '{_metric}'. " - f"Values need to be one of 'mean' or 'median'") - - # Default color mapping if not provided - if _draw_colors is None: - _draw_colors = {draw: color for draw, color in zip(_draws, plt.cm.tab10.colors[:len(_draws)])} - - # Calculate maximum ability to pay for implementation - _monetary_value_of_incremental_health = _monetary_value_of_incremental_health[_monetary_value_of_incremental_health.index.get_level_values('draw').isin(_draws)] - _incremental_input_cost = _incremental_input_cost[_incremental_input_cost.index.get_level_values('draw').isin(_draws)] - max_ability_to_pay_for_implementation = (_monetary_value_of_incremental_health - _incremental_input_cost).clip(lower=0.0) # monetary value - change in costs - - # Create a figure and axis to plot all draws together - fig, ax = plt.subplots(figsize=(10, 6)) - - # Store ROI values for specific costs - max_roi = [] - roi_at_costs = {cost: [] for cost in (_plot_vertical_lines_at or [])} - - # Iterate over each draw in monetary_value_of_incremental_health - for draw_index, row in _monetary_value_of_incremental_health.iterrows(): - print("Plotting ROI for draw ", draw_index) - # Initialize an empty DataFrame to store values for each 'run' - all_run_values = pd.DataFrame() - - # Create an array of implementation costs ranging from 0 to the max value of max ability to pay for the current draw - implementation_costs = np.linspace(0, max_ability_to_pay_for_implementation.loc[draw_index].max(), 50) - # Add fixed values for ROI ratio calculation - additional_costs = np.array([1_000_000_000, 3_000_000_000]) - implementation_costs = np.sort(np.unique(np.concatenate([implementation_costs, additional_costs]))) - - # Retrieve the corresponding row from incremental_scenario_cost for the same draw - incremental_scenario_cost_row = _incremental_input_cost.loc[draw_index] - - # Calculate the values for each individual run - for run in incremental_scenario_cost_row.index: # Assuming 'run' columns are labeled by numbers - # Calculate the total costs for the current run - total_costs = implementation_costs + incremental_scenario_cost_row[run] - - # Initialize run_values as an empty series with the same index as total_costs - run_values = pd.Series(index=total_costs, dtype=float) - - # For negative total_costs, set corresponding run_values to infinity - run_values[total_costs < 0] = np.inf - - # For non-negative total_costs, calculate the metric and clip at 0 - non_negative_mask = total_costs >= 0 - run_values[non_negative_mask] = np.clip( - (row[run] - total_costs[non_negative_mask]) / total_costs[non_negative_mask], - 0, - None - ) - - # Create a DataFrame with index as (draw_index, run) and columns as implementation costs - run_values = run_values.values # remove index and convert to array - run_df = pd.DataFrame([run_values], index=pd.MultiIndex.from_tuples([(draw_index, run)], names=['draw', 'run']), - columns=implementation_costs) - - # Append the run DataFrame to all_run_values - all_run_values = pd.concat([all_run_values, run_df]) - - # Replace inf with NaN temporarily to handle quantile calculation correctly - temp_data = all_run_values.replace([np.inf, -np.inf], np.nan) - - collapsed_data = temp_data.groupby(level='draw').agg([ - _metric, - ('lower', lambda x: x.quantile(0.025)), - ('upper', lambda x: x.quantile(0.975)) - ]) - - # Revert the NaNs back to inf - collapsed_data = collapsed_data.replace([np.nan], np.inf) - - collapsed_data = collapsed_data.unstack() - collapsed_data.index = collapsed_data.index.set_names('implementation_cost', level=0) - collapsed_data.index = collapsed_data.index.set_names('stat', level=1) - collapsed_data = collapsed_data.reset_index().rename(columns = {0: 'roi'}) - - # Divide rows by the sum of implementation costs and incremental input cost - central_values = collapsed_data[collapsed_data['stat'] == _metric][['implementation_cost', 'roi']] - lower_values = collapsed_data[collapsed_data['stat'] == 'lower'][['implementation_cost', 'roi']] - upper_values = collapsed_data[collapsed_data['stat'] == 'upper'][['implementation_cost', 'roi']] - - # Plot central line and confidence interval - ax.plot( - implementation_costs / 1e6, - central_values['roi'], - label=f'{_scenario_dict[draw_index]}', - color=_draw_colors.get(draw_index, 'black'), - ) - ax.fill_between( - implementation_costs / 1e6, - lower_values['roi'], - upper_values['roi'], - alpha=0.2, - color=_draw_colors.get(draw_index, 'black'), - ) - - max_val = central_values[~np.isinf(central_values['roi'])]['roi'].max() - max_roi.append(max_val) - - # Capture ROI at specific costs - if _plot_vertical_lines_at: - for cost in _plot_vertical_lines_at: - roi_value = collapsed_data[ - (collapsed_data.implementation_cost == cost) & - (collapsed_data.stat == _metric) - ]['roi'] - if not roi_value.empty: - roi_at_costs[cost].append(roi_value.iloc[0]) - - # Calculate and annotate ROI ratios - if _plot_vertical_lines_at: - for cost in _plot_vertical_lines_at: - if cost in roi_at_costs: - ratio = max(roi_at_costs[cost]) / min(roi_at_costs[cost]) - ax.axvline(x=cost / 1e6, color='black', linestyle='--', linewidth=1) - ax.text(cost / 1e6 + ax.get_xlim()[1] * 0.011, ax.get_ylim()[1] * 0.75, - f'At ${cost / 1e6:.0f}M, ratio of ROI curves = {round(ratio, 2)}', - color='black', fontsize=10, rotation=90, verticalalignment='top') - - # Define fixed x-tick positions with a gap of 2000 - step_size = (ax.get_xlim()[1] - 0)/5 - xticks = np.arange(0, ax.get_xlim()[1] + 1, int(round(step_size, -3))) # From 0 to max x-limit with 5 steps - # Get labels - xtick_labels = [f'{tick:,.0f}' for tick in xticks] # Default labels for all ticks - - # Replace specific x-ticks with % of health spending values - if _projected_health_spending: - xtick_labels[1] = f'{xticks[1]:,.0f}\n({xticks[1] / (_projected_health_spending / 1e6) :.2%} of \n projected total \n health spend)' - for i, tick in enumerate(xticks): - if (i != 0) & (i != 1): # Replace for 4000 - xtick_labels[i] = f'{tick:,.0f}\n({tick / (_projected_health_spending/1e6) :.2%})' - - # Update the x-ticks and labels - ax.set_xticks(xticks) - ax.set_xticklabels(xtick_labels, fontsize=10) - - # Set y-axis limit - if _y_axis_lim == None: - ax.set_ylim(0, max(max_roi) * 1.25) - else: - ax.set_ylim(0, _y_axis_lim) - ax.set_xlim(left = 0) - - plt.xlabel('Implementation cost, USD millions') - plt.ylabel('Return on Investment') - - # Show legend and title - if (show_title_and_legend != False): - plt.title(f'Return on Investment at different levels of implementation cost{_year_suffix}') - plt.legend() - - # Add gridlines and border - plt.grid(False) - fig.patch.set_facecolor("white") # White background for the entire figure - - # Save - plt.savefig(_outputfilepath / f'draws_{_draws}_ROI_at_{_value_of_life_suffix}_{_year_suffix}.png', dpi=100, - bbox_inches='tight') - plt.close() - -def tabulated_roi_estimates(_monetary_value_of_incremental_health: pd.DataFrame, - _incremental_input_cost: pd.DataFrame, - _draws: Optional[list[int]] = None, - _metric: Literal['mean', 'median'] = 'mean') -> pd.DataFrame: - """ - Compute ROI estimates in tabular form for multiple scenarios and implementation costs. - - For each draw, calculates ROI at various hypothetical implementation cost levels. - ROI is defined as: (monetary value of health gain - total cost) / total cost. - - Parameters: - ---------- - _monetary_value_of_incremental_health : pd.DataFrame - DataFrame indexed by [draw, run], with estimated monetary values of health gain. - - _incremental_input_cost : pd.DataFrame - DataFrame indexed by [draw, run], with estimated incremental scenario costs. - - _draws : list of int - Draw indices to include in the tabulation. - - _metric : {'mean', 'median'}, default 'mean' - Summary statistic to compute across runs. Also includes 2.5th and 97.5th percentiles. - - Returns: - ------- - pd.DataFrame - Long-format DataFrame with: - - 'implementation_cost' (in USD) - - 'stat' ('mean', 'lower', 'upper') - - 'roi' (return on investment) - - Includes results for all requested draws and implementation cost levels - the implementation cost levels - used are based on max_ability_to_pay_for_implementation calculated within the function - at this level - of incremental scenario cost + implementation cost, ROI should be 0. - """ - - # Calculate maximum ability to pay for implementation - _monetary_value_of_incremental_health = _monetary_value_of_incremental_health[_monetary_value_of_incremental_health.index.get_level_values('draw').isin(_draws)] - _incremental_input_cost = _incremental_input_cost[_incremental_input_cost.index.get_level_values('draw').isin(_draws)] - max_ability_to_pay_for_implementation = (_monetary_value_of_incremental_health - _incremental_input_cost).clip(lower=0.0) # monetary value - change in costs - - roi_df = pd.DataFrame() - - # Create an array of implementation costs ranging from 0 to the max value of max ability to pay for the current draw - max_ability_to_pay_for_implementation_rounded_value = math.ceil(max_ability_to_pay_for_implementation.max().max() / 1_000_000_000) * 1_000_000_000 - implementation_costs = np.linspace(0, max_ability_to_pay_for_implementation_rounded_value, 20) - implementation_costs = np.ceil(implementation_costs / 1_000_000_000) * 1_000_000_000 # Round each to nearest billion - - # Iterate over each draw in monetary_value_of_incremental_health - for draw_index, row in _monetary_value_of_incremental_health.iterrows(): - print("Tablulating ROI for draw ", draw_index) - # Initialize an empty DataFrame to store values for each 'run' - all_run_values = pd.DataFrame() - - # Retrieve the corresponding row from incremental_scenario_cost for the same draw - incremental_scenario_cost_row = _incremental_input_cost.loc[draw_index] - - # Calculate the values for each individual run - for run in incremental_scenario_cost_row.index: # Assuming 'run' columns are labeled by numbers - # Calculate the total costs for the current run - total_costs = implementation_costs + incremental_scenario_cost_row[run] - - # Initialize run_values as an empty series with the same index as total_costs - run_values = pd.Series(index=total_costs, dtype=float) - - # For negative total_costs, set corresponding run_values to infinity - run_values[total_costs < 0] = np.inf - - # For non-negative total_costs, calculate the metric and clip at 0 - non_negative_mask = total_costs >= 0 - run_values[non_negative_mask] = (row[run] - total_costs[non_negative_mask]) / total_costs[non_negative_mask] - - # Create a DataFrame with index as (draw_index, run) and columns as implementation costs - run_values = run_values.values # remove index and convert to array - run_df = pd.DataFrame([run_values], index=pd.MultiIndex.from_tuples([(draw_index, run)], names=['draw', 'run']), - columns=implementation_costs) - - # Append the run DataFrame to all_run_values - all_run_values = pd.concat([all_run_values, run_df]) - - # Replace inf with NaN temporarily to handle quantile calculation correctly - temp_data = all_run_values.replace([np.inf, -np.inf], np.nan) - - collapsed_data = temp_data.groupby(level='draw').agg([ - _metric, - ('lower', lambda x: x.quantile(0.025)), - ('upper', lambda x: x.quantile(0.975)) - ]) - - # Revert the NaNs back to inf - collapsed_data = collapsed_data.replace([np.nan], np.inf) - - collapsed_data = collapsed_data.unstack() - collapsed_data.index = collapsed_data.index.set_names('implementation_cost', level=0) - collapsed_data.index = collapsed_data.index.set_names('stat', level=1) - collapsed_data = collapsed_data.reset_index().rename(columns = {0: 'roi'}) - - if roi_df.empty: - roi_df = collapsed_data - else: - roi_df = pd.concat([roi_df, collapsed_data], ignore_index=True) - return roi_df diff --git a/src/scripts/costing/costing_overview_analysis.py b/src/scripts/costing/costing_overview_analysis.py deleted file mode 100644 index a2bd46ad2d..0000000000 --- a/src/scripts/costing/costing_overview_analysis.py +++ /dev/null @@ -1,371 +0,0 @@ -"""Produce outputs for cost overview paper. -The draft version of the paper uses outputs from scenario_impact_of_healthsystem.py, used to model HSS scenarios for -FCDO and Global Fund. - -with reduced consumables logging -/Users/tmangal/PycharmProjects/TLOmodel/outputs/t.mangal@imperial.ac.uk/hss_elements-2024-11-12T172311Z -""" - -from pathlib import Path -from tlo import Date - -import datetime -import os -import textwrap - -import matplotlib.pyplot as plt -import seaborn as sns -import numpy as np -import pandas as pd -from itertools import cycle -import jinja2 # This is for the latex table - -from tlo.analysis.utils import ( - extract_params, - get_scenario_info, - get_scenario_outputs, - load_pickled_dataframes, -) - -from scripts.costing.cost_estimation import (estimate_input_cost_of_scenarios, - summarize_cost_data, - do_stacked_bar_plot_of_cost_by_category, - do_line_plot_of_cost, - create_summary_treemap_by_cost_subgroup, - estimate_projected_health_spending) - -# Define a timestamp for script outputs -timestamp = datetime.datetime.now().strftime("_%Y_%m_%d_%H_%M") - -# Print the start time of the script -print('Script Start', datetime.datetime.now().strftime('%H:%M')) - -# Create folders to store results -resourcefilepath = Path("./resources") -outputfilepath = Path('./outputs/t.mangal@imperial.ac.uk') -figurespath = Path('./outputs/costing/overview/') -if not os.path.exists(figurespath): - os.makedirs(figurespath) - -# Load result files -# ------------------------------------------------------------------------------------------------------------------ -results_folder = get_scenario_outputs('htm_and_hss_runs-2025-01-16T135243Z.py', outputfilepath)[0] # January 2025 runs - -# Check can read results from draw=0, run=0 -log = load_pickled_dataframes(results_folder, 0, 0) # look at one log (so can decide what to extract) -params = extract_params(results_folder) -info = get_scenario_info(results_folder) - -# Declare default parameters for cost analysis -# ------------------------------------------------------------------------------------------------------------------ -# Period relevant for costing -TARGET_PERIOD = (Date(2023, 1, 1), Date(2030, 12, 31)) # This is the period that is costed -relevant_period_for_costing = [i.year for i in TARGET_PERIOD] -list_of_relevant_years_for_costing = list(range(relevant_period_for_costing[0], relevant_period_for_costing[1] + 1)) -list_of_years_for_plot = list(range(2023, 2031)) -number_of_years_costed = relevant_period_for_costing[1] - 2023 + 1 - -# Scenarios -cost_scenarios = {0: "Actual", 3: "Expanded HRH", 5: "Improved consumable availability", - 8: "Expanded HRH + Improved consumable availability"} - -# Costing parameters -discount_rate = 0.03 -discount_rate_lomas = {2023: 0.0036, 2024: 0.0040, 2025: 0.0039, 2026: 0.0042, 2027: 0.0042, 2028: 0.0041, - 2029: 0.0041, 2030: 0.0040}# get the list of discount rates from 2023 until 2030 - -# Estimate standard input costs of scenario -# ----------------------------------------------------------------------------------------------------------------------- -# Standard 3% discount rate -input_costs = estimate_input_cost_of_scenarios(results_folder, resourcefilepath, _draws = [0, 3, 5, 8], - _years=list_of_relevant_years_for_costing, cost_only_used_staff=True, - _discount_rate = discount_rate, summarize = True) - -# Undiscounted costs -input_costs_undiscounted = estimate_input_cost_of_scenarios(results_folder, resourcefilepath, _draws = [0, 3, 5, 8], - _years=list_of_relevant_years_for_costing, cost_only_used_staff=True, - _discount_rate = 0, summarize = True) - -# Cost with variable discount rate based on Lomas et al (2021) -input_costs_variable_discounting = estimate_input_cost_of_scenarios(results_folder, resourcefilepath, _draws = [0, 3, 5, 8], - _years=list_of_relevant_years_for_costing, cost_only_used_staff=True, - _discount_rate = discount_rate_lomas, summarize = True) - -# Get overall estimates for main text -# ----------------------------------------------------------------------------------------------------------------------- -cost_by_draw = input_costs.groupby(['draw', 'stat'])['cost'].sum() -undiscounted_cost_by_draw = input_costs_undiscounted.groupby(['draw', 'stat'])['cost'].sum() - -# Abstract -print(f"Under current system capacity, total healthcare delivery costs for 2023–2030 were estimated at \$" - f"{cost_by_draw[0,'mean']/1e9:,.2f} billion [95\% confidence interval (CI), \${cost_by_draw[0,'lower']/1e9:,.2f}b - \${cost_by_draw[0,'upper']/1e9:,.2f}b], averaging \$" - f"{undiscounted_cost_by_draw[0,'mean']/1e6/number_of_years_costed:,.2f} million [\${undiscounted_cost_by_draw[0,'lower']/1e6/number_of_years_costed:,.2f}m - \${undiscounted_cost_by_draw[0,'upper']/1e6/number_of_years_costed:,.2f}m] annually.") -# Results 1 -print(f"The total cost of healthcare delivery in Malawi between 2023 and 2030 was estimated to be " - f"\${cost_by_draw[0,'mean']/1e9:,.2f} billion [95\% confidence interval (CI), \${cost_by_draw[0,'lower']/1e9:,.2f}b - \${cost_by_draw[0,'upper']/1e9:,.2f}b], under the actual scenario, and increased to " - f"\${cost_by_draw[5,'mean']/1e9:,.2f} billion [\${cost_by_draw[5,'lower']/1e9:,.2f}b - \${cost_by_draw[5,'upper']/1e9:,.2f}b] under the improved consumable availability scenario, " - f"followed by \${cost_by_draw[3,'mean']/1e9:,.2f} billion [\${cost_by_draw[3,'lower']/1e9:,.2f}b - \${cost_by_draw[3,'upper']/1e9:,.2f}b] under the expanded HRH scenario and finally " - f"\${cost_by_draw[8,'mean']/1e9:,.2f} billion [\${cost_by_draw[8,'lower']/1e9:,.2f}b - \${cost_by_draw[8,'upper']/1e9:,.2f}b] under the expanded HRH + improved consumable availability scenario.") -# Results 2 -print(f"This translates to an average annual cost of " - f"\${undiscounted_cost_by_draw[0,'mean']/1e6/number_of_years_costed:,.2f} million [\${undiscounted_cost_by_draw[0,'lower']/1e6/number_of_years_costed:,.2f}m - \${undiscounted_cost_by_draw[0,'upper']/1e6/number_of_years_costed:,.2f}m], under the actual scenario, " - f"\${undiscounted_cost_by_draw[5,'mean']/1e6/number_of_years_costed:,.2f} million [\${undiscounted_cost_by_draw[5,'lower']/1e6/number_of_years_costed:,.2f}m - \${undiscounted_cost_by_draw[5,'upper']/1e6/number_of_years_costed:,.2f}m] under the improved consumable availability scenario, followed by " - f"\${undiscounted_cost_by_draw[3,'mean']/1e6/number_of_years_costed:,.2f} million [\${undiscounted_cost_by_draw[3,'lower']/1e6/number_of_years_costed:,.2f}m - \${undiscounted_cost_by_draw[3,'upper']/1e6/number_of_years_costed:,.2f}m] under the expanded HRH scenario and finally " - f"\${undiscounted_cost_by_draw[8,'mean']/1e6/number_of_years_costed:,.2f} million [\${undiscounted_cost_by_draw[8,'lower']/1e6/number_of_years_costed:,.2f}m - \${undiscounted_cost_by_draw[8,'upper']/1e6/number_of_years_costed:,.2f}m] under the expanded HRH + improved consumable availability scenario.") -# Results 3 -consumable_cost_by_draw = input_costs[(input_costs.cost_category == 'medical consumables') & (input_costs.stat == 'mean')].groupby(['draw'])['cost'].sum() -print(f"Notably, improving consumable availability alone increases the cost of medical consumables by just " - f"{(consumable_cost_by_draw[5]/consumable_cost_by_draw[0] - 1) * 100:.2f}\% " - f"because the limited health workforce (HRH) restricts the number of feasible appointments and, consequently, the quantity of consumables dispensed. " - f"In contrast, expanding HRH alone raises consumable costs by " - f"{(consumable_cost_by_draw[3]/consumable_cost_by_draw[0] - 1) * 100:.2f}\%" - f". When both HRH and consumable availability are expanded together, consumable costs increase by " - f"{(consumable_cost_by_draw[8]/consumable_cost_by_draw[0] - 1) * 100:.2f}\% " - f"compared to the actual scenario.") -# Results 4 -cost_of_hiv_testing = input_costs[(input_costs.cost_subgroup == 'Test, HIV EIA Elisa') & (input_costs.stat == 'mean')].groupby(['draw'])['cost'].sum() -print(f"For instance, the cost of HIV testing consumables increases by {(cost_of_hiv_testing[3]/cost_of_hiv_testing[0] - 1)*100:.2f}\% under the expanded HRH scenario and by " - f"{(cost_of_hiv_testing[8]/cost_of_hiv_testing[0] - 1)*100:.2f}\% under the combined expanded HRH and improved consumable availability scenario, " - f"while showing almost no change under the scenario with improved consumable availability alone") - -# Get figures for overview paper -# ----------------------------------------------------------------------------------------------------------------------- -# Figure 2: Estimated costs by cost category -do_stacked_bar_plot_of_cost_by_category(_df = input_costs, _cost_category = 'all', _disaggregate_by_subgroup = False, - _year = list_of_relevant_years_for_costing,show_title = False, - _outputfilepath = figurespath, _scenario_dict = cost_scenarios) - -revised_consumable_subcategories = {'cost_of_separately_managed_medical_supplies_dispensed':'cost_of_consumables_dispensed', 'cost_of_excess_separately_managed_medical_supplies_stocked': 'cost_of_excess_consumables_stocked', 'supply_chain':'supply_chain'} -input_costs_new = input_costs.copy() -input_costs_new['cost_subcategory'] = input_costs_new['cost_subcategory'].map(revised_consumable_subcategories).fillna(input_costs_new['cost_subcategory']) - -# Figure 3: Estimated costs by cost sub-category -do_stacked_bar_plot_of_cost_by_category(_df = input_costs_new, _cost_category = 'medical consumables', _disaggregate_by_subgroup = False, - _year = list_of_years_for_plot, show_title = False, - _outputfilepath = figurespath, _scenario_dict = cost_scenarios) -do_stacked_bar_plot_of_cost_by_category(_df = input_costs, _cost_category = 'human resources for health', _disaggregate_by_subgroup = False, - _year = list_of_years_for_plot, show_title = False, - _outputfilepath = figurespath, _scenario_dict = cost_scenarios) -do_stacked_bar_plot_of_cost_by_category(_df = input_costs, _cost_category = 'medical equipment', _disaggregate_by_subgroup = False, - _year = list_of_years_for_plot, show_title = False, - _outputfilepath = figurespath, _scenario_dict = cost_scenarios) -do_stacked_bar_plot_of_cost_by_category(_df = input_costs, _cost_category = 'facility operating cost', _disaggregate_by_subgroup = False, - _year = list_of_years_for_plot, show_title = False, - _outputfilepath = figurespath, _scenario_dict = cost_scenarios) - - -# Figure 4: Estimated costs by year -do_line_plot_of_cost(_df = input_costs_undiscounted, _cost_category='all', - _year=list_of_years_for_plot, _draws= [0], - disaggregate_by= 'cost_category', - _y_lim = 400, - show_title = False, - _outputfilepath = figurespath) -do_line_plot_of_cost(_df = input_costs_undiscounted, _cost_category='all', - _year=list_of_years_for_plot, _draws= [3], - disaggregate_by= 'cost_category', - _y_lim = 400, - show_title = False, - _outputfilepath = figurespath) -do_line_plot_of_cost(_df = input_costs_undiscounted, _cost_category='all', - _year=list_of_years_for_plot, _draws= [5], - disaggregate_by= 'cost_category', - _y_lim = 400, - show_title = False, - _outputfilepath = figurespath) -do_line_plot_of_cost(_df = input_costs_undiscounted, _cost_category='all', - _year=list_of_years_for_plot, _draws= [8], - disaggregate_by= 'cost_category', - _y_lim = 400, - show_title = False, - _outputfilepath = figurespath) - -# Figure D1: Total cost by scenario assuming 0% discount rate -do_stacked_bar_plot_of_cost_by_category(_df = input_costs_undiscounted, - _cost_category = 'all', - _year=list_of_years_for_plot, - _disaggregate_by_subgroup = False, - _outputfilepath = figurespath, - _scenario_dict = cost_scenarios, - _add_figname_suffix = '_UNDISCOUNTED') - -# Figure D2: Total cost by scenario assuming variable discount rates -do_stacked_bar_plot_of_cost_by_category(_df = input_costs_variable_discounting, - _cost_category = 'all', - _year=list_of_years_for_plot, - _disaggregate_by_subgroup = False, - _outputfilepath = figurespath, - _scenario_dict = cost_scenarios, - _add_figname_suffix = '_VARIABLE_DISCOUNTING') - - -# Figure F1-F4: Cost by cost sub-group -cost_categories = ['human resources for health', 'medical consumables', - 'medical equipment', 'facility operating cost'] -draws = input_costs.draw.unique().tolist() -colourmap_for_consumables = {'First-line ART regimen: adult':'#1f77b4', - 'Test, HIV EIA Elisa': '#ff7f0e', - 'VL Test': '#2ca02c', - 'Depot-Medroxyprogesterone Acetate 150 mg - 3 monthly': '#d62728', - 'Oxygen, 1000 liters, primarily with oxygen cylinders': '#9467bd', - 'Phenobarbital, 100 mg': '#8c564b', - 'Rotavirus vaccine': '#e377c2', - 'Carbamazepine 200mg_1000_CMST': '#7f7f7f', - 'Infant resuscitator, clear plastic + mask + bag_each_CMST': '#bcbd22', - 'Dietary supplements (country-specific)': '#17becf', - 'Tenofovir (TDF)/Emtricitabine (FTC), tablet, 300/200 mg': '#2b8cbe', - 'Pneumococcal vaccine': '#fdae61', - 'Pentavalent vaccine (DPT, Hep B, Hib)': '#d73027', - 'male circumcision kit, consumables (10 procedures)_1_IDA': '#756bb1', - 'Jadelle (implant), box of 2_CMST': '#ffdd44', - 'Urine analysis': '#66c2a5'} - -for _cat in cost_categories: - for _d in draws: - if _cat == 'medical consumables': - create_summary_treemap_by_cost_subgroup(_df = input_costs, _year = list_of_years_for_plot, - _cost_category = _cat, _draw = _d, _color_map=colourmap_for_consumables, - show_title= False, _label_fontsize= 8, _outputfilepath=figurespath) - else: - create_summary_treemap_by_cost_subgroup(_df=input_costs, _year=list_of_years_for_plot, - _cost_category=_cat, _draw=_d, show_title= False, - _label_fontsize= 8.5, _outputfilepath=figurespath) - - -# Get tables for overview paper -# ----------------------------------------------------------------------------------------------------------------------- -# Group data and aggregate cost for each draw and stat -def generate_detail_cost_table(_groupby_var, _groupby_var_name, _longtable = False): - edited_input_costs = input_costs.copy() - edited_input_costs[_groupby_var] = edited_input_costs[_groupby_var].replace('_', ' ', regex=True) - edited_input_costs[_groupby_var] = edited_input_costs[_groupby_var].replace('%', '\%', regex=True) - edited_input_costs[_groupby_var] = edited_input_costs[_groupby_var].replace('&', '\&', regex=True) - - grouped_costs = edited_input_costs.groupby(['cost_category', _groupby_var, 'draw', 'stat'])['cost'].sum() - # Format the 'cost' values before creating the LaTeX table - grouped_costs = grouped_costs.apply(lambda x: f"{float(x):,.0f}") - # Remove underscores from all column values - - # Create a pivot table to restructure the data for LaTeX output - pivot_data = {} - for draw in [0, 3, 5, 8]: - draw_data = grouped_costs.xs(draw, level='draw').unstack(fill_value=0) # Unstack to get 'stat' as columns - # Concatenate 'mean' with 'lower-upper' in the required format - pivot_data[draw] = draw_data['mean'].astype(str) + ' [' + \ - draw_data['lower'].astype(str) + '-' + \ - draw_data['upper'].astype(str) + ']' - - # Combine draw data into a single DataFrame - table_data = pd.concat([pivot_data[0], pivot_data[3], pivot_data[5], pivot_data[8]], axis=1, keys=['draw=0', 'draw=3', 'draw=5', 'draw=8']).reset_index() - - # Rename columns for clarity - table_data.columns = ['Cost Category', _groupby_var_name, 'Actual', 'Expanded HRH', 'Improved consumable availability', 'Expanded HRH +\n Improved consumable availability'] - - # Replace '\n' with '\\' for LaTeX line breaks - #table_data['Real World'] = table_data['Real World'].apply(lambda x: x.replace("\n", "\\\\")) - #table_data['Perfect Health System'] = table_data['Perfect Health System'].apply(lambda x: x.replace("\n", "\\\\")) - - # Convert to LaTeX format with horizontal lines after every row - latex_table = table_data.to_latex( - longtable=_longtable, # Use the longtable environment for large tables - column_format='|R{3cm}|R{3cm}|R{2.2cm}|R{2.2cm}|R{2.2cm}|R{2.2cm}|', - caption=f"Summarized Costs by Category and {_groupby_var_name}", - label=f"tab:cost_by_{_groupby_var}", - position="h", - index=False, - escape=False, # Prevent escaping special characters like \n - header=True - ) - - # Add \hline after the header and after every row for horizontal lines - latex_table = latex_table.replace("\\\\", "\\\\ \\hline") # Add \hline after each row - #latex_table = latex_table.replace("_", " ") # Add \hline after each row - - # Specify the file path to save - latex_file_path = figurespath / f'cost_by_{_groupby_var}.tex' - - # Write to a file - with open(latex_file_path, 'w') as latex_file: - latex_file.write(latex_table) - - # Print latex for reference - print(latex_table) - -# Table F1: Cost by cost subcategory -generate_detail_cost_table(_groupby_var = 'cost_subcategory', _groupby_var_name = 'Cost Subcategory', _longtable = True) -# Table F2: Cost by cost subgroup -generate_detail_cost_table(_groupby_var = 'cost_subgroup', _groupby_var_name = 'Category Subgroup', _longtable = True) - -# Figure E1: Consumable inflow to outflow ratio figure -# ----------------------------------------------------------------------------------------------------------------------- -path_for_consumable_resourcefiles = resourcefilepath / "healthsystem/consumables" -# Estimate the stock to dispensed ratio from OpenLMIS data -lmis_consumable_usage = pd.read_csv(path_for_consumable_resourcefiles / "ResourceFile_Consumables_availability_and_usage.csv") -# Collapse individual facilities -lmis_consumable_usage_by_item_level_month = lmis_consumable_usage.groupby(['category', 'item_code', 'district', 'fac_type_tlo', 'month'])[['closing_bal', 'dispensed', 'received']].sum() -df = lmis_consumable_usage_by_item_level_month # Drop rows where monthly OpenLMIS data wasn't available -df = df.loc[df.index.get_level_values('month') != "Aggregate"] -opening_bal_january = df.loc[df.index.get_level_values('month') == 'January', 'closing_bal'] + \ - df.loc[df.index.get_level_values('month') == 'January', 'dispensed'] - \ - df.loc[df.index.get_level_values('month') == 'January', 'received'] -closing_bal_december = df.loc[df.index.get_level_values('month') == 'December', 'closing_bal'] -total_consumables_inflow_during_the_year = df.loc[df.index.get_level_values('month') != 'January', 'received'].groupby(level=[0,1,2,3]).sum() +\ - opening_bal_january.reset_index(level='month', drop=True) -\ - closing_bal_december.reset_index(level='month', drop=True) -total_consumables_outflow_during_the_year = df['dispensed'].groupby(level=[0,1,2,3]).sum() -inflow_to_outflow_ratio = total_consumables_inflow_during_the_year.div(total_consumables_outflow_during_the_year, fill_value=1) - -# Edit outlier ratios -inflow_to_outflow_ratio.loc[inflow_to_outflow_ratio < 1] = 1 # Ratio can't be less than 1 -inflow_to_outflow_ratio.loc[inflow_to_outflow_ratio > inflow_to_outflow_ratio.quantile(0.95)] = inflow_to_outflow_ratio.quantile(0.95) # Trim values greater than the 95th percentile -#average_inflow_to_outflow_ratio_ratio = inflow_to_outflow_ratio.mean() -inflow_to_outflow_ratio = inflow_to_outflow_ratio.reset_index().rename(columns = {0:'inflow_to_outflow_ratio'}) - -# Clean category names for plot -clean_category_names = {'cancer': 'Cancer', 'cardiometabolicdisorders': 'Cardiometabolic Disorders', - 'contraception': 'Contraception', 'general': 'General', 'hiv': 'HIV', 'malaria': 'Malaria', - 'ncds': 'Non-communicable Diseases', 'neonatal_health': 'Neonatal Health', - 'other_childhood_illnesses': 'Other Childhood Illnesses', 'reproductive_health': 'Reproductive Health', - 'road_traffic_injuries': 'Road Traffic Injuries', 'tb': 'Tuberculosis', - 'undernutrition': 'Undernutrition'} -inflow_to_outflow_ratio['category'] = inflow_to_outflow_ratio['category'].map(clean_category_names) - - -def plot_inflow_to_outflow_ratio(_df, groupby_var, _outputfilepath): - # Plot the bar plot with gray bars - plt.figure(figsize=(10, 6)) - sns.barplot(data=_df, x=groupby_var, y='inflow_to_outflow_ratio', errorbar=None, color="gray") - - # Add points representing the distribution of individual values - sns.stripplot(data=_df, x=groupby_var, y='inflow_to_outflow_ratio', color='black', size=5, alpha=0.2) - - # Wrap x-axis labels ONLY if they are strings and longer than 15 characters - labels = [] - for label in _df[groupby_var].unique(): - if isinstance(label, str) and len(label) > 15: - labels.append(textwrap.fill(label, width=15)) - else: - labels.append(label) - plt.xticks(ticks=range(len(labels)), labels=labels, rotation=90, ha='center') - - # Set labels and title - plt.xlabel(groupby_var) - plt.ylabel('Inflow to Outflow Ratio') - - # Show and save plot - plt.tight_layout() - plt.savefig(_outputfilepath / f'inflow_to_outflow_ratio_by_{groupby_var}.png') - plt.close() - -plot_inflow_to_outflow_ratio(inflow_to_outflow_ratio, 'fac_type_tlo', _outputfilepath = figurespath) -plot_inflow_to_outflow_ratio(inflow_to_outflow_ratio, 'district', _outputfilepath = figurespath) -plot_inflow_to_outflow_ratio(inflow_to_outflow_ratio, 'item_code', _outputfilepath = figurespath) -plot_inflow_to_outflow_ratio(inflow_to_outflow_ratio, 'category', _outputfilepath = figurespath) - -print(f"Inflow to Outflow ratio by consumable varies from " - f"{round(min(inflow_to_outflow_ratio.groupby('item_code')['inflow_to_outflow_ratio'].mean()),2)} " - f"to {round(max(inflow_to_outflow_ratio.groupby('item_code')['inflow_to_outflow_ratio'].mean()),2)}") - -inflow_to_outflow_ratio_by_item = inflow_to_outflow_ratio.groupby('item_code')['inflow_to_outflow_ratio'].mean().reset_index().rename(columns = {0: 'inflow_to_outflow_ratio'}) -inflow_to_outflow_ratio_by_item[inflow_to_outflow_ratio_by_item.inflow_to_outflow_ratio == min(inflow_to_outflow_ratio_by_item.inflow_to_outflow_ratio)]['item_code'] -inflow_to_outflow_ratio_by_item[inflow_to_outflow_ratio_by_item.inflow_to_outflow_ratio == max(inflow_to_outflow_ratio_by_item.inflow_to_outflow_ratio)]['item_code'] From 69ca90b1bc02c6b950b0365e723231f981321b0e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Apr 2025 16:45:27 +0100 Subject: [PATCH 435/755] scenariow_wast_min_model: use default pars --- .../scenario_wasting_minimal_model.py | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index c77a3bd0e2..53fffe99e3 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -9,7 +9,7 @@ tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py """ -import itertools +# import itertools import warnings from tlo import Date, logging @@ -43,7 +43,7 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=30_000, - number_of_draws=192, + number_of_draws=1, runs_per_draw=1, ) @@ -79,35 +79,35 @@ def modules(self): stunting.Stunting(resourcefilepath=self.resources), wasting.Wasting(resourcefilepath=self.resources)] - # def draw_parameters(self, draw_number, rng): - # # Using default parameters in all cases - # return {} - def draw_parameters(self, draw_number, rng): - base_death_rate_untreated_sam__draws = [0.030, 0.023, 0.017, 0.010] - mod_wast_incidence__coef = [0.7, 0.6, 0.5, 0.4] - base_overall_mod_wast_inc_rate = 0.019 - progression_to_sev_wast__coef = [1.0, 1.25, 1.5] - progression_severe_wasting_monthly_props_by_agegp = [0.3082, 0.8614, 0.4229, 0.4337, 0.2508, 0.3321] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.1, 0.17, 0.23, 0.3] + # Using default parameters in all cases + return {} - pars_combinations = list(itertools.product( - base_death_rate_untreated_sam__draws, - mod_wast_incidence__coef, - progression_to_sev_wast__coef, - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam - )) - - return { - 'Wasting': { - 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], - 'base_overall_inc_rate_wasting': base_overall_mod_wast_inc_rate * pars_combinations[draw_number][1] , - 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ - s in progression_severe_wasting_monthly_props_by_agegp], - 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / - (1-0.738)) - } - } + # def draw_parameters(self, draw_number, rng): + # base_death_rate_untreated_sam__draws = [0.030, 0.023, 0.017, 0.010] + # mod_wast_incidence__coef = [0.7, 0.6, 0.5, 0.4] + # base_overall_mod_wast_inc_rate = 0.019 + # progression_to_sev_wast__coef = [1.0, 1.25, 1.5] + # progression_severe_wasting_monthly_props_by_agegp = [0.3082, 0.8614, 0.4229, 0.4337, 0.2508, 0.3321] + # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.1, 0.17, 0.23, 0.3] + # + # pars_combinations = list(itertools.product( + # base_death_rate_untreated_sam__draws, + # mod_wast_incidence__coef, + # progression_to_sev_wast__coef, + # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam + # )) + # + # return { + # 'Wasting': { + # 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], + # 'base_overall_inc_rate_wasting': base_overall_mod_wast_inc_rate * pars_combinations[draw_number][1] , + # 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ + # s in progression_severe_wasting_monthly_props_by_agegp], + # 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / + # (1-0.738)) + # } + # } if __name__ == '__main__': from tlo.cli import scenario_run From f46641c75956a00affbaf2088caa145f00d51a69 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Apr 2025 16:48:43 +0100 Subject: [PATCH 436/755] test_wast: rm unused var --- tests/test_wasting.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index f0045cb8a5..50e11d01c1 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -833,10 +833,8 @@ def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): # Start appropriate treatment if am_state_expected == 'MAM': wmodule.do_when_am_treatment(person_id, intervention='SFP') - tx_length = p['tx_length_weeks_SuppFeedingMAM'] else: # complicated SAM wmodule.do_when_am_treatment(person_id, intervention='ITC') - tx_length = p['tx_length_weeks_InpatientSAM'] assert df.at[person_id, 'un_am_tx_start_date'] == sim.date # Check full recovery with tx is scheduled before the natural recovery From 55a3faa3452d7d9ba5002069bfeb20d9eb5b5d11 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Apr 2025 17:18:34 +0100 Subject: [PATCH 437/755] wast: read_pars updated to the use the read_csv_files fnc --- src/tlo/methods/wasting.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index bc3fa96d64..72638c02d1 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -243,12 +243,11 @@ def __init__(self, name=None, resourcefilepath=None): def read_parameters(self, data_folder): """ - :param data_folder: path of a folder supplied to the Simulation containing data files. Typically, - modules would read a particular file within here. + :param data_folder: path to a folder supplied to the simulation containing data csv files """ # Read parameters from the resource file self.load_parameters_from_dataframe( - pd.read_csv(Path(self.resourcefilepath) / 'ResourceFile_Wasting/parameters.csv') + read_csv_files(Path(self.resourcefilepath) / 'ResourceFile_Wasting', files='parameters') ) # Register wasting symptom (weight loss) in Symptoms Manager with high odds of seeking care From d19934277f83c04c1932748905afd77d4d100628 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Apr 2025 18:17:10 +0100 Subject: [PATCH 438/755] long_run_all_diseases: BACK pop_size 20K and 10 draws --- .../calibration_analyses/scenarios/long_run_all_diseases.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/calibration_analyses/scenarios/long_run_all_diseases.py b/src/scripts/calibration_analyses/scenarios/long_run_all_diseases.py index f83cd3f613..4a354e026c 100644 --- a/src/scripts/calibration_analyses/scenarios/long_run_all_diseases.py +++ b/src/scripts/calibration_analyses/scenarios/long_run_all_diseases.py @@ -22,9 +22,9 @@ def __init__(self): self.seed = 0 self.start_date = Date(2010, 1, 1) self.end_date = Date(2031, 1, 1) # The simulation will stop before reaching this date. - self.pop_size = 100_000 + self.pop_size = 20_000 self.number_of_draws = 1 - self.runs_per_draw = 1 + self.runs_per_draw = 10 def log_configuration(self): return { From 9628bfba949cd554939035f9f0e561c9f8bde894 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Apr 2025 18:26:45 +0100 Subject: [PATCH 439/755] wast: import read_csv_files fnc --- src/tlo/methods/wasting.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 72638c02d1..e69fda1360 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -17,6 +17,7 @@ from tlo.methods.healthsystem import HSI_Event from tlo.methods.hsi_generic_first_appts import GenericFirstAppointmentsMixin from tlo.methods.symptommanager import Symptom +from tlo.util import read_csv_files if TYPE_CHECKING: from tlo.methods.hsi_generic_first_appts import HSIEventScheduler From 71c59fe02c01609f78099c93e193c4599ddaaf62 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Apr 2025 18:30:21 +0100 Subject: [PATCH 440/755] del old analysis and scenario scripts --- .../analysis_wasting_with_sim_running.py | 252 ------------------ .../scenarios/scenario_wasting_full_model.py | 59 ---- .../scenarios/scenario_wasting_orig.py | 96 ------- 3 files changed, 407 deletions(-) delete mode 100644 src/scripts/wasting_analyses/analysis_wasting_with_sim_running.py delete mode 100644 src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py delete mode 100644 src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py diff --git a/src/scripts/wasting_analyses/analysis_wasting_with_sim_running.py b/src/scripts/wasting_analyses/analysis_wasting_with_sim_running.py deleted file mode 100644 index b6d6480c91..0000000000 --- a/src/scripts/wasting_analyses/analysis_wasting_with_sim_running.py +++ /dev/null @@ -1,252 +0,0 @@ -""" -An analysis file for the wasting module -""" -import datetime -# %% Import statements -from pathlib import Path - -import pandas as pd -from matplotlib import pyplot as plt - -from tlo import Date, Simulation, logging -from tlo.analysis.utils import compare_number_of_deaths, parse_log_file -from tlo.methods import ( - care_of_women_during_pregnancy, - contraception, - demography, - enhanced_lifestyle, - epi, - healthburden, - healthseekingbehaviour, - healthsystem, - hiv, - labour, - newborn_outcomes, - postnatal_supervisor, - pregnancy_supervisor, - symptommanager, - tb, - wasting, -) - - -def add_footnote(fig: plt.Figure, footnote: str): - """ A function that adds a footnote below each plot. Here we are explaining what a denominator for every - graph is """ - fig.figure.text(0.5, 0.01, footnote, ha="center", fontsize=10, - bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) - - -class WastingAnalyses: - """ - This class looks at plotting all important outputs from the wasting module - """ - - def __init__(self, log_file_path): - self.__log_file_path = log_file_path - # parse wasting logs - self.__logs_dict = \ - parse_log_file(self.__log_file_path)['tlo.methods.wasting'] - - # gender description - self.__gender_desc = {'M': 'Males', - 'F': 'Females'} - - # wasting types description - self.__wasting_types_desc = {'WHZ<-3': 'severe wasting', - '-3<=WHZ<-2': 'moderate wasting', - 'WHZ>=-2': 'not undernourished'} - - def plot_wasting_incidence(self): - """ plot the incidence of wasting over time """ - w_inc_df = self.__logs_dict['wasting_incidence_count'] - w_inc_df.set_index(w_inc_df.date.dt.year, inplace=True) - w_inc_df.drop(columns='date', inplace=True) - # get age year. doesn't matter what wasting category you choose for - # they all have same age groups - age_years = list(w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys( - - )) - age_years.remove('5+y') - - _row_counter = 0 - _col_counter = 0 - # plot setup - fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True) - for _age in age_years: - new_df = pd.DataFrame() - for state in w_inc_df.columns: - new_df[state] = \ - w_inc_df.apply(lambda row: row[state][_age], axis=1) - - new_df = new_df.apply(lambda _row: _row / _row.sum(), axis=1) - plotting = new_df[["WHZ<-3", "-3<=WHZ<-2"]] - # convert into proportions - ax = plotting.plot(kind='bar', stacked=True, - ax=axes[_row_counter, _col_counter], - title=f"incidence of wasting in {_age} infants", - ylim=[0, 0.05]) - ax.legend(self.__wasting_types_desc.values(), loc='lower right') - ax.set_xlabel('year') - ax.set_ylabel('proportions') - # move to another row - if _col_counter == 2: - _row_counter += 1 - _col_counter = -1 - _col_counter += 1 # increment column counter - fig.tight_layout() - fig.savefig( - outputs / ('wasting incidence' + datestamp + ".pdf"), - format="pdf" - ) - plt.show() - - def plot_wasting_prevalence_per_year(self): - """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of - children wasted divide by the total number of children less than 5 years""" - w_prev_df = self.__logs_dict["wasting_prevalence_props"] - w_prev_df = w_prev_df[['date', 'total_under5_prop']] - w_prev_df.set_index(w_prev_df.date.dt.year, inplace=True) - w_prev_df.drop(columns='date', inplace=True) - fig, ax = plt.subplots() - w_prev_df["total_under5_prop"].plot(kind='bar', stacked=True, - ax=ax, - title="Wasting prevalence in children 0-59 months per year", - ylabel='proportion of wasted children within the age-group', - xlabel='year', - ylim=[0, 0.05]) - # add_footnote(fig, "proportion of wasted children within each age-group") - plt.tight_layout() - fig.savefig( - outputs / ('wasting_prevalence_per_year' + datestamp + ".pdf"), - format="pdf" - ) - plt.show() - - def plot_wasting_prevalence_by_age_group(self): - """ plot wasting prevalence per each age group. Proportions are obtained by getting a total number of - children wasted in a particular age-group divide by the total number of children per that age-group""" - w_prev_df = self.__logs_dict["wasting_prevalence_props"] - w_prev_df.drop(columns={'total_under5_prop'}, inplace=True) - w_prev_df.set_index(w_prev_df.date.dt.year, inplace=True) - w_prev_df = w_prev_df.loc[w_prev_df.index == 2023] - w_prev_df.drop(columns='date', inplace=True) - fig, ax = plt.subplots() - # plot wasting prevalence - w_prev_df.squeeze().plot(kind='bar', stacked=False, - ax=ax, - title="Wasting prevalence in children 0-59 months per each age group in 2023", - ylabel='proportions', - xlabel='year', - ylim=[0, 0.1]) - add_footnote(fig, "Proportion = total number of wasted children < 5 years per each age-group / total number of " - "children < 5 years per each age-group") - plt.tight_layout() - fig.savefig( - outputs / ('wasting_prevalence_per_each_age_group' + datestamp + ".pdf"), - format="pdf" - ) - plt.show() - - def plot_modal_gbd_deaths_by_gender(self): - """ compare modal and GBD deaths by gender """ - death_compare = \ - compare_number_of_deaths(self.__log_file_path, resources) - fig, axs = plt.subplots(nrows=1, ncols=2, sharey=True, sharex=True) - for _col, sex in enumerate(('M', 'F')): - plot_df = death_compare.loc[(['2010-2014', '2015-2019'], - sex, slice(None), 'Childhood Undernutrition' - )].groupby('period').sum() - plotting = plot_df.loc[['2010-2014', '2015-2019']] - ax = plotting['model'].plot.bar(label='Model', ax=axs[_col], rot=0) - ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, - yerr=[plotting.GBD_lower, plotting.GBD_upper], - fmt='o', color='#000', label="GBD") - ax.set_title(f'{self.__gender_desc[sex]} ' - f'wasting deaths, 2010-2014') - ax.set_xlabel("Time period") - ax.set_ylabel("Number of deaths") - ax.legend(loc=2) - fig.tight_layout() - add_footnote(fig, "Model output against Global Burden of Diseases(GDB) study data") - fig.savefig( - outputs / ('modal_gbd_deaths_by_gender' + datestamp + ".pdf"), - format="pdf" - ) - plt.show() - - -if __name__ == "__main__": - seed = 1 - - # Path to the resource files used by the disease and intervention methods - resources = Path("./resources") - outputs = Path("./outputs") - - # create a datestamp - datestamp = datetime.date.today().strftime("__%Y_%m_%d") + \ - datetime.datetime.now().strftime("%H_%M_%S") - - # configure logging - log_config = { - # output filename. A timestamp will be added to this. - "filename": "wasting", - "custom_levels": { # Customise the output of specific loggers - "tlo.methods.demography": logging.INFO, - "tlo.methods.population": logging.INFO, - "tlo.methods.wasting": logging.INFO, - '*': logging.WARNING - } - } - - # Basic arguments required for the simulation - start_date = Date(2010, 1, 1) - end_date = Date(2030, 1, 2) - pop_size = 20000 - - # Create simulation instance for this run. - sim = Simulation(start_date=start_date, seed=seed, log_config=log_config) - - # Register modules for simulation - sim.register( - demography.Demography(resourcefilepath=resources), - healthsystem.HealthSystem(resourcefilepath=resources, - service_availability=['*'], - cons_availability='default'), - healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resources), - healthburden.HealthBurden(resourcefilepath=resources), - symptommanager.SymptomManager(resourcefilepath=resources), - enhanced_lifestyle.Lifestyle(resourcefilepath=resources), - labour.Labour(resourcefilepath=resources), - care_of_women_during_pregnancy.CareOfWomenDuringPregnancy( - resourcefilepath=resources), - contraception.Contraception(resourcefilepath=resources), - pregnancy_supervisor.PregnancySupervisor(resourcefilepath=resources), - postnatal_supervisor.PostnatalSupervisor(resourcefilepath=resources), - newborn_outcomes.NewbornOutcomes(resourcefilepath=resources), - hiv.Hiv(resourcefilepath=resources), - tb.Tb(resourcefilepath=resources), - epi.Epi(resourcefilepath=resources), - wasting.Wasting(resourcefilepath=resources), - ) - - sim.make_initial_population(n=pop_size) - sim.simulate(end_date=end_date) - - # read the results - output_path = sim.log_filepath - - # initialise the wasting class - wasting_analyses = WastingAnalyses(output_path) - - # plot wasting incidence - wasting_analyses.plot_wasting_incidence() - - # plot wasting prevalence - wasting_analyses.plot_wasting_prevalence_per_year() - - # plot wasting prevalence by age group - wasting_analyses.plot_wasting_prevalence_by_age_group() - - # plot wasting deaths by gender as compared to GBD deaths - wasting_analyses.plot_modal_gbd_deaths_by_gender() diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py deleted file mode 100644 index f4472a6794..0000000000 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py +++ /dev/null @@ -1,59 +0,0 @@ -""" -This file defines a scenario for wasting analysis. - -It can be submitted on Azure Batch by running: - - tlo batch-submit src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py - -or locally using: - - tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model.py -""" -import warnings - -from tlo import Date, logging -from tlo.methods.fullmodel import fullmodel -from tlo.scenario import BaseScenario - -# capture warnings during simulation run -warnings.simplefilter('default', (UserWarning, RuntimeWarning)) - - -class WastingAnalysis(BaseScenario): - - def __init__(self): - super().__init__( - seed=0, - start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2031, month=1, day=1), - initial_population_size=20_000, - number_of_draws=1, - runs_per_draw=10, - ) - - def log_configuration(self): - return { - 'filename': 'wasting_analysis__full_model', - 'directory': './outputs/wasting_analysis', - "custom_levels": { # Customise the output of specific loggers - "tlo.methods.demography": logging.INFO, - "tlo.methods.population": logging.INFO, - "tlo.methods.wasting": logging.INFO, - '*': logging.WARNING - } - } - - def modules(self): - return fullmodel( - resourcefilepath=self.resources - ) - - def draw_parameters(self, draw_number, rng): - # Using default parameters in all cases - return {} - - -if __name__ == '__main__': - from tlo.cli import scenario_run - - scenario_run([__file__]) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py deleted file mode 100644 index 59f7470afd..0000000000 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py +++ /dev/null @@ -1,96 +0,0 @@ -""" -This file defines a scenario for wasting analysis. - -It can be submitted on Azure Batch by running: - - tlo batch-submit src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py - -or locally using: - - tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_orig.py -""" -import warnings - -from tlo import Date, logging -from tlo.methods import ( - alri, - care_of_women_during_pregnancy, - contraception, - demography, - diarrhoea, - enhanced_lifestyle, - epi, - healthburden, - healthseekingbehaviour, - healthsystem, - hiv, - labour, - newborn_outcomes, - postnatal_supervisor, - pregnancy_supervisor, - stunting, - symptommanager, - tb, - wasting, -) -from tlo.scenario import BaseScenario - -# capture warnings during simulation run -warnings.simplefilter('default', (UserWarning, RuntimeWarning)) - - -class WastingAnalysis(BaseScenario): - - def __init__(self): - super().__init__( - seed=0, - start_date=Date(year=2010, month=1, day=1), - end_date=Date(year=2031, month=1, day=1), - initial_population_size=20_000, - number_of_draws=1, - runs_per_draw=1, - ) - - def log_configuration(self): - return { - 'filename': 'wasting_analysis__orig', - 'directory': './outputs', - "custom_levels": { # Customise the output of specific loggers - "tlo.methods.demography": logging.INFO, - "tlo.methods.population": logging.INFO, - "tlo.methods.wasting": logging.INFO, - '*': logging.WARNING - } - } - - def modules(self): - return [demography.Demography(resourcefilepath=self.resources), - healthsystem.HealthSystem(resourcefilepath=self.resources, - service_availability=['*'], cons_availability='default'), - healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=self.resources), - healthburden.HealthBurden(resourcefilepath=self.resources), - symptommanager.SymptomManager(resourcefilepath=self.resources), - enhanced_lifestyle.Lifestyle(resourcefilepath=self.resources), - labour.Labour(resourcefilepath=self.resources), - care_of_women_during_pregnancy.CareOfWomenDuringPregnancy(resourcefilepath=self.resources), - contraception.Contraception(resourcefilepath=self.resources), - pregnancy_supervisor.PregnancySupervisor(resourcefilepath=self.resources), - postnatal_supervisor.PostnatalSupervisor(resourcefilepath=self.resources), - newborn_outcomes.NewbornOutcomes(resourcefilepath=self.resources), - hiv.Hiv(resourcefilepath=self.resources), - tb.Tb(resourcefilepath=self.resources), - epi.Epi(resourcefilepath=self.resources), - alri.Alri(resourcefilepath=self.resources), - diarrhoea.Diarrhoea(resourcefilepath=self.resources), - stunting.Stunting(resourcefilepath=self.resources), - wasting.Wasting(resourcefilepath=self.resources)] - - def draw_parameters(self, draw_number, rng): - # Using default parameters in all cases - return {} - - -if __name__ == '__main__': - from tlo.cli import scenario_run - - scenario_run([__file__]) From 47941b7a77e05835290fbf5373d510c662f5349c Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Apr 2025 18:32:33 +0100 Subject: [PATCH 441/755] analysis/utils: Inpatient back to color map --- src/tlo/analysis/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tlo/analysis/utils.py b/src/tlo/analysis/utils.py index bdf019b45d..b990536579 100644 --- a/src/tlo/analysis/utils.py +++ b/src/tlo/analysis/utils.py @@ -869,6 +869,7 @@ def get_color_coarse_appt(coarse_appt_type: str) -> str: '*': 'black', 'FirstAttendance*': 'darkgrey', + 'Inpatient*': 'silver', 'Contraception*': 'darkseagreen', 'AntenatalCare*': 'green', From 856aa566cbbedee5a285e70a9c6f75d6fb2b72ce Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 29 Apr 2025 22:40:23 +0100 Subject: [PATCH 442/755] RF_PriorityRanking_ALLPOLICIES: add priorities for Undernutrition_ treatments called from Wasting module --- .../ResourceFile_PriorityRanking_ALLPOLICIES/CVD.csv | 4 ++-- .../ClinicallyVulnerable.csv | 4 ++-- .../ResourceFile_PriorityRanking_ALLPOLICIES/Default.csv | 4 ++-- .../ResourceFile_PriorityRanking_ALLPOLICIES/EHP_III.csv | 4 ++-- .../ResourceFile_PriorityRanking_ALLPOLICIES/LCOA_EHP.csv | 4 ++-- .../ResourceFile_PriorityRanking_ALLPOLICIES/Naive.csv | 4 ++-- .../ResourceFile_PriorityRanking_ALLPOLICIES/RMNCH.csv | 4 ++-- .../ResourceFile_PriorityRanking_ALLPOLICIES/Test Mode 1.csv | 4 ++-- .../ResourceFile_PriorityRanking_ALLPOLICIES/Test.csv | 4 ++-- .../VerticalProgrammes.csv | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/CVD.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/CVD.csv index 52b99ed461..35391723c3 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/CVD.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/CVD.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cc09af1e8f19821e0db693fe260ab1775409fa8a391ed2ccccf09b96543528f5 -size 3499 +oid sha256:99eb5bb3e95438c937cc306efce065e13314503fa42d29f69f43d0e7b7ed55f6 +size 3691 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/ClinicallyVulnerable.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/ClinicallyVulnerable.csv index 8c7ff906fe..36a8acb982 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/ClinicallyVulnerable.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/ClinicallyVulnerable.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a34370ec4e83a3726bbf4f28c6c309e52ed033e7d9b48f53888496fb7aa5a7ee -size 3159 +oid sha256:1ecf780918457a52ea696a4d78b2a714461c286524e94ea08ab0786b543f9d3d +size 3335 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Default.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Default.csv index 1262bd6035..ef406af146 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Default.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Default.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cfb5baf5936b7ba3c207d627d55ba2c44d1d01958a30de5e54caf20ddb3edd20 -size 3501 +oid sha256:9765f315c5c14e5f05f9f5ad8d44d4a0b199fa646663bced90dfc9b2d435665d +size 3693 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/EHP_III.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/EHP_III.csv index f37a393041..5ea57f975f 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/EHP_III.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/EHP_III.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:57449b3c28576e94797e8d400bc268cf9201d7e596c806924bdc30525d699c77 -size 3500 +oid sha256:d16375b7d09471b7cb8e642ee5ba5950eaea1839344a1d78dbccaaccc2b37af4 +size 3692 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/LCOA_EHP.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/LCOA_EHP.csv index 83d405f0ac..74e1693f10 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/LCOA_EHP.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/LCOA_EHP.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c93a6fb2e4cad0fc034b14b272453b70e1642ee818d1871a64c77466699bd123 -size 3499 +oid sha256:d1dab952563f8c0ea2925abfbdd433bdeeece0cf90618518dc8ce84333f0a1ce +size 3691 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Naive.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Naive.csv index 2540feeadc..3edb46845a 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Naive.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Naive.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0fe06f32b2f70bb1ca4c1f7352b903ba525afa314e614a71d67aa29ca376e17e -size 3499 +oid sha256:833be1d5561c8a025fc236908c3154591c34f527f949aca66eb0c036c17159f5 +size 3691 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/RMNCH.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/RMNCH.csv index 6fe57d665a..b079737008 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/RMNCH.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/RMNCH.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ad79df6d5a331739def0c5fcb0d4c8ffb7c803442db519da53a19d566886a41b -size 3484 +oid sha256:2270c7abfe61d618393c72f2b8b91e5e83521fad88e346dbd3c50f0c70daca2c +size 3672 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test Mode 1.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test Mode 1.csv index 5db5e3409f..4f36332334 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test Mode 1.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test Mode 1.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:be03d20472c7f1e476a02dfd8ebcf0f218a0cf0aa7fa12cf55a83139e26bab7e -size 3501 +oid sha256:bff2f55a3697e5d03ee74d1aeb5b665021dabe9b83d32dff5706759b090f3778 +size 3693 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test.csv index 02d1286257..377813f49f 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:79d1805d9389115bbd2a32296b6e81e4ae5f8465e4ef11b0708400e4e3f85407 -size 3501 +oid sha256:90c96330accbd06f723fe0f9935e6f66895ea877e91aa99bcb71deaaf16e3d7d +size 3693 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/VerticalProgrammes.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/VerticalProgrammes.csv index 1df2416902..12dcc372ea 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/VerticalProgrammes.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/VerticalProgrammes.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:419b8f59fe5bd8cbcc212c4b5425c42a7d1172416cd3488c81a3533c84092e2b -size 3499 +oid sha256:226fc79de5d5391085f1c60171c246016d5825aec65069e17a4305e8ddde1fff +size 3691 From 8f6fe660c846a1417721ef3d03a56c42b48f7599 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 30 Apr 2025 12:58:32 +0100 Subject: [PATCH 443/755] scenario_wast_min_model: 4K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 53fffe99e3..9d07b970d4 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + initial_population_size=4_000, number_of_draws=1, runs_per_draw=1, ) From 9c5bd7a1c12bc78ed4ad18b27c7c3d160fcc39d7 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 30 Apr 2025 15:24:11 +0100 Subject: [PATCH 444/755] wast: rm misdiagnosing feature, not ready yet (opened issue #1612 with a draft design) --- src/tlo/methods/wasting.py | 47 ++++---------------------------------- 1 file changed, 4 insertions(+), 43 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index e69fda1360..87a92f6ed1 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1675,51 +1675,12 @@ def schedule_tx_by_diagnosis(hsi_event): complications = df.at[person_id, 'un_sam_with_complications'] # DIAGNOSIS + # in future this is the place where misdiagnosing will be happening (but should be happening also in the generic + # first appt), however current asserts are made for the case when all equip available, hence they will need to + # be adjusted, see issue #1612 # oedema is assumed to be quite obvious if present # in addition, based on performed measurements (depending on what equipment is available) - if df.at[person_id, 'un_am_nutritional_oedema']: - diagnosis = 'SAM' - if do_prints: - print(f"oedema present => {diagnosis=}") - else: - # all equip available and used for diagnosis - if all(item in available_equipment for item in - ['Height Pole (Stadiometer)', 'Weighing scale']): - diagnosis = df.at[person_id, 'un_clinical_acute_malnutrition'] - if do_prints: - print(f"oedema not present, all equip available, hence {diagnosis=} is the actual am state: " - f"{df.at[person_id, 'un_clinical_acute_malnutrition']=}") - # MUAC measurement is solely used for diagnosis, as Height Pole and/or Weighing scale not available - elif 'MUAC tape' in available_equipment: - # TODO: rm print - print("debugging-WARNING: full availability of equip assumed, we should have never get here") - muac = df.at[person_id, 'un_am_MUAC_category'] - if muac == '>=125mm': - diagnosis = 'well' - elif muac == '<115mm': - diagnosis = 'SAM' - else: - diagnosis = 'MAM' - if do_prints: - print("oedema not present, MUAC tape available but heigh pole and/pr weighing scale not, hence " - f"{diagnosis=} based on {muac=}, not on actual state " - f"{df.at[person_id, 'un_clinical_acute_malnutrition']=}") - # WHZ score is solely used for diagnosis - elif all(item in available_equipment for item in - ['Height Pole (Stadiometer)', 'Weighing scale']): - # TODO: rm print - print("debugging-WARNING: full availability of equip assumed, we should have never get here") - whz = df.at[person_id, 'un_WHZ_category'] - if whz == 'WHZ>=-2': - diagnosis = 'well' - elif whz == 'WHZ<-3': - diagnosis = 'SAM' - else: - diagnosis = 'MAM' - # WHZ score nor MUAC measurement available, hence diagnosis based solely on presence of oedema and oedema is - # not present - else: - diagnosis = 'well' + diagnosis = df.at[person_id, 'un_clinical_acute_malnutrition'] if diagnosis == 'well': if do_prints: From d05f61bf99bd6e62fc308c0e2dc4c6cecd570017 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 30 Apr 2025 16:41:29 +0100 Subject: [PATCH 445/755] find_pars_draw_nmb: a script to find which draw did run with searched parameters set --- .../wasting_analyses/find_pars_draw_nmb.py | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/scripts/wasting_analyses/find_pars_draw_nmb.py diff --git a/src/scripts/wasting_analyses/find_pars_draw_nmb.py b/src/scripts/wasting_analyses/find_pars_draw_nmb.py new file mode 100644 index 0000000000..ea2c84d841 --- /dev/null +++ b/src/scripts/wasting_analyses/find_pars_draw_nmb.py @@ -0,0 +1,33 @@ +''' +This will print out the draw number for which searched parameters set was used +''' +import itertools +# update the parameters set for the job +parameters = { + "base_death_rate_untreated_sam": [0.1, 0.05, 0.03, 0.01], + "mod_wast_incidence__coef": [1.0, 0.6, 0.2], + "progression_to_sev_wast__coef": [0.5, 0.75, 1.0, 1.5, 2.0, 2.3], + "prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam": [0.1, 0.4, 0.7] +} +# what parameters set are you looking for? +pars_set_searched = [0.03, 0.6, 1.0, 0.1] + +################################################## +def find_pars_draw_nmb(in_parameters, in_pars_set_searched): + base_death_rate_untreated_sam__draws = parameters["base_death_rate_untreated_sam"] + mod_wast_incidence__coef = parameters["mod_wast_incidence__coef"] + progression_to_sev_wast__coef = parameters["progression_to_sev_wast__coef"] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = parameters["prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam"] + + pars_combinations = list(itertools.product( + base_death_rate_untreated_sam__draws, + mod_wast_incidence__coef, + progression_to_sev_wast__coef, + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam + )) + if tuple(in_pars_set_searched) in pars_combinations: + print(f"Position of searched parameters: {pars_combinations.index(tuple(in_pars_set_searched))}") + else: + print(f"Searched parameters {in_pars_set_searched} not found in combinations: {pars_combinations}") + +find_pars_draw_nmb(parameters, pars_set_searched) From 6f43509a0b44a40c43269ed0b2dde1e11b993217 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 30 Apr 2025 16:43:46 +0100 Subject: [PATCH 446/755] wast: minor (a print updated) --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 87a92f6ed1..b34624c715 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1000,7 +1000,7 @@ def apply(self, population): # # # INCIDENCE OF MODERATE WASTING # # # # # # # # # # # # # # # # # # # # # if self.module.person_of_interest_born_bool: - print("INCIDENCE") + print(f"INCIDENCE on {self.sim.date=}") # Determine who will be onset with wasting among those who # currently do not have acute malnutrition, are not being treated, and did not recover in the last 14 days not_am_or_treated_or_recently_recovered =\ From dbbd2f54ae6bb6087b77ddeac7432feb278f8265 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 1 May 2025 17:57:42 +0100 Subject: [PATCH 447/755] wast: rm prints --- src/tlo/methods/wasting.py | 490 +++++-------------------------------- 1 file changed, 57 insertions(+), 433 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index b34624c715..8b7e1bd17f 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -232,9 +232,6 @@ def __init__(self, name=None, resourcefilepath=None): _agrp: copy.deepcopy(blank_length_counter) for _agrp in ['0y', '1y', '2y', '3y', '4y', '5+y']} self.wasting_length_tracker = copy.deepcopy(self.wasting_length_tracker_blank) - self.person_of_interest_id = 31846 # debugging - self.person_of_interest_born_bool = False - # define age groups self.age_grps = {0: '0y', 1: '1y', 2: '2y', 3: '3y', 4: '4y'} self.age_gps_range_mo = [] @@ -269,25 +266,15 @@ def initialise_population(self, population): """ df = population.props p = self.parameters - print("\nPARAMETERS:") - print(f"{p['base_death_rate_untreated_SAM']=}") - print(f"mod_wast_incidence__coef={p['base_overall_inc_rate_wasting']/0.019}") - print(f"progression_to_sev_wast__coef={p['progression_severe_wasting_monthly_by_agegp'][0]/0.3082}") - if p['base_death_rate_untreated_SAM'] != 0: - print("prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam=" - f"{p['prob_death_after_SAMcare']*(1-0.738)/p['base_death_rate_untreated_SAM']}") - print("-----------") - print(f"{p['base_overall_inc_rate_wasting']=}") - print("base inc rates by age group: " - f"{[s * p['base_overall_inc_rate_wasting'] for s in p['rr_inc_rate_wasting_by_agegp']]}") - print(f"{p['progression_severe_wasting_monthly_by_agegp']=}") - print(f"{p['prob_death_after_SAMcare']=}") # Adjust monthly severe wasting incidence to the duration of untreated moderate wasting p['progression_severe_wasting_by_agegp'] = \ [s/30.4375*p['duration_of_untreated_mod_wasting'] for s in p['progression_severe_wasting_monthly_by_agegp']] - print(f"{p['progression_severe_wasting_by_agegp']=}") - print() + logger.debug( + key="progression_severe_wasting_by_agegp", + data="A progression_severe_wasting_monthly_by_agegp adjusted to the duration of untreated moderate wasting:" + f" {p['progression_severe_wasting_by_agegp']}" + ) # Set initial properties df.loc[df.is_alive, 'un_ever_wasted'] = False @@ -339,19 +326,6 @@ def initialise_population(self, population): # # # # and, in SAM cases, determine presence of complications and eventually schedule death # # # # self.clinical_signs_acute_malnutrition(under5s_index) - print(f"\n{self.person_of_interest_id=}") - print("###########") - if self.person_of_interest_id in df.index: - self.person_of_interest_born_bool = True - print(f"initial wasting: {df.loc[self.person_of_interest_id, 'un_WHZ_category']}") - print(f"initial MUAC: {df.loc[self.person_of_interest_id, 'un_am_MUAC_category']}") - print(f"initial oedema: {df.loc[self.person_of_interest_id, 'un_am_nutritional_oedema']}") - print(f"initial complicaions: {df.loc[self.person_of_interest_id, 'un_sam_with_complications']}") - print(f"initial am status: {df.loc[self.person_of_interest_id, 'un_clinical_acute_malnutrition']}") - else: - print("person_of_interest not born yet") - print("--------------------------------------") - def initialise_simulation(self, sim): """Prepares for simulation. Schedules: * the first growth monitoring to happen straight away, scheduled monthly to detect new cases for treatment. @@ -363,8 +337,6 @@ def initialise_simulation(self, sim): sim.schedule_event(Wasting_InitiateGrowthMonitoring(self), sim.date) sim.schedule_event(Wasting_IncidencePoll(self), sim.date + DateOffset(months=3)) sim.schedule_event(Wasting_LoggingEvent(self), sim.date + DateOffset(years=1) - DateOffset(days=1)) - # sim.schedule_event(PrintPersonPropertiesEventIfUpdated(self, self.person_of_interest_id), - # sim.date + DateOffset(days=1)) # Retrieve the consumables codes and amounts of the consumables used self.cons_codes = self.get_consumables_for_each_treatment() @@ -400,11 +372,6 @@ def on_birth(self, mother_id, child_id): priority=2, topen=self.sim.date + pd.DateOffset(days=1) ) - if child_id == self.person_of_interest_id: - self.person_of_interest_born_bool = True - print(f"person_of_interest born {self.sim.date=}") - print("-------") - def muac_cutoff_by_WHZ(self, idx, whz): """ Proportion of MUAC < 115 mm in WHZ < -3 and -3 <= WHZ < -2, @@ -557,14 +524,6 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): assert not ((df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') and (df.at[person_id, 'un_sam_with_complications'])), f'{person_id=} has MAM with complications.' - if person_id == self.person_of_interest_id: - print('-----') - print("Acute Malnutrition state ASSIGNED") - print(f"am state: {df.at[person_id, 'un_clinical_acute_malnutrition']}; " - f"complications: {df.at[person_id, 'un_sam_with_complications']}; " - f"death_date: {df.at[person_id, 'un_sam_death_date']}") - print("-----") - def get_consumables_for_each_treatment(self): """Get the item_code and amount administrated for all consumables for each treatment.""" @@ -703,37 +662,22 @@ def do_at_generic_first_appt( ) -> None: df = self.sim.population.props - # p = self.parameters - - do_prints = False - if person_id == self.person_of_interest_id: - do_prints = True - print(f"NON-EMERGENCY APPT on {self.sim.date=}") - print(f"{symptoms=}") + # if person not under 5 or currently treated or non-emerg. appt went through today already, acute malnutrition + # will not be assessed during this appt if (individual_properties['age_years'] >= 5) or \ (individual_properties['un_last_wasting_date_of_onset'] < individual_properties['un_am_tx_start_date'] < self.sim.date) or \ (self.sim.date == individual_properties['un_last_nonemergency_appt_date']): - if do_prints: - print("not going through because") - if individual_properties["age_years"] >= 5: - print(f"person not under 5, {individual_properties['age_years']=}") - if (individual_properties['un_last_wasting_date_of_onset'] < individual_properties['un_am_tx_start_date'] < - self.sim.date): - print(f"person currently treated, {individual_properties['un_am_treatment_type']=}") - if self.sim.date == individual_properties['un_last_nonemergency_appt_date']: - print("the non-emerg. appt did went through today already") - print("----------------------------------") if self.sim.date == individual_properties['un_last_nonemergency_appt_date']: logger.debug( - key="non-emergency", + key="multiple non-emergency appts on same day", data=f"A non-emerg. appt runs again on the same date {self.sim.date=} for the {person_id=}. " "All DOs related to wasting are cancelled." ) return - # or if HSI was already scheduled due to growth monitoring, won't be checked for acute malnutrition again + #or if HSI was already scheduled due to growth monitoring, won't be checked for acute malnutrition again hsi_event_scheduled = [ ev for ev in self.sim.modules["HealthSystem"].find_events_for_person(person_id) @@ -742,8 +686,6 @@ def do_at_generic_first_appt( HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM)) ] if hsi_event_scheduled: - if do_prints: - print(f"not going through because {hsi_event_scheduled=} via growth monitoring") return # track the date of the last non-emergency appt @@ -752,48 +694,34 @@ def do_at_generic_first_appt( # get the clinical states clinical_am = individual_properties['un_clinical_acute_malnutrition'] complications = individual_properties['un_sam_with_complications'] - if do_prints: - print(f"{clinical_am=}, {complications=}") - # No interventions if well + # No intervention if well if clinical_am == 'well': - if do_prints: - print("person is well, hence no outcomes from the appt") - print("---------------------------------------------") return - # Interventions for MAM + # SFP intervention if diagnosed as MAM elif clinical_am == 'MAM': # schedule HSI for supplementary feeding program for MAM - if do_prints: - print("SFP for MAM scheduled for today") schedule_hsi_event( hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), priority=0, topen=self.sim.date) elif clinical_am == 'SAM': - # Interventions for uncomplicated SAM + # OTP intervention if diagnosed as uncomplicated SAM if not complications: # schedule HSI for supplementary feeding program for MAM - if do_prints: - print("OTP for SAM w\out complications scheduled for today") schedule_hsi_event( hsi_event=HSI_Wasting_OutpatientTherapeuticProgramme_SAM(module=self, person_id=person_id), priority=0, topen=self.sim.date) - # Interventions for complicated SAM + # ITC intervention if diagnosed as complicated SAM if complications: # schedule HSI for supplementary feeding program for MAM - if do_prints: - print("ITC for SAM w\ complications scheduled for today") schedule_hsi_event( hsi_event=HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM(module=self, person_id=person_id), priority=0, topen=self.sim.date) - if do_prints: - print("----------------end of non-ermerg appt-----------------------------") - def do_when_am_treatment(self, person_id, intervention) -> None: """ This function will apply the linear model of recovery based on intervention given @@ -803,15 +731,10 @@ def do_when_am_treatment(self, person_id, intervention) -> None: df = self.sim.population.props p = self.parameters - do_prints = False - if person_id == self.person_of_interest_id: - do_prints = True - print(f"{self.person_of_interest_id=} RECEIVING TX on {self.sim.date=}") - # natural progression or recovery is cancelled with the tx and the outcome is fully driven by tx - self.cancel_future_event(person_id, event_type=Wasting_ProgressionToSevere_Event, do_prints=do_prints) - self.cancel_future_event(person_id, event_type=Wasting_FullRecovery_Event, do_prints=do_prints) - self.cancel_future_event(person_id, event_type=Wasting_RecoveryToMAM_Event, do_prints=do_prints) + self.cancel_future_event(person_id, event_type=Wasting_ProgressionToSevere_Event) + self.cancel_future_event(person_id, event_type=Wasting_FullRecovery_Event) + self.cancel_future_event(person_id, event_type=Wasting_RecoveryToMAM_Event) # Set the date when the treatment is provided: df.at[person_id, 'un_am_tx_start_date'] = self.sim.date @@ -832,10 +755,8 @@ def do_when_am_treatment(self, person_id, intervention) -> None: ) if mam_full_recovery: - # set discharge date and schedule recovery + # set discharge date and schedule recovery for that day df.at[person_id, 'un_am_discharge_date'] = outcome_date - if do_prints: - print(f"scheduled full recovery from MAM with SFP at {df.at[person_id, 'un_am_discharge_date']=}") self.sim.schedule_event( event=Wasting_FullRecovery_Event(module=self, person_id=person_id), date=(df.at[person_id, 'un_am_discharge_date']) @@ -845,9 +766,6 @@ def do_when_am_treatment(self, person_id, intervention) -> None: self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), priority=0, topen=outcome_date) - if do_prints: - print("remained MAM with SFP") - print(f"sent for another SFP on {outcome_date=}") return elif intervention in ['OTP', 'ITC']: @@ -871,9 +789,6 @@ def do_when_am_treatment(self, person_id, intervention) -> None: hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), priority=0, topen=outcome_date ) - if do_prints: - print(f"scheduled full recovery from SAM with {intervention=} at {outcome_date=} and sent for " - "follow-up MAM tx") else: outcome = self.rng.choice(['recovery_to_mam', 'death'], @@ -882,8 +797,6 @@ def do_when_am_treatment(self, person_id, intervention) -> None: self.parameters['prob_death_after_SAMcare'] ]) if outcome == 'death': - if do_prints: - print(f"death due to SAM with {intervention=} at {outcome_date=}") self.sim.schedule_event( event=Wasting_SevereAcuteMalnutritionDeath_Event(module=self, person_id=person_id), date=outcome_date @@ -891,21 +804,17 @@ def do_when_am_treatment(self, person_id, intervention) -> None: df.at[person_id, 'un_sam_death_date'] = outcome_date else: # recovery to MAM and send for treatment for MAM df.at[person_id, 'un_am_discharge_date'] = outcome_date - if do_prints: - print(f"recovery to MAM with {intervention=} scheduled at {outcome_date=} " - "and sent for MAM tx") self.sim.schedule_event(event=Wasting_RecoveryToMAM_Event(module=self, person_id=person_id), date=outcome_date) self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), priority=0, topen=outcome_date) - def cancel_future_event(self, person_id, event_type, do_prints: bool) -> None: + def cancel_future_event(self, person_id, event_type) -> None: """ This function will add dates of recovery and/or progression events that need to be canceled. :param person_id: :param event_type: which event type to cancel - :param do_prints: prints for person_of_interest only """ df = self.sim.population.props @@ -920,60 +829,11 @@ def cancel_future_event(self, person_id, event_type, do_prints: bool) -> None: Wasting_ProgressionToSevere_Event: 'un_progression_to_cancel' } + # add dates of natural history events to be cancelled due to tx, the health outcome will be driven by the tx for date in dates: df.at[person_id, event_type_map[event_type]].append(date) - if do_prints: - print(f"a natural history {event_type=} for " - f"clinical_am={df.at[person_id, 'un_clinical_acute_malnutrition']}, " - f"complications={df.at[person_id, 'un_sam_with_complications']} on {date=}\n" - " is cancelled due to tx, the health outcome will be driven by the tx") - print(f"the {event_type_map[event_type]}: {df.at[person_id, event_type_map[event_type]]}") - else: - if do_prints: - print(f"{event_type=} not scheduled, hence no need to cancel any") - -class PrintPersonPropertiesEventIfUpdated(RegularEvent, PopulationScopeEventMixin): - def __init__(self, module, person_id): - super().__init__(module, frequency=DateOffset(months=1)) - self.person_id = person_id - self.old_person_properties = None - self.old_person_scheduled_events = None - self.old_person_scheduled_hs_events = None - - def apply(self, population): - df = population.props - - print(f"{df.at[self.person_id, 'age_exact_years']=}, {df.at[self.person_id, 'is_alive']=}") - - # new_person_properties = df.loc[self.person_id] - # new_person_scheduled_events = self.sim.find_events_for_person(self.person_id) - # new_person_scheduled_hs_events = self.sim.modules['HealthSystem'].find_events_for_person(self.person_id) - # - # print(f"{self.sim.date=}") - # if self.sim.date == Date(year=2010, month=1, day=1): - # pd.set_option('display.max_columns', None) - # print(f"Properties of person {self.person_id} at initiation:\n {new_person_properties.to_string()}") - # self.old_person_properties = new_person_properties - # print(f"Scheduled events for person {self.person_id}:\n {new_person_scheduled_events}") - # self.old_person_scheduled_events = new_person_scheduled_events - # print(f"HealthSystem events for person {self.person_id}:\n {new_person_scheduled_hs_events}") - # self.old_person_scheduled_hs_events = new_person_scheduled_hs_events - # - # else: - # if not self.old_person_properties.equals(new_person_properties): - # changed_columns = new_person_properties[ - # (new_person_properties != self.old_person_properties) & - # ~(new_person_properties.isna() & self.old_person_properties.isna()) - # ] - # print(f"Properties of person {self.person_id} that have changed:\n {changed_columns.to_string()}") - # self.old_person_properties = new_person_properties - # if self.old_person_scheduled_events != new_person_scheduled_events: - # print(f"Scheduled events for person {self.person_id} changed to:\n {new_person_scheduled_events}") - # self.old_person_scheduled_events = new_person_scheduled_events - # if self.old_person_scheduled_hs_events != new_person_scheduled_hs_events: - # print(f"Scheduled events for person {self.person_id} changed to:\n {new_person_scheduled_hs_events}") - # self.old_person_scheduled_hs_events = new_person_scheduled_hs_events + # else: event_type not scheduled, hence no need to cancel any class Wasting_IncidencePoll(RegularEvent, PopulationScopeEventMixin): """ @@ -999,34 +859,12 @@ def apply(self, population): rng = self.module.rng # # # INCIDENCE OF MODERATE WASTING # # # # # # # # # # # # # # # # # # # # # - if self.module.person_of_interest_born_bool: - print(f"INCIDENCE on {self.sim.date=}") - # Determine who will be onset with wasting among those who - # currently do not have acute malnutrition, are not being treated, and did not recover in the last 14 days + # Determine who will be onset with wasting among those who are alive, under 5, currently do not have acute + # malnutrition, are not being treated, and did not recover in the last 14 days not_am_or_treated_or_recently_recovered =\ df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_clinical_acute_malnutrition == 'well') & (df.un_am_tx_start_date.isna()) & (df.un_am_recovery_date.isna() | (df.un_am_recovery_date < self.sim.date - pd.DateOffset(days=14)))] - if (self.module.person_of_interest_born_bool and - self.module.person_of_interest_id not in not_am_or_treated_or_recently_recovered.index): - print("person of interest cannot become wasted, because ") - if not df.at[self.module.person_of_interest_id, 'is_alive']: - print("is dead") - elif df.at[self.module.person_of_interest_id, 'age_exact_years'] >= 5: - print("is 5+ ys old") - elif not df.at[self.module.person_of_interest_id, 'un_clinical_acute_malnutrition'] == 'well': - print("has acute malnutrition") - elif not pd.isna(df.at[self.module.person_of_interest_id, 'un_am_tx_start_date']): - print("is currently treated") - elif (not pd.isna(df.at[self.module.person_of_interest_id, 'un_am_recovery_date']) and - (df.at[self.module.person_of_interest_id, 'un_am_recovery_date'] >= - self.sim.date - pd.DateOffset(days=14))): - print("recovered in last 14 days") - else: - print(f"{df.at[self.module.person_of_interest_id, 'un_am_recovery_date']=}") - print("smt strange happening - do investigate!") - elif self.module.person_of_interest_born_bool: - print("person of interest can become wasted") incidence_of_wasting_bool = \ self.module.wasting_models.wasting_incidence_lm.predict(not_am_or_treated_or_recently_recovered, rng=rng) @@ -1039,27 +877,13 @@ def apply(self, population): df.loc[mod_wasting_new_cases_idx, 'un_WHZ_category'] = '-3<=WHZ<-2' # ------------------------------------------------------------------------------------------- # Add these incident cases to the tracker - do_prints = False for person_id in mod_wasting_new_cases_idx: age_group = Wasting_IncidencePoll.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') self.module.wasting_incident_case_tracker[age_group]['-3<=WHZ<-2'].append(self.sim.date) - if person_id == self.module.person_of_interest_id: - do_prints = True - print(f"WASTING INCIDENCE on {self.sim.date=}") - print(f"{mod_wasting_new_cases_idx=}, {age_group=}") # Update properties related to clinical acute malnutrition # (MUAC, oedema, clinical state of acute malnutrition and if SAM complications and death; # clear symptoms if not SAM) self.module.clinical_signs_acute_malnutrition(mod_wasting_new_cases_idx) - if do_prints: - print(f"assigned am indicators:\n" - f" {df.at[self.module.person_of_interest_id, 'un_WHZ_category']=}, " - f"{df.at[self.module.person_of_interest_id, 'un_am_nutritional_oedema']=},\n" - f" {df.at[self.module.person_of_interest_id, 'un_am_MUAC_category']=}") - print("am status determined and if SAM, complications and death determined:\n" - f" {df.at[self.module.person_of_interest_id, 'un_clinical_acute_malnutrition']=}, " - f"{df.at[self.module.person_of_interest_id, 'un_sam_with_complications']=},\n" - f" {df.at[self.module.person_of_interest_id, 'un_sam_death_date']=}") # ------------------------------------------------------------------------------------------- outcome_date = self.module.date_of_outcome_for_untreated_wasting(whz_category='-3<=WHZ<-2') @@ -1069,16 +893,12 @@ def apply(self, population): progression_severe_wasting_bool = self.module.wasting_models.severe_wasting_progression_lm.predict( df.loc[mod_wasting_new_cases_idx], rng=rng, squeeze_single_row_output=False ) - if do_prints: - print(f"{outcome_date=},\n {progression_severe_wasting_bool=}") for person_id in mod_wasting_new_cases_idx[progression_severe_wasting_bool]: # schedule severe wasting WHZ < -3 onset after duration of untreated moderate wasting self.sim.schedule_event( event=Wasting_ProgressionToSevere_Event(module=self.module, person_id=person_id), date=outcome_date ) - if person_id == self.module.person_of_interest_id: - print(f"scheduled progression to sev wast at {outcome_date=}") # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # Schedule recovery for those not progressing to severe wasting --------- @@ -1087,20 +907,10 @@ def apply(self, population): # schedule full recovery after duration of moderate wasting self.sim.schedule_event(event=Wasting_FullRecovery_Event( module=self.module, person_id=person_id), date=outcome_date) - if person_id == self.module.person_of_interest_id: - print(f"scheduled natural full recovery at {outcome_date=} as the person has MAM: " - f"{df.at[person_id, 'un_clinical_acute_malnutrition']=}") else: # == SAM # schedule recovery to MAM after duration of moderate wasting self.sim.schedule_event(event=Wasting_RecoveryToMAM_Event( module=self.module, person_id=person_id), date=outcome_date) - if person_id == self.module.person_of_interest_id: - print(f"scheduled recovery to MAM at {outcome_date=} as the person has SAM: " - f"{df.at[person_id, 'un_clinical_acute_malnutrition']=}") - - if self.module.person_of_interest_born_bool: - print("---------------------------------") - class Wasting_ProgressionToSevere_Event(Event, IndividualScopeEventMixin): """ @@ -1116,11 +926,8 @@ def __init__(self, module, person_id): def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe - do_prints = False - if person_id == self.module.person_of_interest_id: - do_prints = True - print(f"PROGRESSION TO SEV WAST on {self.sim.date=}") - + # if person is already dead or not under 5 or not moderately wasted or is currently treated, the progression + # should not happen if ( (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'age_exact_years'] >= 5) or @@ -1128,25 +935,11 @@ def apply(self, person_id): (df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[person_id, 'un_am_tx_start_date'] < self.sim.date) ): - if do_prints: - print("not going through because") - if not df.at[person_id, 'is_alive']: - print("is already dead") - if df.at[person_id, 'age_exact_years'] >= 5: - print(f"is not under 5, {df.at[person_id, 'age_exact_years']=}") - if df.at[person_id, 'un_WHZ_category'] != '-3<=WHZ<-2': - print(f"not moderately wasted, {df.at[person_id, 'un_WHZ_category']=} ") - if (df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[person_id, 'un_am_tx_start_date'] < - self.sim.date): - print("is currently treated") - print("----------------------------------") return + # if natural progression to severe wasting cancelled as person received tx, hence is not happening if self.sim.date in df.at[person_id, 'un_progression_to_cancel']: df.at[person_id, 'un_progression_to_cancel'].remove(self.sim.date) - if do_prints: - print("Natural progression to severe wasting cancelled as person received tx.") - print("----------------------------------") return # # # INCIDENCE OF SEVERE WASTING # # # # # # # # # # # # # # # # # # # # # @@ -1156,22 +949,11 @@ def apply(self, person_id): df.at[person_id, 'un_WHZ_category'] = 'WHZ<-3' # - MUAC, oedema, clinical state of acute malnutrition, complications, death self.module.clinical_signs_acute_malnutrition(person_id) - if do_prints: - print("assigned am indicators:\n" - f" {df.at[self.module.person_of_interest_id, 'un_WHZ_category']=}, " - f"{df.at[self.module.person_of_interest_id, 'un_am_nutritional_oedema']=},\n" - f" {df.at[self.module.person_of_interest_id, 'un_am_MUAC_category']=}") - print("determined am status and if SAM complications and death:\n" - f" {df.at[self.module.person_of_interest_id, 'un_clinical_acute_malnutrition']=}, " - f"{df.at[self.module.person_of_interest_id, 'un_sam_with_complications']=},\n" - f" {df.at[self.module.person_of_interest_id, 'un_sam_death_date']=}") # ------------------------------------------------------------------------------------------- # Add this severe wasting incident case to the tracker age_group = Wasting_IncidencePoll.AGE_GROUPS.get(df.loc[person_id].age_years, '5+y') self.module.wasting_incident_case_tracker[age_group]['WHZ<-3'].append(self.sim.date) - if do_prints: - print(f"{age_group=}") if pd.isnull(df.at[person_id, 'un_sam_death_date']): # # # SEVERE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # # @@ -1179,15 +961,7 @@ def apply(self, person_id): outcome_date = self.module.date_of_outcome_for_untreated_wasting(whz_category='WHZ<-3') self.sim.schedule_event(event=Wasting_RecoveryToMAM_Event( module=self.module, person_id=person_id), date=outcome_date) - if do_prints: - print(f"natural recovery to MAM scheduled on {outcome_date=}") - else: - if do_prints: - print("death due to SAM scheduled earlier") - - if do_prints: - print("---------------------------------------------") - + # else: death due to SAM scheduled earlier, i.e. natural progression class Wasting_SevereAcuteMalnutritionDeath_Event(Event, IndividualScopeEventMixin): """ @@ -1201,16 +975,8 @@ def __init__(self, module, person_id): def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe - do_prints = False - if person_id == self.module.person_of_interest_id: - do_prints = True - print(f"DEATH DUE TO SAM on {self.sim.date=}") - - # The event should not run if the person is not currently alive or doesn't have SAM + # The event should not run if the person already died if not df.at[person_id, 'is_alive']: - if do_prints: - print("not going through as the person is already dead") - print("----------------------------------") return # # Check if this person should still die from SAM and that it should happen now not in the future: @@ -1220,37 +986,24 @@ def apply(self, person_id): not pd.isnull(df.at[person_id, 'un_sam_death_date']) and df.at[person_id, 'un_sam_death_date'] <= self.sim.date ): + # death is assumed only due to SAM assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM',\ f"{person_id=} dying due to SAM while \n{df.at[person_id, 'un_clinical_acute_malnutrition']=}" - if do_prints: - print("death still happening,\n ie recovery date = NaT & not (discharge_date > tx_start_date) " - "& death_date != NaT and is <= sim.date)") # Cause the death to happen immediately df.at[person_id, 'un_sam_death_date'] = self.sim.date self.sim.modules['Demography'].do_death( individual_id=person_id, cause='Severe Acute Malnutrition', originating_module=self.module) - else: - if do_prints: - print("death is not happening because") - if not pd.isnull(df.at[person_id, 'un_am_recovery_date']): - print("the person already recovered and didn't get wasted again since") - if df.at[person_id, 'un_am_discharge_date'] > df.at[person_id, 'un_am_tx_start_date']: - print("discharge_date is set, hence the person should recover due to tx, not to die") - if pd.isnull(df.at[person_id, 'un_sam_death_date']): - print("the death was canceled due to tx") - if df.at[person_id, 'un_sam_death_date'] > self.sim.date: - print("the death was canceled due to tx, but scheduled for later as will die with tx anyway") - - if do_prints: - print(f"{df.at[person_id, 'un_am_recovery_date']=}, {df.at[person_id, 'un_am_discharge_date']=},\n" - f"{df.at[person_id, 'un_am_tx_start_date']=}, {pd.isnull(df.at[person_id, 'un_sam_death_date'])=}") - print("------------------------------------------------------") + # else: + # death is not happening as the person already recovered and didn't get wasted again since, + # or discharge_date is set, hence the person should recover due to tx, or the death was canceled due to tx, + # or the death was canceled due to tx, but scheduled for later as will die with tx anyway class Wasting_FullRecovery_Event(Event, IndividualScopeEventMixin): """ - This event sets acute malnutrition signs back to well state. + This event updates the clinical signs of acute malnutrition for those cases that fully recovered, i.e. person + recovers to well with all properties being set and SAM symptoms removed. """ def __init__(self, module, person_id): @@ -1266,23 +1019,13 @@ def apply(self, person_id): else: recov_how = 'tx' - do_prints = False - if person_id == self.module.person_of_interest_id: - do_prints = True - print(f"FULL RECOVERY {recov_how=} on {self.sim.date=}") - print(f"{df.at[person_id, 'un_am_tx_start_date']=}") - + # if already died, should not recover if not df.at[person_id, 'is_alive']: - if do_prints: - print("not going through, because the person is already dead") - print("----------------------------------") return + # if the natural recovery was cancelled, will not recover now, the outcome will be driven by tx if self.sim.date in df.at[person_id, 'un_full_recov_to_cancel']: df.at[person_id, 'un_full_recov_to_cancel'].remove(self.sim.date) - if do_prints: - print("not going through, because the natural recovery was cancelled, the outcome will be driven by tx") - print("----------------------------------") return # if not well (i.e. NOT already fully recovered with SAM tx, and send here from follow-up MAM tx) @@ -1322,10 +1065,6 @@ def get_min_length(in_recov_how, in_person_id, in_whz): f"when {recov_opt=}.") self.module.wasting_length_tracker[age_group][recov_opt].append(wasted_days) - if do_prints: - print(f"{recov_opt=}, {age_group=}, {wasted_days=} >= min_length= " - f"{get_min_length(recov_how, person_id, whz)} days") - df.at[person_id, 'un_am_recovery_date'] = self.sim.date df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # normal WHZ df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' # well-nourished @@ -1341,13 +1080,10 @@ def get_min_length(in_recov_how, in_person_id, in_whz): person_id=person_id, disease_module=self.module ) - if do_prints: - print("recovered to well with all properties being set and SAM symptoms removed") - print("-------------------------------------------------") - class Wasting_RecoveryToMAM_Event(Event, IndividualScopeEventMixin): """ - This event updates the clinical signs of acute malnutrition for those cases that improved from SAM to MAM. + This event updates the clinical signs of acute malnutrition and removes SAM symptoms for those cases that improved + from SAM to MAM. """ def __init__(self, module, person_id): @@ -1364,27 +1100,13 @@ def apply(self, person_id): else: recov_how = 'tx' - do_prints = False - if person_id == self.module.person_of_interest_id: - do_prints = True - print(f"RECOVERY TO MAM {recov_how=} on {self.sim.date=}") - # if died or recovered in between, should not update to MAM if (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM'): - if do_prints: - print("not going through because") - if not df.at[person_id, 'is_alive']: - print("is already dead") - if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': - print(f"not having SAM, {df.at[person_id, 'un_clinical_acute_malnutrition']=}") - print("----------------------------------") return + # if the natural recovery was cancelled, will not recover to MAM now, the outcome will be driven by tx if self.sim.date in df.at[person_id, 'un_recov_to_mam_to_cancel']: df.at[person_id, 'un_recov_to_mam_to_cancel'].remove(self.sim.date) - if do_prints: - print("not going through, because the natural recovery was cancelled, the outcome will be driven by tx") - print("----------------------------------") return # For cases with normal WHZ and other acute malnutrition signs: @@ -1430,10 +1152,6 @@ def get_min_length(in_recov_how, in_person_id, in_whz): df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' - if do_prints: - print(f"{recov_opt=}, {age_group=}, {wasted_days=} >= min_length= " - f"{get_min_length(recov_how, person_id, whz)} days") - if mam_classification == 'mam_by_muac_and_whz': df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' df.at[person_id, 'un_am_MUAC_category'] = '[115-125)mm' @@ -1456,27 +1174,16 @@ def get_min_length(in_recov_how, in_person_id, in_whz): person_id=person_id, disease_module=self.module ) - if do_prints: - print(f"wast indicators updated to {df.at[person_id, 'un_WHZ_category']=}," - f"{df.at[person_id, 'un_am_MUAC_category']=}, and no oedema => MAM") - outcome_date = self.module.date_of_outcome_for_untreated_wasting(whz_category='-3<=WHZ<-2') progression_severe_wasting_bool = self.module.wasting_models.severe_wasting_progression_lm.predict( df.loc[[person_id]], rng=rng ) + # natural history (if not treated) if df.at[person_id, 'un_WHZ_category'] == '-3<=WHZ<-2' and progression_severe_wasting_bool: self.sim.schedule_event(Wasting_ProgressionToSevere_Event(self.module, person_id), outcome_date) - if do_prints: - print("the person will progress to severe wasting if not treated") else: self.sim.schedule_event(Wasting_FullRecovery_Event(self.module, person_id), outcome_date) - if do_prints: - print("the person will naturally fully recover if not treated") - - if do_prints: - print("------------------------------------------------") - class Wasting_InitiateGrowthMonitoring(Event, PopulationScopeEventMixin): # TODO: maybe will be updated to integrate monitoring of < 1y old in epi module, and on birth schedule to be @@ -1573,11 +1280,6 @@ def apply(self, person_id, squeeze_factor): rng = self.module.rng p = self.module.parameters - do_prints = False - if person_id == self.module.person_of_interest_id: - do_prints = True - print(f"GROWTH MONITORING on {self.sim.date=}") - # TODO: Will they be monitored during the treatment? Can we assume, that after the treatment they will be # always properly checked (all measurements and oedema checked), or should be the assumed "treatment outcome" # be also based on equipment availability and probability of checking oedema? Maybe they should be sent for @@ -1587,16 +1289,11 @@ def apply(self, person_id, squeeze_factor): # a child 2-5 old, if they were sent for treatment via growth monitoring, they will be on tx for adequate nmb # of weeks, but next monitoring will be done in ~5 months after the treatment. - Or we could schedule for the # treated children a monitoring sooner after the treatment. + # no + # if person already dead or not under 5, the growth monitoring is no performed if (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'age_exact_years'] >= 5): # or # df.at[person_id, 'un_am_treatment_type'].isin(['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']): - if do_prints: - print("not going through and no more monitoring scheduled because") - if not df.at[person_id, 'is_alive']: - print("already dead") - if df.at[person_id, 'age_exact_years'] >= 5: - print("not under 5") - print("----------------------------------") return def schedule_next_monitoring(): @@ -1610,22 +1307,15 @@ def get_monitoring_frequency_days(age): return p['growth_monitoring_frequency_days_agecat'][2] person_monitoring_frequency = get_monitoring_frequency_days(df.at[person_id, 'age_exact_years']) - if do_prints: - print(f"{df.at[person_id, 'age_exact_years']=}, {person_monitoring_frequency=}") if (df.at[person_id, 'age_exact_years'] + (person_monitoring_frequency / 365.25)) < 5: # schedule next growth monitoring - if do_prints: - print("next growth monitoring scheduled at " - f"{(self.sim.date + pd.DateOffset(days=person_monitoring_frequency))=}") self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_GrowthMonitoring(module=self.module, person_id=person_id), topen=self.sim.date + pd.DateOffset(days=person_monitoring_frequency), tclose=None, priority=2 ) - else: - if do_prints: - print("no more growth monitoring scheduled as the age will be above 5") + # else: no more growth monitoring scheduled as the age will be above 5 at the time # TODO: as stated above, for now we schedule next monitoring for all children, even those sent for treatment schedule_next_monitoring() @@ -1634,9 +1324,6 @@ def get_monitoring_frequency_days(age): # TODO: later could be scheduled for monitoring within the tx to use the resources if (df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[person_id, 'un_am_tx_start_date'] < self.sim.date): - if do_prints: - print("not going through because is currently treated") - print("-----------------------------------------") return # or if HSI was already scheduled due to care-seeking, no need to attend the growth monitoring hsi_event_scheduled = [ @@ -1647,14 +1334,10 @@ def get_monitoring_frequency_days(age): HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM)) ] if hsi_event_scheduled: - if do_prints: - print(f"not going through because {hsi_event_scheduled=} via care-seeking") return + # the person may not attend the appt if not self.attendance: - if do_prints: - print("does not attend to this growth monitoring appt") - print("-----------------------------------------") return available_equipment = [] @@ -1663,8 +1346,6 @@ def get_monitoring_frequency_days(age): if available: available_equipment.append(equip) self.add_equipment(set(available_equipment)) - if do_prints: - print(f"{available_equipment=}") def schedule_tx_by_diagnosis(hsi_event): self.sim.modules['HealthSystem'].schedule_hsi_event( @@ -1675,34 +1356,28 @@ def schedule_tx_by_diagnosis(hsi_event): complications = df.at[person_id, 'un_sam_with_complications'] # DIAGNOSIS - # in future this is the place where misdiagnosing will be happening (but should be happening also in the generic - # first appt), however current asserts are made for the case when all equip available, hence they will need to - # be adjusted, see issue #1612 + # in future this is the place where misdiagnosing due to equipment unavailability will be happening (but should + # be happening also in the generic first appt), however current asserts are made for the case when all equip is + # available, hence they will need to be adjusted, see issue #1612 # oedema is assumed to be quite obvious if present # in addition, based on performed measurements (depending on what equipment is available) + + # for now, perfect diagnosing is assumed diagnosis = df.at[person_id, 'un_clinical_acute_malnutrition'] + # No intervention if diagnosed as well if diagnosis == 'well': - if do_prints: - print("diagnosed as being well, hence ntg else going on") - print("---------------------------------") return + # SFP intervention if diagnosed as MAM elif diagnosis == 'MAM': - if do_prints: - print("MAM diagnosed, send for SFP") - schedule_tx_by_diagnosis(HSI_Wasting_SupplementaryFeedingProgramme_MAM) + schedule_tx_by_diagnosis(HSI_Wasting_SupplementaryFeedingProgramme_MAM) elif (diagnosis == 'SAM') and (not complications): - if do_prints: - print("SAM w\out complications diagnosed, send for OTP") + # OTP intervention if diagnosed as uncomplicated SAM schedule_tx_by_diagnosis(HSI_Wasting_OutpatientTherapeuticProgramme_SAM) else: # (diagnosis == 'SAM') and complications: - if do_prints: - print("SAM w\ complications diagnosed, send for ITC") + # ITC intervention if diagnosed as complicated SAM schedule_tx_by_diagnosis(HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM) - if do_prints: - print("-------------------------------------------") - def did_not_run(self): logger.debug(key="HSI_Wasting_GrowthMonitoring", data="HSI_Wasting_GrowthMonitoring: did not run" @@ -1733,17 +1408,9 @@ def apply(self, person_id, squeeze_factor): assert isinstance(self.module, Wasting) df = self.sim.population.props - # p = self.module.parameters - - do_prints = False - if person_id == self.module.person_of_interest_id: - do_prints = True - print(f"SFP APPT on {self.sim.date=}") + # no treatment if already dead if not df.at[person_id, 'is_alive']: - if do_prints: - print("is dead, hence not going through") - print("------------------------------") return # Do here whatever happens to an individual during the admission for the treatment @@ -1756,19 +1423,10 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data='consumables are available') # Record that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'CSB++' - if do_prints: - print("consumables available") self.module.do_when_am_treatment(person_id, intervention='SFP') else: logger.debug(key='debug', data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") - if do_prints: - print("consumables not available, SFP tx not scheduled, should be picked up with next\n" - "growth monitoring or non-emergency appt if this is not follow-up tx,\n" - "or if not naturally recovered in between") - - if do_prints: - print("-----------------------------------------------") def did_not_run(self): logger.debug(key='debug', data=f'{self.TREATMENT_ID}: did not run') @@ -1800,15 +1458,8 @@ def apply(self, person_id, squeeze_factor): df = self.sim.population.props # p = self.module.parameters - do_prints = False - if person_id == self.module.person_of_interest_id: - do_prints = True - print(f"OTP APPT on {self.sim.date=}") - + # no treatment if already dead if not df.at[person_id, 'is_alive']: - if do_prints: - print("dead already, appt not going through") - print("---------------------------------") return # Do here whatever happens to an individual during the admission for the treatment @@ -1823,19 +1474,10 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data='consumables are available.') # Record that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' - if do_prints: - print("consumables available") self.module.do_when_am_treatment(person_id, intervention='OTP') else: logger.debug(key='debug', data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") - if do_prints: - print("consumables not available, OTP tx not scheduled, should be picked up with next\n" - "growth monitoring or non-emergency appt if not naturally recovered or died in\n" - "between") - - if do_prints: - print("-----------------------------------------------") def did_not_run(self): logger.debug(key='debug', data=f'{self.TREATMENT_ID}: did not run') @@ -1861,18 +1503,9 @@ def apply(self, person_id, squeeze_factor): assert isinstance(self.module, Wasting) df = self.sim.population.props - # p = self.module.parameters - - do_prints = False - if person_id == self.module.person_of_interest_id: - do_prints = True - print(f"ITC APPT on {self.sim.date=}") - # Stop the person from dying of acute malnutrition (if they were going to die) + # no treatment if already dead if not df.at[person_id, 'is_alive']: - if do_prints: - print("not going through because is already dead") - print("----------------------------------") return # Do here whatever happens to an individual during the admission for the treatment @@ -1887,19 +1520,10 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data='consumables available, so use it.') # Record that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'inpatient_care' - if do_prints: - print("consumables available") self.module.do_when_am_treatment(person_id, intervention='ITC') else: logger.debug(key='debug', data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") - if do_prints: - print("consumables not available, ITC tx not scheduled, should be picked up with next\n" - "growth monitoring or non-emergency appt if not naturally recovered or died in\n" - "between") - - if do_prints: - print("-----------------------------------------------") def did_not_run(self): logger.debug(key='debug', data=f'{self.TREATMENT_ID}: did not run') From e87a282db46afad6ae2df22d92c1e35d20a9c90f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 1 May 2025 19:10:12 +0100 Subject: [PATCH 448/755] find_pars_draw_nmb: PEP8 --- src/scripts/wasting_analyses/find_pars_draw_nmb.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/scripts/wasting_analyses/find_pars_draw_nmb.py b/src/scripts/wasting_analyses/find_pars_draw_nmb.py index ea2c84d841..1f26191548 100644 --- a/src/scripts/wasting_analyses/find_pars_draw_nmb.py +++ b/src/scripts/wasting_analyses/find_pars_draw_nmb.py @@ -2,6 +2,7 @@ This will print out the draw number for which searched parameters set was used ''' import itertools + # update the parameters set for the job parameters = { "base_death_rate_untreated_sam": [0.1, 0.05, 0.03, 0.01], From 865fe0981a61635242905971e1f975bcee8f3fd6 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 1 May 2025 19:11:48 +0100 Subject: [PATCH 449/755] analysis_wast: numb of draws as input par --- src/scripts/wasting_analyses/analysis_wasting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/analysis_wasting.py index fe20014fed..b2d5e495e9 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/analysis_wasting.py @@ -25,6 +25,7 @@ outputs_path = Path("./outputs/sejjej5@ucl.ac.uk/wasting") legend_fontsize = 12 title_fontsize = 16 +total_draws = 1 #= len(folders) ######################################################################################################################## def create_calib_outcome_csv(sim_results_folder_path_str): @@ -819,7 +820,7 @@ def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): # Analyse each draw # for now, we always have just one run, run 0 run_nmb = 0 - for draw_nmb in range(0, len(folders)): + for draw_nmb in range(0, total_draws): print(f"Analysing {draw_nmb=} ...") time_start = time.time() From eed91d2e01404b67a06060803b799ea63e14858d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 7 May 2025 01:41:42 +0100 Subject: [PATCH 450/755] write-ups: Stunting & Wasting instead of ChildhoodUndernutrition --- docs/write-ups/ChildhoodUndernutrition.docx | 3 --- docs/write-ups/Stunting.doc | Bin 0 -> 801165 bytes docs/write-ups/Wasting.doc | Bin 0 -> 360099 bytes 3 files changed, 3 deletions(-) delete mode 100644 docs/write-ups/ChildhoodUndernutrition.docx create mode 100644 docs/write-ups/Stunting.doc create mode 100644 docs/write-ups/Wasting.doc diff --git a/docs/write-ups/ChildhoodUndernutrition.docx b/docs/write-ups/ChildhoodUndernutrition.docx deleted file mode 100644 index 43a6e5c3d0..0000000000 --- a/docs/write-ups/ChildhoodUndernutrition.docx +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:409f98f9e6f045cc349f37366c44024eea3c2af30d555004f71e1d7629bcd5e1 -size 949266 diff --git a/docs/write-ups/Stunting.doc b/docs/write-ups/Stunting.doc new file mode 100644 index 0000000000000000000000000000000000000000..99534a537441fcb10d857a6dc8ca9e4b08173340 GIT binary patch literal 801165 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

vogm7M-=8t1{bt_{!(p7c2kL4v#4zu%UrhAU56y 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 a_fO611$~jY{Bk0j&#}B)!~n2X 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%0DU4WD+?WQatTem@qPU1ChCV^ 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�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

+|O@6HFZm-k$g+ve*J$8#5D+DnZ}|vV|LSD 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

9-=W6nnHykDihX|eeyc-8RZEje`#?={rg z8VpPZ%CD)Zx4e<1d!dL$d)3A+q^b1KNiMljI^43^l=$%_Ya#+Yk~zn$>p}|cbr{a#vW(T(fRGxc`j{Q zH)Vj8xOd_{gx3uW$sJ>BR|CBSa61#CCayRqN?W$wk;azjmRu!fn>^%XP|Z9ueF+9`k{}=Kdd_@sheD+W7E68%f!*o^i`Kc5mLsn*t;4|L_po zh9Lvde1M*UxmJE_C~D`TJ9b6OofCV&2O2?9XPKH+O_XX!=<$ue0seX|)!0Q9JZN14 z!IiNXmG*CaM6RVxZL3#zOF>XAQh|-Em#eX=Dlk%)#VXWO-CHFn@z9^;ahppSaocZ*ng@xZ764Ru?N`&2GOHd-_VvLcus@No^rk5 zfLvT-U6yYf=yH-)|6wc?_+<-n>wzXDgaf`l|Dl6aCr^D&2{(+b8sm{IkoA_YVM}oi z2PK%RxKpN1gTn(&ixml*$GnlWWA~8e?mnJEPe6DQ43!93aXT~jd3qky+9lx5FpXsJ z$zxl!g+eWJq!?RX7Gp6YhNdK;?=Vl`2Zk;F^20Rs25f-5KnaAkuT()sr*PzzH4I6> zi}VF~-M&HabRx07;JrU42X*w zD%G+Uj}wDI(}=)IGyM4W2ae8Kv})UmyNA zBX`u%!GH4L$<{|6@*4^nVZ{h;iw0hf@vuJsMz54d6BR-yHN0&5>~dMN$}R{cjUZut zmvoj-yVR%Q0CafH|2C0Aia=>LAuvC>JMB(6DCSXQEUM@C_{kyj)w=o^E# zv6WD$?>2J&QI`mwa|j+Knm#tp(GMh&Px;tWZ6abNDxy^Gq#0kNdRc1;nrxyMJI#0D znwcM0;`fxPC{xzz3^6{bf~~ltQr0QaG`+P1=G;Zi=AAJWYAEEHc`9sGa18H%+_cOT z#l{CGDbp!7ohg&#PGD|X-}n)^KDRLbHI0FnuujV(+qeY}@#(auwX(%gY&$7u#V=4v zi`)A{E60C8vyT!l=qZjdNVHZYVw;89R-1YCi7Hqi0 zx@{`Ueze6uF#Du0UnB_!DZfS`3CQqtG|8R)RMTYeD53GSOkW6gch;N=F3r4=Dpx%9 ztCmA$C!v<8aCSVX$xS?3EtKOJCX88*v$35Hl^N~N4wR-4^UP{#<)vU6Y}ouKY`(koG$LZ;cS5D z>_F|jI6~%$2jhvDE^2pYF;`PX)@mRG7#2_K15=CKc!J%)vUykTRC0SKJb{nn zj3dnESUFQGQa#Ol^r6_E_}Ap8uqL z_Z_OYB_D5oy#~eHC~6G)RPTa7pHR02(3K=<$*A6nX!R2zI?~eb9e6P=&l2hU;ePqm zm56w2?8T}3M{b_EBObV4@odqS2Fz=I)_C;;?rqJidGT)aRU8AozB|!ry-@JBGfsHB zf;V>-@98?Hn;m$0dzxpj%urZo_Zp({3yzN6S4HG{|NaxyJW+T>xHx2WLgSTMo_)Bd z-1vcXPyULsCA&P+=tRIelZBe+JHvi2=Mld=r*D&M>y8I3xq5Ey@W0B%IKFBK=_U6!dkAjD-Wh%S zeD?z1DSd}>?l8QHSD(r{J=GPw+JBX;x$~a-z%nIG3b_(0h zie(bZqLqZti|EeEWfHwcf)dNYqrT(|!2b$1sKF%uF3>5^OriD<*x4s@Xnre~gvA*o za;Qe38xE*3%0^+J3s6q`URGRRJ)M-RIjgxnRZ zm3JE;Rv<@*15#k1A5xT@mS;J_(3))7v-@^w{YBgC*^-f$23O+YFtM&L%S0=x54L* zR2Dqr9TG*g(w=3Kb<=+re;p0BjT>IyALE^br-cqPAOTd5l+l;-j2Z9LDlPJ z>$OZi>A349b3a@eh3QZK;=Y}oEbcZ*gS>;$vw5>Ae?(wDUQlbwgIhyB6w2723b#YAb=v%UBu?Db|)A75B zM-h=yT|+dS8u)Oqw~gU1(XBDOJs$Bi!fmD=ALg_C}tYg^qwQPCKJP@r6o z*BM3*#VGH>PY{%z!sDtj)KH9K{P4822#Dl4K0w<{-}aNYZfqXHsFa{YT3Q;&`a^R^ z!@1x7t&gUxI3%0YQ5ylOOQ^zFw5p2}fmU@3xhvO+vFP!BXfE1V0tG&)iBFPT7H_f2 zC>~Y2gtHBocqS;gSc_t|_I*7pyWB(a(3FwXq(@zm32$f7VcDi)eZEDRd$EQE`l2Rw zMVZE`3-6`ZmM#@QpoLJc4X8`3#NT&~QI)SH{YyS=!oQhLl`rk;-PZopG`EoA@hLhj*yRg4y zD{fVegXg>{He*s`Zt7xgzZ*mB@!|19dxyD@B+##Glaz=}lA^2MH{!MqnfR$?_ zTQA2>>&b^k)@C8=w{j0dCGRuhl~mXj%ryfb|G7P8LnXCQf{}?DtHiH*T4kBrGa1;0 zh)D0$7iCWx)}%k4;%www#fZrat47z2N(H>eAhOnf%C`62HrirP=s7XBxEpUeQCK|1 z)WvoLyvav~l^9BC**LbM&{AvFZ1S*htcF5TYx7JhN21W02SZZVL-ujr#WE+bQk+|6`{962P9s`kq29Jw-YON+hQL*PIzg_WwVoV0KHv;*Ofm z11p0cOb$rZ`LDBJf|$PamPs_xf3v(|B_SF0kn}ouR%0v+Mg0F}bWD^OX&1Ci?x<-z z5z_b~(VfI)&-?P$TjeFYw+=E+`0?Saz9n=y7V z!~iU2YqxDeW)-s`sEk@76RT1zY9_-$sIR8lxE$MCrnOkxRe`RRbgy~r+ew#$43{_p zOZ`gYL6KXDgj@*8DACcPY%a1n3Jrnex;AY7EKprn%GQr;J3p@DuPaV$WmW_Gm`D`$ zWDiSuw$Ej^bh7cXD~2QVVwobNUlK`mCZ{3$3=i_QeNCk`3?4tbl^t}w8aP+I^51N` z_vK1Zt(m4Z^Pzpw+S(tsjz2MTFjI7ch2X9$M#@W1Ji^{J?ny<^5G#_YISXX0u?2MT z-;3&`sDAY4u8BK!$gUNx55l9X$oKB%~F1HeUNV*KC`}!7h0|Y*K^2kbpNi? z2HNLex(O}!GkiLYFz{($@S@_0X5HU?MXdEUvAw_gu8Khcs)uj1&)*NeP!uX`nCc@0MH66&>_oSii9SC82SnzA4^Y@;+1eB-M#;egNP5#9S&`#|W~ zv4mnuv7=;Nx`cfD=kAKH$S{?XkNxGGlP_AJE>|_mjx||DE0KW~d&U<^ zCrY8FZ^RRQ_gKy~Fu@+}gTGDZJ$-Z9KGFA~^{E?Q8LZ1W{hbi^K~yjP>r6~u7Xs&@ zgeU%sG1o7XB{f2i(v-NcykvszL7FqGnAm7eItY;kjwtew&}g0~DCX4N0WnDd&AFIR zTgKarbun-VJE-0aoLAa(Ud6*-(hMm8pm9v1A-FZ?ifVAERDNJJl~>Wqel+XsaD~4y z#OzL9wIlb8(w4=4G;LmG2ZO;HHkHp@g>nl{a3+#HQm_?4WbniKr$~O-<7~a3}b+!Zdj@W=~#4k?;-F+CF&@L|E9IkREZ^$TQ-;4JsA` zfy6bH!HIH^Pke4_sQDq{6svZ`6UddnAsPu^}?BONi0E1q`E3BXNCtB8w zNj)@YZjkxi0Y3o2=r60lW?xxtBc3&XOdMm zFCkJ(Oj1iqYB2{1kh$QW9gYPzG-F_)yBI1vCs$aJiLc8*HD)gxv(XxptV>FAQX;8L zsEe8!V``(w7*SrDQC1gXH%8cC94lX74=rR3GRG>^kX0oV(Fjpi56Q3*snLgD5~AXS zy{Jjr`qMNyW^h@wB_wFhE^EvlK4uf2xKT*aE}`tQr?|(exgyzw4b0Lb2tUpvRg-9{ zi>I?VKcpHzE~hETsEfMH44pk!DQGRI3&&+mPgpdQRVm=qe$WcRo;)f4Vp=eh{ae5( z6MZPXSb(QAZCsXpmMiL5d|Eg4%g>Ny}0r>X;FPg1^0yQ-eN``U* zs&)jq*+=8QUr?e=pKeDxy;OYtZ;ZM`gGPu&MKcD$w!O6A@Di)>wy{=085P&aip`-1 z!EmRclg*$d!pvt=2I7yUsFs4%Pz?6++k@EKqVD(w6JgD*)A#q)S+y4^C#Q zV{@se7h-ZvR2jJZ_w;c!3*Lg6+j1(Y#EOSXaD~VI6ygfQvVH?1eshX`41aavBB?XZsL>7;*88nkwKArV_NR`nAu=(kLAG7{n zfS$@Rz}=9-YlHayA??~CgoF?BZrq}fKgf;bnxO{m1pv0@Hw@zLduXr6T?76Ph6j`f z2HO|R1yl}HuHcfnr@qH#J15s0(`-)*a%ysW9exUKk3-ep5$!*~%)uV`e}+3jJDnd> zaJ}w%qgc#hEO8!z4p=pq*I)+%kn%9keq=q0JxEHR{$^+%OvsKlTpC1{Pk_rItMyRP zJq~p09Qz(OJz@qF4)xOtg)j3NcPKaXe+chb=Ja6np!DEC5FpqWcn1^4%^|1H{3U$E$f^s7WvgO=;?8K4$R+dJo|NS|XA`q|Z!h6%sV5Mpn4P&Z_~Y8BPHswns61VAP--Gu~=pC921b{7)95 z3B~_H_Wv-Fzb<{R(|}qaOOg45Ku@LB-D@IAL!Q& zt_%JJ(&aC9?>J;`nhO^T=LFdXx&g{Q1AYv14+a%*8D$1jeLHy#5nAES6R^VaUj}x? zgs@j`O^#Q6-?27RFYl2ZOucVaI5~J@bktY!=Ll*HPkgOxM2Bw8vUqp~~?1Muqu#LU+br@PgX70_t1qydnun881A91@n zbUEtUpig-FdFBnmoSrHi8COHF5t(hYiEFdZ;?QT9d{|U0umD@Xa*st!PAvVS^n>;d z>TU4R;m!Qf<`GeV%4hU3>EiENXj8KvaN&k+O)|*u!SD=j>9=*WIu5d~ZRfg%^+i+z zOIoB`qp}*J`lp5a;#|2`?SKG;N&Gbst{bWO9b{tE}DE^d~e`HU;2}+tv zmG=!M_hYJ&OZxb+W0H1+b5T=)7sPPWL(2L#4Z_mVn_&-f>uDVH9_)+;w21=MW@M!V zs3bLW>0x`QdR+45DvrSI^xX(V5ty{KfOYi!1_5GqA5;c#Q?@&+^6Y$-;A9up%Hfo_ z#70}CaZ%ysjH>zuYLb~DbViU`nvq#F+N+3USCLb*Sq#n(fB#ukVaAyLI3KpTVQ>`W zoTxn-Jwyf!3XxSF+@n1=pL?cS1}>a+kJEb*KDU2F3cO~jf)y2U^YD{4fle7SeM*TZ zKL%2oQ<+ey)u9FA|IDO;uT}>&Q7crSH(JCoV{<+gXanWt>^K9Gtpugm!VzajiQ!Nk z3L<+Rd_d)3v@~}$erq;qWI|>lm`^GE(uSk8MmZw3=7~YE&kWi#(u3XoYo8gj2ajtC zb_7b+Lz9boa%Y!GpdHN@enh-Rcwt0NngbI)9WdaG`9^oq)7{uo--tBu16OQ^13wm> z18X?VuVKKQL(&rUUFM#b50>A5a!Y&r5uv)67{Oq?~{Hl#__kkyx39_f7Wg}Y}fzkBEEk9K4=Sf_Fy*uQ;m#Kh7A z_Sy(v=;6RwBnnU#qfYJjF z|H9)n6&$En+pe$jpqk=N@f$s^N6PO%VhR{f@Y!`$VmJ z!8QJ+V2EZ>DQJ0K+6YU=emlGX!@@4u1!ZRqvJB;LJDGcjc+I%~B78DY2;O-WFyy+! zC6C*w@*#SC7VtYQZ0jcV>rEb}BZI0CB0s!l4<~xok%VSnl+{5k$tnGy!VX?f#x=k0 zmiI9x6$3&7k=Gtq=vy4-gD>Ot23LMS)o}MHY|70#A7jdC&|`EY7^F3oW~kQZLnFLZ_U`zCNtRvWlR$%ggxXM z_oT(W%Tpm~C5xm<7DXvV%h5i*Yl<2aqhS)37Hf?raa(+YndscVqb6BS<#qNb3nqVm zojobLnR%~YRq;pYVqoZ=ASJ(;4+4D4F1q<^-sLC{xr+-|$p9*MReu%d#*@i3bQ^4H zW6(nf;S35&(QjA&Hd!RR1N^NfMbeDWXc7aL$OzTkIBi*Do=(NgW-9vu@=$<$j2%~6 z(8ewgc*?M5DRzq6q=-4$y%rIEMGR)&qPXt45nc2B@hb!P+`pwbq_PLpQHm)Qh6(mv zgB;y*{3Ud+oQEN7rzvIc!%=%oA3q{SmB2YMdQq}q%*A^7Y5gX6%b0a7?Aivl8~SqP zOJdfd-f2ZYy+uEnNV-*~LrGJPi(bTRCi44WF6@e{x)U@8LGc`nKQeeDZ$vdKKK-Zz7-RiYLOS$>L%< z6%9_xFBuCFvVt>r?7&5R|NXR{wOsIk|u zcdT8RJwCL2492}`KGzPZf}E2Po$WC(f+xE;yf`T+XT$8!UUqbS(~75`CPTFZ>it=& zU_)r-m8&pSHdi?#$rg*FnxW5KSKLroHAJVq!e7vHBz#qUMwxaoC#xj8DptG?5uV)p z)RIDwi>kJRLV>dvUpX}EAQS@sLf()@eZ;52`vGG5PA@M7{ezYH2$OsS1O(m?6hvMM z90C>O$B!Q%GZvESAph+^`}SRJ9gOIm%#5v#{|g!E+^nrG)MX-Z*fF~>UI{{4x$k(J zQrrT0n-W}H6Jj?C_bH}Fn8z$cMdMwUg9IdGJ5gcHPxAaXJt&I&p|Cwp0P5mq^8^Z$ zQT!}TAdGx&)4Kt`wl!LYllQW=L8w&pI5s4cT z749v&&M@d_li3mn9dn`uFSGMB(~2gV0a%-K9x`ZZ!_FQSbI}(wR8W+6 z=25++{n{+`mC^FYaU1Eqs2dEVPd;j4wa25=1$Z@C`>V7=>G_iVEk?Ol>N5+$Yk9mI zt)srL9p`z6L2XbTEGZ?Mm|TY2j@r#O_=){mrhd&e1I-Iml3^@{eWv(`yVsyWY9w{r zQqpbBF;vDAQ8y3X+$HG|3z%U^*&=o<4-&Bt7Q+-hO>PG-=nn@XN)plFjr!YQS4KcI zwUo`;(Tr=C{i|(I85y|-+}}uBCD^Kf>ZqVLHXr8dI0p{c2H}45{_@gqdW7W5?|Xmz zz5~4LV!x>Nr%Arh`M96tm+M;i{Ja=e1#~O#rA7I^jH}XrJ>NNBx(6@0%IWfXzV5yO zzg}Nz!8VKZNWW(p*fbZsY>Q@bDyY(9keK6kbzCx#QS=QO6GHITXfWPw2}o~mCWXe(r zk!c@yf@zSCKs=H4Uq_5sz{ z7WIYI{fSO?GdQg4d1o|O;`MQ`Ln_XJwd%Wr-$uIyT#)2`=gfsbx;{gmCJ9jYq0saN zsMBuFZl+(N_Ga7P^VlJ;;%x^Y4~2S#?C?=1W`*yF2q~ze!WJA<^^qc{++9+&qz3G2 z6a@MDyE&x#g&z-5d4#R3J5Myg=o{G1SbAf4jEs71M{ zTe7XT=}*3lRGcsZ)7iPdkPy#Omf(Q>C3AEku6Ed@)__K%vGhLxb3ly0>sT04R>b<# zK>lFEb4x~Iz5xuQJWr+lBD-79bX_p3!?qQ}Yr9*^bcKX8-Kr#{X_$Zru2*k4*X_1C z)wYsGvvm=*SHG?n8|5r3*EP6N(X+$_6kez@e?=7$$KV?D`mJcc2!saX|8Tj@mE`kvst zK&FE9VG^BcBRr+IfC!Y=wDJH(i1B4KBSfXiy^7+RT+Nqa<*C_fi2^)Hz9L2+J?7D9@S`*Eh4WwDCVi&i`ORO9izk$(^h|GQ89=4r!&u_Gy?y%wZ zd#y%0@OzEEA2j>Je&Ds*!w0%{Qh?pA6S)4M)$pw#Xt=(a({HsKP1m-&ZnN7OxZMZy zSc{P_{ukjbc@6aWYa2msJ(N?8B^0000000000 z000#L004Jya%3-UWn^h#FKKOIXJs)iaBgSpyJb*iG1o3gH_|vX?(XjH?(RR>Q`R|J|3O*kM1SEutf`;Vh=jYVaRB>_f{r&yW(2%aK?!v;t z_V#vgaBxym(%IP=4i3)0CXSAd5)u+jOiZt@ug%TP=;-J$Ffiog*?FtIu-LaRMqlq&kXA7Q3GmX!eV z`7hFPa~yhHn1cusZ|Uz?NRYyma6|3{O}4n}K|~P$fBOGKI_fPip&mX#3I@HV>W ze*S%-<9X}_QesOrj|=-^$&xtIFiI|;`bB=ZB2~Xu{!nmV!NOmZfE zu}jTcrH6Cm&huiOv0FL&;pKCH8Rfc7!V$VYPi=+-1!&Yu@F`o>mz4|@hs?ld=#Euu zTd$M-84}3<69`>8b{CTiPlOPNIp_WDoRi~lBF5?|&%M$~t;u4s3E+rZwA|86Tv*N2 z#a;I5>9w5Xots6#JMYz-2Vs4CoORW$SbME`4fm;-1W85C0Fe#-C}8_r;F~H4{Ab+7 z`1z(%+LEFh8I}GKq31+S(xvZF+9;d`?8jQ;j!4kXArT-Ocn6h#@%AQ%N#otPLA zcgLj@M2PBxF468Zm}Z|U69MD98-%oBuevr|7wodjOo#C{vAc#!f=Jh%piR}%>EyPt ztR(orQgEHdK?w);$%o?qD{Hvvhv+I#!8(*fU+R?0lJi(4q@Ke*V$UAii&0 z&2=))yis+ux&)T^`;oWl=O;aCcTgPV+WW0V^`qmDw6C*1VMX`f^0KD)l}WWw+ihB` z1nqwVCNemgZj@i~n7P9WW8lt$1zNUr8 zbf|IzQWuvcD4bwX!`fcSt*@#euRp6y3goFST~C(&6yv;vKLcbyhJ?!>BR^ex@sa4q z8!RdrJJ?JgmdZRVd;gLm&~ww=dj2a*nyPL#$mT7X82LE!^7oi%rkCdX7uJP5T*UTi+yzapV^?Xg~T5^|W z#gS<_b@e4`7oJs&%eDrtx+6uML}TZ_T4Ha#Z#)VrPe#d;5ps<0j68G{=i=b}?r+<^ z*F7M@rH$Isy=F2}1+)G~?l(akfv*%l@P_IDJn)n;dsM>Qr8HhhOh|X*Be6K)Xi_do zd0FcIKPx9p2WnqQb^nwN$NpC(1}}3onVUZ<12m4eZg(B7+qO%7EE|h7B{khRp=gDh zdBLj=KRG-Jt53?O{t9=jGBzeG?s^>dWKVrc%rLn=8t>I5j}7`*vxh} z4cklrmwH`vKi)wLG6zITYM@>p)ej)3LFS;E9f)1IXXNM+8(Ubx_n(nx|JaG`-kdhpoU z-X-qxV{NFpSKw!u(ttSL^y|56B2vOEEM!amPZrI+m_uzhc#M%!qNj(BUhdlQw@NX3 z79sC1{R<{}Cb5wudI>-sRCHnb{7bCk6v$b%s}9}`cb56t1*53}LTIYnuQ9+3mqavV z4cy2PxZ1H;?Q$pd%IOJ4)v5$^%l^`W<^}jgsB1m$eo;DSer5~$swx9mx8Kq9S+aS0 zGn_=EoGD&xPc>ZjnmiZho1@?V4V~4~N(y|%&2i@7p}DWk5>a`Sgl4)-9kf>?+&u97 zb%1UJjlp80=}@tcu?q57kU`7Vv9?YM)s>C9!shJIOpA5>m7d+T{n*}`lls7y-CE@> z`iG$IuSM|+FSFMgmqU_;R|vVQdFYW6nd{0V3H0}l7z5A-Bgin!cvauA_3@6u{0vSr z8)Ra0%rp@@`_wVBe}db-362>0>q8}pso?5a_j;m)MbLyww8FZTr{YL9EA9W*dP-mq zIX;n9uVo2}GUB$f-W^`{y|M-xrzGfm$x$^nN)#fX91K)3uoas&i024d8f-KVu3rq7 zR1s8tl`smapX_eeoV_>f;%|g|mmf5-P4rt>HYz1~w>#0_1R{e zwHnag1L)+ZQ7+M@F=?cL9iyWT(*5(7Z|l#OakO~M5Avj)a%MQo#KIFwgJ>=58oRO( z8UF!FtARrz6s>}h96R1)G1!!rd$jqtpS!%Ho95=@e-CF;?5}Cfn-NqBg*uT{I7X}W z5!_ra+iYvU=v~xf9hqvq3r1CvY0(2p^ zTNPxwz3E*<0VaUsNTO|^zfDG1)hvB}_hw$*(X&j^Y^Q*t7s)XB72_?3(rAaUAo(dF z!`8^y$O%C=YAHEbT0IPMgwP%{m)1sst$Y7Vt`~h}$hOrcIrA`K?+X6Vz&qeN;>Yjx zSJb-4VB211ld85!?5VUX@?P!B29!6UgI#dy-5RKHOuX$J?CWRka6Ih(MHeCSiyJg- z98*B`wRrkkBGOm*eJ+wo3`*iImL^8?0d`bwj%Qkv@$v^>x51*e`nvV?7RT=9@F@fz zcEVpP6v(ag>H>XLPnW%==;NS#cL>W)$ZY-ydPq)PI@hW26qsvklQEC+6W@q137v55 z;qsr&-ZzEoRR&v5q02FM=Z^14wjX?Vsls(TQhcCBe+ByM>d3K%rLB){q2068U^Ltc^laQAaV{_^yrPDWjLILm? zm>bK$C4Ksc)`lMAiK|r|B{=$8Tn_C{pI&k=H$7MBXRdp7Y;D624>>}ZJq0ajNoAC^ zeyTWLSsJf{w^~1mdAgdjcs8TY-^oky6gx^31je~9j^e8T zQDVoFdapJ8*8G7*OoN1DQ~HPg7eHsCh?nW9uWjR}M1pvB<|gSWN7htnfFMSIPFnUK z`WSeMZ$4J%lsQ%7*IzLc02ymt2rAD;;|`~FfM#(N0)lD+oqfFDW-Er8zl)H(Q*508 zzM|n3qQm=H7Cp_D0lkQ?98gjS5cBw3t<-uF%VBjbW=y5-k&5nIz{&K6WNa|&0d(kI5ko4c>!n>k3C zpjJwYRlbuY(cLfaZJx>rQJcf#x?cAjCA=TkC3cA-rH?Seu%lP4ZZ^mCh`O8_Mn6RV z>V3%}yf&O9DW2QXwc6Cw4He#I@Rs!-DJTBRo7ZY`YK|UZaDfGezq&T2m>K|#!JVbouq<@i`W-&a zXGJF*nT2RL$PUx-q*QBhg^Ok#&%3wzxIv$mt0j57C5U1HS=)O!OBj$-$&m;yJ_gi$-MA>8^f@OVQlsbL{e#hR|GG1 zbt)fC@ME>C+jRXxtf+vrRLelg+u?dqI3I@710EAsQ#7)gGKMZRF_XXUY_%DL$=ldm zC+a!br@at`FNN=88xc8hx+Q+rQlsvP)W-Q&OMAnx37-27T8j!lkIg;2rXFVni74u! zTj>3Z!JtREz?zMdi_>_=9oG_!grp^}T&#?|`;^b1UnKCx!MLQ;cp1pd-a|h(bA+H} zLMj{4t(x$vv%F#ydFrO!avQr93FMgVH|Z1U@Y3mn9Pe&Kt?PJp`gH8Jf2BRBu0#gP zjo=~A)afV&pi!FxiN)G+xjr@@cy3iv2^?JlA-3#n1r=@V`+o(yFRmC-yI=Y_NwP@Q zV$}>ot{0HCdRw`+;#-tiaRpK|Qc8ED;jhW;vKhYtx4zmSvFC7Z`_U_Tm+P(&Xzz_o zs`hTq3v{x(!B63EW=_^^lgshaBi|#TKPw*1O_p|u94vX4RIMe94e~U5f@Kb1|J%0q zPV4T*LRKoB{Ho4Fut0uW66N|k<|hq!?B~z_DW<19me{*Z9>}K*H@yQ_*?Iq z;Vq3(k)IY@GpB%2#j?m!Oew9glFDqF58<015y|&M0LFXRX(_tV4=DF;_B&4Yj#qAF zZ@pH%hdY_{?>VNuN=AE`Mp65K>U#2qJ<~h&N7@(~V0hv0WJfdb9!uE|Fj%zV#h4rXiE-AS+ca-# z=7_;3f&gPSM9)$1Dsvs~WuGS>$9r{(Fxe;$%R~dEHz#+>n-q}TNA*Lgr>waPI>-2R z**0<;u>7%qCVrLjNO=C`s8*G4!VmQA_uc;_YF|wE_awr!Izp=Na!la(lFgc-rAR`) zW*Nc0l%W?nG})eWr{!{WG37f~k^y%qQXVyG@ufF%h~>LI#2>-ML%!5pWexV`3o2Gp zwre4_&L$LWSf?InV;>;{tYToUbGw{s=e&O{xj&z0*Wx)Az)Uh zPQxT;2Qh5su7zEo5>m{{JFGc(qu}=swtHV!=YTbaoikU#jr)axQuwc#8kvfhc<{5n zno31Fb8Ihh6O|KWlXLg_{LZmBOAeDfHIB^b{dnec;gC+TcI)eNXCRGbMeCX{9GvSG z`SZS@SH5iVi49-+!{Fc_{r=j5gfmF17-^+oyMGHXI4_9?{D&lkk&YW5wupV!E_j+$ z)~UB2YdCJUrmiTSIM4C*`|v`FQ&km{q;Uj~PVT)a{cHSfZ20iQoN+?-S7^xLzOJ!I z8yr5JeqKxworr>TTFyUpX_&3_oLwOQ_gUHG*PEh{2Am74@3yS4IlkBi)Uxg5Gn)0~ z*=imenkE!yF&`qizwIJ;eDQL8qm zxej7@hE(Q03;FL4Uz$+%5?yzK!Rd!tqGBTIMoB`|_bs#Lb$N(_w~CWythzlIS~8-7 z&@>k#%ThHt?xO9m^+Y0hi=pA*gQ$PM{EVpqN7-MJ*7DJnb~t0qe$IzTz?jS1E8k_h z)t7}jf1{cTs}DTTaCAn3V|Kl|@B^Ox#T)f>Mmr%EuC^UV>Q0FtJhq5Z`_)i+^;Z#e zw{#}S=`Rqho7-8JWA(w1zNN?sp4y-tRU2h=h53L3*s8hMBx%JEIs)X%sCHE}9k3UJ zu{dyc*1C?mL=h(O?Hux0F3Q7}l{U<^cvj5-SRAd^q-cq7l`iC>C#mRI`7rJm3s$x-O-$= z9!u8J;aE+Jzecojqd@EuxZuZf+xqGGU?_ODyXiKve7+OE$Vt+!*%=@#vHgyN=Z^7s z7C<=b-uv{(MvGrpVRZQ{GY$M#as3r|`_EFlU80s~0x6ri0oi~_9!EA5Big!+D`sSj z#UFkyRD&a*V5zDKqR4=r3FTqD!20^0f`FWv>EpO;0$sNXQdQ-L4r%2kP{Q}`heWvF zRYB6Xj~zhDz`ws=(s2W>!vCWBVEhovc~w5Hi6AT}V~)myo~>mcowU&Fhoip&Wg+MZ z(YUBzzv8QIv!k#>B|u*12y8~O_;D>ZUBpp=hFrFmqmCJqS08Q_G9QxIkQZa=jOKI9 zg%u~IwD;py-f@~7iMcp87_8utRHyo@3FHlGhHPo@?Q{0Xl*cpAiY@jeAAhnk`b;|J zc}tcj)^qYnwG)f$t;R>mHR%q^@*1#Yt=Pl&)kRoeIS)Npb}o?yrSBH26z)De za~f&kLctza%bZ%19)N$-dTSE^R=c67g(Mh4>GJu1RPdftYlKZjG)?Wu)lONKpfTE! zW{$vRiluQe-4(F)m^2~wYU_wFR0?E^6MEN!tSW-WIe5-KiSOU^4P8XZgS4F!Ch}{v zzPU`KYE}PI2&XPLnQ1bw$)BW?_<`Q#KVpNCh2};1?Dt#Z8~_!U1awgFWH(&XKb~(h zdi6*dYf^Hz^by$)c0$@J>!TE2k)wZY0GmJY=Jae)c-_9_5$H8dHOq&#CmWNWHWbpAFFt z0Rl*MgTE8BFHD97mAK z97~b#QEtn$me3EbuQ1xNzi=qiSOr@Q!ikG>=r~eLvxHM@m>qr7$gU``qp*2Ftmedb zhxJJMfiNE_c_x!(y6@9LblOR}p$_FMwTg^;2tW+4OK$0An2S7tqA5#ier+6hahtTC zR%goY-c{EtAyrnF3EvglUx9fElF|w8Qhnd-K+ZeSoy50>znYCL!dzG^pjDXiZCo#6 zCpq-|rmIshGfY)wgNJCmq_lhbIw`kE@RD?-0W+(GFJ%;@PN>_~0lKfcYUIxLLOaf$ z{Fwa}-?lq}p$ zp4W8D37*Wp`>f-G&Bot!YQ$0w2~3nY1}b^G%64Ws>UX@kd@uD92w(QF>RP{~KKov& z0}=W5Q?RHyT;OdbP!G`Ur`+iNm%H&tq`<}fk;@|FHspK;Z$u$w?_0(k`&jMeSLEWECw^H)l7!;g6nE%Xi`!&1ciinrBkRAO$dfBUPOajjv}&YCw=~0L`1q)iwX_^ZLA$EHNASwC&(JDD%$p45FqyZ5#?z zdjEYg=+N+KVNfSm(B}Z#>ctS{5AW?U9y3VB~?o{=s_=9*f_3c+zY z506HH`R2CHtCKHt`Js@1)waR6JT@TT3;;mM-}f5_S$SBhE0#I7I&e%k#pSK5zSgJD z!pAOTw`ACXutQihTa$#1Fo-o0zs(;vl@**_J47IXPs2oqqq+{C{{YOiDfWuE#5+A< zs0_uSU1cvk39%lcs4nqQPR4>SGWV|MohB$aAHLj;>6w!hm5FeZ-Xc`}r&&FKNey8b zgqdt96gVa&89|FD-c``0U5`jYM_7q?!e zBv%5_dQ*R}itNdPz8bc^Tq7LcN6k!q$H7z8`O9QwzKU;4TaEb3FX`=Eph+7!)&@ukRY|B= z)z)z>Waz9X6^cXHv}yqFthj-k&QaD>Ws|oF1}) zDHf7b5lnr%9_@e{!#s0TJ>rbGZY zGwp%yyi#ZD@}NVu@z~&!gL_-%7dT4A>H?ZmiQ!w5tAA$C{>`3&W5@oP9c^#xDsP_H>}I9ckg2#X2cdQN%o8 z5yz=lR|JPd25%_#_uXPJ6~JZ*l`w?_?+0M*#JQiW#nZdmMVO4F9&OjK-Og{E%&GhZ zUrY?8W|Y=DC|DTymxOVn_LuAI_#oRHrXomE7z;WKXAcWAJN!JD+tu)(RfDRrtPvk*KsP2 z_^zOSHaG_RO-!Zr?I2bsrY+=FBkyIUe!X!xV5(-`nVOI5w}kEup73KJND9H`IA4Z2 z&EWJFB@l3Ot3R9dO(XCv?M5sW>Lv$w+SH^~b!I%)Zbhq|aOSzze~_Xg@X&@mWKz7p@e-0Nlu zk~AMg+#7naN#>52a4i<_o$Zg$(hBuAlF^*>fd)F~TIo6xas?TU@`5kyeM{RXJ?V&V z?K?^jpWCC7z)H#d&FQ&^@SK<`@rMUfD?E&To0=gg+5QD$Knm9ei@pv>w z`&j4hxGQrFkvg<51_nG>6vK(+@bcB!b9>Zqb2fAXIGdBcv8HFF_Ooc%LX8#FZ0W3( z!(Yu-OW;^hT3*nFg-#Tb4nyh>^Yo1)j}OJbHXTQ~a~{>sfUYev8F!vg+V)Ep0BN-t@ZZN8^NM13m`w*EDc5{(+fhI;F-Oy_X6ly)lk&$5m~n-O7Jbt zr*4zpROI@p3R( zlv497>^aID#6I_s)a^yIKlN{o9kDV^%7zcv(;17)4PI2VTgqM}lizG^3s1ojGHN zdbYg!5xuH#PIfBNVj-#j(b{AAM~*`pU$jmxO@XnGzh~w9Z8XQW>Yyp<=^Nndgdhv^ zkkA8x<#rPg^sP0(k?f5s74AF!pf&Vi4NZ_JlXV#(I~4;pHHWz=!$*4ryWYCC|LW+P zrCelz;EhK^C$ja$uVn8&z|e~PfZcZFp&^%3o?8Ot@#atWZrKr9u{v`DH`$HCb4#}M z%%dTYI%#v z22UOPvelT`GUSu=GFH2ybNck<8mYbPEfjt|>h9VP<9wcgP;CdHTYqI5bLB+LeH#a* z<`q?g+FFwz56vSMSy80{slOf|csc*BDk3l0X*3t0^XF!?46UwOIY4T^H}ZZ)0dtNM z-cimi!1M7#fFTDrAs_o9X1vMvYsw%Odv-xQhQ45B_6DyLCU|CMZhEyOV?Io^n2IP3 z`i%%}P@+yJz1hmw%sZekv)qC^3NAzb8rRiG-LWBK2|c+4J)@kx96mHsfu^mKz*~!N z-h)S(Uf{MXjQw|RJHmnpD%0B{uHz-T`m~1LA%TvRTNxsLDENct`~%{?!dTz4#dE=r zH!T@ob-*L~qU*zl``-8J?>SN~Rh{9NtV?!~Mj2hHi50#ZoZe%ouZst7!Vl5Oj+kCf4T}WTdr!M>vk{`emYDss#}M3WvJ=Ox zg^?wH^+)|rXn zX%~Y&clTE#y09i)wl7=uzcTG0y0)DdYwDkG(azF){h`lvTO5R% zwak%jtDD+ifJR{tpeNyDQk+^@ShrUUo5K^_bR=QmXR#aeb(;~(xn*F@!G3EfDwNM? zN|P)bhGdR9r&uF2X{Y0Qx>fVY8cg|PSrhj`+2NxyfZW|C4_gAGOiN?vDkU7!Z2G(P zR(7*!F+j5cJPvrj__AHGlw9|5W*1mfkXtYvl%c}eJO))Bdt0ekd(F7^;>d+}<*;R; zY4aP|zEvN1W$9e54uCm6hkn{3$}V@NOR?Y{kFX>~kxi+!kqV=`K~k*su{2+%uJ9w} z>-2V`r1{ZjbX&-{UOe7&%y?vuzMjJ!tV^dOR(9_DH1YA& zsBpave0KmFeO+NZg``QJl|8+iGvy(4+FFR7Z{*}Q?eDw43KeNprIAQHLfIR5Lb^HD z4n0li?B|a)zAjoo1+mq5JflC`mZ!si{#SR!2z{C4Sx!^Ca(2QGJsrb$E&Pzou=o>` zfE@$c%<3ibaFv>S-CvdCCw7<&&0fo2%!!@h0%Kqle<|l2qS3eLAr&r75!&Ur#wAX_ z%H5z+)Y_pIyoAzk@_(V6s}r9P$i+ZFyITD0b|c~wD5f@kE%T#7GGTl;YR}b48|*T3 zxGZUAD(AV>eb}qAWVg8lx6)J-FOk=%?&;5uZGUVmgGZGl$g}{Pxp`K?KYYJD$F|P| z_|<*f#Cg}TFV_3~^aDh#e>GnI6Bk|*2vP|G#jNIP)=CXRH`i^I7$9|Q-(@4S(&C?$ z=v+P*F*PpFprktXAsFP#YehNgUHBcltOzbNW|+}0GHO5JpzT*y=|(dpq&7Weur|ng zv(m-__3gR$KpSmb>01PMJbwNrtV_uL|iXM{E46CiX|{dyb%zo!0R%5J@03d zgvKFHw9fWf1f?&3_=bz|fTw?j>=R0XE~9+Km9P zDn!&3@Go*juK@M9U22K6Xw?eSkM~Aor7YN!&&*m3s%GN1I1+XcmnA+~rCWR-j&MX`B@g2%Qyap=bCM8OPKd2kgc$wEmNR~zrT5;`pi*DKteeS&< zr<%Fh5^5MkA6$IG>}o6)IAogzwx)9tZLac8I*EV7I@ZF#MdJY%#e3;F)dI&!R`qN6 zr*{c`&!C}bku_Lb&ro6RIr_nI8kMxXRr-6hHOjMoN<5zF*1+GT$@ZuZ_K{rX-&P&i zThV*7f?Vmn^?_z(o*fnQ1W#>HnN+{f0J!7JMvnms_f|KQolR_@(2-Ds~|a@8m?;0gFPioUyQ4 zG&JcseRnYUZ4)#FIFR1@xAW)QgBqox=+hmu&s*4s5L-~{BnOLSH_!JB-IqCb_ zzBUv#H*`X^O+dLdN?NYZd0J&Mg(bFyVTUvqJKnNPNekl{dHIf(my%6-*Kf08)8lss zJ{Y0dk)rfI$QPynvI&Zp2T8qW-{JlH$L7yQvj9<9ZeV2sq?5VH16Sbk>FQ$!=6Fa z@71rY=7(QnRNp4%%A_-=RC8|fpZxE12p4HTT(&3~Won(XPIdRn11Ef5kd3DGCz8^X zH7b*;SrdRSlu8*eY_XFu9Bwno5JIez0NNzJ2~J0fJN4C-;6ET!1l8 zTUU88#A?&!Ok1@nKzA|+I!`PIquEo@;j0Wlw@#_cW3kEm_N7FASHOhm*Ti$kE&hsb zxMpw*;<*ca>9eh1#D8KZy4ZAeo}3wFaGhMwtyVx3EehT9E)ee^lKWi1vYVCi!G}jW7O1Kq={aZ zP3oKr!L5ap7O0b%2%SOD#8}-o&uq1CLi{%oVKGzlE;qsOBAE08 zEm4aKC{=wx;0>#As`-X9=#5I5q=(NyS~L5j=K8!yxJqUE1dr^`f4LXBGc=<9*sJzr zy_5?kIb2uSVO+tYOGmMldU!&YceXtBG5%_9u9(ieAa?0J?e%6A6&|r!`$3y<-oCif z0>4_Tev=>_^7#iNaAtCaA^*p47l@lKg*iMj3S6TXm9G9%_FPO{`WhX6ch~l4itH3Q ztI^y&IK{~Fc8XLf;MNG_wP?Vs>&1R)+>KofKQ?&vHhp`(K4`?%On{u*F$n3!QqjKX z;hRQq%S(=8nm~Q)$xdFFcfBGf@5=rGXyqDCMF3%41w~$x9L#WBjaeOQSV1GzygCnU zjV9)~of!m>4o&8qA^n@H1cAJ$qTGtKyUQ&#-}N*z@G@>xm)U=h3Clc!LHI8j zVxExk@*C$rQT)ZXp(NrATQ8m1#IT9Al(W(O#h{tlxM5Wp zms9i9k$peh%a@@N+0-(fE8530Y;g#>6UO0vC7JFZe!Ow+U?9ix!wWmf2cD6#)h_SX zUL)Of^!zPHA%pOO%rJ{#U-4kb;WqeFyd+ii>TT^YN9Ii!#{EV38zqOH(Hdi=_*R|! zgtZ^s)U~3peJ-7|x6BB1T@U~z%bPhokCOpbz$)JZPiI=aBMgKmLH1BWuFX!GQEK|b zU6ilU3KJkZcCnvQN0PLo-XD5Qik@hIx9E_hPfE2i`Kv~!EMD826UmItOf!W@N%Qvc zzu6yHvgrAW3R+VOOd#J7d3Q4RZX%8(znzjCzy0%!hne&d#VYx*OdP$4?aHBK5|ub9 zzmm!3a;!~uQ@ol5HA@E;F$!q%_U*bVI5Ox_%CVLG(qBxZb>)w6jkfG#Qmv_!n=_pV zY7w%+EY3)WGTgVQ|RN-c66YI?%j-oxyMN(5N^Fknwz-I)|K z4;r`-IHHVsrr#}?V^XY!gw)P^fvYDpFJZH!UkR|a9txttGN2JA5ZLjbEIwhP;U3l; zuQTDy!~5;Iz46gN@UE+XTYJ;J2RuaLpt4p@YQSzy(mT-jH%v`R zC#8gqU_%+e)W0WTy>ntgTi1|=R=Q2XJR=3^iWn`;07iR6m$Ey;Ig;%dw zCtTk693o1GzqAnQE;$+xZ@%@nqc7Hz4h)!NYSFr9nBX{+bXq0$7IsSbr`b<9PV8zP zIXFBIBsHr-AUDaAq>85L&S~Q(s67msMJfmK2EPK|rc1iV?v%0Z7nu9b=&mez;Wn)r z3Fl<}VqxmqCJZ~^o@onfetF(ei5d%4+qu{9II7Q89$}qqD+nN+&u{QDDo4|R$;%*l z7j4Wg``gWVi$>N{osM=2gMKQon!)@ZXb zmR=h0>wHd>ltccq-C=00GP)xjW47vyCpS^p@PcXIbscEa^VTbWStvR%0_=+G3|L_* za$IjZKM(E$yX-w=Z1H)d@fn9Eux*N$D;DT<;sR3QJI&(T?_e*$E~$ENr<~;DPeCso zAHhdnhp0Wyt(uo1tBbIl4C%PFpZ4>AIW{W6M<2*<`rd2#C?CBR zBtIPHfp=Lw1FbXs@qP!%KmU=o{~5j3YxF}Dj(>jH`Gq_~yvjq$)h{vxhk~U4pHnkG z;!F2w$Ed02WMlX7{i~1%&!ow4ezh)jr@#@6v?2_FUvMl{YK$3bl>SnmFfBgla zb_}Sts1H>_I`P(0P!M84DOix~L5E^w4g+su_3j8yW6a)uxGF`_oYb zh&}jSLqO8d3=M}=Sk%vHq$FI$F1K>qPQq|UTAgpukV?8z!L`FCBQ2^?rl3tlH39Jy zwoN%p@AfA7R7%W~a*nx(4>Y<7GQZ5;)l3?2XyiI-ImFhU*DodaboIQcVg$4 zadSqA#kQU9Mw@+S4;%k}Yg|CBKYUChUK?wsacvG#wdQ3r5^b&8JeN@Q0~KqLH9eJo zZ0DcE*yU5r`05www3SUb(ke8YVGT1JJCm6v)Hbf}`RuQbP6xSc9S!-Ka3#%Lc48$b zuB1r~@YS3hoM|0~Mj_!^+vu84)95)F&S@4z7@CmCW*)>vz@g zW`?a>B6wIEjoH7}Rd~F&0B0IUlODtFINhx+2+Bl0`<2hGe+p|{qC6i8`|(2TgfMla zX|QWHxg7CA7;Sj`RnrQ7ch9@0Wz}1%?qjmb@b$tnle(v&Ds}rYPP}_d;3&;pK{Y() zIyk)L#({zGDE(+q6%)Vz%}cshf^wj;Yy)G$c}!!g#Fp~xualmy0#qAz&!JI z4|RZv+4S>z7M)BFOpXd1Y7>CFFsUNV(HH#!HFvJ$DIIhQQ=yc$+of(9A9VCHsv^fxC^ zj+qptQLR@>q2*T;dhb1I0FiU$vMA|K2!$71rmhAlo>NOTxGIiCDYtE3s+|1=1+h>~ zlT>eX4s-^D*f9)BuQO}(?_qER$`rxc?l;A@86B_@ilV8x^0b)8TF#+qJ2zTavT(OY z?H0Ubzw<>aM{90qvEDL>k7U*3%NIe5?lC%|Oqh=yr@0e@KHWb+e;1bP6=E*Oxh}`6Tmg#r8H=t(7RwfJpJO#+#sWpeSs#%(7 zI*O0IZ`LbKLMg;+H}u2ZtN%FSGJ-t-u4ls#)raFs48%M`|5NamKw|s<;WfVh0rt{y zXK+GM2Xd3+Cj}O(3aY#bE4vD#Als2MTlLmlq>ofb6cI$1{bn$Ha0@-Kg>m*5i2y03`=SOTxlwU({3|7pFs zTbX6&^??55Nd3vXKgYu{6pjFqR{Te~^7-#Y8pJkrmP7B;A1v8j&-ERL=g)SJOKjpE zB-N{0iDZ8Fn}ms4?HYNMtd9r6J3RC!*5Xj(MHJYU?LO@d)8L0S<_P27jv-;8zE&@9 zfrMGvWd188SA=c*``90!pwi9=-=MdOXFNcA!~EH#66nq993oMW=5cQ{^s2`=dQ@;6 zx8o|92He3t4c}v=xGqv3Dg3&BKIq2tw>7n*h#ub%Ol%1uynf=X^y9OT@J#sL&MYi* zm3*RGIuLU8of_@+w}gw%1q7{z3aG^v&fQ|AVEAYt;V-y{TbtK4np)2r9h9j7_FrIjf^fy9l(o9>sV_f}|=SEpXY6=jdB zKdM%8-sj%$4$oc>33@(R*Dp$*U2bm9Z);Z2-``*MUrxubc9ppD{IY;Qc<`E35V;>LGi2Xdcu7`mk;OpaVpIrY>;H~i1{#0M5{#=^dF zT3z1oi8AW!f(o|7J?Glp{yJd(Pb#d%*_#wc4I}8eu zF&D0-2OryfeVhHX^pd4$NIU8LUvDVM9DD@j$HcgO1WgN}*LoePvck8|HbSa%MzAD& zoS8Jm9GeRLEbJJJ#T#b6S&!Kz#V;Y6gE(ycx*34=W=s?l$te6`izqy7#~xxOkOsib zxzPaubdHcC%^gpi?sj*)&tFF4JvStTsJ%Wzu0n2KAAP8PX6_#R)}J~gtckz+dcwIU zQa`9R_jdmZDf&n@JNlZ&|M~R5cL7{ztC_A_!&&N==3-eCck3d$7GZyIbZLYWc0+hH z{JhHj5qZo>H;A%o91wH#?sf-J`Z#@a#ms~<8{a9p68^|J&TXvwe7UMv?EVxjTo6NW zx0lwor_8nha6pg0ke?1{To-a77B;s?Pb1#_-BiBr=t-=2iN4)mYvV{X%SD=079lVF zoFLEp2H%tX=C`?bfp5@fwe7EIcQdX0Ts(jMedl+_Fv~kKfMK}RcvSjt#$USKQ zLFHRa;6Xc&Wcw$2QLoFh$?!Lon&|$IOXX3Z2(eo-s#}) zEWmB~%cSu0z$ZaZz8H&5&pVpld#M88?qQffej0m6wZJ%_V9;27jP=JYP+5+gzKr@h zDKicDloL(-9`rGZ=^T0dQX_vKTzU)q(e`oshiP|^`+g=t_;o?-rLiRM^<{#ccC_!` z7WDZ>`hI!$4GAeLuon>~RLt#B-nyzWP^{P>@O3!_tZf|dhgPRqr()IrZO8xFN(2O* ze3>V&vg+Z1w4E-m%;cT^iRkEmXmaRnViTeVbzSD&YnFp>e4(u)c7|86-vGvRng;t=^0;Y~jEqjS5%_-0ifa{fg-q!bpXff?othfo-k9hzwY zTvNYm-lS^^(2Udjt^)yTyUNTOisnc}au87dHNLc6P;P z0)mde+~;&}xAD!Z4egh2dd?axI=v96)k}{wZxXQ2rtgX&!w*T*V3c0>HS{VrA5a=G zjdz|;O+rC}pO4}8`x66}cKpX{@0y`EHZeHNyWH;(?CcM@>0i$Z`NrH!2V-QADIpK3nGKOv|P<8etVRrg_f^doCb2t=teGB*X^8?(!DvjDVH$MIioD-I& zkrTK2=sA<`a(I;dr3c8wvh`X2^if$l-u;9YP{{mQ3OJ_jBKzNpd#j*0pk_fhB*8t% z1P>0u-Q8V-3=YAA4esvl?(XjHGPt{2aQA`DcX#)%+S-S^Z~xnou5-Fidsm%mlIZ=! z16|$&wyycj6|u>8aOWm{mtayUnX^XFp_S5^1;JY~zxC0gnfLp`!WB}vi__8fT zNyRBg#P3lr-K69Rk!v+JnMo_w0imp7oxUw)sc(lya0NTxWWThjum^=ZxgNVF8lBFTLuSBpd z4Mbhw`D%eU<0=7j! zhT1T#ox|?;`vf-=oZlNbEHL-cUD@Tg0edS)NXaR!leUn9=$$=OfwvQN@0m`c=X_nH z*y5`;g(q_+5}W(7O&rqMw}qwS((flNck?@6g=V)#$?1)r3fn&?!L=~aZF3CaT(RHv z`q+V8*L+MP)W|Cl*v4&Ur7P2yd1Bo_#t~SHdxwhdyy*|8EGKbA(ZL<|DZGVD7<2?W zi{i}M!(Q;-VZrI1uYAC6l2tD)~7Pt96@@Ye&~nu)p^m}hn&*Z+jC-Pt%gpf=-T_Y z4iLwj%(Y3QL+e?$XFcGl>wBPMw5Z#EA2)t;B`&hDKVF2$wsW$^s*nO7i?3@^Rbx5C z{~x}!{;z>RsFT9_+{l_KSu9*uIyX!pmsH-mUaV~6W1;;vj-Z`s!Tbnm$mBRpA3oSQ z`F#751~qn=5!ib4X5YPh!7Vgter%6?Z|E$yZ-3*ppCw=o_hS5z`sHG*U0%^R!KgRM z-AMgVXLGa|RHg!_8^A+5O+$PYR{^dbEMk}J)^|Hk)vCmbSWIL8t9RefWmTSWbF|R% z-BX9D+FYl3q|KT`61HewQnI!1%Vf0^n?!K_ub5OBSR7Ajz!NGRi>8Ky1eREKt>D+T z3aAZgJNF<;w1%<^j$#=}fT4Wp_p38*jXlAlggYDib_WYUP-}L`xVGGD{caH$QM1|} z?av2(TPEek@OZ$}=5jv)_A&Hw@}yuf3PKhVjTy@eARpbz#g|2DDPFkOg$OnqNIGbSE7n9E%Nc1>nBC)JDS!Ye&X?KUDlbm2E1G8}KJzQN8KRZn4z`<&2B#%IbRp(KV#$sxW(< z&CiycnK=n{s5jlNj5nFljQs)1$orc_;d;VeMrI;yV0#Jm%^_;4W*7HKS^Ge>8W~7q zP#tgtFT9&e11M9(ZJGINoo4I~ZUVZP^J4!8<5+m`Pny>25>Gp!6*Gzmodl6|DZjF6 zz6RnazfptS>~>qvNE03fkH|Dsjo+T2N{Paydi6r>$A| zReB;=tEgc!Dmfyrai3MAFv~4+`*XF~bhyE2XJyC#;H|vg@Wjo6xX#bYXnK$og|!Lu zghY>Qy?jm$oH`y0))M31%vy&pmG*AxG!t?ya_?4Eo6X)Cu4#cWp(4o2*VgYe>Fh3@ z5nikssJ!l+Qo2oeRd1^)wj2=@v5C#)QTePwVvz6{ThUY~K?Z6uq4Ts5xQDOyP1N0$ z`JyoYr;~(l^>{E>wPF2DH4-HtH&N zV#$7@W4nq(oKD>;s)`&W=~3M*OmlFzIG`z?gsJ4#38rq_%=9?HC3o@fo8l#3K3%fm zt+e*$ozZ`E{ZYHIl+l%aAwTW8mCi+X?nPU=#P#83tvZ)%KSex49q{*r88-BiR7PIv zqT+QT*#TfpP4gfuBAG(44qw)87WJrK+|H>;{HO%g}PGCU` z8+nAjwcKUW%u@CaqjM@Y84BY1;zPC6=H-h}*3RLYwF!^)xdfNU^PSoxKE1Ae0q zA@@tN_Bz?dU~?G#AD<**MPkKGDRG|Hf+~ur9pekvru?I%9ap6XM;1qd94)?_On|Qd zq19UT`QsS)U9T{`>hjk4UEyWXnQQm4P-OG|56ZhvY%)Y@ye1kXwRmZvCIJR7+&hG~ zy-#RSu1;Te@%om&>Mo~M@miS`x3x#N-I{v6Uixm*Z;TC|$Tz_T%`}0dfm?2d;61J6 z5nM#ArKyJ2n-Odqg$o)OPk}IJw#F}H%AUfNAvq}QA9PBm3I@Xmgc)blY#k1soUXF& zBPa4dw3_=+qLMkFH=%SkH|ItNc9L(|QSv(cn@_i&BW>0;fAypJmBqCp9!y-6>98;K z>xdyKuxq?2p1q6&hhIV}E(?y41(-N>OD7p*ogLj3OxsKzrI&rd*eg5dz(*)}Y-#b# zXLliQPF9$cQO_aBM82alWyWPEhCc%(^ET{=OZTmugW={+R3w*)(EfCj!>Y#OflTK( zJo|PgQ$dr-R#)JM+P;`e&N^xA(GGnz=Qmf=|LLV)<3n_p&Ay6 zM!6HpTaWhN;t4#N_;HC(_c1;m&tVSxZ;hnzhnr1=XIYW)%I$#UhV#>!$Lu@Z3Evpx zJ9Dm+X(xZm8w+yT_~ZC6<{iuJMyNNa`p4jg+XV`nPhRD@e|s~h>4T$Zg{Pf~yx&4# zJKhMsQ3jJ7;v`-bbwn9@xdzlxWR4=EYkvy@)c)^Tn6Sm(xKFF0t`?n=WYAXJHpkx~ zTjVW(J*bEqUI!X7M&6+9E`j)Sf$AAwc+|eIdU2kp>?ynn)+`;rg^F*wu(_YDX9--3 zmZf9;YJUSAVHt}Yb6DJ)lq|E#K0!4zwVk6JfOv8>I2}&8HF#GsyG>9yo{8RLYkiVO zWs0+zM!95xD?L%HJ1ugS-v$G}Rj6H!jmLIzbsAU~k!@SFA|j`K^A zoCCFGB4fI28D^ywUQ1%!SpT=t`fX+E$Qb!onD1VhRMX}J-*{D6l*+=H7V_t|pVvW( z!t=fgm5)+2snXRxeV_N7Ipz*TnPHIv3@6$)eceyugdKTemvIwHF$6UK@;%xT)QOvB z(V;pn{wzlplkUf(rb0`c_`NpSlKt*4DaNye9Uj5?{o?8VU+jfGLT@cKn4YlP^aVP% z+d}K5UhVAjI+lcYvd~7E-}PbHq3z!>Zcc>s8C^1QDpYm=ZDEabY31UiB!%&qiYmrp zaCsj4=SUMH4Hc$fYsrPCr{}PHp`OqIgi8SOJhT{dP7ZX!eg6IU4)YQ;6BVL&AhbLj z0-dk z=j?&siF)m}0kO8@U!gsDC=Dn&W3!w9dCbU`*AAyF%b|TMe_+qxgP$c#J>#izUWLXn zeH8iNXNQL1LlX>}VdeE_1Z;9WEW=Rfy$_qqbvH7px(=_iiwpEv9O|!dE}wE2%wl13 zUH4;Qb=}H~+e|@iVG5GJ)(j}?y z_o5baOW7Lddv|(EXkX;((tPNlAL!3W!aFboFqa@AsoNJt6E7=22&26o+oK<%i^+C z4$M$_I^&W^Q)w|grNH_6X7qCztJaB&*@7GaPksHQXcPqcXg7C%X~p!(!^6fb$GE^Y zJn@wTbz@{QAtQIYy?@?$<&?sjz&-me3u)ye80hJ+Of%tz+@%_@-Oe2ykg*iJZ-c+v z@+B3g5~)0?mRwod3@nT>ldPMwU?y3nc`BCWCvsbZ@v$_%FdK@o`2qRkmyE$wUY=*`8Y*8{|VN*Ksz?g27Gpv7eB^U={QODhs> zfpAk?u9t#Xs-Pm8ipVgWwyjLdX@B!X3!hVa<*6k zEcSpYC-=Q_bbj>S^Fvk{!iKd%%slh0*fJS#S z#K2I5Ilh`Q)f2AW5OrwISclAOqL%wzD;=7V#86XTckwfA<1~^xHWE#~N5sE0T#B|+ zO{SakPXd+oU|9;!;FaPy%wH;0N7}b#DXsdX=OShenRD5Wi!h~x!8uFUEi1>}ASRM* z!rKT-PpOs-elqsi2&n1%E5gq|{BQP4b$`}=fC3C+0|-7@&?=Eqv;Kh{J~Jbt$`ZGX z4$x&Ew|*&V)-;vVM)idY&TGecD#ee)p=y+!UGG7!-}XtXV_=@RWH;lZ`FY7;%B&>U z%d4Yu&?OQk+)e0~yc&)9*o4dE`Wg0jmvfdCW0mnx^`E%h=lrIi^UflpG13~yB%rw* zEXU9pVQCHay1|HX-{rDH3}%RRxgcw$dD0s zU#^Usf6S0h4C>t$jhxdxIE(+G_Stw#NWb(Hbt0uXwSLCc4~+vnW`U6XhE&dj@N};I zuh(D4_j5mI;;^dMxnpt9kTNpw<)(?YWQN_ zYqAjHRh;$K^@)Ro(`7YcQ~QXXKCACj*f`|o-)y8-{7nj;*b$`0kx-JzY%K}xLz23-e9;+JS_`#L1Oh8|Q7kfqD@CtLj`m+xqW1F+>08PBKDEe z>um6`(O=4NC422G>`EdQT9x~ez3vjxp}d8>!T2W4O@=9s;EKw`ib`%&lzN{R1nCqY z=$9ex1O}mnqP#nx-I}=%6`C9vm~J#A$g$lBzZo*cB@k>!^)XqF{kX6E zHj4UjXGNMh($0^JJ)DjQr83Q(snnWZHUDV&GWWAO+Q;5W*RdbU`S+pI={T?Y9{;d2 zU$2&0z{=IwM)2J8u;7|U*q!pvAQqSfskN*<-3gDwQ$^_BNtC=4W_leTVaeu{AMfLh zhbsOY)V8*iP`|J@q~Oacsb0j8io*{GZCqNp#Y3s^YQOu)sZLO;`!HGOAF0nxm+(-D z5JXf1OMKknkE}kv{B7bgPmWY1M1H$LnAz>;+V8Q|nzxf7ZKOEmBTg&oJJP38ke6;d z18GU*N$h|R-Z?L^5ZStz!%ax>lp~4wZo)&nI#Qd0vZE=_I~>igittWk7L0b6nLL$Q z((pPiOyIKj*hC(e7@3M@yv&RYgduJlEh*qaJzb4Qv~W7F*T6Ao>n*szT^;Yb=p$Gx z-3a@fsY8A~=Tz$uqAMB>igp|p5$5>H{ zJB6N|-Bu$_?4ocG<_;#`drQ>w*&m3jATKPmN6j3=A0p;T7j_c?A01Tx zy6Q(gIzoRrdBPl*?O}0izQjjEFaF8e7?{A)PCVk@D_}0{&D2C>h|Id}CK_~&InV+Q z%W5*#aMH6DwNrDNpsOY7C+p3WxM{{tcbNBZTICCSLvGXJN78%K){KJda^?&?)67xd zt@;y_tU<7tFcugJZVLmIW|7{&)4u;{Xc~;RbM3k?h1|6tsb>q@w(6_ zPWoqvM!nM?-E9Wq5I5EbD)ymHU~9Yd|JL~mC+v3R+7rJ_E1rN&I5p(u`W+W861^!Y8CkC+md70F&6n#%ITsYP)nOU)cf)`HBB5+6+ z6w5WottzuG%@G?ERviJ{!6%Z20uL|a$rTf{hL%(OIG+;O+f0G>M(dc$U&P5*!x?m% zXSFwKwWR;9)li*#8Y+%F*V1#8GEK@}RruXbC1?36%*bS#6SKuPyNpWQN~p3@g<~`f ziDMok^O-gZWYL(X>aA#BYKQ8sajV^Pa@_nQETr3M=nBqdb>@a&Yh0YtnVb9FMa4vx zkVxU8q!Y$)kJJVzV;Y$>FG~cbn;G^|n{VpX!FAZft2j1h>EP*T#O~AUvys! zv-na|qA70+aD{2KaV+q)t;OSC&G9I-vC8-8?s$?*Nrgs?b@dPr(D#hrQ>(1!XUJu8 zT;u-LtPMQPTq+c-wqU%H%?zg~cid2Rm+$q=Niht|JAw;Ny(2}xE)C$|MXXYr8Egq@ z3lLSUUSMh1lFpn9wg!ziQyt8F)b1R42TPP#aXNrZ*ltm1G};l!+;7!Q#;(R_v-QO_ z5jcMJafYyr;JC%!Sz+qPDV6kOC>W-OYV2-c9B1N|%A*J)N@qCX9U^%y0zr*869a-{wI`tjdfgu{y^p)E6}8#xPC!Y? zElD2Gsr~qb>}FFZbXkymTf8mEye_^Ij-QB_N=)gy)`|cFt#z156Yri86`l=M*T5+2 zQ&VMIyNLU5C}f;r3-1N5vbKlPtI=IM+>#_EBA>MTJ|sk#LDB(+wT>>8sq2s&xz?)? zB3PoQMn_0wj`-JGLyH!#^^Pj#0EC)vZ^ILJ!Gk5GoS;QaOM%OL5MHaZl?H%{y4Lr( ze!_lH-2u4KxULwkIzai7fJ-I_qCb?Q+#p1u(#|cKf7b1{TeNfd?qR6Evb?zOjE0r% z#=Cl6bx26H;It;bDLPz$KCfq-DSL&}45)m^=h%8Q86qf8;%jESFvd$rGFVm#F##D> zJL%hnrqj?5j^TXZcY60&Y&mLMW>|+4_-%2^q3&ra`C{lYhFyuvp>?gB$^ErXW~hEB z1I`JjyXQjKt1m^50{LE8!@_&oqlX-^Uy!!*D$I)|u3D;cbijf~i2}SE{;gj@=1zm1 zYa(o_u&U0868i_XIqIt^%%qkzJ5eK>X*v)OmRhpE1N1LbVyjbhmc{itooVvCfF|$} z7~Q}O(V7IueldqSoT->(GcoI7KUdfTsK>JDXnks2O5sKf3@ed z0*w0u)Bv_tj82eOe|+G3$&7HNA`92?S=8AUj}Y@s$E-AG8sAuPuvw+E02GR zBRmTnxSmVt#xpP$fPX5RpWrfwPMAu(n!Tu%wvbIl+O?ts5*!fDfZoQ?s|z6#cqM{PK)NRi zt54_X_+zXM1Fb;WH+v2=DGRjkfSiwYq5~*_X27;QcbzWdg~=4)!`(c8Ystx9B;?r6 z2EFKFXTm3ZI%KciVeete`huwVlN&-)VVmS0!?Y}DQa8RQ(U#2h^m0r!$?dg>_vD&c zDDxkCx%CBFYUfB5bPfu5cRAeE6Wb~Z2-@uZk$nkcJZ`jyifoL0mwnoEDsiRCVah4r zWDC>*fyG95*tiXVg( zJ9iAOSGG=l^pHlgGPJn6ydZIatznPcPqQM25x>Chr))?a+Tdu+5-FJJ!_RT$XNdw{ z#&>(U_O(4bqb-P=;areYeg7h4N85v2_|o%{S``c1j<9?kL0ZsrpQMD*pdXPd*FT19 z+z`7HQF9=TjXysDLD+t7OjgZx(iLhmWo%ia#A2TIB6r+!&W&pa-%<)^uyS$6_=lf^ z3vVG%I||(O#ZVgy8Bc83zlkX-4UL7W(NfJ@Z zNuLC5a5#_daK$xK{jc77<=`LJF&|T=v8`Xoxg2Xp3oKq(0>|N`xqKFX;`N?VV!XT% z;xU&zzd^~^*{bsaorJ}jr>63f8Bds({P-TtE|&XtEOL3PJBmWtPnZ@hr&M!=hV5x7 zDJioO>7u(Fvk+GTfS(b4=?Gg$Fot2r67eaWU3dm|%F+BLH<6dJ=~F*aETqXJVe(fwW!_m` zvSvwfAi|tv$g)k<%hL{o&s;bsckfHSnGau zcPk8^=^NQ9>0S3HV_1~o*N*)vLk;eWw>bs2U{t+lep8Qg_VN?IT-H8&Xc2X&PVxoH zvxV&9gGhmC@GbqH7hsk43xCMyup@R8&6NZnGp1CXXQ9}M&6I;jdNIqB=R|I-T?EFg zN8RE@4Zi5fyEb7>Ew5qO2->Mb+V$AG3nS)`svIdbnUu$-R;dHqoH7ev-Kq zQ12$0NX`D`AYsuZ&+IEV_Y6+qt@zCKi!oD!15MI%Ss4qKUkKCQkSi9c%1+NyL~w1L zYf*<`+=3EZ?#&KC<48@}nU86NL=ce<4F<+W`jziUW0dm8Ej9s-hhU_6fw)ZS)n_D= zV;|6WRHV5M5KiH|Hr|(=oGkv|{u}3#pbwHm98^su)2u#>Kx?E-6xo#vqt?QT6)yZ$ zp9gfq{BhT>S`EFH4*+kXfs&?4f38QX%@d4cfg^ojzNN#1Is5sA`(s+Afr}uM03kiY z!^I0o0zqgiKxKOwXPd@Ma+{cD@r{UB= zUF2+P9ln8;sj>5S>&}v~ERu zsqWMZ>Jm?s*QP>quGYEB(9rLVm&xE|7p(>D$uu3Sf?fn`t>f1(MRj>Qw_&w@uM|%B zH+n`dDVTf0tM zCOOil4=OR)*482P4NIb-ymqJ<3Z62=?xI=ll%KCysCfTVv4@wSTQa+7)C^$Zu?S3J zlGhsg74buY6hSlM^*4G00Jas8Bp&m}Yf0fhM`mx!Fhu$t%jHZ>5*LA-dR)YrVu^ua zIyUrEUueIYdlXor(gb&kzSmqWJSSf<_H*rAETu)t5KMPyY`!40OIbfq0(!-;siqVo zuSRIr%jJE1$DB1K8=_ew3#-VKZ^G~;n zezb=Qn|yPT9#P-(8qH1NpFqDvgjYoB*OI6cHe`0O$j+orPwes;Q*^{KC;VhdB7&Q< zh4&i6d2};j(HRvt9yiX%&D1m}bylu26TKmM(UvAHSjvSC(vv`N*c?EbnvY6|dlts# zj`k(uM3D}mxT!@X4zE&t#^E0z*mf3}S&(E#7^lXx40e;q#91^U7UfP%z7K$IO(~WQ zRYL%Lzd+gjvB&=u>vS>&U5s`sX8aXFyEH-^UcSnX_I!UIy@jye>qlgL-J3vGHrb{4>#UA#BzKYGpJ}dwQ^X+;Z_@ePPPPskB z*)|ywG?N(7Y>FJLqQ}OXQwjCT#Uc!CtI~UuCY04~+#Dc0mT{DWvlx6@$Mo6O8`ET> zpbTac+1P94cp4_HK*D?`cu;EfjEUOL~}tgaw{vs?QcK&HepQk^4TJGJOB+ZhX}AmS`10zvBip1tj* zt%zpNMOBKO#kVW|!CX_g;$K>h5poDbj@x7JH5Kt<4=*Ao{*YUvzT~K@Yrq<9v5n`V zJ9;EU2TQQgB$VO7N!OV_wk9M~nHw66V9KG)g@hh|1`(7wp)Y(eq z*E#yS8cp2GU^+j^j%ntpqVXJt?YE*PAbUKcg0FGW75vaKzPI0u zne7)z2z^ri@+l}Oa_Sg1pNau;S@d!MwIiRHrBG&2Wi2ry=Ux-Lr+lj%hIlX1%3P;~ zn|5Yme9&WlVfNd~zY$YnCIytnx1Jfy zb&@qL39`FgY~8`>j?5#VKn&NAF|G`l6Ly(A+My~SH^sH|P#&L#P?(yc6#XiLBD@u> zO&VIvU$A7e=0wd|qyp+9*-VkBk@B_imDwrRV-4DKp5X8K`sF82)+ZL27p`!4g{CKc^qd#g!2L=_d0RVGdhW#No`-j>B;$eFV!l9&>5%$NdrB%x;L2SDC`Er~g%Zx|ExYK3pLLOvtA$)ps z-m9VZ8Qv;XS7`Dn^jk9Ira$EaFO7tK>kYdS1v;PV&G4o8{j`ZM7_lY&IH+SI$()ub zX8|(QeCO+Ou}Cl>*7dirDn6V-7mZg;{HI?_{6+`H+^1hklQe+y?=N&o9Vu+VfYUUJ0mUEe(!g!f)@FFJS|7{{h|oF#h=1dP}~) z8({e{3R!$R?>>2l>_zVX&nYX!XZWKbHp2zxpI=X_i*J9|OaB{MtPuBl{yZfx9PQnl zn)Y9NgwY)5dY9}0BD-KoP&Xf)bY|z4tQ_x`xb^N&39kZcvNB{xXiJT8A$%j-f8Q|aQ;2g;hY!_? z&q)2h$p3$NqbDf`^mf2<$Eo)xv|6p*eupJy!LxY%+BzdRswU*Y6lknHe_5xjC+4_y zSftyn{#sHfQ?+h?0BHLDxcO7J_V^vWZFw3t|7Q>Tz;(#5dKsI|HqVk(rV9d@sYy;1 z@XbuBr@l!@WE#bZtA}PJ8L#W53~A(R@;r0m_exK1Pp8eScic@n1Zl$~vR1ulH-eq> zo!!%l*YO(07B9O=v$wUz+?Y(I>L{UV3JNFbxYx!S4%R%Uo!BQY&Q^C+hO$BS%;hc5 zW{VA@kHWym{KWYId8w|~M!4;VCrGf~1oS0OY&ntQG}ub~jKBjhl?>m~!~wyLTFQb7 z)rs5pqI(%cvbu8{4?@Zg+iK|Nzw@J>XNcY+$X^DO ztLc09L|20+_6IKh@gL=Zz?B+XpZxRu??Ph!9G>o9=ZbI45u0g?)lW~M8*v$_Y$o%0 zQM7B?16t+iLWz@55SS={Q{Ef!y-P#ZuF!1H+MYKB(X=~G;DJSjBJ1;Lo1T9F>TTiU z$BuosppE8vosExxr=~Zr^$Vb4|L_MxP~!1SH{>PExjIyWd=z3)*L~rE({R%rEYxWB zaujM$8?#LyVfCte%!_n-0w9WKx&19UIlfS1@KYZ8ivBd|Ci=?aq6Hw5xEPdt|0r#` z?QS|E#LlW6mAgfE{q-M7xc3$pz4Kd6_rDyBuY4t)@JBZp*5;M2>MsH81QTyWFUh6( z9DfM~2xb-R$n!Z66$U2s^3`m1)?CpwqUEFg^z60VF0)=Rs*5O`q~cz`IS35hzSGs& zga}3do)PzNgM<)H>`2I}NfTJ`ZJv#FDSL~JKiQIvUt$N6*1CIro5NX``Ko^cE#eU< zeVMM_6}j=D7r)!CE`B%oczWp3_+pHl^jOb9P@U|{6GQT8E0gRo*k5Y;ahZ>H6mn4z zG!jg@+WL{@@{?@q|I!pE?O(qhnI3kCtSHF7t*un9Ul#9>bT-Pa$83y2bb%W?HeR)< zagu+?pZ^a{^GtZfz_Gp-t*cc(%U)-xXNKGB9Zjkw=YW6X2O3~B8(i*BCbVWBPNfrn z>=jNFJnW%LT}F?0je4@0oI{WkP1HHbAo>d@3x!j0Pxl}}%U!!=j@Izzg{EUCJ#qFf zl7gVKg0pk-K+AyBF8B2P_m;EN^@a33IdzkU3E^rAr@iMoE2Z-OwTT4s{AaTWy1;NI z{S523=hNta_l#L@mGN^IMGy0UFlqjh|J1_?Q{_{^`T1x$HS~`yFqj|bG&rW3Z=du+ zXSfhB2VXb-FuBS#KXO>n@4&hk?627XsWy%LlrQzBZm!;W)LDe$S3DNT`=1CrCc-#| z!^A7ci2i=BZWClEc>XZY-$@kc@WNScr{`a`F+rP(dge+&WzcQg z>ILKKdc5t0b1(>cd%xAec^|`6lAQHd)396jP(L-={{qNXza73-A;w_P`8(^)-JBx) zNk%$i;6Jp2oSZY!@AcZ7d7XjfyKEGebn5k*-RB3VK0SRx*li7(iMBQ23udVq-l);J z_kzhsjafTM_SA?>-chGz(LXosf^(gy85g}9J?CnXTk5c0J7mL+J>K?kRCJnaB3C^A zgKWsoa#d>|CGAo_ktofJ`AYuiL`ZX}^#U+Y@&m+*KE}G0E3t&T5)k)<Bpb=Bu%s z;izBICAxX3l>{kqohKC3#~1(#H$u3Grq$(F#2$%$gTKUL(3|kD)Xta}dbQ0AHD$-x zdF)s37DZsTd!{O{^A4BnQQgrbEZGzWx~MuZs8d* ze95$b?>!{y-x-Tk^pMBaGD*yEX!>s)i4-W;odO28SrGuOw+jqCqn z`Sb*N6nMK@(qTEGUC?55f1BwNMcQ!U$d6;E{_bwQkX+Nc?Smb zxYSpm>B)qlyE;F}Ui1iDG|BxQ@LbyE_j)`<*pIGO;NWPhbed7J4N|fvw&-0XAuM-wL#3cKM3jTn_w)$>$Laa9OpJt#^V)CL@!uo#y15ir`2-QwctNn5S06upB z08mQ<1QY-W2nYbsYD!rE00000000000000d0001YZ*pWWW^ZnEb1z6`Y<6XIX=7nd zWp!mOVsC6@NpxXsX=5&QbY|4OcVJdU)<1scmZ$gLYYHSlAR&aNiI5;o1O!Z|0Rlu2 z0Yy;}1rM={3nt8`Q(`sXFv7%S1%Iv+JX+JPQGex%z2~l zTcW|=pv{+4XHT0s*|KIYQB91<@W`}@SIj0I1u-7llWE$e*G!#VGPW1dMQH!tsOF}b zS1(!f-a|xo+?P=El!;BPgU#omuMT*>TQe%`71m+6Z^C^+^US$dkFO8TClYi-`u8uL zHF@Hp&_>L6$a|R2w=*YRJzIK?)#Lpoct3X8#FBO&z z6@L$$E#bBs~d~PH3au*}4gHGT?bsuhS9xE9E6&E`JAd9BFAVY$1@1%4jT_Zl?vfV6Kl>5<9fQzyi|Op>mkN@SyU6RncxQykB}5XMs_o(IJ~ zv>bD&7J8)CqFjaRAu*gfEnSg1fi^pEeG2(QV&ore;3bt;Q6S` zmA5Y=gLIH)p`RhLfmUemz&b{y=AeFoT$Xx5cq+9Cb3TP@5aTbGxDFiD4}Bh!eoP&f zuECs7kY9R~g2En3N{3T>rQMjjA9If@$JKRsQ-?7AVO}r2%im9}lD;QD`aLWar+yTE zp)zSV+7{C}n#FVu>LwxIAW`Z*jJt*Hpn14PC2mXTUS0eDA#3-h`th9B(b-wm$9^@B zO6%``%3QDcIn!R%^Z$}p<=Y`IKgO@wezKX{<$unpy*%pEu;ba8+ciI{YvFeO zKV*)B{G7%^eoj4+%_(!5ryK*<78@Y#^?| zOipHU|GYdTlUE@>A~;gV)0w`{WD7FqLv-B!3{c36tt`^QqoFl-Cah|o`(+%L!_Q(!o zFKm1Sc{|EFVLSB__R?T6N+*%WBhO=_l=VDo*3%4N$uuY`Y^SEXZa4Q5-Vsc)^tqMo_>JR&yt_@*Z6sSWM0i`YSfldqqq*&1;_&OZPX~lQ!i#?mvl#lUpbFtxQ}zD%4eLv zGcik^lX^nsK11ex12~8C8F&bD;_+;b=9)}f)InE%;QfdihvM+7wN$9qy_s4i{sLTV zB^Q4#9)Ztt|9*JH9NGND|Ge$W^AKPY)qg8UL$U_)1K z4E{cUj=Egj=mDJGk%`mb8?qQM?aK{8EO7sc1C>9><9Rms-Dm%@Kvko$%6W^bgS+`^tBc5FQQr6A*gFo-|wR< z#C2n8j>_5ZQdC-<`cZrgeDzDJ7w26~V``ujPaTluss#9MA6rhw|}xUwp5S z<#F)0W@BoRW)q(6=@9ycKKPvE3R)pmgD0U&-XC_1_~D66bV8TH zK3kVkuqV~0TFF3$)M+x33DQJnNV6&}WP!Aj71BmFNITh6rwE)0=_Dtli(HUya;Hv` zhdd~I$&0d&e2{($Kn5t7`VIT~Aj%;Mp&X_NWQ3xr6BMNwWK5NDNifb2jWQ$JHj>IB(|%2LO%Z|)4)nYuuB zp>oJ_s(`GZu8>`+60(xIrH)ZIRaQ}V$nL7_K|LUQQcuWU)C;mV^@co$&Pg4mbLm{j zYO02;QOoDid60dm4`g5J3t6j{>!=Pk=%>o_RoS2VLk^(xAqT4EK{NnzFb#sdfCi_& zry;7mkcL1Gr3)d4(NM_YGz{`08V)&vE=qkzBWVQWD9CT=Vj2lqPop3k=wisxR1Z0Z z8X(8gXvlFiCiM-Cr?IIcG=avU+(_dgC(;DSNvfPojgU<=F?E=x&}7J|)Rg*~ra>O2 zW}1TXB{UUsI!%L|LCvW{bSYhe@=ThM`id@tJVdkTQj}-YOvpKO8RX?OD|L{rpxG$T zr8y{HNtZ)jMOUQ0q{P@<@;$Re^QDOEmAk3p`d$047gCsH5Nv-A|?bM$oT zBWh9Q23ilfk)DD4D?JOjiJpUeo?22L(q`J2`hZ?gJV(NW*jb4J>MlVBdr>&5GqgNnbr&l50pw}SZq;09)^cHPT{hfBu-yq+n z*CBV(8<6kNn~?9)TafS34#-{fc4`;ldFnmdP47UyPwztRQRN5p9^{9#3-TlSJLJc- zJM|9zgZ8A}rBCPsl>e#9z4RgEzvv^#ee^Npr}PiV{q#v{Cw)eHQ*YA&$er{#{R`zU zXdmR4^eN;)+7I~^eFk}m4y4|quj%vD4mwOvosQEFDE~}9qWlXTh5VKNo%$P{pkpZi z2KhHSN&kU7MaLme)6c2x)Jnggtk8+nHcHWNs3CAO30E6U8WKfO)@Y16TqUh2iIOIl zL{Y2NYV9`Q+@+&TXzPeOl8}g4F>g+UzdJGY)gD)Shd<)TgL{hCjGv| z*VUHz95P+$d1nTL_{Yg8K?|ZRi!zrQ0Bb;$zhhd7T0yTjrn}&sOM=k0y1bR?^^lTA zr`74XQu*XGk}=%`Nkls-FY$Z5NuSZ2s5i*a2=t9f>h!o8bgHee0<9ji&}d;Qt*q6^ z+-MqHxZ$93Zdxry)#@S8mB|E~tBS_GNiD$cIzAsg1Rfi-IwOYRJ#m$!r>adWNQ0+( zjcR|btg0HzN-syx-@#_lWZ}4z(9)z6B}vvoTXLJi(<(D?2%wE#LOUah>Ya{bNRm13 z)OS_fX+j$54bZyB`UHtTxv`i+=&K524GOLEDM4mn=EJJ zPSyY>Ff5kJZ7G|yawes*+?M#g!JPI2jb1buWoSf1Gv1Q~6REaBM+Tii(sA5r(@@j$ zlIoBEk6xqasDw#XPQlX6s>U<-W>w=xwMMJr&ulgrb-+8fG_<2>(_>me22M^YFL97# zZYn)!IQsc`z@6EuCGO=~t(n_i=0M8Bog{IS8uWUDK@WD}s4$_38;s9=0pqJm7S|f-=2*-!x_nP22k7TO-R4PoynB3;o0eTxYMNl zxXmkI$#h$8)4Y}(-&t&OlbTF_h&o9!19zM^B^7sCb6SZy=-!-Bs;uJ9m`&C^AB4qp zdKsQ>FmiU_lhexP9PXsEaL4bB7Op+4$si$mnT#gRE~>Rar3Te@hv)TE)zEz@MJ`_#bN~GnK|{L3wVf%?6ej5yuk*B zw5mAs@)%%D55(WXutZk7j^hq*sI%AT5g|2g3YS#Om<-U40qi1S{ut6=;&*xrW+H23 zJqH$4CUe%(NftFI=@6VbB;b*HsSPMrYgXC0s`PCRcRFK^$xOLq&o)qjnlqTuf^;^H zp_Dux%};spiLZ>WHsib~in{t+J zOAZqsF$>hTdMncJaA&nA zD^_kaFc8Nd9$Sqj8>c?-p;_%l)uUcj5L_PsR(D4RHEv_=d?38Tqb0|k-Ki%YQ}lY9 z8f6TKka?RcSyscG$z(Pgp?#pjU`5f4wU~`Ipay#dgGy*d1IL}L;?Bsol^C7tSkf5e zJmRuvm7T*~`Zf=DIZL-CXBMccaoXx_NN4jWoH1iV!&xbZ3|Y>@ojI>%c4KKc3wNAX zvz*AO#Af?L)XB14D;s!}#-0V})7vvjlq?o|7I*4q(~?cj+&Em%d>g1Y8_X6?H+*t> ztv!2qf^E*&cdGXmhlNL6NpF@dR-MgigT4)1uee&x+;T>a7K;qxQ_mebbI?xyIiW{Eygc_&CW;ENmsdOM!eO8a0TCI9DteFuN z4C%q36g4byt~B%UbVN?K0l3p3t~t!0f1Odr-mHzEWLe#Sn4ujrqM8Py+AUVI6-cz0 zFgFu$XEex0?i*SYe_gh7r^TMqXy8-?+!^IO06DYD&Q+yva~_NlvJuppOK#lduxrj4 z%;G>gn?K=<86It`QeQCT?Th%zfQ@wg$R$U1W2tWD^4jO|s?DIfkNn5Usnc-NVc)@} z!D&bE1Gj99uTI^L&tRM8F?bBMfUYnk}3FbH8%Br0~V-^#P;Br}^aTv*h zN|%Z28g@qv=RH}>F1OWgwm7-!z=u`?*RCZ)tx%BBW;bCSDkWer%#G6n=WtYGJUx-y zXC&_1CXdZ!Ne|V%>(*_i`JFDzmRr)rEJC)C|x-*g&cF&>J(pK+6%5>8=O3a@qjBqThUH,mkUZX+KK zgkrb5)3Z^}Jd)(dCSRTp+Atlf&S*2+98jsn#_3A$&TcMoBsk-|qux6_cK%63Hrh0H zr@`fLX)IO~?@42|IAJRrhmXTz2Mmp74QEsyt@sIqhcM6@0;UzFHJe}*8wBR-@qjli zHn=|SJ?H~Y!;NO+J=rW?uN{o%wxSJsvU5I6>(Qht$mGCF>D>_@471DdCzi!s$w1@_ znuz&8E%-F2) zaH7I4&0=!#-MFl?Xxo6|^JSHtt4iPITo@x{nar6>LD*e=nG=sKXE28s>1-TZJRWuG z8KhdW%xSUa;VunAHGVqsT4pzvYEaE<&+(msunU_?o5!R1qomdP3|fnNs^-LDH2F+v zCCW}`24K4M&e@es!8{-20Rj6dhsEInzt|ky@&;cv$g5b+JMXCXF27U#fMIfIT^^&y z?bX=q=*i*K+HD?(&FO&FY%ZHqYXcl%D)1OqXyJ@v9|cjPH4vgcF|c~Howd5aJw9Km)#G`RP{tI%ie5?=EiY4c|dR)EpD63YqeV)E^c{aFuRF0YKo5FQEZZfaS?eRG69*^GU zwg)_3r`PRtcpO0h30q0KRmXk9ZgAM4VO;>Lbl{9_xBB?5NMo?;+JF)Yc`_*n#q@2? zg)st8ye?-LZw%N|Ush?*lS@IQOgHvi3I;Pg+E%4P){z&V_{wxTlR8pf%gk2Jss`1( z_CBPHC;DMhXE6BtuY*d zyT@;bZ+kFxt0|lf@+O^0o45N;-}@q76?ayT&KEET{Xw0}ZHHdHdbca!ad|z^n$zd> z>YWa&9j3Bd01vwzI>3cfnB8M_d-xn-6fXpf5RH1>9;XMskNYSz?smiOsBt*`PSnJF zV7v%7mDyqULM1kb+rfjPsvx`H??fE(aep`4_}3$!&yInB83br-4T)j}HsUeG;fQkE zo1HlQn%V-HUeAql#)92Fz?O~ta?f1G}K34>2z&6!s(>b_r7+p@C-k}S_Nn9qo z$!P}yZSY8^z6~hRXja)dE=%9$aEB4pJr9yUmkNMA^<|X?a|ZK8kTTu0%{d&-@Ms&& z@@CF9PQ@rH2rc}XukE#ndSpOScZhlI14#CCtPcVl?r``IQK#3(%zB6VH3teugp1i! zB|5c%KrB5$^_(Ni!E7qX^Fdh5=`q{m&}Jel=o9>Lr8t^7V152#k8>dJpKv?epusp0Lm3_d#p!pgRB<+MRkBif@ygDB0~+7#9@gvw8h`gi*iS z?RWUxP){P^_xjvExIQWq&^VmNhn{@AC!af!41_(txEF1#E@uEJcc^+qP_&2aE=Mqg zjvPV0Q?hb4(t{oxPP@~GJ%QWquoA@!?ZBM@>=5(f0Bm*vcjkQDaf<~2JDxMEqzoJ|%n`z_ZsywR zT^t=5N(ymOibV8(oZ@B!rwp6k#?fbw+f^mHfV+4GcP90a6UwH-+&Eq@--vk4cE8IP za=M)!J~_KN?#%AD^=j;HOZ+~ROykb(*9RlkXgI3(`kWrOFJSO_BR)^S?{T}_Ay3c% z+`04|$S%9h1>8Asf#K{_Q8z=c0O647OC)f6X^J)gdQ74R%NSys`FfSEajofq&g9Cd+ zyR*=#D$%2hL<-ZhQNJB&G|_A-$@4+%oIC-m6EKNFrT!3f>9iKQv*#m&l}GTl^Af+0 z7DxEUF}*Wnh{o;7SkmARy8XUj*ckLDg8p#Gj~Pe(5u?xR^uSae2O_TrC7=by^*Y@l zXCP#7d)y(6?+*H4gyP~bG#>N^f~YL^ab3gih~d1akiT8KNWvd13ZRYM>kdODZch*z z#{SD0!!8W;5_Y>eC3x&^{&_MQl>ZEgHyGI2Ia zgd@>t$RCTE;6O#ucqkqT2BLv>zzYu5ez(yV@CJO=0QTixW0Bt<2-rL}zXu3(Tl5yc zDGxyHv&znSdkiTW&4mt(kY%!XE|tOVD$qFjg>nXqwnNH5u#E(ZiqxqGg8p0;Z{`o= zZH&BLbqB|BA8Yf9;>;1ku8jI4G33 zRVDiMi9|_Ssr;)Hj$p}bD$9)%4#(q=c6ZDlEdalSqR^$sUgFE1kBoNCq;2OVexK}+ zP=B4{iJ6i`&f>y$#&EkfQKrk6fn1TV1AEv@K$pc(M2MA$)Z@}Y= zxg#+n!e}fMiuCOCxCG4EW+u ziPs;6h6BJK6yyWF#JxUF3E1d)pp|5j4+PA_{XuLVh&pxk5&RD=JH+6I&XCz@cC-aJ zvl++;6vpC-L^PO8SOW1tNunTH5RZfs;Zn>7N8^y!6bJ>vL0c$fG6hT}p-?!4Gj_;_ z=;(zew-nNjdCr%_kB$7sd!Y@mC6RsRG#JoD<NJ)w5kCNHk$!US!JRY;h zWCGQ8@|w+j3WmbMPU#7%-;Q*;qHOA#=Ys_WkPa_kQXB{eq6tjh=j;^7?t4rQ&ZKRL z-xqZ*RDb{DOPY(?yGz@Znqu)lG?FN=#A79iXhAX>4gocVmPp7KG6h3HZ_tO>WeWIl zf#H0?q%WT250cSnK_C%<5xR6Kh$kY67KCd%Tl zyE_~#gh~RT1m+*cj;x(86ew;NDF_6L16Z~@04FpR7vl{d-YEznUb~6Pdjtr4jh3Ag z7OT}2vEWeMrf`b|CJnbs6ciT5BSnSQP(iq3VR5{;AQml*mBnK*yVD-=o5S2U9MK41 zYVH^TIXVN*NT5AP1|Au)v;n0{m%>cSaT(WqVPWpe4MyOJzfzn_-GRMWnixTYg}GFQ zltFYGr*`V3PCXin6bfl63itBZVbU zYN8Oj47kd}*$tot9GbW9RPRf=wo|{G2Z}81J9^7Hl$jF+p?IvY*jkY2SePg-ipQd{ zl6X67EE&2s);NjyC9i*m89Xg-b@QgLlT+kdUid#hoyv|P$ldTb_)B& zE5+-@o5iK#?cxgYPvXPk6XKKN%i=ci@6rTmvUH`iJhC|QpO`J?js;?oSRz&w>m2JD zJ115fn;p9|wmvS$opEnG5ig2&ijRnoPY4N3!kTa-+zI$wqBPMz(U_Q0_|8$`MCz23 zN?|r;iqSgE;-uiiEZ)K_{wdB?XR#QwxD&HjDgGI=cuL$VZkI@!Bwa4u9a$JThFLgc zh!(&mpGA+%Eaqlr;mOS6qWGB1EbN$tKR1ge%z|MSluD(3P8}plea4lhY(<`rJXGng z^i^t+`?UV1oTt>Zeyvoa{v5@m7+O!ae#zhd;-2ikqWz-ui{W1+zL@q!#TS)dlz+bc z^R1sR`h5N813qv5d>Vg#;NAnb9JmwL$;j6pn027$K=FaXeIMD^>K;k|3t*&$Fj`Nc z7P5aj|F{%tbrsZQ4oi(7W_^ z+C!hvKKhjQ(*gR9zNa7QDE*5R#+blFCNY`a!t^Y_f-J-$tR3^S5^ARR=n~pRm(u$* zi$0{;^buW7|DZYaG0mla(v`HAuA|Rs0ewN&)0cDu9i(gNGwA&*T11EFM*5m=qQmfz zZ)hn2(-kVS0f@X$y`%$lJp8Ir0uLd{f*vW9q29AiQZ%#X$I}4%jg68 zGc(Y7=A`GCm-S%1SREV0&Syi|xoiMi&Q7t@td-qEud!m<$_nUJRz$C}QZ|7#vOlwt zY!qu?7qfacnl-U0Y$CgsEnwHN8`wg&h&{+|Vw2eetb%o6<*X~KB&xZ1%;<)ZBQ6>~ z^uh}U4;nb2|M~suYWwy%ucrFkb9(pc*`s?^x5};+psxLyM;L>{o`gh=sOeaWuXl7^`cM3h`fZ;KZhu zcEjuAN!veyx#taN(-P=gACCuHghKo`0FUtBz=^S@7TZwN$Ajsb0WCDNp64y8FT10X zy2l$Jhu616vbPNl|80^lf^N2*HO(PxscnPF-?z4fTpP&rWed6aYe&0N3-xYkSBi<) zP*QuNvKHn#*20`E%zXi-eC80m+2`H=iw^3VrYGx~E`dg;OmA#c>d~}HoDECr*STU0w1Qnv@VI!&{^H|KHMf{IlHNF9MGg%r)Js2Sj)mm)6?Laczf0X;!ABU zreESgzNzEpQ5$Ad+0;0lPkH)8zRbGmv8BtVs7t+FT^axztD9cSGj9m^(@3-)U0>In ztZN$(3r9gLJiBc?-r_Ii4VNyh<5Qg2gxRO3j0bJ==S~qUWtdOjmYNajg+{10z=$;y zYa23EnHNU$X8cKGZ9_vmZFjudqAk2t?v#uz9c?vCOgAZ}^}V=ddx{l>K7O6VuF6os4%6#_hRx zhW^pxj8DQl;3M28m)gF^>`b7qV5}eKqAj41V2iCgcWF#zWIcRlvWjn2z?UvU=RxjO zVnbowB^PDX1>|PH#Yu8lrWT#V`YH8qU7;Vo=DG zgrLYvhEh;n?-p;V+K}r6l)BWGjJ=<1v6Z&See1UcdpE>vc2FV1JN-+!hkR(pZOmXTe_5Gm(bW9k*M@g&Nh~jze&6m$@)f?P z(qD$w3;S`u3&zuL3~XqzaPDrge6I@3HwbqCQ^B)`sfAcwteG3TCDvH0Qbt2Czj{mR z^Tt|Ek=%)5e9mc*L#9=GCe}K3_`gDYAt1i!_J-!3=%uCvD~MHMSk+%f)MvERJ(%$+ zKGp!flrx{_w3vNo>CyqUsv|G8#kT{g0bjRbAiX8TXy zpI;ixzwLk4;{n;n1ohZC^rpvD->GTLbbH1FM1h)#*^!6WF9=@CdveeqHfRLs6LGT7 zh9p}uY(ouOa?$Ae7i~nbB_rxL3QXwR*r#Db0iM;r7{d-rtrd7JujDr|e#3hjjvJl& ze(=Q_oFCMul3JnOPu{{vt$ z;gXSULysI?|5p>CnJO_*AD$2`ea*0AeG=epYN;7oe_ccK(#8f3nuRdUP`DxnAH(Ut zB^KD3q5YPIQci}4Izoe~1D|`mp^rX>n17uoIR85To)1vIY97SQ*$|h`f|zlcCphD> z8!ivbz0&0lO`8re^%96F&92~-=EZXY{wqA!_VvfFL4M$VP3h|U^`-Z(w3V(|t}Fc$ z@(Sd8ke9D4FI~Hm;TbEvZ>6^MUgT9Pb)~m0mP>Cyz6JSaE5x4Y8q=<2ps zxJ~75eHXW;vs)~4Qzv&(v87$HwWQS2q12j4S_+cZNYoOGT7UTQCzI7?H|Y&VlSZpE ziIQw0CYXXOZ1!mbX1C32c1SLBhu$T<+x0H$T@x<`Z*4ETEv^{U}wNzvNzw1xW7cz8spFu4;1Y6zE zF)e{4Zr;XCH{6(#eMo*i^&cX6GbL%UyqZF1o{ps?YF1!dy`SIluLWtT%sTtc|NkX+ z9_x$TM=d8<5+_{sua%*cJmWnJvK4Y4ZqoTEeh4St|4%2eW9rA;&4kR)&9shwU~||f z!Ue(v;U?j6;gF~m3&kpNkk}}$6}L$mX{vO;bVRO^C&@cB5zV=pCe3Y{M>RXOM(uL# zYdWKDsBW?DCEb_$UixPJ0)2~qul~59o#7(Ga>Luk_QnOquS~M(TvMazPo`H)2hA39 zsrfwfc=LSo?dEkBhh?I|o4u=jhW!PH;OOdD;rPI5 zadvQycP@5rbslnccMWu{aeauNL#|)lMt2;valU(udzSkHPr@_DbCYMK=Sj~ip55M& z-b=i5yf1p+_3ron+b8?{zEWScZzFU{qjw;F-W{fjxmkfm1LNEqRz@C=yd2pRITZOdYK%ss716t+k3=^|--&)2{V^uQ zJh67Mp0OdZ#@OYtn`8IIo{jx2_EGGc*y;E~iK@h|#NNbriB!^=EKEL}{A+==;KqVK z6+Bk(Qo-K~zAQLis4EN<-d*@;;g-U83O_46R@A3xRME7etBaNutu6X%(OX5I6uXPN z7Y{0)P<%`Ay~R%!Z!P|@9kp|`D{9xf-OzST?XGIKq}_w?=5|*^py_A4)q5w z$sMokcw5Ic9iQvCz2nCnk90iM$=oU4siISLr$L=A?lig6u1sl2=LnQjH$ z?(6npRo|)&-L2hk>;7er9zE{rv9-r%J-t1fdS2agVb7m>HTQb0_qn~_KWD_b?A%AI zlhrNN+pB-9vDXZ(xwYoo^8)7$I&Z>x3(s3}-Y4fB=o9Hv)Mr+o2m2^}`}MuI@29oB zYgg9(t4^pZs~cE1t8RYXt#x15o#hTp%K-0y*nsu}$_MlsP&?p)0iy;?81VOjB?DIsd~D#Bf!hXt zH1L~2mO=4BT?d^%X!M|&gBA{2G3c>DTL--{=)FPT3_3dK#9$gcWbmlL;|E_i_~ya4 z58gKT?ZMv;K6XLuf_4{lzF^q}D=zrrg5yJULjprehnzFy!XZ}^*m=Vq9`@$&4#T?+zjpW=7l{|uU3C3Ldq)T(hK*Q1;pmyx=W zu92~kGe*uE`Oe4>M*eH$p^-m~>ObmFqrMpR!>HdbmM<>9xaY<5F23R72QL2X;;-uy z_1D)wS^s?fEA=NDs6p3YYbbB%+0dt9V8bm9Up0I`+CO^C=vzm>GWyh*bH>aa^XAyd z*zsehj@>p+8W$Zmaoi>29vSza@&56J;|GslJbu&o&&Gc}K{LTJ!84)TgmWkCoUo^n z8mk*GZG5!xz{JSJ;S(R2cw|!Xq>4$^lOCA#_@rZ#PEHmknByAwDOXN;X3E!7^;1iU|GiEw{PL?Ll9m!wM7?T4(P+rx@i;?8$)r|vIGtKC z#Q))};LwOf)w`;9*?W}jvODsGy#j?UotZsuS97_??c)E=+np@#+O4Wvx5}+|}Xo%jH*3_CbC^I(o_` zUGt}_htKHMyKa8FxmQ(1FRbi8wQ-W|w!2QRzKw*`2_m5x@mMB3xoh-#Q7_6mhs>zD z+R>v&8K09VCWC?)cM8p;KDn!W+3<%-rjgz0S6sm02htQQGP0q))g6RU7mh!xtT7Fh(7@my6=g$$KfR0)+mc2w=? zzTUMlx!%38YDd)@J$CeX%KdENQ?6%w&Mn-LlvgWQfHHlHvL#($t59UCS~n^R|DBF8 zRVv-6nNP)3M&0P*n$mzyS858lJ9dl3Iv1Ck&CZT)w=>$=<8*dj-Qe__I$}A+#T{2S z6iZZHYNv_{Uzxo^E!pvd8*b^GaHREHq4jvYE^Qn(E*3p7JjvQ*RZ&r8W!&xZc%7Yu z%B}^4j2D3cXE_H$vGCR8xaL3M-3}wl5%9^ zus+r?*WWblw!xz`^IMXCf7t8sRFC&5t7_kT;B)0SdE*xUuZJDxYi_Wy$IhLxeA;_I z2+G)VhWpvrDW?ZqKKZ=SactITRq8`+p}YecvBFBlR6*@(oLxepQpw9QCu8Oi8y0JKHZ)6T;A(<$u?CKC*o{I7en%N)JYbKp~euFgR^kok|cKD?`ANoXF z*{yzhRfqAHO7kCl;@d5Etow&tSvmTWs*d9>m3N#p$;a&v-S?hy=-E~8F^j^g&p*1P zbM0Q`)phsoRt`V6YA3TRtft?o1!c7#V+HZlLD`SBM5z=uJ+~%ew^&>TZFzZ_!O*p< zMpH(~K)}`B<|uPH+f&+GtJ}FHX;pQpwj*Y9Ycx9ZDoYniPeM6KluIS(Y!1MQhJ)-ue-p}k-p6EQTrsJHR zy@yT1G4Ofs{XGjpQh;e7X>Bq-dmI#mMME$zd^%lp_$z_>lYktXt{7i zY{Hx^bWTlJYtu6RuM^D%{;ySaI*n{JnFRi)Py`E>Q?{$T3~rSMTbo-|RCMR$Q03Kn zwZ+=vs^Thdm9VJGiO|n;SIlXd_rhoW4kYDgm6K(U6n--F^Bq@gow0KE&s<;CV4{JN zfsEvQLE|tQC8pDJ>H+aotK9776c(?H+l7tnKBak|(#-CY49X>HVIR8}dRVJG#ioM~ z4bZvXVIZ}oR?uic;#El}n_gPJ#*SSqa{?{}4OCV=9vsT$!%X+C~jQ38b_KR`Y zLxep9r00W@xgZ+mM@TKnn-t)G0W8^Gh$rR1wF zC~BzHy}iOsiaOS zJ&&_uM&GdQOg!zs>6#DO!nO04>{Ax;74HDez6tKvk*CHeOZPX(vQF^nG-~uI;{&s} zGtN~fzNzd{-g#4br0n%i`^c+LP8A>7r@Qq|tn?{ZZ64+yp?Hlg6f%;WWYNdxmQzU=D97tS3xvy*c2q`dm5vRf)| zcXX?AN_q3sgHxtIedE>Fbw5vxB7_GqzqPQUp9-mKO+b36m?ly20fq z?ft(uB60dj!_4E2rzew{ri+pZvfC&>&IxA975sidPJ5umPuI$o;$QCT=jdFMiQ=jW}}J>fp@wO*xcW@WTK&QSj5gXk%)yXC0M+l3Vyffz^)17$Mxuu3xz6ZHBu%BR`MuV zkiX_L*8lj96RWSCuyD2V)9SC4J6w*u zsqs4^5%>KKdI4mtYPckJBO zALm~G_;t-oAH{6J=7J>I)IGC(vsTawq6VD)Mt0{NcRKmTTj~pLU(X3%vT=fMEluya zd9=y2w;&#v9b!7(@OEu6C*AzXw!o9^+>$!_ zyyzs2O+#hfcU5;+&n+;vUU0KYCiQEz2}e);B-zC-%E!vb-?25v*jo5cHEop!ibK>@ zSvG-f)nHbk#xr-kl4oh)sh=g|sh`Cm`}QdVKm8QrkH`44GULkvVnZHaIiOAUj9Do(Qm+ItsligKJS714>70mwDPNR zLfKe9^v_Se%_e;EA!~g1^roRx-{c{|@>OyY+K_@ov)t8k4~FRf|N>oxp1?9gdN z9#pFBnQ-rni}+zq78fPcab>ZZ1s#~GjCEh%bOqFu;_KW6k2!Lzm(J1Pq$1NJ80nPbLY<< zJ_2YSoZ2sMg8hS3SmUtEcG;qHTUIo+`Y(^bs-Ou`rRbENq)c52EY&tgOhmW~#U8>x3;>q{_vH+~}1G|WI zJ;By|o<8BrPeDU^a`OG1&bYim=g=FLH|WK-{aq~0dvS)Cp4r-o{aKjReWcv@@7Cq; zHp3gKTfSNH_}$R`r^>g=cS`ea6px*rdNVUVx#?NH=j0>Zijj=exh5!T)-;f469o_d z`*B8tc6o!rVHB1(7|*l^;zy}USt2%Ms`2Gpt4<#}PdHH78XF`Q_dInU-*+j;lpQCP z`;}wpKRwbp>Y9KjK9VTvu_&Q!Q5igCyJhk@y;>{I7cQ@Cy=#&38mm-$eD-APqr5-W zTA#pLajLF~OHz=W4gkl=ETYp%9)~Yz3Bq_mCuz?zp066t%a@SbVaCX-no%QU?N}8T zla<_uGuE8Jd~CR&yr#Q%>Fs;xuYdTl?VXfoD}+m*ct`5<%3S4r<;gv425kECsYUbF zDW5*_VQ`2dS20p)S_95F z-$X+P!kl@+(0Qz{@~*OVaqEU#lvlVOT6YUwP7W02wcf`6Pe|0Bg*ob}5hn+9mN_}_ z=E^(iCMO4~R@j@`FD*vNO@SJd!C-ew_7x41)6JW-DMZY$mwHCd=)@^4-q&9Fe%HUv z7FKAoH}o6d7csw?;o!pWx; z$3csKlj5BnnIj1mY&(?xAu~v=tAyisO8b=ET#u*rOUaW1rDdn)2@qH2#?c6>W&JfK zrZX7NuqlX=^B1dds-y4$u3>jbdss0BcvYDt?ZGg->!XqlT??la-m9P@{J45P52R0d zD;l)mgFHB=S%9DNGC1X?qRfT|6jaXYcPfASmU9m9d20Q-51HoibxZ$sEui{>^6@EU z^x-V)oWA|Z_t_Qye(t?>%DxN(%~Dt7;{IyZt!dzYugYOGt;w-L#$VN=kCaqBHp|80 z^*=G;LFJd*l^L_(x?PxMG`sMsWpkV5&3pE){{Gt5<3OY`@TTj=j!Ca{yt+~+6;rR8 zuvVutXf$Su1Of%2aM)X5_O56!JE`DoPcEylXFnj6msMo7!M`Eo`EF)Yn5@cu*U6~n z&O07l|FkgRk+E(1Nmhq17oJ%(WO$pF{_&o2%Z)8}zY#CUSC!GY@XqC9ep#5Wuhr03 zjM`JO#;yt1Bofh>!x44F;%gdW8I7qi^LNoq%Uz5!P-WMuY)ETUr6j%f$xEyHU&#NC zm+}_>YY9!$l%3Z=s};;Ligmf=)oItsn_tw}RF!OC&tDklzW zeUoc?%GI;RH1N~A0hn??)5UaQO-GVyq@j{1c_lA-fXsNpV`ZW>fx`ncYAh~th1N8< z5dPMjsdtd4y`o|Q7vt<|FdWBqFL~o>{qp6cPr@)kJa-N*F5pKC;YTL27*lpHx&Def z?p|^HJ>^-Y6%4wEb$RH)s~*1UDdp!ate?F1_(AK`<_V+fCPcfwx(Sh=jn~bd zP&=k$-J7dEK8DrI%IqYxq(_s4<1HN z)k{w>3wjuWJs+v(MrVz|pbIq7BFxesLV~~@O+6(!g~rG9iCb@fWL09j zz|MR6+~<^kzsrxM7W+nd^XVf+54XEu-rWz0tK`#rlz%F}%|E!i)0m;yUo-x@avATC z4kPNd4km*rbn1W=)mbh=_+uY8Nz?W}mnv_IK8`P-3sLKCQ!*ZH1E3LwThM1MHE? zPJJwuf`MG8zEAVo9L)7&l?7}sXdHTnkfk)y&}(}Aj`T@E?U{cbV>|Y-x7hsF z?sJr_S1OMnEZiepcKV9ePlPJ*2F&gW^tDLcQN(I&;9qPdWW-gyF0-XjF_1YVVxGK9 zAYoDE>0+@*<*6=J;+|G#FU(RoJz6=&4B}djh}0%!nK%RFc87Q*Q-kQ;@CcqPDR7URE_g`1=ZHHpIg9Y6|jP< zeXP)1=@o+Bo4c?szMVc+>|?%I0a@JE5{D;-FwECjj{TRt$2hRZIPk}~vT@^bbeMKG z&`56oamEp^Tbj$eRcZM7Pq=*VXGYUFomQ5W{k@+Yzi!LEUDflems~P*OMmUuitq3K({_a zuDQ$U)f;gZrtX=tAWPFtMfMYydI$ts zoP5gZ@2-My&ZSbnyC*;YwzBKk4Nu3Vr1BruweP&KOP^_;cF&W*_vs62j((tgqg+2} z;$!g0Bh#*Bh7FfrqkIS3@Go40q4Plg>11Vt+e5mQ4P3QnpH6V_bgN&qa=Ti7-YlxL zVXwHi6*`+R`HnTyCJnnL!4mzHZ{9d~ob{Kg-+fgWGg3LW;j(KcHtpH{)j?48m59*( z)Im84Z8#~)wIR4AuhzS=LF=)HE#Z|77Mt_GXag|Lev5Gw@PlxLljW&Hj$(8AO<3;y z#MBq|Eoaix)BYTju57KoeB7NIXH2{6S-xq#NgO_G|66}!=eN`k6Jn=+zT{>WeC(3z zl%F!+{Dwj!Ud-vdnj*5;EJH0K|BJ=i8mlkrd(9`>MW4?>4&%xOhlj#v=}A4v1o%;Y z{J7jF+_?5EWr>-fCQSa8;ly(KxN!Z9n(3WcvcK}%$NNvQ{&sd~eDmacr0V1UD!r&( z_vthGUij*BzwBiec7sx@pE2_??paA9alHIG;!FXo=eC-hH7={jBrRz%E6TD}bzoOT zd3D-&T7D$aYP8z)7hC>oQaFRKu54^Y$MTSEKqBEb>~6njv$B8l`u5M-JCCfFU)SsQ zNbtXDrLUh}CpNx5@T1=SIF|Qfleq<&3S)QDu?Dd4#aA}?%w~IyAt+nLVk*w4COe7p zvfS4-SPh|1BgLVOGe5AM^=Y){^$!(Eapw8B0|Ma>@0@1I*+XXC+*RtaykW}$*3r;B z_Vy=dHZ6Kws-8UNk<-S19NGNn1%n>hEe#srgIPtMzqxRlaOQsH&Ue_oE|t1$x$@q%mKDnWg&Om)Ub7#FTm|~V z`JnY!pOGtWEvjv;6Q&310u{Au?r!}MW2L|C^~wA`+=ml`TWh^gU;+%qe-$@w*Eluu zY2#Jux28VblzrWHf2r*IQr`U2Ps&VwG(ZQ+ad3N`+KU~hEQ?7Ovj47|UD!y5Kx##PS8=p?}E9`vHIUNHZX1ad){hKuM5vlfC@!O1c9#PL%*3DX@TeO;( zx`E&t@uuUls)TbMm)OH>no`JY%J%2(?T__$#rEWDi7ituYn{dRE>fOIM|!^U>g);9 zt^SVyGAGDtWha_-&z&GKwq`G|R7&k@+-85FyU40>t!&WP#C9=?wc&^p0pIdgWKi_q z4RuC2u7x?pE;DYn_k5@6_DxopZka6g>p6Laf1a{$sVoiXHfbe_`#)ozxK#6+R6X(H zQIqbuw#$Il^Mwc8C6=IR7Q7`gd58k}EE*rwl_iV^kyme|oAhX{^wbhunEQl;$1&8wQpYDFs@fh}`#m$PJ<(RzO7LMiv19Q4z49B8rI0x)qT{ zmSs^{uXR^h7FpMYX8NC*_mU=UQTO-xgDuJP`)0oLotf`^zw^DutpWOjv*yDe(CU2# zwzAKl-gHO{K|ESv4iR~@Ql*KcA_E5Nn9yv6C0A{B+dV zRq$I(g>Zz|DTJ3+z$?fsGb+$YsxTtfWASn29(ZBCgKboS%*N|*Ko>4QXlLy}4llva zMzRG@4{N&s(p1wX4tZ+etkDlV-IsMgFna&p3E+H@>((U@3Lf@Mp1El0XOqS(UUEfT z5zGQYtx!HhZcwOLMy-(&86_P%MF==Bab3#*(}syMB!w54-BGI!#*M~nK%Yo+>1S9s z!@zGO^8F`a3TuCz3Z11i7slxo zF-j%%K;-mDI#O?}4;mRn2N4Wf(0{}%j?^nBmXU;+5^fuP`W3O+5RVhDhDD4wbn54y zz}w8Aehm+tSh8d>{Oh0Jg!h0l0CT*=TUrSIXiDMGHwiIrmVb58KOa_sK#hEvmiV|g>WP`cCUDi&nTa+ zB=t&f_|VePi%Kr0T$m(flF|&>(P{GwTGw*H551N0Mlm-AzIE2)v74l}7>2nan>Xtf?|APqP?>lG1LgWW0eNAREJJVoiPOW?edejx->K-;b+@@lA{iMy-=pAE10?6 zG9TEl!|(8Bo%QsyTKU7Q-E+d#6zVG2`8e&mcYWiK=Jl(sQ*-IDc+`c6Q#7G|v1AS; z21ZKyYxi9fF?FJ}7d39A|L!rR2dlbiY*MUjWg`)im85va z(N)e4K9$}Kfs?gg@vOggg`Rm0wRjR~Yc)t?Nv6X25LrxYY_cKDOec34X)wK|WD85Y z*DZoE#wE3h3x(_)tZ5*&?_z44liVdCeKilws%Z*#%Mw$kI^oYHD_Odc9bOXKv{+pi z{_Y^8^;M!p#?7y?9|h6O;YnSg-c$jRtd4w~+|vlb|JG6BrgBY}rI7 zLdXloTQVT2JsTXZT*}la*@1my`>xj1hkwurJDl#mjy$#7^!Ts=^(r^pGTzBuT{P0D zhC532vdlX6C_Q>0T()@YH}aeskhW}|Orjc8WG@3*x|kY(wa;;&hPBaWC?nzt3RbVD zO{?NLN6cg+AC~nkH>(bwba9a9ST+ zDJg8;6F=GyzX}mQl{Vbiv#s+!xGK;=;7m5T)(1ziUO2ScjKsUu&0A%0nz)Dvdz4+d zv)OJ}Gf_Otsu{Uft!3z)%}CMryPXtF>%#S_z^~9^VgvXwi=a$lLm~Dm zBUcu_VXG9r2Khv|OKi!twAt{4}pTjLI4X=TbYZCmdY}k?8us$D(nlU zovgc1qsF`L1bZiei4$OGmcUpex%SM7ul=j5LICUKF$W(?Idb7|{E-kSd=Xjl3 z)1B=(=^C$dbgyPxbf)B69DQH2?g;qiJ+)O`!s?S%wapt>@?#3pq6fyO z;u%xkM_#{KvD3#G}H^m19r9GX9HnxNqg3&w@OE96U zL!c`-Md)fUMuhwGhU^`M3b5^}&^bFMk!c3K6&N ze7t*~wcXD(Y*9pe0NdrQR0(g_>vWN!ygGojSY?rsh_gg$t@MUwD-*c%F<0?thd#d2 z8(ZvQya;aIx{u5%p@Rd93G=o60oM26hDX@XKxU* z{U9o){!!_ILfFti`3FOeCG#Ud7SG1* z$wCCo0(;f^ph{=JOj&!Z-WtgEQH8pMx_*J4O%0a3a594gWk@2 z;{Gsxc}%1wJ7RFc;(;Tk{cikz!5O0P;XceDJ~40jHOf>AF@g=-e-QNGK4;u*q>TqL2_y0g#{-X?0I15Q0+h%_` zpUL!%*$>;k;6u-sJx47O;jydmfu%q$MZ%L+|oo! zZXs>z^kL!MdCwivce-#^(K3Qxq$N-;@`uTxEx!trM`w#Nku9oce>FZhH=Rbt5SM6; zHl+rPL4+;z!4}i`q)l72&~qT1)(2Ng=l&{w6(W9-w)ogzqDKwApl6>HgZ9t+k_p^R zY@wq1P%XS(fdt~vNQWc3kJXwO9f9QGP!$&BkRXq%S0!$2mg#^R@Dvpq8oi-8RE)qP zqFdJ|zW^-1FrHAU-RQfz#PXTX$b_S=fZ)!hvl~T+7>7jP_z{zwhTUPF`RCvZ4VU`# zxdfA>uz^WlI`9&ZgamUpTTWNMIs?1NG!A}y=({y%=3qCj zfrC65iFG!5Lw3$?cnvn?=7QP(N~*I`gnyv%6FT9%b>1~W{CLpvzl!LRMAh<1K_TcE z4^juAV>~EG#p)wBHtTg7xk`@o11%$E(W%ZdRD7U7+x6Su0}uO_+PahmVwef=ddbT6 zhI}v+7r&ijVU@WaOBua4(=(z!eLL@7M>t#j!PHI)esTd!_-WgQ#V;pDMHcK>z2@p% z?rKy0qrO9bHd|8$bPr5laR`3om1(w-v1f{VdM{aTDanEI zkv~iUxJ1@bQgR<>H~xx!X?$>XU>ku;Lj&?(m&BKaw3j9Jxq|eWl-RY#yTjyx9i*+q zq|}sOYO4So@yZe@eq5H4A>6S4OgXiLw|o6(GTBVZ=mzd$p7_u3qW_G63Qfby-I~^? zPfA2Yj3LV5u&eESOu8Y@khhblEjzn=H1(pjbaS`4zqgJ3S2UQ+U-!j14!;ZM1x4nm zM@pxp35rZ=3|3@j{Qa9>^3nMW-mMh%nQ%SQXQE>wW05|y)&i(6108oTy#+e@=v@cK z5PCcNWMul!3-RzF^O7yj%TWRsEK@21;81&0$(qR)+hYaUTdg#wCHfxy^sYxs-+cEc zpcMVas>rErq+)rUO186ErIIUva%VFD3b}AncU{N`0;iwHozCkfMo)?d^1FcA1@Enc z6DqLN-Pc3GfCZ1uo58ic_sO5Oe?K3dMBVeS_Tfb>LoqFg?-QYIj;NCf=di`xwST(9 zQ8$CuEq!FCU*&%w%CM7TSQ9WIVZpt`e2KR{I573WfOW1gwy)q zN{O8C%lK7@_*tSHF+JNl?}Mun;S!t?Q9a?h+N+_*^~4SPmLYkAB9UcC12>yYS}PwG ztCf1a%#sB!Gw-(ds%qUm&ZNCawsCR2Iicmh0z1wPuT3)B3ygy9Hg3|NZ}jGo_65AN zh$$K0Cn_#Boak|-D~h77zbLqX?wzTwUJ`5fKm5u?{Ic_ki+Z#rneKzD6m_K1>Wn-e9K{j1H0cO2 zD!zoOqlWSsb9gYF2mC`BAl8-XqO)C(^aK4e&SwBe2FNJj&54Gjid3UcCNnePEXx#_ z)x>$u-R?^UaUY*H-?h20YyI!bb^ix{H#Y6|$D3=$EL=X~fu)Nz#c3ICJ|o>7|35gv zNk`nd11~KZI&AU6mgc2bvWiPH&<}j&e{zkZJ8vV66np>WQI$x_&zh41rssehn=&jk zRPV?sqD=Z2bxip~DIhjEGnsZKKT;0LQ_iOVM+!*EP#TIH#thLF(CtSvjVnj6G?Kt@ zS1)dXy|@j^`cUO@aZwbGn&TrFg*y+d&wDnH z&dZ~85k^Z(q)J@iIw=COHKE(Ze-BK)Jn2h27BdnNqo+^YAoO22&KwfDXUA#Xo4sDAWAA@E!K zJ+^Y>l=0g_J)w<*htI7Fi(fHr+&I=F!`N%?|pq2{2VA&A=&T9F-pk?2s_^dbs#VdDKro>z$6 z%&U`k*)zJs)U?Zq6b_)$?%2cmEPb^`r!J4w7@>GS0>sE*ef%Ksuyh)Vd;1> zBh%B;Qcb2P*gJa&ImqFidj-MabB1wKg`S3|5?I?{t)@F%AlKeB~FWx5Z zpoli%Xr8VRIl5A~xnhMA$R6#bjo>r7mss!|R5ovx7=o-JR_sB`f-pWjTx&AKYGXGw zYt<&NQ=djFnj*UVI|T2??tY|L$j%P*CAIFg?ft2TJE;r476odo{!XRqcifxn?^gQn z9qWl-X~grQUuigrN4`zjs8p(s*F;1{8f^@YM=>Vrbg`@j&#%tHo6QPN5sUqpaK;ri z$D%_a2j{!#(&U6m)%d3$F(Q>cRBF_UR~Oz0(YQE=)Q;!R;qT@|(-Ue&8ru8sA31Fk z{O;{b=novM~&D}J#Es8BiwCEmU{Hu`jPOvcdo&;XaD)< zJ77v#F+Fr&{**Zl;c=3VnyD)uxj16nYv zJ+IO+V+Sjfi?^@y{E=f@cdQq)!hFx#y&ktJ!Q&POseF%Jidj2$DnsMNp1BmE@!zo( zfhzq{u#j|74nth%f&keUdx2nRKZtVZwGsJK7PoWR4=NXWZA9ImP+RAGP(?p?*@yx) z0o>kgGV1~)PkC)bJ$qg2gDRl{ut)Od5?CgBWk+C7M3quWYeP6gxFJF%q)75N1c^@7 zJ&i#=f9;X;VjG9b;xK#2nc82t zo1!{=b|sD9$|m052q!tEd=-0t%Y7bzVr(sT{?>tShf2T!FdkZg5uSN0|>+3xl#R>ZG|j4N9z_1dD`b%(MJ9fj8y zY{=a3IM)VOuK3T2j?;ARw7b*jl_Iu7Q6FAxk<>;kQ2y8o(FJ%u28idHT)Z{9KTJL- z6TGd=QPv*(i0p>}qHdhvcdHe+Bk&9(@z@9JondqaI{eS0JS0$H$9xAh0PhDx&%wJf zoYfu^+5Oy_KyYjj&u}#vhbbcP4D^FRW7YmDOfIfpg8GXv39@crf9HH~MMTfmwAmeI zYgkgiSVh>AK3E>)ik?HJh@Ne(^}&^Z>|e#NT*S{58QVi9xa9{|4d(aklVUnAbY5T& zu=P|J6-^~$OI3(c8Ducq?NP}VOI%bKO$Qki#8Rc;<7{Owe<&L|494t7$}){18M7r3S%cTMSI1rIj@Gnk)~<@t-wrUI|T#=sxonS>;u zKd6gU;`K+yjp+k|1?>vxDXgI)x=FD{AB$w00%{PSP8rmOdIJ+|FlZIL%4K!E%s*!5gQad^tDg{F1AG-wz^oO&PX&@0dX?>-*8Sz~?kQap<^p ztb6d_nolBF zjk?3+QlIuJk72l*esKBtOcgC`{(Sf*!VJeHR8muU6P2aTqO<(s60$g|M5)wM#y)rp z#Po4Glf!w1rYbz#uD9X^Yf5{dV0r;v&?96a*X>nhlYF|Y=2v1Eq`#=prqaJ5z~ScK z%Q#WDb&oAf_tS0X%-&S@OOX!;PBZ;PP1g|CrRhGc8nS$bv0Fq0rmsLZAARenKlm(@ z0Vg!#Lo2zfR0v+{Xs0OQzR>OO((OxY6F>mJv~ffbEu!fU-@Lcw z(do0{iJOjki!&@mw`|X($0Fh)A6qoMsD6Bk_C0w0FOFsBxT~-4U2-Cljo3Bkd-$nL z`Xx;tTsUg#$+;7Y>T7ol>S$z@rw)z99Mjo(lkHE=?IGgXzKE=uw#zlqn>AM2 zBg!P(n?Y8HG>Lx4_D+0oSFj1INZW1OZTAJ7?BD)giryP=B26p$e*1nLaYA>lhOI32 zxzkfoR3dNGnKfp0m>ek!awCZ3B60YkzI&9bf6%Wlj;eduZ^~RY>A5Lye7X_d+dpo9 z6gv$m31DUI%#mx4%ozE^QLfGNx4MQKXWoM+4-c(}G%HQIcXRrDpgcV3VTk?2gjg7| zubaek-qGXss~ZgB?FqjMlM8Bly&)6e&iUYqK!u-2O5iy!z@GHM@}S=59n!PSwLZ8K z(EnHQD;M#@9w|NABKQ4G;(fm$nN>3YKX+CwYx`|f=TF+~JsxOk!ozP|ov zXm^-g>WbK3;2A2wo%F%+q`m@{Ooi55y|+h|Qb&9ANurMkOpAzDn`l|PKTJM#(`Tjg z?@xd`>4WP_UGLG>&z;vLmx(5Vt42tv6kLZAYbXfU{^WTrdESo>CU@NEY~YOCS@gV` zJg=qy=zFg9dtOIlzZnu!&Rsyyom4(=HAWcpVHzi5sHz}<cp zQ)lfs5^d648||-(nJo|;Y7h2k&j;sikHYQY>|+v2d7NYD2a@JVXLm^L zfKEBoKH6f4}e!YWoUm`&Zw=y@>C)**1n1`vEjZ-f1WAgl4;Nu%CS5kG^}qpw9DYlZ&#+=ozxDf!mQzCeLQ+u@=9TU0ivF@^WdRvKbZD9*K6qv5tl`x|ho#z`AuAM*a_3@V z?6D8cvfGoACOt{omeeycY0dxEw!39`N?g2bW!S7?RYQk4aoh4$(wdkUn`6ODZ`(9w zXV2sNC^5$+EtQZl3NwJcxN*4Q$TWB-joy_8e@x>}{uBMd?@9X8x21)@^*w1Jc@I!k z>>Yfw)iXD=#q*?@Tf22DhLJ3wFH5z(!$`GTx1zN#wnGbdV}R-}t_cOghLOmYE4;I- zGj@?D&T%Pd?7+d35?3d`vuVu%n!8$7UR<@|scma;3*!3twHBmf1~pFcwjdo*TqU+Z zQ_rv~=~l^f64|ait};l-JpG|7t!z)5H`p+B?S{#d);|?dk)K~xQIKCLnZ9=7#I=u4 znYi|+f_{CAiu(3PE$`ueqE|@I|8FgidE$vNV_Mf+sxouR%X2d;rRP_TdGN7E$BbV6 z_uQ(=yqxMvB;VaZbX!1pK+kzZJKTnTz~}IvU?BiDIxt>QxKU zGQuS!_c_+QoJ18%>*I3$l77`OZ3G*dsKlBRKc+CPPfbipj-WYB>Qakz+L&mf7NP!a zu#7~~=qUXOS#YpKr&EwVoq|wg>qQI#r)Ew`u;NfVBJC`Hq<}K95 z3ifAkUD6-liXLZybh*51k0SNSg$P+hyTEmIcA;jC173+zH>|Fe^snV&?5DR>4K?FB z14y>%AbHwx)>F+1hL&k1TAZ-m?N*C9+r`j49XNm!$}%^*ehYcry+8QO5_7}TBpEJR zL&xD7+JUrgh6+ZqbTA!EGg5Q6%)$5lj4*C=8CQa6O*1=g|4Lu*Va|TXl zPLg)aXccHwW?Cheno(on;f!2o!U=`jHKg!?;2+>^99xwFQvnGMCrl&m@0?-j{zIed z9$29T(Mov!$3Oh|*ujaTWMcmnJ5CK6{7BzHkIw%Ae)#f3r-$b*#A+V3n~9~dpQH@i z6Qls2J?ZIAFVTthgq~_0T&G!E0^cmR9p~ECtB1CrCi`tXfZyMS-XBNaSG~#wv&&_u z0dd-Jz_yqTc^n`2&fZAU3Oa^9IQBaZw}P|g)6{AvmSsr`=*&2wm4^VWh=$u0h)Ap- zPK^YoVtA_3dYm5Z{ZbM2nh(MHC!d#zA8WSm$33lJVi_p*Bs*pRGBHa^7os*locou= zp4lffOy41&>l$@yixK|sz2e1R_^2E-24{07bqFSRuS3w)BAD!L1=k_)e-*8XJ@61? zCGQ$2`Ek8gc>liGf$3ds(RYet&+NC>H)_`w2eeBF{iH&`4oP79!3E|x+8aTyP%Pzq z7t>Z6iY8qLE@b|7S26=Ta+%{DtuKAbfG`k(??HZ|_JTd=9SMGiA@Aq_!)0eXb^u8p zT$g!cCvzNr1ONRG^ctdY619(+K>AQo@?$}A(vPr*g`Q%)Jzhbt3O%x!H+Ch{@NS-8 z-?+I?SrCq~pb0!c1hn{{Isc&jIJ*L+xl&U4@> zbGK*B2j*^O2bC$*e4s9Xqmo+)hQ$&8tO$dEB)2l@yG8`{Z|*K${~N(nW;$Di_zj|v zM1b=<t;&F0=63wevpw?;?dYLSUlPmP3_6Jfq zoSMMaeO}Y(2lujC=w&)skp`DF!rP5-SsGX|9j;8J!E&KT&z)OvE_nQ3wEQ0&?w3ZV zVk^58o$T32LrUWHm6b&yp~=ZbMIkm@oW(4ahLEh?_)JX4m2O<*a=t51Xbd${ z_<@*QMJ(szy?Ug)uDAG>Iy6*x?r;d9CVxGAiw3Y`Po(7gjDok$oVyL! z2df)LH)h)4jO}aUB7pIy+=6#qiP?i|U(CtM$*kk99^RufDrNQcecj15=^A+Br3DA0 zqDS`G_xtuY)SCVyswzc3E3;IUE^vXg72X4Z;I6Fxh|%kw@2GvG6z|BtspJv{#N zzu-}N=riYa&+2CNpRxS$Ndsmo_M1Oyednj!+|>`@vzIT!-RI}EgV4QKK+EqvbSDM( zgJGQ=U<7>rqeB~O>UKW57@yW@?xI}dp$jUNO znQAol6v`N^v-BKkt{7@3W{pP!O=bMYNyi8SC3zR@j2)9)ycjkJqkQO(@cQ26e{X-X z?}uO}+yrX>{UfN`0{{KH+wd4YV$a@bv%fy}@%WcO&7g|r+NbakcmMG@_|=E=s#?!} zyYf@ea^AzjPPh-WbnXSAJK^&$FMMRoyb!nsOotnop>SKaJ1g@Bn%QOaB&m>RH5BKG zVOga%*r*QChXPt61wzIooPihp!82#TxY{$3$dQe!@8G1$_zB~@_3G7nmrfsFW20;b6ooy`fknie7AP`^hY0?GHo4u zW66xHZG#@%?wmbiUP^A7YyRx{`I`ndKASOb?(Ae&pJX^<(cS}#7Vdi<-v@Ml&c4XK zPdTU|e4o%zJ*80|u>vc9Bnm_=SIF$VD#jX97sJSym>3gf((i0G=~$dGPz)L(X2$?i zn=3uyFX*2ZSGteC2^Tk{bPoP2rtQJQrWo^3a2s4bKhu9^TP!t7??bsjRI5mE8Nq#ora=Zhq#e;TsMftSE&SV-r9EuxuFq z6pkmta~ImFW~+ULQ!i;0$GRkrHbXn%*|X@%&jSyk1n;+JB4%MCU`#XKc#YloM})DxhWI zyQM`>EZoT6dd+b5h3bKF&nWrm!Jm9|=`W$5e}G*YJ!6MXSJPWV;2m^|eb;%NU5j?L zn=0Tf9G4p$W4A|9T2)SNZWPrgRTrLw)|*2YEN*F}Zl$|F5|1@sXt>wd)fJ; zk`Y;Apt{Vnzd8_f836Yn`q{Ifc`C`N z6hu*60`V>_=VKHy4NvKSn$hW0CPQ#Az~w4}xKLF%2oE=@v{duml=>pMvTfN8^xMUND+^e#5;VZF(+Tj)q%csN0M8=%xB$KrPlH0O8h##6zjYkP z_0vl{E8i&^{to;anBL@u7rn{ROVEDEXD9||Y_=g8H=fs7ttPozo@g*oA*$GTb-alp zTr>wQCE_xg(;}!G|EN2Y{4+Ou3RAI{5GV@bX14*a|i3UaAIdgH@x7N^y zmPSj~ckH5LH`WiuHD{OK(Q`PuMblzfNfz+aNpZMME83#); zBw(-IvrI8>Md5#P(sJs9+cjq-dsaQ|Th&q9qX~6Qz^ijP~{2p4(L(Qb5A!C6=q#N?;fv=kl$M0}3jB|NM^My<1gO zJ=C37ZLZDeSCpPtD|<(OTC(TimYPxFx}kZkuWV?|D;`jqn!YwKB{{3g-MWPW@NnlP z`Vgt|h^qxsLS;E5>(Pfgjvr;}g;I;1onAO3`Oha(+Mdo!l3Mbf09{0eC|2K4So!QFwk6T$?C?=L_y;`lS#dYy-}ZdH^U$HgwA}L*cH80z zwlyNQu~ZsWNV)k)5#K0%enLVf<5Vg$#o5Wc@9gCM#(D7uOx~}k87J>}^%xpcQP=e3 zKf3LKL1on+@7s8I;l!-`H|Wxo+?v9)+}iQAh1J9Qx+_|`&(Nar)l=1B4^%w5bM>SL z9@7{GXUtp&I})?qxsEJ1Y|JQaD0Gz!Kx4L`(KnIN+o&3f#QL1AGg zTctr`XUn3aSv2-kGnhEw+;83mn+vq=GfDJ?d~aaqL(fU z2Al1kCsdEj`XG_dOUIzrb}u>QsMYYW`Ra6nP`op>9o|W%$yt-s}2oi^U&$c$|9{+)`gaJ zoJc7jgPC%Q`II{B5oognHT&*!Qp2VEethg*54$3SUSl}w@k9km?kFwFE-dh7T z5K&eaYRgQhFDj~G5LIiKGP}Kok=kq)nXHD9L`NfTRO9T)jnV~2pHa^vgU*vQ{V%-CH=!mN)? z*!A(sCCTX%2jsY;tl);{(r>5YMMT9kLPaI1LRm!R@}}TmT46I3BqnAteN?I}Mxj(9 z!eyE6&&GYULb3vlR+$!Wwf~haETPM-sI`~l|B>;BO>nNA)r)l4`}E;%bm)gTmOmY4 zz(=lL24h$5{|%$Bcazaesr8+gg60O)*mhHW5e3ZE@$uPgq1l{`i*0A4Em@kX%MK{G zO~??qX41MB-p=Y#cv~cd&Ht*`p9KD&x7<5^gze{%E`R*(7Z$EM6O@ur+mxD6J(Ou& z{`flw7p{7nnZE1^{Nb#};dJzEPEDv9Mqfamnw;?!!^I-qk1co;!VN24?u6w9Wq+CM zmC%M)l_z;OirR-L{xt*Ai{0cbZ7W|4h)3fjWo0Y>m*Weu>zXs$T7f{2f z?*}M58_#@)TBh+0KL`at3V;KEPEY|VcfdAKvje^c+jf8&_&W0)d<|4?hbQ65?dW^k zc2EVXung($dfw z-xrNvS}|@yNyVh`?C|lG#goTWRgHt8*RH`$<0|-RB)`$cmS6uj1BT+9d13K{yHpY={&$MMDa_N}%@n6AbXMl^IlN*kW{R)hp z2Ay=((`?YG%U@lFH=ABZ|6uoTn#!bRvklB5r0qGWOg_wN2)3FPhA>S^irs8Z2n(YW z5=pQID>^PQ!!Kca{&GJ~?%RuNhR)w%BTl#}C#T4?_|Xjm$2eT>ki)8HA0M%5RYMvt zKdgTC@c~agRgqB?a#*=zUF!G&1BNH0^9W=&vnawI6ID>U?}cJMv*P)Eu!b+rE8p{y zIX2dmUAFfC8bvNzQDvkSsfN)eI9%k;165V6CqvYP;`5%)twj<8WnC4PKvR z9tV9@ta6%p=+L*oejV65PLmaj^KMV|wa@z6myp7zsC{3})4=vg;nUbyyeLNDhUu#w z2mY6}!0XrH^{)>d@*EIWZhz`Sb}-{cd^PA5mh)waMtBXr)^Uk(d!7JWuld#H#JBTW zKA2`VG}E~D6LC_+7a1f5$j-{|+#SU{2v^gMGg+a0!@VYED&@^2jI)J;C$J@`^8)(b z!Cj^7R5Y)V2AM)4B1{{aBeaw@FbkE&)pcPl4aFI!#FF9^Nl0ze*&IS1E@plka2$C3 zA`N15JWE{dS6t7%I5lCb$*H&KwliEqtf`A>ub{)ZXBWz{&vUVyQXAuuGD-A|pa`568x3~20 z4xC%}yM@8({yDR^n-+`N;fHOnHaA4n;~E**3p3?`h(7sS=b=4&edDP9dIMa>ZNb=x zy(4U%Bv!QS&M&zG2pco5U98~cYPmev9BxntZ)#Q>=}?o|w5i#w3aE)emWJTo5s)=s z;1}7V>m7H%d1F3JTkYz2O+w1pjIopT55d=u!s|ybJ6ZcR&*fl!P=tkL-!$k)G?-fG z!j6+n6<(>Qm?m=9^grC+e82RSBg>W_Ig&W8tYpIYveI!}+bc^KA3M5a$x(Q*V%pTo zswq>%x=$2$jzrDm@G6Z;C8r`S7DIx`YPC!7jtG`W666LQc0G0rDKc`}yB~Aph~s?Y zc7+Q0)^TQxO2y>{5PL*VPvfAI93_1WOKjH*)1?S`WHxo=df|^B(eG9+DJgGkuFRd^0S8y{ zD+{Yu<`p+F$7iltGxM{TU;TRAV=Kr1_2?^~!HI+FM%46cX=th%(b&JSX(U>EDV;Z1 zEvW((M>$_n+3=2$*=#X#Ic1UPLa`ecI!AS6^I$J7vCgz`P6>6RqbV_EK&G$=9llFo z;Q_b~6d)e{2t60zT>##xd$fq#xPqV0uOInJ>6`~AKhC8tDjN4NcNWfo&%;)@7|1T3 z2Xvo4vA_Q;BX{qB%6mV|dFt%e+Kl|In7i$QwX8!@LB&(rHj^PLN)m#}i|BjZpPe{F z8;3!o7HR5D_n+x-Xw+Fu#?Y-5*{L}ywMA=C?0$2S0g+&n=f6ik*17ohERd@>4u(KsKR1g)(E2Ip~u`EL~=u8iy zoX#8<5r>@GTv3s5#OeS$8y5czFHIW@9{3li!Ic*1DVbMxd;TLChWR$E;gV2$Avi`S zNXklgHnXfOB!u4C96~t-ZtX3CrNJjEI*0*Uo!X8Aw8?Xp*?3P*5BIz&se#a=?zjWt z4JL`v{uQ-66SdrmS|*j$B{VBV6cg(6X>8;#*9vcYSa=JgB!T~>gD_v3)OnI^u>o9$mh*gt67N_q8aJ`h|TGAQpOw<#NhJZ4AsRW{S_GOZYB^Iofd?9G>=MNpY!l1Y24dUD)C-ZI+Kyu1}sdi#vU{ z1pORfZ{1U~3!Z+cVRC*!`J(uFvvaID+L&aYDH97K`J9#C>!E*23v?NBq~fQjnZh0K%v(gqO=Ae-kg%#B*Ddw z$iJdNS%NisoJq%yFW(T=$hfgnAJb&nacJbesl!zr{S+B)*X0RpJ$rWj3m$rY>sFxK?s>Mj z3YecSFN0s;9u5MuNnXBg@>2+aZVVRWlnk?CnMHR~D#q*OXvkS2>N*S~ZaCFy3pnS%& zIk#q1|J<^Xh(ceZIaoyIz{tzFAA$o&PwZq}S0&6M+xGLZ-{*buIGh`e2D$>SY5y9G zoWCEf>iOd6gcB2K+FD79$wWEiH*J2FtFAc2-+bRfyH;%-)gWAvFBylg$jg)RYVtGi z6?swR@V@R!v`80^?K{PLDgNMUweM2ABr7(DT#DDbGx-KQ3mXug^$5=}Dh7L)1P3d0 zW;0SeZ>rU5Vq;6s@d;*rE8QV1fow@HLM^R-X8+%QKfg8PtRyX=e6qDIg;mCVniC2ww|MX%m zZxsH04-&3HuzftReocFyxcUWIX^GY958_@~yyKbgn4i`>^ZmQ6Pmg$)K;b3k)WR_!pbBFVEQiQCrEz`S&K z9CM_jp4$f5XIAXJwsqO_SKyMo;`SVmaU%*7lMLBqFLW0rZav7=g#Kdks zfWBP&zs>*8?(h7k`3=s0^EV%OZrRzF!LXtM{Ywx17SF$jA6vW*zRnDVGs}vLD&bFP zhqtp!=&9T_(Yt^ZybEwR*wl*`rf}Eb9xwvQTc(0|Jr7uNZ`3U3jX2!5)4Cj z*&&)`)wBei_&CyR4co?K_K3zqO*5IFx6c)W@d(^T1lLPMngAz8q%ok1ZR2cWWKRgv zRAiD6sR%Ddj-hv?VyqS$ex-fNI9Dg-V)oigU%+Z zTYVM~ie%1htU7?V7)xsXilA)FJJ}Q@$L!D>9DPM_M*CM@DKWsb*udR7Ztw=$@86Nl?JCKeAtfeM*!xVzGR^1CS;` zm@V42?Vg_QY1_7K+xXkIZQHhO+wN)GHs9>qy%G2B-nbDbD^7fw6%|!cRhgCb3vvO|9YlcS0UPhb$l=T3ePT_0 z-o1Ww?lmjivdTxGE105aCwjM)#^00&iEjVZqbRl%dQVG9h7p+?8>XuvgI0gTcRRLN zX~aln8pQ0qEbxp?fFVn3WsPfjf88hrx z6mlkjiHGp#+is=H6Z0W$q$|d{U0Uh7dywRSL*9dzq<0m@=y8GYDf2qpH9R`j*c|e6waIrjhZQw7-3gB|s7gj`s0qXm$W1-LSafBQ*S!bdMy0)=g?!wpSBT;6Z+ zEOJTU4Xq5i-%;F^1h#bW^@wX@vUXjccq{=;Yj5lIpDOyim!^*eVH zaG;PSfEG2BoKu|7H7_|gY5bl&&8ShNPze(;1UtJ7Z^ocj8>5UcsJ6~LOmyzSl#+Q& zQFKt64UBHKHu^F$3uyuyv1jkr0oJ4Ne#2#XhW9TWQbNK0^^i2f;wr8837&KD!E+7a zXIMW5=l;z7M48I^v-&C2$1%n>>+S(+&!81*^CL;V`**dR8uO1UR0t8ht9a~9>_tv- z=;k3xSniN&jngcp=s0I@iR-)l%W5|+Ob41IlBDGL_FYSIv1a-aFeegVFVRS}^W zx??hd!IpV)v3#&sQi#}l0%ynqm7QR69hTBmi79GLW0v@zXGODhEf8|SHXbC(ZpaN{ zJpZTE?(+0gAEQ=bdsU?FOp`$&bP7c=hsZ`Bgi%$Vx83i_U%HHDO9|eCAyMunDb9#j ztLMg-a&NDm?XYjgAk`xmHT8Z{45xeZuFHUyn++j`{nK2Ipu)C<6i6l8>^^cPbJ z?Av>JO{&GtN{tKRj4}#am7hl)TNc0;PUhis@KUNNw%i3)&K{{2dvb)|?asrGp#<&S z_Ma={}T*ua{4I}suE(5**-#oe^ z4VyhaI;W|*B&`%aujAJ~N;^h-Wg&s_0khi~34UURdY2++E7`JXlwtu4%EQyawEfLm zlycb0Yv$oFXi^JEEI{;OQA2z!dO%eCZQ$(tfK@PMG*^5x+kh`Mm3m4m$|XDe&(#~o zH>M33GE1#YH;k@U)T$prwf}OM4F)Cf;xsabX<-xVrO_;7W`@L&pEw%|!|uWMHkW-l zmiS-<1;CJziCp0A#T}EKggKG>Q(8gtDn2Cu1nFs?^!2IU#SK+HSLNjk`P=$F?5LKR z)tYZ4yZJBeh)7WAXzrK&m%!^=PVSB`qOlnV*$H36**2R}s;(_=8|e-h(OrYsNBGjn z%pvi>x?N#L@<^F`@PN2RRAvT^Xh3s^mVFXGnO5d%`}R?S%P@#Dcq>d{9;DAF_$R<_ za5p~r4UwZoB?^bh?)EoR-AP~O6`QYmPZ}-xbKP~J=iB~7!BW)f$AidGU`V&)^ZK;W zYC6dZLvZHKuXN~L4i}KU5K>(W{x)p5J`{`fB|K=aaTfYn)A%I6TVz_WD>s{~XJwqL zTy+u;S#f{ZJ)=ZZV;a08Nk8c0hIb9Q7zj{)!yj*id$6ArgZmqo@kxLf6z6(r}30*h==%*K6vu{8J0{suYGEPQm zySX!k-6diQwBR5sOK6Cw;)1xgR?fo5KkF6-KRbC?=$K{k!aIY7GwMN zVhKDTbW8fMz%XHHx&$m0Vq$QkJX^#QH`FV4>v11aT87X-`YCou6li2(G;PL)#s>2` zfWu>sexrh|3fBSz$7_bVML8I+@Sxn;n|(&Pgv5PPTm0rav>6xa)4Wt0TNJ0K5481N zR8hJVp{nFsB$0!#=cV;LxhfGPBj|}*u=XK95f@Z+S)9P58met%fDbQlRBhkmm@d$y zbQdv)&*zV_^k`=VUx5(L@Iwnpvta)AQj`Y2v9UDVJ_tjIp1wg65($Yop?}p>F461N z5W6%o_d~iMR%yxi`u9wJwZ;S6O!}wldFMy$ta_ckv7{(>RQNdgX0Op&d#jiX1jpuj zS(;SLZM)HEs&AM6beKVTwAaq+#e22gkl2c~_WM9CiuqRu^i{6=gK~oni2zGn*iW+`H z5P{=CLtu$Saq}MKlt@ddRdj!omqo~*FVYg26)U7(>KJFwXSyAP*SB&cv}gMIM4bcSu(y-Q?Wptd-OwNW;a4w6$P4{HTX zGd`4eK1D$VH{+Wk4nHaQ=1T3^^rnvy2NE7&+Gc zCewzieGbl5`8gwXLn}JW(e6E20+Smms+YUs9aQQ60rUPM{RE*^8TisKJM3%~fK$f< z2{1_dmv2D6oyH7KDwiXDW47zd@KS8=Ll^%cX>8gN`Ed?J+cm*{TTH0VN024}p5%-8 zw{*^q3{c2q`|J5HA>Px}^($NUfE%wVxd*HWV|kMUaT`n%VS#(}1^^VN7)8H@N+r0m z!2TX={zwALHsuG;iGo?zpF?@n>-(XxmQuMdAIcwcuinzF`*^cm{|FCf?RXqb<;(Y& z@_HIp(5$=1L)PGVPLds|Jo$s)agHnW%2}jIcE3GG6`iFm$B0mDjVL|FO6)+U0L48} znpC2}(tc#wT%yWY$+3!odYtZ0b{l*5%TK}fKi|&uZ>iB#bCyiq?iV{7QJ)`nf;CI* zU?$g1Vhf7CGw}eu0Z%1N9Mo1BPIs?W-IX5H8IPKV{3De(I9IFpbjAh0`x|0CLSpx|Z|pkAtW- zKg2PZmCC)+6zdx`#!vr0_~r<#`wjJrJAnps2y>dDCl)*evQx*zo^(h3WyF1fB*tB10wP^95;X zgzRDy(o zC;t}lXGt0}76eaYzcRxH^=5z+2uHd8)_b}mefEZT>Ylqx-TD zj50W@tvY)(u!@9|Ib`CX(9d0n2?!&R(@CgNvs6f_Xc0n-l^N1Xh6p!9M!Hrba-17^ zlGbGOMb^JYwNJ}Fmh0um;{&CSJmT`kgGG%oT{>Z0q7B6c2}LN6b|B--E6p5P?1?IRYinNkcrOTd{nj;nf%*2 zu6=%-ww;_+o;+)}Jyo76DmyB_PtC}Z0{L8yoG4p2IeZp(Xz|<4g*^mCy%g5NT;Vl> znJ1jD&K;#?bZ&a?rudQ(4r*#tc6>T02YfaSx9-CB3T9Z36y=Tv1f4PY$D2XD1`7&^ zrG=3L9%?aDreEiNFJTgHDB3Vzw_MVxzr)YP2BKP6Q@xI3@zRSqRG z4dx5toVL3-2kRqTH&6W1+i6}|Drzjg3U~#2J)ayoe3Yc$R85LQvWnS)9DBEJ`? zm^^fAhzqPL>7BpI%c|-NS+snqZj01b`~@^+c!_f7;Gb@|W|WLSr8la1-IZ%rorw2DB!O6ZXwrq( zUruzKRH+(RR+g0l1r!I*m*LKsY(yW7g^UiznRh)N6ESE~0oAV~Hc`VNS4APgC{ZR3 z!RdT@s8IZ8OGJ+b%3QMv5xEejt4s|nEMYO!6Fb247gwuZP1CV!&5V+6$EN3~l!oIt z`$0~nyGLZ4@v5e!e9iI2P3bh6>`8(A3so{AZcFxa6=AW4e}^N8wn*bEo>mz#9?OXF zZiu;arOVS9!`LJd4)g_T4#=H!$3DtLdsyniN=>p;wL_r8Wj6YR<8ZSMS(2oWaJkrW zTPEF&N7U@a#`YVKt($1NL@nQ%b8-Km+4!4d6L;u*MGVp`-S1G5k!S3YseR9p`Y8-g zt$3OY_;Ult)!h?J(Vqa=rozAuZ%fkG;>yD)fzMM!G>_pwEbzMxLT`fZp$$J?Pb`S6 zD>YISdW|MB5(j!76t?h%8YPH3o@J(^*xjv5gbKWGXQMp|n0ju58^e)rA2kiZ!z`6O z?=wGDI?b=T9IP-L-c}!gpEyN&$Mp-4*=&cwVeV4J27&P+&OdH_urYsBW>;E$4MCLKc~H(sQ>EI&XiZO zH%=>eN9{tXiaR~iJzYJwR1kHdAeZb>E2m#5~_;rF6qh#umXCC8y*OmGq{N| zlb>|JkLd`wd!B>CKTd>$g4AW4JRAwo&1aWWBy4B7T5FYbC-~mF zdRf%|63ss&ccLVnBV7)M91UsW8LCnbSc+ttH9t3S4ZwAO=BBb+Qwlqe8qoX4|K=;4 z1L$5)^?YweQmDCWxF0XTr^5Mu$cw*nGq=J^P|QD+au&QMpgO)aY(J-neavQxqgSYe zTqYL}s;}!YM+($-z6YheCktx0qH~5NWEX)p^m6vF%CpXEjW@X( zR_9TT$qc9>`bah2ECO8MY?NnZ%IGP+A7!3bCK=H``*y!=%;e$(wf_3(Hz2c}MnPy8BS?ASUP1x0mmbBy??|!lNIg)MAJ7O ztYcMMS?hrghv)raLZ8>|Qdpno0X%Y$5Q?>CPBILI05DL^%%dxJrF*r=<~vQm=jnBj zT9u!FkQ1KOBZ~BD@*JhBa>3b1;`++zZEjt@KE=l;yz=|!U}a_ry11zQLXp$Udch<6 z;U@1;;!6_8Fh-vOv3S`_@wZpLBWWwir1L8R7Xjho9BZ`Qel=yeb1@myRFMPkXKTVU zVjobNKT5mvxWYts?cG&!ZY44{=-TIigg4SJg#$giO6w+N9FHJXuuD79mjL?dtQ4h= zKu3^l0G1F>p-bh*V>vtdIY?=fbB{0=Sb=-1vbsMR_iTF!3#LE@w?3?{sDzp z_^TNX7PqCCoEpI2TL!EZQLz865GPX(AG8jTV8Z_D#4wLd!jrz{$wcm|ELdMlu)8uL z;w^dAP8m>}@xA0Z(mnc+^Y$&#%}uFl><7Nw*rn*Pl)K}|%w=X_(M4hcwB2hwP1NS7 z@G8~tyT-*op72%ERG14em%#eunuQxhIgU;l0Y*U@wc&xGCz6Gu~Dvprb90_k%UEVnmqR~4dd5O!huMD-KrT=!4Q}+QIv!fRY z_fUTWYkzj-CCbro+yOg6KLAbmSo0&qvu4ry*U*UgcPpBR@TV3ZyAn6iY!n-;*xGB~ z_ETlDZHWs_W{H>5;7`-%yZ>Mhj`y;#X6p=l-9vcIU{ZP4z@QAK;yTalwXc%919a_z zD|M18z1Fjr<9toTdN|gx8#nW&f5VXQ*t+}Mh;GvkaEc?EP%sCI^_M%vla3(ncr-Aa znx^d*uZYF0&QS7b@>N%?!xX!`hJY)@Q_h#ZSln+#x|P<1f7J$JFggds=dZo==yb7c7`s zTHacZ`TdE#NEjY)rWp<38g8qgUuxjaqx61+MTE8Z=erHBk|8CN#x&ZmN2L0_ncm1F!r_HL z;P4u4T@%an=H*73Xd4rqOQ~-sMu9aA_pm3a9Kc95g^iAiogRbH8cQQ|$&AY9B&Fb$ zWl^wZO`1L%b)VqsDE5xuRrL|12KA{ge|dV@(0JbmDtYr8g}Z zOFGSztka$zaFQO?nvyxHL;q9aY0GVYa2S~|eL|UAMQ_F`-TBl*)zj&-OkeS1heu_YHPqhLCxRBl1Y+nI^c!|cx7 zoa^mp~nDx8Zsii`tsh(}p8}s96ty(n`8^65_ zYQ*lV-?a~S8m*>G#3NLUAit7epLsX_iJ-=dsrn%~umGDynk}E^Yg`z6L_j*TTN~mM z+Pu?{I))~LtrvXTD}aZUT43ST*=!r>aB5NK06w3C$&ogrOFHAKA*$N!8W4dC+Iba` zmPGGjC=JE~^RQ(Z+xvA7UD=~bv(hD%0#9t`+b_7BPz>pQmp=YYs8AJNpzdiAz>d$& zz%Ebw8CEUGQZ6y20N|G`+9JRc0`k(|DaDo^|1#e|i^C;#_jAbG&%Pe1K6|_{+-DU3@)ASw=So=}hYlA)*+Y zLg1B_XWbaG0cK(~L_yFc%d(-TEYJOD{-E~JQN!2f$bHu};Jyg*@5f^B16gz^ty~`d zdF*#HqSSaeB0RjDbW}ho_RJJg14qp8Qysf#&BH2&-q?B$0k;e9$6{`>Sn^;snM@Ma zzV?0xg{-?9l*~cRg2=Y;(cgJvHrcl~p(801r3*)?6adFhIOR>cBcZQq(&nm-E=0^w z$0yTJRQce1q{xt_N4Wdo7}N@1UjpsB@K-mpvy5y>N3*nt=&h{pziZSzsFif{(&e7k zd!fwx9R)$>?u_%tQ!+)z<0N8OZOb}q;cn$XaxzDb>(XF?B&>3Onyw?lvch645Z!r# zuTLwug+KsbO;jsNLE#j#pkQF0IA|0=0rT<#C2#=_ClJ&AIJwBQmx>FENSTWc__rA3 zI-e^g%k?(CV!d%=gkqElHke{AS(5llrl;w3yO+Y%IEIJeV@anZy(RIvyi=0tM|Q;! ze->P{p3xagYFZ*}Jp9_|9CHJ41(nk-Egk|9n-QRYS=SdC@=f;7M@mi4Uuq@OHL`yy z;piA@E2nlcHGz~wei(bA#eU?HtiopFnp{Thnc@bK(Dh<*ur%cFOqRT}){o>--(Cq* zhDUk^j;EOO(VWPH-%WB$Zq!S&;>h9I-C27pKoM?aBo&95P<$&mPA>jv+?Z~H zKrzXY_OgIZYW57>C@LI=O>@ApYK1%nskxXu|0GzuU)Nx6N%7^6c6=0DkMmT8Q&3jp zn)fulCWG?&Sq*j7m6!x-(v2SPCtZeZ*8M=?!$ajoPFQc-Ue)kyv(Fd!Q{nPA52^`Y zPte;7b`EJS`qA0y`}L6YwQSYZ5|_|%23_vPATd+r!$Y9DsVv_)v8AW<&0J4G%jk*l zh{#}D!9UAj^wX^^zKeQvEVm8gglF!4b+y~uYs?!0i z>t6f~SHJjovOn-)=eS(_Se_oPR(#6~a+yNs{Uf1kQc0jzaPhr{n}Yd-Fm;R{N2BTiOF~6Q$F+_{mpd;A z%)$HfK3q0VPajOe`|p6R!Xa_Snwb?^>t5;7b0v=3!QGXHR)1b@HXW+VKt9ew zX1*uF!5bSHJA3DmL34H^*F3jWjax?vaiA`Q}6@-#1WTPtPjtVm>%IGwpqK>Zm2tgbHAI+)pQWkx&P|fz3F6AWj!YKn- zMkw@r^SlbQ-@e3>#G@ySXWzCtP0mAL>Dm=9>3}cR5!;0u53|akGKn|!>9Dhw5tmjsxj3~; zl(9NeX3|Uv6b~>5NprWXjrK!jGr4m;YwjBvj6VR=o;P+&b3xg(d4u}2M{JoV(6eue z=|gj+ZxNkh2hGHrEDPT4X0fT|vD9*7>sW>(OLfCP7*`hZY}925cM>Jq z!{j6JNz~i8fi=S$_;;AHR>nKz-y-g<77`1Cnf=E)e;O8Ja|2>r zt2SBKO!a_0a2kNA5geh#o}JH_`SO5E%cfUV-GEN2@^SeysS5i=LWEAud6A@RcxA_o zO2*+6$@IP31eK12V}+C`8Aqj5V%)mco}}hMRh26Saem2)(m}-&E2;ZL!m(!s&-Mt; zVU0sdXXWHDJVnk1Noy-@c}-7A$--4dHEy=@VR@}gMXh7FR#$*WV5RyI&>qSxjv9^l zs#Xm8)d8#EPtF3H{&DK2ZKQLgVfrMmnFlJ|Jc zoQ)RFJ=C&SugYscQyk2!%gJvw$j7BO<=J@42QI3ya}yTk=IAwdD{*!9%OwRQ#KtQL zl(v>la*`x}RZ810t8s$1uR9$ZuvEn_GqO>cp-)XFtabY_vxXG!W0i+4B25U@SZ?kO z`U{P?>BXH~YSLc3a^O>u$Z13p|vs7z5Y zJJ88K6}Rhnk204g?q-3c-^`UrSA2#_DLZU(RHb`pnF#_}FE%bC0p=?FAXZ=Vw~10{ zomdJZy7o)dWUNI}3QY1nJe>nsy~gWPUjgNxQpY&m-__!$ za)*ixA1uWay#&4g?$HWeOJj|$g#zWRsnjm83)7gUc8Bsthit(JQzo0~f(t(#^G-$0 zjJVj{67h|wF*Ulk7p1#%6I*_OJsWn}-Jb* zqe=fX6R23-JA)_Jby`DRV@xctH+M=lp^*u06R@b2%%kF6kA7R=mgrq#6Y-5t-PVWW8kTbGu!`^2ZH=W0?)EL%ICRo`lINHRloF#GM?ehf5i6 zP-m6o^p^>mWl5JY;5Y>@$^R!)$MkDa!<^!{t{p(2+5Fa^qBS;yrpF-~S%+0UsR5w4 zw8Q4YElhJ?fPfk|ET3=heWD!3# zfibI1$lkqCLgQGok0`;4C}v+7(Jgg*hWJz0t3>Al;$vZZF67O?cr(jeN+MYTTonb; z;JTK1N%M?ERVu)o7E(8jWptHqz?>yIhs~Ve-7mX9jw3_C9HO}Hddc&Q_)J^;&j_Kk zo;ik*Jh6d1b7T?hnMTG~Zk{A#s;7Vg@W-hOrlY0^FJq#@0!PNoRi0MK9D*TWdY<}s z)Tde`YlLYdXNHiY1;Nq0*E8(VB8aBAnW1qgjyN~~p2iUVwi9y^g)=fm5t*j2(SpOO z)X^L~dvd1qVQie%@2l1XvmUlQO|mR$OM>>9K3Rc7B`#C7flh<0+E7jD-($t%zGmRU z@PXPHWVu${lwnyO)1@qDRpviaD(VtOtN&q6qcg^N`uiPKXDY{NcJYrBg^uXOnrKIs zH~+=DnG?9qIB!wqnzIwjM_5fhJb+JU5@Al%C9cMZaFO&G`Xi~Pbo$cgo#}(BGm@o# zbiMGB;hF9Ex0UJaz(rf^l}T(Jl?LoqAFUBx9o3r3Wi9};Yu##{$%(i#tJ;ifUDXBm z?~IQ=UqkNNVpA}FarLF16YADf%)FjC?$&^=;f~ReeGpGSYrW@MGyt|U^Qu5={mKcq zGrXlyYmKub`#O*7jP}{gg{d?7O5fMu?^@!cT1TeKoNPy^%Y3&J;g%fYTwqfsK>^Pr z{Z+Bpse(sT#;LtWKu(eOBN~s)tUMEs)a?AjBS`by&Z&q;xaOION3d@3>Z!9w;J2*x zBWbsY?IPDBqDSg>;maB5dmL}U*CPXdp4{m#Z^_*GlO?IMHH~F)0N1I(yn|)K8JtFQTEqAQeJ3E^b zWbOnpd&t;h2JV#6JGY!Z&pYAm%$GfHcfRdhvO8m5Kg7epSAE_f#G}DiJKliYezAK6 zFJ`$tBR5L9gEKE`!citS(%JoWFYeqvvU>?H#@qqNS7qL4xs!G;h}?0ryLB&w+{u$W zZrR z{2rsF4D#FjSFOU)&eCaDNiO79yr81i$_OxtgHQ!0YN|##SU#7GirV^fEUA*1T%k%C zSY52BF4df&TV0|C$)tK!b*JxlQC@DR!L6ylQ*q?hp%Fti=3v>J7*Wf*#(1tgzXE=z zgPC=$a&wns!?75pOO)oJ^7{#g?y2HvNounE#+2hJ8rV%Y&Fkh)Z% zISW>KvYmewE0-y?Qw?WghK31v#(8pQLO$KoDZG(XdHa{(GZ1U~uSqmC2UQOt69(a| z>DkD(x{6^Gf#$WvMj;bu5$Q1UA}C>qR3+h{3+af;x?g)DV8P%z)yY%nCrwRDfP<*_ zf4-Isv|#u5s%=(MLdbUQlT=;k`P&e&Q5B8uRQigR03G#o&uBhCC8+Q6M(|K>4v#92 z+_dWKVo50H^H z#~>ACm2No!qDENa>El1jQo?zvrNk4iiNq6?h9Xa;=0aa~L(%tSUc!4}fYf>HgOvv$ z1w)cB6+=@=Py4K<(k{8;Ij($N?3n$Ed+_i{+4EfRsMc~`vpSApr97DhU6v)XapS;Q zrDId}Z&U`SYjLTjXz0|f<(VV5=2%PK1Px`PM?E`vqq9JArS>%1k?6BclXOCgea7Sk z^Rz?3y*e}Jh)EcuUrc!&2vOlL*{8#Gf{^Gf>Qc@t)0)oTiXL7FYYl{ujp)~y825J)Zx z`7hObm}e18%n7A?kV_$&dnOM}a^G=ja>Xhho`-nr9>bZ3 zc@+UpX(;2PdtGBbye1A8ncjukqt>!l%8wK6y>u=)kdtRzkB1 zns)z4d0Fqz(Y8fVJXMS8WbWc#X9gIR+h)z~ah+!lKoD!6a^3Xi{W;ut{`>X~blkHw z>+$*AcSmUGh3R0Cw6I<)_6!5_v+@->WUmP*x8*oY4=tQv(|SX8mY7# zaAYI!%6dQ6j`~C7^ef@(t@*~{&V}12~^S6=jHgzL9(Ei@_`3KyfdFP!k z|8dkSSp1Df!hEpbOpiDhj;k^f2ZlMVJ zTkeH(#%%V#+9_;U>a4jV&FZyY(RhQmCQ9$iFIjmLXN~{9f%N!o(V7mf z;eTrT&~`?u-NHPp^(539y9z-_6>H;>8=*~57a0XQh470Ca^fvu2PeRuVW~sJV5Ni) zLUEV~xCkolSI(iPga646vR9#vv13IQqs|N#s$$N7=a}hd$eJEz2sqjcGkUOxOJs~r zVvIJEvLg{64+*F(-W4BPg?Wp}mYnUMhgGbB2sKM zXec`FRcZIu;+dM=E2i0RuvY+*s4BS|9%0AeCU6jOO>9^GlsLex7wA&mm+Q2?Z@?g!5GjYb) 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%0D7KNLIC q{<~OS|4R7ltLEUgXO*Wr><@#b2_^Zh^!?c505Ztlq5}E21pWt+C80?G literal 0 HcmV?d00001 diff --git a/docs/write-ups/Wasting.doc b/docs/write-ups/Wasting.doc new file mode 100644 index 0000000000000000000000000000000000000000..3f76356d00ab855cb0f7cf22f2f1e10ee92384ed GIT binary patch literal 360099 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∈TCb{mhr@es)Y&$phJM#~VHyzE_PxyPA42epq~B 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

)kN-&Qe@lW%4#=(#))sMZk(v zrirn2DC#O@uTM;!=CPXHYzX<}S>4Rr{@A0njYN|+OmmXW_OWw}!r!x!@md*5HS_wO z{Ogaq;MJ2P;;^bKD zsf--Vr2YWm!8z*XbD%Gc1+dCI@#v7{#p~Hrr%yh)G-lx0pv%)^Y< z0%$Vla0}dY*6CN$wYV-jlJo;`2f+K+&MEnX(Iqd#OWQc?W#qLC$10S@yDJ1VVLBg# zsyvs9h4%VI0m}Ixn}f{^G6GDSrJQapkE2M|Os7bqn3f_sGxU zGf-ZKPs22SDX@GwP(|?yC zp_L?UHdT0Us;r_h(SelVlf_QqAdCt5=3{kZ_)B94UpX~0TA&7O$G#sbuRmr-~JP{Y2#PE0q z9VbMa*9+Zs-4XYJM04dn zpD~3JZ zWIoMeU7JS9C>r#arv>W0&bv8UtVUAthMvqW?;bG6|7M8ok0J)R!;3Vj*O}*hvEu1L zhZmduSE>ljJz;92^G+OUKv4np8su4}{ClRHpPH`cCUZlSq6`ha!-9XaeE~-)8_ze_ zZoyldHpO-2+oX(iY+Ve`jeu`&d~a|MOy=QN5uOS5%G>yuH-ajl7VV5Bg`n1`Nz&S z!X8UB>$Gfzl!I3heq8B3UaiyOCrX>e`~aahnWf=r8bNjsE+PAP!?vVt1p}p$KZf?` zD-N>2eX3rLq$=dN=DV4J(0vVOEs!+ch>8p>`Y8J$Wj61vS(`*OX@iY^{*fame|t^4 zVu53MXgtAC&B+ZXHj}4=2ukIF>pkiVqK{LLs!}C$ywIB)x}UXYI(7AuOioK)plXjn z^_^7LBQD4eObg1EwI4;YiYm%kTALw>Hm2ubYo_h&t(fN~$|kVoFW=b*LD%NlZz!mx zX&a4|vFuy3Ol@c$ga_Uv)9h!rddG2J-_+4Sqo*n_BwTnoPpPtBLxE;6r9~ryVCqj@z%Ku*fdNilcB_+GIN+k(RQ5^=iHqTd4AK?Wno<^Y3xMZ8T53ar<(5A zW_TjG*OvMY_eqUOH7G(MjSs8E*;5$$W1GDUY*(8nr_rPo&f8nMc1W*Txem1|da+v? zR%E)M`8GD5zLP!IY(j-8!l3Vq(TbJy5*=FyWo&GUyF!=r)}lJ8x$)Vf>Y(Mj?xz6RK?H)l|kd&g69}y)JWZ*RuYVLU4gqkw)H`q{-S| zF--3WI6)dfTBY)~sCn5-syvVJf~}sPt7qE&Xnf`*v6z$WV#7kksh6G zPAPA1p-(4L#WUgQuFieI_$c*~<}nRz<9X^Tk6(cGj9w6P?e@5Q-h^`?deLO7n3&k7 zV@9Ud=Bau?RbD%h)GC;i*5bMo=~r!X!i!mVX%D)xlIz9A#L`1nGd%WUFBMul2M`i0 zEGc;ooXrMK60retyU%P8#?q_3 z2Qi&$%K!dCfzHZ0iVKFO$M5&=I(bIZt$DxXmVF*Sbs7I_LQg&Y2SXMY=G+Ef-D-m1 zv)@}K>41AfK{MU9?CH*cQ=5`DtzjI#rK1N<_k4nd7iw_3YD@(^tnYN10nLKA^WRhc z70G;CxQr0pdg;>>W;PIz2|K@-k^0tl(hY_8Dqe(J|GJk8-H&9a&sf-z)V?^mxG+63 zq}!@F?LNM$kuJNML8aUnQe( z)rF3ps1+voE2WoYd~vFykxS@IcT0z#uN%=`8*CglP0!9< zubw_Z6fL^F2p4yI7rP5t60`kqXUL$W%YNgCbvx1<*Z*tACP&(2-WTNqU!e!~A##i( zrQKfrz6MX(qTzgXeum|)Ui10Yr)Bd*k8 znq!`urx()u^Vbe8TiTK=r3LmSPK1oY@DxrB*MjuyvMHD9RnomO;MQji%v_UByQ1Ig z4I{e5xhScD`R%tRD~+WOzm_&+q~9FB4m~THYr}+9g)fdI`%s?}TcNDS{;h`_??YhZ zkYRcH(_!H}g;*SAYUJ|nKMrD>nLaA<$>#j+>qfTWobG}IyGq|Dq3k~TVtKD?g44KY zSlsEQ)5ILp5@RpeK1Z&ob2S#+)2Q>nq#ks=3-Rg7wL%W76bi(JpX+6G0S=B&G{l5y z4T(lyESJ#=ouAGNRbDoKQoU>t4Cz9G+)91JJr(&!UoW3`@TqmRaX@JM1EiS5A3(PS zu*fZr$nNujHP?*{r`{@=<1Db_hy1|pqBJBkJAsg@M5K@ zPyr90CgAn?P#y`wVhrYUAqnAiv6A2#=NnPhdZKeXMdD%z(jLa#k*f2uzbLeSDsU0z z_oC>bEqIEvSIKghrx$*MD9A9-r%|t~9!w`rHpuhb zok|t~yX=fVTC=|0_8J&YMzZVM#eYuwk0*v1VMIbcJC7|F*rZm`)!@~n!ih0ltPFKQ zTl%>W0`h8kp|5XmKo0NPkzVosTS1IGCoT>Vn}Yx4)ekne#{nzdsED~b!71KfoXJdZ3QW|8IHwI8x|y54(O&p) zQ>J`aJGeP1%#_cewM;fD`ZPqzyN4}u)B0fVSa##m;`(oBC^~{uHL9TLKXO|0a>F|R zc_uEo6$?v-lX7|~vhAkP+uBV%=+4^+eKa(Ho+yfn+x6}8{bFgf6}uMmYK`*aBR5y|Za);jII|S&u;-0=v}hRT zP-%ml0Es|$zt>|0{otO_>^3Y6RTZvIXkB=GIrVBYq}%U%(+*nVagDYfiN!oO3Ydi9!Kq*G=l8=80t9hn0^(G34#y(O{ z+u_me=&@>NBCxd0^Q;n|Kq?$Z70@n|1Cj&}RjkJ!AoV5nnFqXZDc9~M8iW!;y%l2Y zmW!ne|83v)lwS$qVLcZkd))__t?adAXsy$rqjS(FS@{M5f5L|l$o2%c|K*4y#d@ULQSxPBM3+OakqO;-CDTg|)*3FIZ_rb@)E9}0w6WcBSf){|Auf0$5 z{)hX&Hs60V&esF|M@yUsBv^RJ^RLCg|K;$X-UJ7|`Rb#96-!@9uG9e@q)hGrblATC^^ zRTdPLC)r(&(rzyA^Y$`{Q9z6|CtB-@!=k|^tLoZy0i#v`jIE^NpAvJ4<(of`@4vn_kDN0Db8yLp{{xgt>@)( zJOfWCYI*$8>sv1+e3|EHly=~9gcOrI(xM6Aj}9>XG&?}Pu^$8|tEM-tlD~RkmGpLo zjC8yk~+K7}2MiJV4~?Qn2hb#-AG05|g*i7O?y^oVgh0qGl9iHSR8 z3oySnARK&X?q$2uCraB4RCksvh1m(CHkB_hlzJIptEQEGS)JEg_MxN+tC zml$r4_is*7-B1T)luf-?yYLU}mi9Nd5Ea--dh#(!I%X;^ZCXO2>AQi3kE~v$&)n^o z@8)t--E_O(??RfT-sJD1*iVt;CgPz$=#-b#&W$AV+(oqpsIB}g>v7{B*s6*4h9<)- zBHR-+Cu*95w7fg{>RCy$9}ujb)E?hv3H^y5WM~*bKPD)CnH5z zU}4qbJgWssadK}p6oqI4R19;R@OLy)JaFlE2paX-E79;c}6CCh7p`vwQSnmP+;fZWo4SEVx7~~a0*Z(oPj!a zd0!GBQMGw@tc*~2s%JssqEL`rR53ukub@u_EQ9l2_~rW+oVrw7bLp#(fba+1yXoG{ z)ZIs4dOlBnc#p&c2=-GIywe6|DRE;m3V>H5^oxs7kSpQz~` z-Ro6Sdm0Gx<`=&$ZvnI($Z2PFTVLPV)be?--aJ9wsTrh!h8RT`esKKX-Y9nLsQ)GA zvibim_hX=AdrHC7RzfkPT@OgobYA#W&;s#%4JSg^RRS}|4fspbQh(;56o2`ub^9|- zV~V3Ry~z7WwP+NW#V3uXqFWtA=P_ zNw~gMkG0^jLc8B;E;mLaO}iVTAzs0J4gxG0U<_uute3zN?IeBZgIFoR9$iviJHH%! zEW9{#P?r`Er!OT0vO~OS%S@yCuTRsxYXG35I0kea=ZV0k)@?dhf2FaYmx}r3sd~MO zHN(-cB(MY3JLO9$??2iq<@p}~Fv^M*7cy~a<&*?g8P_0mzQ=mt6Q3xmm15O_4+ts9 zCOl9wO#)0@%bAfen0=uWTOA+DXn!(N!)+~)HzgVm?{lnt>RqV`XfJz-oz6l3iA%Bd zc~^`mc?^x3&o^ot7RpE#rIbHdtAkaS12iTs_NxLQ9K%oST2Al*(qC;;g`g{^EdBU@ zhrZa)0CL#g4XW1o%fM{K{V^H3F3MV-Pxo=50CN2G!jnja=eQR> z)$H=}?fl2u*bxKQ_nQR_t$zf1t>l7hf>Xm~vY6Q0-$0}71kx+@bj84)i*9fK*uk^+ zU+IM%;Jm8ZXJ7XAzMS@ZgJAO=Xrhp(2|joQI=Mc&yw|@?f9ZLw8J03OAlB~r6*JnQ zP0AKp;8Qq4eL&3BZ8HoDp|R|a{$oM_>#`*os`tL|`7a>(e-Hfcf&V@5|MUTnR)R*c z?scGr06%{NofHkc^(A}VOj)|UFN0I^vyrPl4so=34%MgFNoR*EdI)0EFpt%m<|yy|eN;;b9Atjg1ZYIHLiu zfDAs46%hrbvS7x$&$*^&F=Q+cmt?Nfo5dq+_kAHAC~?H$_b-6@lw!Nf^}&?_2?K7k zCjR1D2K1M@205>uKSIHWApzb<=glX&r@|wo3p}o^bGZr{D`u<_hVhInBtq$ z>q1*X`80QF!v$aNqmqy}^3`%*8ur$TY4ADknyL4yJW(SAm2wz-bW`Ns{P<#hu)D!L3dK530uU3oc!@G5y*!b$i!- zfp}ZCw7a*az`?S8t3Kb+pV#Y7Isfe~fE6}oS6`-Dp!?eUuF%vEu1p~Q33xEy_FWnXw=6Lw8?Y6NU7QnbL5X@4;JPiUyVYdwD@A)EE z_-S*yfXDU%w<2R=t3}mgwCW0ofoInq5#rJMFRZg}Era5WE&>#1jsA_|#yqCGt?t0} z%sByF#35!M{L)@W#A!jZgOM$!ilHB6ip#$C27PZJzvDH%F1Y)(nFI7Mu^(TKKCoOu zx{QJqoIn1ht&c7vc(16KY>-a|ls#=}JI}vGd!*mLO&fgI00{Di!MnckS5{$ZGzdgO zOo?-Cv!q7N1rdgZq$KL|`!#jkkl&oIA3VL^f28@D$OU8!@I4tKLm}U!+*9zSm47{9L}X;#yZTdtgu?X~g>~~|IbM`v-YP$^tg9QS z{mlgGdQ07t4HpJw+{U`{7Ee9;3J&zrS%(<~H@-G&D6=zrB*nk=z|B=s2eDA(LC}{W zi^Gbd9>>s`?tz}}^TA=_gDLgmR06R_ z#2@c1-O`S;O!J=SvE>!<2ftZI8s14aBJR2oxRDej4VXdJfa ziKq3_lUAxq-`ET+<$-0qxzRKq0&2orz4F5{|JNH#AFDeNmg=aAwHv>=@*K-Ww6s5` z>HEP5omt7Qpbzw;=%I@qUz>4XdWq+kU;lTRXz4)Ja)Lq{xx|I2a~_?78VDM>=dzGd z+nZvMKzC0IZC=_aZp}D;53Dqv7A*?dPD6Y;2D7AyqBPxGx0eDz(@SE{99B*XdHzod z2f$@yBH>AhX;%;@m{!;O3Bon`Wex2~QHa+frp`B^V4EM%L$*~5K zRUoQtv01ZCt3E=i0PSSjJX7~BPPs1))$eEO4@gu>6aWvDp7r!C-{8orN$?3H%u`4X zWomwQIHqL)J%Lc{9a&i96Duh91?BzMPNB~^nnZ7h2hv0N1d8G8hvj|$BdvHhyx6M& zDdbV=c-sD)s!?jE$kqXY52Rgh!FjbruG@C0{wXQ{d$LjGxKRQiW&5`Wv>)LWGxh>2 zKL!0qNBR{(-(ZyhXW19CRFTmVuiXPy$_GQ*(~r1~G$$@L;ges}0I7?=7`!f7?&X)Y z4?snB1k#xL-mhCRaxvYTkC#GPs!vzItO~8K&1YVe+vyAWZN4BTTEKYFsA0dbg_CUonZ2 zb4@EP{-c&2Cg@$SsEg)ZEgeloCwbEdz3%DX*@H~t%}`v3PL!s|FVlxFwjclE;ZOi9 zc?UcS^1qHI1>%}M@Zl#-%wmYoeNV}+9a<>hm*|@m0Sh|Ie3u!@vfK79hMvzsruC z{;KkP^{?TOGE8nY5L^W#2(3@Z2bDem_Icx(J>Q5GaKC=t_CxKCVRN5&bBz2Z_3CD6 zm~fgT>`>kD^|&s8_G@-R(LTxO00@WMrseU6Vdb~Ds_%_xxW8@j0(XJimJCWuMaMPY zP=t*G!ZqykO~u)pEdWG$l@A1aVSK+OWFTIiGCMLOd#?{iwScclIVGCtEyaP*Jr?8q z&9Ha!oxA6W-Q-=eGC)YjU^8+@ zwuF<{{s-NS{1#f*9JgvwT?Re=s6edD=I>3^yTd4pJ$F5wH?*tdJFZN}|1IdxY$y63 zwK~VW8*X9sX|Gt3Y|^Hi%jciFHZ`Xl_HPE@e<5M78erDVjT0$nHh0(jl5TyjYORsi zt&!Is!WSnS6_<+3iJI>78t3f+U)U2(Km24*e$a6vT<$g5rMbNncLHC8kZ2aSd+w&{ z4+cB>XX!ey=b{9VHMh-boVWS@Xn+gUg$j~Dnv90PlEBrPW>HFtm(<_)2gXyJ`=0)n z&wupMt7Y?Gw^r++;dTBWev?QF;*RuQ+_d}jeo~G(x1liN`{w(P50HzJ!6afF&-hcT z0O8XQzBy+4&m7|W-vn8$>hmi}wg}A|x07Um+mK*xKb&b}@47~5#cIeH$mJO!cFM`c#q$kD_q$+=RFd_7RyCd>(_Nj#VOxvSB zx^MuH8XX2-ZgHTZ|JuF8!~Qv8xW4^hr&jG2Lee}9Gmg}yqLY}Qg#9McL{Rw zAlmc;5~O?@L+fxVS%SOo8%ccms>cAQbO4NA^sGT{@x#g002aTQgeh-6u3fU4vH5)Q zvUdBW#Ag6dm#>pwwLCshUuSdthf|2r=l$ycYK`*jO*Xf~G)nH1O!4pEzdHb(S6;I< zoP8;C8ps01qXxm;*#Rt(F@dB4{$kxsuU{k-j{;aF~F^Wy`To9*1O=l{#; zPAD%7;DdkVy5Bt|6zqtx##zir*!}>UfQ4JLY4>A5FBQ1)#(RN$MD~Z%1FM8>dJ{d* zGMNCNGbtr5PXEOp0M_YV2Z45_U>4`x7G@_$s9q&S1xsn{_no51L08lD{br1B_O0)` zI6#x7t;*&}f2Ez@2M|6Dl?KY;^iVpvI8IVP~>qFnn;d$B_XFD|65B#XH1TOa zz8@E>&SeA(2gO6a>AfDAQO#DS5Le3rR2VSnB!Gw-1}=itz|&y6tyK{CG<>P!Tdr{d|zC<+cZdm$~hBGQr z8l3_QVcUZ~K0uZj3dT!$eCFzq*e|5{H?u#xA^;^7Tr)(;7=5(4J#>kLCNwZ}_k=;m zS56Dx#nz$2K1uCu_S}PFABJaXX z+kcyy`ts(oS2N%NH!Ic3dtNE_yCK#v*1m^cDj^NLq3z^=uL6q7Y<#f`_&qbmAU{eo zc-q5zqeNlWH~8WBL_BnUnh9=@FMf!au9*TeyZFVY_tXh*7cl@W@bGb#2EC_~wBFS$ zOf~TsHGyJav?&Y*PCv#E)<-5Qr(S=hH_yoA&CFgV2Rw9%u_HYQ(05}4>8lQ{8Z~;r z>&40U-(#$F$!11|?V+p>iA?hgOAKcqgooq{LrtaE-Z}GGL5iV zT`yzU@63gi{1~0W$ae0%UhNfBPgOz4B;Xwt|4ncuc@@Kpt2xmBhGk%xJ!taH*8hgz z!Y*q|ZSd8ie^xEO&ohdEhRN}v*SX=afd|2sv%`bGZyL+L`@=6_n5SG$7C8m>zWKAp z^8K?)elWoQ4MF{97teRh@K@W&w?_P{1?xNO{#VD+w~O>wQ``T9r2oHlE2|VSr_|DA z7RYvPG;5B%_jd3C-#HPtii0LFyZoc?G)Cz>C@Qs6NrlGiM>vLSmZznA4kS6ChaP2p}JgrobGx()%Zx?^b>jlNq zZmE5dOFso%SnYdP^IHMjy2H13RMayh2iVc)I|C2htFE*@clbN=8rj@-1eZJYy%jEa z*+}0A(H4>IQpk%UDoiFhbA6?J0Zl_mn@U)V{2C-rom_|Qwd|n%v5G! z2J>8}`}h2o_jf=4ywCf-pXdF2Zhx8UI{+9_Mj!gkdU-{$U^+qu~R9- zuZM4nYw5{IC9koOc@4XLN%WQCzBduSSQN!EmW5b>QDooj7-F24YsC6cHFtFSXkw(d zm$x_T!v;#J<(4Cj+cat$H#< z?r8w|RZN3kUEH_tccd+<@>Ykvy1M?a3;y3X0-4-a0Q-H>kWG+6w)TB=f6R6)yal_~zWsaHMXY?WA3 z7gh`EgC?F@_@W+!k{-eFS8II;y9I62SWL&09q&0wZDZI%MkIy1wyo`l7q zj)gZm{zE<7_jdq%*=3#}qYf(XTA9MdX}Bd(LCv}9N%E}w)63SUUy7Mtn}5B2x3m2! z!%K~;pED0*V{Tk<YR&(h@-)4hjE?Q;E~=;38wmFR#MrmJ;~Su8T1Y@!@o@n;7#yec6x#wLAamng4;>{?`S6UGU$zz`~-Z^4~{WylVS* zXaCpG|1XEuLe_Hr#{@$@g$z90;$(Mb&Y7a)S-K>5Vtv5K&}HtB#rfk|+*eViR91g7Ruf zz2RpdaQ7N-iz-ES#sV^W`~oFbQ2oiTvbqPf(4OkU26=sW@^_-`x_M%q_;=FD3PLq?PUJF{$$UHG4mU z^gcIAvt#}efvxfJ*mfMU`^-IyOlBB@OgJ!mHG80KYK7dy{!zAINQ#yxEp)_-ah~PbO|76@qW^px~%w_Gvdv|5hu#rWH0P zr|EH3{%xoAXqOVk{Tx74jdC9C-#GjJQt)%g?H}H(7Y~ zfz(%3(G>%B`0ySIOU8#aW6u*0@iIM7?>xF{C}z{%Ln3~1|Em-}U#oPL^|{8sw-xff zN}Ze`xA=wbOilfw_|bNl~&QANT1fPZ{Rh=Nhg!f>U`%KOJ;$?!UWL>qXe?Fd+uA zt;>b`{vLzv-aX~C5`aCV$JHp#0k+fkdC2x2MzlugPUl8?T(0=}Cxb`gI<8HgBvze2 zeAx5N-NKnfrP$_eM}G|_=+s_%4I6p;fk(km^cL^$v$ z(xB7AX@ihYPp`xlSIMjc2a2K06Pv|AUn9qRD)}o- zhLY?9#qg)?7uG93I{j-^-HtJQcqIwYoJ2kgS2hsaYhELUkM*+c!~pUV=o5ryLA|g-!w#}G`$WF0M|9MdRzdo41#(*~(+RGgY3L-c7djs}6V8L(E^l-25`8nC$ z3uwGxxt!b>;17-JypP>%45;*gl#l5xj%1Bn&b$-^=8-=B&Oi?gj1qh76mGYCoeV+gw+ zH=qxDf6%GKb>Lg3vi*C&k_NL=7)va%krNz#4E^YaHQ+~oUi(ZL8*}L<8*~DgxYC`G zHPxE~2#B&7QH%zXDmRuM+0!k4L9Tzg56kNF+mzgZPTX-V$>4LG*zHn8?7}3d+tjCE zglGbIPgUlih1I<1chH(ASU{`9k-KQ=LlXdcsh4@o-jY_{Vk@1#>WKuEHZydZgI#8q z0d68kt}^Wn*+lXVeD=vp=*E#_;Spox2;~-G#5c+Ok=0niJ1u!4)Zae%&$M<9Lv0d$2O+gR@_si2Ur^9Uq1rMrMM4jjQ}v_|uop!h4^*INAZH7e@+b+NVNPVBE=*GJ#fpN25- zSM{;xk+O@kt{qO5&ZXz;yjJLyvvqxqq6lSKXkz`=gQ6x=Nl^JWLa(MoP3IQQSWE8G zObjH0^xUV;PCiY|C}wN{!j5w4Zq*FX)Tg&|nWI?;sdx0mk!m+mJ9wPUE26*M!nh08 z2`ocU+m8fzYp`@tgxewB-jp~)6XKPEn`|`L!6?r~d zkUoZv1T=jzs_F)5cWCyq-=!(bRdfTUNAs zU?dnji?fwFpevV)Uzl@-7)$!Rx$`cbY?KS(OGn$CVTamwQI4BbLi|PM?gXI?$qi411 z0Ph`?xYYTr>@x>yPqCvrfk8y^m<;Y4)%r!!Nx|&NiNbJT4mw1*$ z|6G8VV-_Yem%pt!2HiW(_2!D`?s*_Vh3ka9*mVHZiJkUeu{(Zods2?P*l;D4&unF7 z{1O8CCfNdpC*V_{xU;^lO@RSi3I;PGZw$Q(qcFh3UExVV;Z?xJB`8uk1YkR$zd-7m zJTuaSL+~E=(>>6f!4(cnwQGYmC?O}7+N!yN0s;NCiofQMm4c1Zp5I(M!ib=vCAVq6 zdKCJ>pcJz3UPZ}zPl-#rn1I=i4jgF==mn$-(gMLsNp|WE6ejgm)qOB5g(Puh*%)#` zKx<5GkFCt3CuIGf%_XL2XbsnT_b3<-HSs;T9+-@5*H}O|u*mzeS=#k)oSqh&^gfBh^ zYp{U2`a#I2<9Z>B6ZrBcHkXoR6j=kjIpaI;BsHAm5giZ;h5f_#a0P703p9K= zPyO%%)Lb#nxXhDK4ej`w05#2OFGn0H6h)Ap(D#QJF`J8`zQoJTHZJJjBC3dtS;zkT z_AWl)3+SlypGv%1+@1rY@ArpwRr0eMR5v1X2y?zCs zH~;T^-lZnG1bAhj5mOYiW%}fl(^G#^jo0jO?LMMbUWmy}zmfjF#rcU;fGp0xV<$Y0 zX!-eG&8D=>*LF)_+GJ?T(m}J3^^j3C&goJ*7zBaQ*UhnF|+_Ec+QIcAAqE5+i*Pw^W z)*U)mbQ!hzO;lg<46uVB+XmVyruW?OG=K4*rrdn^T686yz92dy;R2bg5mn09Zr?qLO^h`9mxiY=-4)#Zz_!*GXRIhhBvAJJ9 z@Db15W=MaB+Px*J6nF(J~Xb7w3fl1rl22XLO0+O zP;POtbLI^g;WFs1g&@>d*5KbK1TYShS;8Nw7#VW83(h0n^EU}9NYMt^pzQ~wacQou zL)G>IAaj11XGUm7;Zs@O*$qRk-B)X0Z?RN1txv56i}l2lrO0R*wH;#}`+QD5mN29{duKUk;j z|KuSrn}HT^)!9!hCCb5~=2ggdM`Uq^-1=(fUdtg5_Tbd=RffwG?Vj7e#@!%8&e-K4 zvc|{Z$wwX87lE;kvK`C@d&8N%@;lui^fGkbJGXG>49vH>&z4B{$sVHfetUOP*&q+i zJufgsB|BHUe(L)Il8>&(#d#e9rhk*Aaj^HJkmJ_Zqn?Y)Jp?Px^}fV6TfPZq>r$hj zFjZo1i5sk}Jm4iC)K-hmL&eKJDePN-rtvD$r8}^$S5HsJBKlNr_Ee{S#qZl(BTMdW zVQgc==OCEAvav9CVf&?a!1Msn=@3PnUDsza!Zi1Tt4ohj8iF=#J@kyLt!klq)edXY z?jv8nR0-S3G}@e7y5!Oq4ZVU{&rbA}FbvU?G)2=Lw3gt+`sJCFf%>FaIT;_$*xZO2 z-53guK#k#5x0OQdylCcup2&cLCDXpa=)qVgm!O6Oxc}vw^g&?cFXnM;soqsx%X3#s zq!B12c^tX;RnC%rm)Qh-yRkF%Twz>`fY~ZHHDk0qLRlVayhT3VRRk9<^u;g0u#mII zT*|=)dxLBgzrAiC}QQMI1o5igB|_F z*3zLAG*7m4=3yz?K6Cwix6zU!n;K%N%J$bui*}!RHPDlFm=Te(!{Dh8KUTo-Ub9ir z{b`#+S6DTYWzWc8GG)|6@s02sskNn<0y}DGGII}#WuEX$Ed^QaCU9oYk$$*!8DXN? z<2qm8V3}2PVJ1GMVmWCmPocVR+0hP?P)Fdz_UY`+S7TRf3L|owR^3qQPu!>!D1n8{ z#Ly^4xD=6>u=u#laSn=3wA{Xd&aRE(MK2OodDh3Fpnx}kP|AS=q8TL0b(TN-3(O^O z6KiFV0XVa_`!d}xA*Z46sPT2hP}xGb_~8+4zv}lbwDaNZziJ!uUsS}EoY^|5fmQKlA0~zBQ({7+H&55JGPMCJH5QeU6oILd zQvpMEgaskp#`xCgjo02kI4}j+d4inW`QI zw`J5e8k}dDJJ)q{unfly#uW*WS7Cy+pMNR+cfx1YWX@_qDg+=5OTa}G{ll+ODUM^ zgLfXP22WzoF;1}~u0JSO)m<@>YG+n%%r>BYOOvQKoXHP3JL0bttX#av`i(8d-<7!I z?2*8VOr&x_VOKR^w=ppU={EA(u>0oN#LnEOCc@5v@Kb}e=LGfKfXKy<%jZeUj@JJy ztCio+ekodI`*`g!V<|#hjiQwJT_5|_+uOw>WGzrJVEsz5h3bEIt5#uo+}RU`)cl*b zGtQhTzhrAp=QKkgndB&{lv|poO(Hr{o;hlqqc-Rk8yMOeYioS5cb*Ut`9<2=;+W(2 z47K7S(e{sYl8a=#lL(OlyYDyW(^p_(FPl=iy|7}p1CC{9I6pFh%9U{+4IRj-xa5LS zyX)H_Vct;*TW`mS@K-R*+MHXHrUlbJ%b=B7!9(Ns$quT%9gE4`^pWp=3>VO^O&E`g zH(*$);+Gh|!|Y+}@p>d%q9GkdMJY7(x_W%kCrh)Ma0i<@XF}?y-JT!e=M~>bENyA* zk2F6<=z?kr(agA?>kt@uNQ1E5=WAPFE-& zB**L2gV<3NFFb;JKj9~Kw{^a2BF$pznqd)8RX;UPsbvk z2O-Y~Vu-Oyl4krs>KylF+IX421j3^rPIjr|ge~!{lzLI)_nUXfV?o$*a-w@sEfJx~ zK((2R;RChH^n#6XgbT&2kiI-)#-U#&pAX%FC#&=ym6RsUE%K@Yh?3M%{-7R8$u%(t zCmkNR{Fr;u*h+bK5uN1OUejodU?D+Hf5e zJ?ee7qCa^}SY&P`%7PPBxz^dTF>l&#_xy+hv%PX1Nt@t{N`)zI-~9N-pyVLJ=|u35 z?yE7)pYnV1>39^Roy%4IWn8Bp3S&+0#qX6bN1TioX-I4x*Jmy}W8-S>l|`%1Q)Da7 zXt9icjcl9gi$)9Vq#@iAU{l zVZOo+XqgF;qey%HGJ=fX#Uic2%Cp@8{u4{eel*?54Y%D8E(&q)?&l&S6KIZxelLmGtwi z27`Sg(+)PY3k@FXq^f#q#A@q-im*`P`CsH8V? za8o2{OQ7-OK{+xFMomv>wt|!H#noJ7z)s@NJj`*{*lG|Sb7qrM`Cu$AkLAQERYXw> zB77pkvQyMzjVzLxFY!Zg{#d0AuVr3;TNv%|0QD}_db=dYS+nLwNoU(#W_0>0d`fjT zQ$t*Zcitv4?Fhn3A-6`pX2xT~^3U{v$P>6}rom?=OfibKly{|J`Y|*=i1&!>qHtfh zV-h!UPVl$cK8q_`QpV>U5v1*f;>dj3LTC2 ztM-I>?vIpK;;33msBm78N9ck*YOn`Tlt*w*h()>CEq?q;UOP#9LyL z_JdE3+Y+g9ipD4z@%?gz;nI7=ef8U%an<3Kk+!6D{=-G9&ayRrsItSYg2fMWe)_n~QSa+<{<#D?dC;b6!OxBJ9x?`!!-cyl9+4qzT~`|J ziyWM$o3K`1xVzsN*)9NU*Qj#Jvgu4ffiDck-%)SE(8PlX_T45` zmooP448$eekrd@IjC4L8<5#F_@p(L=dRDNKlb>jFMYxGchte0)UC-_i# zFK3%zgg(%~r9B@Cab%R!7sGoZiq^>lhUYeW^eIepOzMUHI(N8{xiY6mta$0jC7Mfw zkQibUK#l$V`9>M-1s12 zy$e4}SGHW0rh~kG;x(#1?mjBzMp`S^0bU@(kb(lr%KWnz5i{OH#V{Sj#N&&1$Qw9Q z7Gi0RQWb>=qSHK{G_)x)UY$quTJB?%e<@+Y`b+9I2)(y)w{mJH(dsYq0nbW9*NXp{ucT^0Gx|a1#w$_DMVTxp>|~`h8sXs;>bge}4BY7|MJlzUP+A<{6qn-WYA0|mk&@we z%o|UngSd{r!$I~LCyEvtNg+Va^yELBsfnn94d>;Vp@GvEWPhiP%}wvRgrZ%(v#Jh* zO{pJPFD4#?L1hfAhb1?jw(o%Bw)|a)R*4$totL1}de3fbk)Nu}+bPaIX&xY@Wjr`n zGf@LKmb6M$MCj1=`ukmuOPH=~GBW&GlJT!s|3YOpy&N_Kh3U|V$(0jGG$$SO&{tR7BqgO4 z#SvC5cZ!Q7nVGJQds^<(pM|!tusG%M!a(G~gi!Qo0(CY>2Ga}HPpvKOENaXy-1rYr zO9u!w4;s)YXaE3Mi~s;oO9KQH00;;O00RZ5S^xk5000000000002KfL0C#V4WG`)H zWNBe9X>DO=Wj8KxZfCT8XFyZwwl?aBItq-Uq98;?!3L-hP(qPWVJyHX(jkb5ln{^> zYCuKB2B@eg5I|8Py(bWwN>{0Y1QL=AMOqRL%+50W4JnLC& zy?cB6PXj%XUnPGP5)u+Q@yD^VLPE>>g@l%xtrQ0SG9vSFr;yMUp%ce+&iTSwv{l7h z>>tks=ic9X{g+>Kj%-cn+O_NU_FJp(s=r9M^y`Md@WkTz{??a1D~5>>YCEv zmqH-$y)YSrgV}!g4ABYE>ToR{smgly>)z|Tjgqbh&-Mk2j`h~1 z;`%a!xO+vU$sTcg1zKVUO3m3!-t+Y$>O%LFz_Ie?X8EQt17=2%E0?nxKD<<9^B#f9 zrr@a$HYt}_YGqSl^t_KVJbYO?sk1W_LW&{0cOo>>&ge-SBg=#N_+Vm;+@sjOlVuG@ z@42b;3+>NtOj!2eHuQCVP~*TpYr;9AF0|B#?&sj!2V-m|Ss>E)xFv?E{tB6@(R*hXp_$}lr}_~SeN#Tp zce_>KNM)xq$5+pH$TQv&t>#;~!E}w3Td}+E9G?LhD(s6pGty-C;naZFodBjmGBPr^ zK?_#ge_ZL;z3F*pxo>Y_MA3Cn^1b&?_K<|wz|q>yPfEdlX5OvFsmT1V9 z_S~4ZUM0$sQzl@$wI1RfGK|;KOv|p4>{M{`J2eU1((cYbj%Ne~w7HcDQmSh_kR>)# z?@djps;?M*dgCFGnXSd#bhq^S{;VyQFdy0SVk6 z2w0hDL-6caD&Gzq@=)B<>{!E&6<+%#EIs|%Rl^U!FGY-;rRhRp#p3f0a>nPak*a0D-C zy-j>-I?lqEjj)j_1$67=xUq;~64m9)qYu9o3(E4B_V$;?)t7yGVwuv%SB@LGx8HBH z=M0m^9CJ^bcwhi&%&W&!5Z%>%*(Hh$9uBWxkooJ9?&I_#At4`9OW4XKGj8Dr&4-ZQ5~v=CDM)(g^xv(&%uOH)Or{v z%}Lrv<%I!E_^yPKOreqzdf-&5+O#yPZChGyy?W~mR$DM&+xhNBqQ^(jKU#L=4F$Fp zknR-^8fT^q;n`LcB+ky4olg#buk6D>`{XBHIDivJz_M@{_JLgfOPD%_M3q#gW}sp; z;kcud0GyOiHs@ouA|9QkHUt7#lW~E?3!cUXr=X^h0%Rz?w>><0aAL~V#ewLGcdCy) zY)l6rayn%S=ZC{sa&v=dZ7YuP0`sh-$WM^e_oyq#IJDXDU7MK;J7z~eC}rZPxpCaI zK@{R9drnn4cxFUF7TfOGJX$*bN+~Qln3Y`}?y{oDFg!KTO3BgsT>3;QoZ}kQ zOH+Q9yjEPY98HEex#U*sD{EByD+{deTOGu`+2K&_d+%>U`|Onh%(=1olC}^FGuOaU zi*6_AALx<0Hfgw5m2IZctdQ&Jcse24XR-(NtoMt zQF$|1y-Rv(~~rYE23LC|^Z*Qc;tEx|Z3bqcqP=6|d%+@zvP zK3~A9d#{--qv^hHgAl#w6>z7`Rm9 z^Ru)2PHPlZNS;Rl z^%m3-RV3|aj5^omnk!cm{iX&!L0Z#}MD^qwGan%M_d9*c__P|N2_)?dj>=*^G~or_ zvawhH^vFn;#skBmtan=yynJ>gcVR!-i-lWcPU}u|gh_kVqGE zRMnj@2Z+$X3JU<;FMG$J@7sxZT%=MZhkWPqbjrH!>`fs!K!)2@UG2R;YGvgVgAq-} z+ft3UvE76|$ya06z~_8Q#^#ru=Ss8JxpQ8Pgcn5)^YO6Az}G;jkl#w;AJJ#VS$&@KE3Ku>BlY0biqWuHXc8fL0qSkLbhZkrMA zKKcrnhiikxhTx3m`Xh~!4h`z+G%%P^rP_1(`S0g2Vr$(d9OoRMk7-Px+$_Q7-2W?$v z9^zy}%YNFj;+)`?gGPrxGhKF!<-M61QWEzFn#tQlVN(*SZ>o8l+{_lMXQ9waLls(A z@~UZZ;>pA^B&?0Cnp7&<%_P=aI12t!0%F7=6J!lAQQ1~IeZQGu1E%7Yw}WhJp(6*V zO}E3I4PB?iRx@s2fiH^ZHH%0FaSmC*|9gZ z)u&23<#J*u$;lfXA~6pg{nR=xm%pCOeiC)iB*c}f>^+!~ZM04yiM!HlChJ|e=%Ie6SPgpN?iBOu3IVBYJ>lI$F!#^058 zc~P9O#+eBI`CVGGBQ1j;6pLJTsFGHs0$VlxeSBn2zzMb~fwK`-{=NDa>qfkxoQ5RtQHri!BfSy+6ba*xh^#0m(mPw;bqSi^plGqYHn>?|kyIAhnOjhDs)dmCm zx-&UJn6}-S8>#GD0U9C5qTpiA|6(0&ts|{aw9Pki-WaBAP zX5^>VglfKwp<8}0HGD@E=Vlcrk?PcmJL-~6s=zyI3h4FgvXkBzSVm;hd`oV(j5UV8 zr`p-;7ovarO{vYX?k)yJPaz`mjIqcE{vDRD;71RO_|IgWu?e8Hk$3H@uFuL!%s}mE z#o1~E$ifqUCwr&y8wX1DlF7PdB4?Zfk_*@tmBQ8yv3FRMWy!_aFNZ8sgAleeC-0#% zEo{i@?V-@aUHPk7`wkZMUd0@w`#;g2xpS1+y-CW8fAYBe3TdxDHxQ?1Zb94P5QNg? z-FhyK+`W6#s|bI@)<;aEwZe_1y2yUxBb-+{_`aoA?6G*CB|^tpU8*B@$`41%IBiDg zr4bESW-wtunB8l25#eW9efYC}*|tt4{ipXLEQ}`X(zvGw@^U*k2FaK>moWl+M{$%JV+*3vY~+C-)zX(6j5^royb(8% zg%dO%8?Fy?;MK^TA)d8W(Ze!9I^${>gP5P#xtk}6qZVn3$s*3N{Fn1ug<>qqdYcEJ z6u^N0&>TuXo4F0Pfl|LUYbu?w!gYgEDZpx7ySS^zw>zCF{wpejX*Thkh>kd$8RmO3 z8=hYF7(GY1a28wOQ^Y_O>8E%3OdDx499VmGzKJ<)4h)fVYt42A$#;~RJXojH*gkz| zcCuPKqt`raaEEGTdV?7Md|PjO=9128S`1QlS3f`)9g#hz`Si7sChn^M<3xoO6E9F ze4cbS)DQ6P+IaTo$udp=qUUG0&%Alb4Tz_W7X@MR;5!uayIrv{)lAj?$~)>vz7?va zW3+oY!9uBDB3N8-Wtr$}tw&imjWZQxe8P>ijT~9>cUe4unQicSX9eAW$JBR{&~;L$I+A$&(cJ>l?*X&z#Vt1`rn#|w z8dynXZ+Fci(p8LeMnodUcCFIVC_)5J$F_JWK<2xkBI=m@#=TUnk?rp3rsWZ=^0aKl zb=a}Qp!f)$@qrjOiMZ3Z^>JFW=_3AvM}1*T1^6c|E<#*Lc){$uj7wnX6$&}h8}1V0 zZBMZ;;s*1?VWjY@b$Dw2nc~5e)RZZbM!wAP+(g6(pO9Q!VDwT#Vw#&7tm*M<@L2wgE%8-F(68)=*Iqap!(oJXb6B|dCo=#>vFnn-E zsYq-~>D_1Q({`q-NvRnV{Fz%=3O49YO`8)nUE(^^M?kn;=5jvs0f}LZ>$A{!*f*t& zI1?ySz4}GIOg@fpj}5M(p4FD$;1kW>g^_W>iCyZdCuoVWUteTysFV$etGJZN^ZW`D2?;5mmynujL;g`6qc%%!hoiEoLE` z%9Na8Ej<1k9_H%acXRI7`wtE7C%#mv(5u;!GZoCrS-Z1TL2cwMaA@i(q?Ja|fC!?)% z-v(X!1IWJ$yILtoXF+ZLYwm?m)cb&wfnjZSF4VU;jCJr^_%hUZyDJgM*Uq}Q$;zJj!)eXcumshM?+ zcOS;b1mbTNXT6J9I_Czh#D${oZwQXG{1Tcla4DXk!)!&`?OY=kd*q%-M5}E&nT9jH zh^M|}?fDD!ON(o+*g<3f<&dgUT&1mdj>HIJJ#QwUT#EiD@@Rl-1tUW#`35T5S0k}p z>rf5_+297lPn=3|B+w9nv9bzn%xiiI?2| z!V%BI9;04nTgIW?8YLB}emT1Js6k|3tz?+NmxyVVW8~}-+NfAzr>DSL`2wAFVFWj3 zF9AigB1_mc53M)V8ffPoa0#tP6|mMfxKbP1{LRHLQtMHV(vtDsS-Q1~+mo~_$xcPO zm^jD-bUcMrm$B`9M833fHqjC+ZG-{|>!0NT@UrYSTu$yO_;hoW3AF>&gVbwMRBsz_ z9;V^Y;lBAODOs-3?MK)WC6`g+p73NJ^cp@k2;EWM| zfr*&EEww`HV|LY6x*PvWP53>O1=(OM(O^PzkVnbt!&%4HJEzn10@kpP{uUt0G?hG! zXK$$NJADUjh6uY4wZ`qE;!tn(VaRq5kKoZ%4|(9dOph{HqkQT}DpVMDw_7Wz0Fwd{%QsUp05i2$2? zukF zPf8*8*?D!|kO(g}U>DjmZEaTdk5A&k$|$FSclCLRT)JF)sDr=BZ&&PP1w%`Ogc^@) zRO%WR5<9UMau?B4$ zqsAK;x{IDE`;k3g{Wdz-FSkxL6^GSFnJjHidypq~fYrkGwHAkMpyFZ#2niP}6PITw z|A3i#-d>xj_YdyQw416~WaiM%sq`Q5Y)V)rbY%y>a%s_(M^I^=wHd!O9V&-fqFs^$ ztGZ-5fL~qEzPlY|tHIa8TVuPSnSS~OJr7T*Y*Aoca6_S2^M?x2h7>bCSsmHOc8#1zWo@~(X{LRG7sw+L_JY+inPYlJ4x><}xf{2g$ww275_ zWme@z%j+C8CqNQ+x-ntd@Hkdmup8{htfsn^q0Nx_txp1I=leEX!7?+;w6DA+R{>*dsJ@xVoS)-Gll+alMwBHo&XYWl_D;)_tGsf;OYE3Z=>=IAx-77^LO;5sr4Z~Zq z;VTW%gGS}7_FO&mZ_g-x=sp<3ye^;`Mqg{7Ef^nuf-kmzS(QEZYl10`lQ%?QhO7Jj z{&@pAwQ@1%L^26nl4a^UKa#nF@m%m^XK1S7X)*1Y;WO@#$u}!fIEMv*1Kvwo@Aj3LLk z5|XFO&_eC+Q5W0&mN!P+RVpn=fq;EPz1}n3`{SAt>|VR%HR*N&^u45B^zKH5lwYyv zlal6V@T(Qt<#Vef?Tdb^HDkCF09;DRE)}rdBBI?G&vJ+)_EPx=s{MR6-p2c_deJ)1 zy|B6zVz{c%OD{xY7+T0l@45`Y10MJ(1&!P-|6nsa`s6i=Y~`sB9qQAXI9#%OhNvwt zg6h76WsWe9foj+5eddc=2iU#;NUDt>g@Vsvu51so*z3HdYOkc%n#Uco{k@iqX%i?1 zY^A5n*|=A3Xq{s-T*I|zC->Ax2SFX`W3#4uVJ5Y!|@ zhDpC60XGvcP`mO)lLEoUOIOfv2&7-%7GQfBr9PVn>Y1~Ajt%-opIb1WTBBh{UT)jB z;fNB;%NsU)fv-Q&;Tb_c9adg&98mp3zO^P4oGrcPPh0cn`U+kd$ zRpGz1FOU5AKu^XTt=T6QJQ;ErV=cxV zfOEH{T&_wj&;yI?Ae5zCa5e49n~Qiw-93adMj5!T$lBMV(vOYxIB6^ntdU`&_kupt ztA_X^#uXb(S&AoXqXvHzY$x zZV5{tt-h1D0m0WFpYPwZ?3GeyA!UdR)}A<%b4J)IpLMHo*0r<@`t0mPnKsjb#7ap- zjXa!GMm+h@khY}%hCrkHK=l@JI-fpa;$0rpRXyt#iP@M!AHJz}&OJ4QF!&nNmPD*nQ3jzw~M5m!_d24!kaRwQHPv)#jOB)?RUe%>1lt*VL3)LHou36HO!3eb(ILpO>8$g$Ig2NH}gcA@~v!dY)IkcQ0qMqXVfSOF<_6I z1wekQ@d@@LUp_2o`>7Do^ZQJU(%>(X0H8lru2=fIolW*YWmM_-tNlJh9Vy|Ii6ck{ zuP+#B62g|>Yifh$4m#{b>IIB+RkDhgZX&8uU5F-R3+#HpG-Ae;H@{iQ?`a8A9-BY+ z@rzJ5e8#yhB6!BGWR*~rCUA`u5c*g1MWNDTm5~;i&z1;@ zFNcbDi-@S-AMVqhD6oj3LXJOM&=<1KyTs|VoU@eolkv>#apL}BnlqYy}~fPX4N zBGYr6TKV|2p!ng=P>5*oOgH4&)2C0LFfZoUI6rKa6KgpnCzm9rKmX&l#$(c<31LBY zwG7cb%t5MAamU+=ii(z(wa$?%oVSRJ8;Q$NH0sJ#=%=VV;D2NPy0wp z<~cjI1Wk5!zKk?zj*(3Cl3jX5o)g`pDI@e~IO7Dpd&!a8&CxABAzBX}xgHZ5?y-(6 zu3mO!9UWR5pdqyDj74OJ)cC7YQ6@y+vxK!v-b8+$$#-GmV@~=Wh{gsOr#K6UO4pr; zNyd=^^iW}+vzhGUzaP&^(yM4|$NRmRTfz@@-P#{KJL8;F=J4_985+s!mDE}xjepzI zjwoSt7?iX!%F5$*eMWD3>GYs_k^4!t?Lxkz3tL$Ac}Kg_Pbi8^r==C$8kX}J+U+F+NUv`$!?PO#SBATF=0o^?ru|jC)NyIu4 z|6Pp5Ci2%nmk?XL7N0`9KOsa{f5n!|M|`I~*uVu9loeXTOGMmao5NNL#T6qSGJPqJ zhzZO3A0YI9o&72;ACHzZddAxMq{W7JN)VZTcVl(Ab8320t`zo*=+)y?KLM`l-(wMZ zZO&Kd&lh=eB6&Jsn;s5E@ksM7BiG!~<$57?P!8$fZ(AMG}J*Q5tY?+i2gY?U6; zhA}|A5YqHWKk+vBi>ZzKlrXImlR)>H_ktpZAmgU$*#X^OgbV?b^wvPWcWPWRUXw4k zeD1S3J2h4pEhYy_0>EUn#UyM3-JxI{^Y^rS{MBHHNwLDxMMoj}+p4_ED8+-?8@FR9819J>q*5caVMDbY|{ z(*;Ov=E32v0&XSQ+6Qy<-sGTZndJOYEA!k-H-Lb=+XdHtsdYn-=i&i0S*}0xb!YSm~VPI-o06wPjzjD@s0rw5EadoznYz}${o!UYecNgnJ1B2B8QS*(ln zDOEr|dlXp9(%lz~>r5hIi_m%?DkzE&vSrDris=?3!}KIzh_gp?#;FNZr{UESifIP< z+9MU>shm=(578(b$XuN_t8t%JUgZ_`B#X)kqrxASOGl} zR+n|SL?@8JbCnSj^Z+++eq6xNW-t^ynCuRRWvG_~HN7})T#V^*WgOQA*stCN!s0$c zu-;l9i>?zKvH_~yG6z9>O_=f;UpNG_;*8c*hN?gw61Tn|+u$l_snLAr% zI$pFdKDaaqs=N5ShUx<^v!(}ALw!oeFrAnzi-22R7kaZc%E%BQX6g8Tc(QU_@i${md;?eiu=|J_OXa_u46qZfPYd*QI zY0cuX$i}UNn?me(T$fAzSf|F=Lb5<8{B$m=&j;-3XY1&bRcbfw!Vf1!qbN?;{oaEu zmjSCYJ|G|Gd!fynY`rsg^WsM83efnJEUIhKjY7{p6M(sJTTKz)n9JW80$v!cv3C&( zs`Nh({AaLgN(deOZ|&nJu|H!W?rt!(T01*UE;E_4A$TPpQ!!fHZa@Y!3`7j|)6pus zPseE--e-~bI(lx%rwlg3ESpU|re?VK0Dy-!WC1)YwDPV*=w{_h_f+~(Dq!uQ^ryFy zEfDFKiTY~B!Fbhv9tWU=9g>tk7B?4sQsCQb%VmSBg#|!9Y3@rQ#*uz{Q?P((0}0m{ ztr>JfG;)f^>W9HdgD+ttZ2=nopuhJgL0AFbv5sWrSvO1|mnfc&QB?p>W{Ut$HI`z; z;1qO={**e!ghGN21&&6>r-erYh!hdnBijk26zMmii*gY}V|DK00|V5cu67`*Y{uSu zqyX^s(?*i777vz@a{9l5l`A=Z5qC~iKVD1oV~m=T#&mz;PpRn~gj~2)N!PHFA)XY+UU$Bx27Yv%35~C3r=5_o5!(fX_E3c;Go!7+;?ti?rIJgo3 zHlz3MnM2%WQLV|poYk3Wxha0#I{yH==FY3 zf)60Pl|a+8_v0{-=n|&+E3_xy)-Uy`uwuB0J4bZ&yIpoQhIxZ4Xm|16>xI%1y|@z-=6o2>IXhxn}AaANv${OLyK= zu3xD}_qCe@#@;~ZX87CyGo+oTo;W)G#DGlA?H^}3Hf_hy)L<8a-Yi*hZ)UDmK7I}0 zzXpe9C%Y|QsPp-ZIe0qph6Mbz+RmS3TAY#zQHMCcr23%`-4WVwjAHQAr>KZ%ZLq!s zP}i_%a;h6 z^V=K7lg>=`Y&a76cq8vB>Cl4EUpGNTg?@cZDyRaB*^fYOB0Gn_TajKgM6gy`HvvAf zWDBOLz&Octm83nG3fOWjvFBfsK z#hK(hM{bG$C=b|Fya9IoS`Ab44fIVHcPJW)s*qN~qjYAKi>?M6Mw2WDZJ4t&;U|3D zEy4!yTJ?aApClKo_T1F?qf(ha$sI>3B|`C~-1JVR;HkTG6~&(j>ab_;b%4N!pH5B7 zIr;Q}oo*YDyz15A7mbCW-kS6v7|lgfy1^oy_&ck$wwz4<|;@Y{wLM0>rsJ3Hge^~$cZ9_=kZQfHRI@)m} z^XiXS+w|hNI>PD;!S@TtzwKnO4%uF7PV#;M&GL_zqX-aN8=@~3e@ijqjV*zs^c_H{ z>cM>S#*Nhy&VM9+*{H_+M$s!BiRw*~W+jIDCBXz&ed~rbanM@dZ#3&-?Ze?4N`c#0 zV6V%Qu8bj!Rfwk1$6yg*8n7#2<#+Ifymzxq&P9aq)cD{|jK z|KPXE_uMC?;8h^Rl>=m|a~>ps%<%wN=Gx-bsMCqC;YZ(8Gx*{ep7Wj&dd2nbZJhPE z)+f4lSX~`6N>SFwPckM(?Z}UN2OmEMYhqghhu_))=GzJOB5$f#{5aa`{)56L#X$oE zsJABn)x_?JStl1)c$wGc!Vko@j^ZVw-|u`}tzSF{7HdMiL%M#hej&I%fn$qX4X4g-#^+dNjmg}>NU(WE~SLedg7jn zI?(?~0pTC-!HHk^{Xvn&XK80^{9vhbK*A+HUjza4m+t%?Y^6q|auTC{Fx8SPpVjn_ zi_Wwm+^ZPLcq0~oz@txV9QZAszC7c7XIcT4z@Z!5EF{9sA?H@g5Q zxZwALZF~ca|8{X8sxW4H)zni{0qWMDR<-LpM>;IxzvSC}Yo3_?pm{;F{f;Mn-?R^6 zjxl9|>Q;7Hz$G*FWm#Smp7n?2U24jA@x6O_8%9# zLdG|N@LLDinX*8nZ$P!#h7QL~6w7Y`C=PhOW~FCey$CT$e>M2fZ8;G76!hI5{hL+y zD1PVCqUzv89iN=``9Z_8BM3Hb_!jWXc$z+J50dcPBpO8@h6-4?aS6;f*s4)E+Oms;;coL#c$YI;ZsN@iJG zW6`|!&ZlzpmQS*<1xVp)ARXTPthXMM+8Gx4UyS!H3F_AMkR6OU*(DI~!DI=B5bFR2m8+qOxWS1Xv?{(~_D1>NDR!DPA(!1i~y<>NLP9RBp^j1h6?xAicN zQJ>5Q>kuV$_>MTG+URp{7Bxoz*>fElh7KVMI&VtS57mafcH47X?Wt~~H=@gb&>!k9 zed=43HSi*^#Uqa9$ZZ&2)Nm9<2>5?$yD{bj4Dj66t2=lR_t9E;M9tGL0triCk}9|@ zT<0$JCyo4;7Cx3qYT?HAdr{?OLVv2_&kcB^vhO=`p#VjJg51Kk)!0-7q?9*JGRkJB zho6g~cY)`O)-?E5DLXc+dF_Eb-#EykO)3M{OhIu|W{9IFEv_8&ax z@#NJ4;GWL=#63kuzDUP@My!g_|HLY_$DTD@2b-5$0IUQ#M5|Z-^H7s91NDI&BAot_ zYKWLo(&<%EHbGObr^b5gR>OdV>$TtRLXl~^2u%}Y)*%IWaRGY49g^01(S*MW0;Cw? zNRS`II5LwzLwI&^^Se0X?&+8RYN^pyKni?rJ_Tl9xQzP6+WPX_<*mp<@I@hm^;VvB z(8ONLTsJ*Z^+Rd`#JlB8tB2PModzJBn?G3y-*15}!uo%V82{09k9Yv{9AsqyoNo|k z^&v&4VYhjuRx_{KAWH)s zn+x%@*6kgoTmVh`P(8u}$j{Ht=jROY1sh;3V7|y>gjUid=crd&e{n%c9kPOtCKRWV zDYX#cLq08_!x~^Dfh^~s2qtu~zS11@+8?lv{CjGzlKS9+W4u zI4!#;FkfKQYC+>4_Wnd>Ay-vbNk&E5&3|{Pcc5FNvAV+%5M73)5jj^uRoRe3^eqkk zjz?LB3=QNF4OWAvgSi3ysAB@~q;erL28ml0z|JSv%y9_J4CiJ27u^fLfKbMQZG3u6 z4*O=8pzFRG{h9{Bm$ky>jYnxOQKlP>Pww zt}5T4?-c3f(%KQP_S@V)nxtp04zUnc2H{O0Ld878MvNVSj5W@Us-PPEkQ2MdX7ek7 z#SuPbV1W(gr(5>=<0|Fmq3s*FoSO)q^O>YFW>rW3Nf^M)-~_Pien3RqdN@uImMycJ z5Tad!K}!eU|8S6SPe&MR|aP1oV%^(veZ-o7&@g<9- zkkX$6PzfjtpttO71C1dt{(hq%BqGgHbNJ1&*siz*)mp>-XpZ0FGH4tRy9aW_nGasT z2IFAtlhu%(oO@u}fVf-tk?8%w+VG1xfHM@v`oiS_O7<-tu#0-Zvv2jHpiCu9ESz>? zXovpuy`7opa57b&-5O=@wK)V1|7ty7mKf*v-G=T+j)#b86-2XkP0jK-+M~fSTEkbx zt}Ea>4ua=MiFs8gT#wPr-*>nV#>|udqT*3P)3-?Wy*c|77{M4P2>0%N8kh{RdeQ`D zrbqyg2(E<-0tL;_zjx=i&F*n-1OSKXoFm&$x>Y?#9jA~>Rl#zl?b~b1qeK-yq}Hvvz?K4(+oaI>gogsbV{lF`OONx>ciIGadF$tb{Sj zkYN>C`D>B_-lAUvdf8`EeXb(`Jkw$eB*dLhEM1#os=|77TQF%Kr87#u!_IHf5pb^~ z9varD3z}!WLSgx1n3o@F%;Li1i}roF=-M$!Gnzt<}&0M|69SBT5Ta{6AdnIA}7I*LUVRf~{g4ivIiwKV(sGx+Y(O>7La-L`A zyx;SA0yAYFIQ2s4&cz-2MfPF8uhIXX#N~v=ydzn9R`@uT( zRd~N=;i?Aa!f6yBCFulcII-Q>v$S5F+0U9M2DWt_e#pE3H#2@YV+Y%3mX$zAANWrk zYrIZrBJ58)&ruac`RcFE4H9qV1;$L?TN0nl@Aw65V;D|0SNp%v9P*EkzC5?k-ooa_ zUw*er9TqrEj28tTQu0Q1gCQ>K(oiw3@_(XFQ-5uviNaN%lXD#If@}j+N^u zTR5ig`SAbGxo zP)t?$V&3kt;GWNR4g@dK zC#B-ycUc2TF*gT@SW_bS#L?xZ;}TA0vO572JS2~L5vlU;ixNF#2tmk9%<0)l&wGNi z26~?-#57F$;@_ayE9bMTGDp17M$EVu^WM|w_aXXAZdvv(1^+_7kaP2Kp&_tW+4j|A zlV1UwG<&KY90Zm2?|pd{70_K!ng1I z?oVB1`wdO znvwGwEy*mLu(Vt8>~CBvIr`i?goZVvg@FAk#IGhMZvm%jnOz9pcRcEW1$Ye;4*!U#^394@@VKG>?Dz>({;+c%_lw zLWA$UY3aJ8)6dr77(x8u+lGNJqFEfU_4`4w==6e>g~B}hiohBXw77^?J(IsyKQN+zCE27&y-sm%o=zgslB?ChY>bQr@ zR)`y32j4ddK9}6GkUn0EGw+~YP#zm!VxZZ!`#Y2R5*Y6NXZiu6H6!Ufq`F%R`@JXP zRspxSgmekhKE@u76c)@it=Pj&c;z^s?izIpnEwkKonI&QI=IQJr$V&c=*8|M0ezU4 zsxMrJTdEA3exz$vAhtgE52m3!B_`l2zf-soxRqr9JO6No7}MnD|>$Cv`{JDqv|#dlvUED&Cx(%=1m zwS%wEL_Vb4BD^({(mrnY1OM6tdeSjxfPXn_o>f8J|2x|8d3WB@XTSdfu+HS@meqJ+ zLGf7q>KK=t6Hir<7SMJ^UtB=OO?#MNoLDX_sSVZ02k?ZVy5G;gv~%`ThS(Wv=j zse6Km`f4JKX%b%LW#a#xWWo2>m;dcEoT;ajO7fgX8?@(UE;G~dH-StVPgqG?IEI;; zS*i}UK4Sqw*$L#=tMz33E`q0^-YMWaUOYdM9QImDBY(t5<;T?R02usURuS#7KPK{(UyRgf(JEQtp&h)|5%#7UXf9PSgXtM~+4BKjHpDj?g z4+{7-d`{WiYrp@Y^R@UAT&zRafB%K39bjYJcdvBfp$HSRtn*jvMZwp>ds`~W1ka2N zI!=Cyve9xb6_BP4U~CmUWopK0jJo7lT!apQFYh0HZ2zL=(AO{2^(BkaMxQu@5xHz{no(rc zLp=cO)vWyH`$F2oZ(kUE#DTpWgUH@bYg&&G2i_XwVv;OK|tQ~fV&=sv5xpF z-o0wGZ5@=n1*$avauxgi2M!#7`sFNTh|NDw?fdleQ_zF>szPW#_}>F4uE95G@y|tC zzpm@8?A0`|Gv6pe2pXMkJSukM_}z`h@gDuy9V6oRNrv{Ga-+@Segn6QdCBpyw;wv> z*Yr}!0n<8RvTkWk+xxhYN8x==zxlNk@NO56tH_K_16v$ZSvz_X5qm16l#Qca(w~C_ zOe~Q<{$MtEX63bq8%`&@G+L8z?eMk3Sfd8zCAw?Q*EJm+Dq~csF3M_oN6@S; zxRgbW#pJZ5)c<4c&BLKw|3C0aN1db6W+{?32_b~+P9-5!wirVZLNgl6$TFl-Nm0qZ zCi^l|Vaymy3n`49VHV0V))|$ZnBV>AoX_Wc%lUqP*YEmW*SY%Rc;360cA1j6HDbUbs~+x>5qW8$5zL`((#nIlIi-=(k28 zoJ7J?_xga7RodR8?YXq5YBsSy!h(f-@n)Sw>H(a(fv`6E>%DM&+h+$9&X4^43OPIM zdx@~EeSICiNgf8N>%k*3PglM&g3kQ?l`hq((_3p&!SQ`peby$CqaW;?k$}$3EH5uD z((8$O-ti?_#)%1!_vYDr};sJ%@ zw&e>Eld>a|dw$IDcl1|jEu6rgLc@w~?T6Y(UM>Mz-pF&oUu%TDW~axfO&fO|`_lBD z>%t(Sv-Bf(6DlG?gFl6=&ts%Mjqp1E247Y3r>$mR-&U(b1`o{r|DHv-RVv!R;Wm(( z*buyR2zrEXWug}Two*4`f3*Giu#N9W+aDg?kRLq)V26JE<#!mb`pRF{r0K4-3fcn` z_|Y`rw;Mb^nh3$p{%9w#1@`~JJ8?Im>U(A}{uwP-3-&ZTWbOI{IYb$;XhY!K z=esJkOz$>h4gvH zMng$n5fm}4fEn+JJYi@c?ItU~hAtZ^qNvd0F1@=GKZdXBvBh*d5p=2dKl@M-Ln?SL z@a$+^c50BDP4SgWHiWANV4k}1hYA&8(p}=g-!FAuaNJbXYA8eU?N9^L@EH{6&fV<} zoTM061ua3cIJ7;}Vx4X%9bGF%X*H5hUJQPHV-03@764RPe8+J(vLt$><@sF=@@pcx zzahaL=PHEoK1ZikE^^$R8k<%b-#x!=9$Gvh@~IK|$~=rc9=qDFNVn5c4glIMLbR)sqiXJL7< zpKoeuhThcJHc9$cCqqGz+0IrOQq60g9uMG^a@hqU;tZF_vvfxk^+Ij1u(T&nk((K7 z_iC~>LJaOyDN~1lqez)MmEE51RJ?qT^03ZtUgv5V@4`*q4dan(ABw6Hcq<%AqIK%f zVDvW%p6lu#bgi+Fxs_0yp0m9cs?8%U4mG8E#K2K%lPG97Z>)LrAbryg9#zU~u$44uAYADr*i<2TfeQF3m$HlbJ%FslMpv2ub-b*UCdV}OZTVFW_-YxmP$}4I?ijEIk+z3!P z71NzXl0j{3eATi#Rh#Az^kMJaF0RjVxKoVv`$jxJ6tsNq@`%mpl4?wn=b3Vx{DN0}Wa8SK?NGlh%JvRpeQ~UJbR57Jorf#u`eyFx zBb1MGsTpMmhR?VLcoOz#7q7aaQ)7}E=WxJzRRq6rZ6aCbq594zmIt}ZvsLuy+5iqI zyKV`c9#uV3P+fM}=A=x~=<~9uYQ0#Iz5{5On~_!44xOODHyKR2PXP%v_R4+!plQlg zFQcdZcG&3->Dk&alWnCSZ(FJzKCNSzx7lRddYG=K!0-nFwgb*+VWX%@gPrr0xi6n* zs*yGd<#T=EOjZo;F>aAw;%=4s2^V3hDEJ&VJg~j@g?Y?WZwjB>_Qxil1ML-&i|C6=H(o% zg61ugqhuM0m4IMw$GMW7j8RMtT95*EbJ9(^xkMR0uXner{my;&rPrhn`@*}D{6TK8 znqPCC!GrML706v)V(;uNF)Byt2W&nE(#)#}9T{F$-BET;+O|XZLITar8L$JN2_6`16R`V3$I0);y3j~1YBys| z+WGHu{gE?Q$IGe{JZ*jM&V!7$0Blj?k> zNejM~Uyhz0zN`i?;+eh1b;jC{`s3o_jwb~U9)sl^$lWltUOcdQV$-QfUX5zbodwpY)7PeqP)E-atG+1$_}MWlAlUw&S0w}vL9YtiFa_*@ zS^!+hIo>Ho0jkg?fpkF$UY-=6{IEYVPGh3HEeXI`NM_2EL{-(hyZv+K`@-cJayOs7 zIleY@nMe1;WO7vC?0T5%qbOJ!v6^>bVGQrFyx7a_y#BqpAzq2{Q8M+a9BE+NEbiiw zv#{U8CXxooId1?(koW%OrFMK%P!^`6$dqK{5M-apV!PJy z!S;Ur$IOn&^ZL^XND2r(%x)G4-=(vm5g|Ofrvrx$^e(N@6&W}HJJe_tqJ8$UEhJqIeio=hym_H6Rp1``;{)Rp)B`J?k=J~0I3is9l>=Fuaov1`rr#b-*4}8T; zox63J48FY8d!)7Is7DW@fXpd#Zp|=2MJ0h>)IxR85M0XwWY77ba_0+|NAiNJXsH6g zIu<}to-Xus8$B;16F|@`>mp~?dr^<#&}G0*9cU%)E~V|Yetlt*4FEW}2k(i~#+H%B zU)7KA9FR0g8diC@+C)8oZ}_oGsEqEJV^f`laB`7*hAivW`pu0?I>F0KS{J=5TUZcc*SlW|Jx#r+Swkp|Z0q#*T*b{x4hG6VpFXsKI+kdQ( z*)0T*h21{Pu9H#Y*Zt7S0-^VE?gsCX&cZ~$rD-a&JIvK+{?XnOo?Q2_>)9sBZaz(3n(dC^q$_T z;9##hsq6t-gV0a0VeB`Q`V2ie=7Pf?kU6%Mdf0mb9A0+m z&BawBiM{7Xi7f2mjC0k}jFOctIyBjveBv%Yi{aIz3=-%Itq{gE)qdj6x{%c(3&;iW z?l{u>WF)R)#wH*&=gLG!er(&mjjP4O7+H9NYg-nnh^@(#Y|A!P1t9C1&FxiR{QX-! zoykBXWG@apRP8wetrV{QR&OzQPlmzvqBawa_|Na|(p>?nQUUI-{9HehfIJnk%XNm~ zWh$w->TmsKx?L!C0c@v*sS!s>W)O!o#Bl!8;TJJkro}4#Vq$#W?|>H`{-+n}hoGQf zSM$$ccc^(2P~40EQ*kzFrim()GfBrEafUCJfEPkfTadT0fbbc42H`_Fo zqq3QQmBAxejmhqfYD2ro9k%dxQw{dfNkCypl$*bbvrt#wWi?|39BV(uAJ9_v$9@3N zhwl6qx|&pT&h2j_q8&9xFw5M81XT~zIuNmg<_CpUkN&>eYZp1>CaBqw^VDz)CZBYW z*%{WyA@=iojTM$A49374p@wFtD_d5R#aKa61Vj=w=#6by#h~xk+bRNlv-NhY_H4LZ zS&rW<)0f$eN#R6o*7@Fin9${55`N?tXbD0~z$^#3j(^vcAP{C5<-I|R6!3v><3&vg zI0Tu++59W=1VD&1l%m9@m#P}ckutg+!ez&c+s_+y`^lGoxrtQ5j9>8j94f5-_|j@I zr+&6K*aJsmi9i65HbQg9mrT~J`Q;;}JQYd5MnV9c&cr(a(#VbfWBWn#_~W&!;SmML zJJx^}8Us9XrvLpzcJDADYt^vo%RuWF)yt9N7v$pKR1%#k-^^jN!;QzlD)( zCTmp)Hg=WmQU3K#1vAT7bh0O4qMHu&0_P~Y@BJr;I@Rgb3N4mFCUNj!mW{~*=W+-D zCBg#sQJKlfCLQ6cVwW8pq_syho==#VXILqMoLL>VouW0%aP)v;5oD(`2hd{b-Y>|c zyK?zJK}Y8QQqZfosA6}NdD7a`a?-6be!ji{Jtjfn;wnbxLm$wH?Oz&sc$jqnxyJn5 zv%(v&CvCo`dnK^h(iX{r!-EIH!3(eb!czYdR0u8u{#(fZ51}H zq^J$V`g6ztE1~s#u+QKANukzwVRh289 zP#CY~l|?^l`EQ>zz;c&nS;NmG38J0F%asF9j1pu^8Lj0DqxlxJin+dU=R_ny0Wdd( za9Kj!2)z^!rCP69sC;$C>nlL2EInCofTL-PJplVLGz%x8r8noVHNvH$Q&3|!rAu#b zmmhNUT@$&W`Tff~wwIalR=+QA*0WDl3d!26ECsVmdwa^4X6Sxe0t*1>83RA349420 zB+i0=6HYx8i3iE(?cobA_Na1SyyGttJ+dDpzv6DkNUa8tsyt#lJnLm$BGgzr0+17d zslm&nLKk(P(aUt%q6S502uFwq%{{BIueZU=1mC|uO++w!Qu+KlETF#Sh-EPi%u%RG zA;4anQ!jKWMw8$>HImXYGG!04qsv(WptRe#sx@NlT9C*k#joO_+` zi56Cf4(*hga*H?kee)n_P)fr2yi3d;tGl)5FizFHbgZS#08m$$j1MZqu-!JyHLA1b)1={fLNpC-QM)Po(DHgD2~$hqBzdF17Hn^cSO6H{%b zrS<0Ql8q_;qf!A?yG?7B>SXX&QKUg34K1L}nMw!VGB>HEBWdDhxXJ~$A~1bAX5sO^ z^ok7-bJ;LwW};TJvLPYYw!0OTx+ybj;=II{^DAw5Sqbhqw2S1oF?cF2g35toWl)`h5Iift2_4}^TLz@6kNhq4@~+PB}t!!2N2w>zI-3~bZaw#oUJc;)a+6Y z0T9qDa(3`il#|(&S~w* ze1{g~LJ5*fwRRCBm%wXqGl#aYQFs;qC3JC#O=Naq-@M+-_t)6gz)LmaJSykkhb@>P zH+UzlIlB`E)A`-tO7=0t=(M?f%L+Jq_FMO!G`ZmM5wR4zJUa_-zN!D00ojZ}<_uj4mKF-iO696QqI zJEB*gF`<2e<`bK{H$~AN+L|2u{2SeLxx2k2+E(X3?`Iq<=X&VzuzLHNt%QTJ*2PrV4>A*PFq9%>%D8_UDYK1wFKTW!JS+6T=$&EllH z%6{8(+11MKBN}!*Mx{3TdBT0Z(hI12QV*N77aLMu_{AbHFC~S|-s~2m2QIQpfd^oz9+D z$Iu^km>cfRd-!N+aki9gK^|6kUcu{~UNYSYZ`$3vyG3qB`o=WPdsjIjP6pEur=W7G zNx64wq>Y{Ok(O5|J4%z#33d-eZkYP+IJe)XleTu>@sQnjKJj_C#C+R(;?BS_Ro;}w zOfQS79*LD$GR%}mBL6Mu4TR&$GNxx9s?a_xb3th9o`p;5$%OI+lu+Z}l}K2Z>dbw* z#aJ4(pM+X+l;>Qp;hRGDzwe%>jV3=;+3hwq2~eDC(;oRe>*AMZU6QGt9%AcuwRB`n z#c?<@>Lj>rNQwtY@iTWLv9nB7RlF76u4jWc2EF-2AJ0;kVXRP)o6aSoYk8V7?qXmCyvw= zq$MW6Dk!*y&l@{ae91J_eYtb--eOYUm08SmMXRAqx6xxgfcZ4Y5;n71lMPCwdEh%) z$=M4B(~n=MO&Ag$)>)b|doy&h{;XtXy$+pBXdW9M#T^BKt4k&(s#>|AnzyWShkE@* zZ*o_L5zm2V+m8<~j7pbJ*R+>x-@ou^WUXM!dLwZW-&TbqnLoq2jK7WWj}9JLIH7oK z5bC;4T3#5Vqy%tWd+m`v4|86$p(bofsS7092p*H&gRT{u^tU}N8QEq)DGmq-(%Fh= zg4d!;J$idk#b&|ku1Rv2vW(L7?h6ion+WF8cMlcHwm>`B%(uZb*X-_oX1<0D_N3&! zaJPs64oOl~hlaHi6`gES#EbJxoe0ICp+3OK!sj+pWw))()7*{7L4nQ6?Ra7zUx2|; zWVfX#^1*{)Pw$qG-@JE($T>;6f`ED>y@DsbzF;KIzvGh4!BHiS$nH9uH84tp|di0wIO%|cEC+9{Fa8Zg3zPwN6VP<_^ZZI1o4#6h2 zW-^14+4MRFj&cnSJo^k6^?9VabDnp>${y;|L=BC5GYxfD$Jo+V-f}mFzxiyE0#I3=w=6=B zTEc~vtQPB|8r|Y_Lgju=tgp_Rrzt{<78c7?7fbl04}ZuOfZ+!+b$i|M6%DWI<=mmO z_=_9ronjG|PJD=;QKi$f99^g8%+KC8QDRwX{Uasr<&}7KXPw^wq6ZYs=j!c<(nD51 zLvIN5NB=1bw|F`>=PMRl1z-V9=4$A^AH!~($>z1dy*lYQsak0h?G1gs_JwnB&YS5t##h{q!(#noGL>??`!&JR|m1Zdjc4ey&ImdIKh3Ypc zL`(JZE=1}q4>#sn3T>FWW8UwZ%X2`kxda~I?W)X_Q$fco!*ay_k**&81)?5dCOQ|P zW59_ZoluKi+unN*H@|@zSUSJC$;*l|)mG4$C@*qlmX)mVzz>i2Gv&rR(x8o*BB%_5 zMM+HTu(D@9*s1g$=`8ne9<1lI9Nfv^PnW+ST?L%XmS_xEDQ&hdpC=R*{whlLbu3TeKcnms$ z+I_wMp>ep7?3sMa!Ukxq9BQt>SVB*!`$XWsZ%S5Ax-c}~I@#>`5bCXgA)QJIT5w&| zjI|H)3ov=HvRviWpuieR4Q?!X+@!;0j8}1&v&^zh2u#KL!;Zb#!_z(^t(l*E^lJPW za-1?#-U`foFR%@YL%6K7I%fQe9P!gl+r)b@Y!eOk<=C(oQc7=i*!B$z56u3O`>(Fj zap4Dg`$Lb{AKLB!&=R>qA^>>o@`G}awQFYd)o1zhqR8UM$=r4`)4@KAW4Kp!(lf0M zwYvifNPYKZR*)DS0VoCuBW<`i!*<_5-5+u6?E?|zx~rA*EJBQd zS=sqzKC}qQmoe5$=Yg}$FXlBt{JJMww%@(rjy%33OWJv~BSkGaa6G?}jqF*r1E|prxG39~>+F z0R^<&4o#RRZBC8-4}0d8W$P@QKF}j40!!jGSnP~Y7)6!a1x{~XzAJ#j#O6i=qYDt z3eHIzTG^s&809&-R3X%KbQ81h@X9J8{;kIOtHQH@gufB$gBpxQ&rA1M>>y7f%4~g> zW4`uBXf!T=NUPWgEhTD9Ks2lVSg=t5V^VvfeDW$8cyZS-XnM)PP%+uYqOjuO`hhI%_+rN=9|&3t@4rn|PWO>WUm$?x01_vT&5!p?rz z{OdvI3dH4#;p7?bIaZ=aQjSgsL6^E&dY;@Hj!B$o%Qoe33kkG3j^zX)oX^)+t<3Ga zoCOSIQSE_+4x_5yMviU5N)>;a{tPi52J6kopYx?i_zx%u5_u$MEaHj`DT0Z~eKgjQ zZ^a2_^Q79p(6mT)`!EPb@bso* z{SO!^u=%ghtur{pOCAKdh#Z-yGjeQUv>`#co?s@Mc^s}|qB+%k0^{yiyz4K@6)8$H z#5v)aUzxQH+`WB(F_e%S#+rF#gSG6%VpH%00DEter)-Pi!6!@7XMVe;r=vowZ?S*^ z&2_0}1PEIt9(S})`}d!St@&wvP+3S2^^&p0?D)A54ob>Ow)vG)z4YYC&?LU9dlNib zv`vVbF{lr(h8~%s&$|HfOcJ&KxH<;z^8h1jwH4Qo7o=BW7p2L=!ZIM0kXU0~$l0&T zBzFJsW%>%$^4Ud7DGjncTczGY1CHbp=@EHF6)X5!-5`};wpqxlX7qNzeElIs?1Fbd zt2VNuQ^LS$vE?}G`^%TD5a**t`Mkv>Q>rp;rnxKk5H5X@ zS4`LU@~V@G)CQvv+~&I`7t)mEN2!sc5l+9K``7TEDck%!s+x(RBSBQ*E|azT16l!X zRJ1SK)$NjsjY$-SDr`JU^JSU^@%4`e+Z^+;K_Sak+@+?*HtVLzk;y`4)3m?OMzRdo zPvAL|-cdTE_(6w*C9?@d@N}PEr6$d&L@sa$n%{hEj@jN_$rd^`r)b2{AR&vnu?+8d zmjJ4ee=>p@odqIOK#k`UBDA$a9)A_iWIA>`#g@ccHA^k|$X0tk{#S!>-7qz*=uWFy znCp)$jooi1IvpPzuPpdTn)bZDz?C}d5Nq95LiE{47~PJjGm156GwAo8S15@zw@Py# zDZrRjpFp`Ps3@`Yj5M8 z;p%B4Pp;5j6{^to?@1rrm3++^@-pMKUk~iC2 z=Y7rvAgsOsX{(&Lvr%D@L&lG^Wk*(=xrzH@?)BQu#Ls{Jl5hU;>D?{Xa{$K3c}=zG zCqf*+Zpf6kOs-_66YfEx+BtZM?v8|WWb`5J}OgyPHi@wjpyzKQ)30r!#mi7j@mww02 z55{6t5$yE(>S}XZ#>9h44e0IW9}hJfV}O({{YOg5lCI&sAi_EKU}q8V%SRLxI#8{? z`n}H#d;H}Dh7Xee$3|RA)G`PyHw$l_IdewYbb)hu&1%&JmT9KR>Kzb@be{Y2nN?8K zn5VdET^_UtoOsYUAuco4j#lvUy-1etL=P#~G*ufl`DwMyV+~)<)kYm|pf9F-wY}a_ z6q5#l;ADi#YWvhHwUmIlGrFB_tyT}?Q2qNqSG&D{5Up0<@|~cSxVPlOOHuzaPAvIb zos4m;9OBF*i$WmKxJLYz8@uGiIngKz(b6q4jMPieeKV05I=J9Mz`Nka(+X&ncGU` ztj3{}ZP}?obwG+c{=2HYMppvb*1mj=c9SEb!As7Fc#4=hwQM^J%?+OA}u7I42?-K+;D_GEubRT+(b$0F%|x z`uCEuL7%$MXthBf?DCzTls*VT?@C0m_M#}WGw4y0rkKQz(;$zbzN!Z;CHwX$+*-Hk zRjf6%cT-Un%w1+ZH8c5GLbaTw+67Qd>gC7<6$1&VTDGVC##IUwnAyJ;e&Ow_f}B6S z4k2-MzJEE9IKVVu8~#$S7faM_GR-SPFa>_C4z1?(hqf}4)V#*oryh!QbD2^J;;TKj z5M`?E8pK_iWw1wAscw*vYo5e{01hobaIR{Yu3m_nQbi7^#8)odM=;i;#r#~{<4CER z>)YT+%~c_v&)ma$4bs*y#Sc)<8eOsnNL=&tVBs;uV`>U9OBJ^s$`HmQ2QyZP>y z+2`p(s{rf_*ba#8&$>&*fu=mM#*rxHI|T;y&o+Eu_}SpaBZ zCZsnwX`LnNsqw0xo%y-;hwSUomS-W;R_^E3_FR86pi!yPX2W&Uwdh!{nLFSjb!1I;rN6S3^J526wXp*6d2a+p8Tom5m-$F@D^vNHVmpS*7zT#xc@%5Cau|{?)VA<2o%1alUZlt z9fsH?R69S}cjo^xDgmf6TLEz2CmQrK2}eH`Bk7&VVo9%dA7Z2@@rWG?_$feBC7{-q z%Dx0G{tBP5PR{tJr~f*OMvaN93o~qYXG%hJqN*3`3{+TAG=?LyN;aAS)uGOrgxC>x zT{w71>Hn^RKh^89h0m*o;!8vQ< zEdrsNaQDra2S?)ozgI&`xY3pxU*p>Yh7nM`WI zyfm5PTfTW zen(m4IclU8KV$Ihs3Mx)>0^uaN`>b%Z4dH#^0n9g3!_Oj)o0J4_b?cf1efB zoL%}d*8@8(?*+u-_Qoj0j`L#-xiWW9^s)$}I_!fx*9#JMHz7scRtAC4G5zu4#Ki>7 zN^QK_$GHjl>zu{UUn|x;vSR_8Y`^)RQyO;b`Fx#TvBx_D?I|ZE zuPmcs#xImwKl){)=Xcj5jcnC9j!ze^qu_n5Xz_Rb{j0xKU|85b@TF@@dZ^k+MpOf| zP2dfc5v;7H(lw9$?<1E*j}RlzjrNm}j(z2<1N~K1pGft}&O6s$Irg_sypv%j@MeVL z`v)&)LmS6*KjSvWlsOC&WEF7rAGxyX9e>P{qQC6gK-(4@vA82sJB1!Y^k&o^n*Pcl zD4^~B((|B5(Swk6{Xqwn=H?r0fxp;5oBy#hD@Dc7i4!*V*`)ee;w@zET0EUleXR6Q zwytU@^2Eaxd5AY5jTpyKblCqG<#Qp1(}mG*-t-ue*r$s-e3q^okeX!Mhpg}ZM>tvm zGe@DO3L12~wTRlxyU+yq37P!mDEhX3DA+Lt2ok8hKoA>9$hG$-6QUk)myZvz-ma?; zSH=oKre=su`CBh%!8qV%rEt-hrUY4pI$N?Y`*Ua>mRs*oprTj?XZ%B{bIG|aH=y6E>ZtLZpop1DnJ zNH}%Ht|0aNkOOSD{NLY{19?BM+qV}>fll8_GE+4DUeOPqhSYuJ{?0fD(my{&SC8BWN55#~pkd~n(W3^8=);6pc5BvmDH)P2d1(c4|c+z8b4B-M}%J+?G zp9+h#YF05mBUVHDJ9gqek)r1`fzA9=0Q)%Z5B-?D3`}NqoIvkj2Kav80!2`ouBQ?5DFI8jAlc|ATOf0Ss0TNYBOBH(n8Y{1jdSo##|u20nVoheQMek-3hN&~D23OHDB%R$mef1F;-Ob6US(@x!pc z$Al{?DFrlV94gYQzPFY2tzI6l7%GQJyS6?$Zq30MIw7K;@rHm~Z#SzT()ZHM9|W|_ z8o|Tw)a_DuBhOum93m8s5pPljCKnvM&hx!oB1MW#Y62;bDK;Xl3?JmuXa9N$)qHf! z3$m9t?$TeU1&blsqcXKkOOZKf-um5~Eek{n33FrjajE6{doyu0nFduM}585V$ZBE=8`kOkCb z06K=6=tD(NAuNYHUjv=VH1&8+LdgQ&*?|fzp{(P9Ne45YvVa^j`0O=v?G2y9^I90mPSg{!t}dVMgrnLnpjZ56(-AaKL|A^r z50yX$L2&?IHr$T`uG*iXzYDnYdlK6)Z0moewKC9DG#UiR7mt9Fp`$PaI?Bt1?#HH= z`nph0!yDFb-kr1?QaHOpv&ke&sr5D*_$^NG!ciugEU$XhY< zzIAcOQ1pUoi`xIn!C3)lC37n^b+HTGv>ymkt{)0n_x?LpNT`KPL?Xah7d`;CK|sQl zd`8WE34VYCv9Tpzq4LMV&;7NLfSglpdVetd!&TqEL3N;oiW3b=O-G@NNTdB8`%SXC z|J<9PJwLEr<7^<17Rj$(TnRV)RD8??8W|*ny|@=z=xW#Va_3DFG<h$bFS8wHvyHOI9>kqP_Td3>4 zZ#UI!L0LyWXLd7X=O9oE9plJr2;V5C-mblF`}XZ-AEGQBqW07(C@4g~dwO(b{lPM= z)V1w>$_`H2E&f+gChb{%=f3VXR?dy&VKU360L4q#spQ;c@5!{k`P|-bvQ#r#ajUQn z^q@BX`UNMDDG?MkZ^EEroSw1m_a4#CwIjQF!4EEH=jdi2VpiU!(vcM*FD+6Rh7hYu^dL+6+F z>qi`gnj>f}zfy^{&NpdYa|i0CveNz~cj{R06Yb65Q^I)d{*`VjqZ<6MS8^YC5T_oB zIH~(`uHx_FWJjR|Yffd*(n5U5+V#ubbKD1_s*O{_E$;}_mtQt(e$kCyjB0(EBt17> zsseS1S!tK@*f8?%PAy+YmE;T_Y!Sv+_QUp!{eNtrqSuhDK`o!{2>^)3^997QYQ=+z zMeb0INC(|LN!=&UZ>mL~QtaBsAeWHEfVCKiisVr@cJq7+_EZtt>+w9XQO6 z^W03$Q=|as+-8#wcf4`Nq~3F3YGk_Xj7w7r66(p}i#d#KY+nwSue>&qckcI8K~G!e zp4#Zrg*uPp5o=-9&vbnm*WPV%j<&E=cqpohQ*`YaZh6jRNkGR8k>Y6YikVyd>K~G> z_k}?<@r9nf0CPJ6qbZV}9GLA5R?SYvBtSLo(4IfL9E`NN_)5!LyY)e@Z>(Wa?Sp;N z@57;DPmPK4{>H|ZI{Rh5&r7qt9^zyWFq{iZIu*eSz3j$x9_~9YW{xeyqh^$bVML=Ur^yS#{s z^Xag#g4Uvh%O{}92R{(l87#HUI^SP(qsZ(tWDMI=p{&qvh1ZrJ@Rx^DXCqT5O`{j5{Gm=)(v$lZY{$IN{SQ@XTCAnq+(fjthq}Q!4#-OBSF<8C7_88DB=v=LkIp{ zz)Uzb`oITt=m+#*a{uurpi-k5>oqqHr|ULtFNCFd)=6O=b?hlLC^glZHg9|7WaQPN zCrrAe+{$-%ogTG{yX2vvI{^Z&^G(6aj$A5Vm}MHj_S{9X zCwih{R{h-j!=(&Q=WhcaX9%?Ek+#}peDrqNsA;NwFYX9&D$svs+?DGl;Xd%;vBc6% zeDq`Bq}|bDP#VEqN0k6>K#{+VWI3}M;xT%cp>q^aWr3)3uUX-}ND*aetMV(M!@=Ce z)REq*s--jK-@nzP;-Kr)vFreLNi1UCA37$HL5F%*AX-EjQ#D4 zAEa{;^Qppudu;gq?akAWB^{QSc&+JnGYf~}eT9Yoo^St{0@GbnP`NP5>UK#jk!gX>w=F#&PX!TBOd50! zj&Q@)Io|1NC6SfjepLrLhXg;1@R_#GmG#`EhHLe-RU1&;^>nySJIh>I!-mo zrUxB8LN4w&B~vGI`nkca>~+gtOey-S#Dy#^)#-0*p!M#rY>W?5%e4*zJ-`QvDz?f|qzCSw3vyBW>ba(@(1y|Yd! z1R)^XD$Cl!2lrB3mN}>eonY#@>0JBQ2%DCNLCW0Ecf~y?r@v3r?tir33*iSo%-wc{ z0@_1LX7m=ev?R^{6Q?m(&=|?QHmH+wrL+p_O~KL58+;ZWs?>OFzr4fV3f2|B##Ei& zO1VOq{?tN$OgLdTcJA|C61QYude@a%o#|(@)tQ2F6*CUrsXd~xcJCl6TpCzo4E5a^ zU&J|O_6ttB)|jX67gVazmS1RKO~m93ErDn>v`qC33*Z*>%&u&!@5>w9nM)bclL=E- zQAynmhhO^UGtw$int4X%A*WLlD?hD{;JD~b#A7r%>(XOFE$6t?_~1dk!x^)h(gi2s zzAGo8xC^^#v{GW6mRw`-LbEhK0^&@0@cUkez8-GB5O%;Uc?&X`( zRA(8=V9?~qkvUmrcKpX93d$iX%tIi{q#(7Af4V52z9$OHP5^uj=p z3b7n6c(wt@I0@f4wa{njU&13&YUFUT-Wq9ZlUp?y17~!r0kP8D`h@sBp`!~!`8Ory zOyG6j!W9d@58;U;OF+ga;UmTMeLz030TYJvO_v#T{o-H;du( zXV1Xzr}K?*RpGEy6-VSygoquM)}#Yqm{%wGS}FXuZ2Bci zs;A4Irb*y-6lz`(J`o%7hYW^CbW^#=Z_MbeEe6qjn6?K1b;)5QWK%7hi#3uXG&MbSW`YzDqKvwpwPpA6FOB`EIXm9KHUhO)o0oMEq6z= z?}=K^m<7KuZKe6pkTY>do?W!kPyS*AzvL76!Y;cOkmGodyx}a-p zgj46xpG_y=LB+@O9KEM^HuI6SPoT-}ZYkg|by=0<`yX}QUs!rCR+=zX)F-MYw_6Pt z==CFn*92R_V4;Va#d?Fe6{LmHe750(AWCNjeW64RwMBrPl4Jkc-3b1;INwHrCT1e@ zUT#w#2lafu*ytj|Fu^FctK~ikW0jAh9z{OM4o|^^wd2y&?c}+aPskxJH5+D{ydA(@185SjmR{R( z{{cbWP0u>E!n*7_x*xI>D@(}P+g^qefFG3yg0=7LnRxS7* zkOI$pZE|_gR;pH`IXPIo0(W&UvxkcZlWOS`^MdxT`2}ulFW}fJt~|hy2ouV0j4DtdkisVBe|6f zwJcL8R`*LVvCVWm>C<;0`NrY0Wv>&`GuHS&&|mAc!W-G=Afxz~)WX_a#-mKNKQ7^A&F5W$J9pxh z@i>X4g6-fZ8L6`i4~(|$ubzLn0h)ybGz+8q!{7GR44;=nuicLBe$Xa#3&b;8GE&~@ zdGt=PyZVgOym0WF!EM>@e^dciA#nk-nvkZd1cB(uo_;)L)7qpCerUAdhhOQunbb=> z>$wYN&I7Uq)U8NuVHl8dwYF?idE&bKEwPkig*ODq&UnjH#qf)ae~5_E4^m)fax!!# zx_gYDT9T3K)Awp;?9`;)3Zp$%g?=`043_g-Fxmxnh$8AyehE5a?2C!OY-r~^m+RvL zDmqQ7#sXT!qI*>NxD08|eY(X8lT5khvUZd7Ka}_Z4g1t&&)B)b9n+T2rPanAb$znZ zjpvVZM@I;(j@$ni`TZgZWy5D5--~)&mEYW&X(U_(RW}=yDx1y@rcT{H)~7$NExi6I(9z_NQIg~$FFU_MLHc{WU1;>ZaAD!t|8zw? z*4KA?3*;gj_VdHe-s90SU7TT4fR#W9aOdfc|MMrq@|*{UHTv%DAOCtDXdge%Ay0Tt z`oJflGrM;-?tCKratlC!v)KnARkrpA8ZBtv+b`F?(uj2j8g}Ejz_1^SlIX&(F@6N9 zXMuWH6b+|`L*knF@@{h}(zbf5zHJ%!f%UzW#efLnSs?2z!X`gvxpAp)ajyUWS^sQM zgUfH%-2dGLh6GNpWoWPuM4Wnh9N2fynOFHt60{-xyWZ#1`uk_h&fj-)ZmyvFobDaB zjv|I3`YggVzyl}-j~Ez2f$e&2 z8G}eD9o(iU5d>N!1{$h+2DH@V@-pAe+jp0~P6LlL)Nf>Lvv}0;J9rXu42x%h$ANk* zAc@0Uck7hO&u7hx|LaF=I52POmg48<(vI~=y0S|=>JWY;<|Tw2Zz@MnLOp7GUM^_N zvV5DQO~r=Dyq!Z6+tSWM9`S zYf$X75HH*cDi5H;Rx*X_0v>_#MB))f1}&j=-40vEu5Msj5)jwd z(?bkW9XZOWh!jK=oq^lv@aN-k`Lut3e!k0LSiu1-AQ-aT8u^aw`1x%1Ss`zoL}0oL zPyMI2`%Mz4M_>JW-|u(EwZFa?g3ismyQ|dra2v1j{{R1~*S$R|9-mY7^;Ih909w%b zrNzK@`)v8TAByGwea-KtfaZ-sW5!{TsiL4!kNd|bOm3?Ln(TXhUF=(~oF|}#g2iuZd*R>I-%4(gV+4d1)J}8il6QMe$N=RwenpZ!wPMX4-dJ3jz1JV`*z!H zz3=E#Cn3u%lDs_5nNer?=$axBI?7EbjlO>HB8@ zTgtZUMH#N}0}E<~hYKCpyJpx_Zn~>l{OrukZ~sB7#6UBG-^$wgWX~+>*2{|8mNRqq zm;GUGi*;Q<<2m4CcaQhU`mPRJ%k}R1scc||cyr2t;fguTz*QST`{UMnfL4-Z-r2G7 z=ab3)Z)(n`4)6sfWY7s-#h*)ko;I?}&A7g46|exkEmu9W{@A03 zhub%Q;!@B62a{7HUr6%1J3GJe9KGfHxzGCDiL>)93K!YVoa8s-3otp%F27fK{0^`t zd$#4W-{$YHXLzq&5m$CI^&5+K^6@^?xmKk~PemO9fYk*&Fz7Tk6ZzBAt=BfGxCjMuY|9)C8Dr?NmpV^l9;&$Kh zLYwck|L5i3z9z1<^>gN|U#!=jih3j;V|3taEOe5d`$|(*E z)R1_<{G5NC)6t6;!$4Wh)78&qol`;+08mQ@2u%qMiwKec08PID08mQ<1QY-W2nYZJ z1*cj700000000000000L0001YZ*pWWZDnL>VJ~TIVP|DHE^uyV?7VeUl`xbFvQT@cRYLVbN0FW{QkLX z-L>vo*FRkIzRW!D^L+F3tvB?gsshnXnw!_IT_bv~`0UlSYuIbou3>2t-~o5`82TPu zyXJfC`7_zq?uJ|GxHZdFlU20l13{1bfPZO%wn@Xh0s;a{L8(MG->i}z_gN(+ixLT0 z$y~V=Ha!&EDOX?sn|GypAvZlro#Yd2brQ@Ze{r0ssS+>+kUqiuXMj+9Ec4fuKf?{@ zKRWq?>}Jv zuJf)k_Q9_}OUB!4H`b_gQPd(1S>W@%F0((sFnLA2Z94U{GBJ>JTNX=FmUQj)6P~8? ziocdWlg{zt^y7X8j*(FVHulHe*u%%b#-^fiJg{y!|FKkZQT6jI!XfYbgLf3O{@Ox= z3YJ005sP02K$Ab$+_VK~QptGZ0Ox6nOw;jV_)O;I0V{gKH2QGr;aO(C08GLzC-U(I z`79TB{c9pT^Xl9}xRc8C80Yp=O84Y8(4D_*>vU2b86!`dBw>wS7(LD z0GH6()hxj0t}fktb~1b}PYfOLzP=$J-IhqO?KY=|xq6;6qpLNTYeOUt2A?9=^D~j; zvtedmn-mRy;ziQCjHufUh$6PgqsYljbu?X@#1g~BZdQ_OYPa-DU!5aM>X9Evq|Y5n zx7j&9s9c?nH^Kc$q$Z9HmSq;muI{4devox^inQYqd;sc#1$(So<$3i{9 z3xSmIaGu5q4rs`B)77P+!{n}=&Kvca0n>OgN;#x`LUZJHEh1x+T$8o;g-~5x-Tbsd77Z$c|Uxb>9*dpvNmETud^eUr$j<=($YLt6Yi5{H@+}i!9j@h znH1}i^ThtZgrSuR9^zlmdABmMKao4u@^Y?N}U7a1QFIB-m^mY&+3WDuxV* z*`+yl?%93KJu89?pr)TlIYrlI#=!z94JT&Y=DZ>=Y};TroqMpyU!*9WId;*HE6soI z^d}bU<|=Q$EhYU#M`9^L03IPQur@5T*M6sdyLzrs!8Gi`ojcLc!%BEDgyqyaUwOhh zf@>3AOy|D|L5J)zg9077tDICcl=%Y1cbl=n=`4?J|}bfZxvHoE0HzlxUC9H(DxDFBv@6vK!Ao^DL9Bi1iAIl+fN#8!f2n zGmfK1JwE4trS@(TFds{>@WRR&ij3e10#iMRpzt)$VNpJghx@9UkVa)E1~V(S*|$7R!b)b1Jh{9s<}il^hRN+9o={WH7A|;Iq}Ncyg!NENa_en|5Q^F z;D)vp0MoDTr}|(ZJW8INTqu&BCYXtsTsTs&ohx42wO?qwCOep6if~uYuC_xf>vc%> z!rh~sw{tGz23~0wN7JzIT0-ucW_yHObj|Wg+g=G2^}?v2i%9N~!LKeQG_XwOeeXX!9?@zK$1ne`)LOwZm$ zfzhkdUO(8=N-j&l=u;vy$iHS`f{?57(^Y>%{$9njUHzem+lF^+sZ$?c@LVRip^E{0 zocPenO#GxPJYFO%b?IF#7YUunAY*FKT}St9R0T;SHIfA#l*o=IMO%PxMUaU`wOmC@ zoqm%R=GkZ@}iB4J9>=m3NB5v0zdmiLBnH1a-ytj zRdkDrx7jVE2#V^7G<_$;VCvVn_9gsOUg_%c;$pv9a*4W(Ik}T=(NFNDYb`oX9Ugy! z#Y=FR4YKDAuV0Fmo|P5{d`>oxUbF;CvDBK#oYt?H!QWv~!>$#g<{krG%or?hlgzW( zO|;0gu0-6B$7kGAq=m7hQw^(%+qRi5hq7kucF7RH0fTipt0Hx>ESX`1lqP}!R=6jT zC`0AfbN}%S9x535At{W(Eao(HU)#iVvy<87JC}fVf{fbe9UWId9nLnZ7pO}5ozK;0 z+ZtFn<5!^<6A2z;5SpX%z`6vB)XLcLUasmip8RZqo}1kch8%;S@xZz$i_oQC&!5f6 z&eQ_iIpO!%X+R%|2(Ki6ID+|H4v#m`v4-?8V^j=>#St}Y0N!b+_Q_i(y*EIiXR|PT zXTt>*FY&PSL>jpk5_!?;)OL3L`g2xwPnCYu@a&z`rVyVfn3F=rz1u(U=)oqfxl^?I zXB%|PGZQtVWu^FCd=Y|iMmSb6P-dT6)gD^J7ekqelJZWPhJib`$RZWLLOyz}X+I6= zvb~K8w1~2Ztov+Tv4gw#a!x(-16>d9b||#2R?&cJip%-gCnJ5vuAEs58DFo7L*cM4+_OB7 z4QT`?QgsBXxqhjd3KE;fC3_;SG;vNbRy^b>0?UNpJLyqk(|L#R?IkDS`Z;KOEo;c8 zh!-JenXmovt`F7Fi^IIDZF`@6qSa%40wTjNvhx!`b_qk}PupUys7K{Sei`3Hhk*NP zx4c`Z*7HoryjjZLW>cqfJ*A3dZx5xP%vuNu#=43XcC2mf)&dtz3`k#j^0ZneP1g6~C001M)9FX^%Ap^FXT&TFYz1NHzjR4}P-%BNy*^t8d;EAlkjz{BtlvE~T zd*xcA6;dUln!x1Ss_4c$E1tc7XGttI5|5>IE#%fmxNgjOCAxi;$K@8i#)4b-e+i!} z9X7{jEvV^kSr|I!X#iSYACVh@W*z={EDgn8L}S@fv_5I*5nT%?)4>1sbYJ3D_(11af4A0}UyJdWU zoN}%nRs_S@S{p4Bx&o7ThojtEh_E|7sf`qIsJk2^vfyV)nLzzw~VP$dP>lCE!O+%zl zlJj$!q>JQiia+3DiSeqt?+)r3+GlalFFwBXNV|N9z}|Ix8PbrMpYE#L7EcW!YC5hZ zK#!J?H1C_qeSnL!?mFL_TipC{(tS17pDAzP?h5G(+XM)#wDN}ZGU9f}c)&!~(}4^Y zDi(z}0sV984pYXcHfOvl4Tfz+krj4tZ))F9)12|yBmX-#Ffb4ATl$SR zdCV2j{YtI7S!IZJ8=Y1g1FG55@(^OjBoB%m+9nO#kP?{o^YQ`?iB)wH0EeUn%WsGI6t6j>kqJ?Y23t2j^vl z;oHYouh3`hchn9V1`jIqN_{8NCo))jrydMi9S;jce_G1;#W6t0$miS3h!*JknKR_S z_NClcPndv{4~<=&#iAo^%sG8Nz^b0Uwjk? zm+^BWt4x9%k%!|(O$tfH=izxnhI-#)ei2im&3W8cwLZ|B#1XTUE>c!EX!bq!XTcT&(NkqY|nLm!$Z~A+M8MZx@|t(ULCdP2q46F|5o=@k>zEI&}+1Wo$t7syq*J`6FL)$R>m}C=QRw7`55riWy1IauV1t=NS`@^LMI8Yh< z-9OajMa&)MSo;NW*f`v|0s=o*&3af%hcQyfzm=A6Zo@Kl#~JK4zT_IGp|}r0cheN2 zgX9(!Nr+;0J>RWB$kPitS#n;u)AQCn_m8NJb>+JkWg*9JWgLe~a#uc*J-9FZ0b|N` z;_dMx5Qoz(u^FoCtA>G5aX^gsZGMWKb_72H&b!$2V*ZGZ%H<}S&O{kIL9Y9o)1qK- zV9XjDb9Cz?RQnBU!B46brLDM>EzeJw7;lv?(s zh!>7Fd7zhSdVU$-S&P)83IuH2Z6qk^g7L)BQJtPKf)?9a%Q~<}l;z}P&*56AaCJE( z{SF@zRF5NO65;w8)+f9w_OzD!m21U7tXW#(Sw!Mp#FyFJft%s&CUUc0BRBM=SAq}b z8%S5xDSxVg)oer`W{OI|sMc>0B7_PNWfdT^xrVW=1}@;R@-;Ah5;Vni-TS5Aa=t;_ zgKtNJJHR7#6J0@+*I{?|K=Rsak>}yV%Je;8KMNu?N%_X7Gu^Hk&u7Wulw&WLibtM@ zEY`FMS24SoXx8Jh*gD@USA#0jabMY3ybM5m>{zZT9l>vp-gN6BbF6thpfH^%x3RWW zX%+cbhUc41e#OpVSQQjgWFK;F1gfOgJmk+_bqkS(r2%M(nZdf)!l(Q(fX8E$6 zWz~7D%;z|l(PWv#ERl?+B=ADSbt~-W&8-OJ2mSUSm+F3g8itxZrbY)2g=N7_g7Pl{ zqwepPeQV2eLp>kz*d!y|HSe1)TWcStS3F@=hlaV0d9ynjEW-;-?-4kNuBJROy!(?Q zB8VP#2mPr6=JkYb(h0{jN+72*E!^odaw|6f)hLPu&Mdr3~ff)JHiTQO&RD|=cvNlGt-sTJ`Gpy8Z;Xl>pso$!Q zV(iXw$kebJz+?~pFh>zlH{>0kGaky3>YLPi5%ZmKz6B6Jsud!4vS1*m@Di%_ed`@y zg4Z0L=p($$i8xTmC6R^GHn0#Uo6dddZOQVLBsBK;)7qt!6Mp$Ii?NE5T4lpYw^AXn zeJ`E=fMEd33hT05478QB-NY!OuG8a5d#9uSd|uzL?03U`7Gt~bZtdXqWEs#=wnTy@ zpCq02m9IggB@K$cZnPG;5(Zh|A--T|3Qod`Oh#&3j5{8NbI~rov zAG=`!|3-~7jW$zeReYGlu8(uh9bdfn$9J{sBVwM_dpPG8jiRwwE?mW8l^@bda2B~T z`jF?*j}_GM_Sz_@smK12-1{Vx`14)G08L3_pNhqDm^yMkRRA%S;+G&LUqRbgLm$dt^Jkm{$&1V>iPCxH+Ag)c9MVH_DKCBaQoLbe%~IO zzCRdfDGfM+`-6XG&?{yi`f)!y`ybiykM{=giRsojnEuR>D<9R^Gb&{f4jBR)JKt?1 zv1|6d-iV6%^Re%mXt&=@^*#wXy60zj?Ge2P-oI1zI}aUy=i&dKl@R`4s8am@kNAK6 z5r#4O86G_s>uNq9?x+aH%q*V(&~b*!G-6@NrgkO46=E^p?B{(JAuwPm>_YTQVDeq; zr121L&@x!P+S+HcxY{#?LeGY;zJMJx9z!`Bfl2o6xGe-yPO13gN}uogi_iOF!v%+x zm*lBTaD*}0a~0v4k%p_wv&Zk5YABZ#GG;#Xa=B8X7sGk#4#)IhD!eT?cE=0BXtZ(t zc9m16*HLn$*t1tvY2nB(XAd`8CDHKV90t4bv+o97w&RXHgZ)lg3!k16J7SXd;G;UzWWrDipEqLI_+q3b4y~n9{k(0r zTp$sk}3*5|__!_FaRyvfD8{x4!!~QQSU9OJ7bzifw#D z!h9~BqIdTP#7iCNE$OOws^K5(Du?9vO`xXIC(E%6XEKvj&F>3~$5?hg3gz_Gy22e5 zgtyAt>a+|&9dCVd5$-wR9@Ni=Xx zo*5wvgSH!atUo}XZkA31l2QWz>Kf^rE*!yf8R?v;lAOK?Nq_@zW?_kjXspf> zmtbAwXL`R^Mwjz|njb{j)|CCgLVvsnBREjvX&C8Bx2s$CoT1&HySg05BvQS_Gt_+E zy;>3ZVK8!MMtDdyETmuTSHH8{K0N(nl?xb5j3smrJkP? zM1>YACJoD4G-E`B#csY9k>Rvi+SHi(HjLdfo8ArXc+q{KD!#o8hTIcGLTvvGjxUNzTsLEN5PI`gN#ZTAO0dl5+oSnwA0fhJ=nOVpX zw#Ny!mVrxrDG*S1(b`KG&32D-T22(zZG3MeCUII$CPBC0GfsTtn#*V2@zso`)>xJt zxuus7KC>#Q*zsyy_9MwgwiSR%D0Uer#ngLL4? z9cMJ}Ydk8mLwL?}iCBD#xB7IW@GR>2uYMOt9*bl%3LnqS#ok)m8Dp+DYQfed<~yJ< z*9~I*+*%`jp2JQ+Uo+r5gD>h*>GOv{V_R@PV4dNnQqqo^1dXwW$?tAwO1sU1@*^`q zeat61IPyP5AHqC2?rlBwSgdRMQ@VbaXL4q@@J_TI+-y?{d-9PG4DBW*;T3kPo^jo8 zD(JRy=t}$0!!AWkltKmPrPeWWXu)j=$F>h;OXJx?g&XwWIe-_ zFT58-TU!ZzJLnt=m?E6oorIE=ZX4H=6EAf5rFORx^1w-na=FrIwQl$RWX;^FUf`}c zUJS2qx;!jx-0M8F0c@AIo+fU*oFev#BDPr{U)O=vye^0g(%*QiO-eAzBGb#&$MBKi zQI6l8`3_oC(u?G6Ofj%DDVW-vYP`wkYVF%V6K81ZO5H6%;)$pvl1dLFrcFZ`j&&~Z zjxRAADp^EO_uKBzor3&~sbI;AgW<@U;@kp)qp3oD1%_gMqsjg0O~t@WmoXi0T9=+L z;oKXNjv)$ayLhxV^VJ^qx;0A>HnT93^w{?<1n$oP-hr#(pnVJBtS)4i?n?z!8BA>iG zSs}sLrYhZojO;zkzhhWo+k4MZ@3|Xf$yp4Rl1^LFc)HOk#t!OCdE;o2Drr7+&WW`n zcx3$}CxRI3$n>rlvd`K=@7{yK!ZZ#`k&SG-Pd;zHJaDJ}z*5?Dc`8pua@|BQ#J7`* zL|NkflWeAeNsG)G0_-SL1+BHwoX-Ou&8!yA{oV5sE}b9Y+fX(EZb5!DWY~JIH*_4 z$ZK?hVqRBU;-ht$^>qhZXxVzl`N6On?ZQFX2W5|W&fGxTvBEE-XE$}wUq%lSYTb4_ zD2Q z5xP<>bX3qJX=_sRINA3YS~Enva4ee0x&M&!n-( zi+^+OO4BJ9vQJRn%I4vF_Eh9a*!cq(Rzwxk>Lf#SJMTwDmNaN&{!?}CwzVs`6KsYc zm>m%83_D^qNcj*(=eLo2{tB zwr_(s6vz54^@eki<%zvKY3f$j563x8eMdRz+sgP3B9ylA_l~tQ{Z*mb_xZ!nNHVDspc=i36(iQ|Jb@?!O=mSBZ0QB{M z$kMGV@sbD-JJ}In3hcV$rhI)!sK0ekSGyB-u3w~N*aNP zJlwV2dl4R8-mfC96iwn{)XSOMLGQG{Ul#^?)3+m#dQaL~9`oMl)qNdI7BVOjtzg#! z&o5J(70>G9%Z^9CWN_5s*6q?_pVJ-#{70YYes|#&{+o-}K}8t;Rtxa-{=weQuz+~- zHMw3N0SAF97mab}?n9lLfnr%@YW60JY*A!xXrf-(Sd+W^yLp)Dawb@KT~rX=^> zzj&D%19zvLHNM`c*xKzi5oDo6+JBTJw=aN8@7vym{gwRk1m<%(a7(Ob`|J-C;=wIp zHjyFZ(=fbj6mJ=tYTr0H_Y6*lO;BBvP3iIeqa|TZQH{8HKOy*VRLg7W0|3F%l1;By zO#(h3syV*p}axY8g@Dw(#PS|~DPn6o!(V53bS7?b2;NckNqtlu?*_5U$IkNdwWW|fcDOJmXO%0bua z4cg~RGHN@j`C`gVZ31GzY7y$wi~akZr~H4T3#Brj~%TS+V&qmGLfHx4xaQz3WxVanel5^IIcN`<2NOUwn0 zi^<73d%>K$R)0{4SK0DT)1Tu|dpc*?kyiO6@oM;=~@0o_x$q45odH zGwER}#ZJRHA)#9ealN5t+T(!zi z_>T1=dCGeCqA@B~!duKM^fl)WM#HFALmgO>(a%bC&v$W-JGq(DGx*!Z9k)CiI7(_- zgNMPG)|=y#us&&ADeC6O)8Ft7^U!lXO-9#3J5-Z6!34%pB|qCDRvDNO$?H8lub>%rcT+*Y&_tNBH(j0A_^$*qx?9aNR_H+cH(SMLlWu#s&4c z!}WL(Yu`)fe&n&T+M_3rq6sX-_c)hR8#3Yu2*QobZX7@b-_7KYNEK}Bbltk^^#>c~ zLQ&~oMlr}4qa_N3R@@qHvW1|@2!1QY724lw!o00xQ?n4{4dzVfiMuinaK>+||5!lW z7ixa}mwRdh4}7|;SZDT~32u(0>wEF0rER9@S7)*@&cfoV`4~mnzPt9=0CbZ4C7#TA zHrqt@rG#yTgn#zGS-_>pvgR-9i5E!wv-Md^eBWcmR`|PB0UTjVIH##Ld;Bh^)+2p| z33H=mo!zovy!ZMd;n0YRftV?t&6Ug#!i0r4rhD#3f5OYdeb+)jJneXOv#>Ys7f~OA zS#_+MR3iYNN{eMcv<2sm`;eVc#@`99 -PLALcHu^~!Aw^oV`>y~KR87?No!pUq#`MrlFULgRI?oNT~H?()iF}pOR zkkzkb7K9)*-e-;+6`8Kapc#5t((2>I8t<%#%M~IxHLgg$pRz}54(lIz&Am5#oTE(h z>IBa$Lq-4S#!{M2KxOCK0_77JcFQxkapjx0LwCiDKTe)~bbB^2#%W)nc%yT~)w^r@ zDZ|$zf9CZ8@qw&v2-GRj(UBxmzgOJ+9*?v}fGYOpjH$_YD*B3cGn(g+ipf9FLE>uG zm8|izAljd7CldR8OA5C*C6wE5I32oEZA&!lzN#YRkRd%jlFPs+G$3W9thm-NAE3UA z>K0Sjc#v?2A|b4L=jBF~sIYo8;gv%6%h$|{5S8XMus5x(F8b+(a2d@*N7QP8Aj|6s z&KGT8xX;zT+OdO;Agy{T_K!#^kn{m^VM#1WUq%JVTMWUIo839_oBkDu>hU4YG&vZ- z+`Cv6j{xk*;9aa}Sj-EpWN@sQ`RtF?mJr&^P}9ug;g{DnInDLNY1W$sb3SS9G@vtP z;NgJ7=pI)Pj0i8$OzmN5om7<|Jn5{eF(IY+Qn8QkcfL7YT{@TXLs8$5rUI$4LH}|! zslVF;Bm9x%#Y^JqjT)661N?_qS>H2J|AzBDxlHl)FIOjT5&oR|f$LjGXaAzA>o;GP z0ElcyN0`(0p!pisTt`&(^x17SNwzu%^Lr1dG^S7J?MXm!QzT)z;yWV#%z!l_GKow! zE_!pj8O%bl8@B?LTePV|p&$ge#1?LJEP`~(6q#3ImiPk`5!uw+HiWr29-~fy_TARx z=oUH}cev&1O!>qogBbEPvoBe}xOXcw7nj8wZKhqPZNUfd^1+wdej|K|QUS4?*obJb8E9b4K)i z+@BLu@n(%nf!6Uf-But9%Y-~K)7H;fZ%U$S&a}VXD`0aJHzlJT2(+vQoX02f+4mkA zpieG4zVgqsLsKf=86;>w5cFKl|0lM7=-YoHg(BL%R`S)vZd}ZPxi$R^4@K1#U9QrcXF_vL#w;%K^~N+T#|c3De2DWPE+7!BCusNePTX zZRC>$b5TS+5~;lFxv{6Vd#vsSXRV4-6yaa_SDL67&iDAp)GM{Nrm&7018^%oF03lo zCsf7`nCIe{{@;vS(PS-Im<0ZwYo7Q!FZ0OKc$^gaI~e9JI1M@?G<*?{+z-nEeF~|r zEaduhd+p_sz6sL~R7g@xWxwz?SDUbX8}=vk^G{`Ayso<~_|yH~l}rbp`7*JG6s~8# zo$x}>c-45t1RF{&YLM-w&yjZK`)~P^KO&=0ddqN^r^LO{^EZ#7i9SiG9n2oD`SnQ( z88jw`X#1-$9oSt`04V5_zB-p;6vc~Y9KRzaZ3eER* zs3fS|Aq*^J+5^|>CbWOhP$1D=?ZC%%jcc|o3lp$rM-`_P5PcFZ*_(JTy{C`M`u7NG_2(r zsB(?_^O9sL<#>nV-r{A9i{U_#k6Vj9Z&PB}3Di_vAzQFv&3KTT?io?L{8{PTE8kGt zeId|`rY%hoTH(MI_53T-j+77>KTguTa3`CywN|fSDSKw6o}f4lVsjzQwvjLK?=;YR zz{XNo9!>`Q&b(L{2UR-kg!FzN;w0^>(&mikx&oD5;+<*d++lII#)YgbZWNXxe;Ab& z4Rt5Q87te89GaGWQYg5{Qv56L(|j$Od}-`k=~7e?AkP5Hopm83;oo#yAwf(d+jV3u zTNWz4Rk&+(EQV!+Cbxqp*+tD@

Lw4=WN@DDkJbWhn9_x&a^nCt&638({atB?5+n4jB}}Jq8RmTchG7C%nTo zrgQAT1WN~eWO;_C^1eQNi(yhA&3f*U2uyiRVF_av6VIeaE#kw_4hMmQ{AuMe+f-6M z`X+ri`NjH#mXfC&vcV6a#XO8yC#>qVrM@xwwVox+{v`*h3TD7IX4--F$Xyiqa-nTZxdZLv z7OlEU@H*lyO3cph_iC4W;DaJSvFRR(%kmaomS+mQ+%VFd^SA;dQ9Hf1D4x=?I7dcO z0@)4!oGZp+uk@i63~%56`muKb2#bM_ZE;pJT8gQQ-P7Uhoo&y4#vt93VK5wX)O4M( z7k?4XXLf+j$Qj44N3rG0@Bdvz1|1h=xjVVaMoy2IA8_zEO@5?t0=c&J)P9RO+Bw;w zKO4LFA}XU(o(I-4!y=2rb~r)gL+@P$M3*{pvnjR_r7tFUB^tWk(#8GUbz2eV?xa`2 zPlVm@*5V|H1~C>aX`}?4GY%t8y3F|jVAag`Sg*7+Xta;e$hnA*&<68}`p=QKzFE#( z?Io(80O|*l;ZFkeivxE1L+flo{KL23uIz0a?p4xMmgjO%>IqT^@3l{H92|;;t>SrW z^gN&Azo2Bq$p8YNX*8z@e$m883>Q;~eN|Rs3~94~%%uNN7E68`L*HfrCu+BOl}n_7 z>ud+3+>`?VFPGW#TYPkq9>Zh*_yIj5-6!3}^8)Ce3Y)AT%f+THi*0#7rS;VLiCv@7 zH9E&N4)a4n(uhW%1`L6PN)Zhn-^fNc3~Iz#6y4ZgK`#twvDSPn@$r+u%r1jGphG8@>^&gLuL?jad&5y z?32Qiq=xG--kCF+&>ck#bc_j5nB^Bam`H$7^h(+X(PgJ!cj;A9+cKA+O81-uHr9THk*A68VG+nCSr$-{V9=yy!j1wdHl>U;hfooaahCB#0O9fBn#V z$ung7wt(a7(vhY?++~|#W|U17Cqkts3oj7Ci9WC6?(4ogWTP1H3U+~Z9dk4`U?^c| z@ZAbOdzqv?dQKQ2OmBo{ydRv(hrEnE8|~iAbu@a9XUgG_Mbw>5*!sV2ff0j zT=umTZ$u8zJ18SE9@4PFJFGi+u+FjNtQ~{V!!5(RTiWa`3bP(ltUoZ8u&15H4 z4;fa8G&Y|NDOa5=fiJ)RC*b3k-~S5*GyH*GD*P+Hmth5B&5CKUQZK;@r;@=dNsS48 znEH(vL!}w;d@5i(-W^q*!E)dNziHx_9AX4mN5wpDg*=6iW(@cMN?u%*a5Abk$#anG zSe+`$h1SxPPPcPWrBF(%VRV$29E;%FL^>VWlbWUiucV43hROGUeJSt$C+H5wBrhHMg z*kVI!_2dR-OxM27Zxr+p#=g$}=lj6Ek4BCgOT_|Tr@VuF|5I8n`!Q24`z~KDTLIxD zQPIt&_B_}GI=VQ`hQb7l@@wXl$OsF{Hkh!8G@G$Tj;@^RjWTTF#085+*pdToqyOzj zc*{S|73jg1P+HSCW;7%sr|HE&dN)Omkb7e{gLWkZl>p@B9F|R_;?PHty&!`z7 znC#?FX1t-*hdRVPEQd7~SZ50Q3Hy_@05We7dQ3aQZ@K>n=gIM^EtmW>HkMGMDTCf> z)UDx+xp{;bfa@oMgLX&$S45pc*BM>Hgb`>j^N`G)grdyjjkB(>#c>y)|Lr_f>Oz{@8GhLhN@S)@%A<4_t@AP;A(@;X3~Xm!hwgtjAW)TA$znu2M0CgrpI%KL87`B#V+V|Rujm$2Qg!;#B+s! z7J)~DsS%;M!N9=Es<|P8&rK*4x0?;BV@xZKeMOVNpO2aE67bzX61fJWTB}uGKT|*q38g6LdWBZMBU<*w~pe(K2F|f1jq^JFtQP@ zNnZ$-oR>~#2hxl^ZcO3=`3{FMC&DjcH)2Xz(NSHc38$dYPn9Pf)Mr}Gx8S|06$azN z#ZHH~#Z2z&a6UjkDsZ}s^R^u*@ve&ND{t0Q0GbjKGLnECUsnRTlok%tsFuvBndxvs z&VX}<^9%>5(?sA~GHh>Q$NOcIR?xoJQonA5rboHEh_7)?cih$p)?17GbH8K$NMPB- z$;eX`uqOz-TYMaIFN6Pix=3h^Mv1nsBTz+GlNtk84%h<upx*>I>;B$$ zLCMMYt&31U0)0A7kE0C0Y=({SBAQ@_EEZ?plv0O=?#n`dT_UW8D4nqB&e#i?Td2@) zhgxv%Qto5Hpj2Q#IMx-~wrLg~7?uI1{@?`kdw=SnpXv%jRrhljJNAKabnOV0!6n`q zaRb3}0XkQ(e++639Dg2qAnb6txIPA8F$}Oj6zsJhp!JM~C~t*^{sQ3zweD6L|MP!^ zHi~KN>IWCIPt6;RKDQn~(ScLo3Vz{RC+`^hAw0{T;+w)j4IOI$C-1mmu3W_z0MMsk z?t~8Pm;-bq+yiP&0g;;U^~f1GIO6mQ-H|~s@okHp&d{DLhXFm7w`621a$hEGGGsl% z_7T{R`z_H^_IUl=?y|MqQlRV#%8CkEs$?Koeg5lc?O@Wp{3^0q>zX~qIM*gm#d}r^ zRq1pZ&m!nh;&4dx*SKUCnK-%)VvZQv5o@OC-TUr658|g?{$>+IfY((r(^aWqG?m5) z>ju5~lwISv_p4pA;k!3UJ8)7eUS)1L-Z}gLd;$4r$b=oiPk8Z;en>A-gbb~vAYCgr zLhstpa)Nj2xOe%a0m^gsr+$RF1vASDkWgonCGdCG9}_=iaRqp&@1ma`_&OtC{2Um~ z06U5=;r>4GIiU0^v}{OvtE)Hmt6IJIlPses3v{Q<+42)ruMMQFBoL1lK3R>-IHjW` z*I$HvbO$I_SwflZ*&v}&np<}^=B~j>&Lcq)(JMC~i;_}o$XA!BN@&~$5jh;j=w4?2 z^-6V2ngV1hp0d98Ea`MbD`gbQ2~}pPP3d7KiAND0e_Ek{VF66>M$u^#k#c{~f*Q5b zfx}&6>g$RuxG-)~g(fAbA(^uAES%%y2WQ&*dUxHtOMD3WA6NTHFo7Z(@;u#hz;hN)bQ>N?la!&^J|7nkS#C z0VMg0zHIyMeClPs&wb$eKea%C{vNyd;$Qz3|CQ_^0q&21GsIuV@Uu-5(s1vR!8u#* zV_8*-K9&qoE&5n)6ke@}yc1cak5RHDyN);e_zYN4?KDKVxr8v-A{+?8Ph{f9hhU~p zjISu3AV^Ruz{h%mAcNjc69n6OS8NeF(Gr{=<( zY?d_}lF2p>mZQ_yKn%niYGOD!G00lmFyxs1)x@wBF_cC0-hl470}YTMtZCrnG@$oP zttBdD1K-b-2A&GLJ5D&WJi-oB`F0=b{-88tlR|Wjx2^ z97?O()0*-Ln?hYO=lEql?b|_?ZG<)7sQE^%uxxE4nYt`?Nm)D|+iCg3MZHz{vYeP}`*Rhwmpg@8iJjstMET&Ev6--VVJUIT}6M)>?m(+i8gWRIf%<~TwYV^(P~OJLm)8z?!J`)Y+D zZBuCZ)GzUi?_JyRi&S}!!kGILzr}_*3Yq33!>JQug}^R+k;Tw!zIbB3D5)LY)H)ZY zjwOis#17OSK2qjfteYi1rKI6)IVIo^wg}SVI*_wrZqZOW&E_uAJcEMJ^sJcRO31Gc z<{g~;GD5tJ_{3JjG%n1GvJdeci0q1oWIZNh>LA^dAbG2+wWK|p;D3ckUaWG(o#rjx zYW@XiV2>%4o3c+2MUdDNe?TqqEA6IG$31FL^O`leEUMIgjBnI|&8OfSn%3!pRqz#s z_76mh$`!n_ke`H55z*^t+7lqUs%Ubnt?ifg{xu@Hq*7_sE{I-7Z+2qIrX=K?49=`mp?M=NTtXI0GYIIIG!TOnCJ?m7p3#QlZ)EyNONisFFgPW*Pbt_b@ zvGij2vD%e1RXcd<_1U;oNyu;IQsuN*;8Nu+L$VZ8yHsl$+?xhvNopBNs}?ldBDKIXgq@;s4@iR@ud-E~58#5H;aTFF`BJIS&VcGvndmN8jOp z{?9IyTDx(dgi>{-(bBrDuPE8j*@99Y#r5l5P`&o!?x;pJ&92mBlF&=EpVot}h+L)pu z9oD|wC!s^x{QvBI>5|(QR4Q>vzD}$yhx+**CQtGUb^3{Bb>}8KzcSG--_UJARvpHFDVY6F}^JX zL_zAPOVej}dC>u~zkm75E`a0N-zNc_;CrGkSchJR`vR7lv$Jb=QFWgE-Az|D)3szl z!WVO0-9}d>g{$esFtRS`s-&rhc7e_&{Y$00)imC68dO92x7;(K4jDd;mt*h%k+|Xr zmg657gD=3+Tr1k4_D0Z6Nz^=h-F{uHkn+WR3h%{YP1ZEkceMTHpYSQXTu+azr-EpT zn(3%}>1kQjC(zTUvkADF0l6wN@UbGEmAypOS0qzbHI+}h+E(>tzP-W4Dm{o@HZ0%c zO24Jji@3c(gQ71BShHN+m*sW-eLDf4h2yuYw6=5nc;0x|jGAfMvMBM5O14EZPa9v3 zxl%>jlobEa^QF!vZHyz7+og@^?9Rrtv02utRyCeB<`_J{oJGeL9dAF6W)*`kz-5#U zy7`0ZD86TVC~=-Se#WCTk|l}Go})B8bIkSh$a<;^vhFD&PoHgT7Fgyu3x{-0Z^7sE zUS=ZAmQ_>c)7rOIf4)2J1#7(`YL+3HD%bigwVv;edummcJV{VZelXtls>-$Wa=Z{r z6kOjww344oew3BH)vgL97FYA5O4XOOs_|VFI1UejLru|K)AcTO!O;OneUD<24!w`A z>PwDeJmKyO9F?a)r67u?XVa~Dcq)~rQqOmk+tNhUbNAEJvZ_y@r%z`W_&&Oq>Mj|A zDyr-3FIV_=3jZAT(f#B1|J((tJmdQ$P?b#EH3jMyaHwtrRlbGpDGiFDN|GsX4{BR2 zR$=cCUDqYNIoXxpooB9$k$<*1>>8SqSdcUHIL5^2pl{l|BO@f%zeS|KgG&C7*u& zHxl0WhVWQOvY-foJBcJn%3C7Rd;UtqYh4yQqDb%kWvPZkaJ(|;%UhCBuQU7Dmldis z^|~)+<3v?u?nT>1P3HZ{T%dL>9TvqnfBWXmbUN)+O?-__%sXjz^Jd}F>tU1^X*PQ^ z$@{NI)7#f5f@P%5+j^v~`DYuuqidp|c-C`(_Ic-M|KI<81dKg?SN;fMKA(UYZvTD*Up;?|3I;WfF5Cq1kH{1&HEEC`DZy3hdd7_b_X z41O)H;U_2}3x~6Q#yrA2jVJVvtG|8z@@gabgE-^(xa|Kq{E~iJ8W37nlhboQh`3*h zk9FA;{>Wwo;)yhdzWV%?s@4Zkw}<|@i;7?b{{)lz zCN&L#mxH})cP6>67UoeDRglQ4Ao38}0J<3Dn45Vi0(pF#h~|;YvnA(B)PgPq&om6x zM#Sz;7hA0-+@3BDAis)K)(F8-T-7y>yCC307~lkuo#v=C&Mn1USvj}#TRy(Yf0cf{ zRm0zYWiM!$Kq{55Zu@>z9+iB=DXSRXrWFqrU^l_n>_cz0nE)jCf@vzEdO8)`M!3y& z)?Gs~4e5ldxpp^=yQP7_`C+s=Ow&HGdXpj~KcrLW+0S7;71nre*&vxXJK$lD^$F9!vM&kKcV?a z?7&6KO>NW!A0^T}P%UH80*Zkk;~Ga_bOIp<#IB;b{S@4(DPVv*q~q71O^e@lMVL*B*`zICRxgQ4`WNA zRp-f$U}Nlaax=3%7d>u!Bv3)m&`y{E-d&gW;Qse+6lB>jd@Q0lq)}NR|CYqB%a-ih z(g``dX8Vv=mgWgXQNmUCxOOUtZU8_OuWwl2u}34`R;7}pmuegO35Wfv`*JX2l-FSC5i zsYPKD3|FXBfw8ZmPS^pX*e5@K_@7k%=?KnkD zUGDw0Q^Yow)y{Vp1;>}26AoIOgC>n}DOgyJ%5JSoFJ5U>!xubx&xM62&MQie;#!Wn zU%LGQ4BC(3w3}uLt}X>D^1TJY$D|-YXGNHeS~1jpPl`uVaS*HbJu16;yAI4y zqHtn{5>;Q(1^paT2M5usW)yBzHn}61ZFCJ3ilq&Mf`ma9&&ZXeyq4v?=8kOa*=ZQw zF7wqE^FelGt~r`s;dHDR7x-Pt&{*x6Hx{mPuAttGYuLVFo^ZSEr?5d`xqNYxF%sMG zL$yS<(HdD`jh5J>0@e%ExiwP=s1mU$1pgZTdaw5trLW)5%EB78)Nx#op7DA-Ej{>5 z3A!O}Ia5L!=b>iY#IfAFV=ri!DY5oMT7{0oZP^zZVOwue{cJ%6qONO#>Ys4Z>~=EV zs_{SKsuge<^RPgq=LEOv0TY9YJtMs|8ALaeETk}vlBkH-8kRB*Jp<%o-cz_HN!Y_! z8Bq?e3`ica#n5nbcakNq;Rz@+O8dwwDt(eI3Bqz9FbHGJyJ9usutVHQhQ$;^;2ZYX zHLd1+Fp^GqtyO500&S(}-9iN4gX&-7azHG5koG2Y92D-FKh8$F)slgr;Ixc{s(M#* zYN2r|l}Q9ojB#u|q3@`@x)NQ7IBAlH|C+!p@$8yW;)7KNyp zgJ9AwHTHB}J3cT@$7OF_lW8S06j)V%+8LCaL6?{%sEHE?o#AaaSvncx_6KMbieZqD z6m0;Ack#J}o-Dh9$)k-amQ+^|HEln){ltj{+42ovrM0_!&OlcI8#Y2aozHayNdkbv z@SGGwRL}sI$jzMxx-kZT2jNctuKbIuC2P2q7rkKSRoTG7V0u$+Vq$4A7A7W^*ETj6 z8}Y4Fwj&C^>C=$yZQMac=px#*W6Y0lA>(`<^+0V?|i{(VP8aI1b1-w_Ev zrFTTePx&2D@Kbq5)K?|*q~NQawcN98McUuGvv1J!oAK^qKTPGCBPS5?QpL9E@O4YK zm=08ss%NDshN#u7&$ymj)tZvDpjF-WTwC@}xb61QDC)6!aA&RZwa)#1OEllM6>d%+wjAxDLwD|s*)2s(m)Ror zu-4BNe?gq5H4t_d-twl=uxqC1dhVXX9H)+#9LX{D)9p%I)n-eyA=K(2K49Pmj~Pdw ztjr@Uhs^;Paz>Ul_l)ffr?MT4#%YGYglq1HFZ4PPB;A9oO-3{s#KR;_XTM3aEj9+- zEh8$)%j&mBMwI1Zm?X?)NqqX~P*Ipv6q3+N6sDdFqLe76W=2OBMf>ebcSAqOhf?(& z&hgAiK1`=H4c9^rp*S1Mxuojd+0BvVux7}S?u+xNfS$PC?;qcb@~LarSvfT2z}nTR z=fEG5p=kcM(KPjbIG*(ezx5(bd=gFbX|{TMRXbtDcTlxc*6!%4MrpovZ(Bv0ca8SeEpuPoC8p88!vfyrw(SyFjvKU@FX`i4fs!LxZVt11V`PGEI!WlrKK?d;sw%S@iVw34C;8x>XXUta3;oQCQLafw z(bLLU{&+onSU=!|72m-RIA!fR2h0<6mWyhf*lTNoW}I->oHn(`y0Y6EXF<_=u~|?H zp(QQ9VX9NL@}+4@7gt8k8<;-$RC2V)ra$h|6o6lZP}bqIE>_n*8+O1TH&i zjrv|5RR$RW7_f@$ z1Kp#)>L^*5zrWI|=5sq$k#@n7PTYM0uX&E=45#Q;LpbeD^rRCvOMAKfiJonqe(Xfg zHqSqDqUYwvQLek4=&5;vU24qT!rpbPJ@dj#UR^X^hOIe@JEe5dxz0bC&dZu*c#?1)$E=-+&i~BT5&wx?EhU@& zv^ccf4hqy(twMpDfOCX{p!fI-Zv5^~Mk zNAo_kNVNszf=(kyAtsHk=~bP=shHuACB*97I5=cTf4OREN6K)dy zOh`gffFxudZE%u!0nvu2$-1kaN6Pz>NJ7SNL(w@&aFTfTBq0lq?WkrsoWn_?HAyH2 zrY+59OA?O_Zgalan=kelUlSEg*K7|f^gPDb@Pla|YV2y|7p5V5nqrCT#uiy2thPrT zXXeWPM9MGtit0M=~M~wL7NRvA{xe`0# zPO||y+&J7e!A-M8Ly-LQh_;>_ZaRaTz~RQ>b`-dYvaAWFdLHvFo*ZskMVZrkB@72a*rp)EEiK9Jo0xt?C| zgWZL4SXGnyBnQ=(4c%UMh8ruSlq(-K-2D8-jT*|Ht%)a%OrPFBFYlt*(l&Efn7hIo zhcPU{RjpH=@_gQ|u*wrX&CheV9VGH}RaMq6e(#b)MxGpQ9BxOmZl>aTp5}45A->Fx zNUkJ4YRKWX{)YYF<~o8e8OJ?f{erBUfO%De!;Qo3IL@ReshXy6xKX%?9RuMeakz1~ z9S3f|}vvQrl?0&X%NHRN#H47atQQcXpab>$o)w4=i1ghzB9b=a`|L7pcYHpCBh z;KPz?S(arw=6(axyDYA3MarxtD|Pl1UDNj5GU{k`MoMTnK?EJp@&u8EvlvSfSvfkS z8hCAJzplu#rKl&IM6iGRRZ4uT?cZ>MidtEVS}nTE0G1k%Q(oJMobqHQc7)2p0j7hd zf3j+b@Wb9_tb&V2#86 zPaqRJ3xiwwo_-cgL4@$<_-&NXW4roMUVNp79sjcDfBi833mXb89D^(v$THglB`;;E{Hz1d;At8N6(zU2hGuCk{1ntcz zh!S{v>I|W`LW>?&3C4_d)#LBq_pP;}Tzc4J7VS{fIO-JuGAIrHdOMz13;x=>wB+um zi26+U1w`?9cU3pBM*^$?>z!5UK3vMObUF-!eqITEu@w4sp&H#d8vEdG;v4X9lD!Q_ z-4Ln;nk>^pw}Q8Mk%dKXh<~DM`Waq}W!HY71wWL9-*NyX=}teT{jl_9@%j5fHp0(z zFd+9-g=eJ-2Z)GA;qd0+@o|ff2FG6tZ`F(-z{cu`gyP4bM>J0}M-F&m7c_+S(l4%J;}4NK5B%1ZPV-*ZnmJN^Jp z0kU~R`!_iSrR3{o={Qb-bO@)wM5kamv}xfLh@L0Po_w}$US0f6UcupPziQet==ZYi zS1c2nF4M`P$F%+Gf-%v!?LTkZzoxs+!S>VhAi>0EJ+$|ze~L_14?eh8(9$bVB+<1U z$_5t`{;RYSOf46V&0S~Ws6I5eUobsQleH6Ws&Ihz)12;V`!`wo^7yN|sX3sfUmv&D zd;odX2iS0&ecd0JVCh7y@&o0;_2?0-9C4j5_yni4uc9O=x+I~Z)a|Qi%eLyd;<4?k zwm{ehx3A}IU)OZkIoMa4H0AbnKl`d_x^KA7ev#yfhXfQ&^E}f&*_7etC}?9~`E?kQ zQJNIPct*NGj-g{O>eC<+tV@WtWdvGA|E>bfdPJF%KgY#8p`%`tU*O+&M0^E*iSLMn zpVB)b^G! zBVGmTUA?-NBWw$^m&0z{A<^lvvT<20KGqvit8RX8jlq!g zqkCccD2;Rt@b-!7=2b{!2%5TXa=oM-9pvpCjowfL~Y(;3_y0dRk{hRSIrPm=J(kar@H5Jzbg)jzL zVlGNHOEv*M!G|hP&ErWQ2_a|Q5%y3WW(0@^m7`CfP}(KE2|NzgE147-dskjSiPy9k zykm*5W*uVn`}9swt{JQ8A~yzkJ{bWL4UzPNS>9;8`V&TJ*JKL*$Pnv=1yz?DpP3{@ z6oZQio@fv+a64#2)xr%jTq(4dP7va8o|3fJn`BT0N~_gtXbgv}DGRJMw3zB?VE3@V z*CR(jJtjpj9fjm-E^qjWmhg&lH-wSJ2m>G}Pm$W$-F>EiKvcO06TeqA+GNVKz<7qA+dN?;qAkA(_z^H{t0|8UKW#XPQ2lVSW&1jEdDYg5GAryWyMB6)wshUvT z>PG`g%|-1|R_7+$xz;s+T5fg?&YHGrP5Q=~GH0){)dyg)V|s+I_VEbcFKNr%w9h$( z@lvIaibR$Bx}wPWZ8h-MX_InW%qUe+%V$@JqGE~C+k0Mw(A;YeERm8h$uT)b0iI?w z30A`(V~-lZnP-;MYl~>CoH^uGMA zjf75lxc-K#hiLpEaA(J-Q;N!8Q4)Hn0lpRqY@MB8-eDOW)n0WCE&y$F!a^=)Ou9ig zilbsii=+3JO{T3I&PR9V=AE(bQrXP@EY@+^<4uYDr|Txyc>d;SKp({TsVoN`5<21< zqG$5sbbNTi<8-_*M@cn&O|14GyO6PX6)VApuon7;mftW4tyZME+J4!vMAh?8IP2~< z497phd*~Mg5X}d@4F*M+;Yco>XO9CuU@PecVD!u9NnDLx(FY$+p6jN?@L-Zf6W1Ww zO{4r;S%F$Dx~zSNna{^)WpO$mkR*2ECjk%CM_?} z>&8C>Gl&T1KMkV$une*BM`(XlTR~w9!UjCnYpQ;g^JvUe6P10T^DORJaZB<9w4m*+&bETn>4 zt+Fk)JoI(TvJIS2+XO^bNJ+VmZ+ZBz!m!ex=JlB%Gb-(+?q??kR;7Vudq@)TrJJQ- zcUrpXXr5q~^MSTrmMn>m;(L3JX>Y~TM_HD<%!(!6>ZDj++Hv@8fdY@n$Ujxo+rYWB z6CVMdW-3kl5Fm|w83%K%D2)mS-IIY%bT!Wv{r%Qya?l+NbXFBZuLm79d-U$Cv3u%S z4a4$9olb1s)8e+>WcX2w%fY@k*!S3QSQA7^74-df+1VuyJivfSh5B~ZhkCiIO2{>D zAI-bi)8tJ{6Mf}8+{#NjO`aujmki&tIZGZx+f{Yr6!9V{LKQ4Wl+b2yir9uCG@uAk ze8wEX-3ZPR<^C^*CHT5|9)a>DafB%0f;#yblLXy1ijxEaqCaDjP&r9(l3*K%sETAM#tFBZd?qBJ7?`#+ zFPtRsgO!3euXc4kFm+wcag237Co69}KjoT&C8syznwBti6SQ##q)^{0pa`-Ke} z9$6`amlr_T+7$E5-|;m3c^spmseR9Dk4FPf=uD0u#vbw-$e5M;3O(A0JfW_}gIrWZg9+x@#-P-#Ysz z?P~wH|H<*UA^sD5*D!sD;%sk2P=zuD@X~2nwR2 zs)lw#=kwwqs7M{j>(g$wjVD=-r_|5GvT2f|SeDKgG(2M2 zI>N3KT6lQJ@wdsdbR65%uvCt}gX53eKaRgm8_@fLu4sHh*?Rm*9fdDw;P^Wd{shZ& zG=tl}qu`JGpB#T1;y*_aUB&b`{*Hk^KDNN|w`oDUqS>;}{m-58hac?DtWjEZVM~^$ zD%JrGBjW=LPsjm#Eoe|2*%l1pga+@)0krAJ+@;fUcQbW7)pATVelx>@#&mLK_It*9Dy7CPsLLNQRX{H90h@Vz=0!h69RQh6ck0m z+#E+B_d>ULo+I!u2vl8BmJHG52s{P?`Je+w;6^W0@-wHC#&b*oy4R#<~?WM}YTj7><90_b^=p z7LKTtfaOp;3$tQ@!1Ku%OjIw6#w8hUtleJ@RFzFHYCeC51bLqJBDz*(8Wls*gU*e5K}>?) zqzDP9Nir$2sEE>}fl=oa3LoWrx-s-8DhXIoKTAhnLA5}Q=sYoI7+0=>JzlxSEaA#! zD)6K?L`#q0ppU~V{|E9m69jxMJt|Yt8a=9R{6jEHCkS8m(;&JJ>8U>KM}TT2NkL)u zdk|%L@j0EA4oV!g9uBgjd0=u%HrqZUDyp97o^VWJ9WkzT7q_%C8_Pio{5XQH*lDmG z@ya#$j5Ju(4As?7na?;24Tfm0zs{y_RARI)T#3&}i6z~%WLNiIni7MTl}7{cR(I57 z>JV{FJ|j)mWLb3#|MX`gKCLEy2!j}6ue_jp2!t$t+>xEpo98-xMmjBtxEs6n(%89{ zZCS6z_`&Ya8s$(IqvM*o=&jpPk`=;UexMoPJlt%Jr0t2`lpWi5Prpsf{&3hD2vHXD zXz|<>P_<0M^6b;6E>5n1&57Sn%cn5Y?C*k>u6=9SfeUY~dS$NmY1j`(!7gggZnRU9Wqomy}~= z`@FKVi)G-k?GZh4!4)LIdI=u6&=FLzLH|~arEQ3g?x66WyGX7;CbIa)@Baaxy7_87 zIPrr$gRHRH{`y2CTUI^aTem=-6~ZdOBlffB2g&he$MRo5z{Df=vs6IQw>{bOPk)}_ znK+GK77j3^@jA|7T2RxqujL{81v_R2gi5ye0*H4}#dlCd9o_`1{N=AeJEsI2P zbXnH@myqwp5Y~`r2rC-$VM18daz({mD?U~Ts{jvS&z>JtUlCnLc?tO(9>SiZ0_u+C z2)1~_#a(9~!t(g_xhuWq%c3RNCp?Y&$ym2G<+lTAgY4lHx`F3?KzL0e9=%^896e3ZZT|&0M;N{9QiJ}jMDM;Ydz$nT#@rx!7e$pu z?~-gBCVH10*|U6VL3#B4-!6Ut+OiBmqkC;U`}A|t=kfa)s-R#ChHQw=^H;$&lg6XC z|1=X5<5q7y#LUDs`=s=vJPh)1apRblkmT8gBYKUh>Z+o8!c$nD%qqAP3}J9hMu5W| z6p?2Wj+xs9=fr)ArOT&R#19ZhGiDA0QVg>&Bxy!QX%>ZBMaveADv}#C4@X{Z@>OqKSqoy@V7tj-o3j z8$}nC1C63)YfJdii&kwS0Sc3TimMPOM=tDgJIqd%w+=O-(2DeO+c-(rfsT0+5 zCG`n5>ODPEms7oY)OzkZDSCz?>DEigZ9hboy3W74DNOQtKo1bWSa%90(3GXCu)+4Y3lR!M^4XDejh1H4Q>D?OwLIi;jGh)j$v zMv`T4%R5W5>YqM?8Bu^6pBOQkQITRq7NQm4lh>!N(;_|7@|H6$sCy0_4@uQ z@o$eJtfVnJmEYr|?r|a4r43R%MRi13M~lTpH_JxR=h1(x!QKY&6_SwA>kw2*DyuE+ zE61dT$|nU}&z`~Jj!y|>fC#>u&J^n8+IHf_`g!*N_G3l5E2)H|bMA4Wi&^|Vy5_rpMp658g_V0uy-RG@ z0K-lw!)c(N{2xvVeqm}Hm_P%a+kQlC!ZZDD6VC4h=?I$skASuYEH#=0u=*KauV69~NiYG$I>i=WA{)me6l^A+mz2NQ~O+iMMDU!@02YNiAOCzQk_I~A5P3ROkUPXRTkSFlDGj+K-kNzh2We;fr7^iJ?BL!LB`hLMd&+BqV#`2EFmg1kcex6vO zpmRzgaR$cy?X8|cjSBfAcMu{6WMPnvd21;Vl|zIzMa)AX{-QO)uU}4#0^?}quoTXo z^H3@DlLI4q2a#*i_Q1|X=9{Y*EUlFhkOQ*_lLZKrES_qfp8UJk;X@0^zn_NQ?>({% zT%cbEMfMJo2B`b7T+}eV_xrbxz{G+L$O@3ptj}%P-P-IWti`(U)d#BI2Zi6;W3t0b zx))WdtjiCb!^s4wk<>G+J-bJbKK^Oqcv??et*iK4JCWXL^CQx*zyc+jbV0q(ZR}+p zMJ8F+eY5ug@M53L#wskC3>veZOoR15GqZGsmBM(1WL%n2fk`S4Ux@UcpVzs&&yfi0 z&>4MnZ^fdlaThjyQQ36&&I0!zfxp(xI-{i`qOg zQ)3Z%6j#G|$SQxurj{P!4n1P)Pmth&Z1UI>`k7H`-CsQps(ei7^6$KCeQK`tdGE|J zU%AWL7v5~LGbs&yMu$7ldm)Wud?TjMP}cknO464&v*1T-5aHwCe@sTO3Z~qw=sor$ zWNzOgzbjON>f9PuQVu<$gcYipa0w$aMw5kUGZS|Exs;JI2$y=iUzkte({FaiEJ^cA zC?O@Tn~g0-IJ(#>NESCGf5&}qCqcFS`8HZfxJ9?rqq7xETiLZAbJY~WhRdSLwEhf? z!{$5@4M;Mi>$evCV`U7p0&&4Hc#+0Z7h>+ExMdeK3?rWfn7XURyr+Cr!sJ?%f=|;` zio{?Nz6?hV=IYG;%?c)5D2-exjUFV`5o)Q>Yo4t8Q7@0g+ur*}U2lyEe6X#NYPb=a zX|$I-GBtLqZ7H=|cQ|QV?Q|rP%^vao$!58?FVcFCOW#WEBh0v(+0l+i;p_PD`sxXT zk$y%Wk;rGRyX+$Ps#=^89MPfc1IQJUjffj!FW}y@xvv&vjKlwNreAU%vr#~Bdu=Y- z8*(;X6uh=$g)*-qKB2{X^lCK7oYQ@iUOT=mYI&_zDH&vu%bZ>)w_(zU=M?ol(pWAj z)MARgZ6n?=caRJ5w^gC>imhfa`D0dni-jj35&`~-oioKii5s$;7Mx~0T8hce`vOus zkYtGnx2}pESzh?@Cgid4X)2KPqYZ78nZJxR6qP(zTLn4!7}xyRbO*IT>@V)cKr)dN zL0tK)FD$2L;wfA=NV-u-%?8rkHR9072J(ZvJZH^&P-xRJIZ4nlAhIbc&}d(k#-XH| zvsbfQiM_w&@1{dZm!3G*$Tf-mfPtvK*@bO16YEbnnF1MEp?zs|yayXLVNFG5Ld#h_ zh_^f2kGhXBi!_)AScqGext`qUviE9oPcpDw>uxB%fel`K=)7SJI#^1vVyW$8DpXVf z`TB^zFt(e?>^O{^TFA$bLUQAolxs=l)vTtcfdv> zAu2W-zz!1K>U0vrQLyPPEF>wL-hg5i{VpN2L}e&aPOT{tx5hWGHh{v^Jcp=-E3### z)XFw!5uDefb{Jpfxiz%I5rCRjJ%ABDhwr)MaJJY-2(3Hqv~%LW%|pVVhw$Yf5t2-g zP%SEBI?;q)uq2kMmvQxi(3Im5)()BUHIA`RUnwVT$e`)#}BB2tGUI%aLRh<4LU!?L@e}-j>ssj!jiJ^UY zyw{zLsb|SEQnsJw9;P`4=BjGx++NfCtSB_!Wfn^)eXjHGF{ju4rtHjp^`R}_*=eoEwj2C|za~twKE5e7H*84w zB56a&U=~l*Ln!*6r=iAY1DBB;CSD=^*D+<|!}P+5;v}Q*;gUl^!W5f?@`Qm^o+;G#xh zdAM0vItVYB!5>REz<;cMt^(nVu-sWHUYd|;$OoW_;X~e3!6#YmV>%y-{vu014W4&TL1Mb`m)JO6h{#QVBzBXS(iT+`gd~Z^awV z4+Gg-Dx^!2+ao-e<0tZcq~m ziYm%y5$b7--=oMl5Zts7L$c+|zwsVzetfIeX{&0G&`kxNB*;`&F>R1gX{N2%SQO50 zV{iX!?yE0tVkEQ!&(bBYZT>7=4Xs#~B(pJI^4a!dX1_e_{{)+;2+n6g)R?-u^58mV-zQS4-=HX;SN{+)G**m6HLQ!=z3Oz z*fSfnk*yi3R*+9fvClMjDfso>2_#&rnel)vw@IEo+2=LT22Yq8)9zQLDUeYkXobUE z{m8&(^}83R1Gkd&+zpO>xG}=>l4r#mam>32k>dqr8PF`Lkf{4^0J#7LC!m3ndTeX_ zIEy&#lL9r2VK}V6SBELiuBHH0cKT?)6QA_R|t61g9h?XI+O&) zJ7w{AWKuPZ;2Th=^nFQ*AvS+d4^Lyr-zCV=V4wM97~&6dnq)e}i^3VfRXB@5EQ_C-}KL z;q!!^gYx4A*KQF_zyI8~uV2!IFCbHJzJSFpykUTU71YP@*TCzW1HJDAZ|wPbcvt{8JUS#J8XTFH z0PA_R6TKPy%C^oQREdi}3|1z=b4qnAU`D?W7ig>2uzV-&xnmqJw$&q%UBrU+w38vr&;=|l@zdl4=8rqL6~+Pwz#~)$ zAzj@Br6$v~VG3ozo%NLeqVNxtnQ=N?apTRrwGyndzv3p8?V--YRNAA2rh$@! zjmnTHNx-ryqUFfC1x2TEsytg%Qf5IPow&IG$wf^zWjO>=F^fg)%+9n$O{@B1)ZJ(nG|xpWb5X_h7+*DwxE zIyxS34&V2(Zgw=#_vYMY&QGS{oxZxbM#FdY7w@`TpT9Xo7^*(7$+U80Y*scZXi_`h zl(;9h4J74O5(m5MsaqNT&<0@%E>p=d6J{UC;E z24`kl@jDlYy zC1}Z@G)Ebwp%Km>XJHpHP#bjmp&}ZJ=i0s!Yur`B?(5kF;sg0!e951%M;2Hw-8pV* zmQq(v!L1&u1T-T`w5!0k(|gY=qsmi1aXO4ouOarHu>&wk9gth^!lpI*X|-^UIutGq^a8QYHcs zTk|wv8IQJatuMxTYavQUg*q6A5@5hGh)t@cYjg(Gdn*Z^tuhEgx{>sBFvmjzR|w-7 zOr#w{A($>+mL7Qi;x+zrLqnj6JdfC{UQUZvx?8N6fNbQ*R>K!X(vw^j>e?OJLA2%U z;%lYS0!;qQrh4|TFYCKJ_rU6C>q;W90ZJY~_)nRsHv`jsyRUuuFZHhxo*p4JrhR+O zJI*u4i3b#uvL7f<)AVuL=&}g8K7TSF{(wvwTRo~HTSjbJcB-`b0CG2?A!uXFc)?kV zy-f=#SD_T)caZxUGucE@WFO)?s6jtz*$eGE<-LMvrE z+6G_CP`Be)5~V9J(MNF~)!{q98&XhZ)2H>IABgtwKgNEU7=;pn|B3-qg_Nj<+Q!6} zEa%(AmsE6?V)X_zsDm?_9iSepb>$O;M|e2gO{|$T(@#`X(PT)IOA$mb)_E2@Bz*JK z!60#OCf>Nvz$Ltp_FtE0rzVxGTUo7ZvDyI~;R0?c*!;12{6DF+?DXs;5#s zU<+u<15kzQL|>@As?b9L;>c70SXHTj)>BESl#@vXloY2mY1zy^KX*lkvcZ#xtprs2 zIt0TiL=}kpvb#YyTWAjm168fsM8OaoL}{_87R$z-BjUfxGBRiu#$ zL~o$Bb>^~jB+-CED4e2tZy3R3)9L5d*_U?O$?7^C1ccoHQ%<^O*w}BiZV4u8`DGvR z6W))lBgxkj$M9pxlK@H9OPqi_&|n&vN=V(2A10_){+R`J2z5u`aXOtWQ>clGF8;ki$N#w&)-iQi>x|^VC2T>OOkrYZ?05|)h!ak~ z6{@4c3-Plu&QcN7)-}%;=m6=)!0VdwWSd!F;HJ*%1bqoSdHu*0$tvcUGpRXou z9b#>=$3lTr35}`!+jeT^rcWAe@LfVLLAaO*D!K=!-T*p)XgqmHNK3Xscm+AS=S#y| zwB)&L+wR&(B%_laQAe%6kACRRvZ9E&ndca)=p7`Wp|;sOGJt^=4hqos_k(ww#~v6E>m; z>(YN{f%Ak6bMRnz-^2hxeO^3kM^fiN^JBT$1#*j+$fs4X5?$WCTi%G?~;!6PGc;yjHir@*gSnL?qvjFy`i$ish6yX_U z-H@PA#!2OV8w&k{C?73S5dwQHWJfFov#-|t8d(n+~4MtEPnPt3j- z01oC1nXYi}UU-1v#M79DElS+}(NxJ$=j($+cE_1Qv{qoI0%Ty8<`LuN$EZy5HBTk1 zIFFEFGMu;0?6D|YPM!}gsL#kq5=Z}ptrlMkKXU@8)ga_HCl+~B4;~mqfH~umIlGMt?Z^$e=YA&tR#iZTV6)-{%uBl4mnV_ zo0}kGKu}!(k2`T^(K`iyQ99o&Ge__77%;l~>XegTH>a=ocqg$GADn3ccpuCvtZIu{ zcZ%t~*2^}Fogg?#fHNVQ{pp&=F*0vNmF6a4wG;%srffo;K@YV%ti&I2%wz?lzj&;7 z^*SaK;uv*_wo1BsEzp!(X67)ftT;`yc4~o@D2~;rg5FXs-QJ-5yNSdH_qt`k4QO&b zl*{8E2*v=`urbIPi}w3k>*$p?!~yr+}O; zU1mheXXtjHjgb7|*Q_vuMZ-!$L4M%_PcNBxVD)1=XNI;rCH_cBMY#a>RBbE`jy#AJ zBv;s*SE)(qQQ}n?!|7C3E=@no*9G+tg-$iyqSh9h2n+{WPy8v>n~Ey6q4gXmL&KoOITBP&!0VW_G)cb{`*`+ASvkZt5{e3n z1c@fzPfbS_)2S$|bN!-Pl63W?n-F8PFjCDa8sj=Bn~(N|E{koKxtpo)tDz;#jy6j@ zrw+9%I!++etIQ+~Q@AI@M{a|j+a_~Xy^?o?lw;ztcpL7`E)js*GInOWaI=uminqNt z+e!8f=DqsLjnGb$j+w+S)?fnhlrfykV{e#5_&Sa`e=lp#ut0u0Vg&&q?_=7GzO#Fc zb4tU1#5byI^y-ze`k_07%U=#02p^X~!bCk}!{Q}xxRa%i1wD7Ez5fCTWy;WbK#y^} z>CgQ9t9(P8^jdFnM*#wJ$2Vhm9aTglN#dR@gkdf40S&m@@hl^)LGFg`U~svc*~2~d zFoHNHM3o&ng|ERG>Z6r7rwsL(FRDXmuIH-dNOwnOB1m>i$s$J+s~i(az0fiH3<#{0 zuC%Y*qv{m+P87g;&RbvUPZeLLL=?3;@etScMF?sKlkGazMlU>|Q`$&bnJ8*+QMTl@ zT+u?)?+uujljQV!CsNkjPlICg^Bm{ipi%t9N`T&>@{!QJ;PRHYaiX*3$Ju|ZASpKz_El}O-(!a6h${Q<+ z_sj=n&69X@(7H#AhWENL4@_7!CdaGeW2ys2voT)!J=_z6uRjuZ2XJSLm@=!MhyYlR zX}Gke=9X{7_E|7=0!b*}0{FSpcaT+TjiI)<2da~}K*&;~1JW+}gbT%#>8+Hjk3s}X zRyw@&rQv356{~^wx^9yCwD5|eMka!Llcd0vfv;#25Xrs?{j}RmeetTd^$d;_lFo#w#i8D z#OTE8GFz4>jJgrs8tMxYpS|5}|(?m|22nH98Ti2$SSh!LLJ~oltz0-By z;~TStH2@udyWJZ4HS6(1E(hO- zHtY%&pH^F6cHeEbWz#%y1X^nff7sTKK4$fywUezQxE8Fmn)W7lXV5oyEbHxy)xHdS zym4f$PwL0uwznAjgDX{WA{?-I>lCUWsTR%`87?x>gBgTAX(IN|2fO$WgseeO!M$SQ z2mz1JZ1m`addz$w=<0*RrjN)uL&_ofT-YA{kE_A&5kYifR2TNtZn$lu!%ooPa)f^K zb%?+RaeNW}M)2L)oay!~%nr-POYt#;X?YCjgls1iiN=cne_uO2Yf=Sng_nnH8@!_r znw@-5|DcBt6m5Th6j=6qT-0UG9Yq2nLyQ3mDF(C>=nEZHriQw?*fqBHA|=l2#cxL- z8}jJg^bu}OsYXA{$S#;EK+derv;LK52^>!el=s_H%XMV1yq7Kq3YpL6W?`&c9@X-4 zJPF48LAlEEcKGo8T3NZ`cKX>IbkH`KFQ>XD@aMZ5s7VVl^=y%BARjc~B8LeNdkx{k zn$jA}ZM81U9$YK1Y(TVJ3olfCOUQ&S6MCQIVQwUa9}cD{{~{M^xhq));%2>#Pvw*-45b3V){bM~L{m3?c02XvtT za5kSZZsZ}J`=j-e=Kg7fo+bZGvJHWRNN-r*M+2SHwT-}>KQ^`xI=)yK(G~<+67_hH<-G+VreBHFx&GyIg{e*lwwyzHbs_SJp`6NF=^HBb%&fmy|q4{7x zQYZJnlnz4G5^oEIB#LXs+aZ+~J1Gk+7Qi3dAr%vc>m-Y*NU}>XPW6Dv&Z`F{4#LyT zk&tE_#?6ux(5$S}ZZ}s7C;Gv?y3dj{BS|X;ND%R;21vk-Y1h!H7w%EfLfZ}pUgc0+ zw{#hYlW}nCnZ)3`JKGY#+ampqRKRDw1dSsO8be#@MaJ(yvi;Mj6TlJz4rb^sSVq5e z$9&-Ch(p*uV`IAci2nmr>Ij63g%U_D)|;|BwQnT8aBaY{(=}93K8r&$pgn)!k!nyQ zM3Ir;S=~W%a*?bR(ynVVm!v-2KF+RIG(Mj3D%5n7B$$}yP^ngX*ZnQ=A&Y=j?Gk7K z@VnW%Cro$3rJi-df@!X}%A0QB#=DVsKXr;>b*3dhuE`s34(Ge6ul|WACqHiyuDd=7 zdg6^`R8>5g#AT>2G^zeNphlPf?;;YB&)LcuuEp-Ie#hCH7UPy;V`^C18LqW+ozz-* zzgxL#R5EGZ-{ic~O9KtvQp07XLr@6mU$u4v*Lr5MvIjdqi-eSA7b}TG4q}c2;=z1_lP;pCvkKDDHgu!;AP6)~1?ot?mZ6v)F1@V~e)?NOmE9z> zJ_K@AFicG2%PR*$9fsfp?0L?P;j#XO_ne`gA1Yc@(YT?Sw?&yZ*ee()uFn#8=fn&sM>T_+JY565|myx37T8-_vHbFSy z)_QjBK%gwYy4GLozyI{-dz@HU&rIDlmDO9(ZG|bXg4fQ24x1+67;C z^VEUoV{>mnf1pX1Z$Qj>aneR?5;2^^S~Z5|W-85t=8L`kg{-2DXnQFoi^K%DH7zmX zzewRMp@!`uG%d6$t!|B9iJhf{Cg;I$g-6({J z2L*Hjk&O^w_#cTwvlrj!vWV=?0t{vM|FgVwS%CRcd&$U8{;mRv>HYwY?{nDIY8UR$Qn7 zR5ECWBhf+=XuAPhmWiKrLt6MhQaYRYyv5V*yiHf#^tFnv(_y4Gk-hdHI5SpmJWaGhMR zNCL06L7SvEHs>rzIAo74<@5Oc0X>$$)${n_TR$K^0KCK86TbOK*HYl?aqx-ACH;hp zgwIcW_r>nXpJHT#q-F?hMbZ|lZ>#QeIG9nkWg06_eA5|G22W5xdLz zBKZ)^L0IIIL}3vUN4^z?VAJtL1%a&2%)S+if7LT zBzjpDSE>X@foq6@R(836nmnU(j{~WZ#qr*{7%P-kqNg8%c8?gn#%9z#6V&mL;R?Y z5G|Q2Za>u#*M_bM_<%fZYkjtKG5qACGhozkU@-l2aYEnoMbrzA{rNnBs$Ng)HwX1# zls+5>wF6MwJ@t%S`4z3n)NI;1=jQT#{3zTrB|IJf-l;3g_7U5Y6&CA}XT1EmYX^kU za@eSvS+JS(XsTq3wvGbNkms2tG4k`JNt3)OUe^HHb;Nz$&Eer8duE;aZ3upt0c`wZ z=AV$w?-EaXH`)72Ru2cfpXI0QdOWmUN&{7WaEA~CdoTX;s0CeEwGzGK14!|*L4US* z%Z6fB0aAuoiobw)z@7NqK!X`k;!HJT)231eIEIDN!!1q8Rk7eY4SQOalOH(zmJh}d z3v+gkNwh147hCM=Y$u%Ye95gEFQP4rkez0{EQfFfta7R-!#sG6X!96e1NPObuGtoE zcowb>8~!ECdvRBQ2unsYIs8@C0#jJcs;to`-W;kW>R{$M(TmXTK0uKHRov2+;o7in zJ9_nO1Wxz+G6H#8Y=Di zSR=6HTop2(QJXsaI7oFE?RV#WO=18HZ#2=Hxt3QIM~^2Lk6KCc?gPL zOBbP@Qfqd>RjA>mLgG`1^_-#HI-U#QtC7^hX>75-n`jUaMkk<#8{3C+3^^^~GfZT> zZE0x)PK=T=OHCPJV3BO*x%NASWg#W4Lv*Y|wQ`V1wr^V3^V?HmfBR<1efWwSvE8OM zKna#s?GN^ECv(99<3vx0ZXJ2E$quL(QNP>d3E#&J_&?_ivpWL*VJg7p48o7&_6VBT=24wrYE>3{$Mmq_fU z>g@aF=tPIff%3R-d$>MeQJSf;`E8&B8Ygo8g=v)M*{Xv(W{4o_(fuXK!#GL2j@}l7 ze+^AH5J>_JSmr24YJS@d)NuRb1{NyTNr?K{^`%reCZRfKv4v}CX39MR0n4nN_d&hO z#E{-lSKCAe5G+rc9LYkTB*MB-wfT{2ykyx+1g~=?zFZL4U-2!qXJGqE`(Z`?WJFM1qj5D`*!8LK5E4f5Ji!PTl^L|4f};%ey8Ce~ z^8XD_e$0L-Q;UR##V{Yz(nWGSo)a-;Pwg#0eI*(;T!oxuigaW)Al82B{Kidd{Thz$ zvQN?lITNAp3d=s%AYIm5u>v^9WT+Wv%t!!XtFjz+I9aHNj-);$k@ZYGZ<^WLl0*OW zj8(^H|49dZ+*zCpYU6{NOQ`j4V7p3}Lh?e2<_{c1FZfbSQ5IrB)mcJQY_!@!J5g#y zc`v27bqfVvU9Eh;3u#BYu?KT|fh$gZ-{B+>KZPcG&jtnvY^PU zm=1a>RM7D-F*F?f_}5X?-JgW)K|goXeYgbds`I`zCAGMf`X}=o?&8J9Ntj-H^j14BVUZgmn(%oo1CpvGcT z`>aQ0rdcV;J)LS;A6Z0(8nTs(Hn5s=Q*b(Ozq zN_nxRB}}oTQ!4ycxrP(E9Ae5T97~I^E2yArbxTcPaO&yxT0U2^uq$bY6la53@U=^Z zSJ$J5?jajkT9%d@z6Ef0)i{go9%?FGOKu-xv_L?zCP zY|k)^-X$FtCt~k+5Czf>mx;dAyD)Nha$l1Jp@AQFcfdS&}gATR?b#Hnm_YT!+_9YO+SKm zUE-$-gILS#5c*DrJCKOXVFPgTLWX@58UVeQF@=7y*?PC$%agRp4&g_eSKv+n8GD-g zokCPF21VCq>?%4OkBBnWC9Ik31iXrehlruPA5a6DS@w}SFZM&x`%*vjkqT;=EHa9* zZrx%&f9@y0!tBWtuIPI#!Ha zF=Eh9Gbg0OGA9Ja=Z$#-_+NUwzV275F2skvog0w>ufW)4s^1TW5>I4Om%Is zxbz43vn%9e)W}uS+{{?6B@};8E5~N%0ew zm9$)VBw!%DBSpdNPOUCAdO4-rxg*_(M{@Llrm$LMo*y|%W| znM-*$3C;3y(7szT<(H=5$d$LC|6`7TF|AIgmtb{JnM6I z*26XEvXi99CB#&(o9Kx;5??wNx^0+^(?1^Foy^2b){+MuO21T3r$-C^xnWfZyE=ql zLj_+mi&(Fq*tZ@;N;$bkoXS$p>4aY=#8e5piU_-&^Uh_%_~<5NwqX+nUUOE^xE{Iu zU$mwFMw>5M;s34@5q#ZYDmHIm5g!|KxXm4p(Ip}LutR%(IzAlE2`+C7Ue0MtAfNIo7<3E zfpawfw;dnVvMzvz-^#U7@>e2)CX~?ZAR;|7Bc7|q&3?m2ic!nYKLL9|uB;_9f~+AQ6}$MM*(rOdO<1=JHaz$(lAg#RRU6{wVndE-^F($n+#Y+kIMV<{jZ0 zi-WpN*9t^1KYAAYJW)jfrt{y;*GSmPmNqIFe>8BEOCU8&sN`rsWww>$U%Iqln_-YT z!@$n@(tSn{iLjx@$!!f)1h+)Q*FlCOj~29?$=SKa^jN~~SFldB08VEQj39`Ps(W!O zMR?!~q(FQDV3lC%-0=_h00ST92GK@-UFvY!obBD(tS(R`3_hAiGK|cWd&HmtKp-5CX=esaNQeknh~=?L2tPmkOl6<|TtGl}V4cH(!2!U4z^Aa-ZDN~K zXZwD_E9d6eck`k**MnTXnj7c0rddmg@Py4vjH`j`6<<62lzE&0Nj(C5^zgkKEZx1T zRgg=)itsEB;w&%Lt6?BdOZgdYe#zHzedhBCbmv=ZZ_6*|2-in00E@P0|5N}@c--UP($bM1}lm; ze%+5g1V$Z?IEutuWf?Nc6)!h4#B7^*eX4(nd3dyN1qtff*HbacqRYBuHJAV-8L+>Q zWM^k6*$v0b{o4_*4B3mc1>MlNf6k3`S{~yektWAqHs3aAvjSK|LWv@M>XY6kNB6r2 zxtX21APg??5$*+KE0NP=Wb8y9VE%=)Vqs54qki5siDV?BOe!GEd{+`ffVXd$GDqy` zA>hnJ=Qf8$&Y;zFYdFjg!~=)cgQTtmX1R2RoiyOVn{zic0uym~*5Qg_!+S3USU)qHipTYrB#cyS(iKH~IxeBGnZ?m_hl z*-}HS)k?G{JyNJKH352VV3h($;LQCxFkqFLv0;@vFOjL_uFg36q^tFcuCv_J!?0Gc zW6Zh&{qxX7_Ud_}!^6@l!wj0Iz;$dVo8!*`9B?}<>`#dBlfRvNk@Na|ICU}oyTPx( zirGLZ#pKksl66$a-IT#EFAe+2+h^4c%JZ7s%VizEfvOiBLKTa^+A z_*O~(bAc0OUZ}x6nNQnTAtHtT(9EtYzr_&tjcYHB&1d#97b`435rQX#m-%y#9?970 zbnC@Fg3lv{1Fy`SGl~C{@#af*Ut8W4J%1-pQ~~4Oer%}LBPSu~_))98wC@U|(M7hx zML8K_oygSB?$TV5pTD{fIhd=9{%KK}ughZFh~Qr>XiV`Wah<+fv5cAAtk!@KPD0o= zhQUH5*N2M8A;G*#Au7!=L_g}A@0?@01k+;j5S{)NaFlyvvR89pagA)%*TOc5L08bo z@3y?=k~h*gw&&J>&8$s$HJ2Y#`WTei)>=-$2>jh3z)&rRxgf!`Hm$nGoJ8;wdvsjE zx=acNU)m8XK@iY~Q}y%xF#fO4EhbPA*44gU?P*hbF_N_aZ)QuU7F*a?WG>fJ6ZFMR zkOOCqw%^SXyKO~i5vRe?`)~a==-klOS+XO%!M+CRv5ufA-Yr!34wLbO`LQh{HEfwLzFN{g4rT8<$p07S z6{%4_?*3xlH4*>-;xCf@FXkEjwfPV19REYR%aje<4R(Z(8}w5yhz?g_T(2;B@>@dM z1~yu(7tA_7I;N1Jz=q3#tpXWQn?WL%Uj(0%AgB90xHP`*$PPfzK#=F)US z#YvkNs5LZHVNq%B>8qJc*TQrg%4m_Gb`&Su+_Hwhf44uMpAnGKNtDe^00ql#;}Y6& zt+GR63dN<7t7?!$8Osl4_4BP-AdH=L%r( zdshK~LkHOx9#r}A*XZhoj`U`tXfR6&X5`AiiY*ca_GV! zs;~t2#mtaPWQmB!zsgER+q2DxsxHN%yC8XJt}4Zh1l|~0cdys;#io*LY#IsMsi#&F z4oezPG#nYn31bz@(u!rA#p#Os^tFYaXGryPZ#}jNox$;%eW`3N9I!Qa<8CXvq}(vy z9)!_hS7idtX+nZ-yJk2OKu|V0yD3<*4?BP(fi5cLIat|#g!W}x44Y79L)n1DO~kUqAMGNLcsY9;;9=gpbcR{`(V3R;{9a1XPG zO6Dfq`znmX+;#|qh^Yl7pQUo?{S1toDm0%rn)~~x#Nx8aT(HSVI@fK%2UIO&K0Un{ z0ygbTlfSuhRsY0=#`yDak+|vmVL8k%vx^Gy2anMAumILU2tOF&%Rn?;Kf?eHns$|v z9l9UI>=kd-yd`UEss#GqX|R<>=C;KX)A21Lws%0dIk$5vbkCXQ0`7D>EAdfnk?&;0 zNFcAhx<}hco`pfvn9jx@A*Aj|S8Y7r>HBEZ{;avB(q|8Y{ zw4(HL=A7}KiZ9s=dNc79A{gbCQT;72{`z_7A-hs)U5KS@LFF$+VL_5q4P>46ZpJ}+ z=h~Ac9_oXKf4nh~DosA+7~Vb%J}oqcPgd=5RBqmhy9+6r?v@r70)f3(lSy<=y-wC= zX_{`(XH23U%(P4jpK2Lr6XY2G!`@p5McIb`qasQ-N{0v%(vnIqNF$&k3P?(K!%_lE zNh~2XXgBIX3oqxzwgdC<1Eka-p_qscU+&i9@mp{ zgOJK-PxeLKOLdVJtdF)j4=_fhW{{@6#=nZ+70+Cp%%BDB$6Ml_4mXHt(#ND{5w3W& zIF#0Uk9VT9=t+z7p{D!k`YW}Jwq^FF8TQ_*h7~17ldY?jts6DAeWt1>rG}^ z*7?azz-0gT2!!*`5r*MT2(=IPMZujrxBnjgyBt^>e=;}VHn%n~HRk2AvoQ@(dnJdD zLv{Npdya9SZ zh+WAnXU_WP0vTkanx(`4W`AP+sy6F=x%)Am>!VH(0j&<|=6e2Di~qdO%~5)p(K)IK zb!|Icg-P!@WL?@pR-{?1Ycuh|)LA-+z*$qrK48`?GyJOZh3no920qn_P1E)1$n!}( zpN82_F)BKp5w!FCqsq%Z3vSEd-V5i*|<~fNvXM6MWG>(0XZDD)^8)x`5 z!X-|H^%MdYU$mn@U(1^-r(_ z!&y_*GF|Z)Dn?(4bkvC|ag;)|eXdWI`}gQk=Rw;umH8g1>$BdfN%pZ*gvWlFwOz}7 z^7HM&su>I82JkXG+>&8y%K&JSB|}$H%^H=@;9^@)y!Bw{guL{h`(ltWdhjZb0aok0 zy=Ic;Zh{h78Q0W1`EI=RBiDw(3?4?g9H-;ZU1qHYRlD5GO`r4FZ_um?zeFm-6dI9m zYU9g|Rc*73fVn5}IwMPomcEy8(X%h4JDD) zasBo6z7Le}M`$OVN8iHPK^q~|brocpo$+_7efP#;8{4bf7w3L;I%NbM5!AsoP4{w< zV8FUeaB6GDC+0m}OSX-xqIAcqG);4d>zNKbUw4u~T{+g*g>g4sjnD$EvRMouKaKIf zI-RveG6=K?z=Z5as4Cw5dk>U4ImcAIOm7~oqyYF6WpmOAE0 z?L%ZJp0wEaA%bTOUjzQb40t=8*Y9Iw=e*OX3Ucr5&DFX@ol(SdIA>Yc1Gslvb+L$ciBH9sk z5G2uF=YXC8|HO*(A1`ZS@$+B)Q%n!BAH2(BcugdKxm%sSp9)d~0^ZeoK~v9bmF2yG2QEw z4VPI~8b-feHSahmhAh%ihbH~UooU~fNrGqz;;@h1oK`ovN43LvmBRCH-D6^M;Fy_>^$x9YmZKx#!&PoCj!4b6|M9&>Ba2uVZzmx7H=%)VScL(-})-(Ywsbf7cyp5T{50nT4`7H1fs9H~*!N zbl_sU@B)5DLov|q*c;W8^}?o`-^R1P9@j{y&vE(l#;e0#Z|%%C2W@8yKKmY+i4{zA zZL;#o9NFq4BX+G2Y#U%5a9B_Cu#pynSYsPep3PWt)9ZbIQAnxh^LsRXjzDB*$YL8c z-da?*w>2r1MXs|#7(>em1mxb$RdL0X46#JWJA*OXhPf8 zeIE+UIYER5D;;oC3sb#Qr{Ig@QPpd_KDWb90U1QV+P=>|!}8`?Arjw=+ntMD;^sW_ z4E}6`>6Z`lVDF2SoQB7Lx=}zsg`&KT2?@;d%Wm0dVbs;pydrzy%6)QDXhH4PPjAs= z`-|21x>!x!Y1R3KQX{$Qo~QX=ar$uB3w{ksH}l?vf1WaW;ZtO6)LVdQ-OE|cVXcHq z5gIE=(XkH6h@P^7RPe932R9L6e5SK+Cw}-*g+<6yUR&C21z)y}CEb(6_B3(<6OTge zH|k&=)^ zVTKomhb6mJvt){S8c(G|xoXW!GGx&yTUm6H0=hHaSKUAGYkujoF_a;09rwY6Qo@M$ zgk{cU*81kM^$d&A3Ru+7R>PNh+Y@+xzV`YJOo8^~t7~8)IHIh=<|BgcA2cYES^#^b zUHuORvpy?A*&{z(uBk{h^pQfcjKEy{i%ibMxeEd2D~z}K#jUlR%vXEkN$X#`@l>)Uq4-e6 zgwEASZC#;mPS5!Th&Rhkl&pFGdF@VFFR%`O|u)Y1=@osKUTa?_7$ixILvyC zU8!h{l>rZH{7@nwCS82DJt|xkWA2xAsB`~d}Tim z%sytssxGj{jVQM&i*^WrMj$iQ3*Os-g!FW_HdtY64O{nh3*BuTCKI!|{Rzb>Y`KgID<_^N*XV#$Ao6(v&&|yfn8rSn zm1zY~#WHfbR@5%z_~K$WD8ROy_7U^N8gly>50TmNx?9>_7YPUI?T=c%nIP@HIfo%s z(=LIX<)oFEu@5gv&CT=rWYQ-7ql-NdE@k_P*Fc-oypDkpWfp~m!QD`42n zYxNNv*JdjQtE{=s8h+vB~7axdiD+OZ$aR zC^}SFw^w`fq0cOzOwXKY9&@R}54qfVNoTTGK5dd5D?WlOrBGQZ4i`d9S(mh6c>lnk ztHL0p+gVF>)m>n{lZ8GQKFnt^mZw1YpxJ@^W1Wk$ZPRsC-C+;=Je|kR;^;FbG7F5t zwo07JQ0~Sl33_AwaDj;fzvNZnCH_xr#PGuCv#ujm@rzFu&p&4gNAz|AZTgi1oR3^r zqU34`C9Z~U_xUE=RC7VTe^l7b5{$$5H0IEhghFgonNP+1osQNdZ@ZnUHn7{(cPX$-e^z7s z*p=SPRcAFGNO(xMcOdEA5*{IZf2nii&QHol3}^JcBR3Za&l?{1&|Py`ORUx4D^)uF z5eStrkFE)`rT42IJxMQkXt|)n`csV^*MpoysWM8zI@W5HH8@1Y1);WZ4g;M z#y)m5<}r5$oLO1xY;;VS$A?eG5*1F!78r{ZfX4vqFQf~5;e&ak>lFVpzH`;kpMKJ! zL|gu>h{uy;$B^xi8%vFH{PvJWnkugZI9Cy&l9$~uO5%9=xELPL!ORls*y(NdJdXN> z;-78>(Sf^w)A0~0r>w*6Uf8{~htiQa4|xc9MMs;lc-n}_hk=72LNCa)5{KM>1TJ>y zTR|s~hV4(T3*O8wvqUz+cBwKh@#&fQ9Eb%c{HSYPPPQkD`KMo1o+~nLidPJT zZb`{s9baM8E$10|hcO&VrT>daLVr*hq5nOVi3g_$wuEEb*AYV?l?Do5Z`rsTMi-{D z#QaJcPgT6Et^2$q}f4gTJx z=np)y;u(`l9)pEp+1h%=)x+A1C{4TW0-4wIGUzg_KfBl|#*ut;K;qMQb;p^-{f=3} z=0ssKDjcbDjf=&-MVH4smKRSHb>?FsB|-YJ3*V{BsmJqs9VbVPepO~z}% z)>ZeB9xuj)CjObHO*v7=_@7G}AA7^dmc9a=VZ&JTV{{t2fxRrwIjD~LK@6()B>Yj~ zfO3AOWf4{o-}&I$?j4>r@8quBm9EmtNA{Dh5^>8eb>{m)^`JnvN>KdFu?|#H4jy#=l0kJ zDS>A{$n+Gl=2_SZ6W#`OEbhL)lxLysb(YQ`^B!t*`yNY5tfJ&Y(ZsM~pyM!N;!~)R z#~{o>Kl+TCgsSRu)MthVxeT&dl|AT%OIen$pUa0D1$VxALP;AtKp0LCCV0=D3X8tS z*H^0hLSgleeVbq#L~Ep!2&d9cRNGAL$?72g#(hb*gQ67{t*MI*ZSS9N16zgrpH)SG zF&QMqAfYTnt%FB~Q-QtJpEfgoJ^#S?6_HMa2yksZ|MVD#kyGOF(=MOVI|?Kg!B8fD zJ|*v>uT7xL#9edaG5Md#X5Sc^D1trq=;ME=<&}ovi#cG}qXQ@6M4=*L&BZLV-ysGSB;m`5$#dIl{l2?z)KL29KZdwKE>Gj}m70O@ z;uab*=u3|Xwz%KhGEa!FqFo!l&~Z~+j}Vy!vYk2>LKQO#(RWI!dn>>kq_*sDhCy2x zp+N6bry6&z_;^=b!92h|Sjx1pC_^n28ejnmhl+6)Q_$I81?orY2k+GFHzK)I3qge> zr3Ok@hI1X}6sPBR_T*qo%(4Cz!hr=K&fP1mFoLv6Fx#(IT<+rr3x(C&av$4R0a~6M zZ%Hl8FZl2e(fuHfyulu)JDUUImsS!UMZ2o((v>&@kLK-yT2=7Pju})(amk`P4xS)d zKX@)99bmHzqMH};+bzvgYY42E1g4C@jfiGoIHOVqufL#7Jo#-JqP$U}z|EWh2e@38w4okErMmzbS(FJXEkJ#Adb^h(z z9a&*}2ePT4`#1s_Ex92n2IA~Kw5Y0b)QntINHG_Ka3=4N33cK#1S%4>&5+&AjTUP1Fo7wO(7{66`QBz@3y8}g zOJSwI2BHN?HRL&%c9tarEbl&kU{RqnduMs-5q9y*ZT3P(*>hrpx=M$U-%6o$Oq9|e zme|9yF0-;9ZWAu$+&hhWB~q27)^-vc_vzOhQ-<5L$s{EQGYmc)Vje5H))sDG715PhPe9J1kD&?Wab%?&Je0* zgqK`HGa{`XswRCkk`F?^A1*ycxOR$V4rJlP9Iv%)0a^*`!A2fUYI)h?iRR8uoX#d%4FR*u%*j?u)J1vH8LxjY z-B1fgE98X`0oWW1Cw>fs>LGC~$x`4KCZ~)%j9AuXs=O6@>x|Vegc9`Wc7>ErU9?jB zG=}v#@CJ=IozG`Squ~OSPGR=)+f?Y?KMu~{zhQW0M$34I7=Fh_90yMl&Yh;1KqwsJ zVJ8-m`7*92E=@QM+bGuZfEP=9!O$!q=Vb)iQbih4y}i(n%y!Qg7YF_@kjO~P%@hw` ztDl&o{Rbrok7G^i_<*?6^Bg8IxjOAGu9FBOpR5#KUGDK9&8=8VBo1VVdeS%|UrWf8 z{V$1_btPj}>lkfMpD(dek)hxO<9r3DROP5B2L)Z0#Im9AB>aHM*B6vD-3U$tW9k zus1*h_3b+k%QD*ZHINi*c#(yF;eRNvwcOJwqE5Gb_2I`VoxE$ZQy?}btTF0cpdGaG zP-=QbTu@#5NiZfU3&vyK0(4$+N`F73<#J7zY1oAU2|+ul7_0wrs7^Cq{R0znZ-&eQ?*=IQhLlGxqdK7v7mcUIJVN`LYpOTSdcybAqm`ZgfEi2 z%XVxTi*+eFgyl9xzr`3wC$==G5N0&`cqE%3-A7GXCu&q*HTbeZ2)6@P8VWcT!Sc^# zc@8+j1i0(#CpFJ0sDqI%Di1t z8_s~$F0jD7lL*!(*FZ|v7 zD~_K?1T|!nSUi>i6?Q8qNsDKVKV8xKCH?RfF^7z{6r$XBJ{(jd`E@L`$Jfl7r)Zh3 zlAo%7@G&JAkl47dkD#8O_1|v@WK%y{;L0DpL$R zWml=;AOi=Jpjxiri2%X)oYxFG>}UJ_%Wsv{4bqL7osUuoYIF-&zUc;!c7G(W`gtVG z6z-aoGNeQ%!N@?TG{gEvu_k9S)E+!GE6AKn6~4C4^d+Tf=5Tt$pq!GdMlNl&k#m7D zgzds3N~X|ReIrgO6T6{KfsX`TkW9?_b1&!PaNV{F=Xbden8wN&GbUClUQ!(*zb&=K zw(B%N%%H!-JK7%#;=6L@(FA`VmiHzbHz<^9FX{1e^krwXxd?XF5geTe_*8FR*-?`F z_Mh)y{fh<3Xah(M?SDbxXK=79cWyJomrBwm2ZplckK6jR&zJZr9T<6(KEPNlwc85b zD7-(p?T+va$}USBC4Pw=tXfu3x#D)3pwZk z>AzpAEUitN+x4i3>Y)Wuam+ZCKG8C}ttbF#+}PHiYDXF1Tx&s+8kScApI{{TiR%!C z{zyyIdZANI*cQzOx2|>0VX%d`rT)lT*T=j6M)8P7xxwa*tD~;)iAap~3jU}DpNf!@ z5l^fOfPQN$Lz<`Pa;i-ftxeR7w$2G?Uz{W9t0t(8BoeApPSQX;Bi8DR6mgUWUz~Cv zrmr#LR!cg}%k?dbk$B3Ox@_JfhX$TDh0eNeA9LtUpGVa{dS#Mi&P=b0@g{Hf-jgiq z(eH$`FUI1Pm>CU{oJVjIB>j&+h1_G7(@*ls5m|RLDKk<8_g=b(O)K_xDof~D_j5C} zuSfwX)@^_hj}kFvY^<=2{VXIOXQikykujK>xtoS1FyU-Ts83Wjphd_M3X9?8QPXnOi@)Nz<}7 zMtPb#!P2GS*l47F`6|N$A`9f>RpinXjT}w+ubp1*CY>s%@8xlDho$5*ZNqm&=o6Xn znLu-hF=xoZoYq#ouunPjSaH)070ob3!F0zFr2P7EPTS_{2h1Ka;-V@u2N+bK?EUA2 zlakNV?*SlXYOJHKJTeYy03Zww#f`r$Hhmamcq7$%BOqEaZ!D?O90#5kSxy#t6VI|2 z*N;#u+``S~65l_Qz0*qlz!4qr^uvR%ac{`LS*tPk!|2_9p-Fsv5xR1iku#n$q1i0| zO@kc$4tfioA5%h4T!&K)K_DAvb#qYqhpL3NxOM%~-gCJme1`*WQY$-BRZ;&Af8@mj z`DUlS4-l=__1R*W?h!^rnC-?pzY~sWFeXbbSwccJb=^Ch0pMnx_z(xT?)AGaT#k}3 z_4HMWM}&d05}+L7e$(<~Mp;K{lhVP%xOU$PfzI%rKjkDnUnCJJ1wTh<83vJnWMuC=xi=9Jg5Rz8E-9^5G z;dMrvKx&Mi*mv+0@Q6wftav!>cY#y(K|84`Okm=D8w$RPmx<5w`~49XXi`oFfA0m1 z3~lf;&riXKAP+n4jnQ1yZhRcHd$;&wcS$QNfyWrf9*-X{S$RQ7 zHI&xhg{Eg&GFdD2T8_(;$d{@y60m7vq2XC*e-mLtjHLOm^D_##ctNt(d48Ym@6XTP zsg?ZF zqZ*?+I!8SE%UhHWgx+^TTyPaFp&-Gt%*bUKtbu5uvT7|$f4d$P$UN3+v~;DCY68Ny zxAIE}WZtg9+aCu=o&`yD>@7NNz3{VNS|4kjkoY+K-tS+aoiK@M-XgJV$^zqWIU!Wx z&&GVsjn~=;C64VwSqtNN=-U!_ji_80$v`Vmh?dK3z6~CUbhOh`xSR?C;TwSgn)9eh z+W#(kL>e)=^b{Balo_yF%0NZ}El+Y^OKjkU*uS!kmf9BR3>>_Zq1M*Sw=DL6QYUD_ zGR&+FNL}E<5Aa@wS>g$TH-+~Tj3U@*NvYH_(1Pu|8*|gZKb@?oDol*#nlAV1Y??o# zA%=49R-E-b9{XI%7^{;9${@oVhDSQP-~ zn$%BIj|CH29$>wEpP)(XY?@*(yJp05&hjc{!w20xI!zk95bTNw;P(UISh1JEKBRd3 zLy!j7QhLK69p3qpe3^B*4~#{@JI*%)2_1p{I?Pd(``f5DuLGWYM+6$F1s0Eq zgiO75u_EgjQ3OC7TPJp*lR8VLVR>v5iLI4k!pK=_#77dMF&ds>c`_>Gp*1AW5uT}n z(b;1KfQG(XA7>nU;k@-W$t=LMMD`XZSDOeC+0M=`^`k3=i4Qy;3ziV&!K02>qGW0a z$(4ow$X+$-@$c{@`YtS=XDkOCPJamC6LV240pxr#>RfxO4Vh_o*lbMYw0m&e$O)(W;5Xbd-J9pkAFp$=Z=BFvE0N%~9}K*g0} zB01XHFJcr{3|sn=EvgoxmS-<&JCQ&Y7`=C@~u&Gk}MArVfC z5iT27M3hT8=yzT|{m_28Et@+{8B!W-uI8hLId%R6$ilUz?@=BLFT%Bd6i6khmA`UknNlxBAmgnfdXsb)F3DAD_bmGb2B7MFs5Els1H>42q|f5Vd07@_K@!+stsL0O&t z$Ge6b&y0ty^N`r@6p!K^0QEVA zn*O4|lSo6$yqg)Act3_UIu8>FjMS*$YJ_m}Dr zNI1S@6o7nk%wsTT@P2q%hMQ*8R@0xqv|CjcO1Gg&p6V~)M<9R_VtGXdQVdlxEF z#ixKr%9|ynb#SFj;LlE1lmZACj{HJ@tP+2#$HZXUd%g1T-a{i39xY;mil0Wo$s)8| z*%Yta8&>m~U@RCJDqDt2RLH)2*su+QEJqqy;Ua%5*=+%((DaJGyNkJ009w@8ctq&l!9^v|%>bq;!hB9#oUiaT`Ngn6q*}rSk#dTS$Ne8a%K#sQt=j4`8t6|Z8o`Hty9ym@;;%gV5N+1=1Mt0;ZF&oPtF-?doZ*QocbcjNE01cm{eb#; zMcD5-OD!7Gz+PEh-4`wa*_w88^mb06MjRZK=dW*InS{bQ9pbnwG!A~+28j=qCg*G? zuWzqk-}h>9PAm$QaA`r{))op**LLt)(*mI<;(6ZF$;pLCTD-BOw>ugTvrP;ZUJZWZ zwPM4spGnqfifv>|vpuNi)bdh$hq3;JNs6|^usCNG>0aZOjZoV$-?@?1tj4;|YH`q1 z2$W^c3EA(BY97Y~#FKdpE4n_%;bptfxvRY7#@=Jyf_b6eH)NCf4_en1af3&t&&2z# z7Z;H?C|;p3=cBWv1>6o68=tZcr2GAUXAZQgsz1hWy7j}((YU5orc=T6cLg*L+RF-~ z&WOfQMg%=(9djztGQIWmqTyl*YP#8l<2x@x;yFlH&>{IOPt0!KKSa?r>OL6~`)mZA zyLu}A0X*ERf8L?HFdIc|$V4;=g^Fzha8ctnH!P#0(f?E!DC%&EVLS`S)=cR{zIPyL zI*}f`FwIae^TnA3z3tyz^OGN)es^%5b{I7OMAyQ4M%q+3>~G3YJaPAS0td6D?l+!u zA->9M&#oz;X}kGekR6L@q>4DZ49;C!g&JWwH9yK)OED_?2?~F8Uq%D9dUgbSs43Qwcc)78^??|vUeX09@4kKWZ{>sl7yqBn6&HQ{_$Sg z#=*tx-Jl)kJc;xsRG2cvdaxWF^{R|#+US6lZHO8zx4_s0*96xVXpAYL!5usA>cL!7jEVn&aN)^F1Z__uCeO( zW@)r3sNIk7s}D|BhPxO@}Cch*&N}i#_0CEpf1a+Gv1mmXpVOH}4vHNa?H0dzur}dn)17Mv*S* zMaJ%GpOuSU-DWPLy50FTfN}#ln|8o?-=15y0mMlVtT-q7++~cd$+lDi?@ZS*UE8+* zfjJo+SIPH$)4WNrpD9TIVVH6=GG@U{_Le*LTmxOyweZ zogVZ(JL1^etV{dxbZkS6kNSGLF5U4~sOf@UW);p`hdLuH! z8x-k0`F?W0PX8RG!tc+Ax(98|Y{@a|15u=pgB|7?T4;Ito! z0pBGJv)j)K(fF^U6RqZP)sMPP{iO5+yQIZ{>eF&{UcI4F_|ycMmyBY_1-=`7vA*W`%j}3282)h$R>F+ z0%y|g11Yudfj53)3xLmWwL=Rr@oWBd*Crz8uJkTbAwMYV5G6Y4t5 zu^Ch@y;rS7+N*@~_qfbs3FpuSJVu;dtru^tPUW#H-{El2oqgX|Fj8~}S9AChn_{Ip zz7nnOcy8{C7S1$s2+(RM(|YnZ6ETUp)R(~epJQ{AG)L+xCqpgG@(aod_N8l%;W+*C#Rv9(jSOLa80a{aIcyqA}{P=eivCHMPpXHUhs@SK8jLKtf` zKDl$4+X19n@vB+ z{*W_K{ki0muN3oJgORWAf0cgLr^)5OB%*68hzV{h`Bh=^@2N|9vtp9h;$9rA_4HGZ zH$1SPZ(Y>*)D4httI^aWmUeTmeUO!_vf5Qsa{B4m0yhI=&dfq5V{a}OUt%@bnMFag zUir4GI0#j|%uhUKM40*_9+S-*#ZiDeqMxD9=j#Mf8WOo6y&-sFHZZB2a1TqFyxr34 zG;ew_U!?e5!<`=@={BYFcgsJFSolt5x)R6tpC@G54GNt7cB|Q%%h%qqER59rdjd-s zF^86m2hJv(p;5;-*_#3&Lfv*x-8`s)+```Lu4OqxJ&}F^lx82mKYVLwcWx|;%Uq^Q zfvI_)%Rpk5SYQ<{O zOfE?|F=xx+@q{IkvJoD=(S9nE>HMT7G&W6F1PiUiTz3#;|DG~UwWXY&Pl0$>bQ5kk*V+V7=BO5!VY&17bSou1)#f1bXg1Qw~gq_ zw5pKLuaG7b4ZEq7D>7K4ZF-?t;A$JH2;|#PFTq85VKOd)6C43;^VC(0CC3d)X?cdF zC9haerM-KF>=22REVQ$Pm;yzX9;5l6!|Hj~;fltRZ@!v zkCRh`6B0>g^_(qGxZ~0=L-xH%i1A$O5%=8Ed+f@T)@(+uqwn7@t>zm%=$E_fUstW`uZXC=TL!*49Brfhr@jVMUTY*|X^Ae^tofa6T9#=G~~1-W1Pp8FJE zTzg~47R|XD?^lO5SF9UiC?UdmE(_+b?Eznw+-6{mwvKnww+>`ra zl2K@VB+R3X$qQlCE?ltizAHXkJ&lnZA1-8+bRCN_WnWegoUdtp#{N4^h#6Z4jLg0k zyctm^T?krK=4k8S

#f-E8#c`a(+Zyk(HJ+r`Ae^afjGeT*@vE`~tj$FW2z3!c!H zpreqFsIIfq+x9byZKBz(laV!$ia`&yJ@ZOiNtjL1M2Mg z@io`r&=lX!^|xf#`vx(4goMEQsEF%2wO9;baaFwC^upkq$N&Mw@n z`OteFv{;+qo$k(7Ye15uw8q)TgoO}QfGMLE(0%7wd3gAWS{~53&e_YA2>C>a|2EU3 z>pG*hff@YRVUCL14+rGpE%7R0#)n*ybnjlVd9b89MQgjxJI~9}d%dl+x;bBl-X_|o z?$=$6P$!SQ=jI$ow_Ikesqzfp+DF0V+CoH`!bcy#vh(}w1%RF|&)eh|RvqHI-?DhO zqRx3Zwe3#tGGM=0KO-Hyby1-LMX!%Xjn|{;&@l-(W=(E68kJ$4`dy(CW7!lxC zm)jKI*E=);Ep6ef+bJ`?jOm#Nn2fnw`_!#hh#sbgI2ZtW(`~wH*0$**s8Av5HaE0l zoDBVw91cMKi>jQQa5sEZRbu|uKy`B_fx1uyfCbn_Fnk&?#>@kLDn%5OR%GHO>Ub*8>6ptWEvrROPW4orOlCKy#-J74iJ}LI$wB`c@4YYtT{4y4=H(|TDsqwhZ z2X%v>u=pCU3+~2MmsB&XzYG5b=(wrqW-JN-^miAOH{9wC^hVuBm+6j=fK#d^Y8Mc# zy0zryBLVYDZMyewHsQxUbijCy*!FN4vgT+t3T+I33*vk58monGP_+CQ6+o`LaqDeB z)oD#LiOE6fKF$OsOqnEGE24tldcf;@O?0XSUJHf_9@vzb|Nht0E@#ndTns=G)cix+u_5#GJH>fwSo@X<0 z{G{|}s2}7g?^_Dc>jEf{Ep6*fGp^M?>qPx0X%)aLO zbhd8RrjGN(Q~rf`BiE`Qg0zPQAG4m?y$fs-JpxU8DudbZ(kdDF#a_G#tqdV{t2+uk zXUAY9mwgGse9I5$_&$^@Og*ie6l34ky&$fv`-Cmoem?RzY`iPeD$rRw(>TWMn*jmx z2$h4p@U$5>esn_3;t!^&4f=UvX%$*#~W+|KOObQe$0k0X3L>bRrA zoY$>JJdGjcS}hGEnTe(syVVOCasg&=2U?(X~ySY zEgjrhX{LSozyMP7-%fgfX>6<0C8Xl-vSlnHIw-a4e>%3~&Nh2I7T~lwlKs-?t$d{$ z@Lm@#Ea~+iN94INW&#iF6C&&p7Sl8$2g0_9di-aV~Vai zRKAjVh0zziWEYh!H^3M*&rMy^Zg?I?W>;rwre@HUR2o>q#{lYm;dfu1K35LVs6NWl zplxFh0YhfAEDJRht1;=^zFFz9R(wXRuBZDT*5mCw@x`9C$CS=F^j@4PiTsIBa}X!z z_0pl7s0I}#M83k6rQIeLrnB6NX@1eD1*IC4@yC;W-asEV`+c3rKlSRBnEofu9+9WlCd{B3G`Xa0wj5qQ#@@`!*U$fE(+9h9?d2`xSsJdx{Ri_D zCY@j$drFMMiHEt}AWvd}_X!hE5KjUxBkPErHeDmnAR%z?3#@2L@(h^oXU$%4c!9p! zkOLI$bB4huUJQ3`E$3oj;T;jg8;Jxs$$9Ez*yG`+=@=lU?R!MWKlQVQNDsSN(qU<0 z9<{)lJV$*dn+D>1B~iuL?jAt|q5j?jXsV|eN%n)7{J(hmA#J$c+Jm#O1$1bM2_|}p zfORilhNB|b1FqfS_XPt3(%}0@Iw9-N%$T>PRl!bFT6InEK7Z{@W+5mm%&R7$8S(tE7Qp5 zO^EXj3o#_CCIZuJNb&UP8x~BFC~>Hp+zY&9=>FE48c|WEpuThrkmSKHM-q{`_WR@& zIcm}mcm)ZipOL-A`oLE}oKAsU*{?Vnjer*SPO;z_F)A-t99zE48({TN)V% z(K>p3i_1^R7Loq}=2Nf%Z8Q2fC3k>5{F|LlTv;n7PASBoRlqC+K7Ws)^*uIUu(iWo z_~Rk=fI8)w3-eBvkMR?lVPfzc{Q{@mnen>kckg~yAhn}kq5)%Ah25oh#-p8hWSD|4 zt0h2DKwout^f%oAPf#cY7dXtH67be92-+{nNHE-yMc<3Q8uXqE;kiSZ&g*udzhCqY z_c&!}+koo_q{Nj8Kg@$qGT{U|;e?(MR;r5ooa<9NWozO&69TYZ&?Y*4M)WY18Zl+l z>!0%yM0vG8BxNQ#YbQRF6uve4+)(n=^1$U8;VJqu4z$drj}SEyV*2e*$_I$!DH2!g ztA@)VlARCPQ}h9KJB2e$ccz^z3wKcRcVIgx{7S|>V~%Gc1SVjga6dv0HsUDnsXuf$ zaE!JQ%s!>XG)bY*IA(iWqX$qS`8P*q{U0L=YSuE4# zD*oD26tBcKgsIZCFRc`m4?J~j>U}Mk$aI&XbA^vTg-CBqp_J%{tmW5!m`#4Q)#JCU zq+x_luDi+G(bQ}b0!WD|UZqLRD~h*0A>~y_yVFS8J`QZ2`yPpSOKEO7eGV$$7SYvh zM~~jDGoQqDKKeow>!$UHsGHk-HG(%lXObEEEdI?16hq)pcvBgyHmTl787jZ5JpsPI zvAI%b2*_NyZ@H*o>lJX+Eg99G7zxFvpRfOgZd@KaE}glKtImErl1*6_`-^6v9~V!# z-KT*c+(`7@g(!dVz4g5eh?e93F{aF|J69p^WRiD(5`!i?z-Gr+_4*k6T58MsdwRP8 zRi1=7{?L8t67!`{3^6Qa4Cx!yr14U!l(rfjMyK-pc(;U0m!-f{PFAD}L=(QGVTB092WQ3gQpNp@tdZm#r=vVh1sR;j?3s9X6w*mQdD{c z=Z%E9c70Qz(LYT2*J*v6@Sv$8>s>FD#EMjqoBv-16cpSIUeyYtS}unKS>zBvPg=^JO^^b&}4q4BqGY7$M7x^K1G{k)wt z;(fx)VcrYPzUWGmJ)wY(zXq_v*8=C*->!*3#y%e*vbQ0Au@ZAWG}k5aPZbZM@Hea( z7{Ppyp?TK@+Wo^Y3f|Vx0;XFm({;u?H`aPt3oDJ^B*6ef2oPe&T1)2@HvZn)0}w*f zX&0HL!(Q(F;^#o|iZUU+!ENt9qGlX?<}og1L&2CV2~T`f>-qshvn0b~sn9^snBAlI?; zZMrQP@opmj7Um-RUPLDdG>Ob_2dKM%Jfji!bele{Hw)+gE2;qT%PvBw{PMM{ZEOJ7 z)oGKouGfhMw^k02lau)YRVH|Cx}U^z%whmGLjb1gzQsh1XJPb%kmMBr;Z(1J>NW{%*`uXTfI))Q8W0Wx8Pgf5UkOw}2yc#v*vPi=!o)l|DoD)(xYH}= zTgc`Nn5&(2z30FH%>%94BGYvz zetRn|-Q6kD-QCiNG*Z$n(k-=+mToCoDj*$_($Xa@ozmU#&Gq`e|GmGneO>!(d!_w%ro(o$y8{sO=s5u3m(|+`AkH_5TyGU9 zZ-(>E7I*-1)s=k-sNjyuRH*kqflL}=0ol1EA$N&C}5H15~ z1w>UVK@!kvXc2>}fy8;Wz>M(AbJ2hE0w(qaNGB{b`})@P6r~vSU3_5}g=qXENq@J^ z7IuFFigKqW5rUjZ$~FRBqfrhL?C-B>xi3JHqteuzH}s~$X-@279`B%!;0((A-|tra zQnFA9YFSV&z2_WwlS!l$jb^ceO<0Yo59EO+6abajnfE&x)UD+x#K{ZqUAZlY6@Ipm zjN+8Rn$dhZrhL=YxCjK~OYFLh4Et;QaGD%q#G}qadaz2JXU-=-^8Jgmfq;PJF2D=@ z0Hl-6umNy7p3S$8l>0U#(9c?R`BP*JstXl6?xnk*2e$W~yLFDhNY6%~Kj-oOK*q~9 z0%3swSG&o;sHrz!5xal0wOp?3e=g2>?^%OdnjN0}aT7*hITwqd6*=V`A8!J3Xm{hA zV9|P*_A#Rz)dpmhtyqxSA*^b9@5gNLUDpEea26P{Ej2%B_nxfz_emPMu0%3@Pu4MD zh9O3-12~tbK##!0&How{*KCE(e2Dm5CdLb6^DA}2BsB$jP)iS014l+L6 z3-i^$iC8=$y$3e1L-R-_xfR4B9CZlmdDWyIDbQ~wr7hmz4y}`XFg50RhBpmv)89^w zdmG|l&1^wuP5t=^PXqR9rdEtgHr0&M1Rtsbd{xF(wgc!Qhi&IBFx7_Y3_ z`^Ro^4Jlzw+Z${-u4yia|QY-oOOtpe@Kxg@m!+ zkbZUIKv-JADlZ&O_>5(NBu~UgZ;>`S#U#Mn6GWiD|0AEL4D!#F@VXN0xQ}^xE(Ig| z5c#Fp&)9!!_G?=9ma_OQPv)ro{S|sX_2*?Qb@Y@XGq^8OAxO!8FsTo~y~eA(AvA;E zfifGS5z^E`gn-g|#AT3gz&mF2sLt&U6aV!hG7;>REV;DRxKsZhfHK@7X1-%Ey3i(o; zRJWW0!aSWdpI=_UYiQ{Bx#%2Jz#gb<6PHj;y>V3XX5D&uoohv4Z&wpL(+*q!b(Kji zMg0_DsVPWgu7aC=w~kL3QNj=W=oZg-!WA!cG8)IqBzfCC-V*s&RI{}~=^|4=pz?Bi z(oHa%zs}Kg_)dTpBf91JRkeE_}86zWcZE)l;CB6ggn|pz9w6Y<& zJjHEF+>~6-`==J*Q?~W8k#pf$1lfD#2RDiqn%aGa3lv{u8^2{=?8*V|ey$8dYJj-#~$_8+ZTM$kU1S)O<_W*d8wn%uwbMJR&9Ka z*Wv51OWS^=U)YQ~WL)O5+kwaZNMsHGW(1!3?5frBt6ZyBGG4mJ(kpKokk^H;k3adh;|5CbX0saF?KAYz|R zHVyb|2Yg1Lg${-W)4-0ce4z#>kaL;Esg0W%6Q2}bt#PqCGrk8{0IQ9`N!SVCK^l{bA4bWrayle(aJo4%+s$|Rv65OS7%S#XG>mGtaL0`I6gU&dI6^uJTn`%;@7ODlMF{QM9>AlY$i#0n)#4AvG4eqh zz1%MW{Xixk!vcv=9NYEjQ2M>?4rbIX>|pLu6mlGh{j3_Se&H+;VdgLk4z7OF(G?bK?4d9nb(!`5g)bL$1z>|PoKWo;G+L}7iYDPKL;w526p=-H2v>S|QY z5*!VjSAjm3$CH0Hj2*Ca8PoqnUhDwpyV;Szu4a{I8_Ifv>o-JnIC~s*A9cm|b*$1D zG-S2aV`RP4{e@nP?40}ocW1h-zm1l>ULC_7$w-pBs%+8rG#)>Ok47xBn69b{mH!}u zLBMwu^;mXQ3D+ByZ^?&o$s6m&C1P8NQc=0M@Z@WeeVTf&+vG9XccY>rT?27dx;-1C0+BUFvI`;luPj2W=9Q{I8e!WaKYI_7#H z+8qw#S%pU9R(@1d{gY-EMYldK??%EQu?r(-7gE3)L9%rKvzJ@PkCnErd#`voJ1sh8 z#*VFL!4jf2(bwMyAU>ERlkQ0VwW)Mw3gBiUnWH%Y8Tl}9wc2@I4Q604QA>he@$CkGR0D%^m}hzdjVjTkAQ{bz|2LEJZUItwMR3m(i!Qng%cD- zfz)8^kNT4Fc%K{3zfp1~W{eIjEDfo#HKdD$ItxoDHU8Xs@p&qJNXOm_-tsADDfOg)T z?-|Yx4df6KDIGikdy5>@Rc#AvSdVapjyY#r2)(B$P3r#kWcUUPrw8|PDM3OyMC?}M z#H^_23Fmvk2rN>kPFvd_T-De;NX438H98b45%;zqzkd=&i1gGOsr~X>lA6+{uCVwJ zlP!{*fltx;IPX~5i|V%mE_Lnoh1R$sZZN*r)W?g?UfPNF&CduubeOi@J@uCJm}0om zF?pV}^vZFho1=92998X?45UIy$fy%d+e8k8C zgS_KOvf3FM1;KEdDwO5*QDFvI9^l<NvnNFMBo>iari!NM1j2b| zUgysMS|lvOotPAU6oG7kl6zTizS@z<8xW5gqhlQ{Db5(A`I>-@%~gqNwt9!*39%7| zJ`xR5fzXbM(a}wHn1+mLxDyL8Dlz6Vm+3(|p)=U+sBoiM;o;w%D!#X#54OSJ1(%9B zr;2#@6g@4tXK{Lo@A5EVam*;op1|%GN*Ey(7@&f++NveYkZrPkDVSSGf^WN>oT5Ii z*r+x-_WR>mdUdC2TKef$dIxlaBpS4Jy^$}#k}bK2rX(He`o&EjrO_csChFy~9q4o3 zk;7-yE+0d>j%Zl)wt$bSPUr-e6Hw3K1Z=akC$B}=a)AymYSGN6)Hzjio9=OUd8tRt z00=KWoL@EQoDUt_9J3=|6B@tOeDGsLc=m+vxD6bLcLV8KymL5nEn%B8veII|-CNV#3sml=TFF2HHkdA5O`S1@b=~z5eKAGrU z=x@4@O@k~XBVKb&E1}Js1jV^K9Kv0_k9#&{s$!z`&A=X&Z-o*b^?$#k>OHt95u`(C z*_y|WZAopXn6uQ3!<-n10AqVEQ{=DU@jQEz@7GzDag=R6^$No zd53LuR)S1}@VLz@tI(g=r_*q3?FmS}c1w4?{%5OXowzjq>Cf}uP1Mu=R0-g1Li9l{ z_PH?5Ly#0jw+U#gs>W2rF*dm>^r(*dEYsNgF(pgT-M`X-H+XO@nlHsliVj1#@c(S`^svqly&d6Tneb_UJeCf$rY z-BT$J&%a6p%Quh2+UWe7Kcp|Bp`w(Sr}@`2jaL3dez)+bEb>SA98xeP zCKC0y&lNbXr{>UvpEL-Rnvg5V4Nnu~guJJ?ppSN}rE9vh8NpR9Qdu7c<`M_%0r=r? zGlg3&am3&rbbX7wW54b*!iP7r~`Ia zGx3Mp6sRg>4;~#1y(XzQHHKjt^;W&pG!QLPE|-m6(b|&{;Db+PB|U&{M&^M&R$Pu3c3WANsrL=cqNr+Sc4Ap zkM3srCwzZU?0?6BJy=FdJkJ_Sv-4rinkRl7nk11}MkRr~dD6m&n_d`hy(zXO_k%6v zB4+2u<&7o=BNEqR#aES2M4u9!R%+yOBSkK_;F*xxz>H?0lg<>C<6t=m5gYlt z0%e)%)y9?83sO~O@uqT-7T}V;S}FV+-_{~MUVdU-gKPfgT|$QCuB=Y|D~72YJ6M~j zMsgu8%z!~VuudGs9`E4&!3JV5q_^hm)TWJl_#H3yn!a^V_J{wq{a3Ik_=dm2cs5pO zDn`GT&U|;b1bl$a&X%S8WCl9_cDqDvoVV5NJ#Mo?z3i?;KQf54Uq5~r zI67}{;gZ<-TTA8NEPL$O-zZi!0j?c*to;vdKEL!|Oi97N5~O3;KY_`NtfujiPtUBH zaXvvga8)YE%doVy)4J1Lv5rW2YT9QdR9+Z4HrGssex6K!(=c|;E4Knl%JUZ!bF)UJ zN;qTIZ`vl#RK@{zjf%&(k&Pi9Sw-EsZ34!^W*o^rlq4{?OXK{gE9y)oQwR4)a|sksrHo?X;Ku zkBNcWPX_kI>IUAvz#j<%$@e3*R83;PP&Vv+5lt*Q3{$SBy3EC%5w`7t!YHcdP!FFt zcvx5o7A)Q&gDDLh?Djj86+!G#Iwt|k!jAJHXLSHI`)byT^D@`{hn{cbSyCE;DbTo! z_-ZP#*{=s3TwqSlx1A3-pWM;yc`7IA%7?T{rDM(zV(f-BSqhP(NE3C;W3Vls->@v8rHz2s%Lk3lEZL0^7rZLjyMe&_OgGW%c{9`&2I zybt_NRM(M=P^t!=`7!lhS`pI$ZwVt%GID`9-h$XrDg~_wvh}4_&+DeGD8&dTLETwm7<0qpWa^!k7i3}r{^~%i9h?UP2cp- zTRc0~x4FEIb+8X&1)&19DT1vt6Vc~ONB!q>^0PMStr8-uLrPZEft4jm^6)EEGm7^L zu?oolIBkDO_?c==Y`pSnL2K-mNvT2Vt)Ai{y(@8Nv?~#$}-vw)@1miJ} zHS!%leppLXpAUKr-)Eqgm!S~?gr8>iyzry>Dr@yct?z)Hebed!P|sfQ@6N(ucDPoI zkoXis@$OUnN79aYVT8v>n41>FOIB&!KylbKj1-E^5j3!e?ZQ37!8n{CsB^Uty`Ew? zL?%|fF^6co7>va!PIoN=>EzbUwsEKUb zMvUxtqbG+UD|ue{WA&^wsbP`PRXL$j1*og)$LNTw>r|5fS0F#zjrt=0T1j}Lbk9I_ zsJ13_40pA7{5%V}y*dC$a{i*gqAq?feENxov{WGZf;#r+RN)>#{HA9NyQVYb+??%f zuCfPUF2wo$topED$h9LvW7NyzKu1C4yIY~ek=hPkW*cOJW=!Uz8{tLhIFp`=R=%1CJp_Z4p;KWXvXoiU^nZWT`Q+UqHM>lz;s0-8sdkJODEQXV zio2lXrcL78Ew|_U?E-hSoPfu!o-+zH_4Y3_sS%i6T%thgUs6Yobnsvvx86f|JN`6GP!b(th=#bE4QxUe?E5g%1+ zyKxxY(Y!6CyT=wWWt*!1U?!+T+wb3A-|ixxMFJ2xNMiCf4A-FU!^IYDqzD8t>J*<` z&hEjWY;dAgf*z4u5z}&F2M{MQF8x3sSMlz>pgab$#r_rWy)|3Q6R84yGB!ojr@x9;>wGnQSW$CE*}3oq`LOv zQKyjD7o%^=sq962lEPX#Px~jwyJxjg9)LT|JLv*(48!bo6CljL5-e<>{Up_Nl9ObO zvKq2k)$}0=T;vTsQi^GHWBgD4Ti1{s>U9j)W(aS&9z1qgtdexhkr{6qjbP$O*NE;%ZfK>*f0ls9 zdAM>kRDh= zXp_L;Qi*KrDGM-irNXZ!`bn!3PUWW}RrFQq&yT*4T4?`OZg8NIp@B9I?#`84%c}}f z+jTZVJDU1vnjC7C5RG^mucyUF=YqL794f4`2O=xnouQ-{lEep{6k?2!bZ||?UP5?= z3b;ZyInBbo((S%{_Op;-8zCc{Bm>?^W~@$Wwzr>E@$A~BIegZ}j=eK9WS)-M+vIJoboY-wOaSp@~7QdEP0F z(E*=YI~~-OCLc%)U5!n!62tvV}PHZLpcy+(5VedA9s}KxG++S9P_6F#35on zr!FwOCLH*cN5pH z&>QY<5?iO*f<`*VhvqIpu{J6P=d8FCr%T)x*hTq1=V1=T^^&$q)GhdY-TS(A{hbiC z_3LsQO;9}@!n+rdE(Pq}BpLZbFn}ToGB59hs< zj^S-%e(_0LZ#dHrc~6e?vtjqqR(}ct^BZ;smNNfJV+F530z>E(yxpM@HQ`4+=@@M# zCQ@=W=wo-)zFgnO_^5n2cqRkX@d`1d$yaKv`T@CqUO1~`k->{4poOnZtP*<_z(MP|~?0vK6c?DW7MWw)^m7ye#m0kdcew9}z^#0oh8>Cz|ex&>{utJzq6( zN5xj0Eb_4zTZvtnljW`I?0MZ1_6yJzgb&A?7c{+yH;nG6oAzLg4#_5JL@^iuU6L}5AB4l*R^(q4NMH?7E^h0o<%ZF_h|h2^2Y{w`t^0SQz!--ctl^M75|y?{S>Z#s zeIw*M(XGSbvlm276;=|_D)OyNA)TvxjXt~#Y!(KcP^3g;EA0jK4Lm_IkbrI7iJ z_^D_9A}Vc&zyo^FQdF7XN-X@opHfU`a8F)gEKbd-ZoWFYzY{THTrlm**f6na$2X=v zyem3OR3@^~h>rK;!ygIIzes*(Z4dIue?YT*s*K-RG`v!XW4t`Aq$cF9ZpX1M$Vhj> zg@W$964~cU<$|R_B$2syH#tOb?1Ob+6hZA> z5XjbE7}1TAri`bwiQ96>e!(jtr{Yq)!A{RpHF_IuzalcVgn)2U=&zVws7@2&HlkCQ z_(sghE8tv-m+8q6)sc$v8^2KEQI}U^CB@_-TQ~_~p(>jM&miOoh*GI!@3k7)*n3D<931`vpOhH1P86;x&}ji^66- zXLQPpY}t(NjjPP1C9v~(n`$s`617t}&nk!yJ<{tsW=f_{a0%K|gj?C%$&p8U4+Ybd zXP)sDi3fbXIG7&W)6w6GlGXmHdZv**t>vhbP5puR6-Nq7yPn#JXMBru*)Wr4Cx~n; z$dj{(IA>z#1K;1+3+B9Yf;mghECO86uLD>1Xk|jrQDiF5E%wL>HF=%AZ zB&FHJaP6M_XAjgA1>XxeEJ6QS0Abvq|HCgx#$y% z(3^Yeq3i}m6cuMEHhyn2G8!OCu`=K6)1sIyerB4#b#u@vVPr%o3L?55PW*u@`+Zt! zt*YxNA-ygNPu8K{+KUhNp9_C7Hmk4WYzP8pUOi+q=SI z{FCbW0eI$X>PTaxNj4`*?}3a`zaP8%4QCfZM=noZO-SU=126|_{Hrd?B{L{;?Iv(%LsX|9|3>_^agsfL=8E4D%t3G8b&JU_~X>3MN zc%)IBXW0sq@1`m>!b+q8Ze%X;o=)c#S8srSU1FL zJJy*}9BVraN|T>zl7l9*nLpRkPt$Fm)ax)ptjt|Z^DoRf0ZCLOPiRlX|N5qNqQw7PN-i)d#=IVCvxJ@v-sAJIeOpO!hAU@Ls0s-j< ziA?JJz*SQKK5*YAt#06g>UaxEcGO1-r3N(v905mY-zGM!g&kP(>qRAA6swh%lNUF8 z9xNm*>iwb1^_~RB=*&oHGdQp6w7sTt*og-&EeW0rqn1|HdmbdEP0gneQ$}=8QDD8W zx;$J?KLGvNS7E-N9Or6Dj!;BzQ26fKL8X+f?+J>^>GPu4r4P#NT(H?m^7w@BCGt)| zDLOD)W52fvJWbti|4jV61(ubcB}CGGf#603ut$KS`YDaEJO(<*ZtYK)^sFP5w7fG1 zGRNUD1=|KP`1)Idd$v@d8cC;WJhz6(5fN$h+_DzomYiDNiE`ANyPLRAnKBjW& z1PJxhmW6wdZNN7igQ{Qsk2cRtHadh$-RL;LXe-(78Cgrnxy+dAny%d7QA4SAbt44=;2aHb+ z1+vvt?x6+BVt5R}pmRUhQo8B0IgoCVx{SV3oeSb|8z7HVz4;-OW8#(X9^agJ^;~Bp zo@3^6Ii>enf`U5c5lE48=NS zx(RH~!gsiL%Q<^s2A+PcL%JBaf2Mzk9=5^P8fExW^t1qLBEk8vhwMvi7ff0iBM@vl z$f?t~0Zzq13eS171DVhc5U9!4SNL7)FvEQ^zYb6P-WRe(aRZuc&WGu%cwG5v5W*PX zFqBWet(Di)jH@PrduIc)$Z?NOIJBxl&|1a=B+171mw7gFkq?c^DK`C1M-}F*})AK@OXVwRf8&svw?) zwK))Q=LnfNiN5ss^-|Z{&?@4Z;m_trwdZGAvM8F(34a&WqHdmiD;Bww1E|^i{5;y* zg7FSQ$#KXL+CWyyDO-r#+Y9JnB{FJX(5NL{Ql4%W6D=z)v(h*JuxwRhZ3Z93WI}lT zUBqUESqIYG1%gYyivxvV3CQFQ?^$;uQ)d}H(_qg-67&`GJ+IC+@m?p`K{?jR{;89V za`s{eDj|y;&yNI=kzivdvyEMyBIr4xvkUk`x3@#MlMi)q5hcqJN)%3BP`kq8Vx#HqCV^<`kw0bI`FnHoIXmx4F9?l{B(6{TPC$j=J{ zk#>n5uR!c`9j0(RB{pbF!CaqcBBUl8$@qGk2<0>Q*n?Seu1M1`-V5Ob_Ru=4VV+_0 z-{0LGO=#QnH)l9xp<-Z|T{^zx&|vOX#uhd$vq_HE$`clTiU5C?Sn}M{RvAp8PWBrR zC3f6lcd!>v6z;uKxw~x65(gaEOpX6;rfnB5p;z>GbZ23t*v2rF>NCOewoGku1>^*hh12jm zNiRc{*%##Z0j}CvOOUxhFUppaKWNyJkCv*JHI~WgM#3@3tZtShN%O+v%}n9RnLAN1 z={4EU!>W+M87vper3Izj2q&DkM~P*^k4b>cOzdjiRwQ2tn`y!ZIh1$ZWj7c~h3RLI zrLp=wlA8M1hK@Y&j|+$^)`|mWz;oZ0Ag=;durn@nLd>?BdTP{bcOZ>aZV5WjD{LAD zVT1rOY`M2L($(LI@ND({V=2Q{N0HoAhjgBMgc05#iay)W4$UhZNjsoc> zfi+bR!ewTh20XcSEe%E@?^CVy+bzv3Z0geYTazFMZqbVOq>>z5D>8EPC=mjr4i z7YOMFPv1w531W@lr*bHFC5mM3351>d;2pdko~p6tm);aJyy-Mnn7>Plk`5*H_st41 zVa=1DyW&7?6B{nv`1MtH`27n3Q@N)Tijf$|f-QJ^lA!jv zOB{Ru2r)naay}ZHH=d{r)s%qf(|*OA;!l#gJbKesq(g{$Az2$NgY5}slwuO0(X=4{ zQ{k{Ze!_?6+Ue&9sv3WC_^fsf>Seuz4LCu2bgN*xB@r3F9+KFdOhngM*ZKR76UEi0 zu?GkW#?spjmI)UZ?*bJc!p~ZTAuIDjl}{co-DaO4wwxrz81)=|%l1v<6@Hqmu`2Gu z?4<@B^^9YbrX;~i_0Wapu1Y1Z@N@zae`Sv3D)*q&^PYf( z_JR}^d&*@98Glz$i@YRsqfsvjMcAqudj4ZO!>8)VJ|@C%i(c z6y_GwGLjPnzBuV_%mk8@3vTUM#pnM#^=o_b@~H6UPCRmh1+m3WIohxCzTt&%Q1iO< zDh9533G(gsQ_*l>B00Ed!d?HYucp0UA$Bb*Oya^9a-MVLZXnEhO-_$M24A&CyDwPy zbosKvxeTK?>z+n1N48Rskok*X6(Cp$fM;TJ>m2IR;mw(>x7OrV-MewsM!Hy%nt0(g zQpL>G7Sls~T1VM;E*hBv&Q5d0n!_FwY$5*iXPRy&(9zr{)~V-tCU|phi=6eSQ+?P= zg0uap9CdREn99alQ|!;vF_7xoW*7(KeEKHEofPj5g;(}_1R=C%UY^hdYUIxeqq z{+#+3u-OnTc{K?x2^OY;7!p?i8Fitcz;&=Dvfu*>1nm0TZvt9{$4+eo!ksspy!0g- z;Z`6XlBSK~*0*x#+#hI}9b^^e8}NSQ@B86&yD91iYAgK-Jzw=MXr5o9%CaVx&Ga6! zWg+*M$CB-R;}5|T$D2{89(#4$&B+{&`@bpk z{!f2`AiyCgA^L*;NNHHV96msP{uf7knk8|&jI{w$83N8tN8xK@@Z{wH_vF9XwJ{KUICzagE3Tzah81gfCz4vH=h&E2~M%Jg?0N zHQg9^rN1dU+56W~Uzjse0Opji9h#AE`}e!FF(tlyvN3R?pD=gPN>#X0Zg$?34tsjn51HtomuUEI{`9o0Y*PIj(#x-3T63=dL!(cU8Jbbj z_doxt2u*HPg8uw6|L-UL9#qa(hDV{ZU#aBCUD8=&To3-DRac~_ibsx8lT$~-yCiY= z^nZMU{PXT)T{UG(Z%e&!_@40T2Q&Un2WlG8PxLL)PrQEV^l!GXOHR7<7QCv?`v2o! z(x(FzYdjaK@@#D$JZGyFC^e|&R?Xz)%bxY*9*@m*dgXsvqj+WHvDdycz%H_H4#shs zW$-$gpHo%0He9dR)2=W0-0t;Oj&}5qn`7?dv6n8iAa#RTHCM5}yY04nY*1sD9zMrkJtr_%mR{pnyU<;h$+cbG z>#aSxk@Y5aru4+=llS;Wt(qafv#mTjg&F1dlV!yj^Nha|j;!nFSn0hlRp0o1FJ|Ye z9UDSyf0ZQL&X-4Sk9-di`uGr>P}%a^cjiwtmfxVzl-#5UnUGh~Zz?cqhKD06>1c1| z1))`+$6`Z-(DtEi0{2VXEmO`VMnvdqLHFh!_Vg|j&425a$e-0+cn?I;fs~DrW-l(mp4+yL#NbtjiP^yGh$2G^Wxg znvHJ`mqkd&Yb}B-3B8d0CzMM|5qLeAdv6#(yom!?bAmp$vf7;|xV;)gu5Hr#^qHgD6zagr~3aq}h078EkWsj9ZqzfQwIgJL=;$(t{1LyvX;1?@LL^k;SFY|&QmZG85|g2aO&nX%m=*kTo19DyPnGk#~_^@Hq##f z!w)^}=6+JfRV%d)taYgIB4dzSNhm{;N1O~>g!r&zLc?qWI2^sMa^aj(2soK2d@H@r z@7IzPqwlSDu@Y8NMlWIlUg@&c&z8wlH@KrfyEaWoXX5be0Q0S8ruIiI4xMzWG8AX| z>x<&pn6<8$7O#n|g1wsI%)1cOgcftXgZ<_~H40B|XE9Ck<-n3Fse=I8#GkLZ z(^VMz&8V7g%{o)trGM!B4kh(CcXe~1@4wnNoSL0QWt4YE?>G14FtC-&ZXGD%rM+!G zPUD#P6erP@!eBX8%9JrxxqY5KO2;r!8`NBX&p@VRq3E4&s8&urge|OlyVTdq@7fLd zz&lMTc3!@?eb5zuCi{88>r{2TP!q3FJyz*EU49hgRei3x?1WKk{fk%$hRPulc>ikK zU)@>4w&4VymanB9XKvSZs26-Y{1e=}ctc4ggkf(Sy#LDAH`|{s=vuUGasv)Us%+1q zaC%yWr)P_Hb`|5$BMuPehW0#$NNGge+oM%x3wQ(y1Lh&IEgCY9R{AFwKGp8+bXT4* z<~sX$EQq~$C0#0Mf#M_Yaq76Tj7PWb*SPzx-_ded%-_k1MB2W0L1r(AO15+Cbj}=d zpJDi`+J8J&>~T^ zd3!_0nq-P!u4f-=5*+>V!nqX4ZgPds>2Lh&)P4`le?H;fVVFSWWqRvJ=R=Tk64TJS z(m9%uIW-$u)VN#ymBNOOIXi9(|3=8OyTOB!tJZyIzy4aSu`KZ5-fAMaVBofjP`0+` z8PGcoAncRHBnFEl?Z?njg_*}MiFq0Dy?oE-d9;dEke5=;CX_m9^7-cjnM=MusR0Eh z`^go+xpCP~mK;s$#7f+4tHW}{pMZ9}0nl#!tT1m0ckUH(KqrnuS~`z)1}t543S!{V zlwz~DyVep_J5=6lI8`9qlm;9}gD~=u70}o=V5)DG^)NpSASJZ*F+>IE%;sTjx+eaX z_vdx3VNru1o$UzXkAiN%Sd2PKy6pa7XFn5qNV2z zun8c8G!f(E0BMGWkzxFD0V`LDf{*Ps>FQ< zECcKDCkxCz7j(;pjhb@ofLR%DrvmSEtqjjaT$UtHZcj9k|4A1Mf$aL=f32Iq3mAR! zq~GM8o7L`Uhd`>c#sm-^)6X6*0w1h_O$pXL`ZmBl4N!Ngz?{g_eei~P3(SWO&FIaH z);NK~YLRqH3eo6bm++4~Q!viuvOYDTljCBIYdGzxiWL#5WXHEt9DxD zGgP|iX8|-_zq|1G>?6546A3iO$s{uyJ@=bihWjkjG1DG1;~!gCH2RX zz2CL;-Er+6?iL>$!Ohq@Z~=NOi?^GB_r<#T$A?(0K*`^jbAGrBdG8i`vY966ntugS z-h0;MXjx>rV4eI%~G?yJ& zF(p&kjdxq#1oN~6-1*#G0mZq>*}+=|z3K6WV5|{l9@Z2esHtyKrh`KwS7nSthg8U$ zM)!fQw_XrFb{NbC+0AqyxAFo!w7o^JDrV8aph{HUd^B0)hEKpIksfe&t&g1Y9qdJ) z!5nyH2N4{^(_ta9nb|l;7w#)@vv!1&i5KcK>l4hQn6*M+^Wece2a#v1))$mq(W?<& zwCz8yXx^xUF@cRaH)f0e7d4hadyrXjm$t_`+E+^mmAQZfk+FEU@9A*^{9+QgmH_yM zNnYm{Mv6neFO^@TK6(5OtWqFp{3BI!!?f`gpJ$+uTWeEtAL zwyh8mawAPws&5j~9UMKuI-4dUoWGDQmX9S*KcR%If{#DMKh}E`&h4y}z)x!)^oy}`yb2y%{O8Bb{ejpak-D=%1`&NX-R zeEvc70L3rhCi0W`KMl9pMSMU23JcOu#(Xt$gEgGvr4zQU67T=> zGaB7G*LB0_MTyR!fkzuopfP`*$8o*wIk8F_1*Q>go(`OdHEz@ttcuIdJg}B|U(*ytmlkwrSAAi-3&RgHh4j{2@l`37_dA zXt@^O4e;RqO>Rt&`E%Fxj=Qm;{hZS|fwH|@?s);xh}QeF zZ#?T`Z70%p6nlSSjkmp*Yp{V`}Pd5>dz6r4xOZ_!UYHx)4Q zC?FtU%cv>e_CKYgqi`L=NgP1Kx)))<#gScS($9)Fs58%=v2JTgSRe9n-*LPN4ePI{ zh=?9k(fa-IzSe3aC*+yz7hk9A{T)j7z2lm*sW{e1+)`xSQ|=*KQK)>AE@Be>TNT`Ux+zK?zf2 zX2H|F!!DGE!|~IjB|&f`ss@fak05dGrsf{0!|d<8&imdnQBSi4oO5*T+@4PZg30Ug z`1WcRa;vEab8uKlUl&w54ReiEB1c*F*qfc{UA?_JDTVJa^p!=AB`YMbYdJ}bsXs4p z#IY3AZmQ@O%4bi*?P!klRKwdeZ1ixv`IL1m__E|A`wQ&i6Oi*GJQ|{+jdrZB1%5TT z*^XdAS=JlOW_8O@QV!%>aUQehWgOLd3U7Pm$bXAPceDUj#PkjVZScgC{whax=m`W*xX8?*Lgj2Mw%wx zxMv$N$Mmw&A~RMesbaV3C(-NL0+UP*+{h(xfZKH}+~_-P{Il-49ncGOA+L3d6^X^~aZ!tm?VW-NAzrBnn*2Trzg~+m&{r#(C>{< zXzTT_Zv(Y+PKIXH&$aBgigDhJOHv6>1$H5CS`1|gB?P=wTFN@w$h|Jg#lAB%`a^u_ z9#XJ#y&QIy(@zs^FM+g3jk}FC0LSX4iN0u?&w)wTbXDm31xge?hD6?9E*5kzHNobe zy=AzXrJT#gFaagIW|n#ig-CwbKm$hC5`TGWrcM1$8B}(^@BHhv| zgA6dVblrr2N=Y|5l(cj=4BaLDKgZjj&;5IzXYaN5f4|sowrlBHGQ-Suo!6Pi@j1TV ziZ?u_v?Xk03*Yxa=l>Xfeu*Z@scctHsO6bRtj`!`R%Psey%_9c6Z$lVkcLjW|4l`@ zO0u8W`)Y8!*--$gtoW36_2)xYBK{WldBaT0r zx4N9ej1ALA;jiMJ&#s>#?k%fiW=uQ(V5GJDb;0s!#*Yb}y^*!~Me3_Z&t)Ziq9#lTz>{iVeMP``3-G1^)V@5K+x% z$pn!#oeWA?i=!%iidX3-w+}}7lWO$rSr6YOF8Mj7I9NLbk@Qlu5H7;s5ZL$I=X}h@ zNU$HQT7h)RU<9*wQ7LrH558e|B0oFDx zXUiLJfX@8b!H1nDC>y~t?%>zDKoWn;djFja>a!fwCT@4es>+JouAVCZz=CvA6yWy` z@w^B0$Sie&&h)ruGr)l%elapu3c}cXYvMkY?I#hn9UXSZZlj!0rMP3$fq02 zeL^60{+P1~?j0bNxhQ2;PAoZ(-{T9GUgkfknY5?7&xv=zyNPk0HNEO1OIQszV6$#r zoept(MPV`Xm2}}IAp@;O%}7{cc+Jz({wB$swS%VV6MOtSS4CqN@FNtD@AWP6+Du8& z?EFdZpmBJgsemCWoXGYJ5e#5_m zyNEWrf8E0G2q_atfc}2Z-$Ip$**|v)-lBfF;RUy1rMO`v(Er=km-tt5=^kT$K2YPb zS1o;exLGCGn0>wxh}S2G5^|XCx#xth6wlSvpQG9UYF=12 z!tYMUDRPmcpc5Shjip=`#JfT2_ZYIxQiKDjnM_7dha_O2;@(B9R1&FH{ZvZVfd-dxiWGR8)ylMOejA=EoB##0aQwme# z5pmc?-W5KYSh(!oz&pZhkcNRkXXNo6#RQ&KWpnbkKb_m-Nh-jWL{Qp-?fm?(-r}Iu zv|sVB)#=mt9KlD52_Z&i&zu?UXEMUXiryly?I`;-1>SHIO};}Byy-Tr2NfNNj%>Kx z+^do-{7wjL5=7sE`zby=-8PdD6oN-H|FczFJ z!3fsSHjCSf7~MuT!y?nbGp}#g ziHALAPd^fEL<6@Ioo|uX!0tDUKpb4jD|5kp#54;ur&4eL-JNQ8y#oL6McGoaq3_7( zq(px&@yk$9@W~4p9MZMP+UnY=KmyupgnR#@No~kE4|PCfFZbu_M0I({0UKC(DO`tP zn5aj|A|sr@xc$$V-1R4mxXvHXOr%-e-LX6G=d=WH#MmsQ#Ds3~i}75*919`7W)_0# zGy{ewd*$_KokGj+gU7`3y($coYz#A}{}N8)1JN^bm>=*AZ^jV7J_mhk_H~4TM@8nH zWUD+*Y=++Z(fTq^C@h1Zf9?mSha|B zMm^1;xkDgQ_ZaqU9B7P<@zi*whhn4${oglPdx3D!L6YDU#$E+oY2D?B>kS?WMl&;1YCB4X5%vm4RkyF zDT{B^(;i2!qr;H7Ga!>>+BP2q1Y`C-q8>7m zy^q7%d0qnz0-HkWx@6*Nr6QW_TW(nIRN` z4?<~q1eG{}R-UptY3K$8!j)iR5})LsZ*dU^7}uhR1@Gg%FRG@Gf3WM8u@);sXc}Xr z{xwBw;HJIvQ}q4(^yv)i$?PSGcN~GgddifZWXK!FOK*U>O2s@~f6+`Y!DTEj5X#TL zk06=88XH?|WX?BGV7umioA)i)Z8_jbw}F_7&2vu5OrhJ@&f#pq zTCR;B#NJ)~(pc(EBYA6yy#?ncX7OP%{4?u-Lmwjtp5Y6cpe4F@4J0?2liU`yqGEx*qSc^d<+GA5|rE0*ACrS4(J?ut^y zJ*(OPVc-zt5x~v%zNF)^fzZ`Wvz%^%Mpn!4k!QyQWtn>KuCQan<=bN(ai3K$Jzof> zG|Zu)T@GH%K|b{afU3=e>J-6E-eV-tcNL&(BpAg_pFOswfiLT#rFcTrl!+gk4c_@1sHntXK4)vW&rm~NIFbrQ2wsdcoaGmO0-gY zR*o5`Gnqt`>D1jAo}0R$Vtua7VvHT{(`vD_4z(nH+T%Mdw-``jBuC+Ud=xglJH!0O za5-GRxOqCcP>~%u7S{0}`xMzE@LBj}{?k3-UVQm(6C+5hGUEPU>{RcDtAU%6B7pwa zew^+(rPs;nRU(o1~sX32H-wX0DH6iYG}j6Xi!$OD?$=GPo0X;wtf z)JO?1TBHbM&C=s=j%lo`sKQ5w*AF4#S6Z2p_PQNi;IHS8C+>6M7R_`8_iL=Y94>^p zdR)bFsRt#}BRr}H*uVohmqSF{oBZtD&*46rFdDe*l%Gvk7*-sT)WBo0fs1Hq_hl3* zO_z_Q@PmCh*)9H}ICg&)2K+b5PjIjV34x?G zD9-zh!ua3hm04kV-)75>!GKhgBmT?~%>9wag$wDJomkd&dpg}?bQTUlVjoSzvBN#Q zqG!1M3}D+-hw}&40T3-9|9YuEBJ$a_#ME3pF&T2i3eYq<(pB|OV6C3;SzkvVtZodS zo(+WYC7w_m@{e)(*2|miOsM=69V^=MEHj%q7HRv<_PmK=XGyVXE6RPpnsnEXZ05?g z9SIG=Z--{J6vNsx7Aso*e=GV)(b|5`8$te0MhlO+{_L}&IGb3oDSbbvz4?ta2@uGS z*$>FD^xsi$5BXIy@tciGQRJ}^EYr??_z8ne{jv5|qY_Uj8{uRA6a%o{KLl6~#ocsE z<(#wC;`Eo>zgXYj&fp8f6iUI$xOsIiffY4CfPepZrsBnDvlZ2(wdO_p`M$nt>8pQU zlfBQ*+#&OD6iZ6cJvL(1f4=mprsBZtKi}=Ypt;{b*8fI{)Bh^__J2@C^?&#kmx&k@ zIY21@516z$frEEpvqj7oFlYbjq@WNRaESjiZZ7k0Q1HKH=1_mLj`w2N4QZerT zt^F7#?hhgdm%|i-@;7=$v-3B*TlDrf1}8c1_p4sa^g2k${kpvGn6K?0 zrcYyF`BCA9X$hLYKkJTa)LrYK-=`L@U$>W#YxMijLU05KbSe<-`1Zf~O>#M{H~IcP z=RhLxe>FMyn%|fOE%mRKVqh8m&FDeJe%-v1M&WNZ2JwIMLb698rHPAq9JN(@e7rCF zIWU;S-lPjY_wtX{2uFOjF#>JZ*`BP}VG%EFFWBTnUY@n`#+ zlT%5;%QYQ*#f&LtfSu1G`9&Y6FGqr|*s4XpleDEP^nD)QzdZ_GK6Rorbgp`_ z#xD+QLz;zdwXkmDI6;@a>QRx`*-nUtoW7WqrT+rrlX*y@ber&J-RgYH;lE)1W{^^B zEGpRHGW$i(>6p@l(0;B~^~~Eu+LI?mCk3zW7qRj*F8nod$i+fDWmR8Ly(7VGJ#FuK zi#t^0(X+ZwA)c~-Pqsim_(S$6v_C0?(xc)o19zB^XwgP!@MaP1#!pp7=-?y4xto0@ z4t`>p=E`gtpcma7gM} zlW8tkV-~pIoClJum~+QqCzKs1(qOt1W@wJT%&2kVJ)5;Uv~nd!(PX*jy@I0jFYZzI z_;$)YT1VyLz1A=>{<)1QH#t*%^?w_GY6@w59v7S%NgUGwx@D(ppKV^w$(w-sl;$;Y zzTyoGoCXl6E}cP9>xc99k&XZl2@?lf~O|M*e z<`mV#_cOD%XOBr^=vxt5P8F6}J*9rHbvHi2E!*W_QU?)d6t6f&i zPs06AzA=-l(gih(g$n*0{w`#ZDOEOBmn>-iRl>Xp-{+3DVa|km>xB7e#c~-{k&^n; zfp<@FV*iGi!1u{Bq{W23eAr(obtu|#Gt-G7*~0$^2LH)5AzgiUK>l(==T+EU9Ym!) zwHAo|x0rdN&D(iv&abu)j?wJNKNm6GBt(~8cZ0SW;j(gh75K3Xqn;B>w;jolroSCZ zJ#6@1^@&Hi{}(d_zRo}HyHe@hmx|{|IkIt2YVN|t$4107A?GJOvN^Nq1V|3;uW#VoBpsu@ z-QY6({ac1L54+w5@|!dX9B%cO-GpechIAYJ9;Y7C0AqmKkB!Pd-MRy=EA{F-9^QK#&P>I zSv+y(BDN9$S_Ui1zviSSANuw^b_O)j?|Gf(iB##mm%$egn!CguY)vT%`FnAGQIr~p zr>g@WVkbh~f1q~u{G~W(W>GHkXqg{+h%rUl>CtMy%pU6f4VHe>?XuRBRo~E)L>ujjdVBq{`jHs_ z6YP2m-FrUWWvqIsDx|-*TOe$3zRV@?M_yVPnlEYe_Nl_vYd0}J0DovM z@lbvHt8MnuCCuNu;3sZ&j;8E3W~P=fc1s(Wg&7x{y{$#yQ)Ss(H_0%+bxU3j`s~uB ztFTL#E`NaB06%eBIWM_%>GdTHAN|T;Eg9?mou+&5bfJxppGidE2GQTW3%&F7+O^A^ zFiAxOJ<*l7M`=t!LB^qRO^7&ev_+R7fWx{5#|je2Jgm&KJ>4uCI!>nq57(U47vuAE zeTVYK-VmnW#HiVKCJ8!q_@3{k-Xt9>!vFg&Z~A}T+-oyk_yVxBtY|^0$H24HG0ULV zg8}mP*V_&rzzGIA{WWV?KN~0dnjJfqbQG|E&aGNGs~Rn1g@4DtB2?wGsI5^Z*h6@i z+K1GaJ388;x@a(vC78{E8S~d^Ox<*<$I(XoN2GQ-CUD0&q5#E}2tC(6NFcUr-F{{Q}pgV**XF_-qk;D$e!@f<>HeXQT? zb)4~~=BSiYv({9xrLS*D_jswd-73kvBbuFT_tc{K^el{%zs_7SAhM`Eg&$qJi8`x2 z{=i8rYSppR@@|Yr@LQZh3O72>4t305hZjpuNj>O$p{sSiOWo|XAIzD0ac7jj{@sG_ zS(J}KWua5*&F;XHt!?~fub;J?y9!;^P2+nmyCeU)HHRO|bqj@KW?WXcVUh^rGy*6| z*~zVDuFWrdLe>qt3i7x(r%*?2ip90`JKHgFJAEQcLH8_*-+eu z6}<;NiY5plNeCNWwMtX4TSR&Bf!2^m|JF^S)`U*1_S zz?MyW?QYmpm7LFweskD&sIE$g9*b*Q+}mTES&A{FE|rKS-JNfNy~t!oGaE08+jNLu zymOj5t@0{exdT(5plVS~99{i%&{Nuk6+C|X_azlwA%FpVtXkVDuT(JrkMi`B<2GRM z5&!`;2t@X{eWJ~P#7Ft!8IamLQeT(_&eI$qf|+!*QEks~3NjN`hbI8pa<|gB1+YLq zAW?T1{5ct;*k@fa^9~I(sP{fQqORhL80nO}fZcnfGq3sJ?PlQS0zeQCKllCwpkXHv zA~3^f1wJn@5bev?7v{DZ<=F-J*2(9rx=lcd4i!8ZfMM(!J|%fq?f_vg#v*?vc7J-5 zT*5Xm*nt?9oT7&md=wrSFBhkx!keO%wVstvOPd_ji+USY62K?|<|!U{AC>e}<^VvL z^TLz8q%Oi;|1Pg2TY$cHZy@_J_r>D*-mzDi0HH>TD>J!|=P5>c;S7(QuS2&O*dBN$ zD|k^STQSf18G0-~IH_F&WSoz>3{YnjDn3769b2{R%?w-~D=(-7$%@l~4v z;kqx@TEh|bY0})FuANf!CXjWAcoY=-I*~8{%qwQ@Y^YZ+2Z1z2b$wertroKSy&0;MTthnvFhGv8-BaeMu=ueMDU^X>p1 z(^ETLx?b-n3i4LS@rYUQgD?C3QoB5#@8nouq&!r$L4*!IKZ2EAV{Jgse-W zo(S36k?d;86A5kg?i~k_ICZ~v68V|Wai`CaF*UCW8aG9ySq}O9k2Y(kL#2SK!Q%dB z3fkMH05{Z4YxF}O@2@6eN?rS_TBtm&+gflb1Payk)!;PmDS<8M<4=0Dtn}07jWmP| z3ffe`g%~!Ok0DRDyv&z{4h8x4*B2q6D)-C`SZ4g?ts|Z74jh#@{chYUT3m+?UnkZx z8q{-A@>~M}^nOeZ@S_cT)e>!SGnv(}Y6K=N0*2w#Dfq`6q!>SJd;@|M5i75NPx!Vg zG;D4i;MwT%se3I%W^bH~#z6KW5qNtvS(lBN9|!>d;c&`mZS#1uwH(~lZx~aLm7f$> zP0rAriHVqU;cVwA--}weOlSM!H9zIoehXmP9O=%V5!?GAl~=JKKhBV7Z7fTHEgYDF zHMT{$Mf#=Pd)fo|hm-Gaw@~Z8>8NxFZJ}^N-b#D}nxj5qE+0Y2UxEBsE&ejn$Ao2ebyleC`DqLS(bmouZD zL_4q(v+2b#pMVsf;#ir@I_Fl;&%_rMnY#-Vsr7rcm#9}xBcWPyUpo<)iMvRI7^DGR z<3LA~(jg^u1r|l4PL3fs$-Y7ZV7S#_Sol09$HfpxHBd-gUj&?MJOG_X_{y9cEjbJ^ zLMsT2uUV4osHLkj+y!L4Tv^uiGI%`?tjXOrl3sw!!LNL_$Ki%etbRuFEk@Lf3T*9+ zH^3>%$z}vkc+Cj(E{kLu*bN}Bn4w*0^yVWdozVv3*qy+C>1FcuQ2%|05+IaWq3<^T zJ>opASB@E_0faQ2fQm^xklLVkF+kisyc6R23b4=FP!c{Mu<6O>Ol3bRQky8~ly$eE zKNZ8}k5^iZpMa2E9QfwGK_!3}*MJdgzVsvQ^}C~D5?3;fPXWSNOnBVxvTCQHq{)PL z3gFPsSO_%)Zz{p_L>Rq@hgb~XwRd})cWkl5_CHsqu9*-qQT7$N^BmL95FCwnoW2@u za+QUVZSqtfe|X9f0i}EHDmyr%Z=`Bs+HJ`GvW5TW>(onrLl#evUrRy ztc=8=*X)L0fcCDnxB0-GuB;lTtPQn0Lo;lg0so@gs z4|$}+F2N-(8Lpi^IGtPy>?Xdf7HdArI<>_!6SBi+U#MJ9Lm5Bh5tVAwS!55c4?5a# z=U+6IxV$V~_yP&O4SLEJ>3PcwIj>iaa#EoD8rE@38Q}z-7p!t#Hg136h0#MiiI>5% zcVs1^yOq1U5NkNf=$1d@nBIo(VozyDCR73HIo7yByeX97G*>8iRv;27w!nOC?x6MF zY6bR?57RXj>5RkB=2RE3paiICGeib)q-OoGhGr_BM4sA4k##_2%H zE|NDmz%(uI2-K;powH2|8Qy1IZ66Hp@eJAhGa6K|~1JEi5uuD#jOur|lLeELg7|Mc2+neG6 zuz>uHAD*Zxx(#0RStLXDSN8>%xiG6s`tv5TLBx7^y^XLZ*v97@Ui;aFq+H!bfI2%VJ+6a zN!nFiz2Kz8B=eR6phX?PmXxvKG49@x<7@dcCZ;E1!i>Ov zdANG0dn@2A5Z^k6oe4%Ttq^Pq3fCRtq#&MVB>(fEBlS8;hk7@Vmb@UvoN zL!gw0^~B~+D7@UkAp!Y{^BFqUWYe3N0c*Q`cOV_JbOl+lZ$A>5Pp^g2Z`%hPTt7V+ z4&;!@p>VEysKBKebSCS~{64$33vDvDB|S_iO93kn3F4rN6nr&&SF~(1BN^fp!R6q? z9V-^+b4?62<8u{skrNr`xr{ANsCOadm~fi%Pv*sjvnF;JMVQOD-&_tv%GzO*z&44c zE=(w}FdS?eW$S_p^B+~k53-cYv$P2D=+fn}z7!qZ=V4rPj=XEtNyf*`uk!HZm=Fdj zJ8thU&#=H@&`&JGbDcCGPEaS~DLt91Q-DWze|ipYl7L_}9N--~2Rwyh(Fwe#K_OZf zcZpO)U`Ww;F!Sj%)a{-`QJ~$JTR8xGXf4s=7*E^rCz=rre!Q z{NjuIS}j)vrQmr3UXQqQbcd&r6V7_0Lc@g{y73byYoK7#)^;cg!jd|`K!}!kFzzWq za%?e733CPVR-@Q88#RP5Hob`E1XU(7?-YYtuu{5Gk+{GsdwSf69J+;8S*tgJ$krg+ zE`89kUNA?wFPSof>MnhV8UM$4E7au(R``#r{E|{yI8JjpbO)4+5w~PEhC?IjmMA`F z(jv1R`-yDd5OvU_UU|rpFewMQjMrSJ2p>!7p-p)zBr8iHRM972@Z%9itZ6c2Nb*o4ilTT$yz}v5|D=^pcg<~B(!X=cv)V%)7{sxd&56#DhetDDb_WHtxw|VfNlD54WM;NP zOJya;MQg7gF(j^gAWKriMj6!3q=qPC%2K!)QRvW{0Y|!d{meGWpATy%d35q4v^kc^ z0t;{I*xZKkFeE+axrQI{<~427Yvi+h8rKm*LSo#pzAuaq1fz7{ymFT$c7ThxAeF1G z%NRm<8{Bu)Scbp@OG@Go4ZwYBd!-~1r-?{b#tag1pDk(k0pSh21Sf_&ez@=Cjh^wI z%nFfiONBqU3lq4s!Lle{@q&Ty#{0Rr2~XvUFk9s-QGf~jveh59nE~p1%J6!c`eZ^| zq0ZBjPF{7~3<7go6aqAotUv1r-*;fmdqpBRgdTVq!bc13e8L2biG60_0#1DC)27Qg zKR(V1WzZs9SG>^26`HqUm1zXB;M8iS^oVZx#+ATEQXj#0uVC{_?M;1NV#nX&{0qp6 zQL{ZvTx2^ai%G#7si!YGZavr!Q8;k#rGt%h`@)^R6yn$8H_*C^$7is@G*#(NXciTh zXcpTkIJ#DMh}-a3{u(fr%O?X3(n`Ud=X#AfzCLkmV|ajRyp17^8L|VJLQpm=M(pydEJhn zeNCQQEBqy?XD*zKsGs9?mY$v>lB5}{$YuUP>n{fcC)%{R#xY9p?Y&PzX$=aBeB1ky z2-JtC(s8*Qoy0K7d2Yma`au1iXiTK*h#6Jr7tmEm_cWi*&~3R&12^LAhaqvbBQ2f! z=U8SZ*gJ%fuQw|*iUALjsz}tlv_k4{HE2Je79$;47^KZW*xVelkrzc*4#ZUv? z0M^6tN4jp>&kJlth0BpeQsqM9xqTiJ{l~XqcZ-qXpcYzu3YKm zNErg1h}KD;6C2pOG6UY zsMYSE!-yQ^D_Gy+a%#v;X+Or|3-uy~sS3Ntx|>JefVFr}y}`;HDCm2s-}jf#)xK9p z3=iifj2k7Q&bF$~h(Fj6-Gz~C-Z!~8vF4j(bF=Ijp!l-y`)nUvC^wYk;dI6<&Rl9# zrBLIO6PZ&720GX6kj|acgs^HbYc`TzduGlQXG)3TC7s1OMg{?~ZtKo%16U-O4 z2%4q2u0Jb@%6Z#J)-g8YtxJCnGvL^?MP(ZR!)n)1Hhlh8WDCyQ_~%bhIFsB>6si6= z#G{RmO;t=MiRk1^cTFbm?jkm7c9osL5qsoNV-k>6XyDAtkFhC#rhQZX_;Hr#q@VN+ zDKt;iV??e`hxdbMA*WozYxJ2$DR-88-G^JpnW0zuE|H8Fi;;ZnBD`C((s1Own7Ccr zl`S;2& z1;>A&B(1M+#f#8&hiwKb$HkpewYq%ppogEjWd0m%13L&{8{Qv_+@$e;dC`%-w?lkYlzDr7>cwL(lcFznittX;8b}X6gZ4>tqyAJJQ&Q{riFA5% zAH!5dc|20)2fxg9ZxdiJPUDpC>cLkG`2t|yOY4GbB!eWoL; z$?!R^c{7@4uVyjaI>5A_PAyf@!*pP-R@wA2{gb2{(>-UAfADIe2~*0) zy%rG?erLt>8pE4Au%Gnv_dTiPS-;oGUBQcV#o)LMf%g?tbKlYLE`d0s(%x5`44@-m zL&OwaS@>Zlt_%%OM0uk#6#nhyx@-51ec+cjeIs&2i^iOCb0(Q55 z+ASs~hq=`C9*HbgCs8||!!MjpueblCT-i3v4Wl;oJpJhTkn^Ou+==xVLLsc1N|&EX zI8^_AFcq;X+qh3TdyMOF2Ct}-&`Z6aPyN*mu$hRP z;?hM&e$qR?H3>;bgcZ+ihIYo!Av1`hOBpa^5T{Tx6KRGSGJ(^hnTafe4f%<)s+oyA z!vP-BGYf8Pz2{9tY!mgUje+eGgYF%rvZeTn7xC7FTn>bsBk4w`--#Qu zS2t-+moByq)I;C{jwaWb`)Ug2Tm`=Q#6K?+sZbMScN24+-?m&e>0mL*AL@09DQgu@ zcZr7%|LkNOHQ6e%5XVORx@7cYWF>#c^A;lVLr0WXqaA#fm6(7FB`glP$YFvPZkZO8 zeYI=+P}9vXr_gcrhH7;~g%GVS0C42`+YJHiOxVs385LoT1-VyVt%F zFE&l7ZGXr)Re{!Hk$X2UQx0RAHLqs2E$fhsJaPA+ibLIX!+(YX|>D|t$AGl{SiD-fi?w9^oUzyTpId9Yy0qgU?Y=F~VS8$H^6WWvT(D`agNN>GmfUOJkr7$`|`ucr3yBa?v&(WI2y2k1-A@@a%Rp|g1A-V#TZJedopxjIy zVp!&vn3dH9gwUe)>*)tib)mz(vgF(!ps7Rg@dk{aN#~@y$Mlm845BomX^{t^f=^6y z=N7)6og9|qcciaQ2geg*qH-sPqAhj}GoU2gaxpOidF|p`(!(rf`;?N;Be(5Mg;dbr&$2V8I006lcpq*`*Abim zDD}=D#kl*c;a}`Py#_BvrMrCS!E|EWSaYepSV#Aq7x+4p!&VojLY86?&nEz zl0Lq2B>8v|EM0eDMa+dd%%~koK_Nk*X|H&M9zx}GCwlZgij3N>L*I^^`?PIONZT>d zy`FQ^$Eu^KxObKLCHDp&x+dEyOd$UW;kyXc2q=ZA8hu}yVVKHSU(TUL5F}U7Wedj0 zOf&4*S1{e;Vz0V}TN2II`$jSFbv?ZVB>ar?_%#RF2T&6bkZU>2ot!OvBmU?2uefV{ zfp0MpZ0jg{P{1*^P=t`NoQ~ofeLVI3T}~bo0Bhev5G=awCCebI znG_nT)_XcAzt8#-i}w*~Xbi9g9UrF9>a1j*Pi0$q+=}) zcO@Vv&X>p6oKUd}7;GUM?<4 zzNtIJ9-9R!JCIQMu`u=&P$Tmw?3kfQqPMG<3jfErQ2dtE0wy|Leziz@HfoC+NTw_0 zMFlD@`inQ&Rk%5XV#KZuwsbCe-CH%0dWZW3pEK|tCaJVmRnzr)PO6`O`+m5f)(F+7 zpf;kdrY1~w1k9e%)52VWRkO~{HHiTx;akvtyq7xgkm`{*6(61~+faY0w6W<(-!B2; za_rsyHa>xz!g|%FmHQ8yPoM9w*PK@_uWFR5mqO?wU#t2)1AF$9eIN2o_Sowq8?Uq$ z5XTIsMt9I}s{;a|%4+_0>77}kSm!YdiLcyrZhK8N@+RA(un)Kco8_v*>hF)zlA9$H z_uSK?KK}?z*ADbw{$zM|aYBIYgeiCEhPqC>-Cs$pkU^USetPhArsY51fik?(Lv^>m z1mcN)Zo>8|%UQeD1Q~yk%UNCn>qs9$x^Fv~Xb92d()HVJWHgU&$8hq;^iLeiFx}>> z`WmNM$Ab>54-s5Tv8T=z-&Z!NI~#}#43-_$00%vC1734j;KXhyr-c|y@hs9i-_4fk zrNKp8T$(0{(^Pe{-ho$z(k4!W3#pmMe8Yp2oxH^(*qPx4iPOAyGmnrMs~x9X>!M2+ z-r>oxZ1bK#cbwUiuHC?}kjnGuA5@P-qc1g}!pa*S^(6_5vyxei`!KGk<*8>*o&7{jk8-<>&}5gQj$QsF@d5u>c;>Ik}i z?hwNeFZM=LPFQgj_6jPi@;*tEz?PuGTTcT6^n7ZknoruzzA2;u)2>(@*E)Et#O@>q z6;hCiPMGUQitv;(D2W@va+#(suc-^fa)laPqB-iqB2ZTGa4*NR@x(kk3$&*27LCZ( z9F=)S?(Qu6rZ=7S1<3!FnPnC%P8fkepz=%4`>a!J3xpG`a4rPBP#EL_h0w%ar|DpY`wlfZE(y&OR5{lpv<~;Rk zCQAF^K;s5MT-4q5p(2%ONl-$wkGOXBDVz^Y;fk~Ka^G=wqQZ+Me2EB^+Q5s=j)s(_ zK1o36D?pXXi;;q>@+LabkQ&1a9`kmVn60va4(Xxfjs9bmizUaEtjaOB2^Py z+-va*WN3P?PBjKs1^Uc*x;mvv4-igo&4JCx2SwW4C*c`U8COGPg$xXk55fHS5H%>; zqD3IuvxAAKuiGKD&6JP%rq0YezPUZpW=M+YVMoUh_Wta_PcyRLhvetogQr%ri%}Uj z53s-Dq*$2crd``jjp?WHA$VPXs(nl$cE%~v@*UGbz4|{3j+|3GS9X=d3EYZDy>4NFD`^a1lJO%@x-w(!KZjB!Mcs}!X%b;#L^aDo{p}F!P?C=W zg!-yq=Apwn7MXSd(GO5!yKS=_AzOq+uf`J7{&HVUv^RvLEG4l@UXC9_!)c8>0y&V5 zk@kA$l1$B^=Z0D-EQHN^+y@QcDO!xFCe_)aC$Zi=y+%x?{ahnaI!+GD_i+h!5Aj|9 zwR#|SP_$bcf2ahNDYLu`uLXnPoG&-!sjq=}!>Rcs`IGm}Am_PcNBaqJDVzEiQ*j%n z{&w^Gtm6AHFMH=TPf$tpp$*#kJc<@6s8ZOH-n&3wWS>f^WL&b6l#Mb&5vq95dmE}s zedid$ahO9#!q_Mrv`9DU+UZdQj}WQv7AP(oJL7TsZyCqCYa5h zG>8MmnX!3l4DIY}Z;OUl3G(AcoAQMJP=r!l5vamP-r0w%AA_e>c@Kb7pXmN_BL97b zk_g&#(9Bo-e(;Nzgt_bW;Jz`%a+X|JV+=V$4?Um>ieo2}3%aaXr&UEEA$vpm_Hzzn zblb#|G6UftTFu1ggyqf~WdhEkyN8md`Ph7VA{V(6H5_SJvk$ANW+LfZrpHN^=X8=G zbnYz%{A}8>*QjjkNDi0gsGs0e1tB;jS=hbBC?3#{N0_*Z74M00#3uK!7uZHYh-iHw zf5r+R?GQQggzqLU3`3TM+6BQf2l1iW=Nw(U3(~x4l zUa|T=E>>0yQMh_wXqv!lZH^8Rqs!Y!_h#cwbX~C@{f^_{gU&fWO#t4IKpOr}+>%@tAW$p}1~!=UWZ#RU zW_0*Wz*rIZT;9d7csp_G`nkX?n?6_cG%O&lL6*WyBey=C@`28)uS({Rha}98Jlb`? zIj-bq>q_+3LEqofcdM|hexlp=@`DC?)|*X%(h3}t*UGZjU4a(gXLm-Y9kyNTiAqoX z7x|Ni9w+W?;g(tZZ8jaP8OppF{38=Ve&mc(I*!W3@m-(YI3FdHl(f{?UXT}2MQydx ztm2jq*0*0OZW@)cCf%PH%eCWM9iPf~8^>cDUME>-cgDR)QLp^fS`f@JJ02QGa3qB} zo+aFd4ZA-<;@V*y7N&DS(^2PfzuWhkdU5Dwiu`feimUJ*P zN~e<);rEDQ*hd#aeL97y z2MbY%ZcLuBowXKOXEim=gI*qp{m7(Pv{v)iA1|}0QMn{v;kjfK#5#vBGi6co0hd0(@Uc(U|l z!f0h6FZQ-RGUicf|1&glqDwh%F1S#&R(1?Zn_rh}vJ+qLM@JKWCTy4TiEiCH8=d@o zakALE;5}qFOm+QlO!imU7u@DNKIS0&(hp*?q3L{1oW2$*$25CcSFvn_kd(68Xft>{ ziBl#~%WfqGD^W@4fb%o2PG=qRC|9(L*NWG$J$K?ICAY)ZI=D;JV~jBby0}RL{qir471Lwk1kpx7ewME$wI0;& z=3aBQ{k_Fi1jYW>-GL0LBH*lS61xmz{0Y)YuwOv_`MN`fQOPpdEieSQFW-Xw0fON< zmwHq=EPlPfayi84f8hltMx-k*U|93?TbPD0!1^%c#if6K)e>;@A{F&0DFwnDAH?jc zmb1=3fh*qn_bYxdV&r%0lok}XGXo~w0pRA(Fwd7DJyH$>DkuLFTZZS*WBRo*<3IKo zpsfH755E0Bw!d+p1o;UqhNX7>AAV#LEvjpB*Q?kv`#fuRMgN(Z=K-b3asB|i%|y`X zzppsN|K)nXFBi7@Wxu}-%SH-yQdA8PTCPU7n1>`KAA9{?Kl%n+$uTnxL{%O$<2NZ| zra^um2tcJFCX! z(9IQXjM3+uVeYH#JkFAiigBHY*3=s*u^H{65cqk&csn66F8WDKb;;7pdsOyOg6^@; zJDG23aFUm-!iMx~L5$L|fwHsnIchaHsIa}6T@FV@#4`4I$GZn(VA+UUE+5P?Uks5M z*^$3`$erlCX3{P=7)?~bxfoXY-L~D`fpTc0{s(f>)QyG7Hp%Pr#0ILC-JoW|z8K8q zos)?hChaN{`_6qe+bda~tNTy7oTU0p{TVRf-0Uu=Lov@$PmaIZzeb*XF&h=l<@)b# z->O`v1v%wq{E{@HacbRj!$>-mWh&Rnm%Atv*?od9^y4NKv`qSG?cHzyT0CnO>3dD)9z z+6P*NmQt9iCowuyRjHn^Iyf{Ey%;9@oNtLo<%&3?075MA*B$*gD|k_^PeqXI(aC8XukN?e+y#uqQUwd22uKd}gKe&gfyhBc_Jz8g^JDL!Ngxi!(LQVt|A#=l@d0r%Z za%#@eKQoId-tE&;7P>8?MUz@-uGuXYM;_hIfJ&k)Z@|v7O|EiP`~TQ`%dn`suK!y? z7$gUzq=!;L7(lv|R!S5Rlp0bI5ExQQWPqVVC8QKoK$Uz^Y$Xu#qKQ1M1KA(%)(F`a2Yc zKIIa?v>&-lRQ4z2f-8a2$5 zW3?UsEsjXcjGYr&C)-{?nNuPb)|`CAts5eXL)`m8mZtMvu{)y;E4yJ+;Ecp36_VJ4 z=<5@dL1Fi25hP;t;mC*@ihW?RiEGsOQ(y=hG0<=$lQq@4?$dJ{kwy#BM@6lot|gC} ze+=ZOghbS&7RNmk;;@}Ce^vH!aybja9zQd{VEz21(=VHP67jWR_XJBJW|%V>y_c(1 z*)v~@`KgaWD-zA?u2H0S^a~XFcNT{R)rLHxq)T>2ZH<+G((TBhoNRis6zmKvG$zcG z)Gx`Qr(09!^|YF#7Yq<6fD8*zVVLk#Xq}X?Sot!$V&65q?GZm6dD6w=9#}N^2Soj-@Rk>~WSy1!NVe<%+rw8DJrAx4g=DeXz;RzeZi1I@~?l>-#4UxJ27sj z9o4ln^Sz8O9{gP>xbm@`Id48jdAaRtcy>$%F97Ig3IfXjc`8t>lmpwKC3V((F{=juVqdI_Etap!kkPo2j5UoBvj9>0uiW#fd|nd*hwJ!h7XvBN(!O0c_jt zpPT{3$M8#uHXy8t)-!+iutRjx!&K&YL;lG?x)yt1rk;?{%imA84;GTscH3L1ju75h zAF5$wxAdx)%;7I~Bo-{yJ=+{!as>XPb44UvY70GVS5LYsk|^PH*Qw*|WX}i*=5a^K z903anJH?J21%EFw0E&$^5-w}jSj0ByI9UM&fTh>bs_2u2aFmve(~@>yr5my@7a`vV zlqW#r)BS1pN73^~6*-_I6Z`Iw;V@9~eYF_K)XO-uHj^YjWd>NIj9G`8>a$aKtS%>> zfb>c%8I#1P-R<9fnxn`GFetX-ptpCilp8y(PcP+~JKl|T_yjY=rtaP1WX+QEv8F51 z9Rv&c9fIw#=W}H>pk=qqI8^ctC~7`;ZcNvA0?~v`j-PwI2rv{an7n3olwG>6HQ7*h z$d0hzI|CdbVJzui4-C+)mT5KbVrgVniTP6rr7Q_7ljIAYJ&Lr$<)-1%18dC&gsgPS z038<|7iztSmw&>4t9V^>bf@WL{gPHX{_%#QAO|Lj%IRJiHf>bUD-C0G#*(mA`K$V! zy%s;60x88csDCIR**hCUFF(&N`?C7>fq##lfn}mo2QUVHCb_cW8^)eED!n^Y&kHhj zXBII1r-Fr0#Q|N#sx=JuxWv|GzAN#$E9Qe5podEb#(}es0leojDtl3j7WlKgb08@*>R?IT@E>h5BV&V8g z_A?4ci90}1!t4$jjTS&OleYtaUly(@dbb?yjG)xu6Go4Rt-sUyhBcq&+a6DJUn|RS zzxiT9%AHKV8`N22cPd^2zPoyJ7?aHj7OFOus|Mp8Jz0<#KLu-4g-1$P<2pt+W_ivK zMxo~g3|UvtaB8qEz!9f13;Z9Ty|A{*nP|PozUIxgcGT%yWq(#7clkPw?8``!z}&e~ z0^ykRiwyB#2Rj#O6|dHiNGQi4G2(Y2wLsl6 z4mnGQzKZ|d>RXn@NXd&A%J1^WX+P9=3zuzsu9YoVOPi3FYKD9VHCT2jI~oni)tePJ zQc&B^$4c`Ilt{!sc1q7NVuc~wU||ny#i)x6H)J=z;2d?i=p|+XZpD2kXJ9yXWkJUC z@YAkKEe_#O{wElTeUKQg*Ej3sYWM8=A4Xs+6!S@>Jfs<3Qyx2$18aQkR%KK@m@fg!e`Ph|s5HZ2A*AcV1|-_Byx(Cx`EyZNfy_A+Eh z)?5op!<1;BDvR0@5cJEd1eOlN8ho(sP+Vh!az_E6Tqz!pK7mp$F42+R61%01k_HCf zyF#f@G8a#*yNiJmz8xds%&S8VWOSPZIsV0VG@Xl0NdCQDtQWP7INvf*2CNn*Xi>E| z8(l!$R!N&}Vt7%wvoe|0ZU5-;v(Nn!=F?up`y{)qRkH~c_y9R|*J&4Og5ref(se4# z<&A?`a_Er(Clp~meg@<_6JE}U_qS5W+khxRA-|r8S&4WWD4+A%QSY|g7ns2>E6Lbt zhmD?~kBnM&Pnrx~jGbju_}#4y*FQg$j2Uf8Cgf65NkZP=Q{sMO3YJsBJg^bYNt{$j zp9InwQ`t$NT+~s><70moA_I4*XXJ{K`u@yPq3wXln{I&Axa)wS_P9Si1l_Qddw=TTTBJfbXj zT8^fKhRCofjR`K`YAB4oT+Y&QT*Z0-#F?5OW!L%*irWLF^gE|BdYd_+>1eX~ajj@= z6qKt){Iz89QKH}=bh@$fh8%ue@H^C>9XYzk;PTIobU5FU8x?Iu*mJuL<1`1CNJRB+ zY9~SQFpEIX3c#6-U1@9yVY#9bi4ek(!c7G(at*PaL=3$)oyJs4@+9<3agh(VF zo4Zt_CBwkSf>tzra$JslTC@T_F9@dx&V{eGjl-_6nQeOSnM zS*0Wj&x8tMqfs!W_F&m;7MPY4ELTt{i%Osb^6@yz?`apOE%itK;+N18`}e8 zx_@uG-{;%Tp45sD6puJ^8K&CVG$8RlUaSZq~if)UWj77l>li`D&GF^pri6S1{bQrIH(!Fjt^rG)oLr} zp9+RgNwPnIE!>`g;%oM5h$G*N5iXR7D@W5;*~7moNl)I0BQYqJofmHOe56l|oKVrO zd#diHNT(-$#|u-%D%ESQuLg@P)$ACYIi^rbm<73lo)wd5TIl-KMd@~DS=P}rT(cvu zf`7IcxzT@Yv0s%@ZJ;NWJak~vQRe^`#6T{X$2 z$@kB_Zad{StC;w@KS>Q^f$UEQ|9b+at*9IZ6;QejNi^vqrXSr`E8p_qymI)iRUZ~H z5)z;Mu63(XbDNpBE9TLK2z>uYb|9!WZAy>#Ht0%;6BDXqFHS?BsW!JM|kT__6DJxtkqDT3APjqel ztYAxJYn6r+a0C+62q*=;5`TW`B+lNdC;~ZRCyBDtnrNo}oWGYPct$*&UGf!#?DW;Y z(~?=@bp2TD-4w8huHu6-&A+9pSUSUHT%5!w=Noe$_xhh2jGxbO#-B=0kXg$!j=%F$ z)K!u>O~3OR3&_AV*#F7E6%ef6*Z)+3VDt`G{>g;dF5w+K_;Zf|X?UN?KWVrYT}$$% z^Pp8}7Nr9QtAf{!2`I`@A+ z!g($3|GtI)yO93R?uAwf$6v-+>l6v6B{QHXf1|S=j}1frxserD!F5Cc45is-?0{<= zj}UP8Ep*}p#oUyQKbxBp@$=Ssv>j2l?7q(?TX|@5X zAnss$0V}EhoVD=3J{he2F-RMkUV7lu~RB`QKZ}cYbWiW6W0n2PsSRhVQJ5QR-+Z= zKg~;D1zqt!<*O7Cw=J`ZF0B6?Fv!9h9fHn>8TO{JSx@XnD#SN=;SOfeM7 z{}gcRGq$oyCPuKAM;p&Sf4verwl5p{2Z>~RUcdlnZMr(}(=(F3m}+_oR4{Vr_j3O< zHd(>y0#y#|7wrHBdq<+=pv4_WertfIk9h{BV$R*SN&uf|1^l>s{mG$2@SGD*=POj()Y)xi5{o zMz5c|e;y1jGJq;|)9~NYDy{LkH;_@M#M%Tn9PZ6b&*yD#XZ*4l(vk0kx83{c_s$zS zOz^HtPuHT;P{M7WGLMSi4kTJmW3PJ6*G_RHxWrIJ@qKtJRBZ+|;a+6&Ocj^DKxI9Pzb~qTid8(#>ElK^IJ*AX` zXIOkx?sH&fwV2P~d}*|s-m`a*zuj1ClEysDh@rkZ)+^D|?DoJhk{=#lZg}W2;e5Mq-?9+B+}f{GANnDgsxDE5p@yW-?Gz?9 z3<2y8`l&VQ>e!eD_Jt|;Usc%yof2CEA=4(3Z9vk9#a{HrK$HUbbctunis!c*>_cle z3lAk7?e-K^%h@KKE-)Rebp$3gM(X746j#uU7#z=@&HhrmNyx|Uw0GGRrjEwtBC4`V z;4hptRpn>*7qO+zcHhnYeX_qh3iXMT6ocPjAh0+y^f~B|oK)K#)bcqv$o=hr&)9sj z@!@y*dl3-i0I|tm;je=7)+#`r2!PgZlDg((#sh972-@!lvYw=6(PH6F3QljyL{XgDHUF&E2yv+5xg)twr{pT45 z>tA;CY;}uTK{Aj50jZB>MOs4bmii>5oWE?e{KwxBH1aWk*$Uth2>Xhj4{Fn=8uMhA znv9fdVI#PIs~q6mU|Gb!b(NcDU(H?|%5ykbTrx=vYK=blsZDa6f^ zqovfgnbV}@M_w`wDc<%>!*9=@awtzBcB$R_su$-2J$si0vd@B6G2#a9j^rH`!3$0g z2TDbvd@?7csi$NZIr^(q=yf zjyUrm-fRUUn*h1VOy*#Ysz&#+_`y{S0WVn$yPDm~p{g8lA~Z$JvGX3qc+r!?-Rj7O zlPU8PdZ~Ct|Jp*dPHsixVI_v&bqM5CkOTjc;v@z%ue#w1Kl8wv@g9FdFO4khHDL z;yL%|9dW~wL;DR&z^Rg~s010y$cYRnS53TsSpTahRef)5{A9*z0b5#Tur2*44xIE( zz9xWw$zuVjDpoO==HOwV9XT~0aOtbL9(wMM32G}A0I4Fpv-Cp<6sm>#zNiZUyiP%l z)zXn6@cTIVs?FpK{OrE84ae}v0tO%K2|6eu97bZwf$m{JwY721EUt~$Z)v6xSQJs? z37Lh~daMQ(SS!sddOg@%gYvx?zXrD?Bb5~z3@WduO?%5-bj)VXft#_SLdS086n!Zt z5Gqi^Y&v?nid*0oD1E=~_iV1K?Vbf7Dp=i13|F z0Wxqs4XJK^yaBGNW;HQDL_eC-)&fdYmIFrKp6=4>?{5l#>`EA$yVSft0CUMJV_v&| z@KvlHiT@p6#daPe_QK~!L8rv}WU9`$Zzrj#B1H2X9lW`oMrI_M@``@V3(eFi5KqO=-01k?y zKhq0vDF<#^^(#LpOMxXyrib59lDQg5MNCC*!xd?~S-S?P;HSMt%q;18N_e9-xl)*m-8*GDZD zC?_=+-nZ>fZ=rL!lRbK|Z2%pQRj|}_u5RX*0R+%INCx?f)__bVeoF|Ckc{^sEj0pS z-i$-Y7y&?B#6+d^f2u`iPph-?nywU|{z?t!d)S4p1zD{1LXgwSkbsS3rXXwuAX|z_ ziD2P1pec+p`hG9bq3v2mKBz^0m&r)!s|3`USipxGMmob*UK8`du?-99-7oRBR)zqT z)L%?%;22rOKj!-%+^g&};1R6iREhN}kxXgc#McRE!Ol^9ux@6)G4XPW%VR|Iuh6PRhX%qc2WHxE05k412N2g$^A}m9@a7V z87QtFfQ)^03v5*@mb;)>m(u@od!f7JXzt}c1NGynu-5gjz~gmSqKw%qe$89u&k~wf zQ0qVbL{}}q9kk;yEg#F4s)r(jWy`cg6~111%@YmDnJ2}}Mz*j&?yeLHvmY*=ZVx?K zO?;??N)+bJoNeqe?=)&RgQ%d`Qe8UU1P_eYSRS5m@b*qNfAp-+M91ZG4sdM)%FL5@ zS)IqA4Bnyh#K!!Dq&gTH1;W%#)A$tyy4PmF8rs5-S_cjsB}G7U!{xVQ8>;INRCFyz z!E;Wjd-W z8R>D_dxm?QzO8 zY|^Jd5*<@qT>vhA zH$0X~m&3oovGD&p9E;IzNUH4r103rfLjw2TaIBku!LiVP!LfAzz_AjX|2rIuQIP3> zg=4u{#Y1@7>3+U6&iU;SLQB8x?ket^Tc;xJJ)tw*LdS3ERS@E)E$KqMCvOtOP!%J( zjj>pI&--Xsg;GZg+7z7D+R%a?Etu^qaj!7*4%kuWcbTVjVihCeo-=rQDq%kSc49g> z?d0-FQI7{SIxDMfzygESB9BUsm^RQSKZ_A8YSlm?&=IL&5^dQmOhl~&%Xv3auNNBa zFKrbL4zia}Scrqi4f5al2VMGyh-%X%5zsqxXDJQfRQKVP2`9VJM)<(GlR=lx`+u4Ktc6!~ZV2Frzb4vZYGt$z#2nV6&Q zVhF;KV%)MVgEns3eIjDujc+Y z{FT%JsFSn}4QAPZ;ohl1E-?01T6{gbQ=yi^-~a3Y z7$iUUOao5`#HQHzJ<_$0CSMM+WmahOpq{J`lSCxDx-Hl5!pBmV~oXD zZ>o^gOS(EVmZPX8^daj`UjpkgPM?wn1BtmK1_>r%HopUp zMB?t07jeUJf%NoeRGKyDd^z8Y1mvf-?aiv-UWxLeAJI>^)D))Wc48}TrfLpF8&s+v z9-7m??xNMR^@e2Oz5G0gNF5}qr!F9h2JoAJCY1TNY~5a{42LJf{Fg{Evo3Ij%ICc! zHtQ`yTp)LdY)UYviWfHD-7AkhfB6kH8y|v2s3IHim`CU~M$Nb}bRQi`%O>y4-_1Kq zH}d;y&sRevXVB~`#URA^3KEi6rZn%K01O)6W3Dcj`CjtAm|9ISfba^0m` z()R9Q3?$fhgVcY8X|0v)BbrRf?y5Wr8s5FYo#cuMBE-8h;2Jci1lKoJ zdP>mlI8dkAp#_D~kQz7=DY!mH!(rn1?Q2Ag>|Pu%FUUQz!-&Z*2_#&ezJ!YU3sjXB ze-5e&#)7Ki?`cBLK~+KLpsE=Fs(SMWRK?wQ?JrQ(%si1WK?7^M2XK%ZwoES4d~JUV z)q7t#ik6Vw^=)Gy-0)u4OR=3_(#S+=F9s=6^TNcRYR-M?qQf?T_7wIvq)NFu1cg9R zMxpT78Y+2}GGo6{tILO%ZhAk6%jAtz(4FWr=O`;hme|?G8HGhkp{)HNio4yv#(t|u z_p>v{A%80MmA}<*o(sj4KVt|m@3%M5{iZbi%dqNmOv3g>q9~`g&13rDjSn`r`zb18 zW=6hR+i~}q=P8JN#VBnjy*o}>Ra4oxZCPrC~&j4Oe> zRSqI)$9@x42p0{Ln3=F=95$W{TcukJ?#jD+9peg9mi|a1R;vaJ;dVj!%zV&o?$oP2 zC|#w$F|+sy>CiCcd&F$FkJ_8wi1Te+N3Fl!cU?+s!Ng5z@2kTc$AX(?73fO4aHmTg zy|4oH3N=D}wl0qc(Pax-zpP7&LOHkMCoju@UOF$Yh+V>6MTz)~y+}y*^uR-3 zbJm~q{p__0hNQAhd!(?rqDk;Cf5bO?;}DwL9)>P8Zb=H0zSbHybg7|@svJ!<7ij8; zxdA_vOQ#Qe!~GcO)TE~8D(xju0p+dTwtSa08R*}!NxhD>>xxmJ6SM4!gOdo-arqGa zSP5P>YaqW3MhSZMkw)U07)4Nh{=k^FGGUMLblir<=Bm+a_;GuAu&j=jlsKXJl5RSv zaec(wOPbwI-1H7FKu*1aBA4t!j41NVt&2$W+U;BQ3 zBNq^~91;ZQ`nnyrJZpFd^%E;QmWkv4Yc0ckoui7ANZe2oeWw&6t0k@ABix%1so(`G z+2-nU0Y5(d(RAgTAo!#vD5DO0Sn{2~A27!5bzbEjP4IR_ z=G)^Wj}75|0eqU#3JIn9seG0n1S(f<>nd`&gF%^-AIMA7T&Du5^MZ%e5~$bvgUrG) zBD!7a;Je)v7DSa}VW@M`A28A%JpT(=l2Pg@w~{oD=TK8&>Y zex3?JKAVhlZO4BQbw9%KRZ}nLtroKe&o_z`oAt7vcq~)kcLZBV6qHySn3SUM{PP5o zK5T@yyWfPPK;_U>Av8iM#QJ_i@taVh*`K8lg%DkfnLL5}A$=bN7KqtbuL~^EZEi_< z)EwgY8v+ESjHW=jTzOw!T43HjmfJ({p(7gx&ExHOY zm(c+t)3Z=ISCi(zvS!$27# zbjbIvcQ~DaZhXXAy#rB;eq*UY@7&56Go&SENd9V*k1{INxWkjZ^`a6kN&ZblcBVuq zGQ$?R_faDB$Y^}N`sizZ8R2@2fI)?t4#R2-k^6|a6v{qQ&FAte$5+-of^BEl$>`^A z#?HuBudZHO<*~W3%4Y+&5wsCny=fz|D!MAZDzPfHD!nROeWB)6c&+7>^N<9(Sz%m1)+Stl-id&Gd-*L3M)L7i z{bK%2aduDf(6X9pq5C;tY27fjrBM=}A(>@)>#Z$%cYfmYv|+J29ml*O94&AVdLc0JM$UmKB(Qu3HZGZU`XC>(z zBaBAKoqn~-#>3s!=Kx7=$!%b2mI70_%sxh07ZPb79a*44>DIGN5F?!M}chX>nB);pSR40RYtk^@_02E5dCWj!G(skl3vW zhLDX*TmpbpY=U}6)IvuU)9UPJZ!_Bzsv5_W!#At{b#%-#oo{wx5VcwL==17LGb9Lf z6GLyuUGks(avNkDCTmSsreqOZ-2DD#Pohku_2le(SZ`8qb?-p$S}#E#SD#3qPM<}e ze_v8xabH*8THom``3CVm3JKKF2ZD>7^P!mipxB$qlD{X%AKz z=p;I)!E#1^^YgyWF|Q2mS+Hyq|7_~!;J&SgxC|3Zcuwmjk(1rB-s6T(AE z4n{=WB5Ahl^dUv|`qUxG%IFT2{@JT-yZOUQUFqRhMin}DgcI^6)62Ywnu-)dk%8}* z`^07wQi1P%S7~;-eU=vTgxhi~JiV+sT4?P>zkW>z{ho-G2f5blsd6YdhnqY#yN04C zpH@@Z2?+Zr=>B+OLyeHCvWs&}QNmlxuQV5wqo5Bum33dh;Zuw(nznd&Pk#azAb3{5MAiM#+|S4=Gw`}hHBxur2LjT>Rq#4gWQD| zbcOe4lb^xuXH!Mqd7p0ZkwJsLt^ahQh%CiKuCkXp)JPx&nijfT)Vml$kTLPW?xE$)QI z60IpZA-~Tyj}D6Bw#JKqv{$`*1Z|SN%0}rWUQ-J7nu?J`A~E}drE^iLGnEGBaZL8| zn>BWVdc{+Zl;x!F5`W~VjS;VzF=voUwMDe{-VzH|wKsZt&qbyW_ zsi$m5B9g;NIvNvIY1ET?+3jn1k9KoRakm}lr6;X};We^tX2WtP?=Hw$B@U8qHc}F! zn@!k^StH0fFb*$%K12zyv}IwKMdqObdoBDfyQ2J(u$qPtW@(A}ExxyuaylD4z!iugmgr9Qne2bR@bn?m5<%3<2)(%%twP1Q5iLly&Zat zeiAp(B7zj;rdxSLa0yBdZozo>bPN^g>=$kgFwEbAZg(mmjAbIcJ+4FNrygA^i8W@U zSj*i{;h2vvzLg+I8*DU!X^u#LEw-I!+B|Zgf9fo;{{y}6-Ee(#+tCXBP~tjeBE@z$ zhgEF_8oI67OM)Se%~3p-Nm7+yHur!jMg1BIF2+^S01XowW94`ku z+sbQGh@|;x?2{DM6r?@@=N{?)}Z#Rq--@3~Ma;ZOKpdIkXYhC^srV=*}i} zbHc-=^nvHRE;E-BHSQH#CZ<+@=Ald3?ZD%AN@ z#z#C;&%{knH(PP&Q7Z0s%ZG-oEsNGAH>HZ&ki}@%75|}b+KUz?tGGgEEe)Q-h5AA8 zok!FqHEp#0Zk`G+K7zh*1NNbbfH9BKi~B7>3SueV`a}D@*9eY{$Xf3;HdqL1M~b&i zcGFTYvE=ocN&GH(;PWUlu!oFx;`SDm=*M^bdbF@Q52+8S<``kP3;%JuiCCqt0{dd` z2-ml?3WB)MeUb|cjz;;JM@qYVv49LeuAvCNqALWS!)y)apI~&WwfG{ta#*2ZpCiXN zTHgyMJ3d4|%?@A_Nk{X8@*%oTCJS*L8e9TXv=yKj-cikkxJcjp%G#vA=XR5z%%It2 zs-H3Xfw_Ykq#Z`rFIxQAXz(;gNLt4|fr@-JHRfA+t7|yH`)KEQC#rVL)y`Nap)z}= z*vltFuSg-{pxLtB;Topj=;7Gu-8uhPw{OXuZ$V4wdt@+867^=^fKVsrv6^GW!}MWZ%gmvnE3chtmm04*Q|rO z1gXTPfN9gvmR*{X1C0bEY&J&DMNROS?x>(kqP?2Dg-pp(sTm0xBh6uVl=5HpK)2(N z%khyvBO^$AdHaU#rIegiyiPbeQ2nQ`9z`$9mp-VUr6!B#ym)hvRk-kK&D>p7Vv&on zb2hV)^Yh8t{?iAHs}H&1p6>}PMmzBycox(qj81oVw6b(&bR9o+4P zsi-Y?GV+eFCxr9+(zr|lTAg#5UGFW`7MyJGNC2kio9&O(*)#V?J?N0Opf-PTJM2phXO}Dkqo%Z z`sXj3`Za_nw2VJfu6ex>a+_8EReyy?+0oHSSKXw>#bMw5ckR%%{$IE1bLV4^sG}l+ z^&PD|hAS*vCbbi^$YlOOURF6+9#E$Z}ahFjdNM^`wqjbae<4;d1cGyDop7QIE^3dKGz2KUgv`Mo6KL-1~*n; z7~I8Af5QA~nJqSngs6mB5{wg^)uc6t6L-w`EQgJ!I0UAfyIbW@;w(=zdse*M-)YdW zDgbq3ev%t*1mrA73%B-OaIW4x3SGIEf0h<}S7Em3jGs>2AGBfAkKF{qRCSX6?V(re zZh`ZDO&yl$G2`;MA%}{qE=TKFVt##3k`U}H-u%`p#$};{){T$&AhSfx~1HEMC_>k@iJ?H9R(F zVwyR*a|Q1co<$Zl%@mouRL#-DD2?6|82ws5B>rQcb1BJ3R495&H5+tjW>5oxKhbb0 zRa=H|+T=HO&eBr6XlBD2FRRv5OSvTeO8(J@H=st=vs&`~s2nO9gnq#w-|}vi{o_{g zWQl4s2B?2p=jz!sW*>?0ef$m$D_ISW$3EcBvq?>h+r?0O)C-BcJJHHri#6SPC$fqQ zrJkyWLN(vCc4|FD1UJQMl60>_l^_{B_1~QP*En;Gj?Ye9>&LwC7mZw0Dh-!MIANpw z-O+$AnNjmK_T*g)DUK22`Ju-J)sZ1`(e;=Xpbew5GnuqM!>Tasn>&(aC;3u-RqLLt zYHt|Qh*)g#F;O9s)g-toUr~^85pD-_EwKOONxYD^r*>(62+Wy{8vWXDd;^DiZO)b- zmp3uWc$I;U#(VE!Ixp$C+Rhv&{Wo{&9C7ty20eyl&(#W-Y0k{F?s;8vwBKrV1=9yM z%4(jA9;c^!HO;G*!>@r^c;h=x_J>umEvq!EW+_5%8WBL6RE%ft^R(n9Zp}b`E=O~I zEoX2XB}^`@36qBE+(;Pbu$p>l=6R_*^zzSe{XjT=V}?6t^bst?M|RSCx=azmEVt$w zY8iC0o(T0$lD3LL3s)MgSjyaY_0~l}y#k)zeu~g%vCp3yiaM!=)Niy!>Y~aMCivhL zwzRQ$z35!EK@|)4fonwTv%>3apB&;l0Twsz1$8xd!_^cT97Run`8_#Pq_dHCHU81Y zxkDPv30}@+XcN-GM(!%dQA}c~t*lM5nl)4|kYc;Nz`X1-Vkzgktv9EGd@Zf=c}xMa z3{4D^&Sk3QfZ#wQmZvTzCkE$z?p@kOZHne~E>)phYz3F!R4n#ebSJGc8OVWI0~@aE zTGg%ZAfx;IKH}!x4O_jS&90O;NsH(>ldFXrg`AYQZ%2S;4j-qxAhaogXX)-QrqO4lN8q)oQZ zd)DXBJtVG4?|2s@fN%#FLW=@*(Sl|XtM4tpWjAtBrXmf%DCXoRKR{4y?EmaK<$^|E zcw>36rEXy!c_=kFXq3ENL8AL<$?5H`6e^3+^LJ04O}++aaFz>d4?5EGMV(=0-%TqAmW6UHt*T6mAEe&) zz2gJx?-SpiUKxQQYF?}*fEm^*y*x8> zjF+V)sWgu>@9XcAH6L}J!a|C!tGF%4NFITyF7yQ^BE)r+O(y>*QW;>HwW46p6++b( zX)A-X&4E>>F@$$B;tXUVOl}f~QBLFmkFnBOahLUps@XP$1CB>961H0+(lwQZV2I_O zEXU27m9=_RR16i%O1;o*KCNI{u$zen3ebz6NBHz4vP-S=#6g}vDQRHv`_3v(K#x-o z3sLi%-ZLv#x}F*uE4v`bls_e~FwHzJzyYtT@LLF3Em3}pzQ>JG`7pi4l$xz^>u{&x zE)RynhXYDqW7H~PJcNgbyWKOqxzLzC80XF%ZQ0&d0HF%J{9h05Gvv8$P2>*z;l!tW zH;2;)M9s#*7UPzR_g5cF4)G5*8*8EdezfL6PVDoQ!dkm+G(VeG&DaO*@_?oz`=6M}Hns;oh`0F@pMSK}B0P7K6{X7`dO(ksx; zH1sQ%@LdJwL5m51|1z~;)OIjzgK}}77IE}Ph+CSO&UtFg8IzOpibubs*j0JTIUyVq zNufzWf2ph~;dC))xcYDz(L*N6a$k@< z7?f6Ld>q&Jmhbq>3o^hS=ln9He2g9pvAhKkT0=L)^5?|!v@Z}#Q-!&@7Bt9wYir`v zyJ5iOrt!AIjJ+%uT=v)$)*$*a3-1kev~Q3;$poXXS4IONlt{U$Y#_Xi*=Dz)16EeScoF- z!RL$JDLkeZUvl}c<;n+M)v&-0ujX@s{phBV`GeZ9TU964pF0fRx>1h!l(k-_8dxSc zpeNs9L7BvW<-lAf!|@&UhjK*@$OUG%Urgy9+3d=lC z`j69Wl;X@5NEjB}U)Bj(EZ-<8mYbcHWVs{uNh>0A$np@o3G%0uJon0?fH%=mTyNbk0 z)&KdMnwGhMU2ok{=L6e7N&oK{ud2i0K_L8^5Daq}wPhYo9GrY-mnpO>>wQK%AM3>l zGu^kZpWW?_a}LOOl$NAdHuv+=H4J>9gSGKSj@~%a{xS<~F$g3CS=cEpfW!;psrecG zWaZ!{j<7hd^PQuJ8+YbdXnu@=8Eg|`R5=UJ@#W^S+LL=*K!Scy5ky(d0Ot8k$n3I3$I6TX>M2wVC3En6_&wmjnisF+R7fxfoDfWdeB z4vI5CL;|?vb%K$;#dS)zSAHr7l@ibyFEYDU0G;Gthj*nalOijD>3A8j|OJFi1}>McRl|7 z^>^Qf?#Z=ro!I0LKM$`mX-=a;>`hd{X@Y)%ud!S`u(El?V?Hn66#$tPMg&+JNjkqD z_nOOAw!S)75S&ynO8pQ8{c@0ecHI23p=AXLM*g@MXBmQpw_+6WeH6)uWxzOM)i;KU zTJ~Te34Vs$T()LW+p(cj10(1z(6$ZlvAD0~iPSS027z(a(T=d%SMN?p-flMhNY|>* z*6)@QYg3WCUtppBBw17DfWz5PN;4r~J8z$zK1_^!)v=ybbZC(Gd&>dVPU7dWI8oGj;=+RV0 zJL12$0^Bcm<8TMrQmJ=L@;b2;0jzS}v(SCt`&Id2Qm)!+jq~c`3Oep!hx?+tiYLdC z(593OUUZw#j7)5e8&JrOdalV_sB1YB8B|j)-+kqHMjWwrU{P*F15EPrKZ}F8z?JQ^ zD!uRhb#h;Mo!bt@!7EqeYLEVFIcs2-Go7qp*-;V5w;X}9*;7) z@Vb#LhI9mG9(O$_@ayOXqYL9EzPoT&Vli8=@A3o*LW61fi>D1%f(0S!{#1x;jRK3# zd|xAi^i2JA1v;g}M+8Itk;32U0Apa7ll*aEF5Y8;l>}cO_8rEXPa`t4GoqxGbx~}T zDkcut7IGbzuSx?KTMWrv@iPDcupT7(=t=P$xzJTKLrTuNu3AD48n+G4!8KcYShlE%jt*fu=-i zHbiJ;7tj=22Jn7cBPQiq>Qn;wfyCIXrW60Bc zn%`M~9pf;yK?Ouh*vX=*?AKS=8{s*7V5HN%>)|(@I4~(GxSNUttOor#sSt}J$w!V0 z+?)a!ztyYB-rN{5ZkyHuhr#)?SKUu@469c1#)Mvf1sLfGJ<2H1d0fWPm zcE9&Hg)q=bz#5QH$hj9uC$t?PAs7SZo2Ej7RB>3IGl19Cw+tF*0)OQOrAm+ysduNjDnr1(7-M z0sb~_@x4<7whDfFG2Wv}36zdBh=~Kf_=~%@by3q9^4f(~Kdu)~{`ld>nh3EAR)NJ1 z8G?Df73tO%ZE}>#(5T;q*)vFw!gwhG>=I5Pn5286Nox4naTS+jzl{5lQ4;?V)V+4* zo$FKGT0yF_{btz}clz1~HDH|#+sO23Jni%E-voos1<5WlMqtP~w|P^K?a9@g&5;l= z5jw%(WVb(!&QQ?J-#x<)3NHg$S5ud$Ndx3b^b+ux4umI>PWAkx7kk07=i{maUDayiLP4ESfgcX~$MwKpO2f^)+5+SoOj?JN> z6HnVW{DC`JrHCE2Qztn8L_8taNYOULK-hG1~WmwaKiSMy!&#K$SPiCK(4Y2 ziz_V!Vcf2tBHeUKWfQ}+-QFNjELDU;ZqZ3n5Uzv^T3&l7O>xaMINBv2 zcVn>Q-FvgrGus*r{tL!mUp%u62Foshm*2)^Vchu^1V4$Ql)q?6pn8Zq8gO~YePYN zn7gJVjzpsM?sC5<&B1+jo8LwpSeUMQ(WYE(VtM#l_BoiRpv zl|jB&ka|Wy0W4^ya$d~#gQps5J)Nj@Q&X7olnW`fSppCRiW&c3Ca=0h24TE!E_P(F zOy@%;?2gJeB)Dy(0&}%j*YPj@0V&Y@+y>zr;l2SzWJg&(j2&!*uvNyED56=Bc_|Uu z(t;=apWLgp)@Y$k3oE|lGP$GuJ||rT%UuFyEff_upjYhMZjLR=P+P(U!O;y?LoTyGB;$S#IB!>g5896!Qy8WJ?@~h_pWVwqaCYpaK!5>g6&kg zLcG_njuzec3|@1!Z-vG?3(#?roLbwtK6D!a)`e$$-(bOjdhYV}%23eqb4Y5bnA=G=J6( zHGFKcyE6RIC5`KRp|||@5E{>krz!?V!zk)j$Bo%z4i_A$tQBr?Vlc1qF9$^gG1R%A zOL2vERpRiK-~0o8Ti zUcd%V!ro|#jBv%Tqe@B!?2wyUgbQ~*g;~#5*-t$*mFQDN;(>pR^MsRS7Yo2f{YztB;+h6e)kmQ zJQFDhMAJeoFBf(877>0rGI|BhguatKU3HCl>>gCvsRy)1`n{ zU0m4WQtM3Ckb>^B0V4Ugk?B704C^=68bkhDptv)9j+B_9pQe2obNvZ=2XXj&abOhH zOijV-;T5MEL(1$n2X&YEe`tH_u&VZbebhjhq=a;rpdhJqH-aGI5|D0@5CrKGCNKq* zlny~rQMy3{nWR!GN=phzNlDlJ4BYFiea>F%+~2+Tx&N&FJX@3*V~p?nc|ULXN4Me9 z@6<=n`tOUI%XpfR*;-vV^=}WqnfO1qnPfX5Vs}-cEKm&phmH#QlieM zL_?aQilH<&*6+@cwxnGpAd|vB1kP2L&NbkJB#O9xq>Er`AeuG)I}_R8@XPPa zgqYRPQzIW6aiBt13Ha{&;ynoTZH)rkj1ewC}|v2E^& z=dNE!MlxlT%o{yqS+jj#tR*@^P#y*cu6Z`Kgo;rRnzFQ$UP`FM+|ouEa$>0*RyvZ{WP0=nKS9n&#L$s zPtnGi+!yavrkUfQoDv-C&iFnJY47R5?fVkP7yrM0wP$T$*{AVUFsnCFSsl?6D4nFS zMGJZNLm$ScMkBzED6@|d3jF!rH7XBCM+AW-0wMsVQw5dm?}=yx-VFl1cE;yhwX5yn zRWN6Jb6~^!;ggyNk96`yyV%ayA5;!bLlyZ05F! z=OvB@8)qH5CB<|VH^}Sjpu2S2ibQPeSWlUq?pk8~ z9w#u2NAHH=B_wuScY_5w8{OQ+Y%r-7A$_6KfM6d=9+Y;=2m`9Wi!DC-Vc*|B%z?dp zU*h2pNcV8C?<=^(b0be+e`j6zA-$*wqon&qFd!CtK}^=4?^$sl;!Co@5Kr*MP6^UW z%n>zOXMeF}C*sWp-;xca1)S#jKnFvJa~^yW3TK$-AlZZxjOEv!Xt7Jw1riL|7rwQL z+6E6*hjpT{jr+HIeQ3*A1X3PFso);HesXi|^9AgliRJ!D8mj zlg$e8SEh0yivS4)c=QS`LV%zUWE#D$o_(I$0dA=z=d`0w1^!Al4T@$s{FWM8`RElx ziE}5k+21y0_WqGIos(!HgjBUBgTo;gEJxTCP-+O z9KC$-X*zT|f+w@Z2F6Aa`BspjEuklYX~AbL=_D2%Hmf(?;vu(#K{xkWPPpGb*lz|Z zEc{wEku46>E)-XP8-477OGIOKv;6iHb)rUw=L9}D@fn9Qu4WAVfzpvUageNhkpp}5 z6@Gp7NBaUy@%U3_FNcitJ!MMa7@#l0cW{}*yPS!96i*5s8DN>0OHkFWP_;dBR zvxo&v_`=OH0oUn{;wi+Lk-r3~j?9wo6HN~)BDc%s_95_%x)i>pl&*BiRG2jfR$-QE zXKH21aP0$51%#EtBO2K`>7-3|A93#l7PNUT6O zQ&TTQa@d{f026Gdjw+*d6z4Aq3egeIr_u?>H%?I-nE`Vo`o<4Fslj~|Z_|mB_gKmv z$&0v#QSlkwiduwl5K3F359+>6#jxca<~kAUQ2zM*A3_jPC5TLu7PR*7O$Z0hm=`dT zQG*JuWT>!i=he3;0V{gJkSB8Q%I=KH_CJw}xx|8pNCoBK zJS)>Sk;`G3=;q4LH%lodZ@ru65LI?!jWL*7P2Y6d{sQY=MRo=ZI;^YO?_{51z+CLM zWn?{s90UU`#1oJVxTl{?n0NpYg$u`0T^D^W91;Qj~{4ZdHqRw8h0X4r_ip>-Y^t^E9UeiaYd_vRH3 zVPq1iCZ_(p0g7A%tZ73W0N#S>d-_7L_)%mPuIR%-?se8nns)C%JLly4jNwzcuzIX-#>}hvSI4l zd8qSRs#U*ksSDJ1lLPn<;fTzzi$5}YAlud~QEM9}Ov@QfWe5?mWIMe?aiY(0k}<^1F|v|G zn=X?u*6AakXUlMD-QH^ZVln(s=}?ZHo{VViS>E0TUtwtJLbu5tKa6CfgX0gr=B};B zvG{FHsnuuPny#dZToLOjlK9dUj zNtKFsLy(MBr|u-d#!zOq=QLx&0`BH!&{el`I~tQ}+O(U@JXJ^iO^#uBnBM`iUW)I| z$7+!Kl?t9(oIwVT549M>@WcoPOOGNplz3a5?sTd{VOM~ z3_)bDrMd`Ab90Kgs!eP&gj~6SCFJI5srKXvs{Nez!b{{_gvb(pCLbT+6cU&y&R)EA za@v{f{AI~#=gCgd(a3au#t!kxVJF{ryZtI+l0xNzOxLD&SMs)9$d_i}@OIinVi$Yu zTZPTK^zDWoSKsH@A1jsfXeX z0Zsa8y!Dj-_dPh!7DX~-c67NqAZCYsEK^4b0-XW2T(;R0!ff3gc$%iidxWIGw&1~= zOnF&W_r~Vc8-403GKJ|EkTBeN4HcDZt9|)~ecp6n1=avStV9cU*F1HiPu=!3JrZBC)2v{Xj=U_D=UR$+jnr3<&=s1S&7TVMkBzp@8}5*8=)VJF&S`Hb?509WBDK5M@`y#fu7z+G zlX|iH0H0K4UXac!A~OfO@e9_8zowDk>-*;-2;Z!;k0ajyOSiuW=swphW(^0&nFi@C zk71XvT;n$tw36<5vyi2Pbw5vve{b$fafYZ#U!Fk^k_7r(HHzuEUC;ArgfwqO_;QT6QB1aCg5*zWHBo_8uHcJf*m*0nT-=Uy(^|B=M4wjG~ zJpXY1i*Tj8#Y+2sex`n4XNh3P=_kP?LNJwNUb%fri$e-pSD!-xGiW6)Rb=RA%J_94 zsjr(oR0!6}Z-*#^J3~i{7bJ_;Q3fhy4Y{h|sc{AV&kiKtLD~S1$@9ru(JFXocLF79 zi%Y_AE9Ih{1sv8sh8aYIZUDbTAU>@INz{^No}rcXuYJ1#zJ7}#%dO?{X-Ill9%aH? z?4}8<$hk6ZdbpD)K8~j70LWrb{j?<&@BLt0bGdjcOd_}6W5f`?hF@e2vm=tl&$>cp32z2 z%Mwm{+tW1zPzid`t;}HncGHLV>izc@?jUk31>0wD|%8~&M)nr66ivVc#k z3<51ag&w<0TyP4~gmUb@yo_1zGJ|&8{B1yN7Bg#Ju&2BN1J}a5b$fzA@%vo}Tcb>E z{RMwISdS_LNH@^;Q%pfB9V72nU9-~nplI2CM9~mIH`DM$y!d9ZBK3l*6r>AG+bOCv zj$<%|(6EwxijXP^uEPINUYe^@eM; zf;A&|a1BD_j$)yuspNf;An87&j5U)-zwA~_{?p)@)@pPcB{Ee%yq+Ga*7VmsdTsrM zC*RKI(h~L1vUIJ+dsIZI)zGXONJhGhART5J(g=iL@2k3X!A>5{=+Z=1>^Pk|o;zMg z^U<}g2ue?rZS#_z1T>PS9&UFBSS)SIcPxM-@CNDl*DS`BAXZJ8!#!7@4kY(l8Fw?# zgJ{`?6+_C_^_o%{Ee~r&hjeOw6C}d#49_TV3KkO=X%EthKt{~d8wE?Z#BsLxX{~|05Rnzwowy%St~wh&1IWD36Ua81mAhCiv6kqAhb17pj4Gb)OdZC~}tXLLl2Cp!_=76NP| ziJL(ADe&X0+rwv+9opFTU|W211-1uB!!ZHQG=bm@hJ%Ly}I! z*Y{ywRw#wJhPMa%O94?s-ESwxJ8;&1EPKZ|1WT|#uhK4&yis5@&>PakfUKokx$L_k zcnj+QEXqdzg^GUcS+RzvVJJm?@;a}6^RVXW_6E4#9o~lg{p|}!EXOoUo>n~nGGB;v zjFpKJX+FObN#9PO*x7;5wQRvnlGFObf~=?$yP{VX4-lnAk5MJm&F#Xl1@7If%HWzZTu1=g zkA7b09-RdvREUHg(Z(*(1+v!WX1%2!$}o4lf}8#BuVeN5!pml-@b&6fNirY4WQ%Nm zYc~%}yMg?$Uw5{179MY9m$b(>DqiDAees5(ucQV^od0b^0= z^o<;65b4;s-B;k)@`%wM(p#g8(!&Y)s@{FcHxx}c@Ap2IbAvxatUyuRBpP8MuK(a2 z*#&$!^ko_u@2sCWv=Sl>Aa9NddVz_%?RteWZzqMa*s*cI|)gPg6B@ZN!Xda zXBxI|^BgM%&gL(hEecSvx5V{S-Z3qOQ#BdD(=gxd#h>NIZ`|F93qZLwkmmMT-R8%~ zEE_;i`0I_jVJt|b`}!HO6F)M;u1ZxHym$?26`MX|kMizgr#T%ffJvwicj2%X#nAWe7lIUBIx6N1@EKiqmT#g6a4E zq++xQ-)8vGX<~Yji-0|9OnIAdkMQ?@KIp^svj2iL0=%yxUam9@-M;7%u}gbyNO(W|#@9jH%>@Uj|T?(P&B>X6zR3oc%~J`8+r@urJ5Fr_Px1f~N|lBm@@DJ7-9d~}Wd z@q(57zXR_K`dSegq}u^P0z*w5@K67Yb9`Y5=-CF!^xOsNkl4Hs3<4gKUW6T&2#WM( zbxP7xzQr6w%!<|{$_^J$m=UA8uU0>;Ky_MX%giv$4XsSG-bjx-zNYKZ#JJBH>NzDn zzGDn^6}^gW{^((dN=$KPLPfCtTu-qtC@v&(0fOuSV`8M$;E0F!Mrq$ zNHx|lNuuAepGj5GN+(9>5{E4S>)$9MyS)YADd8siI6fyS{So45#W6mQWpg;#+ZK$< z;>SYG5SdR@Begk@Y|D?@3Q!uoP6w_oY>^dQ4xh;2^q(T|5y#Kvu=*@7mi@XgSm0_4 z`Og7=;BPn9reSJg)&y?8bFkdr(pqk7<_|q%O1-m6BB(97@LSL3E-JD8+cWT$Ea#U_ zFHZ(w`7a?Mn3N|VaZqbmW*Ki2u-CF0>$4=nQy5m9%-{woR-ca$kjZlvYwq;zjfW^i zAeAJ`_|>G(f5)(4Nqt(G18O^mE1k!&{XV*6ROU!%9HlO)%pnBfn9n>C4B*qO^4}Z{ zs2_l<*8yddiZ;AUiz4xAl3dG2rKjreUf&sqkcf-By$lMuf(7Ru1W%Nk95}+mY;KO5{As-7TI`wm(@1q*+(Z|^3Tj2fOneW`jZ+4xq zfL(!m26bQc>IWW2gDU?o)PicpYGd*~+cT{4mjQh)h+v~?VxI*IC=LdR$kQPA>G-|x z)noZjjn($#4L?&oi{fH9lcmN+#1$Ubu)heSEtvU#Mm&yDL+`L98NKq#kX@^Nc`|78 zi>`M0OlxWQOy0fuUY8LeC3f>d$;Gm`{bBK2)YAp{F^)&bB3FVq2J_#L1%4^Jp{Zc- zvfP)d@{gpVo<;CZ))c3doD3=)lGA<8D)Aj{sGiMVRFe9)tEND!^Ya?kl)QcL49Jt)m4yiFGicT_vE!Jj<8$BpC|r{{MbWFv!;q1zo7%YwfMnGJ zKZf$};EvUtcJfe@#LZ>`R+qeOWd#BSB7DYQGh898O$9))iNvw2Wh(s~UsL@|$$D4$ z=!vBJg0&YCGX4ZEM{B(!{v-7F0`Xtt==~iiCO}r5JlR=C3%@^sz!Ri^;1fQwihJ3E zfyRPAq1S(`E&u!#fQ_i=Z5Fw7s)}&?D~6naeZhx(@3+RPS1_xZfA^whcY2U~aXyuW z-jCBbN=#trW zaD@V&B;e#^+(OCwyRmK6NIO{s2iE9~H3e16&(Zn-hvW9FAJ~r&yjyxG1~!U+A|t@0 z5TYW=|Mpj`sZoJEOFHm7#fxAF?%D(WO&0s-HDu2N*>?T>kDkJr;4+U!QlSqxzxg50 zOAvuk58*wl&6ExBH=@NZ$EY$1!Y}vf>SNf2XN^#}K>fFp_wc;4JN24$>ha%U$=sbD zAnw0jbQ%_`*zbo{Em##FNq0$`oxas@qRJ$HRyBSpFdmA8#w@oVA6d;MDXEQ|@8^PY zv%|2=>OJ``wKhXv)*iA{4aPfNG4Hkh^V`tg-dguGqKk^yy4DiZj%-WUYZgFvI1SB5 zBK)<>L69TJ?yci!KMck6iwd{ z<^{e}NgfE6w1j*~n|X7qw}OLQ1c^p>ACx2M^H6Bjn!p&aw{l}^yx0LS%7PK^GhZkG z8}PB%FLh(~MJVRC{7;hBZjo9WdvIcn61JonH!JAcNhw>thCd z`b8}62LPLr;A@a^Q)c}@{SR{(jORj-YZ=M&2G)srfz_~Q%zL@A4R1E@swLSZEM`RD zgG0Y!^+(#N5LA-{ip*p%-5Cl7Vvco%$OBr;7f?i90WLfNsGJW6&4iR2KmNtQT$*^e zdmKIZUqpro!koWP)kX4b^>vW3ivHRb&?Nnhh!5W0= z57{=`w&LHIa|Q}?unz+KeHQi~!IS^u43jKtZ{pE)^&hlB53F_#mN43he8$K&Xq?)R zR2>lD036w(2j>FbKaP9o{PO;YF4ORQ}#^$={e$Eomx)S=@ImIqfyxgQ$j z7K>3zJC|m1B>)FGG78<_L=}Ikxo2MrN_G7PF}Qf?v9zJiZHPhKJG!^P*uH&PXk&4x zua`pc}LQEov1S{6vUBABm!R@h4K{v#`FaMgJi zl(;KIN5x_(^Aq`mjq5AV@pYK~32@v>ruUUZmC}QJVZB12Xmdq5u|E9~1PmvGIJeu| zdHKf}Bb~5~CU4fs2~4ya%U&mE49ged29=lN&~s;Sn+z9C&32a50wl#z_%+w71XP~* zqlgqP;;TMm0-Kt;1f(|B0vIBS$~<|8ZZU-fhiH?yOz|vPC(YASS!R+|Lw6dr@gYu5{``yoPg|`(vv@7L(2tH%k1`1El?-oM5gwjX$S}@rg_Nd z@SusXgl(Y#k2!KtH6CGCY+zqM4P5ji1h-+Nr*E)^!p@k+=g#@606exlpzuVtPffgr ztrPwOaS%O68EowbQWM2sr7EwpEF;_T-5ro}b#i01#HY^q$U-B0$k0Q3xK*576v%q@ z(5z0P16CBN=X5ZuYX1Oe*Zha~*pj4uDz1Ef_s(}^qWSsd$LB>>RA_J-AS|4gLg>K# zY$y>eIsF&*78nfahddyC^d?#0mgNYQ`Q5yLW}jtrjB{{yRI;4R~vB#i&ha z$W@{}PYB9YjUX$aILifS)_Z<;>cd6`sUmO>kBmiWIcizdQM89@N@OIaP4r>M6h3~` zyCxbN`q3sY@zUMzYN;hm4FF`#axOp4(^vd{HrUG+Gz~?r`D#|5p^s7W4#`UJvSnRA zk}@=uiav+F!*&DzTytZ2GnHXK4t*}Fl711RmhMR&}M!YnOcWk$R-Ns$SlKE@yzQ5`i&>+K(AB;Q z@p^xEtOJX&;w-=)DNsoq5SR91FwP& zzdrsh2^}i?k*gWLtLpW)g2!D|CF@sO=nwc~Kssk9SWx5#Xbo$LXvfMLr`Q{>>E1&s%?km!Kjk|W+SvfY^(zXtL z5BUNUibJ6y!2yMqSVKW#IgGqknmSP)j-UX-pZEz_NEEC$#-HOC4vG;++4?Ud7$PhD zvYjDpOMkxSMHFmCd>jUVfV>mJ%+!ANN=j2#^Ps&dQ*wy{>tcKO=>^icDmCBk2Xq0@o+j;n*N(Lw31eKt^SPC*SgR9RIr~m7SJ* z2CHId5<)}IDEpLXz5@xy!pt+EJ6s&0bVG3srq!_9JWB3Ic=bQWx%5l+39|#GwnhUN zDu*pjb-=7;qx`TN;FopCAgn`W-v|`dr-y@Z#0I&gUUi$@=6dDRJ~^wHlqmo>u!=w*Q?aJ$Oc}ujIrs5V^uh`R~o>Yzu?-gpg5rQL z*9%R)`GQMpV-F)UMwe15L~ok`|dse1Q1^S z3m{A=XJ^nTJf0MCL9ADwvlo3~NlHq#x-8x*}Hire1FbF;( z8S&CU1Oi?rfqx+x3 z-JCYQq+75R9xLR9jXRo;Elfu6!6Jg_1MS#kL&MWx56p2H6CpVUGID(M>+0|Hh`K1~ z;Z?<2fgDP6IWY!S3`$Vpd)gC?5JF3wxv)SMr8sA$x$!V|@|3XFw)-rNlQZv9Ro*H$*O z@FK{v7pP#?Sp`36>TJ&o!_yCePEcGBtRxUD`%OtS>`RiG!)~S2HH*{~R@>@o9l%m} zc3_wAYR%A=LfscAQMCwXSclN#!Vrs~?;<-Ek!A&C)O+=1n`!}UktZFr-f=d|MRul3idHNQ+836y5v;V%=0 z7D2B0M%ACYB-zYcK|^cNxUQxke>W0Fn9=L7)fl0$xCI?R#q(!_(bOFHtjf~(g4pp0 z&q-1_l>E-+IhD_(gA2ffR5kgGy&PUYm_D z1d)ul`W6F7?5PmN*F}vg<&j?tw{?!VP*F5MqkA8v_`?KgldY2y#$nHTkv58NHXR|T zw~VyoB2ux%aMEVi2hq*K>eo&ueh>E1aA%skLc`^{{n7)tszoEwX}Z7vQzhO&359!Lk zEu#Uppb5~CWYZN{(L#*HaUK1M{L8iD+b+?ZWKk6Aa(mtuvn5hC!A2&Du3IzBRnKL) z@}vU$9`YtI`~8Zk*TCd~03CLIeRdenf7|)#27F*(?ga>v)T+G2V*fDa44Sk?a~@4e z-_go0$vGZ0K^gCb0jEhAh>2>i71MMF(FmgNc-wVbM#Wc~4MLw2g9#1YYlsz4ujrt<#i6lG192 zgG{3$!>^*7YxTDd+!)yDxU27WX0|Kn>g4j8QS^H~E&@^d_B%DriQp?=jdC8F$vH+mc=B);PdVIzJY3lJH43m6NKWuVB5*RGmBu)3c@}W-V$zMN2GT? z^-ug#@NfeZFD)6w5r620A&*eLFUH`$?H7JxlC}%q$t9q9(<~k=(+^36%6^(mB_!Npq zR5fZw*m3aU?hcq=D}qjp_-z{RZe~aD2~nKY6o5k|8~XSXFCaxr`P7jj<0+4pOY!TW zqxbdViC($331ql4W#{FG4>eZwMc^(Il;-(K`|o-3+zpg)&CJcnc`Zw52WV`%crC{} zVSHzGK#BV~J8uf9Ll^sH$#Tb`-ntPWi}Gl2lxSV|uYJ{H%Uk}3lXyz+;9!4uw^;;D zyrd#j!ips&2d?hvde@jsmcM5MDTSwVhSxOhkxAgRIYyxXp#*PgpI*0lvIng6z*-Jn zRhTl(NjuyxGQ;x_C*g<`+^l&R!iO}cxQde78yi246a8ARWbr!7caUA)8lu7!K}A?H z(idiQ_dTb(Y@r?X;5=-h1Q7dxc_>Cx=_8_`j*2*s#hwUWzMgRkS=Xe&eu?vr)^UZ1 z`BhDA2&K^lUBnvPy{)x|xfz_@Br#!ql--%^UrUMls0%5XYTeLFv*A1iMNB#cQKB7h zsqa|Mbfqualiy*f`MZx~Wr`i?r&Rx%DRgWDuhjEwC^5Z_VjU@;%mAr*pdQ|eGibaF zwTZG!(VfRnn$MggbOrU~kiaFgqPzGzvreA4YJWa_p(l>3fe(b$d} ztALPQNKx7lU!d4szl#BOs#|bV<_9*GsXm*7XTlLgMXid3Mq+oy%n8_y$PRchZeeN~!fXgDI!)pE1gCgwjN%%hmTJcwT zr)@%#Ve(s_V~I_QnvA27|&#VwqwhWSRu4#54gw<&bUF6{mN#Y>(P; zSS>t9jy0@6%R|dXXPS6V*EjQm*tJ*D94AeJL&(9u+gC)rkljS4AQDZhj`#`Enwd*Z1HA4T} z&B9NxzjesmM|>P{FRd=Wi3${7C~91=FL-bCTHt*K=Q;~M;W{TR(OShdX$_%^H9HgL z9NX&iz4^NSEyFb?Qa2gH9Yf|Re54L;^GG^LRu`*oV*DNB#(d77%p z#pQ=hbRi_;j?YrKzTff7V%)1}SiRthUCUbD8Q*8+{Zz;m+RB~j>{qWfm1UCc`%lnH zDk)%p-qgSNWneTBdRdA5d2~{+xQW7u?0jMUh%Y>$0dHm#9WBYeKkebZ{%^>zZ~xr9K(W(TSghQt zG$;*!Mgr%x7w@;~;PsR=l*J-%$>I5xTqP202{piJeG_~p7#XO4dt!+Jz;s>0EhMt zBMTP1N4v{e_$+jI(927GS_{u^Zw7!5HMKh-pQQdCa_EHffCBnAj4^PdYYzJBH+-*= z^+Wg_;AlG#YaB9-xqg(#OGY%2NbiE|MJ=4p3~9-yo3lu380;P|0X0+m%>SRqk$msbI=_5s0`8~$L(omt2}i1V`|vvKP*mq1TL@ZwE@8*M(kpaAn)09k zQLhwWo8f6wq3Q0-I|%$?^82L|pvPd;PHhf@>U-`DFx>opq|IwRP5Mhv6kPH{+Ysaw zA!M4#LY%Q&yq8fdSw4svfb!;_Tt~WXsN7vb*-W4p-0LVc)5JbG1rvretz9(7;_OQJ z`W=Kyn~&E(ZCo4D!CUOeTo8a5nL-K-Y%kD)KiZ*Y_PJmdH=3LN2x3@&vO7cg*K+hK z)xI4hK8<}!5wr{?KH2p89ky?ex2KjoEpXwmT3hVMhRY-bM2 z5Ev24n`qHGSU4k=w;R{1ai|wkMempl`+ydcVZL=M6`t;>2`EtNfTpj z46E%Lh!fU43Yf@QE7v*{2)d1j_@Pe=f3_Hc0*5Zx89)*KlFRU&E3 z-)eF!us9wd$hwghU)`v}!C-h@FHhfmuCMUUO!T<=Q$Do#gyU@(mOdgJ<;K#9czuFBpLXDuS{?#5{^w zRRMWV8{=ealqiI6tww~9ih~#~^)v($uDm|uI3>hDc>){@DA?al8KcL=*@{(!EKQ5w z-MsBNo*gPoz*?gEZcK#vOf1UsA(_JNEuMoCVMkto-jjUjo>Oyfy10X#Twy&z53Cs)`Xw-I{zBrl^Rz!ywD^$ZDVv zuZlPhC}ElID8r3I7FuZ!3TX|}lQdIP-~Q%rvtk6yjLCY}-o3h>Oa9xm{PAws?~ecj z|MM^RaR?h0>j3D~U#D6HX|q=Hf)3%|8~Ev9g)`=!?+Eb!^HuAhDZzbo^dTYc4#ava zf|#e7{^Li()zSMvQ;S&dBPmwRSb(}V?RteKj#|>|*AY~RL{=>sSF8TVFNb6}5;V=? ztWpx_#VW|n4UTN7FpG848IT}eBz)_V1$Z9hmyC=Jq{!X0LlXzVTs3IfLkX%?~yl0R=x>xcjSSAV#PZsy7awZy)>$!vc53zE#RNxWQS>1+x_=xxXg*Vc+T?{@2Ko_?@ia{Cvxv9XE zs082CQTwrWUTK^Z@r!ShnnT*t<6NWa67lcRiWb(RzH1K$+sbFc{r4#Cua1$q=LTh;%!7x|zFbZlJ?6$3Wz zOf(jDh_h=7^9(Y``f(T$-@rEP4=k4uQ$FQ!aL`3O=2T>J_%FHX2Rh>0%B)%4uOXfY zxp2R0pylCw&nJBY59>~_5I77V6C>UZXd2VMF}HYiw-qIkJSe*NCxgXpfAJ+{2wJA_ z&zL}MGL=EEpFRiyr!G1Ms?c(4L#OJTYEWKJJo4BDn%QPoG;j-DQa~GLA?!RRM=!2Gt5HqFB-M{>em1s{ z-a8u#B!OqqUtwbavbqWv{R^&$yOt(LfyOXDsd{M#k;EE>5Kn{lp=_rOVMI-G-+U{rp`Uidd(Z+Qt->kWtwBX|@sD$V7`v;6YE|2vd^|-b ziyIm2rtJi6i9Su36@^r`Q47L5^Tp60PqDW$(A(RgYpI@$P(60Xk?Am?&AX@AQq@qk z(&?69^z2&71+tAJ3Ip!dhhT9r>83um{RAvq6?~AW4osQO2Z0Gq2o)k5I67|Y9!YQL z^Tfm1XHie>8&#%Z6SiWhk_4L`Zb|)v_m4Huk4gXI#ok)x5gmOozH32Cg{$oJb1hpr z!eUp=vcCqth_{%i%Q}a$G3uQ$vw7Z6_)28#Wyh1=C5b_cc9hOCHz*d@ z=T;!j;Ob2_n%8Y^5~DERo90s{AiS=wp7Fh}AM?J0_}N47;x-ugO-{JXT-MAYDmth) zcz#hSsXH#2aJ;K*3do^?)3zKz>+o#wopa6HHJX*(n`A!JzijC@QX-VG3-Ji1PBc|A z^ZTs~g$2z(-_$eA!!<3vv@i=v9-`&2m?mLvEnlR0@?zAdn0a0>hV?`-9FTUc6PIpY z+v`+(=VA&$4$To`siS)~;;mif3pbL!R(&!{UcBug$mQr;NYnOZs4{(^!aBLTzw^ut zThnJ>rT*@KgS8T;edAwguDQ);LH~35^0`94NQ?SV{EyR9@{#C9#P9wxh&#rygsM>26wS((z4 z^Kw+rDiv8AwjJ0sL)#^Sh9!1Is81MMU&Fy7;ahwe)KOBaY6Bkgp~D`7^IyGIWxA!- zI@oZnM5NAQF&EfcUGre?VN#m`XH8G1J=puG;j-k9bMF1rYph)HPU*3dX- zsu|`6vUHNlC7)R%eLlr`$r6~Fv_TPLq6>)-mShg4j_tM%18~afbp^ZrSn*X#vR9?* z*Z`-$Y1b|?M;6@h=W$qr5i)78%&up7iAAX&$m%~1?#0bO+{F2SU5EWtwgp98t(Lpd zYz}+RP#Uou26T>BhdgM`ZAnw61=}?<`7G!JNj8+5#TStuJ1@`i@&KgxB8CRuXFE2& zy|3&7(q)7%BMu(7Z*Wph^!CPh@}cV3ABkC{GL?Om^LzV&PP|^otN|`&!whz;@5TXD zhhk{3r;C%^J8ngGjM&W@5ryjy&#UI8KY2P_dcis!e~43r?di!D-sfcG@4~LKI)6-H zZ~20^a)7TMwa(hv?5nKLKtDd|qPYft5Q=&&{Gm>DgM##m(yOI}rHm3I+7^JN6;_G0 zGMd_hcbf((IER$3t3Gg~`Pre0Zg6SKdr$6@&e~&;I@?q|P104?wSqWx8|}_3ptpYl z68XvbhSs1WiS4{{e;83($1so?&llHqNPZ%q%WgAIuzV7=f=uUU%3%w5;k1M}c zRm8s?2t*YB_+Sk7n&}lwI&8cjmNBAH z=|f^NGsCVRP`$RzbiSM;Bc8e?%}ZxOFQTZrLYc^AiDZHgZ&$y6M~JGByFBW2FON*erO&dj zukXNuB7V)RWHC@+oq?<+_wy*aC@(@j=`G+mYvXJ+S|h36*JqLiI0H>y^O6bEy7FE} zf6a+7=QgJ=$q=$&Qa#J-o&F17VKlXMByKZHGx};;cb&0rdE3MfTf=e`J4?_FbV&R2 z4n_sE@>z`muHzbNEnXFlIsQ&;zAF)?yz}jY@57r9CfDnDE{D#P<|~qjKdVjTZj2&@{Wit^=8A!yy~?3GuOeGD zd;3mEc???P;j9W5>yw?uMBaVPe6SqWlW^)@;I#g!uoKq1*MzF|e|_ExD5i9N{b0kJ za*H6)&qQ|ny>>WZj;l8My?fH=^{d+YN||~%3k9dyj7Psk`Tu%a;sEAfo_3U7)Z==7cS zWG&n+mIG{|g88UMKug9Madsj)Rg1H<>@^eXO@!Hu z>JQcn+r5@OW!N;A=o)5f-*;>?wG@ku7Et@S_r|<^9g|y{v0!%ro4q&i@o55^gTzTL zOK~+a5&vswPW4#chaxYHFH~9n^!TGRKm(Q6>s@10%%*A6xdxJb%ZN2UQ2joxKlL%l zHz$Tr@aHYoJ)8nCQuk@FRHxV#>NS*H6R>vDyu?@iJ@)QFBco2VW?NJ3RkV^7{sW>M z8>N)h&TjvWQss|=na)hKPf2-|?)9+|X`W@EV3os2CTRPw##twKBrQaf%e1gMcN(u9(}X1<)UzA8S`g%{%wvC#3> zZ?i66kc5QO7Y_uKs@d+R{QU>x+~}&BO6;XE{FX}pp@kruW_5yQxZH^GCRIbuy7e6v z%S&-r4Y?tg%+9C9f;->vLSFCuC4*GbnAhcQG$&AA zs?+9F#;Ix+$$C;jbKBVFz9UmHDjs%Z-|oIJvUzt`TKPl1mEx~jPc6$sWEID7dBnd5V#SeTwJ?*1@y{%(TIJSH$`=#i^Zl=3zu&HG-$6yFyuXV?y_^^=ej+5`VxX z#upgLnB?rtc>TGJ#EBd0m*qQ~*P&~pT5O>@xn05d{Vb^P^eqY0>kq4v28LjKTwzowZ`wYD zM;uP{zK;%8u3P;><@5(LTCb!^%~_rv0?rbmb2y7c(waI?sH4qsEgz!BXg!>dU8ib4 zb=@~h`;(<#Yy!{y(mLMAKH(OO`UA&Q*Oz|ha?0X~FHGOze* z3D)*r8uY*&(TsJw!tX|=wyd6(|uU64(i#>P6i2E|LylvoPrqo@{XZZ*R&NuUuV7tESGxFy>O4Y$?lyxY!1UlOHvWYB!;<#x z4xe5H^ttzGI6_L^Ytz9CnN0PM30876KXD8SdA)vke@sNZ<~ik6am(B1;}m3 zWo%kl{*JtVUS~qz_U;%21yxvu&fW80OC61`d%5Jdh~JhZ$=E z^ouUzK=knY`GdVpXO@`ocssou^BAZH4P-j^P;8T5DeOn%A8F_(dauJ;zI=k!&b3L|7cT#7Fb>n z(&TwvO&xOyiS?s%PYyVt*7n3C%sYUq$(6}=pQv z_(XM$C>tU0<=aYbvA~E;4exjSA}KO<5*`RQTIMcC6<7Z;crexaCn;FT$qIR#Djv%IcYoZXrmd^hH!A2yv`C&dv?A`yE8YzwUz$%oGmxfcGLhZY zCoWCNsn{Uc{59n`S7n`XSBLo?0rA5urJ4G!g8S-Lpm6pY)Z45!50%ri3&~25w8R@xiX(@ zO5;|(bB<{VC{gSl0x|n}Q%-LxBx%l#z}9Ng^?at;`C?)Z;GYg@Fa6xZT0oN6HKTZI z2pxOTcxE~U>J!+^B2)tZ%?^<)C)kLfyituFqhnyPC(-p@5+~e23O(e(z=2K3fZ2VD z%Zn_z^2t`UJk6~JXmL4wlSC+14%(6_;K$xCzyzb2K;^N5a}s& z+=FiNF$^);6MLhdOUUic>8^XkTb}^&7@%KSgvdOby2sE-fd< z+vX!4!v5ANa{=o28^87ezo8Osn)=Eb1XcDl&bZUvQULXI$5^RxOj{z0>Ulq-~ z_1|H*1wgPho#6>{a@E_@gpi=K2F%idZTj-(gEoeN=kC)v=43gOq= z25t7!k9+#_Ziv;B%Iwf}DOesrl30@q;CWsPM8*iWS+Pu7=Dz(xVU~4e>ffnm#CJn^ z(Rkn?$EV7&7h{Rj^B1m;pKGh8uNa&hetG}?u*FfF-p|>G6S6LDK{@QAWcqvlYR|ik z=dvg)Adolblg07Z?;SyqwE0#fk$YS3lV2g>LLoB8MVj~wmloruEota+ zB--fi)UdkaE*I;68$B0vPpm49ki3!3It_>_4g3;H@6Pn=fca%EqljC9v>^BqkFo}P zSKc+a828Sm9p7=lsMHC{kI2(+vA zEs(g*bnbWpEc_Y?9~*j|7|soO-2wuN_!%!+t%{-zw;`9HT&p+mc(6U~s4r+QNe;W;j^Nf;D;; zzLGzr_hY)I_Xxyidq-6*YpFVpj@U2$Ty($r7@26VOmRx=0p^drQ7;HkH>lyMYdYpHaPk1JMws|G< z4hW{RY--zgzpmAHAo7%=_<%K*`4^aMF}2bL3=?Yaoo5`9N~|$<;~_~N@_$D?fw=a$ ze%nQd{)TTJne!8S0lC`L^-`?+pgXE&Hp9t$RN$>KLN4Dm3wwgxp>qo5La!civ0~{_ z2=6!ok4)~XO_rYewtODqf*FmrjG?T+ezYE?_PYpifVmT6uN9ueR+DnosF#3m2LG~Z7mekK5xn;A z-!F^|NUk3^;iO44GUh?kKnP!b{9mt*tGvkF5fV(rx@Yz~84|6)j zU$ocL!MHG8r*4+tYL@oUYG~kGs4$ezuo`~CyFy}9ovFU<|5v1NK{X-=IRk@oJbv~)|Oy9u`Y&K1XmI@Osu!EPP6i5G&b*N6v~Y|z*Y{I2RW^M5^u0`cuLAz7|HR1-0R)51H4 zsqC)@c}I`F@I6sw8Ol{^9*8_nZ8Zf;iJa=c#%BIngOkj>D>ITnb<02qbFeR1?2tADrfGWU*n5BJXSFJ{ECabEjs&L_>3nefE;|v%m#@411 zZXOcG2Eqp26WYR-rVccj=-@Du===M9syp1{=6cBtjD>cWGjrZJ%xR3oK5YwXHK`q) zse#A&Ipxp4-jcXgIC&LPoGt+Md2Z7VinaV`H4<*WpRuZr6W(BUiiDa_#+ynafq$wG z9xIh8n8UQxQPFS^KLG!jkiI0o=UX&ILPGo}13&S0c7qB$w}w8m5P0_7!q!@Z-^I!H zrPgC*d>m@TtMFA-l(dnMP#{Q1$S<%kz)!L(a-5KmOy466FMLdQvay>V>0S21OSSGW z9ce*1GhZv=P~kqn#^+WX_>{y&rI2Y`1Wl72kh0;-v?We$up4E4oxmk^8#EF)Q#&HL zL9nspUiUeE`Si$F<`i`H=tqiEcg9MHH#=V0hgpvqB!4hQMS)H3B6$n=?+App3Q2!`9g z(iNo#A-R<4v;gv_hXBK-3TWvcJx zXE1=lgjlU!KIR9ClghKOsU~k{1e!jmM|v=kB}$JaAfd$`umeA5&7LOeB2+fHbPE$c z2kb3KAmpAtJv1hF1N=sWM;CfZ*w{N|b)YBn0R$n)>!4ek{^LuuLl56mu#D~?UvWa5 zt2dd_uQ!B!4?`acJB-ruy%B-tG+!yvGzjme${#O|UG$43i7U&H<@@Q;<3HVxTM{_& zd|%Z0oGfg*X*JH$`<|yO|B0V$I3Hxb&N;m^0v9tS6i}x))GG=!GMRzw-Q>e#kV{Wv z;KU99gd+Dbd}hXp{TJxQ^@FAm7r=E)IU-RjqgCBUsEXR4fF;5nML?GXq>9u4&#LC& zzR$0`NuaN37!{Zo1a$b;+e1<1d-rF`bKh&`n#TJduBjr#=n-BAlJKM1c~n|d69+(u z8XKAb-G0wpuox#UF`voP8C!uRA*$o~d-Dlk^v9&|8fw$%i#99A(YnUzq8bDtXLDE#ckWpC7)w%*pK8fE%(hwl)S_Y7p+1k&`jq3RA76BLZ zcRulxK3hdenz;t(^H z1?MLhrS8wTdFNKei`GfA2fRi<9fh4YqvSm`puuJ-wxX@B5) zRUOSCv$GpYB{KCvodQ9~4eDvg#2}r4LIK6}soz(-O(x>Lg`q479YFFY8GVjskp*~2 zpB;UG@{sPmN&@^MeAX)S4%h`1zPPYjeej8|qIo3)D(f-WKL|FNyH65Qz^c4=><9#< z-{LoSco0Wkn1(hOAXE{h01@?qYSD2IFRdw>Xa-hR6OQG1%ap%|r*F9&6&QTyEkJ;| zeIYaG11yuW&hR}`)c5qa&ylW97-gKa7%qEHVMA;PC#`0HJVl0q2fP?*EDQ;zbxJt@ z-EXYLu~qi+A_)~eIsxmuatCZkE?~#4`%QT>nXb)`Fc}>-@7jfnhVk80-N=iYZ3f*D zG_+4DH_Y0{W%f_&3>R&~wi)f0bkuW-kE_>)UW*igU;|e=jX5xCL$@5Nr!bq9yZc8)KaiGQSGz0j?#zKh(DI`?h;?F zVuyoacQp)jOVnBe&Y@tpfBi@W%io`N1`F#Z@=gh8NZS|i(T;wQK=AS*B2Jqp2#3OK zxQ7)kIklO`-MNj}qi`uIM$5j!IatJg4-{W9G?F&+L6}j+&i*loxZSHv5>`~O^ubIq zb>JKa&i2L@JCgoHt{mgJ4<@KDE2Y z2V{>`CjXFYWKqscVe4^?6y)3k)=ZkqGYl*`VaA`T{bv<*y+R57NR%{I)IKpA@@c3G z0177jY@F5h&HIp^2@l)`U!W^++$u*eSkTu)&Wo2875;4_woKZ%9C`)j^!EHABu>msaT?wHuA!~S41xQ4%x{Hq^yq{@1DPb!uY z5C;zg`qJv<-+cqs-_$!Eh8dAOT#P!2Oo|vBBoV=`@0w8Yr5g1$*ijd$0fumjpFot+ zCxs!Fu^>_|4Jpi9sBZ?p@u`^8!X~d3O$@^)0D!VV6&xOrX|(`o_~DRW;T3htsL>w> zT=pm-c+Wa!g#scoECofk&3PxlW>-dq0PcVN<{;>MxR!`0s^sCVdI*}+j>8VL`*dgT zV06H;-dZ3mP^xhWXE*R&_(3c_gN;d zvC;Pgf^_QZe0)$Y+et}$?1|b$QmpK;et|Q>L3{-mYm0*e>`RGYsR0H~#Bk*Q+2B!5p6Ez!c(x5tq^&El~=yOjX_B zK0eLE7O7DP(8Ov)$NiBe_UNgq`vYpa!HBB3N0O>9JK3@?D%l}O_&ALmmYD#~YX6QN zU+&HUsj-_J3(a_ zhXYpP)JL?Bgc(%Tu|^d{8CJNL!6z#}8w1=!EyvgA%7!l>q`acvHVL{(v@0Wh74S1@ zQ5!jh?#bwyo7lrjXsQG<2pA=1O~MnuD=ZOyKR#%YF|AfW>}1`q%$Y9gsPkY}JxZDF zXS^QkV3`%XsaVw64V#{W-K{ugERE)%jH>q6;kf6ic|;TqLm&N`FpK0O3*(|2U57cP z+993ZV?#|D%Z_xF-V2=yXT?Nh3hnVQz4PG#d21|>MR}JU4%FQ883kLLIyg&0Xs1{P z!=R}xF8PlOV{yB{tLOUS{K?jx`>?5cQ<6aH=nnJurVB2L3%80tq8-W_9`;f<=0bi` z|Mj*JLr)4_^;=9g-`$4UPZXNSNwBl;&Q%#`1)}x1S~!x~ME1)0oHlB~j*VM3jwv$= zC+W2qaADTBBRL)B#ua6=S9t@;$eiA8sQ$?JuyuGs*aY#mxP>$`a zF#AQ&G^|&ddUp8^9 z6L0spcrtnG+Vtp)MWB*8VmqNS}9V zHTh^Fm;U3pq0Ast!LXM-J9}5qX^_vmFT)~^PlGJnAxIuJ_u-M)I3h1#<#ToBb?)e;E{m+T$@3|ubArS z_m*epxLwxGAKO))xsV3P7F7coAsJs5o42{B|9H25y&^Yd$nz)JzcMu#>;V??|0mzH zN8I6UJ|!$Kpc?hl8kO|^epj@PwD|$YPyeITI@okCh0oMiTzoS;ZbFVouwu(vx9y+l z*ZG3KWId&Q$Hxf?C;H?3HsBfsANa)oX=buMfJBjv#lS{AZ|eh?GGud8PwXuv#R{V}`zDdrJ4eVxY*PA?2h zBU=u=M#b`fhVq5QfKY&D>866SIB^Y;XA1g3$CAGZ}+Y?`F zmCy0{u4+riie`~^U+SoM;puOEx{=AkpE`&w!3}H;jeI=<`NJ=USw83{j=KuTw+OdD z2eTeE5myfP;nw=+1w86c5{foX-QzAYE>P3*!cOFK_sSf#vV1k{>hqD{9=&~%S>9ig`^09tuH+U5Vndx%@eli=eDJBNx)iRU^fYPxRaZX$#uJew zE=6{}u2!N|vs@yV5|@830Xa8xT%iK^z2^&`QcLNzmabMdJVxu9N~Tr?)OYnMG|?R{unLqyQn1M1 zYPEK{J-To}q4t478S(a84uT&WW*QBs+6g+OP+Y&$f-YBI{vc;sFN6TazeUK13trP&f7whp)T|J zRpvhwBz{j=P>ltq4AF^e+QemjSbw)f$#TRIz&R1Anf~E(8r)0y<{oqOk{R#*@vUrW zlleGv=FJ}7`PO_cDq#YeHaFxETyz41zB7EiaYy0IEM zunigT)+gXpoO!+YC~d)AqsW|TVdLIP?8`>u7RT5S$rs$##UO)vZYg1p4$tbd{Zu>f zzGHu|`QXUe~5z`u?q9N45A(Ccqb+ov&zqWReT;;aJ&3Aj;YgR*xPjWBtu$uSM zphC;mBfgSa`Bw7h4rW#D>O}Uio3<(#B5JsXR;-)r_%Dy$p2L6^@}z_97|9!K>&=VK zde&2~A|^;i-2m+bUB7g%3hwmxT1Afr(^O^DZN|}>7oHc{ZB#9=8m9w4>E7%6r}wSj zqy-jR`^(;{p*t+c)q5K02NtXw%{We2r|e$`?6Y06vJuKAaF% zb{E`fP$;^4AKkG7C7AX`r?zaVV4Wt-(PN-vOXuVIX09^oK#~GtiiI>2QbEA4o*xiV z?SNMWiwt(GbLFONG25Z3cw~=7-uoHvC*)=x^MqJn;~FNRowUy79X4oN-w z;3Lis6oyA8Z`b{6ckwwj`4fqFp<$zaR`%hDt!4!ZH z<+r#@{i4?SdDE|^dTge|DA)r_SOvPnK=0GIvNRPU?2gxy?o|Nxe4FU;Y+UsX$Gkli z6n%otIP*lU;dT!bR*TIBv56Ufrw7NJeDtc>{H6%zi-SSetK>E;lw$s2jh2|G0flK; z#Jg5X5^0Hdru>^+ohPmpI9Pr7Q|5H!SviupA(T4SBEM5DEO4i1msUL;S7L}iLrO}J2 z7rn{o>MvtZt6;=VH}h&B9X5kB?JjNqic8~oU`nm)%&9r$C%JiV59^dx5nEqvnAoD= znc%)^_}WVI?lWph(Y?a?G#=l&-wsn|`xHM9s?c$Bk7aInViSatk<}lwvP1gB@b?eP zn&+QG<<6Ite>7srQi`$VNeOibn}mlaY=WK766S)Ay9(*~P0hj56z|sKfGj0%7eAOfDBj7y~7?tvBWn{^{QWx=4idWX)y9w-g)faow2Vo+^{jJCfHtj zvO|!)ffF|UXoiw~rn@_v}d6njm0m1e~eDr9dU=TI7_U05In+SeSN5!;0z+`xKUcalEnJHm^(w1}*DA)3yh^xc$Og4!b^8LuuY%}Df{u%YpzLdIx zftmRcTnae~vBuk9G(DuuW`PH(X$+UAb(br*7VWoMnfL6fWUA${Uh*ThZBT>mQql&) zxHJF9NleNciHKePJeL3OzIm}P;s3K_*!CE)4c@%bSz9eq{~a-6s?cGXfu&r*PVnkY z+gG}_+lwZXSfU?_h&}%MwS!&8$^L@CrPt2PNTT0MckO%-7lpGxCYH0g=EZkM+hcam zFj1IT#lVTb9F{r5q?d6_Z5c6g;<)qq;mGu%X1epVb@QE#v$0jTt6A4fQJ<=v8%J-s zYnPXL9i5+`zxL#tpZ=Wcp+lY41IOQ5Uy>pyB9K>`*mwU%7D1G8w9B9kd7fjWD_GMb z%hx*rrgc6oj?49nHTrA4&Os^pyHWjTtt7uwAA`N;@|5Au@}}hE7u`dnNAXBwP& zlN4f_K30~aVnxJ0QB0=7*#gQpe~uz;1?>OA1sjm_jo-2-+}FJwO(x3rb>dak`yN3C zW@>T4q&wfL2Fo5}y}a|s97Z%Ga6ms01YCy&)h=&g^c?$YHklLL20$V`ebhgrLbI`bkAX1NHoKW36iyG}BgNpmdja=(>1&O>n7!%^hE$5@*ijU*kCK)&vPv zS`m*;zrPxod4|`}=`W_4EoE)M5w3(y%KO7#f5@;XmZ0%+bT?{b&_)ngU41eZOWN_W9q6=_7@$MpXyv+_FcxpgH_(pVMx$N2SwD5%)JmM5L^mCsO0v z2kF_8UH4mgyvYQ35YM<{=I5;ocEY=X@AYE3MBe>()`VH6shiDLDi^5*k_DOt^^!r5%OYaLB~+b{UJ;nb7s6)A zhSXDjYB+0Lo4j?7zbxBt8l`7Unq-fD_I>Q_l|FByPe$2hC0)TGuQJeC&at7utZ*4; zz8*e^5B)k=w`qICh}qag{O2AUK-g2tn^CWIt0%i&T67^X2_X-O>{FRMoa2FBE7SZw z^7e204w5Q|6Ip>Wb;A^^_r*Hmul^4wZ=y}|wx)(K>jo-^>UN8W~oD&WKiXl2-vq9~o4q;e?do|qB#jmm2Kypx(n3tpvy6CNJP4_vX(jotZ!3>tqL#&kLl+!XZ(7X`_=@-mfE7u*rKO z7Jb#J`h7efWL0t)PYvkL>~)rXZQ2qg z0aHUQ=!u%c+ub6hb8i+F;ZvdTT@=5bK%V8Vs=wdNiW!NLbLiawu!6lt&y!W^~t;Lfefh^`pr;mU}$;*b%6`H5C zkdZ0>C1OSu!X7Dk85dd)tGBd^w$F1M;f`U~t9QjWpLY4?4U$Z-H81|kn(eGg8G5YpN#4hJ0jjH_z5Ozy^*Km}M#LZ)xG3$4=6m`u++$?l;nozIOU z+c$zaIH%~ESlhnj-1)tczfV96y;?xyG+xB+VkR`lS>xl_@ZzfV;0StO$Omga%$5o&_>5te04bQA!XZ;$33I_}%FL_>BMGz41ZFBK)*F zfU=`=Lz?CUqXgGm;#(Mz!X1E4d4Va%7!x9RMF+QWs%SG+z`_RW`SR@6$6aN~Pc3rm0{LE+*0FHGxxjqC2l+}j>Zlw|2lLI^uh1^U?MMPs z{sWo)QoiF*0P+1jFrf!XIBB}C#i;aNH4Vox0z%?XCG_^BkrI} zp80tOfD`ls&to>AbREwRgq4=ZfsQ^OOa5H-vt-aF?&SBn=YLYNG~&A2(+@O}*FYbh zn$sUpQLRUE*0ArO58fhf;)-0yp%7?KCi5B9-Wvo0F{!}0Y7j6KeiT1g(EX(U2xx8* zHqEX8#7Zi_7{CLS0RBX}3c$ugJo`gU!fz0(1RE14O>?d_u!)r4c$PoyADD;~AiOvT z1QhsySX?sbYWM$zj7SGg?)EJJCZK|l-~SX{GP3DtZA;M<(D@JK zIL2pv7@^>k2LMVu|1tgioMg2d9#9f5K)7WG;cSAUNW+Lw^PoSIRFZD$*RQ7t z1#Elmw@NQVgtZ#ntTV-(b3Pjv>vEOiGO}!ng}=}LZ(Gw<=JK5a#I<$3u1t@Sf-h^9SnE&L({*HKgWyu|rvOQRLlJol56rhTd*Ex= z0i-IqO*Pcb9>tlQt;n!;=s=39$Pjg7a+w@#t6fXh24?LI;* z5Xz6o0Hw0I0Z`>SK#+9JF`1MxnR1_upOp6&vD1d5q7Qxy0D2v6;6G-H1(Gk&Rnb!e za-;AUO4{ui@9?OE?`3jAeFQ6-fh8yc`?cj4;#3WUqV3bEF*VY#=^ zPz5X`o6cZJswE~(wI*4t|M9TIcl^cx4Z&*6N(^C-JYa+SnCd@Tg7bi?!;6rjZ{b$0 zh#vj-b|kSmt>%bS&(M)Vuok8^Kav{4K~;I=ER6Ln5X$^r1+ivvLK7@rtWfSzp~C~!rk|F z9L)LSy>4%pgQ zMitYgMjtcTLojeZ4}BzsmM`o-)F=_s;Fi7qo%}e?z8zW)R93vFh|Yn|gyHJ9}{qhqoa6 z#Iv%ee&M|V3dp1Tn8?K8c?u7Ogaiui6+tTBK30mp4F2_9z6dC6ekQn-3v6b_KAo2d z0`|qMz=h6lA(=ySd#xE^Y%+Wyb#j8#E9XTqj;H#i>3-!1P|n*L>{ZOhG`)ZKuT46r z?raaJr&-d)61jl};yLM+CS`eP$9?QE^cNKTO%HIs2MS<+psDwSM#(XrLi$~(29~J)h|Fb)&0<1CsQH(f!nZ;X zq=2cl%%q-uxQnxK>zad@0~fFctRnyoinf1s2MbiswYE8@djvYAB6Bc zgB3z0Y5|h;GTx8E z}x?4dgP8GqEMLu%vW z;l05mJ~YVfJg*bj;t2iy%^M94guR-xXfwQRU|JiY%hW-=K4Az+tYbYrub)XoZWdsQ zGXSbz^VUkE;P2Fm0pQ3*ii zqQA)Tt+On=jC$_Uk|23>P4yCSECx|vKtq2SX*}B5CpyKQLBWpvz2Y6qzXEPgQ|&9% zTda;xIe3Lujq$DmOoM0AD>5j}+Stjnmdj_oNK3ZQ7#OOZ7J;$aa_XfwF^<2#$Fk+^ z+4Gf~IRQ4z{NXMniSA%$Q2Gf2(Hf%wLJ`NL1Xz-(h};vy#wJ%{2I{-i>_<=+T=I6; zvG%!GKn`gp9v#g?R(NOrCs<63`XH1SAMJ}d8jtQfoCJ%G%EZhL^-OsMSn6y>*%@_P zIQWH?9fP<~f&?s!N#w_{B$GpENk$@@%6ugL21ko14E^9?0nwdkexbfZqY9VDXOA5f z7G)j7{IM$95D2zu+!@S%Ph8wqOct-Ah(Lh@qxMVQMe`WirQT;@4sLDmD%~ROrxf3t z$DY4fCTUzoYE{2nA-X&>2f{*00%kJ6*3R&4^3AvT)%u@p$XBtN6+1^@F9c^ML)ad+ z$HdBqk%A{KsKi)o+Su6o3Lw$!p)h&m^)B=w${{r5MgILRa$eDxfcn$;k9t8sO5&MZI^+A15GR$>=!#f#i}pYO ziqlO4qL#&Q&}rRgE;=0{N5IT_?!S{>8=)1bsn}l!VBB?}s7+8Wut^Xe@b>-;evsxL zr*&BS>wWwg;Ni;tRf*~s6`@FdWxR99sC?(wF4hAJ=Xfi*0^~;9ug-WT13#^I^M}KT z?p$kC1Pp-_urwBn+CK)lDpSh0O6*K5@eVJZ{X>j)C(+TGsGgpXgU6d*h*pdcmb8rE z=ouh2d8Wk@McC^;iR9-A(SQ+$C$cEpvt!S0WM+U3a+@;&%%LNR1rej!6o0TA!*V5CEP6YGKW_btPijjl7H7!mg{M+Vc)=j~#f zmgN9bg~QcjIM*wVM=8iC=Y@z=mWAjY+Z(JLX>OVjn5v%OCdzn^)M4f(?@4M+#FP`KDhXi*`sJHQyh6 zwObg{(F1_2Qn4QpCm`IL{OAQC6m^uyGDLzEJFGDA3-(mu+b5lO^X0$XJfU#cm4AA; zF;Z?4+sC^i1y0ycs4%crWIt@M>#jz*s`+e*bQ3b8+;PBD1W4iUHfu{NU@HE zAMaqx|HRZZFm=p`V*M45jQ}?h2z zL&4|}RYG5oSwGvJLeO`?^jR5;$%zv}fxOwHy0caAK4ecc2HpYv5Kj4P{+080e_q$K zc8kp0pD2dnM_0*j!inxMfbdkxd?d2v+r53$k(vH8GDHGS3(`Ozq`z}GkYF6C+V8#&8@#`LF*mM1rJ-=d(F`t`Djb=;0#}#L>sa56NdA2|IYWx9%NuJEIwsD&Noj4+5I0i0I~-@bKgmv_r?Fd z{#VS+j=x^koxb^d>K+iAik)@OUq1SK*56{qbsUo8kb_VEbE!NDPsf)zI0@4Ecal}Y z**S=j>*L?X_3za7za8jzN?zxG3`wh^8C)2sQ2fsq2UeaDm>|RwMN}&On*sJcP`AgP z&YZB_d5eb5qZ@c9@UO{arr-kwY}uWgCo*OiAF`yp#<_6WAduVhae=icX<12YR!J+^aQwdJ!bDVZwR zi1LFqiGClfj-vl0_5S+gOC4mG=k^(wwAl1J`t9V+A7_cHRTjhS=SMSbSyfsv&!3>F zKlRZJehMU4olwx=f026zLD6NMpPe6I`&l_2XH`VAbOQMH`iFE=w={#&r|SXyhE-4q zc=-?&h}hzREV7EE=Qb;d%TfT3Sj%QOs|e2Y9Mm$ZL3aJ%wYW1s(C5rbD~D7nsHOAs z0itDH_49fC9H4z&q?NDG-axq&bosnV!;;V@6%W`BbL+cDM>44_ZFKlVC7*4F2kOiMI2ht@ zlw<-N@^Pq`!t1e#N`U0x!1s=@bznB>Nuw)&tMH8@#xHs71e@bwV zLJ`XNEIN`R=lOuz-&L0AVoidN4os13}TDX|P(Y%Qt=gLSM!tPoRkoISad=%^H3(8xu zn<`Fi2G$SSKsDB|(W7Yk5`@)jz&InN%%n*T7`p4~6ZI7|11$6*Fjnmcal{%J_P0X7 zb}&IOj3oXG2S<-|XY~|5qdERjv%FW@_wYS1|I`+d0I>t1OAIh$RZZpAg95eWs(^F1 zMO$E53I*PAOd~8ZE;}H5w!^^VHLOy)W#;h&1loR3xzc?F3_kPLfuv&sFg8*L%TlkF z5pr)Bc>HpMwB_+H2&g_K@|4vpASyWisS|k=+`1|l1hkZl<`_m5jM~77$#v?U8T~6e z@{(l@a)4B8O%PztXb}!*JCaM#ZCH&mk)3^$z=_(1ed+IxiMF%fmeIl-jz%KX0b{lP z`dSan8XtV7JRO)}sse2Y&qaXq{{Ym#4?(7)T4vnvTL9ARQ+Wl>)Ng@Pz;vGPzSmC1 zt1n>rm${*33T9xm0NqhQJ;S=jQ*Eyb4Dd)??@Lq!1)qXrQ{QzmvQz+i$Gkk*-Jf~Q}2^n%cX#}rsdb6fYZ0>+)H*WN-==LFDBEfoQEE9DAC(**7?z(qN=05)F3 zl5b*Z#0P*DZ<4tIduuM3MHNtj(pwnvMqz{i2)Um8!yW>YNHDfh&$GwCl%m31enX@Y zJrTWY1L%DA10T17+_7uQ=l2XtG+Xf!N>r@N@et^z53A{zcL%U+%CC^u`k|Ey=t1J( zn0-}&hWj>A$m$_Jv|vF_l93@2IA=a%$D(4K{2~L^MrmvfzVN-HjS=s(Czzh{iOdf~ z-O*HOr2VSX^h%%V(KzqWScNA%uZ$;rTIW=18NrL+L&6r`BF&0*83kdAwh@+e>cH`& z#}0Lz0mWD-sGGbdQzUl=j4ecxWRk1f(OJ`cJZ%K78&nbdz;04JlR(rP&yWsG%Laj} zU-9XJ=$RJ=91tWX_OCz@)ombzK?H(i^=!fL(@6T2fdBEeMU(xj^C0C--f3i;@_?@C zcv-@W8yO`$tCLqmcVsR82+&bF+z4keHZgdfyj7B;Dg+#+_Pk9{TY6>^B4mN6q|r(H z=?*fAf!ed%HtIhzflMIC&S;(;+aeu@>xyzllWRV=kw}!F;uz*6>#;0PUul;7>{W_6 z6AhUe1(UGdcTn^68gL1Keg*}ZkAt=5p+M|WwI`l|LF=bM2Z|Rt&-fgVVj(a2XM>v` zvkbwXG~|mHmRD=zCH@$05&OUDa1xBsusu1Cu0X&YdrTGL^8KZFh?A7ZF4aqU1E$7_ zgqOnK-NA6Ptj!sgk@6KWwt;Uzr2)D*i0<>|2^lA#;i#+CLFa5vOYgP7fH#AN()ixQ z9ih}MxJ3i5Tc_bZId9B)r<{l4JrHa^#BYGUKf>W{j-%;bcrfB31NSh^+bPCLQH}1cs2?W9J%Tq<#O18A?0cq#|GnHCB3JB z8fH`PU5ff$sH`vK`Ci*?5ZI^VZ2JFTMj(fMS-eBS0GLZLaiQPud3)^2k0(%d+Cua7 z%Z#ZGrS6~_GC+Nhlm<24xPW3*i`ixwLfT!=FJZ+V1my%TdXdh75a^b9a7=V(pjsg= zk>y=b8BS#rd4$^S3>{=?&!rW;Rd0v?$lHwNvu+Wl@DixGQ)UY~{qVd6mw6aEox% zw}1ccANFO3 zjENPyyTm+`pZh4BUXJ2}@Ag-M5_PVkmS7s=H-WU_zBoy&kL_*C@%o;YX4l5e@i4gW z#9O(}@eKPvz*0pK;(=_wQWSrm>HX>qvzdnIGt{5hUwjXrTfOwmX1-3|x{|2hH+^+0 z`Swg$kR0B(VkN&Ggst$x8+_(@;-ues#j@aO=t{iG@V@7MPdRktLb?^VS$&-UNd3xl z^TqXDA_Z+?5Vy&9yaK6xIruX&nDu^CqF?3nenitwDiTKaK&#>h2vT{Hj{HBE`yvq4 z%~AhLKSfvGj|+VNG{PQu{iOHN?E0gXYN~?x>45$pV@`#UN%jy>s{@9`LqrfpS^}ch zn^$XBraFoh^ra?d4^J4#baTED_pfRL&NUq;D zewaw>pE%A<+?laX$98@^y3441y6oKs9en-B&1R76i!*l_73*nhZr~5Y2ATb1?GhKE z{`C8~3!ZQj;r*6#Yz}oE>Yk<9O>}CmM>dQ1m40zf zjl~svw&+(wKh=oK!RJ;h;O{SyDZ8S0-MrEjo3z?U>!w_EpG0~uY>GZ*C{y_U{0V%) z41T;jIZ|}wv&gabYOow@HVxn{y9r1^bj=5$a1W^QHPb@vc(K&(P0nwMGd;Cc?v=L8 za1*K)Uv%rVOg!8;xBAm=E;#q5Tu035*ICH*qCu-$`;7vf_rWDYKR5%p!A0ZGl6P9K z?YtwDNxL<^U?|dg_gIb&1ooAv=sd6F6s>RL4=nM(ZR^y8S-&;?>i3jE7&?&9uRzs^ zzk9)6Y*3PKRW{^SxXP>^QI$jIhwf-p(#Mx{_sH|&{MgIcj!xt2_cD++vU(v_i5L5Z z!WV%{LVH$Sn>58K^^!O`FKO`RD9eWR#&#XWkg~Va0v?J?T-p^cNGR2hwT`2*{1)fE zW?T&@89e=8&aZ!qnPKOK>^`lYsalY5!`z`+jHYyskmSp;&-Z*tNJ-*iinvW6GkGaF zYCeyT#^TonXgc|h=%sCbC$IB7*&D03-+D&29u(-LrQqo|ZOlKLOW0F{ojiMcPV%*8 z_(c#4>Huh~f@$Wx;|a1evLMnDWqKbaxYa^x%dk@Bxb^QMMQ?z?_@w!<_38Avnf&L| zXFsMWOs6Eh#F;_!eikGzZ~s{6)M$e$U$JKLJe2}q);)4HPD|`|+1MV~Z;eJwYyg>X z^#_+y%A(HCoV>u-?dJZIMSjjxA#Q)peY6rC$hRMeVxvHwSZ^j-Gm^Weh+O!ewv5<=PhOC^Jq>coi;y*$#Mt=x6yU%ZW9kPOgF z`K$em%jHln2w>Jx)|j}?cz&S7lq2RicZR-5aO99#rU*V2(S-chz;Tnk^!d#mj2Arm zL=x>4P?=n9KdqMg4OpBFdYBdqp`v1@C>H+eHZO?D)O{_O&zZyD{r)|q&GEu*m%V!d zk|3n9JbKl?p&P=e?C`S$-`Ci&=~>6eLyc=&k0ubJ8*>P^?C)K!U3)Ki$HgC*WfUMM z=PUevMas+lh{2)YvezrDiIAXicnt$IUiLwTScupvUtn}tveN#!89sO$hsy-9!i-P$ zA6VcqF!4=I&aZ&aJ}HJgEA=-?gClmZZx5g|@_744Wz$`xNJg?tj>lJ;*&2YdVt zNVk7TBNh`_;GHq^L=?@mv!>2(ZPs5u#^7P<=u{6DT6s@}XVPT9nnD#TN>$(4M?-uAYF59@7w!%o_D@)=9{%<-Zit<{GrRe_s?HlbzaALoX4S( zG389iujiA4>t=lyJt8*uKW;0zVBa-fj?VZf%o>NDe7&U8RqiH-l~oKFJu@!Y*W_w=Uc zp<>n>ZL5vjD zI&)IcabSPa=X!tVpJz8GEE*J>{-T0ucu)RV-xcEZ#X*JiGA&tOa(I>lUp8xt07kMP zya&-=;>l3#xI(lURM4*ZGvU!&ld#IFB6$|a&r9V;iSYb`22JmvLBhDVaOR%NcM-U& zh%+&2JbpB0SBI&T?A3J~n5A7hL>gLGP14w@d99HS&0XbTJLCZmIQp*#i~uYt!hkuh zEE-CNKAu;%6pbFG3<>aKT2*?rBD=T-|6-xhL za0(%<%kU?q@_UV#Rfkn&?aTku%^9=+zkm10;SracA$-36(fav%UtJ)YrT&DZP|F;< z+)8(fTs>{SFno52j1^7q*xzVT*VQ`Hl4@vGzBN43?I6A=0USynhC*xB?vq-rionz1L=lo1DqF ze^H4?QZ$Lxkja@XIB}2YU(EnuYL^fVN#hL5U!D?kCxD7}Y0?+NwZ0)vyo?b&v9ss! z#v`3g0}J%EIdS$`NtubJc`|$0x_7*PZ6o%TVgQ1BTtSuN82NA z4ZFnC=vGN`-2XnKP;^I|6SFqxVNqsp9q4@}Adzt43dZM{tJtJupvme*cli_oAhO=l?$BkdgaG1yIBsf~#gi@x%Xy0r#Nu!8rPu46eJEc?(M@ zVGNH|H8LDI!#egfaWf=>Zp>HJS9o6q5*#W>%WE6@2f6B1VRIGw{FfF<)u-S4MVmq0 zv1rer#ZTTe)va2aBb#^UKkBq~{XTm<`=On77(M2$s3kU{ik#oJeikQ9%rp|cr0xD^ zydk3-P_wn$Vzn{#wHH_}YHgL=+~SO(ne#|y!8v%7^4&>kcJvlPbZ!kO2S5gazwCG> zpFT&RD?OW0)P%Gq6-k(2_m4=_2_ z`Apn4IgElKk}B6JE$7T-O0oVj$g1z4mUD&|*C0wqk5?qp52`Z_t&pNR3t zeT_z;U&ER|xca61Jkfb`62w)!6X*|AO&iECZwD7pbJjFUP2EE7K5m}3_U)QHO#;Pc zBL&piGX!&CbY6R9FTZL?%iwdE%Z|StPoAp7!>C`-JR9)ER_1Dc_0RNTJJg%ei1lAa zStk~F56Io(U!k18Kk4N^O98T9KGgU@_uqWLy;}d(>d9|5(c2o|)Y|pP)veBiYFKND zx|)zPA`Y_Y%u9{fnx-36mbci>)5<}L1ozA`sg_|>s9sO%Jk+*6ew4?A997Oo{EJjA zd;uQw4|7uLed-SVkDEyTCcTt`5By^s7G5U&7X=sgIE z{<^RK^MlEO*Dw;Xo#_ljp349<+KXO5GT8nY3Pfd8z60`A+Ui*0>#YTVn=@Fo3VEKC ziX6{6?t?UBFOty+aNAfUW3I`|9uEPKAZM?Csd!u%9jD-dXO>IJQChhUEd{!*alcIkpfE z6uK7mIFbjvxyS7RxB~z!H35nt9~9bZrK`3Nd?y28fWQ_9L^~`ouv6&vKq6p$0l>!_ zwLtan1xTrgxdVHoRX}qB;zFWGgE^DQQiDetDLiJ08KNFffmilRH@g9Z-xdH3wHwwB zfZE7Yz`-;IoY|vCKnJL1*RV6Z8@xW$O|UCL1*09A`4Tfe+Me1Uk|x+#11ez8fXY{z zO}-y0<|cRD#BS5Mjae!%IA31?JiZ>FDfR0BNPy)6DE5r9?GP~QHrIfevkb@@Crz&uL6T>X6^oT1a6sW*l1FBjspc1~*!NNm= z>fvw^80sPL@F<+v18m5`w7VW-%|1Rf9O$4nXOfIE_hcQ=q8JLWZ(0Ohd_4a_jRQ1D zfXHtY37ghv?5h@Bb*F#sc+wxG6{Khq3xmzcCxALK$#YY*Es)%+gK)_cl8>Mt0h^;u zjeBu^Qtp6AnhptX6%+Hlk+oIg3ZGZzdjzz+>~$cTD5Q^GVliuE4=~VAS6LUn59_0@ zyNWsW%c2C-((k#Tmpe=92G&dnEEqwf1dpk*3W@j4fc76qzx{^vfN$n<{EL6_VHOWV(yU5J}3x$CBix9oKn1>-wP zAPfj4DpLmDFoKlgVI=27^oup!L>1;SI3fwifZFr~ zb6{r8uXQ`@W(sf01BhCi7mAxdA?oCh;_#9e^3Or8$a(t?w;v_9aSZT2+-&Sg;&{`d z=9BHasIN%!$#5MI&Yv>wqTeSthq?w7-7U8e@G)L%sj*-Fr9lyZzSMq1aRDb|zb*P_ z;UGdC4$j}l3X}OetsP4eu*+g>&$-(Rm`cW>+wxDz4OQiLF6&#rO+mR@cWWd5WZ&<1 zW@*F0G_I^#O%vul6j|?c?mbnxqBd2&&7)au*XViHZ7O&$NGW(RVldU<6v3KarIyzv$%%qF3` zg+GfDeUzbil~92yyz8gK8*%moiqs-|g*_u((fqaiaU2uYApPPYHk0GLM}G0EU!@NB z#R1DdYvoO=H_f{0gW3#cgK3$BhxxYN#u&(7_yRiZQ~!4B|;cy#SsG@SA7WhRfUY%YgYNbS!+p6 zuO;Y_5LL(>cpKExqba+*#Ubl*GH~DOsbPL{f%WI9L>AY)n$4FX&E7Y3y}lb8#MBWL z2Q1KyI?I--_vsWEeIca4f_Gt&)!m83ZudQH)IRRnP`lcuMf>wah#TVAiQ4|0r`xXe z&1#y{Wdmf7X;^wL3A{(~S?56Q!^dkrn3- zWni1sfqHRYLp#yu(`^$0?_V{nnPpOIEg-}|&iMAoK*=`~ZR@;op-_aL(~ZWcXpfiv zWO+i|NfWByuT`KXM16WG-*S{JXW4)8O$*cK1@x;5e%;^Y9)KEiqEISt{&(N{e}E2i z^5S;`rnk;DSPo^tHx0o~^3Ox_x1OEOWIBI*E>CvycILIi$=X7Z7CAE2@poNHGd3Bw zx|`@giqF9MerCvZypa!0#arFq>}zCD)qy(ef7p8!aOZ^j&HX%ODL?DDUeL(qM{h4b z;vIdtp-d~zY$>jj@7%0YJ;!{#Jd}BM3}^7!5^FlUur$+kDEkVRLKdIB2bC7!JzAtS zh68bw@>emRklj7Flgi|<;c>aq@<0rn_`(~0v$);|%3p_Dt0m?bq~>}s%;xY@QHPB6 z!Q#7Z%ZBI3o^~G{*_`@jQt$6DMvyMNIp;yS9do<24JVymNjuRx7AQ}4H|?A|3%+Co zVw!5@02gJN`Q|t>P*bLT?i~*VF}5Ny82pG>&#&Al84Hu&dpyIcbpso-+tLzfkkI?& zkZ=C?>Ce%w&UQF-0qmGPS@kxx1Uwnt86_p_=%vlz@%|P;^YmDp%>5D&X*L9cx<*_g zY$D0=x2xN)%737kq>4F7CH~@ zgvztW*04)qA#Q_5;(C(%1Z{*{;yvf{%SFF{v(wb;$cpk-ibB!~^`0++g{vS!-9K+# z_$KxQCr!**tDY#SU!x>5PCEDZU4Xq9xC>??zlS^X4cdIH^I2scy|heJq_=SW7wVnA zRy4S@3JLyNroV)ESzoxtVTdt>$m^2R2f88Ee<<#$%iLH03TB&nF!aOd4PQMmJgmc_ zF9TbI|J{#}(2i*xrCoOrD|Zn5J{+_y;cc3~{^vIqw*S=={U2WC|J6Sd(p6aYvm@z9 z#BbOaO78hL?>dYg5SP8v1>_~Tn3l$>2&o>D+l=8TQZ>pg1zmAdLMkaM+ODjan z-miv@ZQTp(-~%Jt5KVZ7nC0(7tdNHUb53Pw^zL_TIul75k|XRmm^-mqSCgKT}<7C2W-{O@58D3c5cEU%C5*EJ4{B7f`MYC8thNoJ5@3B@dJJtDto z0-r#5@c*4pI#zf`NIEgFsEGyT8BajMeyo0?k$e?bYa(48s|9lU`}?3X zBYY#uT9M577=1sm6?y^sI~TH&iJ*pp$_l*A6+wNcB=YKLQM%-dC@6AAo(PV-IlT(^tW!?CA$yixm*)IrIb*(3Q*->(r_yAuApuD8Yl%5*FhDNtL_8 zpxn!)$EJ3bOd*x8*yWTGxTEMHcO(@$HFgHIOTkoWCZ+nVD034a(soV(%TjIf@9M}O zv-(KtQxLY*WU1sGKC6e$o1-tf&w!5NDqw7>B5T2{OKN}K*|`VELAk{1w0)qa4q30W z1)Am03;95`&8}Pbc~5^ER0$L#c{kj^Qk;!S+`B=x+GY-=svB%>W1Ob`Ya<;BHPPk)_A_S?nkrw&^zm@R-ac7YSeOKJ^sd!rv21&zRP}A#dCzT zka`||94+n<1r001zekp$_jSTLW9{-CD|4d`d$afvVU!rh;t2`s!@H#(TpV|wwfdu= z)RP~el>c{rMKrlpC!`eRk8TVeN&f?5{?yIyCn()ap1q^Ei^)K?{(qu}Ul7LcMmu!l z2J+AUNDrU)f2@a(x{lPu|E-6QpzV8bwrOyX>7b;q~Vzy|D7{ z_c}M&=R4=J-RvLY_p;l_L~vAnhwYY5(hVNZO>GITtn_~ube!hNYd){bDD*PpcH~xI z?B;NPf0|AViq(G0-#?i+)%BG4`$HgMJ1w@;Uq1vAe#DT^!uj*zu>^|lpQAqCyuJR< z|Hq4wApi5>tuI;~vJ4J+<`<~8`Z1^xLk4qaAU^PX<#0KK2y4TgZ1VgZ;0F2Bol z{~U3CEqk5p&3$P?|HLdtf};gZC}9X_(LenA>~Y;!%|FBwCCEQkfGdDI`}6%FFSs+I zXta0W`H;7P{9aQf4jg#!f8{{VkJ!H=*z3Mu0$UtMP+)8x?O1+2buWSyRyFI;OADjU~{nz>QBV@&(?G5f!Agu^zgBHc5eHYKZ^OQ#PCUW!%08Jc}XqKtsE6J)*t$%B;X?>r=YpfS^s~ z4_QZ~hw@-ODETXqOE$20CF9HlCv`Pe>#C=jZ&tj*XN%S8LW-^*gSFyNU_Lw#_J*<8 zxVZ2OU)V(-$f*BJK|1@? z0&a3C!ZoFVM(bWJq|@0-I5FHOrSd(V*Pr*#S&1ejB_PIE)aP9fA&fn&%#O7IuwBFX zar5=uvKyr^5EO4*43Bp0{Sv;ZJYPs-|ANs+4TZlF>Dvn}6ViNiwUaw$+h3>25mE)r zU+cY&rt+coMG%T-n)MT7wK}+Le(HJDeZX|y2KX)P+BXz^J5V&)=X+o$UAW)Z-lmGM zWh(Zz>@t2@jk)?@C}>^e_Bwhz(Yn(*|D2PW?J|TXDplVfdsbO^XOtI5DZ~v_WjcbA z))Fd@?J_T;c7&R;U}ryfFRM33Jg3iT@0$<1))U2LU3YAX%DNoll=xDF*RujXv>{#H zZGuSE?Hb=5?jP$}e;b=cB@h`Bu#G%62%-7;DdXK+{$Y8B(}jEkoX9Tr2cbP3_MrdU z0i*Y(==OLu3qY$F^k`I#-_g5btl94y~2g#^y$m?eja;>*@~^lI4Go_ z=;wk`+d#Ow>_90bf`_>8=^*cjqL}Cez=A(f_Hv&pnVF?pS0PSinm|suA#$O!Xhay4 z^70?_@zlSNrR;&}dc?{C*}?!zrh+~s znC-o40{!vgaz_w2t~S>J&*(9zS2*)0yHu<4Fb`N5)19Rh8ZEF?&jJgiwf5&?1HcJO zwl2ifB>iS6@bno;k{qrBSeKH0TMZOY3E_hrb?YC+(qa1)RBL?G<_!D*3iqg1g?ar< zF*|ci99ZExRXEjoTabr*rxP_|yCH94ex0ztxz<%YBu%@HT=laS9V8_QB1||py z&ww51`}xrm;4LfzLH(K06qwL_Z-Tm3cO)?Extd}oM(_kDp6#gbwjOl4cObYef)Lti zYbmB__Oh;ft(eCrkwZ0f6|J+WuFg{?NzO>iD>aG+@rQA<#D0!I{ovd!2o6UYuUCVN z*SQ<;nk=eNUcz0?4x!!b<=BuqdtRbe(rPgG9r01sM zCbQz0o;S*#onyd#g0yi<24!yk6x0NaHCN<5h93c^mmgShw`1a$N}I}g^VsNpPWu7m zH`dI7G-~pkO7Yz9o+FZ@{;^!GBCv$U56YDI=Y2N&_Nv2sqE<=W<;4)xONXYT1|4B; z&)@7T#@h20 zo+O3BhAMs&#QE^1r~r9B+m1y_Wt;f|nU*>In-I0G(;ZNLSq_CKzYs^TBQA2=K}q=z zV3$vl1iy=|WBsa|Wj$@zj^}mWE39x03#PJJM|fnDjs=a|W=BiSNS!WGc;RPQehg#W zpHN-X10a3md6x-Bg~!Z-deqfXb@Ss*rOnueD-K3K_9ttx5*%4Y68X3DvvbsBWR%Q8 z2C{>)VV~lHYx4G?$k2@+*n@c7^zLP=KDiZt>xYoC3k~Tx;E1obQ`@!N)ay$JW)oK; zc%rcPT_NYXz`m|Yl|VTBWnD+K>~Y;zi6ih!&+(xZ;w{qcV!M;`A{zbOl)&)!;TO%o zIm%O~mT|0=H-|?mZ6AVf=9x}8DEIE38!%*2cm4H4?tI`|-ZK`I^h1B%@LW7tum=b5 zOu4e%&luex$LP_EwX*S!ITJwNW3q%mEZYhbtAI%dYt>;t&=vT;M6 zC>SH5YhH+Fg~46g=qWAiih2RnNH)r2?;5Nn9oKx3-&ToEiRwm&yK4Y!?Yh)RgD7b=Di~=7&>ihBa$JJ;SB%cP-1}u^PEA2Nbt{nIvj<$dv47wrShH%#Uy<+Gu1_J{UA?Qvr*R#x}{JmI70wMML(Z*yAe_~ z;P_Yq3+eW|=g!}b%fs8)ydq9BNaHfunuIs61XBp%zY^t{XW68m7wx%sNZd?}lUifL zs+JFW&ok^_AK%?GF-vz&^tn0_2)5)w^@(@w6^~Y&&ABmceWWOaaBc=6byp zUnVjOC%(p#Z8QF+d%j!$)hC~l@NS>WjP=^G(V@`B(>rnF7vj|GSdm-XjoDrj65R46 zVrqKty4-K)bHFms59VVTL!S)aFIj_`v8SrLTif=)j`PMmVxm}S7Dd19N8DwLQ_tlX zRB&Ie{!C6-h4f|gxQL>>cPF+-AAN$eG?{rsTcv2X?sGCL?7+#QA9qdh+T5#eQH2qIzohZk$LM*YgA3y!OMY{b$suh z<~?J&M`l|_*lOsf#}~!>@Q8oIS0mdG=POR6YyiGT#%irKk*iS75|?R;g6q{nxI{Au zCGHqd=qytB_e5PHqJ4g)ckERk?5E16iAd^%AhbOZonFw8>lujp4|AjuquGK1z7I~e zB*R-2rrq^V5I-8BsEbTZ-6w1`jJ*u|$qV6Md5k`#Mg?6)w%iIbHMgg1TUVr4hNa*M zMY%oP^BHDjeNC}(XMv>>U}3%goJt_=7yylSCOpJ z0tjIz@6%Ln`6roqn|wz)fL9VU@dF0DsD-Nwl*ePc?onsO%!&)ZPMY~G6V z9>h{sVNgH?_A4*SK)>gziZ^Vl_9UhE(<{B1)bbOrjSkULZVMTzfRI;iG^qC~ zsSMK9j4Lx)nU=4|F#>l`yvU+78+&Xyv4}Wmvhe%&Ia$@nwa%Xk+ZcR4D1cI+RT{BY zd~DDX4DH2DyuEI}5abeAS?)I*uaJfF!~Omc&O??VdpLgd3wIDqer}R(U2qbC1*dm$ zkqPR^$x!KqJkzBx1*${GJobod>Gs3q7Zz74dA$$KsXsv^IH;hdJic6YRM7f3+1Ykw zqTpvAR;5``M7Ps;ECXV2;l1zLN*UDR7a%K+3zH1K2Yo1n^QJ5jv$`p#QF3QQhqDW^ z2g^}5J;{{D!Tx44^20{op- zd%R-67! zSfK$iFoC7j;j_H^yW`+>-qI7IHo{=vs$PB9!Y9?s{WzlQ0Jo0WaQC6Tu>Rt74$sBpBvss`(jG$QG32kaM1 z4;%;x{fL(0>7n&N58UlQz;lb#P|~Bs84j=n_v2sK-|_6Y!S1t?U)-HD60rWU!dIK0 zhv}!yolm3{&X5ygxe}13UoLR!#2dPEDxhRF{*}gW!1kx8$D{ORWrbOUYT5FM?K2Grb{hPoCUJ=tl&$E`tTJ_LDyJ&itb(mmB zY_+{S*OJXrBjB{7%E%XQaXzXByZ=K;lt$lj6w%cWRP{Ab8W`)by`xOkR$uyD5e@lq zjZrXS2J9y^N6KpU!6-eM3KwEdx3eF#T-1Ei?KsIwBdZmJ=Xy~D21zTjd2Agc22#&&KvS#@^Oq?U4p!ak7cY&O6U$Rvy=*J>8Z=9tcl>Na%2B1*G?pL6O>9xTIb>A=Tmi z)bk+d!)wj9t|GE;|Q_zW0W8ckHP!}~D zx6%6csAQ%Vv*HqQuESXT(2SKo9G+y>z+@mQ=b`Wpx`T2qszGtaN?lQI0XH6(Q0(a$ z4Jz<{mKY(7il&ag=i5T{hZjJW)ZG*H*z9dqtgcFGq$#EM%tDFx>fiu#S0; zyqR#sf=nRdn)-~EV#hkP#ZZ%VLG0vaL@ zan%j#h=Gp-3>8n^XgKQ?LLlGb5T+8d9Aw=cewt(=&yyd2qAqtyboyRjBCi95YYQLi z4@FYy@AqJ+_T-X&^f$}5dQQjb*bZS4_JcP2y~vMQ!!i;owUUxeC+?c!lQql=XB~;=2+J;Wvs&GnAU6HF<(O;!NZQtHMKkmw1Xk`F%rD9Rb-=B%MH_fZz?-lu+ zZ{(-YsLUlowB##XB(J=-P6+zqe|= zTpN9t?$FSD>$IfTg9baFUdJa ze|ZGtY07LH3P=h9+o$|%)U3&T+F12^`?+ROPe;+E@LCP=d^P9SoJ(sEd^rJ;r5|5p zzyEYo;nkH1j6z&HMfoWy%Sg*e3l~q{!H-E72aLvt%^M;^7IL|9HY-$-O~qr%m&%E& zUZ!{~EJGVsdkxtXYg$pARN-aXT+K4mWstHpo%3*>;J%$sar2fiX4nOIif%;X-+TErl zxGi+L#OQ^nw^o0dZ`iP4l_mFqh+sZUBa3{DIQxeMV`RC`Q9t2$VNrQF2s6I#*FGH3 zM8XCI4n$g%v4LEit*q>boF>jzleOhz!iWVK)(1n(91Ys>bkmP8{M#(U|LS4B#4w>P z9!rgss_65{1MT{^R8JFshldV|=Pd`%cil{zAhBnCTAL{|3WYU0k!%AqF1xMz9Br}t zMiws^i#gHCbR%9&bYu`_+rJ^6jn~A8hY1{{JQkrW*3H80N?pEJWB*kSD{gQ$qV;@e zkJ%Qv`uKKceO(x6vzIPs7Yzp6Ys=-iy4=@ zKBAIzpZak^l3;_V2s0~Gp(Nsc@wk|h*w<4 zX@ZbY(fk86{)GrjPuLxrSPSvI?%U^-?p9QzE_u~HgZWx%c1u%PQjXtp$2Pxs%w;Jz zPPu2UT8c4l47xW=!Kp9N?wn3(De`kKBci>^P`Z$v)d+y)qnOygQ0@aGdgY7^o7D^o;9!K74gJc!{I`DRrVD7cjNNiJI|;zl!NL8N_JSY!(3n3LW9+H zHM+oP`AqN^=J*Gmo(eSur+1?LbNb()b$Q00EgAsr|A69K7XP;#*n)NjfCsM!_y2(A z-LwanMo2_C0^sII&7FDx1$eD8{PVl_eCguk`@vSqPc(KHpg$$pA{R z=LZ0;HS_$!LYM>?Zen7r!CbxU^+kgbAg3ZKc9D0w*ym#+s9Pk3Ot7l7#UNHZy$$D}d?LBZK2ev9ooX9_IXCr@z2Hy;D+7W12bhW4-a%W5bR>*QEWHdJ*32 z3{jAhnRDo6TVu>{Gvwd=oKpulz_XWE$IY&Q`TK^t0ece$z_sa#RwD>kaH{jT=3FZ# z-S!py`icX8(;bM}&ApJLS%r%pj;ir*o{5-qELYK2A}#6>4?ae$tbHP6^Swc5+km); zxY{iI+Lb?t{7qJd6H4vakuMrT=UpSNl5cM=z1(m6BiXFg9s3t>hIf5GL)0#v>H>=& zv#?>Z4Kedm7FEa(KT+XqMY9ROho7?4 zM)FO6CunnkoLz!xGn@l~bkVUG?F?M2OELY>eccF5qw4_EoV}@|xPG_p%G1g{Sz;~2 zp2|QT~aFyB-W#RtJ9AbHsL-1BRBxk=AmTb1`039wwL6n+o z7SFx29+s~iA)TD2Pj>ICU6q?k)XT(vR`8Qw5o`i}n!kI)9_tX0z|o;|HI)}TSq$hx z0K>g5x=esz&H}19h0Y7b!czn&O09AKnF4)tkS~5&uyL#`dic_ZnuF2w%x8-vPgi(V z&50b_iD)12#80Z$Kt2wl;vA0z<8=W#C2HC@D73};hE|T!gya}7^7+$I(RkKeXRNEc zxHgTczAJrm>>H(X8j{?F`&`$10AS;?$U{#QgK@}0T;{TSP>Eh^C6pm*k5r;3=rY>p zB8SSl^2eR@Eo98J;VFPBUdf{RkYPwh^f^5XzYUsg;$$7Z*yBEu6Mbwq`JSsflKCN!P zEZz{HRinhlfLOs}Jp_&2HZ`6_hB z1H$kV&hzaGl@WLCb};~qJdQ$k;Szvl+q9yS|6-RYic7QaqMQTyvXyy|pIO{|)9UO9 z0NsP7&y_V%n&&{Zxp8UJ0?)0dOZe<)6;jorU3+cGrRoV{v3J3==uSAvd7BJVwE4fN&Q08_o1zq>uQu_hV_X<#cR1Zik%=nvM*TiPwVAeRa zEO}^~+uFx7xGk5LqO0f!g#rQ&TzAM$h8E;|FRz(1naN?=Hnp9|jG)r03+R!G@1j;> zZxg=CV2B2aMJIl|`#~NrN?vOipt}wTuJH!pEO$USE6Q?3Pixxog=>(>P-YQh=MM+_ zM}C;Jdlk29aLawr)2U&}4~E)3bX}%Qnr5fJVQe^nbk{kze}tej+9Bz2xY;p%1JlP3 z9`CQ6KJd-E88y3w(}Kl?&q87 z$mgaPL1ZzwuV;sxImoBnwZ;Uw94yxfUDwmc9~#7SugSEnVo#Or(p*r!qU?w9LVGu> zW^5t?-m&8MT^!&q=1B-%wI}^Xw3ri^Jh)D5XQAZ?0YY zU|F(JQUePYaC^T;a}5T`mf3_GKFil_gP2$F#Nu{5kDm=L^aT5!p!mWDq!JEJpEiyB zgbkM#F%OYJ4h;*sr`68%=}RNf^5eKYpYMN2_%R3X!y;2 zidom_{jO#h#QB5FiG(CxlGK#?fayMRxkw@3aMAf5vF##1 z=k4`|p}ijhWv#^NH_%wtYJ4Eh;b2-fUXaXllw(j~G6ESes{&Z1KvCn-v|chj#7$jj zHkW)&74II@A{TgKIxp;vXwvWEa^Luv>cl`D$+3oQnRs=AibMfz5jfbHn3N@bYT3 zL59|IE#+HvJUR=1XdDF}{9}OrMw>oLmoF|9HuW5h2fFcnsYw6NE9z# zf@5(kxS!>z%2%5>fV~>$?1Xy}h(gY)>?GtS8_2UEsS(8istQFhu(U|maZ5Ec^_+gl zczIF;E*-D0*om+&yKoE~uyzD&eMikwlVgH#I!(G0gjFZddxzYN9u;+0pSLZc7vH(F z|G0?}rw4n274U5k%!42qwl;VmR_VVAErZf-9mBJvk;`E{AbLE+-{ewZnr|d=@)cBR z)Fx{qCK!&}m(o?LEsbKhcL^5fBlo8%5Adw}8GWFuL4G>gAqq5dx^4B=&aC#3GJ!pv z6%J={)5F)3Rg3#iQ*vonbS5!0gwc0a#McDP{A0M~HSg1w$$xK~x1Uy+m&4$3gSykA zWp)aF8WW-x$e3VXX{{JJvM1Q2pT0Z&pb%&8R#@lD!W|*b6O}uJ!KEG1mHKm&xKuZu7;l?nLq#&ig-lBcm8=3A2c&cb%e* zWs{5;jVZkHa%fzv%%FuFBbqJaUM*`ku2b~d(Wgj5GY*48QkuNo7xc{W&cwz|B zx8q&7cC(r)k70f9r-ZZu6(+Hb6a5DW(|JT5;aYy?+NB(*6FHhR5)*-mIh{Xl!&ra$zU>>`&LHeOm6%*Uxn zH;qgDv}l3tSs}u@y3v*iUS3+2;==iBKTGjLR#)3QepbiO(MjTPZ;ZH`X+TqaBz0ga zixzbXz?hFvXe{%#%?ys0tEE_NC;}V|YTM2OmT`+-1qr13Ms=1dDR(>*!=qX^C}oaT zM|;=f#?f;`-cd@AoQwmIOsf}5lps7y7dNHhm&G|1-Yy#PTh`D#<}rN(!@r-?KbzBs z-|-4vsASY06W3~DptO}M=|?;japYb94+r)E=|P=-`0_o)eNPlGJk%+9;z*^51DOQ;Ktw=@WloVK za22e&Uw=UfZ=3M-m#3G4_CfViSi`a>auM2>#}0J?-N(b$E`&9plX;c7ZINOPhOfzj zLi1vPD^apzvC3i|7hyZu2-g3kPs;#4JeKLPoSnkJz@fC$AAiVt?J^iI=Wo58_&OwT zvd>u{j!KGJFq%n$S(Sd%N{~DuyurMCaeV`Ha zJa-oC;Sd|aOt+s&KwLKMN*5Hq;ke%oXD;k(g6g5Q+{HG*ihY&%vVP$GLs$s(6=hM0 zLZcbh{ee!yVqH~)b$+8QKj;pTP{K{F2D-#GgGQ=EL5z1sMS8Lg`TA9<2TP32uK*pR zJTqjDW56+jDu4pfBJ9j%eREY8Y5AJ1C)63JeD%8oEoA!_Btb?Qkj z$U}7Y1p(y(8n;EiD~d>Bsk`5<`Z;4$Cu)CsCQ3kyInYZq(g@6+CYLQ!RCF+Jf2cV~ z4(g=uMIRgHS9DyYpgGb|3~=@*B+?uzljsQKZ0~f=rV^g~^swwMsyE$_mJc>}XnWNh z;SunJw;h_-P_8@4Bv|?bAph^}7ooybCXmPHSm}ic`{puk5!EaG$ksYB%(<9(&v?;ucB8^0Z}zs5 zfJt#Z#yA!+BlWLR510vIyTt9ahg&8TS}3A8smxH+`(3kd5E`vBev~Skc$<&3wS1YR zG+E~hBw16x8Ap2IKBE*MPb8pX(h_SQkw;@o4&2^*S$$C^7*w0v$UOtch}EAwT(wt2d1>8l!3lxl^Rsvc#} z2L#EhBV{UYFStyfyBx5i2PES{Vs;TxFpSmk1)MEi7DvUz+|qY~8KV4FG+dGy71o-wmdDB$toKl95#ACy~2-J15^l7~y5>>bmpU+a*yjx&E!XoGAKIih`1XI~|9I?@M<<099O+ zxiP#5(3Bs@->fbYFvboVJtrMjzJl(M84~`uomhBpd*1z=D0!yI-Qk;dh$CyE?)Ua5 zCX_h3Ys|>-w%p8hnMcNAQc-6Znp$ww8m9yT(adafuLT7Q* zeDJB{x!KY+Xf))v zBC@N&h*r)Ts3|Ul!b`}9Wf*yjiX|w9e|*Xi^`7Z=@(<3h*xIy2`O;sqD+f?egreS< zXD4^R{TvxzY7GLNGer$kL6}>IEG3)tUyb(?Bp=J?39f#gloGDnr{CDl=oiGWf;EJ) zk({_6v-X4}yYPiEh*9IPZP6$j92&pf;epdw^m+8)^7-S?o3NK!-PTBKaGT=ka3?6( zSG_+pQ?O7TD5a+v>~fIlXMyp0Qo9pFq4Z-^mBF!%Om3xi$XcE@ZK6u$G2+sw;(;jG z5AEFg_0l~+J)=7Pq-tcoI@Oi=3-X)bdwx-`sng2#V`tLE=2L}nu23*nS~S)E$1Q<@(^ALhEBmJGSte+t8q^@Yo9TUK;Ung< z{7f{u)d6)NpKp?-ZQOO*Q~`_dijkInJ9xmJuR+0}z6rV!^Y)>&+E?`^%Ji}4RLll5 z;Ss`?by&S(XzBOR?DNX? z^Cb};Um7G?24|F!`^%aBdXiB#H_o56HL1@WDc~RXt=M-p4Tmw5r9pX2mOX3l7PMhQ z6=9yYy%u|@qv`A)d%U~Ws?VvHYsIR$@|cHJydn|ve9%tRy6`jR4hWqECzZ$h-ZPA= z?mAjAKB3U&AE;}z>#r%E$Q_P05WTzBqn_az6;ZmqYbgTott*Z3chA8@ACoT>PhT+L zXMHD5ORmF;&?Ya9gW+=vOoD-sz|*(?3ADa2KLfgWKAcvqqWaChpSr>V2eEX`9Q)QH zV;X{%q^(U(j_mc+yynjht~!k$kIFus{9wsD80WANB}o{|5nrnubDMBSM2@yf$Cq-H zI~Qhb+(=h&jH2q^D?tEVU+;P@x0ir60HrA$ZNwd);7)C=Pt?LmmYElg*r!K#CY;Fa zz@U<_FG-Nh7a{a_8s2!AIJX|E1e1SbimSG8GT`rKHpZrj90i7{9kH(qBpFg)J+;1_ zL>f{wP*Z%ffBI`~+^H>U=P0wxWMkQAmj~an4CcIfHU8kUYLUIF7HPcLggbUme<;`6 zl>8c1Gx^S9JJfSfMf~@|f-`fU{hJ(4$#sDnd4k!@{V2^VlByBU8qeM)Sc}=bp*h3O zNJfF1zDX~bs0I^WF;Td~y~*6}a|uXYrcC2J=t}HdG9iZF^mC;;Hms=ocw87RVRj?d z1WzY(`sH({kRu1RP?WyTTjWp16@#|o@WeJGmX%kfC*9eGh#?82FUc@*t9gXR zFzQE#Z)O?M!aF{^%OFfGSR4^t%CE;YEh!f}XfsvgtvZT)J4NatLO{4SVS@tXmWL(~z6~Vyn}^&uCL! z6M`;a-t@?Z_IwZ7mul+BtnWGR(+V#-W;oQ7cx0=2q|YO=ZA#3`3)+4FfAZX*f;3c7AaG)l?U@c4bZ%`=yX3{mg*}eA+10#L;gvM;K zt?7pTf+#!Agz@i|*Ie!7+g=_?SrQH@6bq=;%+%~f4$#?seoOWGu?r{zqyd8YL|*&6 z#N%zPBxH`Nokq}UH7~LvJ!u*5@k~Mc!EiCw0jHt5z@ammPFwrUe3xnG;V2GHyR<5i zdHKYfuu-#d)m1z#_jwoCjE%>F^1O+`JYHq*(wWcjFrRqDa{8k|`X#e*!fyKijlH*y zs&akXMUj>e5D;kr1w}$Zm`EcEDy5?k-8CL=$>yH@kjY$J|xH2VX^E~EKurkIi6cz zOLNdkf4;+&6LP8%!USWxK9c$b4rQ+t{enK+ zc5(B!e%Crjb&No`&E&~t%n1vM>A(W3BhB6s-*dn`ZycA8>y=0Vd%nFKX{ITu?0Y}@!(#!h#o zO&=Uq7mt*ovknf*eJG^1XCD78fL@O>bVNX(K}9nzEbofyxiIzc=f}+;nKQ6eIYQsj zN~@nAa)fR2cpZwGgKc`}lM`>wQuu0MzB_KxR<+-H)RL+G>A8Xjy$uyOkG?P-mL`bW zT4H(@pWl69^~%+sw!<=u@f&T-YmJ4t#qJWy#@8PnjS4tcl881}_0i{3imV6Qx8zT! zP)?q-Ce01Yr#LpROKToV9w7ZBt;8>F=}}6See~8*S$xZM`524J!wQ2eyhqexE$6B% zr%t$e33@c&rb{0ypXIL*k#<>Jcomnc*7i;QK2b4B`&Gh`SK@DDti()DjNgh+H%>-u z4eM!jb}m{WDU*eaTgTGL$jx?tC>9@iPAMl{k2lL`q+3pLqfxwk_r8N9;`kEJ z>-gQ~1+6fG=gde^HF-l?7F ziROA9+{as8-jW^mnftzjLOgZHkzE z$`yVtqc!dki7VWE!Q#S=3&M>Ly6lH?+tX^iEfYN7Wak9^AV02F$+aqaKG1FX8Y>;X za3mqEFu`jSD^J7h_izfGck?RrjjSzaWK3Fh+RneFY%ma2tK@spfzRWW_Tmjo^5S6J za~fgnv=_wXs5tNn)XK?h;w;kNh%VBN)Zxz+(40h3~GrlXkI)&kMFIT8HstI zd~AfqlIYzMgJVl!qO#vL<6japR(>aXm2671o^@R+ zBKNj;lUVG>G=Zq+Qo^$?MxORD#>YGFD>vJnV9c2c-(PpwjWL5CD!EQrzEvGMhm0*kI|q;fOnLcn00lN)6Mk z?)K&1^Q&v_;jH#@#c?pGrO>0mU3MdySknQtV0qyx@yiK{p%BNK23ikV(~s+_W3CF{f)P=Yh`UG zmS{iel|L6w%;EJ0fMFF$`FqE~XIYRYvE1LW4R=;0`rFS{$9#-S(>;^9 zy2L4Gio-_5drfbz`2fZ7egr6L(OqlL&VJk8o|By)v?`kpKoM{9a?O*se9eWs`q0Gv z!v@Xx`1mGY&KD>0TWgK?7TsC%nRq5?_}*P`BB4?ThqMeQ0x$YzR<^I{b*i~f43+o< zCKqbnvX~TA&DAe*y!}Oy^e^IT#KR;=d6jgN6-VaiamP348n!RchqDA;%CY8S^PDk@ zI65(t_1MFZ;BvLNh-*&6S!0hsem&@^%hM8hz8{1h>D-so?}*1&IK{G(51#RCO2!Gl z_uD%NJbq_sp6@v)kB0%BoOv0jOxi;&7sc2Q#p+(+>9jT*t}Ee^@p{1*dzhSO2FuwR z&JsuW^Z@LRrD8*1OdZL=dpb4){P)qc{MtO6dMbn|3dy`r^g|j?H_AY zizLGFC0UmPWhMXoo3nZkujifOpPYp;5I(2ehc@r8?U&zCf->a`!N=VX!W5iLj@Cu3 zINTK@KKktPi1sfsY$9XoZw)ZUn~ikSHEPVeP>$-J&8j-G%Wur=vfwFEUUN*n04kbj zia53Pioo@h)V1A2_58Nw@5H~nyDcpgv=rG63;G6hee+W7ekP~^0> zp^M-Q_w10C0L35l+teR9XR%AoZYx~=;|)^tpG(?*r@Z+Gr#BUd3Yx2zsrDDf>M#O| z*jsns;{cq_i`hD6cN@@Dl+*aKlJJ*bej^ZW1x!F(|5H@}8VTz|#pT%+6lAS^obH&O z@tjNL`1v*|Wb926ny&BpeQ%QL8B&4T? z^}|=qT8%u#fwI{Fy><5(mxK>|1rlYnkKvkdcF|9UA9r@Y?p)&Vhev{?+W z13`KSRk~Zpi?qj^QgNd8xE=|*&-$c!P#PK`tp8 zh>`T}{m}o&tcnz61Hh7WrT0c}BWq`&&bLe7&VuMqbVClI7ue3TRSM^8s1Q(vCFoBS zNhsZ0)_4`UAzxTveMAcB{8kLJ-;}&}TUlYW<4Ik~VlBNH02J1YE;&(@tDBd8s1s90 zdH{*{0M?+>CdR>fyI?rj8g^Y#G+-iJ8SZL1>Lc11n-@gDtnMtsYKz!aLuwpvow3Yz z5R$4=81gc+CCg3X68C{AYl3Q%=ihYZhB~EquQK)ySY>O3RUHilS^CY^Ol=8w(UYfI zbUpEoEm)@G9JrcPx$LWc=p)7LA%o1)H7g)O$I-YFmH+`ik75iA@RIH^Z5K;>Kz}%( z9va-cxb}%HWaFIw?aO?LXAKYn;sSL3+ZTpET2~1vihqEjwV7YJwOtydSOAa z`ZY}`!eoy3A+4%7D#tY#KVN}EwqkVM;j7NVz{g$Da=(Zepmg^_%buZGIC$2_b8v+p z#dsdVSGH)@()FQs5yC%1QbJ6g?>~;Pfn#C5&04R}tWKv7JHI{Ae0Uwe85bB)p5icn zTO~q3CEm#m-3#E(kLU)#%npCN)6_dN;B+r<<^b~HLT?fT#k3Z7~Q7=nxt9FItGDH=%GLsgou zQi9+8)%Yc(EHea*nyD6_IB5^&e!~LCKo2ZwX`uh9v%hp`&E1X3c@cIZ^h!y_$37k*ZVm`WoM_qk+9punn?|ERM@e4B-fAk zyYH38N0JfH9T#QkL69~=GLiZxPLvrET}BOF?I)+4X#C{9SVI#u40nr{Xu_(1_0TD# zcu}%MeK$v4*qtq<>cc8YqeZFdRlge?WXA~yHUnWn*ZC2*1xS(Be+Mzqej)s^^hJ<6 z6b#lsY=f^z7*OntKJ)K3$Nwd=k4k}A2_^b4CGp9vJQ_`#PI+v?cCNq2 zW}Nr7@W8cbu2tyP$-+e~3&k8>XZ392!!}6JlTWDYqX_R`)WPLnXK)9p(Vc!oYhh0$ zW|rWxkQ}?o(?KAFFAb7+u@KthYgMicbzQ3x+JlU>zIzBj%t|N(y48hxRH`B2sEZz_&ke?tJ#sK1wEVS zM#y`*hK(;tuZ(`w!5wS@Kpbx##T!`f(ed1MK@5O#V0MqUsC}ts<;^rbHr!7_K%t5) z=@bmSd$Y+mFV_}p!cM$~@&}g#iRH)i{s`0jt`ZJOkR7^BJ&|8hkyXGqKyiO_ZDTlO zt9+4fU_MKO_BkoO|G<;884H7|wbkJRjlnRZ{`Yh`huMu~Uvw5p_1T^sT4>pFgwFCkTva_G;5JP`m zqqwX7rFpRF#u{Yo8y42VnKe(mPY=W)PTR&pn$H;Oi@HZpJ7#5axC2dJ0Q5jdL2u67 zI*kV3-!!B(q>&zD_5jn_QZqI9X8D=Sa9EvsVvx?wD^JFS?ham2VL@Fy6Tc@@^K*5L zt`p}@Hlbg!v_RA9*_YR<9nB5;D4w2b2@x71+;c7%u>beDi+!|OP;hOZ6h1G@?D}op zsLT63388akuC);V=k563kECw4>siL;kzbFGkIItt?1IxD-J*@Bgcdb$fy z{Mj?uW@!LMbYqXQ9>jkzW73qpK>5I5x;@GddnekwZ1Se!RcXOD#P-gHzHwi^-%lm9 zF_Lj}mx{h?+#dpMLvyN&mq$B%s(7nDQRh?s?Y%9QT3XJ+H`X zf&x{gVkIFT-)f`{BY2V>knd!Uu04OYo}(pDb;3sj3hr*PDE?LxLf;!A10Faf1r6OV z`YQ0Eob@`ioK1%d3iWa~H47R1HSm*jplv3>Q4jQkq9Opsko`D{a~RvOY4@G)V{P#q#qFU9 zZ8BK_J1|RdqF@}fw4y5C>LmD%6HA=wIP7_Z(E6*-c5RY}!sPLjPhM?j%VLd^C>;?z ze3JAM{Lxu(fX$S!A%U!cdV@|f1!1}~_NdvBXQJni9poMvvP=ce;_1X^Hh7&PYn1HJ zH*kFDsUlU7_p1Bga3O_wun~2`Ao7C&nP*OxoS5-)l~UtQcmX(vCHB%27h6rAOhu&r zxP{$&N9kv5c9ZOhaPy^ac!Kx4;dCmA7Mh;4+>;5*GSL3^@*q2(OKy9}-tO{6{_3;_ zZHte1y^u8+(n&Np_<6_^i4K0R|Go(6fBh}4Y?T0#tE|}tP{h^A)i;LXoaYven#y~J z5Ns|q`?QnT+qQN|HRghDM14PW!8@}587?F6S_I-d2hA=q0ymBvI2Ntqy~idHEG^PI zGNjHth`&jQEiwZ>oJe}i9`%WoLFku1;4EnzbzY=QD$55y^>?P`XMsJVjSebNFWz*85w zOUO6d;&(>?-O7i8h|J-T-JlOm?Z+Nyw>Wo&r2PEu#&9um4k2joYo5ChxfhTMc2+0| z4SMg!5p(A~Erw_)y3&HQ1Ga6c8KgI?!W4zyA=*jXg%Gq>F#|)ms|R6XXr`iiEUMU5 z?25(nZ>0T8eAgiq|7e`ypTS+7myG}d6_3xT1%H2h_#*J{ivX|PtHA%|f*GQi1au`+ zHj)w$zcQOnN85pj&Ihu6V7W`qxb(T&X8j@l(V?b`xMDne0FaHL2XJ}M?-AY8e9+X- zSEBqHvw_r=#pWW1K6Gd;4-PHq;s}7IN{k4EYQ2DAo*2#o^wt*N)hI@%iC4RhpOxZP z+ms|siwFkVCB|c{F&84O>d*9o`#H1BHU{GBcJOpzi39jphgJF#jjRGNZ(0<7X~GZ2tKpOC}NnFnPiAkwXAd zUL6FaXXM*q_Leh#BOLl6hSF5LAXz5v4!Lw1N0~AcASfuTXXTUtp=EP>3bfsoL~u6{ zssN#^6GhWp9Ttvby|oW^>?tgSbII&~f@Jffm@K31Z8VINV5L;JWWQPQ?6!vr#X;t0 zoC(RHu(SVW*Qx7Qn+=$V&jBKrpB~oIVLz&SjEDl4u7jTSy*R2b*QCfa@){lW*RhoP*{M( z9a?#aT$e%}#XRBghC?Gy@yyo?{AJ*tY)avmkTi)d%ex2C>U# zVGp$_853#R#MV$FCYMlWvXbjt8D|&i)WOM@LAygU(WPa3;FXX;&x% zA}RXIA3RT7s;;3A*0ijl-o+qE)4eZPSo|T`=ZdFN-@6D=PO#r26PY=;*Zqpo>Jy9j z3>1QftD+>!VTn8vS;M`#1~j7$=MzPdqyms$;9q5c{aNf>?PVATbfKuqIug1IpS1U2 zb};3UHCJL-?GSA^caoQ`l}Ja8!8fE4>0|2=)EqI7?_WN1pGwIO(zRSgQz{5XJ;i%& z-NRYX><2#2ctK>{pnO5y)#WDXo%^~H zpB53}V?Gkfc!^eb;FLUXTa9;sDFT+=MIa>ag3yPnpNwq9(ymCBGs?!1!$emoSq| zGYKAPZf0@b*LR{}7>GWre~UQLHl3i`x9wW_k<{SxHRqm1B;aIi;ccAD$@5s@C`*$g zGrE(&Ps}8(VKI$TZ422CHLE9&E1ztU4k7&+Z94AlN1FX5Eewhdd8SBu356ilWZ9--V$sO#tjMD!Vkm}OWW|k~H>CX#MGtDE%aKr?e-%0S>{O##o zf2E{UNfgccMw=cx@>l_9H>r+}@3fFlJU0!$_m4<){HK#prIEm|*Cb5lb@Q~~#S=+S zPMn8%;t@)-X2JQyh1AL*LrxKr*knzX-9u^|mWnObP}8eXqHb$x_$a7c%~|6z*VjuH zD#0iUwmtItS5J!|aCuhwb*LuIz8L&pN>`KHbv!GQ!W1Ztw8$NUpd4M1A9XxiBs|_m z&#}?Qg8X_MZa7MQio`3aJaZsrfWr^*j8j~I$fRa%P3)oIbETbWysK$va&R$(h1VD! zHwDxx`mmIc>*wb+Q%>|$wWs{9SsEAt>H42*7Rf&xJMQ@)E0RW}3|)MUA%1hn`T@dZ z9FCx9x?Ic3?LECoqDEM*uyNxm!qnVVO*=JFHSE^3>?`6ye}zBM!&zkAfL%~y9pTGu zMLulup?{j4d$F!k=_$(*Qx#V^HoI3L4Xl;%3X_$+eUYyWtv^I?V#m@tXPDZD2^ka| zrg5h)NtHw^3@uzG#QRVf;TK(f44 zX{EC!*0$SwSXqmZ?}7(+SSd(0y12CBnh@5y9uXSA;+?xR-^*p;$?nz(9#6NB*<9yL zEcM*&5Qh=x?#6;4I)!_Ds=D##axdI}8+(Yb>{XLtCHbpH6H5FLEH9gU(sc)({Q!2+ zqvH1f_5zJjrPwCBE5&P$;w(RyE**W^%p>(Q@o93d20<<-8Ad}_hL=6y>602meG$rI zGgF`1r(S z3l3RT)^BQPdLlC~#vf{7Um7o%)ou6p6b&yl=CS5j#@A6Zs0@E-zxV!{$J@(MACo_E zDK?Je;xm1WIeM!Rj0U-K4=+{5cD(Up-smxw1d6Tvi)s`PiRNhMf>t3fy`lH+!`5^D zvSEdo$0E+gHPb6yp>c<>4bnfe4b_@lG}~k`*{++}f}HM@yZHe6`)`$4}n!ZEmYfudHr(j&6`cWtD z`I4ajq9J}!W8=~Si5A}AS6@+ZG6%0G;P8(^qT6&kNCZ2{WEPSvr|Xci?t{QI69|NM z_w-Z#d|vn*4<$4#^IU(VW-QpjLtOkVS5Tr)V*!orOh3^3boEYl#C|x-Foqqg$!d8~ zr|w~S3p1+bNg$aUTi(VLziDRjj=?A_^} zzB+#^1An!bh}0bBuyU*TuX9oh^{XI@ETR9-QsV#mK-uSCZy{U*rQ%@$+&#MhDDT&< z&h>WhK+$UP9lMtMjxBS?emPP=exfZoWV$0$+r^>a^+8EkuFLNc2Jbc9ZqvV1F2zz< zTc8jw)d7u=)`3@Bmwes2*S2GyO%A@Cgt$P@fidZ^#5-_a@Swrs)cWnD35=#aTyuJ8 z2{pt*2pKbPt7Wpbgow-uxpS{Sr1|;~QH~{Gw7CH!{-lE*&t+mjsmP3tNE_bCQ&_HxgC`-PZ$X=DqaaW#hQ#_QaRH43p9-msrfHTz`5TS+dZGM?#xf#w zo1XXe`rKoVxQ9fj2cO8%;6P%!z5{!=fjhU6Zw@H94`a&Vz;Nw{vgSN#28J0?n3PzD z7*8;`6rd0Y&)xzN$fXD7f6pai?hzyzFu*zP6W?nMVeyhB5);#no0n}GpugRcb3~29 zXxAYGVMNJ*c&>#~BNd@>+JgwegeR*i|323X9M}~sREXL*3 z4x}6C*FSTVhu_rb9v-jba<#}r;P|fF*UF*NSw(vMT!N)5p}wziJe27+zF8cY4EdRw z>;lcbQbJH*DD8pS9lyeiJr8l5sdpjJs9Yi-?C6OF3|}8t~xOhik$7o-oSAf7H`T9=oKgWRuSoRM%-0^X)HU1<4hRJoFHE%pu! zzCBX4Masv$7sq3Uhvi)S{Yc$T457LnP`Y#LfBsrg!gfsU0fj`x$BS;pNSRXi499r{ zjv*miFnAzb;b&Fp(bFCPtqfI>lHbW~5`G^qMrQbuVx;j|M#)lrke+|WXZGku*i=eE zdX4OCGvp?YMP??5zxxG(EzP~T%k?894Z}rC#vvmx>azjmTB!IT*ctb@4F{5D z`ldjBAy2GRb5O{9E3pP;3Ctmne-_p|2?KEz50i&P^HEB*=%dC6(T^f>BBWIT+a!9CU_oezl;V#gAdAitjAZ-wKVn>0mMBls6)zyzn=t5kS-)ia+09 zxtfOw@5YGm7Zcv{x-_9dc`E)14;_%^7U+fG=$Pi}*>obC63QXl_JS|GAQcQEpIjf) z#g7E~gb546{g97v0N!ap3;%@~;Vc0wy<6Oa z2)5H)A+%HPHktcOm@iS`s0jK`Q86%R8kCVh{?S~f}ZGOUd;?z$0VJft=P zEm3MR>kRHj)7ok*RdsEEj%9&w|B3WPk8`O+HrAHt71TY72}0xc7}zEs``SD|tma>1 z^pcPXm*nVOsMqNgjV9g&blJ*e3BZNet8gZxe{AVEBp!4y?n4WbHx{bMN~2ev$?;6? zxk0AHH9lOSwcaC(Lo_ik^1*KN+yMUicqfDzG#W41wk=6r>V4(DA z8K-}EB(h5;7^0`l-_u>Sb=;*n+O`LNlfB1qd|j_iNL;rzxj2x^^T z0d7gHg&9b#Yq14g@-&O19l2QC7KT4VAXzq$)5Np4eWc;=Rr_LDu9mH}+35!T8G&;p z|L%e@ZroNWciSo1pasE{Qq}Q2!uQ9$$D!xu{1t&AYF+;blrC*$lrH8YVGCp#MZ{-y z^N*pd#i@NoE@pK3@7$;!J8UCaog+?%w!tSSw{nr#0vK3`7khS4qeU^QGa*o~@kreb z{JZyzPDyNd+%V)XabR47H24q!VZ;Y^vB&heqfnDvxF%%Kf6YDvWxoy_b5+F(SBgob ze9?{QbztGHGw?mQs@zFM@@>IoF}bO8J4j&5foDM;V#{4=&)|klz=}GTkHuNcWCSN) z=4$c$czCI|Ov-#{3laXI*&8{7bHpSEWie2}gdOXNW6-W9B2l7zPyy#yVpC_4*_MkY zQ$g79Aq&s|sY(8=4)I0^SZ~Rl@&4I*L3n|@&(?{5U zJ8<#;zW`tUYdG_NV)b%%8CK?&_%e(GdHhl7$8hY`C13n!z*VFvjzCSIxfTucoX|lf z0YjuBsq;UrNP2OO4uf#misRNn5!d&d2QCLPC6s1|sl%HmSkt(O%!^9RRLcYCj9>*S zY9=n7&G(eU0}L|#j&a1=JcGo`B42;t&y^Xj}WZxo1P?Ict{jWC8 zf3L1DR`T=Ba8qW9h^IOpKN`pqBru)oPss%lBx>e17j2_u^Yahs{h(~7I|t38@xN(wvf;~I6> z%meKeY`=fM(@XkVw;=17_iP-}V@)JAl}6SKR4l zi#{|*)`d~m{SqaxmKsMpcd@pc`^>~giObN@>5uEMy;1h~(Ch?WosTq`*afC8q$^1k z#8ouJpP6?T{4C(LeW3hu4pgz&2LTlNfs6v2!m@>SbeVvBtgwK5jL`XGSfgm}^X3l%Ne zJ~(ImI3zYd>q3v>#UcRCuP^3+rz4mKWsSw>Qypb%9}08Ad;8y(rn#>d_meie?=BA; zHPM@7Np%8lu}T5e`>m+Vf7e}n&N7795c-r%=Sb{KD(OP3_qbfvxz)M5yYJX|)Mi(+ z+cEcM=+DC{A90RFbo7kU;d#eq=SoCQuHE!MtMK<>Dl?fl=}%pAt=np zH@Cn)ryrWl2Q0`2`qd@^h95*?=3e%#;{4BJNo~^zlx}0o*sa-RjK9iIVymltr+ac< zaUCf*&fF2>@39UN&luFxsPtXJ{P ziVv@gE?369L!C$^1X;9ND~U8UeCEUvL|H^XazRu~m7Io0 z58kJF$*!C>=GL}(*^EAKKuCJOJ_MXkc(Fs88*ny*i5?+M#GqTHFCLa(~(al}|$(#XfSu5L}Nf705%@wlTuckaFNR4(lULsil7 zi_MRDEhdC_&{~+UFKfG}p!pKSu*0@Rns2lg^#v=x~h-o z+McGC-mnYOi?vqCR#DVitrUvXER3a%DG8IioLZ6ajwfdz{juo3jBEynE>!vE7l&d% z3KiOl?AYh<^=nmVZ4c4-LGKS1q)B0V!|jsW*U=C-wCk%$bx@dz-4$`JR&!en(5~)& z?_ek#JG2XudThrQ0rbjgUszxKB)han7=j!t+1mc~vh^D5)Laszob1pQ4-GwphS%6; zuavJtqr>4@Sc(}N=G+83O~O9Tr(+c@=Wn;nnn00t(BVPZj*l z<_wvQKYTYbHDAHGwXSOv`z`QxrET$AuAndH#4O@m*VMJB5f+v1noib)ca+ZAt_}UG zrG7!ZGLttK82oIyv^)Gs5A>S9x7U7VVb(`%`MvfIr?{D2eO9pI)QXW@GAo)UYqa5I zojci!v=#%r(w!6|8QH6=pS!yvv1Zphwq79buV{$g>s_00{VEL$&3R~69CmG8V*1ji z7xVTBChlhFn@Z+#LR@hxfL{1|M%T2B%T~XMJIkeHgJ~O!(hri$9rMQJL}}fRGLi?uf(F`vhWxUXyKhsKpH?c!-uTZ3QOI&MbN(C)0D&;;9t|f(p zze8uQVHP}8%9dWFt5no49Qpg+>Sa2ka$X&fL)I@JKZ$vw{k8*7OoUW(bQPjDUU|D8 zE_Yjy#$@?oLs+Hu>UejP!{2*P?{pN+hsCYD?m2@&hURR?s8fH=&ivW6wJR$u2C&Uk zOG^7>Gy2tec_u7ZrHlcKAnW4pER$^W9&1_}v(k>uc)r7R)f03q>bGHDgXZhnZ<;dR z?C3f)D+^GeiP;8$B(-<^`X%r%HDc<%kvZI{Y~Ff>o363gVw{_7I47c_ zg_HVF?f@+Dh7Ok17pM8Do|y4QW%ki)zZi_uE9uRd$J0!H`tTveW#yqhvh8Gro zqrGP)af=7Dm)X!wT%=XfqMvW^erwXo`LzZ!m8y-i_(?Ndn`#Z_>Zh&DW#T?JGF?bz z-7T)*^%eodX86Vri4Rt%`&h8CuuhOx&5CyCh|CP zmDz_qrr3!UJF)yGzK8DpTMeMs=y390#|}uinrmh#33lkuYD>Lkjd4wN6J&EGD&0}P zz1O<+x?5saQ+C4kdFK+^BiuBOR=gp#Cnz99-o>ABYIl-&hA+Bk*BCV~antfU= ztGX^l^1Lp2Z79+StJs>Sty@i~Zj)SxLhgyKu0v<ZCNOuX26@0J>%^Pb0cKrKwNt|LPXhtGDE4sS%af~(S-MzNz#4=!{Nm0Z!GM9EqnE%qtzO{UJa z+B{H4x6&S>{c>@uLTqOb1Fer3c-N_H7zf+c4s~^;O^U4wtENUyoL`MyscIEnrG7YD zw7J!CW=&XKvf&aq3ZA}Qfj@|gnxfkEF~zOPZN~V*^!FOBxMyPCV(r+k*kOMWb0$%5 zF>H=wY<`_@NV@XXqWOHESy#uSI9IHy9Q_8Xm(7v<9J|>h$?{Si%z;{kUzrs+?iF6h z;(~6rR-}KmFOI}TDJ@erR@4n?8+kOTf#N-K^Pk&8jbg{r<8#}JW@l|*-#Mk8+&q2T zBKEE;@V>@~CT`$qYF`Q8Q51fbiOx)oFzPQaO$Z3KnV$Y|`8tJ!G&ZdPl$h?%WnSWE`};BN==+-;eBX(WV4jMV zY8LGXCNib4O*_rIya4a!RRX<}?RB*Bg`kq`c{rybrktCHTzLgX<&Me#CEO%w1bN`%_8R8I<2Y;t{@;v5x;BFTs}6YaBKm z6V3~3*UlJm>MZsD*a#ej#7y6|nA5%X%g3YC!|UEgr_pr`A<73d6rozNKAVT@R_@Bbq_n!0lo*b;Lo*2oupVI zjf;gPN$1<`h#z&C0ClH+b=SVs&l%WUpbf@`+IQX8V5-GOZ^UOLlf7-BSY0DK-QvfT z=YHI~Z^OL*Y{moTm=kM7Tx&R7!i#^LWVBeK`>tcd%`+44{`v7=Jj!3+{m+M=?BW{S zj!|IQNH=p+tvqq`BZP6iunmz(kVrF`=z>Qn5mpa`1`p$Pb!m9Ysh5!FQAcOaR$&gsxCc;1` z_o|i2wyNsKlvS`&n8JCr&CI`A0mITq1&)lxHH?H40MxsqFZYVR9c4s3eJm`n!0V6P zfSc%Zn3CNa7`GBVKy4ia_$86@TlvFKMvE^svH|gHZ!(twoIzvlt$UqN1SKYRLWdab zFKSrUXm!|M(-Ug|?rp=Y1LB=d5CGKY+;_M0)v4PkmJ%P$Im-XsL0DMk=ow=vcTiZX zDzF@`eDhK(s@P?$F>)}$>qx!k-Pb7z&dkdDTY7)!x9+vfgJZnWz@wheWxpA7(R%3S z!XOp(N~q`XYuIeIqs}}bX!;}X7W2g2+buQA5koL8<Lab1H+n~fA-4Ulg3joM>T)II)B7;%vG#q1?MDg| zyFbuRo%b6?9xag#ao$bSmoZ&h&4{hWdJV=v_Dw=^EjX6n9RTI5j;ASs1AjQP{Cm_Z zDR3IPePg9inxkJQ5bTj3y6yGo2uz#sFO&2Cxi4^Owy0!i(2B1YHv2%`;yesGIRZ)@XC3?q6X>XrA^!Fltsc%f z0h|u~jc>`~`n*j1|F{%#=p(6?T$&JCIQLTU@sP!4J2V^qh6tk$C%6Sv-@60qNap`M z{tdVAkOl=rknprb@UvBbj-YE28V=N$YC`5SApvGG0gQRhZK?j>-lq#2K#3zCmC5+` ztGK2uAEEfuJkAs)WUA$|8*stG`_soTFuVl=kIw1U2A;DVs*XSs7cP@>+BvBAr~ZD) z9e^Ydhp{UV)iF7n6aY}>K5SD;B*Eo*(CA>!2{B5ck8$6l%6u>K_iJe;=OKGxZ79oX zwBA9p7c9qL#}*I?t{Wp95=Oj7ph3oc7j371eh1WqEs>N{r+N7fu)<@=lj7?_n3;JB zM~*r#|M=UB-f0;HoCc{Mlheaa+YU{=m1X$X(EP64-zJ9`qdLaO>har+7Vw&GaDY9` zPC!c}xG{0sj{p602_&rvCQ*Ca5y@!o<$vbM{M)Mrh292UHAjPvH;GjY4_$`f+X1HYg+SS;9 ztas+E&N^Rt6hzsw#rz19r4x?bD#-J7n+Z%jl|FJ9`W{Hm@wt{pm#uN<0<**qL2u0- zW0`?0;2<0G=GD0z#Pj{DJ=1c8b9Fd$7LXtp>^G6zKfvIh7jxwT;n*9fKw|b?P>5s( zs#0Bhxh<|M5L<{rg~DDn*Fa(8vy$7Em!*TG<`0WUTT+E;cC_~}DqM^Gn@#ps=!<~cssdZ}vY4xi!X|;~ z^n{*zGL4*Hz#J^!r%;Yu`5eaKhxBdHVkl=a1?Wf)4cRr>dWdXc$B9GABSi3H@fXoxQUlBSkh2@5#7IF0h>VieD(W|Yz{vN1A_oHle8lLadzS-)@Y zJ0^z^&7D%AGBQ_C3CV+-Xy?AoG*-`hcvF-$lQlh4tr&Li@G6oPix9Cln_k0236y4T zLwSf43O2@~R`<&dOhH=XN&H9#d>PsxRMM1h)NHs;#P7@)s-tP2{M?r2OyL*7J>WM- zbKPmN#cUF5Z&YqDEd`37*Q@~%PcpM&{fkZ^8?fGKB^niEzk!0vRJ*NHBZvdIEYyam zLDJVHq|hvrwd}#?XFaR#aM)I<_br8Q*qU;VAsbW(=x{?EMK1^U4Jt6L^}+p^YTQ49 zp;ker3;QrwHX|PMExC4L9J+^`DswOXd0N-sTh3~PF^P37)_(`FCf!aI^X@sQ(!@WW zTsb^xJMxc9(yU}R?jN0L0%Q#gaCk?;;mtE4foTn?gbGcIaE+!!$cv;2Sm4JO0=UsL zMs7>blk@7M-10k|y;hKO;P<<^0VAa~$S*gqQ8$FxTu?&QQ`q-)>s{Jh^{<9LmRXmX z3iDBve*N$NhQH^E>f&Q%=KF+V-=MH(@|wqyG~$z65RJDi9(}l-$#9-h$nQz5Y9(iDQz$pjjG@(d;H_|{%il@phpL`pU<^0 zb{{}A2_p5#^N2Bd$*r1I(N|)3@Us_*V=2nEq(iy0W_sUG`uj7gr6x>22c%zluNK2y za0GvPBnRBR46&?AZcAZnLmP|}PCvblgN6bWIfM{TaR%@n2=mOpwRyNMgbYDb{&a>8 z_>qlT_WdhDP!_5JG9g`3d}i^SuygLcr6Uv-Sn3|7uM$vX$oY;e&?D+C%)pMasHTwh z1{_$GmH=`p{^Oc(vhq1DJs=YH(CxyWA;l|oL_GV1rhS7Ef6;m@Vxw#sITj9>@FMYa zSE%a_3S>Ge2u;2YtE4rI36(>rs}~VZT!=-`o{x*q2aIun7HST}8TZr3Ak}i;p$*jklNC8x&7UtQz8mdd4GpJAe;LJJKj9l8)#v`d;wPgi zR4YEjG`^E<$$pP1IeY=*E5@Z=*3);=aB-+c7XZ)!==k$`GO9Tb9+zH2qz@_)Ou#wE zr4jI#UuS`n=L0qPhQ2f;V~^kYk2lxvC&v7n`**4bJf*d_t#?#3scVDiX%xjbM^r0; zBT$e94$(eW$Tqqks)>V-m0a#e@Ea-?z~@8dybw+X@8?QjpZ#MJki?1q=0S-QQsI%O z(#VPRwAciwe1rfFx0&wGbl;h-itgVY%U8Fl+qcfNOTIbnvHwX~n7^KpFV&6w{YWZ1 zwgS*mAtuuDm9KKvFPmd7@-sm1x55TKP&d3H1lVcomk8Hh7d+WOiT4BM(4rc#Z-l(A zlX6v1FBsWi_1G~dsrl2r9GAyFjD1(IDG$xzU-kWUmj5+VQ>dt*@{T95tqWAuDtq)1 zL8%B~+uyb~q5Q4qB40Z1^6?SgAmEllWQRMzU9z-95T|5=UvZ<)nmh2)u8+xkqi& z8oJb#Ylz-WUw^6;Eol0Q?6Jr~1&;O0Sx8G2l09xKp9N~b3 zcZ0_Uy!9b{aI?({;FzjHaz!EE02Lr%-fMu=-;V1vJViYhkRWmrhg8FzCA)?)8k?J* zeM{Mlr(Btff>RL4bow-CzhxpF4aoX7&hLjz5bBh`1VdHS~{7@+IU^9Hhb|UzGGhrqSuQ{Szjf#r(9f8`X*n+&p#UclZF9 z;6D%Gsb484k}UmC^z~89cw)?udE#^|{)=7OK0UDsSGoQ9SNi$q%>QW+e;LESz40H` z(6{I_I$41@K(P11OY66arY{6`Ofpq$B(_xb+i(wfM%yqp4ka_{T(iWjt~$;6C8vf9s#^!pxPTj~z2DGU6GRhxpJH9$c$+ zXGZS@>Cff0KfssWZ);u{Fl@LnW%MYugI=V~%xYxhb9#Sz^n}}5c0K;jef4vcBvN_k z7IO7rh^4+y2gMqp&Imu!VrM`c-FHjBCqQ>@+O~Sc?+;6 zHX#Vo-K8R+fP{2QZ`f=$-ErpL;M4E>z2A48bN)Ej@w%R1%f9cmX3d&4>o+sMiKqO- zK6tqq9i4zIUSOQd$;rci(Ut%Im&+diZ%F9B=fKngh(~eI6p7g+bHlA+W@}`-ix{DGLlLe;k3Cj0QFkO5f+d)tlD=9AO~tvA~rd#h#tAVMEn)FLI}F_ zjL!jv8jt}AWNuKD5aGgq;6YIz$wJ3)}6pom& zL#vk=E`N%=-#7;-(+BCHBdd@+K*rhmIB>ZmY=FQvA=Zt zLSy{Pp9tN-h2$z+vw%zdYHW>WC+*({cgQx_SPLd41jq(B7T}-&5mwVX;TeNwo$qgn z%XP4Dv+-%C0{R$@sh+~rZj3=2qybVvyW*B-5T>Y7*x+&auB1~S)5C;20fv;MmM+oM z_m6ACelr+zeb=rtZ}Abf?P!?&Q&I7Lk2IPIBvS%Y1nnak$RWq^1(##pU?p_A?=~U> z{2#9Ekd`%^mJjgUDIQemgAsB=I7G$ix7R}7g}&Wn*RHGV_-wYwbIAKA%@;+2&2r$V zpiPY4XLsvnL&D)CmFnHQJ~r-zz;8QcGZ_it0pZfwsat>WfkO z_>IRL-iqr!pYkTxk@>FQn---$2>GSs4?yG?`h)237ddp@6gkWZ=R*8C zn2zt09okF|drBiWsub&45GdQP9xsrPBcY$2N*!&FAg7@Gx;UhY^n_DfvpLF_{2lBg|-GBUjDkAE=Z8I?X z=b<}E=D#l{SJ2-@eRXvr&$k`Bw7=xT>R!g_DODF6n{=<+YsszIC`iTfkm z#~;nN8d9XgdRy-}^?z75A^rc$qVLiA{fOCn^>V94N#K7h*QGaH#%h?Q3Gla{-%Ly! zLbd#-A}$c!al{=J@J9l7MxJc@jO4_BsxT$(6Z6G;5qvIJ}?YO!q`y-@lz?miFZtWQWrd*R`G^ z;J%vIYFL{1@0R*;?fpSSGsNlNBwsph{^)7)e=(VJ-uulSiv#FzR@kRj=pm;FG`W|8C5P#nHaIW-R`{Gwq9`*l9 zpwhq0`X?2<6%v>Jq{5eIO5rzt!Lp}1ZwKIDGTZhjrvFEe3HQ*RQdl^Oor~x4>2(s) z`h7bFez@f0;F8Z%UH`8|@nPbf^L$3#Mp9&qL*IOS=9;k{<8S-l;p9SGrqnc;)Ubao z3OQBw*O4O3X2r*E$SiOhMRAqtPi~T(``yAu-R9GuJZ1l>syUFJYjWGJnMojq2RvG{ zg}53E-gu95if!l8{A+vCgz9BWeY?jbjL#KsxmW#eNH0B*I=8k@J!57*uIAYGS@}1i z#)yREx*H6$=3`#7$)yi1+BAn(O_j%F{$?*1#ajZa_&7_LE6TCG})SO%BUrUY5asm4?omNbZl_3hx~Ss@V~PC(Q#?n#V6sCoKeTN z`5sl`78Y%6=(d{9+yM^KAEiaYL03J0pQcu+g2Obd+v00jQoG4o$+(2pQh(#a-_E@? z+6i&3sGmnTBjF1gJKHgtA*#b1|FFKZ+oxxtt@H>tWwVeEqrtKEui8fK7j%=gx`A2DK_Z!WAZ4rgZd!RORwl5wuZX`Byr)5OO>f>Rke@=J{$hMvt%;>f3 zuIz4jbB%^kF)PlZm&T9xq%W|sTCc>32YyDfvySsjW;|=)Tgu`4+*l%XTlXIoLP6m& zx{x+;TQ&@q@saF{Hl?2~qc>ahDHI+yG_n6@*>kOO3T`GtRc=r>bOUm|mdLkp15+W+~k+HAn|Lb?+lxaH-CAxg`lIqtNW9c4(F$Og`9n8Qh?@IOH(wl3}9 zSPCy?`^j;BqyP8f)2K!QMSmW3+N^!uwd$PB4RoxZJJNikE=r&rEC1s7jp5hNKJGp^ z%-jtTxzBI~MHQ#?LKV;{4^v2~?Mx=H@qiOPP_L8xhK(uaTgf&iL#O!XUC>HQV9Wf= zK6|1PFHII$>HdB;-`&5zH;OxThyZirEhMAD|lst|w*FMdx zBpCpLj|Nps;GFS*g1&23ip9{(g*OEVLEd`|QfR7rSGo7{zXC=9qIuSVL#xxj@94iR zV8&1%>NogW_WmC=Dk~il1dg=-`;3OS#f)>1e#3*$!jLew4J=I>0rq^)y|r0STIt(Q zU^Lk|Cl|$Yo~HF0=0B_0T(hFU``)z4kA}v@gUKv+c1IE1J}&MUJ(Wzh1y_otsney6 zW#;2Q+K$4W>|48Km;MKZzl=7VcQ#44u4MQOyqT=Sg51QdF;i?LJ5&FjwExJYQ1CXE z`Iz`mR_z~TFr|?HSvkKy{}MqPjnqVrFGI?h-diQ&d3q@mg&P8Znh%X2*TpIBsuW6-77FmGhx4ZYAZG3CRR=Ox;_S8t?Qx<&CA??OfLN_8{2Z;y zlk$g3<$t|7smGVWl5f_1fm~uckDT9bak8x(E~`-aNj57qc$|0oV~;jMdpspHm}QC& z)~?~o%dsIN)*cUa<%}<5;b^PP?@q%H3MY|8@E5amdR_%i`}VA`{C3y2)gB2vAgrZ3 zahPYy(W1+j0W9Z!j6Yb$YGNK4W3cs2djA%%w{`GXfnr7F{Py+~A1VRFj-1&wp7s{W@UNk$D3%%lLnY^^H*(O5dZ?VbKx`VCvr3rqL=9KM@sQw zs-w$W;3Dqqd4utYEQv#7CDCihZS_u7eak7!o{fnd3I!1G5l}h&!pHZqn})?U?HtJ| z+1!R5SJ0)~d&EfEd|#`#>(%>1SDWY%`QNTG- z3S$RNPV$RN%e;%gu;BmKh&LFfX;{hzAaz=--r`(62~?3;~dvHH!Q-$`(N zABjkmQ7%u1OXjvJ@0Q-FmBg=V-`6a<-%KAOCbi$koYtZj#+8+_@DP8^&vav8JNeZ@X?G{#9)cKGkFej!jk5i%l-|TpY5o z_y_c<%9k6z$k1$CEo9`=ls0hx6Q1$UPrcuGFpwIbD=`MQ9*b|mw~yF@nKw{hscB13 zf&r4>q*4Rv66`N6#)BPd03#qrA~=-?#e8t}gs2Q=Q2lqYeb(<&(9;?=kt~wKn1@exH40O_meeb z?Sx6F`0xoz4d8)e0vKMA%tKgA4O96MGIDb90@;qC1*W(Z`m)QF8H$4;cXx?&M1m-< z&+S|gFy0_k1HlH! zWz5{;K=!OjST{bQ;rEsL@x_9d{tZS<=q57c?c2j27Fy&c)ji}8NCcx3PRDHa2h{=N z#PIFE_f_%2X!YW5qXGAgB^)o5-=4SDS5MG^s8&lw{WeM8sV0{>O?!wxHuHD9)^&aPc zelqRIvEpMqrZiu#bh|#QKT_m3rAw838!>)^toi#p!h`TTgbXUm+HlFp7M?j&1f#gZ zVir!9HuT`r+?W{tZGmgGkLw&vopvryziXU2F|WU^^n&|_YZQNDcHP#>-qdSoUAs~) zkeKlqZKp#D1uT?CB~<$G?~qxr>;XIX>u@vrlftYe z{e0CDn8Y=ihv2YOHvv(P%E$fG+D?HK4Te04mc*1RjAl*~Id$O$C9y7J4gT>H*n(|a zwS9;F`-po(5X7JFjvG!YmrTO=ZNZ!o#EUKH4G3y`qPUsn=$LUIey*6sCED`*>B{%p z4(U+XFBKOlTdI+d53u-2YuwD=-mBYl45B091V153Z4~^LxK|i!+3EEgKV(ZO@-axT z60q>0heaDjLqS7N&wrv#{q_*f|3Au)ctT;i*<1HWgc6GV#fCE8XPS%vUw zh^C3gMCS)k0~YVs`(QTy6^|*H4dl>B`K2+c9!Qu8kK4cwndAPig4?kb{35{MMVogF|F&9hi=_~*9(W~uPYIg* zaCGyRv{>;zGH3DjeXeRdQnkGRm(hB^Og(-d4PZ})Ve}GLdy0m$q2ZS zTOLAtv#q|!Aq*B2aTs?*6=qw(y5xcXnAa)(+;(tfd(~p1kqbXQR*y*N$B!G@(7?~; zCi52e+=>Qd3%+VkHp%N%XWCWj%cs&)Zy=`mw~HSO%;X~;P6J$x4>rW#^z@)#f80Xj z%$Q5JwI%|{O`Ix$xwzxKqF>Vh4+d_q>l*^ttp(}r(<;RUtDTg&|N4&Rriu2k&)86W zhg4!DiDcVsfF-||1ThOhIKT)KUc-vyD_q$d6 zH?wCSfeX8xBK`iTi!$`S4FQ?^3&K_Y<_W0W)rCV()vx4lc7-V%T%Ps@M^jA9ugn~X z&LQT+6V5@zDPWvKd^1yUbxIk7A1rf{C_gX$hTP(frMHy_xwif|>juaf4PpS{ys~eU z`K6V?sxc*r(>$5PYqUz7!Z^976A2q#C@tg5=ojMta7JdbVd+xF_Tt~AUn4I6X)#OI z(>Fd6&e$RFE=uS0l9)ci;c{rzC*4*K(~fwJzR}^{p8+xT=aT3N=?cJEQo6&38P!UzKV9kwEHDy)8nq03L4iSA z%3-Pvv}i?qxY0Stjw_uWBrU(5qEg6e6&_>l(IJIcZ2H=_pwG4OA5wz9J!CM@)SZwB zu0=eM`)vn6RVX2e=(8>V_NYN|kZ>zKvjN^w#oeUGAL#BbYA>P_AeS1qe*+k32u{)6 zI|P)(js?IlRRLX;iR15uorKC-e!FHg)BzC;Rrwr2de`6+O%bv#q~YeXAs?25`xRa8&ZYijRn97H;rZ#seZ!r|I3o1EPz32$RT-SMwf!G-G5F- z^2U3M4J2>XI%fkZ@5N;OMW!;6N#I>30wxRq_vuc&EL#G%cj8-9X>DByg*1!<#>XYW z`}PUQy{0xIdtg&Q`MC@s^rQYKaL>A>_$##6CX$3Mvpw1faa9M%Z>XVstrs`AE3JHU zwZ~9x`7^1zRVhZbuojB)K~{kuxUL9%TjEKCtkd`!ZN!6qzK4_IgnqTsp68~YplJdMjhZV{i-%UBjH!M3 zx@~Yp*`8Y>k&~^l+!0}d>l!v(ER1ubZrXh*871MQAvSZLS#b_6S2&~`+PcK%bAbdS zs3DTCc)@sM@UOtzm=e`VtBJ&fytMX5MJunb%L>)rWGLAr)uO5`ws|=Ey@J)4B*Y3z zbRhT?8M&P$QZx5X*lVyo9(V~D9KUx#dkC_0fys=D&)dM+l}Sjx_1nL`o#sjkX(g0H z(9rq_!u?jk02lkTGM!_skKBHLa33QhZd4(OZ=r)w4$M zAu>(3kzQU9rbbu-zEB2|7Wd$bt9R|9eU4-%|M>&okezh(YN^ld2^bb6S3T}Ezm0m- zW=G_t-Gsj{k|#wD-Ma8ex8I))_sbUe-eJ~#<2XMeO=AQhO`7dy0uW+U14rAvIu>Sv*O zoxYuG{S*+AGLLaOd+$fl;C)c5qS_RZ|^%Mc=)?9c76qb2FI#ksdp~LqPQT|!~ z<$e(kN$&CO9D3-ncAj_To0P9QOVY^w+x_OVS)rv*Q_Fo~0I=Pw0ogfTPAsbjf)jw* zZvdLBeRHV60sVDmn_2m6wZLX3*1z!xQi2BA&yy#j)Pu*MPtHu0=7lo3R5%d4@p;DWMz2}XY%lI>T~*e1irfOx`YTt}AXJ69WhA7n1<+n$ z&?^oEq?Hzpahn?hjy{v(w6OuC9-kK}q=smcYIiA5v*RbI<$kT4hHbdemFJCs>d;$z zW~O`&h5JH^owxWV7D!N37Et66wh8HeSzHVfYs+12(dC!XFLNr=VrkA|A0cfP3`zr( zZZjCK9jK_W94rI66c3r*6>}VLu065_iWFm(skgrIT@+jl%6)m!x=XE+v5ur06zD_ImYlgNa%Yed zKI=FfaKIb)N;!Ginmp>t(Vr2fEe%Nj@lsR!&YRIxe4Y1V5&+r4qTf7b`20 zftG?vg-_iC|LZLO<)lz9!|vy3`u zuH*aR#FOH6pt8Jx#O-FRY$3EsiSR4BZ*BB%`G_v%QY}Gs4E56Wu1%y2WoEJKpnWe! zjdTi5i5|no(x*13Zw$Vq*)Dszr(2}I^0?t5$$kg(`;A0Waui%fJxV-AY`XQ{Qjrx+ zHAr_yk4t>x;xlr^z`rr-X_IhX+(@L1wrkty*JVcbq)X|0k;_p9M;Ak2NzIjsWhV80j{~hS2Vhsl%du|#6I53w~f$Z z-zJn<_&J#ssfu9IEkDoSiVlgj9Gx$o5X-Pc=ki+2i`H5KeaQ?zy$QF{+=N0oH$wb6 z0DH;AUgLSJr9pEYht&5gv11xc9*BLL>DS)mE8u`LJ%yM*LJ<5=4-jW=Zwg%;FG(FHga>lBSQ-mk-Q06jv8~*X z(c+;Zg3v{;dCj~{=A0??O7zjxV){n54~hQQ7D4X60w=s{-X? zUyJRvO{C_&p&Z;Xqh2-LzH#9INfyrsjiLwlQs5mPGAZF9t5a=Q;L^8ApK3`5(yU=!?bdTD4+<%?oa!3?`qr{9GjHHd z2SUu00m1w#pG7gfYAKdCr%OM^nnstiZ5#*sgc{UD3WX8&Xr6lfNXpVT9a-L-*y!>j zO-@2AHMvoyiOu#F1eZjW4(P{siMK0?U~`TlHHB^E9&6o~XOW_&vL)Fihe`%DqAf?( zt{Hyl;yHLc&vM<|TqL0)?P2CS3o>j^Zj`t`la|BrTXZ}{>G|p}CHvd@MJ!z<>$x#0 z5BI#aUoFYYe2cQourOD`xab+Zjk*)!`8sk)4lNr{Q}Q~@LBzQx`{)vHdin0uP;Txn zUyG6@_Dc?qVtIX?E@{}50ZUa?K7Dr+P*KRzeD*jBB*^B(FxetoB0j1r%Y&txre>AIzEIVg2AcDfW~I_}^qw)QmT+f4W6AmvYEd^QvM!BN z6a%db+`YLdOMZ(xv~BS=7W5jn{&&f=Qgvx=*rw5hb5j(S&gVAQhgfFed&}HXU6Xun z*|)$yZpmGvtFG7N>ni!41bca6($msbs&rGJOQtaVo^Hg4GuomTg`@UHXFurj^E|qc z-}I^`+gB4alcSXo+bh(>YA7%mk1Bqr-LrWsnc$rx*9O;Zmgz2vs>z@U|1u^m#>P$~ zTjzT$FVXinP;$`=5-h%YoQrH!^D(AHz0Y#W#w#g;b&d`R6IfJy~=9;GM03FZuciATwsJ-+k+GdTMl0A>V zL<{FI+GgHkDaluF8y*{QjESyr@GO3>@Ofc4RbeXbL&kXPb;H|Tx#h-CB(B_bA?y7e zs$K76oAGPl8IpgxHy@pcbs{@GKLrw}A5(IgzaX^gI%PEO##>4#Ey`a@UbzkguH=3t zIy@U)HtlON-JK{2eJ3ee9$ZE9_!nD&5B$rSsL`bSYv@8guhDoE({~42^O_vW*o}Fy zyEqObrvc*v?Fjv?;`h;^a|kpLc`-&iy;BcmU3%x-|54J1G%KAd-C-QXNj=73__t;;G833w{4NuDY?P z=T)Ca-zG`IK!{2F1}?Ap%9O2>Ss1Cu+gmKsPfCA8%v(JI`cB+Tu4tR@}Q}1%ZXn9(|h8J|<^vh2<)hcqElVR_&U~<@T_yDu!xPosX4? zpT|uKZHOo}=F%iIXV3SyB(JWr>+;hwOOZYLF4x3sK@jfP=9^EDRqxvLK%TDEN> zB90YzdqgGS4(5Zmqfxn&h?D55xg(zy+U(+dc3bZv;b}4>52og_xirFK%?Eo+Mmf@7 z@xwC2OU5matJ=tUavtIa@}Z9$&`yA3~|6Z;3R+(ue|0_p1;$&#=wZcPZ~^I_HKF zAFFaCCM&Hupw=;1r}*92gg2!E#al9q=&>|`yR%j5-D?#HxFV5{X#OlIHaJ5q^-_0G+~l1MJ|6ZcpG(31sQ?R_Y>u9hkja;}CsmD6|P zS%Z4c1RRmpX?h^4`}#=CGp#$cMzo|shq&&fMHF0neEDn*?_)}7v9LQeZw9tj`HT$| z*E-=USgOXWi^U~GX07{4qZzwm+tw-4(LOUJYO>r&NATg$KwJ}MQ@2z@}Uz#Jm zck*?gJ!PBOjXev)>utAgy;)YDrT2Vi^J7(0BP>@vfs#;_snsrVMYPb$eT{Bm`sRn3Nl*!0)s#}?k`*N2NpU4D~Yr<4aQ$>EN)!Z^FM__fx!BC~Xorpi;q zkupRq-=&)EZ>t7Nk(^E*KdAhL(3tU4P`DHGyAYg5&?4!%M&h8ByYUV0`s{q78!I!1 zb>%83Rah#$e10X4;=!g9Gcf+PP{*&^WeIl-j{IZFXMym^}P+U zCQ>yEs!XfQZ9@jGLd^D6P6AsSEpAWbl-gA+P*xHev!SZVzAl*|V_y72MY|GkSiQ}{ z%h3iko@MO|%d5q6PGqa)y>YM0_lGF1@!h#|r$?B@K>=+QXtYK;VeWi8N~l~?ka^#H z`HSax=t5YK^dtLVd{Rn9xUmI-((0_~9R293l@NRjG=Si2x{7*Kui0e2( ztgs+d-@rh2?L(;8cJ10D_}}|rx_o7RJh1%mu3e{J!ZZbc9;e`bT;V~O-Mc?P?932MQl80>$Pza-xT}^8#ah+JF-@@^t*OfGhEDTn ze~Gv3-}n>&gRXZNnx)QAxF?Zc3b0mFJ(<15 zR?6V*_6S4i><_$@nPSz9-HaDr)`FB(akCzTRD)VAv8bbHgZ8xCOs(pwwGp6EnmXf# zQvtnHF?NvF*VmU9H15cVDYc%V?z0^JN|dZ#UdHFRe!VaL$U)n*xv_@gZg{EV#;W%G z8z{hQG2FZByw4#ZK-o9dS8B&;HhK@!nVmq!oJMKj*1PxM@q!ItYpj_#tRQ8{8Z8yY z-@9MGm#fp<+qTE-0n74R4g=Oapnkl<5WO_f%3$)PyjriII9(!~GtZ!%c?oxGudTNB zh~M6_?sBJc4!y>YW%erpnG`_cdLHn_i*ou{y+p9>`({jiAp0skh+v$ zTM}i??p77*;W0-)q7rcQ_UkM((-jd^&(w4~vKl4eJnEcGP~w~X;lqbKE^hjh z2{qVrI^~AloJ&eArzpP>H*)Bzl;UVaeRF`35{5dK<@sg2P;N$*Z^Cv`E?K_t4%Sgn z!M~u=i?o>91X4RqDrOge21$$troYRX$9Db$hNJD|6IiL7Q=HRx*p@PLNY zomj`h+r{wqP3wu4MCL~Zo$PMb$NU=dpN7%LTVcC6)N~Aci!9op_TAbk?Kv|CQ#KvJ z2#UuFLY@QzM@SgI5}?m5@>@-*koI-w8Dd2C4BM3g(T)zXd!)tg1|(kY0U2$mmOq9) zZ?uvlaC5h++t99Emr3xyAt+SI!L3lMWGa51D8TS`EFwbFgt&I;~A zv=;vCd;Wj-gU#Iprx|>*A0E+0-YzaIc{}aaBbWPk_wFM=K7cXCnl z;S(!k)5k1^+K=@$So94wbhSB{pBd@Cx-ThujNlydtz+V1x21RO+6yz<^Y9SV=I@%J zth)%s?Yj^XL2I>1)cy_%j@5ip4-(J2{)4BjF01tzI%}KMP+#(z5lf!>94QQKi^mM>tPRe(>A*8 z{P2?CyfZU2A;-sBWOr?MBu9RDx988VDBT6rmZ@uiI6r0$yGIxJ?J=w3qxnF$6Ih`= zd@rUQ{G8cYQR1;VR-eVOH9f~o8u%{99`b^wVrFBAJa4RS)Fu%c1|Mc;OrGHL< zkB$6@sR?8$%cs>BLx{B(X-iuLu|O_pVq@1YN_`*z^h`_ngSJMpU0+wR)cP06 zR_L6WZ?E|aHVou5Hp<)@23`~sX!To8>R@8sxy2Z4gvtT(sRk%)x1Itn&UqVnT!Y17 zHu}_*4@P69gT7B|tn(|@NWb;_Ukvc-0EWWhNJ!&mt`5(XUH6I$e%jIjd^|%Ws^(41 z)tS_qjM}Mc3L~Zugq`!+lne^rhbYw`9G+81&pT8822b8*2wkx(0S?i&$sCYRbC;Gh zv%uG|QhJ6ZKt9Xg81ycO>hL@{v`-X0R9!6++-XcoM4gq!$@&8e{j;nPu%wurMe`t) zeFmw@%#5U>;)C9LyIg8!&tc;`KiwChZKdT6`HOce%Y$=PQxz{^MjC;*#{A!ivV!5P*KoRt$gG2~{)?D-(~H0Yhpr^ponez_fkuw*&5IbEKL8 zTf)&NN^asBuHk;R=b@I*h*Ok16Z^U1p!4)6s{#G1HH2_E|8YLMMRSDFQ1y)^nSNQT zymBEnzrU~8Qi`KhcJl_-K51Yy?0Oa3Y(5_bgoi_Vy>flpcM3UdTaZy$7g4Q2Cb}9_mikR`_zTgY#XOw*LxifA%wIxz6{pg=ovwSo>#X*;Q#R1$A)E=B-EuihJBRzE((53qV6 z)X((r&3rkPJ6(4?wP4UQP1KK)|LDjNC|>G&J3aZfv(Gz#@5kXRZ7OtzR3*LSZCA%T zSGT#2bi{1F!t9r6Vgx+h7DzDOis51(v|P;-&>g==85kAR05n$hz;xx1iy87&XKcJe z$je|tJ%#i`B6Yq?e(*Rs8tEe#MJZ3xz>Q(#0+Rn#>+dkPG^edi3)Gdgp;8s-$Jz^| zPUt8UE0KVfUShw|C?&6YgeW;^=$Z0Ln@D}29k4*SazpzM`K(^N!3vg)>0gCrUyU6~=ZZZ}Bl+dUYJl!L`|g$NJ{6o-$_V#f1uu7YDdzid;SB{^ zz9HUM&7r&dfipjEvA#+2$I?qoVGA3nc(RD0an0b;`%b%O%#zAo&D8pCO=ZxkOtb8G zg7;jv6#vTO(Ee+&j)SU$E8-rYgZ;-Sc?+12E>K%2##%b(>BAnH!Ls0JH@twPG^Q5k z7NS6^RPM%4V0dK2Lu>wqb=sBqH=ot-qU@kQX4@25=-Ij{Lnq}MtKI#Z^2uC@qURQz zuKhCP!uz>{uOFj8(bGTS<}p9cbd;D2#r}mUSOB^|w-@5Oc}@c_b)`bI?8`QjEX;=v z;KiV#8U;4>SxuxJ%lw!=nkbZ=zXu0s`(m(d$Ah>Z7aiG)5N=T66838Jo;EjrwI$t1+IEy_`${c#v-FUG<2OX&xXp7}{8F<4{s!_PhV>N@9= zcp(!Z6@O2ExbJBVz5Du;scb_00bK0y!xyF+X85k^3>O^Sa)QRz>&DFwl_~wHV(v1b zyx|1wNTAuG{(>&(w&A9$Wz6uhLd_AAEGv(G!H%Ywk#j$u zvuD=NBmL*Mrl7Yxlj?YZ+sHM}8i5tjgou*-f<~KxlJ{&T@3UFW(f0+;X8~VZ+m!zV zulpVcH)8o|RLBJ(_vIyL-XV&Y!mOwpU-p_rPX;UnJ?II(A+nDC`aq`w^R*b_nN8(9 z2$3d>GL48gdNxJJH5@ecxGY87*)uD^k_?&g|MRtOBin4EQ)TcrSU{zO?eo z65IHK`|_DCjm)bh(Io7X^d7$SNU=_&@phB|zwba--AAgC-dSHQ8JHMa z>4Z?Jl=_k>)u~|N8s8CO7yqk@hV2mb#P#bR*mo!!;`htT4@)JB0;=LTwg?Y$-x}h! zGuERz@%rdVw}zI>_&r8C)39NK6FYUATK{Cb*$f-0#P2)owJ#&ZPrlq)uk%a+@^LH; z;xs@hT z+k@niCAn!lbJjXU&$9@zy(X)Z75zp*{p^FohX=X6`=RC$%fr9kuah$?(v0xCtsOU8 zRz7s>+=ElsO+>l0k4`q43~$v@Zv}E{6n++KUsj7zefDX;nrqWFuLg~f`T=jIagXWzav7AU9ZP}nGP8!c z$_)~)$2uvW`{~MO&K&YXhyX1jkEn=_HEin0duR=$s64&mthPw`&_74B%Fp@vH23XO zFC1o!AD{jFsy}9~wm;}*4GCK{$$`vUXY8C-jve^^dF}j~=Q>+j~_O;a5|FIAawzC9-5 zdhLY13vV9v_}MY>h_aSzNAGp^htQeukqVeK@LBAo+HcF{xw|!r1*6=wrw z+aEN!w+~2@y5E3gnT>lY>syV__;h67Zpn>VfJH;(XK7qFa5kkQ2%)o7aZ`r19R(bxVQrTA_->;&1-ua)H*RdqxoM@gM@ zW(wTbG9sMkf~u|QB4$sQmDhPbkRO~CIx`pY(x)@E;P|^TZ#M}QE|NrIOib?c!(35X>*WAxS;d^aw=t8$isqovXz4R~V3L?kO zMRKhhu2HZ}oJ{8O3Zj_xboQU7%)F3NNM{-4S8E(8SPn@l>kcpN?2j`9M4CjpLiWx@ z28lsiX2;QY`ov@69e+@jfk;Y$Qw!u8)66fO4r*0Jb{gr7itDD`jAOm=X(h$d`K&>* zf}-bF4ihEQqlBKzT$u%o8YZfGScA);qjwuV8&q&|Fta_p6D=d?7znG3}m$V_al>cJ!zrN%5W; z1G#9k{;NlCdF*ywwz*cUKEXYBx1>TVrV^*jGvz$;o){ChBCwZeX72H;W8RAQbw;LT zV}zc*;2;^JMoE{vysSHe(^NDN_ac}tFk+NWkd`DmJz%p>RMENK?(;{j`NL zvuO!6!uEbw(=)8E2H8Jq1c%EkMNg0U%9@nW`B zHb0UC{h|t6a|pWof+}sgLED6X5cq%Znq0QYu(s?znqC;D^Y$Cz{Qz~>iw<*LZug^y zT0g1npMiQsJKZnZhrKYLW!IE$N6QdieMT0UAn?&*F(2+ktvBIL^llH|$Xl}Ff@+FE z#w8Oo;XF(osyBt0bg4kgeWn{}1JavWFw1hTdbx9!`wI4%iE+!v?6QEd3`K7590Ibb zWyQ>bp%<0op`rbwB)xhhj0-$hYE4aa>9Wp}T6tH!eSgUOYuJUKw%n(mQl2iloE>uN z6NM%JGY9WxdiF@Fe5*~rpO>C?9KM!cj~I{IT%CdfkCB?GZnV`n`*2}F^>~lBpj08N z4*W0mS)2>pbPJ{)K25~DC2mjcd7(IDon1|>U&+W|&_1-L9afm_f!mW7r4ey<_-2qh zN?S$#uog<%j__RT;mik8S%vD>-m_5`pVoP{B-TA22q04vb*$cl7;4r&XA$cCTF=-V zrSOK@--=I;`4$6pK!+d^i&q9^tf79WAfZ)Bf_KLFTM7nbjRLbQ3krtHyh-mwdfCO! zd(Y7_S6?Bu`azo<$!5Tjx;?^ri z&(6}vJ#G`cSL4~@mgsml#EWO|KKbL*&p(pUlQ+_q7lv*~+z9Y0KG7#*G{R8JF3uJsUGsOyalaW=$aX!*&39LV$@htq^p4^4^=GJend?tRqHo#A6taqBL zPlw&woLNs0E!HgV#jy3x#5;;9Jy5#MlYKfRn@;sjuF%(kI~1HfGufIZ)d#(r)5RRK z+k($Bb>H){*WhEF!YRUhtpl%%OjSq>X1v>jQsk^TKCW3U#^&p0u=UhEayq3_RJOU% zLtnT{=70@n&7mdsC5OR#qR+Ej+FcBT5SU_3(Z2i4E6khS`NyiJ4@C!lT2+p0<)rnR zyUb~c%as^>Nk~CtCm=me?p0q>Pm_Jen&N7)xQBOc;Eax74-3h+FV2c2y!YR5#FJ-P zhM4P_t40?1_UFq_eTpVy`#2nYEbg>8!|nYIlAY1~k4D|kDp>CEbJ`m#d7*)*%KTBM zt2g&0?`%WwFM>q+kBh&as#?@LANf?x?Fh3=;H=Pf9r0}7$_TtZ=pJ60ihC^I`S}Zu zQ$9{|B>&1#-5nF-5S#l_)rj}`(#P~3iinEPXUS!)QR5O0T}S%LY@&!7Tu&8O`P;Pq z>2ajlp2HN_Gd6w9&h^)Hc*J$v$mSyC)4YOEEx0)E{)lQ_Q zoRe{UN!WKJ&$kHK?c(Ykt#_qwLi?pq?SML34(Ot**Q<(=sJVNd(`p%E`@A@I z>G<%czo_)dKTGk{mDq0+q#+)U2 zs8QxL{d)6;sg@H~St(7rZHTJXA7~)+G)WtISQ2xln0QV(j)H8s$%L?(py3E-v4(ua zaS960XH^lqDbn(#R!zL;VDZE0QZ0m47n>H`bNoB5}CgLoptShV8! zvqNl0<$ur{*=c#r-k`K(>iqMxjn{v%R>JMJyd_ksuXeG)7fq_%WUhFczkCl0ZWz{)3)Eg@r!qLrq zwV8@VH{jdjSdUJlr2z$vE)AMw=6i~~jWR6&Uh4^*MBfmLu6@kf`ISS(K{33(jyRjQ z?mlbtX%B<8>BUcSrmNPG{$aGJ-kXEc z%(|gcBRtbzj+6ueBa&YHLX|m9zw?KB7|@|qRG`hSy7o~n;}GeeNv|+wu?zj!JpWGS zuaC3p&)p?^DCt&wJq^nk^UCUhaixg7>ccNEzz={;-#AV58$R9nM(3ByOxvivgIZ^$ z{ko;y+@tynH^)5r-|~x}_N`72R5)Cu{e_x;qnz8&Lhu$Zm?8q@Ln!S-y8UlperLLf zK-gy1iFbTr(WKAsc=+GMWAMn|FD8pe9BESf9|R3l@nMDkqj8D<|BC-Gfb)MyP+oa6 z!+}yo{SZbm0uEn4DI3Sl6e#A1Dlf-F zD3+f^4O(X}w-{5_P&KGsRC?76^(vTjq(%6IZ+<{Nsj9huxz5jz&NGQkE`XkXLjkd` z(dNpS71Aau{7F(`57p-M!6k&N=(y6MT0cfR=$0{fmlvp0^VXml$E40%eL60v`Y4X% zvs<;d1t@YbT8l9?NUBLOYvSBBozKO0ZGNg!hTU(Vgf81gmBb3>2s%v$fLkwu!8$@Y zLNSy_upC!AXkk+BxM5Ghi{S78Lp4)CLCe(ECT?pmIueSzdMM25u5I?Q)m;@zO=}o} zK2#Ra{w4~+;2lr`3oSCm;K6nPYpjgP{U(iBGntnz=RexbqX!sX0S7DxKNgBNoLcGq zq21FZek{_TX~TxwhlcE&v7=WN?~(eu(N>Yy3IlsQ&ro*eoJ>fOG-I&g;XYzMAE7aJumOYzQpF#=96i*Tc&L@L*jGYe~15+Y8j z4?@qkO_^k`!wnYM-#Np#>^ikWE&3gnRPA4NLo<{0m5y^ac^)mHphjbzZ*_irXvqCx zITm`7+`WBJKO+1V`?t3SY2)gf5PGBKAAt=2qfWk(=ZQZqN3 zNfJ5NzeF>nmz<;`iG2f8zqeBRb~pC4%{#jNsJ)Rx;l^c&JbicieCzjYtj{$pndrI? zzaZrQKv50|=lTrrH&<*d5BYr}USSWXDqo-VQhwyTf1Se#GUg{7aRAgWRnKT@#&6|I zs&(Z`^9$?x3zA+CSf74jY}W^E%9dr76}5xqdZ2e_mv-A4gh6ITOd?FGOd15X?0atr zx|%scIP(KVtYn^Zk1S91y^RYVHjI>Xh;)Mzf}}JIC^Ddes3;*VFo3jlgS50Ff~1O~(hSH@ z(u`6ANHcVIcfIHGxvu-W@8|LQw(rODZr?vQm0`_V>pah6KlV6EY@kQX1wN@6sxn%q zAvqz*6j4@pUT_sIaF=HeTM9S)8X_OQh{b% zVC9mN3b8uZH@N;1*bK27{56uS?r+^kJ<(yNtm@%;rfXnM#|p#J6GG4t2L$7N#fmWI z4v=KF2nHX~?*VTqq0SjeehPq?A1PHoHo3M9LDNqqbTn;hwdmXq4^k)$)cBV5Fh~F$ zyxln`p*gGNVCGt(kk60Kcgns@>esq%`bBs1q}Wc5r0i>~My&JQU^t&1;s0e^4^#1j zEAo;8Lv8vTNYQc!EL+mjNM%{9RQ_E;@l-Hhq(t9iBE%3#8LFx0pn*rISI!`o?HxNc zqWxl!06)XXj1(iWWcV8JYR+lvni3fESOwUo^+5w)4Ne52Wq(fBLCxV1N(_brb6X&9 z`nMhFb4~h@V-47N`cA+)-kFKMW}-p&p}S4!Q|;7LEgt2zkQItcQ|#xZ)3XFj0_g^@ z_D%K~d9PGFgXWv@DyTBWU!bx`|3D48>+5*d)1-Uv4GO9@TOc1>4k>+e1fwa!?3VYY z6Byw6EW`iQ)6nC`;x(z3VPJ`?#oQhj`*BL^@+{meQHgTR73^dC&usdcvRVN{xzI`^ zG}}Ynqk|Pl9|>De4}ZFP>-3lP5U|l557oUd{FdUqaVnle)36*_-QON}g*!Tv2EGqC z$*Zs#84yfQ*7gpW*p|#mde+_pX~Ogk5ZQfA6xgIi!TCO^^wnv)Q=!A3a~Abt@{Vj64P$!gkd%thkeh_FM4h8 z5~eZjp(DgrK6Q_1)p_T3i8sPh%M#a_8#4{Qjz+h#nChKA|NP<1JkF0ucIf<&!w~7{ z6d1`_MA!V|Yfd!RhSjI#Y@#*#3(e8D-a&-uoUldYGnKQChWGsTuMVN9`jVY}z`kD~ zXWx1HSkL}ux{_t#>#Zs|{x)Q!yUN3$W$eZG1oJre?~m7?f}r>Q7$i^H8-K8Y?)d*= z%oL@R0R})HhQ`uB-At!UQ>nB{6k2~e{>ly$$h=^_Te8?(Pq zuSs^HbS`*eMoFAe9@?_lEc&?zvfIpT}`d_bTHH=4H#`oe8OU`^=P8^(K^!zqFMgc86)`t;T6gD=A+2 zH=~!bF%`k?!;89;3}#N_h_@{q|a|b@BMO?9( z{FC^&km{+DS5>iOi1nB)c_LV(vpUjM+Og_>WhYU3+P7Hmdz4*-T|#<>0Xk}epWfQ_ z2iEy_2Z#h;_RAs&l42p1Dle`;WccoGc!t(~RPQu$W+{r&cf9{N!a-ogSHSZP!P={G zwO85G#4};nvQFQvj2q~#Jx>0>W*!iL+RQbu6t5}S(LVj0?IBdZDYa%$#rT*paMX4X zQxA-s-gHu{DxM$hcnYrC{iuBCpG7-h6YS0PL)rGK44xN1L*}&n$rOB=*o83ns)LpR zsPj(c*9t!q4wm!ZjO-koRG}Q$(l@K(NurdS2FiLOnYI3#V0>L*mQAr!IE1=$@C~#>FAz^Dv6C6iYH3XI%Dk3QAL9 zI4^s1!ix*>&YI8KAl+j!V*Klw0wp{NqzOyycSAKq2edLPj`;@(&+*we17ONj*g;FNo=^!;Qo_C5afl5`uj; zn&?k`kZG4%V+X>Wuh@IsbYz=&`CRXI2eq(_Ret;yRunQ-v78OzhFW1GBRWQ`WYA-2YCSVv%3mjkNBCo|m>`Ou%r8HS>Docz;eW#qWTXxvOzAq%4Gto2X>_u}7dJ2n z3a7j!F)7J#BTOJ9nkbC9Kvy~KwLK3>{WDK6BK^pWD1s{mF?e@iqBbC~Hp@8}MI^@> ztwtQK4T^-_(Qyhr{79`9t>8M*jwaS(1itM1R5QV#@H)F+Rg9Bkh2G%Mws%E?Hsoq# zLO%*gPDUp-UYmPg_jDzlKNf#@An!iwg(u?u6YBOvPSf(~m)Zj|KUGbA`splUWsVFZ zt7^3Q$uF+$H+e`mVV&lP55G?o+k_`?lGX`^CSHL(VlE-t>Xy&{OiyhoD$hJ;t#d<= z0-z?<5hs(~cxNZp6t9{aZ`=L#wOZQD7;nVin3HXmkJrV0Qt}`y=;ZEKLo59ENyRP8 z-peXDWH0Z9Qt7GODqRwc;PUe@psibc+v6RoG-)8%_xLg`bY5$336TzakiBDTI5PEQ z>#H7Xdvs+ zQM!yU@Emde{uC`$wdQa z*quzvyxuz6$gK%=VsSSXvqb3-LmGEB@Oqe+XFfg*wWeVC(7+aHU3iy@i;Gm2EPvN zX9Kneo;FDJTpNu*Uc9-fyBQ+_Gl^F9{5B&Jh43ViiOjGO8sQ)Y!k5yjdcyTTF3jr< zsLQZ%h|ZqAK$DD8w0S&mxTiDNjVn+6;>pHc@+X72mu;5KbX#i63#$gk+43j()!P~| zy?hkks38wxb#Q`|8u4PI6ONpzmsv5JpF|u;M-6FQ^7jGq(1|ve&!cd#mo$aq!@AXL(nBKwU4N z+^hHMZ((_LnLpPk#u7uG;!2_TN*|snrM1g!y4QMPzUX}L^|KdS7Wg?kTDtkKm~2@d z;j#{B1&Ac*5xU$`9g?_P2Nd5YKK=(c8V$0h2Cp>Ws{&#Z^C)qS zazZyT@|DCTPq+%(^CNNef(ygL^|n#bUyM?jE>G=Fj1rreC$pHGQg+(Kv6AFApOM(U z`J0Zgw)6Uy#^wzSG=VC)^V#@XxbI)j{diu*Wvgw;7t+Mvq5s3H;K3R})@I*sSh(R5 zx${w^oUdC!4^YvmUlf(h7GF+pTWmIWJubFtYD%Mc8*vWVDffkXI+i$G#5b^xLH^>T zrDbwZc@Dz0M~f;wx#wcy-bV3xwbyUVVq}`xBc(1#B!x`-eD!O6p`3V6t=gC~Z`vPg z&q+vq)wH~&VRghx5!ZQGN;6-3$uY*Flr&o8zFy;v{sU>>2Xx<-$kv?&cXM0b-}l7p zXj<{&ej5!H8abYCa4`h+#ey89&d!ue1Om=_cZ_q5DBgStPSRm!Gl2JbTV^euX}9=s z7msR1>i0bhdx(8I@q;^dyMN0*q;=#5{B@+92#)2ES#YySjA!YSc8Z>ec;zWjNvq^; zTAsWvX9}~q6{vUqrYw>*+`T^725r4=%S!+HBCUZmNygALeo~-i8dv3RF=wdVm7A9j zHd}@J>p#kdil)XgZ&oekI#ZFvYcnmwby+rL55G{@9?KK5ssUEg;s!_Sjij9q+)8++ zK^%Rb3yU5Qd77nNmE?HR3@X&Ew}ms*PO@1{x0eJtGN<-K=w2k}h7PF_4aD%KZ;y+ftfI3F2p;(H0~=qKK@dYJgG z_t?_pZ5{2dcG2|&(^$|Ko+=oy4aFMGZJ zt$VcWtvi1U^f#gMf%bACQrw-4<{d9o#Vu;6^)RpL%iwE%Y_p-5%^Ht_sJQ#3w+x7w z50dw|jIo)<>gBVCjyHfD?Fp#pUJdXlR~^sVGruq^B-hr}x2Vh!!?PYAZ7IsV`!?@Y zTaLVw+_$up1wqCyF{Wg5Q=#%}vN6uEWtQpks$^0t>gxn_VS@B~KtDZ{5j(Q~0Ap5& z4cPiZzPnktllD#T0&Z|kgepzAs=kP z{@e}V=sbBi4~8)XUJb364nFH?$4zZEwS&4O!Q7y`w#<{Ix16(p%R!Y~VtALZr7gOR?-!bc ze{ip%CL^3uX=#4xX(aw(QQXE;H;s91iBnc}3EX`=TV5N)PihiF-I#D;a$&kNb%vQQ3nI zdg_NJPMOr<=V7&o_fsRiS{So+U+a!x-Y;+K5HW)#A^YoR32LR+H0?5jTl4ZFBY$!B z-lJd?yCik?q?qX`_hs95iMMmN%3aVL;XmkG4CMYQSH2kpF!pd|O`4lmvwzvcec;)u zM2ViCZ@#Cx{u;jn&6?9wO@`e~Y9BYelSk0@zDr?ilas)esz0ldkXgwoKlyq#oCAL$ z>(_n3iZ1Gu#`y1T44=Mlq!Da%eAO@BWP32vBpJb7@E`~-nRC&dhq;L}N8H{<3Arm^ zZFxGZB}y&3vMg zNs6Qu0`Cb)KQFUSOJH+aOIYDXOzJXUtJ9T}b@3-IB)PAcb<$C^qIYP`Qr-lo9O!;b zlSm>~r&pD4_#ky~wMJ6oMix82Dwqg}A4D3-^ZiRyKOV znWdOm;ROxU%fGiZeLu9kd=f!8^X;4WP_SME8Pzs_zofzDKvfRkH2of_^^6Qt9q&&* z;psca)g>m%Co(#dMfO*&;_#+(R+mPv7TN2cC8YG{wV ze7zU<$jG(<21{f7?u=R#PfFQIF3puTcWu7vk3^KFwEN4~|7i743N9&KtH@4dZXBo< z#l|b^7!64uh5A&zLkPHfd~j)PkdI2Dy=x~FvSceg-gCS1?$8DSVa%^YH1kg}rPRZ= z$6u?ii(`gw|BX-DDg)hQ49+wk56xOSRcX!0Tsm%J;*x3H?awp_Mec5IF>qwDGx$A; zx=cAcnhxHNA8GGUfC)E7N(e6F(lbz!oJjHj~X)#@q#IpdziuM14RvL>@bEba!yOt){sxEZmpnBX(U0EDU9zL5Yn!IKd^uF#HwM1$Yq}Y|G#@24tQr>Y z5;c|b;uUy*%&Y13JX^is!-~%}BEu=yBxZ(N?qQvNR=f#3kDnrUA(Z0U-i*Q}MY}TV z#mG4LUR!I}#l||fdzOwbpVfIcJ8az*dDTaj*gs7yzAjIR>>CDWjclW-AK)&2`LCf}X6E{!nCZ`2 z;wM4wuZyjG101*dwTE0YQ+1gh2wAPEksd`m7Jj<_`#|pfeIUPd*Aodh-630(@Kic@ z*YVCT+rUZaxJBu!JX+*~-JSRQxlEpRPP6X1V=QLAc#F)3e9KEW+Ta4;@i@&nA&1{w4V$!-CO6%mi`OOQ3-DzkKxY6^*=zH#NMtY#ZS z_7zRZ&HB6)!q+V?TT%x#;Y3 zF|i_wZSloz+8?VkoM+Ny5*YqW9vFYQ?E!{H`EomNgcZZQIhXl7OWbHUO0Y~vA0F`W zyRn@}q*69RkxGyTI_a)p%7!^{>q8@E6j`x$VrVJ_?p{_^=XjyE(DA5;wz8f139Qqz zzBF;O(IHOq+NT6ndH9ngnd?cKAcE28;e%!dswdTm#a9}7amJ1OS#8eOo_Elu$=;N4 zLWtnTJJk`;_k`SO`uW34v3N8R?s>;&9^1WP>6U>KIZEm+dg@X@ML03PJ>0u(ixv^Zf%h;&55H1pop)ukh(GE)_u-eyTzZE|ACpE4N1EIB zl3KYA2{PNFFO~vv6#rFSXnUSRbgVx%rHhk(kWGUY?C%0E+!gV*hoVV89R|h`9g%TFsHcP(X#n0sW6c`etM$IEgM7@52v)7*LfNZ+R_%`kRLHZlGhT-=Km%1m( zV;v2P4OdeRvf?2#@&0p`ai34u9` z`FBt!MWWAOHqO`b(a*Oft%1f*Y0W|3l?+Xj>bq>=>j_G8&h$Q4l>QcDFc>m^#65w?v8gEW z7-mUZ-H{EDfYzJ`5=mXr56p?T!Ih%{S8jAFSL{RjRzeck7mZld|Ni;Uf*&4c)__K> zAL{||6+U$LsSP;ihfs(W4D5L9wj6**;RyUgS#rRUcp|$EQEU{86I%4Z?ci_IoGoJH zyYpxda6Ub(Z~k_A0+mVb=Xd;|J!iMZKT1+V90(irm^#qZ3tk4UDEluT6TiwK$XKL1 z(aL}8WPq-v*o~R1nil>=iCs@<6}X4wUW zTM90S9@Qv@`*Qtd4#s7mqt|!pce2x8xxZx=Oj^G1DFq9N@3p2gKue7D2(A9-=g4t& z=D-JUUi|wTv^)ipF&!B7zpTH-Ll1CAUTfa`{r25g0PZy2J^!;ke<1nM9`ZZhP~8L9 z*VwC0{~tej(>0Uk1V{=F$RmJ|Dc5ip7(2=VCtmgLo^a09%bkV?fBnkdy2b;*>Q6!g zjfBKa!Kd~`-H-JF4Wcgl&-$OuKHEG1&*j2=z7H1(^gY6#n&2wrYzYQaS^UT` z`_BuP_^~8U%6XGAez>flOgjmzmJzV#^pB1}hMp6!k-9@;qYDCM)s0xSwDoUi zR&GY{{a)c;uNwg(3LyiGn^+Zk!;9>zC?(ZObwkUM-0m29k}X z7}uA7x}vQ%{}WZTMwC&T)R@n$x}UicGr3yG{_NCeFF*>1Dnf7V;tJh7i1>hnAX{Uc z1-PEB>UwtkfvYXN?|<(zp9wwF=5z(!>zglrKRsO9@3gv=sI+#CR0x$h{4^(TvVk>w z1os4VFkGMwqH?{SbScLD#hC5c`J0A*? z%4mT6Qv2t`JdTl9za>E?zMz~`_j6_5tH6T?vj_e|y_I9Yz%GNEE~7{z3yi6iV9Oc? ziUj96){0HwS*(PdgK2I<)}?0b{>MekKwVO0vnO10{6OwIkQP*e<@;@S4~)SE;VkAf zQoq#24@%ww|Hla6p${7(!bzwjVvw%HZDp&)eC0GCSlG*Yb;v31p z+s*PEybc-eU~Yp}?qdUo4=P$5q&I*FcY~Afy~b{`n+93YavP?pveeZq z&%JknCw{p>RLykUFrZLHey!&0bQRd1U4iT<%h-W+Oq{^;E(%N=`?QK8-UjyCfw?Bg zW0DblZ2a`gM{MAEw)u<$pb>Hhvam4B8?g1}ud;y*kL^8^^|0f`v6>o9IsAPv$Ne6u zsuy*~DjEmRv&A_CH|;V`PQmvI_HYiegE|E?tGhv29U*g1{q;npG1D+s>_aULTJ}|< ze_WA|2{_A#?JJwYY((T_K@Q^K;FhBsetU|YK!AUQy|gbTu(Rl-FZ!K2TAZ&7<|_2&YyZtPKnApNQ-xj&-0$vv8j7|B2=~v%1y?QN&4D`yf}AVXMU_LzHu`J! zCnHZC5Kh$D;fC@gIPTu{>&N^_d9!;-w7jViPj2!*ae)LY5Yyt)TL82N8+VD$tKsa~ zVoS&g?>LIbHY7U&aPxT*Mi(0R(@&XTCG9bq;G92K|(Rk>>S; zjBH->oa_|wtj`@S$1kf3r>9+u+B%zgW4ya34VIjZDd4?>M1w6Bl(K*R>10DcDW~bX z0zSFac&XL)(hXW2a~f^8beJ8tIOhxLXv@On69l}c_A=}{Op>OFr&BM8<++@f@^O7{Qa~;0SS(A7;hRf?AzuV zu>1DwCJizRq8+>IB^rr1`*tQb+tj6zGep;>KybzGo-z)4PZX(XoZJc4G5TqL5HSp! zI%QKN&q;!sbEw|wgUQ>xJJ8soGx<;oWh?Bg5DM)QnWU4yYgrcUFMh|=Pt_l%W8~SC z280BD+9`~#2Ad6o`v?LrROlE`_GiHL0_}xXH?q;{nP~ADIvq(OvWP7^bE0jK)pTTW z!D%!l*&QEL)E{DGTh7>o_S1L@V)*~FqTwjmVu_r&t6OQJAY|X&DpZ+!b_52J?)W~I zoVbEppT54#(xEPPX6f!2bmSbh)9TrH0|VtwA3Gtc^(|8DzHJ~e%eWmBo3*wwY&a-g z@uPMoizy)0+pJ-%97dKiqs;=@o)1glu|uA&l>tyPj=2RI^)-!1MtFncWhv$j?R>NW z_SPDg&?=c@@In*9_lu@l%%5e1h7m<1qXLg!VVLC6u6B{gs+IC{Oni|bdu)2axN!E2cCk5#u z6=~Yb9r486B9WOk3tJP?7 zR@o9aEVgLySO{yuw(&!WKs+A>M;@@^k?#_V)6BP(i0{`*^&F@(a3v($)f>2vxRxFj zO}w>B46`XKcYOo;#+l=^CK-BW8VY!qvWWN8eLuiLx6SEy{a9tDvztr2Qj~e|#AQMDEC# z)Zz$>@g|#J5birrd@n{gQQie-_PihMp|Z^}tF;uOho`Q{u(1uopV8S0ZGDr7j_i6z zUbG=&5&MgQgig}y9GeGH*epgRC8a$O&h|}4kIkn$@+d50&}%&K{IRH{d*nN^byf#L zcB)0&&@ed#t z_rrPa9m62{UdWb&@Ttf5^;geUsOAGicnyCz$de2t#9V*R(8BJGf3IVG+T@i|H^;^K zfI>?=Sa)b4*{gLP>Z=Qq5L?#An&{~M5q>-VI4-!fo?vwKhhFPsi! zod4P;7%RAbh3Ji>%O8&>B-JC%)C0m6L1f=D=e>(=Uo7qX_9M#2E&$nEO$Xg?I3V%)j4HV7LW}J_T6&L75f{*!lB85ZNl2 zUlXJ08ui`x$jc@KNVo>=Dp$UNu-@_+x_+?2_rP{~!u0vvpQY622je%s;Q>ot3dm3^pdkj|L+H66 z$vpPjFZC&&BokcWTA}azlhR2?;2fzApOAvWvC04tL1m|VUE%LE2B^IZfVE0cPGiTM zfo$9vL{ym>GUQJTfqU1#0??a1n6>gdgh_F)nb~3A3{v5y0Ju|qX9q~SAI!Db_oL}v z?0{l)5M1XoKOPq-wF#)}zJcKXxu!|=!d;<&S*Hbj?bl*&>PuJ|gBQC$WLvC&P zS1)Sq`;m{l<=@^9M$6PLsGGG4`a^jkfsi^MgxO)*MHtDeD*%-$Y;% zBIV|&wo%6gAl}ISeFV=lP-#~i3$Q5<cib!RxnEQw|E4 zLvNZldWhsEO5Eu@y}5D*6A=*XIGgbs3BG5zZV&bT{HVr3*xD}FGoY#7Ll&Ac=pvFW ze3(Szo`Gil{<=V3$%Cs7zz_)`K|}9+@PtP)fcA&z86hDM>uP3meZ|n!*)9E zlme|e`4wL=1*a!RM(s+7JY38<3M8tJW5+r}ojzvU z!s}OAK1)1ovuk>h2Cv^*z>0yGIP1C;(;Ax zQhOv3mZ=j^6+A&b3QvqY0?=SaWjID|Ro9(mBSs`97QGBf1jVO-j60UyytZ}xFG$D} z-H^Qduqsw&mVtd0)MDHIuP7Un2WR2t#VKh$-rn1bS{ z6k}}Mi0TRN+i`?bIcgmN@!ZmTPx!OpTOv@xFi4>)lIL}=Bs zH&|qdKnYqN*5rts0|i7AvE_S)`!5)peocTDS7iR-YXpHT-j#Pp3ghX~Dc=HHW$b62 zq-j>2WShsMugips2FAFngp)5f22o3j1k>Xic+R{&U32`#PBkI;rSN(vh%oyRrfeQ| z56<90{43Iumwf8j9~>el3ea4I#{=L}O~_33WIMxuR|U)AN|r9c!KTq9_H>Xhj3tZE z{xY*&NjxPcsQ8r$H$y2G%PN}+f6Cu&*uTyl-N+;*sWN-KqPjyY1AZIW?~RX`>G$sy zGJ^?RHOIaS9~z*}-bl7ty5FHSxSO)R9;f!^JXRW+NI&V&v6HNtbz7oY1lU;w<4xH6oR* z-MHNu`^7>ESwL$i=t1UGmp5jjp_q;%Dmg%vZKj^CM5!QIJJ}MT8a{IZbo#4jlGTXk z3c=SuLbj5#F~S(&2FvH`IqQoITWIQzmi~9FxueSc`>=eLKfpkOJUM@Gz>k@TUFsk3>8S$a6x72NosIAJ{A=0bDx~wP+PZ-F;Z+6>6DmJ=B|$~` zyI(prAkg9^!hVaV8*&wn$D9R~4io7bv{Fyx*31q88(r~TH49=F8XuGlx+b=1LaVTA z5Gc-98jy5vJ;YJ9zJpeIAj#Lyw=ysVhMOeOO7sX3Tb@YXTYpW=$a99a#+n^DWW~9y zDa|~Vt3p9Gsf*cO$xPcF|obhWd!0yWIzMAjCZ@DErN{X=6?&Bf@N+ZD2j5WeD% zzTANw3bxTNAS#cDvoYzG(Oh|??rLzU8bF3Nfz)b*DV{}B-Z?3a8_B{j)m^|?^u{nw zsGAFR-$12f;zHJkgDFFLARAU})8pqb`PDgj2NWJEUW%IpRp#t~c+%jyW|LQ%m=Q5+ zfI7!0m*OmVjL$gP>DF6z?Fs!MN|5V#FhK~rlE&yIsT0Z1-I-i8H>3@aXlRP#Mp<1e ziOcXMirCd0K@KmOLl6Kcw1s# zSPwHrSU0N6;ZgZ0r(uFQZzK=$kg=U3T(D(c-7uK#GlXYOoeR_n@I^#R>{tnP2YYX7 z9LlR{x|ve)3v|}Ch#9da2*dQ=faHP$HR%@a1@zoGBn$~p<|daKwiVA{Pq6Mz+otrF zyWGjIdJM~OZRIYAVVoj31j$=7Wn+|v!khRNwBZAfHU1*AAV%l!ch*HIeEe=q;myxT zd#Q_9Lb(zoPfD^iHs+wF+!Z~MY^`EG1&bAs&Tj_IZu>MGjfiVOn(=z6Nk1*g<)6!3 z&PrN1jzIz^hseYfvL z{{oU*0S~|J@hjEF=)q^$P33|8*ulM9Jjsp54wJ|zr7);^9HWo#u)T&SPNw9D0k*%M z5RE#i4$pr>vV7tm7Yq4WEjUB3lY_2QT=33A zzHOcf-}swbggQfljY&79x5%sL+a4p!-R=*3OfNmyn0;PDJ1~s17Mfe|qUkrhnE?#- z@`Z@jb4zd!5w{3))<9nj^&VrN8be#f)ZL(+<-uS6&4Fjoz^X4H5kH-sV*le*3Sj`p zmE<;^{iJ&MJ+jGoU+AGM1wwT(cU&xZ`+&Hz{jCV`9VdB(k3+_^&AA zsAO=mfzPNtVz}QyCc3l<4CeP0O|LxW{SA`;gE0O5rT!OL#Q*y+`5(dl%}NyTvQ>qS zkKJ_wm1#L>dQ}1ksSNB9da0mhb;_$tg}x~pP7LPMI^hwLg;T~R{t=6YSS3Q(nBP|J zYG;=a@!l&ubFBOGvD*K?$^=ptuB+82V!= z4fEOOWi1m8DX2M>gofC0Ra!IbyUoxv->Pxx^dv>B>@ zFoLwe5hyTM8~9T98fi3pLYPIL1nYx@$>Zh4n=~5JkVkkAIDC6Lj6v4v_cefW_Xu@P zVxa;y!+Uqo(gqDt+5ZB?8X|T0_J8AI$Jbl+nALL7_1#B-xt->vTY%I>f=2C3Rmv9l zZOgzTYzIX<6S&Wl2=)F?*z4K9dT)LOAWQop>+HM}UjQJ>!3Q&v%fMb! z4kaSc5jvKGgwPBqo7hJh;R%J>zGVP;wE3Otx!DF-nXpVS7;Z00ysDqcF;{o+g@Q*etvUo)y5LX#qMt$-vWUmSF&qUC@Aqb9{`6knLA(!4xNEh z^$R7Gns+#bwFK1T1}@A&I}s%=Z9)bN{E=>c0vGoi8UG!ix`73jKMdGPs1Kt>|4)47 z33!ly3q$oaSr^8YtHxcdZza zrvv3E#nsxRa3|9_>N@ch5ZmmDZ%ruS1@Q(~g4xqg(R@fU{Kh@?x&Yh>wK1wy^aj8K z-`%2)mBK-O*K0V00x84JKkxd{q~J=~!X8A)&%jsT@WkbxIhmYs`)Yt>D*v=27{HY8TTj5;R}uC^z5C$X zJA{d}c5Fb@cB?{?T^cakEY_pR7{wZm&%i1I->yg{mCJ2|FF?NE8sYsHWK6n#9)Ai< zx0`|igg*b(7;tSH;`<;F$90Mrrc1+?FoC1nOsnJBG$Rek63lJkd$0-vWxcP%wb0F$%)>QtkQy(S1<-Nq-qL%7r_?Q?jp4+^nP2_H(nuhTtYhHJR);6VGXnk`+3bu=N49 zF@pw&xIPah20)&cqx27%+lgF)C2Tq<6}IoKEz}Nq4QIvFu>)N2%HG4G&_2DL0J0As zx_~cI{c0j`TVusnMD~vdV@wn1{2KaztzlHd3#7H|_$vZ&#dpotPgW{Q12k;+oBzcw zLfSo|{M)ZCceaeBuD2RH)nsxH4#vJL#G-LWs_-T;xH0zse0&kOv4CztCA}9A#uc9l(%E<} zG>9!d1S4v#=xgZ8O`9hZ2G6IzlHbGc+z|1yzojLa?riVU%$2 zXi+Gr1>o157)W>&oE-5GpErooN13(gCvR8MAWs{Z_@GnC{=QeT)r|36MsbiBZrZtv zRk(m(%>7~+5PWSS{fk2nIxc;=nY|tdkBt_9Pndfmz?m)hqqx%qnD1a8?(62eI6s?w zJsl~hU|s8nGfgVAw7iK~D@+Y=Df4c`tp=LQ?*`3AcpsSmdFu((bR`G+rN|5jGex?d z#umP~?qLsRCm22CHlhv<_oPYW%w_z<9);rzwv?$~YzP}C@i{G1)T^nt(F2q!w%maf z;ktdQQ;8ioxHn?fEERza!Kw4ow|GYTJwoOLr>MaRhL&0|banCkZ~BqGpy3n*Ssmk? zL-u9yI+=ZAabKr`5u=yo7CLrjSB>DAc&)@JVJ=^Yy8znP0``FMbdc5ZnKb2jAXB>V zX%AycO%Z|}Ly#VEmNM+m*Xbk!DPGt5u{1Fwy&DPP1hOL1*S`--&1?8T|FAciA#YI| zsIf~($%a+Q6nCs`leL*sb^mjz{E!jM*2*Zb!C#&BzyUKJ2sXa7h}sT_C{o2gz9L%j z$AwS#{z{|xSb`p6Yfw3p5A_-;sd(IIKx-O{C$Hp3`p1_v{@I*HsD{qyDjqqy?_M_BZ~2k!nq5|q7N z3!7cpn(R_0wE_E%!+%uqMD{I|;CMq-cx@n_ue_g4Dxh+Hx~!Basj_SQOD8Inz|Rh} zQkj@xKwQeh9wh-BHwsaS)n}(i8(+TtkvaB5=@i5a&);S|*GG{LMv=t4=#BsR9{_CT z-vQXh*+3CDgg@hbNsqzONW@$qfk zAmX}ykva(P3C#T7R4~a?B7EW?>NpNF4yv0@{8xgePdtnqT)(<4rfSVC=ffO6p4OD^ zzSneh%^vKPke6`H*aCqoM@|64H1&JAegCWq+W4l@V9l;*8A^1DHK$x9p069b3FaZN!=_`;y@iV=cF0jsyiXXedFjX(mjnG`7--=N z5xxWqU6{qO_M9mYdJ#j6PLilusBdJU?O^dbH0(TzRZcRBO+l8ha1d!Z+%@^78Sn_Y z$5K!vyohyomLm{LB@z~b^5<&R%vA?sjAw`Qr1y6)SBCNpsMk$ds^JCIKo3=a1oY(V zKq#&l#VF1La|gLvji!)X2aJ%BnB?z;X4R9LUiGfd^U*!qi1lYNI$6{~|4IeWZlw^^ z&B4&j;k3Ed`LiuOjF+}F2-%ZsI0c^<2IV;U#rSl3j~$KDAH6+jckrW8oC7rL1!xMN z(fV`xU`kL4P8gpZ>R7UL@%OKJV!Z27PE(T}vMo6a2`6X#_lC|21ase{P3F&CoOf+G zv#(sCOFvn*3m$-b~6LbbgSknf03V_3viGfH-^jhd4 z1W&?L**vqv@9tKAd%dHY-4F388(TU4!oCZ48s5|#&vYzpZCC%Y0jXt#M-ThSN}@Ip zcW}MdrKrK9w`Q=K8VsG8`24Qrc^g2T^b|7FaSRW3!Q2>W+u63{4Y(0W1=FeG*_NWy zJ~UvyV~Li9)?OP(A=l$$eJ=Tc=fCaO5E!VA4FNwRQl_eurgqPl4xZCp{5N zQxD?Hm|;6#G@A+w#t%V2o_LHiphH7JozL?^toeQ0BhC_;00*MV-wukFJOA zj~)sFz^sQQ7U{gNcj9k-UU?R9qtRz;hh>}RjNj=7%5T+C`iZRKL+PdUIyHyAj*Zl+ z!Jt)mu{mC+dht<_>QMYMXvqBrtu)g5gTLm)>1AQhTXSbipnvA+lV1>!uawV<$9~uu zHo4um-Q_WKE53`7MA&D7)GQ!F((Z9;GvLs*mP>sxVo(^|lm|4Dg0$iM)=B4GE?@Lr zfa#^}c06}Hw`Gdc*hw}HVN0d5A7M+^-9o{%?u{3yAZ5(L7*KLoPofU<^`H{V=k8Rm zMW#iRl>UXzpqdEq)YKZ3m@$%ql&a*9=sI~d)3J=ZVE8(3s9eY|!Sxq0j#r2l<}Kjo zGzxUqTOcK;DVTE-p_&Q}j6y?y)?- zZ(F2dsY}=C8mzze+A>zU708Tf&^qfK+paH;6i+u|85#la^`qV~#GSxQ4l4^vNmA8j z#lx=HW}L4`GQgRpN-sm%WXn#cYTko$U^bu^sMEaHqWx`T=f#&UuAYKV@-{v4Q*DAw#Z2@6FzfB|4C8$13WcyMY=_DPQ8*TSO?_wV8q z%=10gtSh}W*&imEgh`u*oZi)b7H2&L%->s`JduHbeAX+wvNmawfVUfVKOF_lvMK8w zw< zl|AwV75fot_fag3f62Zgq){p!P^Ch_7QMy`5M*S8JN)hFF#4IG~ zNriK*Beo;cdRRxTHENh3p1b5(Gu$KydEE}?g@UzMB_5)+PPX}ydmww^Bg^ZK047y3 z>cE~WneBL#Nf}DW5t_!ALD|=>{Z5HH$_j zrLP;4?V@GHQwTy)x?BQ=`D-M^K1hW5gv7NoT}o+)-hnOjs0t;YJEZkmo<9B7`#QU!l`IITVEbYx7wr5l!lPWq#U<%-kuBT*{1 z1PSCiR@76K9r%d@H7uv}b?JAuCg>B4c6g|IV&Ap=WG48OvEt`MKfqdCQ!qJZb2^@$ zW6vUvJW_`XN+Q3f$d;WYD4#mXiHGP&XYI8R_oM6+9Newm+OiSb_dBq-T#6WPV&3d9 zu0^{+pozVFh-;1xE&N*ZAq$_s>>Y-S$|ay*zzS>fIf*^vCfH9fL`;8Ugk!E^|6p7Hb@8XYz35O*sFpTH#*d-fgei_A5D65pRLT zK%_5@_mE0^G!atm79$W&B4r^Pwk*NuH;+ES=s%Zi-xhh( z(--HNP&r^y5KSKbyLsD9BkrNpT1AG9mxa*n&|{U#1tV?Klmo|pa|%Wc_QK>+$;s4P z&o6b6Bq$<-m%XkSS9_e3#}rIW2xyA#QzKp@+uJWZ5B89g7x5$PO5804C!@aO;yJvs zb$?$ObAy8fR^o#W(ZVcWy_ zv~!W=1`{(^z(Si6D^4f$IfObaDor$R`5MWBI~?A*2yqz6$;)CqX%YP8F0bFlvi~{D z;NY#eus_t_+>8yi#@Ahv zn%HLSd}qdk#O#XVMVq`@a%#o%lP^i4$q6P5gsF2*7T|=n>82JOd`Ca*mp@8z5oyCP=PK%NqmhCQp+)2K-Z5|4|c3DroG!n0po-Bk=9Mb z`dg}Atkb9;@l`r0MMB@{JW#n?*-4$)v|~3PC;qJ1q4CyF9(N?^+oh)8F^9ydBQ28QB-h1dKXpJWr)jt8Hkc3o*ypxz`0cFnByyF< z+GHtFl(rGgOK2{cjO`{Ju^75{IPY_07C95gVd`Zk8u>#!arr$jXHe(d8? zF?^4bF5n$lBFQZF+wMH_$C6z(1}1Ugm6Q5YE!PJ-1GF_~vI*Xg(VlWIVUQ!L;MR}t zV6^0ZPM&qrDaOJ4v-jdYuUL(DbyWsQFp(nj*an7Ou*bap-}G5sM2B&7TWx$rzciHD z88=w+$MuNvvbML8d~FBU!Z>pVWba<3(&am?ve<&W!gpJJJI^(54SqEfX}%o$**MzM zax2M&Z!gWx&AeKhNJ5lli7*W&_BN4lPUr3|bIde33&4Sl*{zOR+6~Wta2NWoV(m>1 zy(Sw6``ce)KFg4q!8QYa7RPYm(qfKz&G8t%HuDS8OpDZ&vX=+*joh_=5c$Tk9%?N( zIG~s;=TZN|AMDrwrBj)*MTZ|m`dmhmT!rt%;Xu}pf3ZRsiH7F;!)R!}{NF$PA9*Av zkF0TTNYK!qpB~j8C)MafStcD!+D?hG2mji0la&W0tZRCfQv%9k2M^a=Ya=YHC>k28 ztU+h#LQ>?zqBobKil7~o6H>TA))1BTIc89D*RVXO=~5IFm>hKjLz@Y44~l(QEwApz z)6RtlW#6aqdZz`%dNs$o11+Bn^X1P!5z(3yN0UjDP`lnbgJjqkS*`MIUVv+2nP4k= zT6YIt0(#|vb~lbdp7>FD+q)oLT98$HVJRlko=`De1iiOK(7dU+QxXY9KyMziPaqdP zscniGVZ%G>j_cjq@|{tCC6!J(`@^_*ujkI`hRW+^*D;CzDK$7hL!mFmD4})-{LS?G z2%4!!0-9(?8^0+Jv=~y|rX)=?fN09WJ!qy5i8;|k+c#jO+S9IKr=bzlh+2!CvL8?L zl6*eZy-Aej^?hUzcxb|PRNvV>1WQXu_O{BGV0yD zLnfi4KYjCZR?a76Rk(cL@=B}&&yI{}$KUuSQ@$@_IS%&!@gjI=$6?^TZ?eZkd{S9t zvz0FV@;80a`}^C9Ni|Uh7SMy(5!OB*!=CsA+&izVv^9-dt9P%#g+^uu>jReXW{7&2 z=gg0l8z`bgg&4z5+QqQrY<~9*@=a^ezbz}nCB!6&$c0F2HPH<6u2LwRvV+_lFo-^_ zFWex&qgDY)8}qPw;m)oSEgT?B-rg<=3C5Op$o2XYqeXsuHVC!{a=n8vOtk|rbst2R z?vwT39IS17|6i=G9Oe~pwoN2Cc|%$Jo*<5PC}?-gIERSQ=CX~~thTJMmSK-q0XL%U zfBtR68i^$zm(O~?xvII%q-vLj^rAGw^3EbYpa!`k-i2@DFL^>*x5yRnA08(lFK#XRO8|gX?jl$;(XHH$o zc=0oR=nz9;s6?@&HBy9C1bKNAS`q(W2yKpm#5wa(_Im%}nM<3V5ld|(@?9jaH(QG^GIL3Pz%OS8%n5z@M-xDZANvb>y@K>1706e2 zO&cOw`gLzEbwI^B6Z8+sBmL9G5V@E0G}1{bm>szFU;&wAVF|ov4Fz%DP}hL7F2l8T zo#k`6lrvVwQw$Mh_JY~^;La+W7tyXo&LdCt&(YG&>*!#0Y5xEBzN9ZHiKJ zK~2yvR0K6k&sq1~MR>vunyrp*CO`c4LjS8ytx7vN75W_}adA5!LWat3O1msQ5(EGn zdpVj409b*(_>f{KGvkRbUPUPtNNgYGsyr%6fzpjVFy%oQ)a-h9z#`a;1ZW`{;yhiS z?6Eyy8Y$zi!o^vw+_Lx!Zn3|0qfh(|O8Rn7WzZcu5|oI!PgA4UV6CJmGm#)Pd5_a^ zael_TLj|McC)-d?vY$jobMOyB_XwjwssGSCGIgc&aq<+$N!uIZ-iy$z_7N9(zAIi| zgI6Q%ef_eyQQ-rtL3Cn2nmqdzPFn(jzvwtw?W}Y}!lRX}%fjI?tuN*hF#y6E<*1o2 zyhtlGeJTeM3B{lXwg;e*8TGm9iPm7}B-xj}#w<&2j4mhvhk*;yM29b;-r6E2<)n>P zyC?mf^7o0{TpBp>VFAf=Y#v2ozjR$}00*EC)p|!ams_uAr@Szvw!Ae=Zb)gQlAwBdZYpx+7&yY^|i1lMaQuz8e%#LYmiVgeV0PG z_{l*?2zcweBVim6U@K2;GY5fAwjTvMu7=T{_$nF7;~cFE#|6x0bF(0SRJw1Bu68yg z6WTitOL{^a&c}oh<4{7ZPUy#u?Gm_o7fB<9hg*8yw17CVpOY>8r4=&v9jxus=jJ8G zA%b0wvYA~~Qn4)GXoc9{m+U@d)+N-vtM!=9yJ-l3R`_Z7C2eUR4`DdaTA?Ugw`>Zz zRD-u?{^4Ww3jrgg{1WXho_p0OvFxw&P~W)|WXII|2s0J_2!8$3ClQL&@Jm*(AN`B9@ZcE^w$MbqiZph4D+5Z@gk(Q$vDmKwk%N`sIXz;m2)fR;cm& zhiJ!DLsqz9`F_W4mY1zrU@4qF+X$}`!{m@h<7}B*S0vstWq~Cd?d1XGBc)=oWRYqF zH~y+Go9+30M#R8(954CZ-8hvw^f}0PXgeuciLS_7CERzjLeng9JCs>5ikn}6cF zdi}oC4fd!i52z4me%Arxqv)-mY-H%m?_LGfke~EH{!j&_TSBd3XUU^o+c=Gg(ea@l zf89s{bP1})A@fEGGPbN}{Sy=5VZV7sHE800S?(Q15_q%$ncTnZ^CVgi>Id{Y-`_`E zoYX8R?)(aIXM%sj`CpEH1C((}NhCnGUPq%r00WYRb@nd(_`PRMQ)9b zh!C3 zxDlJ3$F84g1Vvp8(vw*}K-Qma*U{YWtt*x#s5a|?4Ky?t4_Re_)nnLEG%V$wu8i;O+c>NzwN|tE+qda z%kujc+3?k3Bl#&{`FLN7I`^Tr3*q?hrqz#kfcSCxkTswq#3<4ucX~tu^2nK8cE4K> z6bVlh14525ZK-}W*bjrhrRQX*5!N5=`~YSSlf0UKHPU{=sK4{PZNmnoS z&%f@Gb{vG7NZZcgd;9$F3E6bMKXHV9L__GwKV<;e-VpSOzk-xix|{4^&j&?y8trDG2zHT$bH9bfP)UH|}2!^B}hW>QyZ#tPq3!8zU}fJP{9Km7G`H zxgT}Fa>NO-%D;(?|J_9uZ^au`hHftj;N(0Pz`+hcSD2J*@79XRy?c4muITO`+d8MW z9a7qC*H@Jpbr&iUga#q0 zIw;}v$mt2vDtaQzu?rDWLA+WwW&IF4ivRlid)6TBO8)d%F{31oXlA?-s6t}rUqAOr ziYS1yg3K@)9YLV(s;4sk$r(tDH~K8Am!~HZ=(DM<`*Wj3nlU) zqgCa1>=(j;xOW7=wA>P$hcr6x<_JNP%U}_$qboihW}bEdEFuBAVkJn|r+`cMzLahn z3}(j@FsQHyh<|%H2%J(B&15@i)zDnM!}9Qr;{aLqmq+6arH{pjTxah+a9k9%0M&s< zHj9CwTilpx(A5RtRQv^)B(aE-b~kgt-s`HN&d|~ZU&EVd$njI?*W;t{@N7lj-pe+x*}Ir3Cr|~baEH76Rz*$lYPZd zGq1g~4-wDFF7@&7b+%KqDcl2QeO=PgM22q^yL&tStZW%ZA*6Oji}*NzRV1lB>^&%E z4{v?w4wvsZXfxZ=wtpB*1MU7dE>sc5{G9z%gou^yp?l<1_waoX!=Pzhjseex2rY!q z3^t{ARmUiTy|Y-+3`mg75mL~)UYub<5bYvEqUNp}&`Sq289$VD8LUpwvHf(wrV%NX z043^g4Wqw4?3*Zrq_9}mIO49HN7@@2{vf%0wpiULXnKeNUGi!}?34u#tp6LN#{$*o z2t;fRl00$e%r3j$ia(H288%NuaR9ONit{14sp5xFnq^_v`W#)hVz)SZCVzhn>{QU5s6|Vlj zk68_h{U3KWc%ef{E%h#g&&UazNY&z5)vo2=4fmDnB|g7I3!5gH*Wj)q&db)#S*rTJDI!4)l(#P!F!@b6^(|AXcBq^uwRFCG7(!|VWydd2)B0Cng`3_L^h{69|5 zl>?6ynev;~y|ISkNMGRh18mOSPxLEZ9Mf+~GjyyYL9YTM)Z=af7!uPQsKYM?^~Qpf zex(@K>=iT3fthecAc|Op0gYs>=+{Tl^1(jd^el|nana4se!dk*a*1B|7_X6aS_J1E zV}M2qf-DpMp^-+B-r=nJcAr<(zz#&x=rrEurcLG-#M)s;~F+Zbx7o+;et2QU_IZ+(DublfTCXx=vhvuzI`uBraaSkLIl z?X|PeAj82LRR8pVytd-{&~9jH(Av@%?)>Qe4}^|spdE+$Qb{C+JBkxnw_&_MX^!1= z+ii&XA4>XxMui~#Y4ad2Tnk!*I_GXi`-qb@svn%fZI;E?++08YKJYv9V9sr@uX!>C znQQyShKVk0u9m0BeQ>51=!!v32UjU}a=`80lAUtvkFkrGet)Ql6Q-0Ek!L$C_Tu;d z{4B8VA@_oK$x{`8t-|gpY%$jTY1F6z0QFu?&qLYW?ij_ehFyA6>B6?%ANdVR9$7=& z>;r)?2hMhdG$uz2G=So1X=Ux7*bvb?%jtq@^TYj9c!x6!5Mvt>&xX)|&kt^Lqis2F z*EDQe^@W&|Wrs5akH`JI!gGGUBCyp|z%&2N;;B;Pm&06DGJ=1sk+AuVC_!J?M7qzj z%Jrc)`fH>0!Ns|A6vz1X>(><-V!U;&OXn&PdL67uW-%=P`tG?d?X_F0m9RfPKhg9A zc4Id>|!2a#6jy5yppDne)cDRoBFc&X^8WQGLxQ5;h?QuO>^M)Cp02| zj&G<9NMhfiq#J*c!l;)nfSYKPOs*vlx~lSm)t#)$AWQU`)R$mh*|WZMv@4=30G;`0qZPwvVLxU>_-d$FCo`tdkmyiqnc#%T;lZ zKW$xxxPtW?W2?F#o#V`QKJ43uUSqHK-Be$~>|c-3Mr;m?#{=SwXt5Wiw=-5Q;NEbT zv8g-qKt+mL+hE*(`ebOvb*oyVA&~PgZ4nbc^At}XEBfp&PyG3F;xDisV2xMK4GNH` zN0lgS+~c+mW~`lfEWDCes$ordjE%bBZvOr8;x9Ch+r=ytCZ9=8A5qP0Mh8+D@Ovw| zq?=b#O=ql9P7nAWoJhS8kqK%FIf<{=;s!U(M&4l@$T%G^L}5F{dG(hSwq5hCV^&K$y3&L04T$>U3Z}-*=Q3>z)@a`S z;g%FHIj+ZDa5`u7>zcOU7k*jFL9^P^1s5WO4F9qI|NGhHd;B-&kQpy``U!?(u3MC6 zcDe#mYVp{FK*Hxq!O`WcRH0gxi1b7LfORI6WdW1=DKz6TLhf--FLr}j(`l}}jgOj2 znlc0OeVuTlsXtbe*u_nAboJsjo(Xq{0(F!noj|FQAK=P0PgYteZ%cmWv2b49Y}Sgi zpGuZ(rgxB+mB|I6!s8qylGc9dT+XImer=2rc%JeGTs71@8WM46+A?OBy*Z!L#g39{|tNTI0QvzfT(Far$Lc>6-afeWQ3zTJO>) z>ILOq&z6`_5IHe?!Hkd&Odh0_Ww&U}^p*S4^PzT?S9#VR_v$qP>;yet2 z3ThggtpHl3tZx=oW<2x>T!&wcVZ?|Od_&* z2F1G*4pw&6mYMjgQHx2&0WkCMquoN>F9GME1G-lKfM%2%I|XhkT+K2MVHd&zgj+FE zH1p5wAQIL(EV-0jxWJpgIFZZ*{g^HDIesidcU_^W<{i|&d zJ7o#8g{)RHM$S2`@rDDRpv7NfS9pp;8@FT92eeaL!d>D63Hh&+ljKgIgV|3dUuHWs zLX|Abj9{$E6gKIcR|FJnS}T4OxYtx@3@9Cl#1ccls)JSFo&&2%*2=UTo+wAD|;?`sn3G?Q@Av%zu@l_MI5{{bn2+GE9!Q0sv z=YUrzW%+!Z__)9$Dz%Wfzxe1GljIeo+J*V)}Qgv`R}4blobek_|WQ5pOe8q?b~h%h$PdoYOh(`>{eY4=HWEsaR+v z3BA_S=_b@du=M3ZunE>)NMw*7B}ZtmLdqG^Ea!5dFrc%)e=C+pTJu{@s~byzK3g8jVV7koTXv(1-X^BUCqP ze_(|?M0}Fp2pelon*b#~cslb@#UZKGz(M1?aE5}lf4Nb1g$3)+IsC504D=I$sRm*Z zs^AWAQ(Z5)CsbRUh3CQn%2Nn!@x(C~ARFe^R^#XTDaGY9G$()}`__tkD z`Q&jzj1T@6aQW!6aTQhnKYXaRDg`w+{(jHFjX$t&W%!gmoR0PX;-iUMWn$5pCEuE7n~9;>jX@xg1LUc{a>AQ?F09BcmF^MlTzK=wBUlw>bd9qy19kw z+Rtafo>?(JknvMw7sZ#BukixeMwO>n^Manr?}-cvJQ!SkC^xH_S>}&ckL@_|x2_sU znID(B7wyEYaloD3RLDdk2~16%ezUS=GPBDFT?w8@sHXijapjrXpv7i0I06-3ircJ-fanWe418 zJ#wet_jeYEI?gq;W#({?oZ6=`JLF+6S=TK_JS{*7{tj2n$uHH*7XLC~jXh{pV=dMM zC4L1FN66MTJI4>F+=L)d;9gi|y+q}Z+jH9k@i%5p*2y_b=sF5!$|c&$s>shG#L5`+ zqSs4mxqWqclVv=PTL0K3e|I9bI25wM!1KyD)hWSj%B8Zvgr_}y7vnFGM|BYo1$kJE zuC(b-JpS$YLroFB@FRTo*<)4D-hkwqFW&%G#$s|&0hg0*1Rjy{)l}3Bn2JQ~k>}-; zf)i^muQVJivrzr(?XLg*Monv7@>vi|89B9BmdCq)643_}8(VfZL_RH0OCn@#>flM< z<%ZOoaX$w(Zaz_Iv2(Y=&~z?Ok)+XL%tb57xq&KI$O-C36Pu>uG?B;|7jkQHYkuYF zw0Sm!jM^R|9uCkXp^pB%-|uONhxpz5euW625);c}{I!8cJeJv3>i4Ntc1TPu`Xk(H z?8fl}0!F=y$?*iL2KgTySQ!M=7xE?4^Rt18PyQ{LU=AA$T(*Tdb%EmKgb-%cv&WxW zcIf@lOxpk5WvHuv^V(%sZ}?Rml1t)2NEvysDr?{98-)1&{heUd2OYZ_RS2GW*Sj=9 zH@6{@S4Y)A8ZjLa29b#k9x_>`=`DEmD`|2;5i*HbVi(-6`tRw_q+WBjCbPKcli7CD zwhl8#wLysSs#7ZqgIZ5aUZIkcy80HpSm0h(pUZr3Thvt}h6ZxL@paY-r54I6$q-UN zgs&pbt8OKdjPP-7oI__)lqk!xPAt5JKk#y9#0G zbUB7n7l<)U{0sU>)HHN$i+^rZo%jF70-u*#vbo0j>GMJ)0^DvCSUSHs#n>R^Tz}6i zz}5d|SBcnl*deI@IuRgypuGA@xzDRQFruhZUWM;3p_LHHQ^Zc&{=c;@#u&%>&)fAQ1UyyVh(x$MP_5CG$bO58a;6PO08n5c5?)54 zUV7i6UcaN1f4N}M7ouGcT83IwBdM|_3lnbICC-6JLv5j>1Xbb9(Yg>uLiACn%bM7g zcCS>#?BfbBN@bi98!Jg zERF$5@yjdT)lG;E@3d?)ih#lpYW49?M**S7-s7reHg>!6QmRb88YstB1}D%eW(4t`ccJVgF^ z@rSKf<221bCSDWq#|4^7^R;lPM5|?@j{k>e2b%3n`5`ycBUM685a+m9$LhetJ~3MOs$f~F)#JGZFCtNJi^Z) z@+^?hBC^qC9i0x8U{eE`%1yhziyQQZdxN2q+?s0ok10%8J>VRUSVT|^AzEpT*0ke_5`*x zU@tPXI2weCpz*5IlAhnU@G)0}2pm#)!N12}3Tg`ZorXUbQJ_SY3Bp5ejZmY8fZ1;W zIH7=)Tce#tC!hx(A-tYMAKq?q!j&e!16K99z`j&rLR|%-#;A9y9g9eV6{n|pX9LKd z4}yF^XIb}`4+*N=^!`;-0@AQD_@)MW5ZKQ>+POtZVxrC(>dk!+0HOpaveU1LJd3g^ zfWD}^P}RVP)G>8H2L>Z8o3(T!v?UcI;jYhO6O}FRbs?l-C1gRp2C$GEkc5n3)Q*#jRC3)5fo=3Oj15`syM5v+Q9%y#aLiX=S3)l))H@CY#s5)7D$k4 zJ2?4N=bj5skGESgLb7nr;GlnJ4MYhpGhLjyG6cn`J}&QCY~khbUiDT=_2(sLhh@iZ zKT^kukl}A?D{j^0{iYXUbQBi2ixmN8+EL;>WTwaJf3o*QQ3`ZFH_Ah7F!4Fd7>>%D z@m1h3{`=boCod{?3Gs|#6e--9af+0{wX0|KQ_-L@)IoA+@I?`t5X8))6c_^`hG0iY zHgJ7)sfJP%SW8Pw+m3*OVCVVKQiI|&EL1*rx*pL;d(AKYp}D)*4y&o9fXkt@AtI~+ zQ^rGpT*&37%SH}NXL;5k zn6o?eWT3Bl<)7B08zx?nOr({2n4MhLFF;AB-$)dW&5>!7(0JJ-hfqhw`Z7I*k;(0Z zeD@E6R_e!aE$Rvs7q zjjH{n!i1g2x~B!q5G+l%MQ9#nSdJH}G$J+Q>!zVTaEG!o-&}|gt`r6?a(F;%ysrqZ zU-1sqIo93TRq*}6dHlE*Uz0XT1OJFbLo4@C=Zc+yo_ARUn=~Zr}@n<*wb%T z(sh*v1UMBDTPIkKT)igC6)iSG9uAl(^T2TQ=KykCaUOK$QR{XSQcHFt9ReLrg>xwO z#5!mhTS$TawGyJ~EFePrIX?diEkr^dEKtOWI#CrBAZaRlO3?$*9FVb*eC7bum^uY8 z$|ile)N*=g6t;0mhBg8lwuP5H&|m!6)wiG(au*%A5qGObD0%Ok>V?iveJYw3%$=&) z)feD7Z_o%=Q-qY)j>$;b&GajKiY~UiDFuk|t&UJ}oHE&L<_l0)GoyWHh1knT!AbzD zC6X}SN~#9v=dH-hhiUg3zBl<_Ht0_qDyUlA8IX z+&OiwJs8>w1dukkWA{7<4LHetBbWgr`9P-O7rGnX46CAG5vfVqYrbQIDOpXYhUtdE!Lw! zuy7s$9k&~~YY7M)9)EgXcZ7z5)b@zkI!qB%_ixUABs+lH}DgYr` zp)c>LUKP?icv!)pzFc=QEzn~J%LLNA)u~hqgY9Gf#AkNRZ%@8;Ry*13BsAU}@->nm zYXDTKY^(}}=MlIVM_mlVLne=}cScE%{mT}rm*%1NO#iFo=zZn82+o`1S9HH|T&s0@ zTEE3Qmq|?v!GUy=D|(+-b7P&o>NRbcOVatIz?ah_ha&3El4*DCbB>M8p{JAGJc5zh zfq%w$m>~_UL`l{A{%F!+XHUtoCjra_cFm88m)Zb2gK{h%>DREqN>0?Nbil#gx>aQt zz73Q5w@2HE=h9qGK7Q(~k+rcAx@heK!D{2s0rLmqmGJ}d!nJX3BC~eAAx0(p`a=qO zC&UvuV-!NR61Oz>$D4S%KrIWsRKdon-7l+)i=9YJl_evDpfs&Jb0sel!M+_peIzTok zPq!~EwBNGVYq5!#``kx25;al1hL-KmQljvembS^Pub>aMm%RI8NQkO{X;~apD~2D{ zAJhMgSN_P_*{^@0_l3uaLaRfd@aKcjX2}x1uBIXn!H5L*bGAutg?e|oQ(`Um2wYG$ zSNYJ@5djx0B_bo|My(RNCuR}AJrvPIxxjI&anvc+&6+c28EW0hI2#yS>qR8+IQeakd7S?%-a6VyFNNfs{3*msd|iPdg4L3C>Z zgNvdv`$A2IPTGwNZhog<`ZweQC?q2wF3|z}B43yP8vo`*1qpSjdd#Ds;!s8efp0#q z%qfZwyZ>~#xz537pL!iEx_Qo!6&NZ@on8E5@?tE6{W1$`E@|@K5maEMXf7I&8Fc)k z2o6$TZ!=N57Cmkz8f0|b|MN~jkZ-f|D~BjYM>EmGCy-%)$Jh!1iH!m20~nH@dwuQo z*93usaYyRf74NWK=eB&y+2)YM5$|4hUZyyFemqU$#pI#2 zLvEELn+WzbT;tA7A@;N3_j=`rj0uz81p%ThGVO|rPV6^ooKA@uj)$5h}+xxxMr8`1jNWXo($`aMpDKo6f&UML3{D24mLxepemoB^t8b7!4|wPz*^W8 z%hM~N_6Cbk^Uv;oVJENNmUn%JEWb2x{uCqzoFx%bcp5S&XpA}@SmQv}L_bt(*1Yf8 zC)VCCo{V#&8`NGB1aQDp(JKDi{}!sW&$tfla*lN#s!i6chtYjgwWbEAi!&|-)i~|* z#66G66&@b5zoE!Fa z#M(yvZwffOAD6aIAW!yo zQTk@kpH9-0Xn+6SV*ySPv#;lTZ%|MSB+cppY2TROUJ2eXhm)68VLYLWwoyAcIirG( zsGi95h~v#_7aIwaVKMPlw+Kp;^TGx@HX%TfPP!P2lc=Xwh4f7tA;9$2T~pJ@OeFCL zRPMWwr;?&?grMF0gkq*e(nQ)(&$5_+ql%xZ^E8vl<}n3-QZIJc%aY5ye<6(=mi{(K z%0h#6%Vh6y?C5h#>%E#OBq8kNu@NNM&U$+%+t48Xw5YOcmcx2i{*BGn&u*`E@#vY0 z*IS4i&wIrnT(d=2BAK8=$rz1Q*_(QNB0l-g7?if=E;C8ivKl+~rn>%*Gx%VPAFss? z9VpPYk=60oC(Sy7RT5Q}of-7sVR4>x#k9sJvMT8#AcW0&W?*cyL#j?(;xF@;doa8X zoqlOd_U!DO<@nhS4cXKQkLDCY&G4deXm3D{Nmr8j?mnjs?!N}o``iB<`jW}|sEMmy z26x0j6`kIiaYsSyjD1XK6*qo92DNX%57&3ck{dI+F>*#x%!xVN5QK2AmG>!DbVzBQ ze7OpW;nmQqM+_vWO>Z@n`z-Bk49-ULes@oD*dDY~u<$+e zH?<6CdwUn^;ivWU8Yc6yiY&GMg=W&#+oRB-O$o3({#wkQDaf(AU-UftOoA;lMXP;Q zO?)iWV%)4thluHI@>Bezx9wBO+*^Cm)Fj$^KTb-Wx=sn&&{b_9OgO7<>J^@g;1V$3 z|0F0$sA^=I)p)njSi9C*7a=fZWyR%B6LfJk;=xW(f}<{~a*h&Rz%rQ^xnwH#)&=Qa z4?eJia?8oY<714B2lfUflksoT$l$r#yWIJFX5~d)_;8qovzvHJGw-OiJQO`0Z8Pj^tUli7CY z(!}lO-sbVOq%)pG zOHi7W6B#nz1%0y0x0^L}=uJ3taoGO@?BtXV31k zxD|6d#^&G>Zivk6q|>f#*mqIO_)v5&&%}lHb*|4&=yaI{#0A$V1zS}eGeI9U-59h`_8}56GQE79C!o9*9J{Z7xe0asz zd?Bpeai^U0$O!XPoYc|-Q~Mo(y{Ur<+iR-C+-2=&?s}x9ONCm#>}+#|BLja9RTOFV zG&6;$>pb*{&3HqsM9%DeMwBhaPZ$;Xru{-gtU?I)9)-cvy7aad_9Xw-nXva0*`3lS zQEEvkuhH?ii008(@|!b`C!Kb^vOOWQ|AK87NXYq(Tq#qwg?FRsH1 zciX!JEh-Mx6I);AUeJD`_I4m%ZlR9L+$Dj*YQqiGA5l>WqI4lk{ekmVAya2Nv@vqz zH;*{_^df4e&O7xH(`2Rs@dlN7Gpr9*&Ym2jkFBXhdWdsQ#mVo@aI106L@5ao-6GTF z#|WLj5uJeE*JL}kv{1Ojg7GcFD#<6!s)RZlmJd8? zQ>QpK`HS|B&i2g38s-I6VoRX0BE}?fU*xRrjj2PV0DrWps4))RlNHp3y>Gsl@W+C9 zaFQa??ajy?%eMHDz(w4nR>xExQ<>O=g`8Hoy1BL=C7G)_)PK) zSu6f7e=5CmEAv_61+#ZW)d@5G_k1UV;)1b@Zw3$Qxz~)>3T6bhUu%Hi7PnSPu*JCQ zj3wz_NRl(5X&YVdd_{9vnq+hBxyubxX|?2ywZsf{!wkw9k#K@yzP)>Bl5Cys%sj(~ zjm_7}8^4w)^9QCA_Qo#?zaDq1_ew&)j=B-bQtyg7^$KM$ry^(YZHLgC*SOzW4ilg^WUNy#`s@a=j%?*U zTM*148k(!#{YPE^SlI_L3i(l!a75s9(Y2zp(PmG_q!J(V&86=)KB&WEiLoe1F-@0> zeag2Wd|XWtTb_<;(_olj#Gl_rxg~b2Ro^f;nRGdD9(VdN2lDm2d%d2Td-Ns`;qeOC z*ypIMnWDJL#n*BL_UT6xLhYG9D2*hHv#GIHbPc_?rwyf|F9CMNS_Cu+e)fBLG0rbd z4j;LJ8Djd96Jij~MR!1Dmz?G1PaC+>@9mYz{gX~4=1k`~Tbt*bMC6k0vC7aMkO}dv zkfGyx_4-jqf}ICBqEu{}vM9EcQB9`AV%m&GCdB7*7YfXVG9hF_Ck?&)G}3D}A!l%y z<~HD;&}{e%38tWF){D}7^`vwZ`#$ic@#5Y}qPb}8%g8QwXCs4LWvGxmuU3`-`tW|qKtjEG^tmo3ANqd2NEWoVykM)#CA0sB|$OAf(g5Pc-Ig6GoMTnd# zS4T+kQFsI4e|a4S8;?Qk#L5J)=S(2>HRI%#>M}9l);iRZjj2M3VM2w>db^l7B^3Z< zrIKh01(=~=@VU&6oAlcO9D@RUhX=<*&vH~j#+Q*77f=Xwk`a1}VZw@unwfGu>PZU7 zbT1;)8fl@u_%-M+U~@j39BvI8Zp{n6;|h&*u`o)#A3Dfp=Hu0qZF6L;+jDI8v5Vj0 zhsgqo+UP>Jnd6xzgoC_#1>&t(2Ob@)Jr@I~q&NesaKd18*-3|iD{-pvYRxJ7GFZDl zrRIERy8@*T(gB+Sz6OlsyG)oa>MYDo$lsx5Qeru(eID$wPfLP_S=&_^#-W9-uPfWC zT`A9TNDiJ?u_Q?2HE7!eXX@>IQIv!KQIwlGg#=#8ZnP$WoKq`7( z`M9d;4(+9Exk{HGn_Hy}<>RNPy^{Tq(eW2V8*%1K34WZR&LCDQz;K4b8Z# zuERmQSkKLh;G;UB0c)fk_9Le<+=dH_Q9^}c?fahwKP-LZ@P7FAI@+-r07Oy^{Uab` zFzq&irpH!0+LV^ObDO|$`_}X?W(^5kPJ@81lgv!g$#dit=#(v+7AL0RL@$8pqy;WR#6zaQXqJ<)Sta)t^0=u+fR;5dCXtkP1%?F-W^V*$Nz)- zuoT_+2(OKl=c1cO;f+sE1z|=-?F_&5m$!1a+khOB*DYq5HyxM%yyi_7@}{fiIXk9; zWp|dEPo)}^+BOC;jPr%PuY7TAUv&znq}z!JQq8`AT-zQw4hk$J|AO`rhk&`a1}xJ% zMc}ZOL|GRMpXD^>N(41owPJ;qf?oWw)TwowW9m`q;N0UqGPQtBMgT}09*eCkM1S^n zgL4uEuJv)M&X~yuw>iSz^8)^g)z)k{w)`Vf9<(%9WRYVWhIV-8h7%mG8ZgQc_P|HB zw>dhGnb{=i;#^Mp?7L~8aCeAhOVPH23LkH?2Pi(g7tk}>?rN?v_@eEVjBl+$Lqnog zaC5emp6F7dG?SD|h337(R=~F5PXadSrCd7|EgfJu0uAPsqivCAALeiU;#$Z;vsek| zaYbhId|D&(F!1Vj<%NCFlKv?`d2ZKUyg}CqnrT%KEN?bmkG=IdZ1KyxJL2ga>20Iu zGd#J&Z*!D)8#pgOf1>Sp>Aue%8*ekdO@>i3(n2X9L+Su(C4aM|yhsB_@E>Iv4Gpswg7fCJ_Rs&(m)`2hsa|C9 zmKr<&@1VJGR_RRA>1%&qlwY@=4*3QA?4c22+Ks>Z2$Tr?yB&VxWMzAU&%*GAi9Vl+ zg}#xY@KI|^qx%iSuV)mJshbj80k=`%5_#NILj9;`|$9qy3Er;M-xp0ZJ%%Aet=c4+2_FZ zD*Bbf-aTjjKL4KgOxMNx=Wi@5jyNouRSyP+NVJb6d}@34i9B=5jpLKknuM&PPu3c85 zG;*M@kY7muu@aI0?;aBT5dz=(ND#156ksJ5f>Zy-0pefQ5I_z0VLKprpIuz~XqSpe zep%hd*|7S9hUwf&OoB1arzm%O8EAMoc?)HHHjmOK3)apuX^a&l?<#9#`ba_5W-$Sz z)Ejn5NPA*C{EW46vLk0D4K*4j*tL7*;sBRy&dLOeH}A87ZHw8@J>u%WKxsRpeV%SLu5D- zwU@Hw;>Ct|2By+++-gtCH?F}6snw-5=&rZV_~bcX>e;x`QwU^#Tanq4^MJ^fl|1wL zQ631}xex>eNf8A2pzE1ptNhV(c7Wmf0z_3P=txcUqj*u zjqR_pB#;R3(&EUH@aIi&3mFvSg$ZKz2pNWyHbDTp67WEJ1Dc0t-dC=>&?6i<+W$&o z9(w#!EaIJK>Gh`nZfy!Y({2^vK6wm!vXfAZNUC6P3O_#$V`t~04n4?z*t@GzEYue! z(;6>Qq?QQz(BZSFW!fyjnc>hjX5wP{5~o07-Cg8V2m-va4r8 z1}h9gn^~6m5Q7d;LWzdJPzbYJ!v-6%5Cp6p+hNI$c1Da-N7O6la~A0Kk%xQ+Na?`P zRE?+%rI658ZT=cZNsSWtEXc&PTkxZj0BUBkhtIP~8%C2lbY&WG*teiF9zZKVXN!bI zM5a=0mNaGlYezA;0Rzc|_#w|Xei?&{UudQH!3KTg-n`@t39bsr)m-Qtv;75@+eH|ja<{Qqx5Q*fUdm@@7vVb;sHJ`Y z$A=`i(rGOPtp=tbopaMML?^@eiIiz;`y}9RHag3c`?tkgR6|akTp0Z-!^6ubR-(@L z1k58G%F-d6p;SUUSF?5Qg(%53h@0M&QjdtX7=ZCXM%gB#4wmy`CV8(W?)1t|$S?wi zf&kQoG-4JxdAE%UJIy=qQF51`V979#Wq_b7Z61SiSYb1^vZ{sY@O2k#f6#k9mXprS zS{eCq5pOJf8WacAwcSQPIL?@iOJwNQ|1b95JF3a7jROShh++jB0(MlyMw3K}q9Q6F z7LaZQ0)`@iNN2_oE2yCKCLp1sl2AfZQLxYh1OfpCg@lkGQbNx@7aeCT^PRJ2&+geh zJ9EB2J}Du&@4e4`%C8I_eCrB?k8+R=z|RE{&=>ND+h`~FpN^^@AD<#h!)&-|lJF%Y z#nSA^+iRaEhZ>X5)ZA*nDvI|}9DBLMB2|KC{l1zb(&w)fWBf?bR6Ya4LfSUm83x6* z+xxL*b|tDHZpqyf`zW#E8pi|I9z&;}JS&IsfO8&94;{Q zPElGKtE4}Q+cjOsbBQ6iubyC9B~*8IjgOd?&x2o%+3zLtEZ-d1E#5v2f-S`2xyq^vhx;Be^rQ1&3d?veiFHwcU~a+e zv{9*X(2*&}jx@peEQ7&cKOTu|E;%S6#BMPehBhnx^!q`R$bcw;`V1l~HHmdC%idR(C z-{qb^+$1HJX>6b4eCq3oPK-tK2|Ix`c;mnrDB;<72iLRRT4BKP!8<;3i9-4m zY8H1>w*T>~svF~FD1oyzjiqs+RTcB`(i9Ks`I6R_htoG`6%SBL0?`?#oM!A6x9>q0 z8ijv;;CjFxSuGjE2E`P!o8DPo_KeXL<68<6CLRRo=`0~`j86zIT2nGE2~^`)ytIy9 zInB;97B^TTVP9K7x|`~gURggz@``wqhD9P_)ZR?%(%YQ&jjxi-D20xFPP^Vwd*UTE zMkExYlg*lQ7+J%8UhY#z&@gb6$fkgMQ0;4R#np@*9w|Z3< z(&tt1@>2TdTfDdV*t6K>M1(nQ|1sG^&I{YfGDl}WY{>&88@3Ow=(Vn84SC}!H*OtM4Ma3A}kie(!fs!eC_c4+IZDZlZxAM{P_`{OQs>en8 zdmqKGiCCVl>ltCtupI35vgxA1=t6WcvYws&xW=~w@B>Mr^j4DYb@Q8BO9QObUWH{Z z*S~7ia|pA^vt*f71065|7PY<`eOQUNd~G$w?e#n@rsH(_z%)ET$&?4Oa37V*Y_yzf z`;CyzQJ48mJ!O1+;2(Nn$c|4pIfy@W_uZwulrh)+#Q~Tp0h6aO;kC$YjKn^zm$ii$ z?9*z6A%HAcx2AlImm}=|v&8Ufl{z)yJRiu)sS+I%L6BG#@~#DAuG=-%V(P2?r-{<2 zG*VV|>w~#&W0?x-Y}KyXm)HPf3r^xS^J65%3c0gkExiMgft~UaxE_zxf%}+um>VB^ zQmaO`6q?`J)fZzsReh<-zO3Jy{1eHVd$g)0`Qu8>4w`vhbhj4$S1#BzaFKqQkk~9?;JAZMspw_B- zfmK0}%ly}*BAvI?tR&3Y^}0<5xEF5g5&4m1n*Pi=E4Zl+Gqc9zWot&nwEO<>B8^xq zPv<&COo<7cYox1MNn9moG zD&l<2U=5v%CAqyd9AdNMRYA?g+Ur$07~=qfSdFCcXXSf1*)7?hYjKL&&38|!H(WD# zgOSjXT}$j!aZYb8Nt09l?Qqkh>?^ZV>84J8f&lKlJlulTZF!$KM3EJer>i+5*>W`< zfn>j=_Jpf{#1)<0FL};+tzu=Vg_FBeV1m1Q&Ur<4;@u#lw1zrY!%r6(Sm^`x`E{?5 z`tYdv^hZ1KwUjx@c(S>Jsg|L{*jnSPergaU>qw_&JE!}`PGu%prdj=S;7jLIgk`^1 zQrv5H#hv!jda7-l-j}|WcJ9h_K9Oyms26$Exnf`h&{thW`4OOr_0m7(RP;WQ0B3q- zI6hN&y3%dR#t!FyeL*w(eh&*0y@xH41N#eFR{?KV1*#FenkBSqL%{zi%Se73h zs>Sd~&77lPN*c`C=ia&75&v%HnvGP^W|zIIG^}b~u*Z4VxB$y)r_%S5U}t&f+V177 zlpO9`M+r3XBA4r8rZ;d8`)41k-w`bKW-Xgv3X#4hs}x6T&~}e*+RwQbrKdHM5~<&C zz2}ybw@J-{3s<7zTWJRv9*L(n31Y72tck}*$`Beaml!76&W6pG+1Tk~GelEM)4Qv% zHAgZMQ@jHw^8|b7wLsFSsr!zXhCc0BJE^=K*N1a&GHIH{O|2VQi<9xg-h3*M!aREL z9v57TGl{2D@E4m2b;2_!r`_2LB?s&YBl-2=jNXn4gR0LDBeT=?YS?ctUmCVRtZYp8 zcKGS>V>!*{DMPsKHeL7Y(yq>tN|7#s`$<<=*caG%yR#qcA9;4MaFzG{F$jr4nVpPL zaLdr0?M#?y@9a2pzTu_G&3BmL zlN^^pA3Juvy;itxC+}KJ`rZ0UURc&xeh3Jc_$93EK3qoBru6 zXG!)ainH3?$*reVqrbEoci&BQ;@TXd2-z#xKP3BMd)Nzn>ewN@6_Ia}=+5}W525qo ztMls?8z)eHztywBf&Lq(pS+X4`}1w{on6~l&Srz}Xw~x~c`3S~30DiV_mE5I`{gTi zvg5afy^Or5cKZ1=!MeAUJoQTJkk$nb0YRL6&RYee)6d4uaHOF;$$P!W@HA_)G+eq+ z8Yd=jieKD${pb`o(3k zPLey(804QKT%U%txXg)HD>o?wImjZ(iVg(@K}x!oH^%D93365eO;GB z4O)NQ#BqolnbmetwsHs;N*L1?-McqwU8)8~WYeI2kWyAIt%4K#| z+6HXnHKc;R>tF8d8eQ(euHzdLsdN1fVpodQQ~G4_QhIG_SnkMrqVZ>N`;Z-ViW=5{ z)EWOCqiq%GY=94$Fcn*pUt!u*tNY zk%ejRd!6t3w{=~+%qyDT+6z-J^20W(-*V1xW-~@1W+gz;I$}Kva=>q>m9M{v1nl%uRnN{Ob#s&Aeam&>)*&(x4yT-Z_7W5tssk80c^+MT_*H4U` zU}5&AU+&5{Zo1*byPD@MiEX6%96$Z#{9Ft*Mm%8gw(QPB?jZxl9uHvqGyOEjdb)zW zgLVgqi&u?{7UUEeYQ>;0VLuji3p20GlKg!@;Ct!i?LjDsP(TS(QeBa~yVo!kW_AwA zw6JDBt>cUoCd>M4#OMX}PdmLdD&?iGdDV{wbfjff?LXok=j@qKzW_6J->QSBi`B); zn6D1gZw|L^H19nm(Y*g;q=NJOfnhtU4e6G7A9jinE$y!Of+}afP=V*?$!qLNst?b< zo~#&i(`7$yrk~5J9OvY$RU?~Ao%cA)r3i?_;-vEjIHGC6%#W*i*b&YN<=fUx9o`8R zz1yO)#tybr9;USn=dgUD6y_b2Z(3=KtzqS@m7{f~uvi%f`+T>EUyH`K*>$kJ&5vTw z%c(ClW;wMlaOTK5%?b2X2;UzyP#pJkyx?z5k^N;|H%FZE^s1FNS&?8|fM8s@$? z95WsxvyG=^N8N~yq+MX!N~AjQmIq|r^WGGj_q*Rl}$uGU>96k;IzF z!dQABCWyDZV`xt}UyMi$#tVAhXx^S%WAzYBm%|l?TTN<|b{ZR5U#fX?jQF|UmbyPZ z&DimVI|E1M>5KQ?f5K}?IXxk|YdK_`tBqutWcGUnM$8LbRISckg>>mHH93{K*q3I+ z{yGj%jK8bzcZINQ#zE5kE_s4+&LD;(=q;%9&r3R9Bidh+Q@Uq;WLVmf82XsMMm@oH zua!|w(YoulMDM6-%yzb$VRhs53I6N6!oz{$i<>v{Cj4Hm$ZmfiN6L}WkEw5sU-RC$ zgNbY8S>ChLI_jQddzh(1X!bwnO}dW>Tb_ zRtM@j@&!sV9Q*!Xgf4^#h_WI zEg=20i+j&lE1Nf?F=)*Pqh>Q6Wnq<>pC|A51%W#W@9@MR%J^xZU4Gzx{z?a}e8R!w zizT_$IlNv??gQGg0ds+CX>44Xo$(99H`I**zU!Eq*Xl$K@5RO~*XjH6z=xV!lWF-) z&por!aeQ{zL1vD&mTY@v_k|vhl}3FACM;ujPhZ_D1mYPzYVc*O(;D`E1zdAxt#keL zO0(il;)*8;CTpk>yL;-!XM3bG2dG64>X%Jh9!0)f$(*G!F?ncn9^I+W;;nbo?hEvP zM|HL|(LG`JLQ>R$BhLKusCuUnF(+;}<21=Odq5EHPpY?~N|_U}{0wEg`0CH$e0kc3 z(A&&)tMCQ34k*EFmG#QDBC(VXbe$_z43pA+OE&Q?t!!{;9!S!T4z8^?7T|KEeIw!r z;`8pNd(WGr?~VhnaV;@(a{j~DQ1wvacw9*Gn##%iT<}AkTd&5nPOa8y8!IZ;wrSr# zd5X2eWR^PyH?dl?4vgvs)Cb{qZ%Ha3R2?cNIBZ~>E83ZLRR(HDi)XJM5%x>a4A{kq zg;))L#ln4ub`7qVYQBr@o+q<;9rMyQ9R@-4;nai1g@nbi-fP+{4_Y*xx>6H$DO;wo zsL>?CV19bwV)ctjYoZw%vQ@dAMzUm?YSG*M)WHoh%z+b;LIRc%>EU|r zrlDAyxNx19Q^WnwQCm9&x}M7XAt^!0-q?y8URE`kq`;i;W$dtlAyHkzv_o2<0fj`y z3>n*xY^AcU{PkSP`h!Q6o_a*&-iePLhPFS5mg)hrI1=& zUN5bvUG}`>_8MoEkx1%-8%4b}=0}+C)_Mik?CQI2+e4N##LozUs|Ts9N!pPrFTN9)6-C&+)@zBS=Muhkay*|! zv{gBbm0z8rcdy=`XaC8*f*oH_iMHPS=n_m*mCho;^-VbL`?VCuH8@&fb?4ghMSdF| zQA<;YZ_ChjBuzb{ecPz7C@`M#u<)kuXw%jB!I}}8r0NOp&AQ-(>Tq9OZ@s5M^9|Na zg|NBWpHpvsCTBNoVQKH^%~WvC*!(dlz9&uoGFhj3EUKTsX^5j?KGs*0U~6Kn8cDzx z`G@2U95;zJ&5VuDz(3lHe)|Ve{i|dK+iS!U zW1hX&?>QjFy;r4wiuhqO?n>}p2~76cy^)7K{RfYy6o16nPVjY`-knR^^$}b{vfHg+ z#yyJXT^q|2S@aRNOtzpF-FHX>F`{(B}8Ic8yQyfo5O7bzv z05KQ4kfbwD26s8urC#Ak9*1lI+cs$?CQ^MOqH%w-m92U8uDEE$dFP8 z?wyyj${>&B?N2_)>ApGP#aFhLxnJV15%IesoPB_(6{mPodlyFj4YJeTrRPXJ46b{ zxPm~w)AWtwIyP9j&Ji;ngOHZOxG4EJN8$~8xucx2%_1FjqVznb`zl@j<*G3fo!p(Q zqgYNkrt>xnHq44r$zj7`t6MLUGC7zl#?kBr`@-yu={b4tM}zy<$`v`fs>#DuaFU>P zns`I2vH6TjuHZd#cZ$W@q(v@R<+SnC`YDNaw_ zu7})UyEB}qJ?)Swnb?k#-g_;*SW_R!yR|FL#Ch5EtU%)+!v5gA+%SQZob>YaftVmk zN_LcT&pD{?8Twi|Ow92NcG-5%ENtL5u4mgH{vG0!2U!xvg^GuptOXl4|8P2t2oA5A z%{6jYyG(Khj(Cu?8N>i`R_&K7y51a9{3>k;VZCpVeOeL46oy#QGBh>Wbe5M!9Q)4N zO6mqZcg|t)Y*7>7!E~>=MUkt~T}rRi9ciI9hI6*sX!+J#xneY}U<6PfkwwXrKkB*}O| zN&!<*ql?Tju87w%OzeBu6DK*-_;iYy*j};C#+Y|*-U(7_LH2q7_uRTvw5}-(JU_A z|1!hOJGcYO+^efx)@y$w;a#GCM*X3%nYFJSw1oPx;W27P zs*Rj-ml!UzzR{5Jn)FeQ%}`4tI%}%P1sc;?s$F8XYKFh*ghw+)rA`>@ov)rdYx*4G z4F8F`x!5$VG5J>kL9J`K!)5!S(}u;oNq3jdY0XeFG?9r6h_I5Xox3D0&b0LSN7-1> zg9nXmP`H>M_-X1GE-r{iwmka<;}Z6YZ0oeJT!Csp^p>ZTbtGAL)2!o7119M3#ni zI>+qiO1Jty)S+ipm4l@hLpTl$*3FyTD1KWq%DT2HYK|~wSg(fX=|3iPzRvpWiT%9o z{uBGbAWZ1vUJb2dVBz7KYrEE&k&6{on3!`Q=7K>2Xf57g-mQ%fFGe^>kKb6GkJD;lRZ^AjB*N$TA#2^WF`Z(JPv~1dHnYmFPwS7^BO!(U zc|`7k%3YtRW7fr!n4jcz3Nj0;oJ8=K&^I+Ge|GGJH}gPr9{T4K0{dttxDO=1pqzWX zFcTmh-ZgSE|NMm%rRjy>vB%uSZ+5CZctqZ^Y#Z1OTQ9BE{Kp%5WaISS0|=>>pzr=x zlJfA4ewY%P4Y>}~8FKq;2!|GhEtXhw|FP%))Qv`W7(c2%gVCSy2S|hgO7tJTI*OaH}1`h zc~TcFS^?)V9_+LxCL{LC3V;1kQw_k#mbKtk;dOw&-C{WQA3IzpedAXGIY= zO|Smehl%sI#Poo*k>yh#VawM6>zp%guTZH0(w)UN07R{d0b0^uPbejQ|L)3pZ_<+C zS6TrBkN{X&OR!3!&=+qtzW~5Xt1Up#|2Sm?pb_>?U@pj@wdN7nXOtM$Yn%{=4Ynvkfonel{EMi0;hM_ zPqbxZ#g*P1&ABQs<|2>#?n{`XKz8!>%JrFm0X*YT5ol3{I8~^Wg1A6EKuKC3wT}a& zDBVv>!{YT{8^ka!rgP>;gA>;-X&CzO>QaJ@avUCba+_KwvcP-6tXt47Z1&8o2hpvK zM^_Ak{o{GfQLuWo_KwfOT0Lv?qUlmElDc8Z^WK7q~L| zubt?n;Vl^FbCbBsU4ZdeTVnfmBk#8QM2@G0yPl&3m5@|0==tK>0_XO1t70-fpi|&}Lc;0J(@fc7S93tYIRva#-|`+T z+vyOaD*jx397zIL4t;v>at05`vd~4(m!KGVTp08QKI6Xb>bqi9f$*e3RpmktFMV5j z92*#ea$iIo-3^S z5&$ZA;1f&9J9QkEKU*@#38>-W0D}()Ps~QTcoir&;4)+!#0Bln%ZtI#+XfD^a-P+` z_vZ65q*dJr_y};HX`BUSEHaFex}=4e`@jI|N%IR_hqmSSk8ib}#*#=8@8`2*LUv!C z(YRtKfpui^uw$Q;CNcf7yq%d~BNZa0>ekTt5d1KSxjtK{6=NZ1{U6h_Ir1EXJn4-&WwaNE?KS;aCr$zOkOBH*72Jw&?`P1@x$eSGsAs*m7t~&!q4pV4!Q+ z@aQxpdY@KV-2qU>%~J0HgRQq$#=z#S#CJ$R+H2?m{+yv*&*2uh;bKGpzIko_Oe}KL<@A^ z9+?gR+gCEOtOpU$U9i?Q-8hA6M?p@hBbU>_H@H^mDL|&VmC&A|9*d5nwTTxxidfG|dHkv9F zGyc!@t%^8F_3;A2Zll$Eb_G|Y9#dfU-V{VA#3f2b`91bj7p@H&|4Td>SN8%+hGnHH zUjeuanSg-=@YCdV)_yo*XY~cZL=Eyce6UjOsrbjS`|gt%F8)V&fvfrAn=re-@BSZ` z@2?!^%lZBLh5pJVP5|QB$K%P5$-vj>_3tnL@ui#V%OCzSVHyOy)Rvi0>#1J*Mn+cXCI3`$)SRF@Fd>dh$xd&GkO6U<~FguL(UZ%zhrT zX@zHhb;k|a^lbopeW(J4Oyxkcx6&K}H#=_5mYCacbD9D%yaP#}pgYjUch0gi7$WaN zlv`I4qm$~R23i1&9B?3gtOEO(J6CADBHWIer1aB!2u1H<2P~{>ZbWR@w$pzYK`>W8 zcr1UY?Ph}3ZK*-)VK7$W6;f*lRCEoBx^oeS6+?bCLI$^Sh)fPApHbaXBEZ zV11_%bhE~vC7EhOZ$IlR$_6fqJj5R*c>B>tkiK#65@cj!-p-J?a0(!}ta)>T6q$dg z+TQ|^?Yzj6^fe#7cHX|)?_6(0!jbawQppf*Mz)3m;J87EX9KCPOOAKoPD8l)6(Mo3 zXIhch#ejCOn(W#P2xC>cU)Jg^^Cfd0JB@mC z6f}!;(6tOU;zwuKJHlbLIi}$adBNc#ukmgi?`@D=X7Tdr{XQ#yUj>_nsqCXcR9!5D38oB+47XDpdPTmP)NI1jz0R66!oJw(MSXD^%Xf zzY*96hvATyJ^g)ZIpliiPCKex@#6ZTa^MK)0LQWnT?61%Y{7R6LZ$Fz_!ru{$LS1v z%Eb>N;Tf9i}m+v2ot zr~Ap<)^Da2xD!zo9|jQH3RCDmB|wtV@na!?mJ>dCRJ=uzR|h2SN^te0i*n#KO}G@G zM>Wj|QNRU^8~vUS)LUn*Iv`Toy775<)H3i!8cLJF(%o$C&UZqYaC_8>+OGX}swQ8& z%O^eVy)u&!s46-R)geWze4up8$wx7E`4H&nrl1WuC_tdrWl9%LGC7zt>3nF(HBRIM zj6Vz^Q0*eVPvwDxC~AX>T@(N`;sb=o*`(+!dN7CF2gK5bV=W)~MS=oRP9Y))Nr?yF zU85BSOI*Mkn5Q=MR4E`Y$dgs|paTH3DH2*mn(doG+r=&i+D{?IGuN8C{#9ZM%}+X~ zK~G|VXyG3PC1c?3lS#kB`OQssDqLg2LMNplm-acZZYtFt%3nofrgKQokw4jIKu2F_ zB}5Lx8$N|^x8#L@KQP%PFbB9OP*g%WZ!ht*NV^&6DmLx6B$O+B?Iou#k;Ky@TiQVe z^O;T?u<>LN_3q2FNk7JrcKxuR54D(Vs|TEbgIxwTEA|$2NXK6wlgB5dr}lsz&04_^ zQH<;W5kaw0mcri&dco{5=xvmotrrq{^*dTL=z0ZhiIH|`IBogr&Zt_sOq z;WBkE4<^UxTa_*}A7b6Z*(}+c-|hLo+Kt~1!GB+vY`^}u9>9i$nE2mz_`kdz(6!>) z8EI8G^m1z$YSaRcKg@Hmv2+(O!<^f@A^1@$d{U6$opU?ncBS3W8B8$Awi|TPRU1B+ z2`qT3BkDZ+&XcwSIe;@t4X38cdyNfI=@PRhJB^dU_e&h<0qb0)4SL~9<%dIey!7pc zu%2xfm*Jy!@xy^W#9P_aB6KKtiy|r%8$r~v?3kYFdAL|l&6u`MQO#niB z$BRXJ3eW_I$nCE=gxaBH1^gBh3DVu~;s<;2xyG{N?6N7Jo`jB)LP(h}T&Q$9w zlc$^(VPRGmLffn1jwd2R!o3kQI1*|Vh4U4aFc>u=yfBTHcl~^Bv=91YIi|0QfX#d1 zn*H}t?o85`Mj$A0+Gm2e1zl8H*)Bp=9Nkt*zw9qPCN7nDS9b(M-2#ny3O%os2_e@d z0*spLMT6(5k5wr>Ny&BUoT2#bogZcUc%eLgm8NgQw&qu$>uD|V9;kC<^^9viYQMPA zE@-HCgq$q{B0e{XZDiW{l=%+7FQTnt0jPfjX`x%|Xs%Bo3~MARW{NI92UH4nQ3MMH z5fr~|pm8ypnfLYDVv#Rhv7e3yxDkQG&jBq8hrpdeLX3ajF3@U7(2G{<0Aay&_gi6D zt|{qpH1y|DH%tNg8BcP*Yc5&klmb4GsG6*!RX?z~KfW|I^5UC~mLvV_4p7Q#-);;2 zt3{J{uC?xFGYz7IYf=9N0`M~pFD&h8Eh=I&C@H8U$G;ksIQ7qF6465)G%m})=eesS z6yzZqK~oLoWEWl$i{j+||8!ZkiOgofi0#wN69>Pw6opnlP{w#z@Vjb(C-`Mk-Y+pD+|BJuPC0YdK2pAdhHfw zx(>a+S`KaU5A)K=Kkf!qJE-pl-@Zt>@%^t|nMP1O!-Yx5_Ng=HlIfA7C-!~6)_b4@ zKP?*uUEz?~GbhJ+;HTCBq*XL~UJV7sa36Kp`*+!;vzbC8+mI z9J>EQIM@}#QDLS0@#C_3LZh|=BZy2rHmw z&}fNd5Gr@kovO?t1r9e`zjXJ47Ku58*jKX z+MY`6vD=dKZi*A|S3*E5b+V5tU9j+{9W>0b5KPYJ)k3{@1@EFDBbWleJXtRH{^TeTGGm(h2tn&_(FDX)zXC&={c`+-eo=SvEN+t^j!+ z)M-2{m>B1pwSh2`_hd%o2Rd0RGU3oP(zpXEpiKVc?-CBeWH$W`N8b^2Rx;cRen_`? zK1kiYz6;PhuB8-i)z8*rw0HfQO!r_gDnDpjN!Wp;~lb$9jd?SrEf3ZARAgs$4x&48Am zI4=J_{p^^_a>V?R=EI?FlN6rUTW@0DsQw9>{g2g)MtOM&&@1SGSxJhYyypl3TM@4v z*j*{|0jTq-*km=A?vu1UqJ8G2-ZP^hj23011XD={=OT=c8ziUUf7s<~V>k+ZOUy4l zlfH13O_@J3XZ&{hh$wQ4kk0`)|FP`gxS0wmXB^8E5GdTkq*$QhpleY*3}ndx^5K(D@WzO=IY;Dt=+mWA0dsf|`K zznDRW4T73aks1B%)$hxPB~||zKYqQ3Jt0^QZnsWJ{ys4Be58tIH6ij7=*D>1-?I6F z-1w`Wf(<=B%Fj^Up9V!h2UIzqOA@nwd<9fl(I~ctnQ)ml#<8g>RR4IHpRaeqFcPcT zQqX@COexT<1OeXh%nAMPZuRXOVz3AxQ4Yte^Ov_H;Cr%?ClM`^(1FRW)Bz28dp-CL zUqC0wU6q=QGJOd4N!@V`-v=?s{Ls99&WfE?NJxKhn3W7Iv9h^Xa8VhrmR#Gb$sim~(te>t3fZLo0rFrS0%jFQF zY_nS2Y`q}dyV?lu4&_KD<&dDKF_VNsch_z6pI(-l5BfiYz78-tD@v2E z*jYUH$7g(6*z?39$X9O2f6x->=pVmn6S>GPV>)5H)fOqh$-%OUmG(p&5v$8z9dqn>u84;1m5vwhd?o;LGKnRD#`Vb7 z6UML?Hu$%yJlK%zx=(|Ycu{=vy*(2)LqZ6l+JWnbFU$VRi|zT+x`r;|OsJYGhqj(D z`1Py77AW)_4MW$Yza%ycJ*|GwIZB_*{(kW;;f0|c(e&tleE;9R^?b?*LTiEP!yKn~ zzt0Q;qMO3{lB>Y+X-3L1{aY{(oH$z|({vkdB~q>d4!zMHc`HvHVNo@{0`tnGt8h zFbG0f3Z&<;5U1Y=hEV_W^#gS=ue%|U=>Q?8Z3S)vJ5U?jwZB>mzf&FZ&#^BD@7HS& zAf56BS}RT?uo~@w=1f|ylNBlmoxram1pInN;tcov+Xo{+X{3V0Ew*PjU%VNr;*=n` z_z)6GpSGdMMK@x@45txpY%&zKPJ^j~wMH<=tu`i8|K*{~W+AZrY{rk4*mwct(U!68L@qe8Nac_PNYw%GM=oDTOhl95&j%R9*YYN zP#N&+w*a0tC!GLGHFTNVSFPo@{NudzKY#t{oMsZHUo=z)w~xb61$6tpN42vFYLT&_ z=n?HXfgrd)hk!FYpNWTCJ(F}O5JZRU)Bg3;B@?trGS` zh!_}D4a_wBm)Hak4hGvHkT0cJLZ1if5%FIy6}&yvC9K@l)9^Ts4FR1^&j1fmbp8Ee zUEpQm)~TB#iK&eMe!eA0Xm$XGBrRpKjQ#bdNHbA}4vCnz!$as`{A!ECHJMopsNbd;ihB=x~Y*AI7{Gt@!Sa*)sd%_HEu zHttV5<|uFjMBVb+=&_ym#i~3fFQFd5LEjvA-8a2|``MCO%*x(3O+N>QgA1ylDqvFG z5O4v_1|ikq7&}zN$qAdGE>L<-o5-j@-1!DptLpd9pT7@q4}W9f2$yr@vKpRCH(LVs zN8}CWOa`sxC17ZwSDWe=SNe1v{C{YgCHu*{^;_F5oS7Q`Q`%zsKp61PY&0OBc<0-n z{~1+wK@*Q|ZlS)K@P=z)kP@h;)_6Ef;dMSpdk(VlU4+nSlX~ycA3_0@>2Q#|dcF&A zDuV+i^fRJP=%xpU#%gk_BJ@jv(gFrmCQ?TE$$u2KV^@jPs-wz;!Y-X5| z|M`XyQt>nXx0~^Rh6U>F{Ioyd(mbg_7i}WQ^cT-lZ#M6f%=q`{(=| zk6zdv+5aoy0{<%T$*28M*n(A|G(>_%#ijzBo{Mptlr3yd5mXlw*qB& zlj+#^pP4j+=T2qUI{6uE7&><;KAp=ieYhc6<>#WN_QuvLpDu0V-@K!%pSE$bwE6By z7+hd0xJYi~Yr5w5V@P?&j`z(*bmmKx8*;z;YmU<(!8G~#6Qwn@Er&$b{ueLYb~7*M*m0F#ysr+i%H5>I z&tEF6@1JnWv(naul8S`Woc#AQ!%%-vKgCsZR2bq_9VV-JG%1@%q`lv`$bpoGy9%R(+K0- zO05@NBER?nZ4IrmAfY>35V%?@5VBjJ51(!>+M60Rjqu{atp9%D%QF5yxk}rCse>k- zkOC;0Q3;RjFFccLy)s6m=>C=fhC(UinGv{G%f3~4SSuS-M&>qw0A z-(lg=yRUi&n#>~73$F3WLsVuW&Eg{pMO#o;C!lz%?)=AY3#%4nt`mv}s$dzQpP|N6 zf%?B3Fji(tG0~7aD-l{@a;{N|mv;X$w+hgeA9|Owpji zxT$P<{{}A&!=7BXimg;u>~k_ICCweKTzCwm!_j=07ZyG$1GCLjVG6i2Ae1?EbO@o_ z&>RBnAU1CXyw_41i2FZpr=p_o>*oLasXb1ZG6GW_JgGcdUH!?u?N}~3PzC15-K}V> z!vM?)-mMGZPmkqwTiP9IC!i&ivq+Y?g<1 zIV65Z;=cP70PqT(%^E4VIB@4s!Q<+EmGEbv8*c35+u(5hxc#AubW<7`-&EfX^!N^_=5M4v3qeHWZa~?g z3wLr{3P5LhK&t3e?{G#F&^s$oD83eA_$3bO%;-n3Y7gk$Ojm~q&hs$@uNGBmc!~;l zOW+G90FWG!(XR}{P%W*|CMB&5>Pj16R@eia3|DXNj)$wH;rWgMH2V2+u`k%3@#R(z zo5Lz_=MT!50B^!FOxfNJ++hqtVBC_?IKvH*K+jJ93}0G2kZb{?)C3?zS$=$T{|fG3 z-l`IwF*%$^-S*SPzKyFmdkQ*iZXwTkRjXoAWd*=5lf9u)mA>{J8t)If0#)Wrb^nH6 zT->YAm`{gW+f2i7-cTg51!wLxe7+CpykS6-X%YhXRCGAdXX?n-)z7_eppoS=RX6gu zI}9~Z=V5D@0Nm9X`)jGP`aA~z&R<#cmtz-@=fjI@xhSev1TX{%#TeS0ZF)#QqfSABPuKjElV&=NSpt?M-r_gp%0n`aM5=z!n8-7tiuS`uU^*|0ER`mow zDj_G@h_;OnKIgB^OVeBTbXwI5*(`wy;@gQqyYSge=?gvY(rwH0;P#a+0=UtY;kUtC zm4Wj3q@au1G+OmQlWYG_YZ#o&amZDJMs>E8;E9hQ$P~g1a0o)kq%H zA#TO8!F?xZ*{(|t)e4W#ycB7ARRN%{R;4kRaok8)b7p|~?jCl*f(5+-jzIeQwYn3- zM^qdepPcuKPhFBL%98f@^gBKW5wNVG9F4YfulEF^ntia=-pT(=?~8Ofu8g6}$Be47 z5Q^WvXgo_*zAai2Mf$+>Y#;sekRA~4&l?at*b?opX*bnP^J)(Alyp6Q2P`^~$j~)C zyQ$P8dc(71B92^2&0GN-{}ei+ISIWJOd5!-)l8pC^|I6{@=_hWE5v?BEO;QinUc%E&9WTPcu~8Y zk%hN~pDGH7UZ{$w^oW%2T^k^ZL!7CDY(H|)#a0z@;H345KG$i~9 zN%J_2LhFT5+I7Fa9i?7!B=c_Q6fD+RbbrdD*{m*h{gHuau$V&J#DOI#fh7zz(VOak zUVs-SGM!zR3>SDs<3A=>s@(&!DNC3bK7QZm2ueB(P8OOvodq5VS1*034oL;XB z4nYzwi1`R6(j^MuTDf~w!S-x>NPr-JRC4*P(7Y3x2FeI9E6PGZz9Qf+Xe6vcc6PNp zsX=)_M?nGvxG0=Ffv8ZUIOBUR~bWe)3X&omGOO^&*pahsy4caF~S#O8)=+uPIZp5a(MPqkZy)XbZE=emT z88?w^KMX9gWhm(&hDEmnAJ{32)8M(sES@~owJW=DTS#8+&5u2XFUkXq+ubb7E?x;} z?GgcTh=a6_bB8yVCBj0)15Yn#+8`#uO|Ru?3nxaF+m4D=4UDp>6K0&H3fA-KQB#F9 z%J-mch5mab^wn@s$Y;)1cf$WmUranL<=(wL6Y<^=#3j>a(q|4~PotYxqJRjkORgRm zHNM*XfC^L497m*^q=Oiqh)>}**o`yJw!;qsh_^{X z6&?kafOxo*JSixz@TbS2QrU*mc0_-HHpL2e0?06THAZ46fsIyD+P=(7qX3Zv3(1k_ys8gTk5`Ox(4i^2uaPMoAE zBP9YvCPkozGWfuDb1|%yh)W>RVnVh)4e!bLqyYX79u2Ld;IQ=pqBj&xkkPdZqjrfa z=RNwV#(bE+TLBZ_x$mm_*fZ3FMby;_0Z7%9L&UKw{tVak8PYsxaRX~4rRrF^Pr8Px z$B;wjsb^DCuFdENmUG1g@Wrxx_w;vEwL)pCVhI%5%rzn_5WtGr0!_~rL>@yDLrSj} z!EF)~^krB7_R%*dcs9!|^$vIEV8dB_#t`5t^+U2?klDcAQ$Q1`hdXum=|b4Gca~vY zE>x2@xJ5#lyjZ6RP#I;QrDY`mL7Q;=(%a_J8K=_C$HAiVm70Nu1w^|;zFAsRM_{^p zAzQDYcW$J06-OPeqru0z=D^HN-ezHKGP!#Wec3&Kj?5rj>D>T!1VN2wZpz(Akn|dQ zZwdV7!5*aSk*-->8kY_T|15gJLbnP~Q#!7|y?0D^dtUdGo8zO1)clNLVGklR-Bp(! z_!L6TxZm*f^%?zuE=t|juX@9`E02DAf?Jh^{@k|(7!YMqTd)Un!yo3_7G3eB${w(_ zMs9pY@xC>Nv9Q)H&Sr0U8OLm16<)K`5<}tV!-B~mh?H0MzYYQbMxxhKEx|6uM-;Gy2X|8eTJDXAnys8m|6 zv{=f7q-aC3?@6+ZAz?5KTF{186^%9fGPaqKwNkX%8e^ETT$F8QEHOjI@;`6g?eqWK zulx9afB*mE@%MP#2fF6Hp4WMu^E~JIJQ2@OJ~_y4&KVv*)#nY(?-)-=`4=y0a9i}P`6!UT0#)@GM z++$7)U8<35)usy%_dN^ev&c`r0PLD6Dx725*0ECOd7OC+6aes2ZDKYoDNytJz(>3e z$VS4Q-watW2^-qf2l#oFDDp%F-p=id_vXBkz|BR-X1>WBF_F2i4Ri4Y^5Z?h|9}4D z*(hT9CV5B;eg<9y)GT!P`J+o=0uJ=CweFzf54pn)HWEX+TQ zg=S!1LILD-N~*IKGcoVEMo>A@VR{C6vKdzpU> zvH~ySER?Hy<9K=DVDOK@`y5#Yrd2WZO#$QK2@I+ypCy%DpAu3Xru>BW=?NN#2Va4U zidJeeOS*_#Q{`6|-jDb}q}qnaDn9;v$6o8r2vD@~afZ>DBkj_a+ zYbd!^S{kFFu9X>CyW>lSZW=N*fV<)e+dVj|* zr?&*Q73MeV7$#W#F8K7>&AbOOcpAbGl$1Psms1^w% zL=bf?>xRP2oZ^q67|sF4(CkQL&{{^CDbXgx{>Jh?q(qB3jn{7!B|fyUXv)^-BR1#q z#DF<~^6q)&7!Bi1Ke@uJ+T(IZ3L~?T_9W;LJN<#&L@zFv5#IOVJo~O^mhKf4EcmlX z5c=qBN3c4uIW32ehdB(mi$z9@3-=8q9D)$rm1uEio&21h7y`8x){aYnB0i_%ReMp4FP5na7*>$>9mQ!>SYy8HCQ*wu5@jP?BDlQyK(=BzK zNb%7^d(k)u?V%~h)hOL@ZA>+=jBl*J8!_-tN>ZMG%fWNef^Vp)v}@*itg?5c_z%wo+xDUL{=xw(E^ zD!XpRNDnO32-(E8DQ=D5J(j-8i^`=exF%B{2HFG5<3L-dsTD**v9Y038L392ke%$a z{E8^Mk{2bt30+`c7>t8z1g0T{3!JFy2;HmT_;v3sMrQ2BUv-sy7%aR2R**2ingiNKBQX zW5Cd^yhD1I3(ZD|D3m9ZEflW0I{t^yP9a4dDep(qrH$Rlbn}+_to!Q*%)QHe_p466 zNe@moSpRKL+z!XF19VT7jsQ>pHN8+k*^fk}YJ#hU1%!4nA`ylxa|j|`a!854$Q5XP z>_OOh{G099kLK{Ioh}=fz{5mqH2B|MDaB)&MlJ7i@eDb}8D(s@?#`||nQ$yFraiM~ zx7o4rAiN$j!kO)ujJM(tf9oyx$&oK~camusw@K)Ov9I!e8hT|>p)Xh$AMp$^aW-^< zYeO+<$l3ObBirT^<=l}c3>^}20F_YP5S%ieh_~)MnP6V|D(Pw;#F=?=kzQ*~@<}#2 z)lrbx60tLYM7SWdD|(W0Q=Ycw)R)r=q)}6n2)dkcq9aI`I?0_jIcRu-9za-8AAl#0 zZN$sX!u09Kr8>QcY?{XPzO<#fRQ33}CfjyOtH<#n-Hrs{Jyz_^My^Dks}`Y0UG}SZ z)~EFDNWG(JYGa4`zCK)DsM;ToImblHT$Xz=HFRTa;pFD9jpq)!r9ZKiOGvEFM%ZnG zK@Fm%j3r(VwBo`l2>I%>6^-6!XnAJ*LLSCv>dTBdea7hI-)%K>_*`ew0^N)ynrf>X z0KZ$k=&qA~$!&>6Sg~Wc00h61e%Xfx>@P7b_}mFq&@8?kWnhqYL05~#ErKAKZX_r} zNQvD~ry6yT>dT~+CJ|G=AI8pw9OCHgDxT)t7t$A6R;*0d zrK+-o`fyT|8Vj3F6^7^#h4?F_qTi#i*Yfqj$=Day!ctz6>wUB|8!F1pwBFB7RBJFQ zXzLhqiE`3`K$>Zexp6#B)L3r++NmV!*z>+|x`_3+tTD9*LSZ-sH$@%Ac-GdacGH(O zfn}y;aR5w}ITc4pNl0}m3^k5-aNp2LBCM@1SUa%;7bDayr`4cghj}N%{`qX{m4Q*l z`Rl^BQwX3+iIq$ox2SjI@V52yj{8_OoLr+zAGe8|w*Qtr+n9(BCnDHypYzbj0-0v4zDrO{1m9!)|^=r~@mL#%8fD>zxaO zzX-oEDm{M3NUYmJyUfbslChxmBK*rY{F|~7xmrP7AN)eYm**4cO~ar16uInlAKf6i z4fQn7BY_j0+&VNYNrG+1lx`Jjw#~LRy`!rnjHvo=ungl@TjM`bO3nvi@|8 zp5Cs`wRu@B(GdSo*@D;}wUI!? zs};LDNj4g$w7Z39lET}Q^t6k5A1&WxK$_kC-X$h^K@>wwY#mkTM#u+M)>HY zTi+`_=ME6Xz@2_>Q^tq?<^jA*?oHfsi)s8EjaVx zC831DADNSb&OyT!bk&w*Zj|J=E#8SItEKTeYwvjz0=xoW4(V9K3i3FebRn@?o|Mk> zCOkDRaWcBOhk8?8&ILacl+Jp(Yxg1;R+M_>&)gs(LC{)d&AA;9ifi?$60-5=<_sZC z(-+#_WjEmeR1&7&G;?=_E%p*4SVV@}7yoeE;RN>{+K{=!xQ=k!f^-$<-|BcSy*_-g zmk%KmcZ}9E>cKZVok<1nlR1U_{8NVrMGPg-z8<^ zS;aV5oikbWsXXHmsW!^TMfcKXu%|)Ao3NL2n+00j2;|a0e*-7Uji$g0)+I><>8k4`Q8t*GN9ef+txbGV@?UZUtK ziE~8$W+&TpuPvHQy>k)3mktpJ{J5O$Up`eaK63}X-XlcNG@kBwvm`2VrN{X4V?j$3 zuU#C&jbF*x75}L?v?z1@B(WcNFIlM1>HHV|4%4CmQWD+$Q{O5dv3nMgs9T$@6&^3| zE3Pt&v<}XAf#Z4EZy7gxePr`H{C2mS{$rH8TtAl*Ygka8WhPz+i*8e$@?=!vb!eBJ zeIEWwDw{p@#Bfm#nFMporha3t*J|Z58l(?p>$8>$_qnB&=7i9?C)w`b7_GvNwzO3~ z^mT4(-+mQm3<&i-4lUBrpx+D5vEvAxDmHi;W3p%cA@2Z#RmN$wKw|8WF*ijT*O!2G z!g@tV><&a73m>d3Zqk@+%RD{)azbT;*T8|szPo)VC4{*q3OU!3D@yMU`agzw1=-Pq zdlu~&H$Uz3@SwGh6d^}4r{8Af%=gEQJ|~F1gNJ^T33`DWn2vQI^=82HvHoZso#gGT zVRVxhHp>6~X`dsePRkX?9^^mV3VGxTCvvXbZq_fzQJ0F2yP zD6CJ*)z+o<1w*&R+C|&N6TL-c7dfkxnh>+SGktXFOVQ0q3(k%08QC@Ft#f(N0q%F_ z=Ika|)JKzUd$$FjDq{^=T(;#-qERGyizm3;F-Ak(F>0e>mSk+YxLKJcY#TW}=xN-L zkSWZ75L*|d zcstwDdRgj2b1&S=rH!G7iPIzRICGq0fJtx`5}MptsLoL+7PK0>7$UP3Ou&WSr`uIX z)OKGZ$C9j{h8_vWZ1h*!ZfPkKX#mZ57P8w4MVw`*<;ffmA5D7SFC0(C9>@W0+J;X@ zDs{AdHRw2vskoLVU4l(R%QTI89X*n?bS#?T#!W0XSdFut^gGbzrQfkT+m>V4{~|`u zWq>Z9IIeP!LFY~z33#iNQpb-}i*sZq%ZoYQ)v}~yx5O05#{QCS?ZqeYO^>0(me8Wn zlvcytz-O`=NxXsAO&&&^G}e^&XKd2awQk;oBAYs?UaorKEL!mn&xf$~EK_IvvF-GL zDR!3XaT?PXc>lFXAFe!tc&>cWingq-fopVRwhI zlG}4^;X|X<>50}#J6B zLW*lG>u!ar+H!&hetbz5W~h^%sk>(@;2bZ{9v}|YW$nD&|Kh%SuNtp8DQ$_Nma)=X z>(N4e7nxz(RCPh?PX|fzy9TFi-WBsGS1^0T0@k*->RY{xJ9Wn`i3d`|W9nSL9l?FQ zpIVn*KPYHDsZr3Q{pKK;hc(m5mhRs;lRn*1A!r5hP>&BTOEkbO?q>TwOS$c1Wz<_M zF>!B*d(7*<{Sr;YpQS%#aSLU39UDM(G7@s|W&=+<2cwC5Q#e>37rJ_asK;RYqDjln zmY`V!n&d_`&999kdi<2~Zq=Rf_7UxO^!6g>HahQ3uP8xJB&)Of_Pb~hUN!V`;&vDY z)BR1G$0;Au$20ApwkNe`;=+@j3_;pC6hTH6YoyC79k%8W&t^&Y^_3@zE-I!3M_5|u z@lBFfubnKPQ0sn-YZxb6mvhkqh#zjz%x_O|N(yWjW3LoCExw;IsQr_U#6AH#{i%|UuF?By|{ zp)W7J3L3urxU*R^6^jIJLa8e_Kh3HB86FDpXKdaa5_r@-D|k4xkL|uTs0M*_PafAh zmUHy{wX>%e{vw3@1AJ{3&|M~cN4G*i0QnE8L;AR1xu}3~xae%B;Eb_zbWquI+0F6R zSv?(LAqnJD!Y5B0J0~Ep5Fq0PW=jEU78sHKybTJD0!aGdYr}3^R=UyQ@oZ4Ry-hcM z`9<@{rueQMJ8o^cx%`f5V*Jg-rCT&L&#yIFf6?QZ=IYCq*fT>URz(CKG+-$_6M!NmmxB!d5Ue{%I3J47MC z&iA8X>>8xAP}=u5C|9K+dWbagMC9y*NLhN43}A)EwNPA5QjtF}okhv>{ZtSzHU#<* zINx`>ZC0C@J3MyrXI!kiV@DktT_wtdbii0m0TE3sTP9F{M6vJH6)&idM=GvW#`6l| zX!jDn=wH{ouHNbfHLct?Lc4E(6!(pwnckq40EcFhdl5AlVJZ5R*xl3WBKykCIV@hn zTF?%=tAHG<5JcBZQF;Jgx^ah=+YB!d-mq(0aXk#ovCX)|MyBPo7k-}NQ7W>VIzfJ~ zDW>?Nb8&qe@L-KGl|g(;5H)7|qvyS+D(bZEx-0ex?9Ho>U-;>kQWW$GWMQ8NPE^W- zZa8qsD2QpmwWH}@SC9RsXx%s1HWWC1_OPRGPP`~Q^`~Y|^;f@ry|#Q$8a7(F&5JrP z3-FviHwcx{ev%dOl)&J_;GRQ>z7%bo9yeav8v@!@`+l`9Hlk`Pl>_wQ=-Z3x*wAEw z&fet?MMoi-AMbVEK%0Mxv%T_XLUbtbLAO{1jJ)fV8uHcg9rTQ|#H;we6Ej@_sGo-~ zAYC$mcE=iwG?;xl-S2hVpQV?Mc?d`zs4-uFFhqD&=OoXV>=SZnUJ=sB|0-VB5=_ zwvkDob0zO!G7r=pK7dH<)6A563gV{O1BVceO@q9V_kJ#4davbU&NCgLHvu!w0_iTv z4ZU{{)UNlAL7H4Lnd{^&6!#C!&J4}INmb{j=fcdS5Jb3*fdzs3j93&hi`*Ax23u-R zgv9~##0~_Bv&j@fiaSwMvLjZ;md~JTcd-v;jqmfeMX8B&lkF#l#XaALl4sgAOAGtVx-7-oKhx~dbCC0A`) zF-aR3DX6Y-$qWaPAND{c85r$!3H2^Gzvn@yIb=qkuiM~1C135L#Tu1;XM^SiuCls8U_Tw4J${29Ic1F<7__xgSRYQSn^ zje2B_-`A6=FRZ07(B0L&d1ZS#cw~xh5m896`*?c^_~fSd%`x349+4 z3df3pA=~>xb5F#_15l9hAthbdM;1k+a>)eFz5@OWlq#W#DRF?AgN;$MA!|*5J1Jvq zAQ3j9ADv^?1%R)~xxnTHO{NBAU?(xtn6UPqmWcF$@gH`sj#M{_GgQ=#+rdRnX8a)g zkqMUEg21-sCC7LHg;tXEC=Bx>HW(9&HyZ{GvkO~iK-`*0W){S9vj(u}P|mEfRM6Cj zyliTV=a=v0W628P(LvB772&$1L_a%gC*?=eF$y9+`;0piV*?{jTedqn=jjcO~ zRR|-#K+)l=dh_VVXbJR9Hpx}y_S;^v(tUUb`k5lC?CYAArubAz zVTMg}w*&LD`qSL%cCt^_0TT^&*;#W>w>pD6d7(7*9VB|LQa@DGF8R_++KtwoeXr%7z;nx(;uPT z=v@69FuazH_ST8Oz_5w5A58+y_XR)Y^&AN&l|IUo7%N(Mfq6Ke?_P7e?UJtNZgd8w zdS83fJ;bZ>!`;)9k)t&MWgI7o8Z3mfFj$b`d&l ziGgu4P$qJDY_FrsX07`ev5OhD&Y*%t*LBr%t)`Ij@_Nr4E_o|)9 zJ?0i=in6&Z6-U0SmNO!;9(49jo;FFdsZ{R3ejzzees)wpus@}oS9L)q$LZnfUd!ul zbz0N+^113$pDLzKb0u!Gcg-kwM6dVHMuw+s`V&*%oEJn^SDw(#ryG zuH#xR$4FL*gtC>Kyw&nKG8*xDy;l_2*B>-tFs|m8_Kv~dvlqT{ zk;#-8^qno#tmwMEJEPc9X1GP!&B6P#dTxFxvZG0RTdME`L%z8}?@ec9&{X&P02IzG zJjhBMFI7cP)#Yt=8GvDFv61$)&^!sR7*{?BGS$dZT1K}7I-&j253mJR=(!Iq5U_fC z>8-kyyElmM7>%Mh!&OrI_=Tu<5nat3#&6Y93sJhpJ^^<*!wgQ`#9KM-nxVoU3`^XE4uBi;S0__6s`vii8>nP{_XQVkX>Ta!SHbv5*Ze`@t{Uo3SqMCF#;z za&o?5AqR_Yv}iFfiE)?7NPa6DJ;~T@r}GGNW_s1H?MqNs-0H-|f^xpp9;ugbtn)y9 zai&mg&U}g3%RG#Vh91&!^2J7Wp;Jkli!m$ABCp4++Xv>&kl-H=*;AMX?@df>G38P; z{U7yV>PBsDh6*_6dP5>nk2H+x_@SrN5ur*6+_c90y0dLt-qXeLs^V=DnkQ1r#^MzQ->L@}R=359rc*00sAi6GO8Lre7PZ#G zY5F$>*dq>_VBW)tDmK~c`b`b%vGxSN9^hCD9NEWgxE20v@CG9$UrIAyWdgcy>>DxL z2XFRE2Ca?U-?y{eqxy)C%@$O&J%u&i0WVs|p0mEWHdD&EU?_%>p1#iUA>o0OACPn_ z(O>;c!e)LEsg07v#*w@*ORARQ&nsZ zpN;g=X$o#$naN2bDes;>ta0IhozB_9ypuc4EA+Y|(v=Jd&FMeZjmD0bIyO!%!G3th&w zoM8U&0zEvJi5WQVcD)@fUs#M8bwzovsYtPRd@}Z?yvqwD&W(v^{`np1Gb4=y(0Agx zRk>+NCfus&(XkPv70b5FhJ&`k_2^!#Df`y4B>xb5QevIEqq+B*xC4`_cZqc%N9@`- zmDbVQZARLhsyXB(EaZ=8aBxklet)ldzBiiGpXuRmyQPv_IO%cWw^0|c#aB+X-l7p2 zi|o&f`=9C`TP!o`r6W7=$T79&9aW%27iZB4k;{fmP0G*>>;=@X>+JLHE1gju0->O3 zo!{1V7BsA|Nu48g;`X3hVkd8A+ z$HaZYs>-VbN^O!>q8LtgH+Z4KY0cvu9A#9pIUsd9SZ+B*kB6t4G%bCX(y$%9g}pDA z82@6=-ll$1QwEiMGqMEld+z~G_+3(la)1B(`-BHMeupB|C;RRXb@)X8nnE)h-`qZ~ zr?iLmwkKe{xW@UsA^#3Y@?D!{`Q@ZRiYa4XqvlxA#w9N z?gsR2nTz4?+DBbWs*^qwwwK&=x!A#^__alMO$gecF?Srle?7zNJid~DncBrEoYdl&wb=LG z`BHu*ZF&poivzQy@{ATqf=1c3llX{pDTdRgb ztA>)8&Yff}*Sw~;6c@GW_S!XhDX;V_BZ+OkWw#nf>mxog?HzPq;#aLwXm+Z(L%_CY zP|=0PshIn?R?B1?twX}NsaykF|F&lOj$f;5b90k&uv=+lyTksnHc3b6-dX(m{&Jmk zx^{)Ifs2275y#@)V(Yr+x7mz^>7{uu1}!rK(RNd(?&66Swon%eQ##Z|TF(A;e@V|( z!v1z#lNiY7X<8n)+yv~YIC#P;IHOHch%hPx2xYl!b@6N6&KJmOZauTl| zVJz82_Zu4-O4g+GE(mr=rT7R69A|eakKC?2^ibM)16n7Gs>e1%Ery5Ly;>U`agN#W=UmozW;fcxaNItNd#1mzpmj(uoe=9fTFlv+-iWK--NJ0_UpwyGnCi_pw-=Wr zJ?|kKYt)ILCefp8|Gq=1MNhJ9<=|Vj)a5$ER*sQ3Iu!E~df;ujKCJ%ak=uhjYpaq6 z71P-rSHnA~q@>QBJP9(hL`_5%ZN$bc;?V?REGl}w^eZvIfKR9mW}hQ&Mu{p&`Pdd`gVNugh0@`9aF z?2&q8sM?J6?2EJG%MQX9Uq%k$b$$Q)gn`2L5&om}AxDN!RCir%KktsMXJ4Ug$4Pkf z{2Y&|S1-8!acyHIfrLVvt$Rq_ZmBWVEakp;w^cEGD{N!y_wGf-77BghL88;a3sGWvvEg7%EnOgsgG7sLy;i=wIEOoEqA%g+ZYK`^z)ym!mdrGuJ+uUTL3TJL>rgCT> z-6-kCS*h4#s@t0IHIk=WQ+WLEJExnD`p>kKHinE(a-a7ePL(*|?V(oEbd}(e6PZM? zTdlC*NpU1k)2?&@1oK@=!m0#P{cfiE$QF-m)5=J8WmevvHL0UXfpL*M<9#vi;<0CL z>5|oFvW0O2TD~Zjyv;XtE?QJz@lUhwGA={mm&oT!iQS>b*`4NGBo7pdqM9PE)=-!v zgHq7Z&-l@Fm?V9?APGIfFHSElGJGK}KFK8psa+8Y8VI~girq=TM)BKrl4RxcoC~Pw z+-v8X&LH}1(n>@su9}+9S#T`dbc&QzKeFIVI>)iYhisUMNo_2@^GtQp-gJ3WX3jW& z>SihyIdVd^18w5yKFHa;%lgNCB)SxQn zISn~6pJ>hwg0wSPko?rUVD;)y)cxts8ysg{9 z(QPWzEfn9e!;k5@rF#?c6)(AYg(9O}J89{EysuQc_SC)CLrRNbu`9^KnrRP$e zB+;KQ*k7o)h0$4!aje3wWp_L&V>^7{?`y)PcrnZeeNr3EuCK39a6vWl_^)_vCzwC- zWdl?%rExy!#tKBG>aZLRK+JCMr*>2(jGwb)>!2d9j!I{Nc@1T~? zx+}dShvDyu1wFLs4k|0ezO(br7au{do?`gO)Ho{Fly;R_sgG9LAA3LU1zM+e2SpA;2_B!(HrHT053nS!F2XQ4d4O7N>|G;|v z2R)6#eXe1(*dq4YIyYurGtOM}BC{6zC@Y=fovZy}&z2O8cXa0xZ9=TfeS93FsU~Oh z`ACwKaURtYfi}V*VLe;vZ&Q)iOwKPjZ8Q1hi3zh6`xT?put&AI-(|RsjF0doVI^g` zhDWgy6>XOu628Y?(D}i+S%hEjQ0L7wplDC~ckpehdlLxzU3AnjO!I(%z?LN&c}jO0 zcfP~k_!Jw&D|)+~$o1=Rw!F(N^1%sjuoNjdpQyB$H(}w48LzSF7~vP0h~Vs)Z`D8N zRc&f_=Lf%!xQn%*>y0MqjjIjt7`eS<>*uvD*=;)hD>z!K{8zF}CC*SdV()s-+{T-s z!|y3slYeEBv9EPen3gM7g1%=O2i)xnyOhmLqDz_DWI_&{3{7B z{-lnAPFxN24}Ti)a~-FWDM}Zl(~nfY|_Z+X^Z#Y&x>0Y*j~#OsW07=cxVSf!bjkf3^G*ZL_W)|@7)?srX(ay zdft;+QrQJVBC?TE98z4aAy3K+b>NLeO6wh^m6H71cWj2L{#QZv_<*flVLuK9Po&FnuCno-codSR44q+$wLkIJa-}=u-N|e58R6ihu)-@* z*W5eq(`{#*c1d`}zx;ozXa;WyMil;^mfrsRC}t6e)JN{?#gct&WgtVD&Xwh6x;19B z+!q8_se;UK2IFyM*RRq7Rm)vAF5Wz}VbPgQi0JY`=&^nSpOrGP@_3i~Zk^?gA^ecP z1o;dUwuYg9bb2RJk68{~hIlg!i5BJGcD`3EI2GEX)scx{oj>Y=0?nM0AHM-;L%bcp z`Vjb2Ypo~C{yYl+RF+Rwy81L!=WE7V2DI`N}X$42~Dr4AqJ! zzaJkk-ff4wH`Faf0L)4#R!K%2>Uo+AC9jajrZ$HVa*Kre<;H_6jp_Lr?GQfcA1Q@b2 z?Wq&!F0UlwIcRTe3~1UXsV+i;7#FR7YzX|?8<1vG+_jw+Z+W){^xiH#RYIFQRdKf| z0^-sWeuQ%HNHRc?-VV^VD1ykJx38V~5jXoX!_)o;s7Y_M8A}v5wiV0IbM5s7N^R1G zb0{Kj^BWL5Tiax2AHEkDga~xJ4;VX738n)00*i}=$HFUpwXa7ce2=D=Za+NaS4VB> zgyBAc#s`r;V$)d)HHAHkD}IC@|IlL#GenbmGR<-^ejq4naS)W$GDQ~Ke1GudF0P<{ zF*1mT7Pb(EbLU9lKH+JZHpY0fdS@L;fpf)5eK4oV!JDa4J`!#)%IPbiW#|WVi6-^z zmZW~qP9Y!#L+ILEs*fKqtORbf4t~`$h94g4mgY77)u{H>dO$cHj-r%0yr{|>6^b_{ z4;6xzU4*Ld(cf<%A7t)~go(vavCDkp2V4l_Sw#6bQ~wN5Mu!bNWF}rM$rw5`4HhV^ zR6zrNrmd6`Mdda^ExlMS=4@F7^k9ws`jTVF+cEwO9QwWchrpiveZTFtZ2?xw+-;b| z#Qyl~7z)F?I7vOo(Z?D5OEtb zsLAahtxO3(3NKyA{D?kXgzcMC?z5r4mNmm4vc-q=x&!y={b76hBD-F(BMNLUZ`AMw zzAkVLBiqk}R~8)y+kL>7@)C`FIt29*xC+#99#wjBS$3l4lKNi&r>TngrDf5>&rrlL z$E)><1WjB&7G71mJNR2o`E4h@k-k5JnxS1P3il=p_a?^Yj5Zp#!s2euxLlQ4q=SI$ zh%3vu;AYxYI2)PF+&PFf#_D-2$^8{@?9}I1P8o|L{45il#P+Ek74(T1x6~lUlKAH{ z%g*0p`*&h7v5!qG(ld10&UWvWMqaZOkS~p|x=u@Z@ekdFA>l1{AZ+b=D+}R77*8?5 zEe>=bv=oUi+ikWEdK3NI-jCD6#c-0>@4OW>TX#jmE7O#ha6ZceX%|y^p<5dK!1{6X zfa67(Q;hX(d*asy?SHU*hhSeAN0bB9Q{%RL;+BXIiLjBIi>0)xZx@Q8`ML-b2UW^; zP{^E-sX*tjcg30*8KzeGtXWRB{?L}wj8wMGsm&Fn#({H2k1FA5d zMp!V|qbBgw`*KrfrP>^?6#}Bm;7`TiPtSKy3$M9}ul+#@;;WQxfHP%!@J8<=9Ux41 z-hx-YI^h3~!-P2aI|#+`c_!yYAe#TZbPv9UNag4I&v-^KeJW`aN4;zkU0*@x=$1hf7>Gii#SF z$|2vV$6_b5J>CgVB5rW6dwXeaXQ*Uox?yT4NEU<{o0xAyINzNQRGMerF}}3Wpma0~L`%*4#D>S^y%T!&0%bVLf>>MwU?_kX!0U-#RoR5P!o* z_q()+z^O+~FUlpykdJo8bWDLOsZC_#}lDuRW1j`LYe^rwfcr=`I zvb|gI$gMBYjXu}a?>}-oCNTWf`eAAH!r(RSN+0|W3+ynkc-SgA2KogiRNr&Os|8;@ z{QXS6KTmwjS@#OMz790fb75Dy0eS((52x|aMB`#6`}m)aXC>iPvZ)pNEjC6R?7F!( zXlBYKzXHZK8niWeB}=XrIQ(DtwDrkie7I86Qe;S2ZB9=%^o*#Mc$`w%BH;V|=PfMz z{f>5IpWGun3FE%r!2B#PY!OUJ&16RB{PRtJ{Sq&O^r(R3T2o8sJ*}0?kjTUf+x^Fb zu&PG6T`#d?8NDznow|Kj+f9MrK9p>K z8Ih`cNLV#k`sH6Af@=a2S&S0!bg|KlrGMNdeWY+_D)??$di2^Uc6JB%-*Hvah_|M?Uez#P)nU9$1=5npJ! zu$g|#SfV~GDD3|HOZZZO*i!TZmM`NGHGW~=eYCF7%uf@6r{!}62Cx}xkp6m4|8RKc zc;U%6Av%Ugn6AQNsLk$gcnK4mQHq!eU% z&8>oxj_I6G<#YYozX<4qiF+T$d~~iC9D7gNzGxQK5n|5H_0=WwJqJcSqQxtMOukY= z_A#8N{U4TYRZUHKzF6u=q!s$yu*}?g1lyg4Zl&cQcw!B6@6UPDurcf*)3O2MPT2P8 z!&N)yw;KrHC6GCvm*D{6pG%OK&kso)PG2mi>T9UELTWST9PY@ImqM2oA@uIVfN6!q zT&opuQ$t`w-swtixkMBD>N)>q;z35a6XY)FEyjizT~8uR`TDXK!zjEAN`$82GjJ1< zCf44xffM+TkuWslGE71m~ci8RhfGnRLC|V{CogBX2V|-`^l2Hl*Sq|Ejs(i2hFT+rStWc#P5KCGkvIr5sVr8*-KJof+^q(a@j`M_h|fNTZ#CtyTOj%ryT3{N#KC3LxU z97lvobS@Onzeb9!H`NBZ)I<-!WU8X#gI27@Na&=J&jOw@Z76}cnhS(q>{n&f{&JA( z2%nmjmHBbP7kXxYX7-@Z6Ov74WVn3)m-R6X>GPnflJ)Kf{`s44r)<5`mSRHQS zmkWjhS!0E%YVt_WogL7AS0c*eDN5S&pBKpSFLEabGQ)hzM+u#X0d42|Bbz2@$hi8} z`L`Qd9~lHeo`y#49rJq}%l7Y4mw}N!z`l&+mXr->hDw{4;Vq}o`Mlzncu)=dh;#?4 zmP9*J5Kve)tMJRIH4Q7~-|lPyGRUB|KCUTXeuggBjeumx|LeJ!KA%$0JX_N~QKb@U zA8{xp8VfB4Fi*VkGFYAQK4|m3&*t7m}AZZd0I?3I2@ z(QtmdK_Z}G*fCULiq1|@7d!;AM`_Ws01Kg}SQRsw$5iy^KLD)Ix?G5}!rt8x4}%u( zyNZ2SMFe{&|JRSwp-=lV^bQ#ZQIz|5Ll6?SN-$2$Z!VOS0Dz@rgQ^!#Lq2Kl%b>NL*1yH# zUL_WM@bFgCYA}0z7!uv$N&XU;SNOgzOUZn`N8nr!GFPUfoAmz&<>)tgwGdfE^dmCgie&73GhE8R<{kf}0uv1BP*5TJUpT2sC}(0JtsV2B1tXDDs(vkAv!A zYQkfm(r&3vpuj8zDJ1&|IJQ_jH^(Og$&j|4j&gFE*9(LF0UawBG-L^FDyR#AFwXn# z)GT04D`5TVL03|@Wuht{Y6&*kR6u*vRJP5(n()v>yAsjItsVRX3cWUjJwc%D7#XdB z;7bs?hDXys$VMJsgH)b|!`%b4+)w=rx&TR-I8ykS^Kl3#>iLzAJCjmuU~g8VNfiTB zuU(@tR4#CGO>HW;bUA)2<1|LmUs!i4$H@b40k1$9Ex-KK~ zFk>kO6JN!SJbb*4ceUx@&on%(L20Fc(Br0}Dg?}agv2JYvy?k;vjN<+R#-ERP?qeF zG!>4M-maK3&!PoHD-iU|!Vozl*&v@7oP$QerHY_HP=A_pUC6`&T3uEfG&IvVFr3s8 z5)fJKE{cyHh=0EVr3;BV;bPArz@sxd zOes~&h%{S3!DT7Puo~K;{zMpU5YJeu+T!!*$~>D6g5%wKG0#pue4`Bt2cz`4<%MgyfO&gq<+ycR5lpnt=I}C>NLFc^)-#F84@VAi$~mx6Z%+ zO+vvdGfqpAIM4HhG$;^80)|n5BGrkEs%%%>^DhqylzDGJ03UG%0EJU9HCDSBl2@G? z%Dj6a^4$ba^VNbm()P+aXw zB=R2q9oPgJ8|u|U~K&dGnsl9AVT><=jV=T&}RkYO~0lr@Z<#lHV`=H&mFDc%MO1ZeW?Tl&krn=~hbEx+m085E828lZE z8wjatk$f^FWVyJ@iKIVn^za)U&dP9}eP zZyj6J(<6M(QFs6Ea6hcrSzw?pLtI=X1XG=JP69H=eF)68(W_pw6B!g7s-pKtSmrqg zl!gVn-MK}!9#j9;t`S~S!+Nqu*2hmGCPwARf8IMnKSnSyWPYz5m~SUiiwsq?_|Ky) z@7uq)tTeE{Sjk(BpFF;Ee8$<;&8EU@!^=<9=GIcd?|;AZF_p4@T|1;506}w_VOOsN zA#^FXifODcI_nSb)H{b;i`P4>!1+yoL7pG)^pN4;G;+Ma{{2^;q~^W!Tlm%d;ob3{ z7&HVb4G8L>r^ao}1)_qHP9q(}1qY6L{OKu?=lcDsav$T&isHO_2Ssn>j_C^4Rq;H*;`T#8SRmI&i|S?B&QG zz94q4Fky4#uPd{!|76+pUv>c})V|>NAGYzA!}#A`9O6}=wxyz)nF*m=Usly0TMn|2 zpvPa(`sbT~n_3ZN`X6t8`isNXsNTQcKH_tX8RO8Ha~ZhwEL~Z)*Er~F%DF;|MJI^O zHN;5%Sui^^SHM{GhjspLP1kGxTm;C?&Y8gf{b?c>j0j{GuWCgqQviC1!C>vMVW9lT zA&P%Uf6Y?Q-dbVM(_W5{ZYyEylh<{B^j}u}bOqYPs*4Q>8+q7vmTTJyO!D*1z?`lGEqGfXa~Ps2tyk`Zs{9%9{#@Hy{>X8*5mWNC zp8o9-iK+C7{+XZ7`k77SKnj&mVEJ3J@zeB0IC)=b ziczJ}RV(dc|8i1)1H%w|Yk$Ak+Wtf4+}$Eq8Syu}`iYFKzh15>*PbOfbscJyKb>K{ zG;(_Q6njXWp4Za()IMUF z45-uT=;}Ucy*Zik!1uc5_O?LR)A5-Xb$9*t(^3-DkUM$+2Dth2=zn-J#KO)z+rKRf zR9EdFC|nNd@P=nSwS>&h@Q444i0VOi`b^H9bRzWZ6y zZkN5!`G4R4JJ-4PzRtn>KJW9~&prO`-;H}JlyLK34+E-Q-(wp|^L-*w`3d{lFF%&c zW+!j%<e>4G*|>qm`ian98#2ev z`~Oj7z7^n=3x2G~-3J#%2>BLQ8dTNSBbV}?8V)KRpPp}UIf!sZ>#7`z1+G=E&I>0# z3N--B+V1dtDj{J?vB_&9xsRXaW$u4|G0XVc!?{Pyh<&jQ7cD{n?6LI@Fz26nQ+)Mw z`G%u^-h8qkJ^jJ=N|>YTz^H^fF&TJkp4RNZPi0M@o1%~ z6~yOC)cCvu5p1Ab05!>@>~dJLDP61xvvdVnjy3VvOA6ryQ&|^%k=q{^b@rl%a!F_L z?yzPK8m6!lT{e@s z01E;P$1D)#@UI_v_frmF%fcQ@s>vH1eK&CGuP;Zsi7IUS`~#BZ=)kjBg^jETF8=so z8`Yu(InEs2FwQ3e#z;1M&cSuZ-&7doE2`(ih?3I|HJ&;u=O?G2{uy~iKRrSt0~#Y| z2LQF9MP+G;&>%tBmPAH1kL!h-PCqInUz|dO(ZMi;aHyZ7X>g>Tb1G~}jcPA?oMqhq zVb5;63$I}b@YScx;?C-m8{`B_)JgbX`9BHF^Cdm&iO)gM>4O4uhuN zS5jxd(YRNZ^|_FNI+h!stLH`kVnQ4w!yt~qtn7tOSMV>IpC z&o(U{6K87JzPb+&nrbU}*B~b*Bq+{jOon}|dSO)1uG$eh#W^;gRRl*x{D_N#-ONhS z>UP2x9iXbVZ=nS^m(YH_VE+ZUwS`CjX*1x>=mp|;9KoXP5)J1SPus~!ye(ZC=ECOo zxQw6p=-A;@9{h7hBG0Nk4D|@93kqqP3^b5(#in^s_4r?&UkYN%y#t7?{y~#)fK+`m zeB0E2xH#Y3D7M$=Zy)ba3<$gA!$^6>{-HA8Te{R>JBn?Zn8p8;Sc)QB8&jTxss#Hl zERs5urXVql?CSq9q9+>Cn#b#c&0q<4C#omqUq!<7ro4`j&wwQR4mK;zMUk z*gvE{;)Srm)U%?z&bADrxFinf4TMk!9S(5GzPXIxr3{g}5%#T;0qyBlHBICFVU#7K z{$G6C#i=%9b+P$f0R}ePZ|mqR3NA>`(h|eb_Ah-9WI%3jkje=jJU9&)9cf6qNPTkO za0jY@{0K){msu=lev+c`uFbMPgc@3raz}|&Iazdee-vl?9A)tiIpU*7AN#)C*7mPK zktsGU$dPDHSlm$LB|3E@|MT0&a+y?v!XcZa@9k}TP_jTChoYM>N>^Ti!e?+J`e`i*a)7TOn{``6h`$4hYuMHADuW)jrRWSVA~SHM)qM&6_46{ zZ8I<)j2vqnRxEZA_#UL7`+mL@-Lh|a2$i--glV|~0r7j_SgHvr_WE$DJ}kMM4VV9e z?)=O31kXXnN&;i2C#hs}Up#9pEV``pQn+^n>Clq&{JNdy)fM+x&9|8o`wo2j92vvG zbIdjW!`=I~#YkW#%76F<$fZO8^BBzGvHN|4)R#!eR)YQ?{@;E_6(nZL1NrvC1QSU! z=v}%3W6xj2#>#^rx|cTxC0`qS`N8(ZUx5@l(KFt0WeUls9}ZuSv&;9j*}lE3?z443 z%+fC*)l>DO_5f=P2~moz2@y_#t@KgY+lR#r^8c-P{mTaV*dw8Z(M7&YUTpsVtaFF! zEA5~1?$vh`a~)1!Qp`x*4FvsQUfyOMgQULOPTu@4ohC%U({F zGT=XFxO-OsJO51(l7qxkv1xCff?u_~HGdPHerlCeE2&GnAw| z!spircu@)v8VcS3Eb>}J5+#HIYCM+OOK^kegtMDX{?k2I78K@C?6R_Yw6qv>FD1uN z%r)g8S;rErp}6AQIY@M;9AmG7gI{ZAp4QNOn*(~PwlSLYfV^FH2@z8h&L!p zz6UqFu0_>4zfx?VcaZ8BT&ZYt#CraVp8J1z;}XVB{LrPBk;D|_U)%qui#1+xc*^U7 zzV)aeFGtCDrwk6UQDD(yZsN|1NSJN=4V5tzztomEMM(}jMFd}8IBSY9iE$Yb*I%y@ z6Tbo27Y5X%WNX)jOx#Pu;aq&tzZi)Bc%JG`(#lhWHQ$2sV}~s?>b_@31_RpT4zv|e zH<}%0w<1-AjBNZo{w?q3Y@mctb1NB%A=jTow&g$F!I|!W*;DcVqFV<1+Np)$9lZB!VWks*ia6%qIjo$7xikoKw(Uy4%~_O1h2h#T>qx2l8rh33wllJu3fnq2B8tVV7s9=qze*dEVT>Qo@hZG~eXdI?tleX5N zM%2jT@$UN3lXn^FXRHgoR++7gHhB7@!OySj`Pi!o7Jlls}lMR_1RikhORb}S3VX)VT<-^)?o%SX3W zG=0G?RNd$nxDw;1Mh`N136NK=LTms4XvpEdbUoTMh?Z#o%2c7Cm)I5B?4eNGTrS~q+(4ROvpwir+-2G+hA#rEg?^H3 z&2A659aF9B@(D9)RA&0x=>WtN^$t$D)+5=)4E)O&7A2vCJ53J2aAd3aJp}q*c2vmB z#k;&LoWE4?O_gLG*3P+Lbf0c5vr4uQ2C~&F{bnPnS)%7w5!$GbhBv=E(Bg%1g+ud< z?b&Jmagd=iB`LNQ1Q(-#Tj+|UFZD$8QVCO9`m2MMvET{8Dz8l?Fdg;8xbOPzyNGdU z>X4-_>A4+}4S1rdL)|VBV3)lPWT4QLAW}W#+(*q5$QVdnLy_7HP2A2w@O#k4yq*|5 zrN26?$_gnS9gl*f9qC~<4-7EoM_)mrC3%H(-tNe$(NAe7JA$;l#Kx}4c>h~BKz z)i)E{C@H&ScE8tCk=0Xnq?V!=-l^wrjs>JM9%i$C@=&}H6+AeCO21I5Jhv!i_rISr2e|M)PGn5ZmnSOsdZ zeF<>WJ6rR5WgD)#bpSAkrSS|>#ce_29n0?9l6z51)m1Ezb1d47>0z9JsnC0#H!Yzt-5Z@%~ORirGA8&Q7DNH&9u_g$ox zoU=#&-T6Q!s3Z0=dr6nnUqS>%6Tb%jy#99QDoS~%sPC$|g__k|6Ol33sNt^i`?(+d zsQ>E^rKW_)chE<=L(2@n!Yn^K_k=|YN11=BFIKGiySrAL3%d2mf3csffpwAD=(eMf zYEjDIQ&xh$uP1H6>htJ0+7@7r|Q>-w|;@E@?-Gv zCNLmTZa>(RbY(~y{i97m-<>k>n5wv!%n@~gIyr*9UH`wn;CoNx)7A&XSIVr?vig4u zY_^SoT0Ch2nFBmS{{E=fqaQ)isRdWDSUmIeUE*B__)f8&! zfbLSQ~)of#|V#H2-v!3U5ifxl|=|O0951_(Qxm*EIzrJIpF}&UbzR6bT;vK3j7OTm;j*`L#5A9a46qHe7zRtTwX;e zsMnBOi+V1X;1$m*k@ZZJ!Eb$+FU&3=cF1$3*ggF%Q3@s9tGm#^M|Xok7J zXt=+HPYn7xi3cWL#~h0Q?u$z=FS}PVAUb$kt;0K^{jLAn7eK{JndHwk&M1fv37Y6+ z!i4v`zKT+g^|?MSgZhgs8;&*lK9Xus?Lr&ea7sJZ;d5#31jCF~NrI3%2i#j^e0HZw zhD(f^rE6Xl>O)fe25LXGL*TbA=>F_tf>19S55T)FyGm+S#TOG_(OuLnsi3dHyq@SfIs<6B zyRx3lsu5Pbar-`RdEBUIV0~b;c8g=5NA6@oM5xD8qpZ?ya+CASF|WNA$;NwnCVWrm z^cZh+tk0SB$Q>8lIXVO1J|?(n^sH$pK(e4y-SGSZyYtiv4%sL3ZeM@D^_1ycWVG_S z$XlYfMB|jJ1Xi3{ce&DtMwahN;i0$(;VV{Jh41X%apZEL%#mBSHVLeXUl`H)>KvNV z*Ag~_qof4Q=jx`q4w)%R3JFLGC{753K_|U{NT!U-V5bhNW~t_v87`!^HN0eWxCHs&`oC?|0b=zk<8)blYxTotP58*YfVeA^2yeWzHuH zq-GO4fdfH zauKWHSGb>1-_mCp^Lx5XlR=}6JQcttc{!{ZLk;J0M2PWH8IdswQk4JPgTVWMr}Eku`p!?pXYto z?N9gBiER(Q$1LBB#z{ZLgW zZO&Ufi*q|lH`6c9?Vy!$U*rg&Ik@_%}bpw>yhn%ScOO2NYbiH>4o22uk%}C-_ z^fmPg)W1fZeOneihO-W?OASueS;|Mh3!WGy4-JpCZqEOu5)NZ4{nK3T_tmu z43P5*n7t4->-NXZ6?Rio;GpuPHXPT&X8HBiytpq;`Xk4(s~nnSjF~Yu7s*Y~KWu7P z8LAO;UfUf!8VLyLO9C0#!~$VhZ%~+B>s#|RFJx9$akp# zeXV1lb8;FB_QcL;YYw<7<%vl+lVBlJLw}%Au!d4>AWYG~pAE^O#b5;sU=n*QmW&tf z$OrZ(v^(4AZLZcsEAX}aucPt;E;BaPU<#U=zaz%)Tu~~tVRplZ3IYGgL&@$u7|yM#cDajw9D3fWD(lA3FzyP-+Zw7zb5^f- zcHEhc(`W~1#L0ym+BwJ+ycGQi4Eu@v3o!vY>0>3{Y+45S-0v{Zl^e5N$mH2}{;Llv zyxuuZOPdktW`MO|&}XF=s|cPhPcO?)`kf`L{$}zEnbQZ1i&VL92WLjbZz)08Ji=^G zRfGi;O+-na*QA)nyjX8M0<~Kc^X+^A8k`L0!a|!}<#D0;5f`z$Mms~V3M5KzR zTGwsPcD6uGdo1Bn9BerK+{-wgI^7$e@6Ji%WFla^J%!W*?QuB%h4>fV=_Sbnr_1%~ zQ}My3+$1Z5lRiljw$Q%a-A$mI0h41y)^>P*m*6;aY`56f-{GF^8aP<}L=IXnaFnyI zu+9)@0egi4a_>&=YQ@=A+?S-C=Z0=wnCdqOR(13g= zmVHyU3_G9Row)^Q-7l-~y_UpGCw8;{1^_?}J@)$_*?Zc%yuy>aT2@-dZn&+*yn&hN zomlbgv0<*_##q(5|fFsz9JeE=%p zrHwYhuHuoJiUAa&?CxHa&5gg-xB%^9Slszg00&a=01hZ=Bb7tHnTZdNPYxXsKWOSX z4-yj|!U3a>*?=q>qEV7Ee?yJeb<+U>kJQGHOoOEy)^y#4UCLhUM2s z`172ngb|8$*ezS8NmbAvPN{9-33R61M(XH&$V>-{pJPRc~1j>jpE8w2Bi6H z@6)nr#8Y6Ukp(&b(X|o*^hu@@myn{}R-vFj^3?Fh<62UN>F9{)W zdx>p-s&-%jNOj15CD2$A_ioNI%D1pDxsZ5O^CWjh{|lmTp=EYyO*0Bng>lj}9^6C9#Ay$(w_e-ZIrQ09(1UF00GF6ZH6X&hQ&-4N#pJh7_Ezv?e znwbat_)VebBRec^i%_4~8*Rh&GAu>j$9#GpZh3dO^-Y}0#o^kZHrvTbPzveMWyyWX zBVsj%HbFu~RzX5EH1j9jz0cKreor({^(NK(TMo4*EO49){8PBX!!EBL7nEfQU24Hn zE;E79TSm^{O8PS#*vEFrCF+564) z_a2(g{Xr<*YB|CgQ8~if z)mDgT=Zx>jj@2}Nh0av7V6XN`@J#PjQ6S7YxBL9N^HPtyfW+r`=#7s@Y2x=KtQ`ju zr0R7rP2Faou>yJ;>IKc)nlsHQt>Z)FCg^V$HH18|`I+nE^5%jUatcQI!ToHQVq~iS z{;1#^J?K#$YsWzjnv&rv83q~n^C5&T0n9}O&^54+mG1Qk1hSF3P;h6_o(WZih={=O zpZIB*D&NL?>-nqWEAP(J%A6Pr^Sv>(n#TCCFHK}lA>9lRXjsfcD_En$*J=RMS3sAT z886|(<|*9eBNu3X_ZSKNK$508b361mnxg%@)!Zmg;4$|By zv{x9Vu+u~zQ=q-snakKKwp+W*pQi#!B6U=b@Er>zllZ-WhO+!F7OR+5beqIzhID-B!@6wDc0Jo(Z+=sL} zfJsqEw~Ln9*$4q6?-sL+igPbcc@1iih59C;Mr{tZU~RVJGKb38i`2aa;Lj@H>iC9; z7`$T?w@A&Kd}pdb1U8de;9V&av}kWjhPs&{kO`XmhQeQzARIJu*J2^qGX%Aw1&xIc&hBDXi_E+85S{9^W|kE#PiA0&K3WW%B5FV~Q3j!!(+w`}XP$m2=QieWNZ- z|1`4SAF~p5BBWf(`{E*oE4`O{PzRKt&m)%=fc{ov;O-jFObi&Mdg!nMG&hMdBkB6} z3)k4{b=xkp#~oP9eCUXe)J#03VGg2lyOCv|h&XZ1jkM=g?D0ILN3yB+s6g_MEOAj z$+r5bTkW{{IHtmq=E7Uh6j3})t$Hpn1h2Udm;)_Cp6xSs$5H-7qHLeVE@~AmIf*HW zE!i$+6YsLlUJqpHRwj4qhodyR3{z>a&gS^{|e#e(^f84k>5g(m1Pm&hDmIv1P8dP1r7l08QnKlozKrI9ug> z<@C7t;#5#&m^gXhxvA$2&{zhN6t#+1GwcYQU4XK$0C)1sTN=>%Uja739F1nw`VjDN znX4*g*8I{WuA1*>{qM+GUG|GQ+CfJ|x`Fv8-7xT*x!5E*%>R*-aCvZ z+pHBi_?KIejpJmCQ3c>}4S>5=pM&BGxvDn9V@PoSu5i^N0|b5%F?yRfpa~ECXk$*h znuWxD`TZaK4- z*%cNcldCKu=4OWFfmeFiq1Ce+l0Vj(_m?vQ?I7pWa33jzOp^vK^+;3G8HkPhGZ{84 zqe5N!VgiIARv_ku=|&D%fTkD=S>>^e4B(<}K<0@+zUYqT=!NX}zqF^ocv(jSwL6PK zR(c4_)C&QqdyuqS{xmp1=5{avFwWNDSL4sv3*D9e8YT%b(0lIvc6XVNZ;!vYw=Tz0U%bz5ejzwm#KL?PXl&Q%k6T3qe_!sgKz&?=$c_xh zdu!~H2nQ&Q9-V-FVX%gTMKDZrtVD!n=GQhZw--Pm;EjSradKsy3%~1Ehq^px`#9Nc z%l$4iU&K2?uLq^YE_~P**nX=IK@C8`^T;o*C8!qXsbTCYh8@>jLCv=1LVBhGUN8!Y zjbI#x)IGf6SI-k1Aplef43V=%+$8hf|mmvhXf%?tfi6N2k>E=Ui8#)Y6YTMnoM9WPntibU|~ z-_wAw@I3e<=eml$hB|ujvCFDes9~MXfEsDw;exNVa4+6LF-06Wt-|?WxB<>_rZ0}t zy{rp1U^Zlt`}tlTCH6e)SiAE`3mKa8E)DaW?*7qR_ELftGH!#w?UUKM5O%yaC=RXbSF&G{T!Oq(Q zF89YViC4kJ1l`#Dh+Vq99Tt#Rf$m7S%cO?D`APNj>1De?UlO6*M%<>aa? znCa&p12XxoW^7mW^thz@#9xdks6?ytAEuir^w?4X%y{}1NEabFo!n>1CT8=JM7YnJ z1P63v`dj>w9_X8CYOWHx@(eFmEw`h+J$R3yNL`rONtbrQiD-Y*i(ZGi_hDD4TzsB# zljdoi{h5yaE^%C{VNAUr_j$qtumAACDB8TIp7fDYSKpIPx|^qq!pZ}dR_-avxmK3$ z0(<%=Oq7gB%MQ@8W#6>ylcLaPccWEJFC8uAbTu$R4*M$OL_~NpL2#%1!Srrh>&Z`HIuja99W&c$e_uw?M{jOtk6KL)xPeV~-IquHBa{=e^SnjJEJlYgR@b z==zITXLaV)^fd2Bzr|Wt`8XO>RC0=}PMp*D4AdaRjCV?Dw0X4+AQ``bWPmdg0*BlY z7S;^xH&>AAgn7@W1i;g_Mwy@2&XA2US2m4snM@-&=0Z5zO|kC~f)ZANF&Uo{Bx)T? z7F7GESIW5n#cVgw+~HXpGw1VxeLEP+a<#cYE2r9;2e}oXal!LJ{MiG zt)~!tb<+AXc&gp9JT~A*x6VSXDy2;#Wela>3?coW%{q>V-2|?@z5_W{`xQPj5??>P z8M0PBzsV73I)+Z=!%SjoDtIWnqdgaLtB#V4GvMf*hkITD39ImsDfnmbDKC~FFh;Kd z{YQp zntO)2DKTv8&_v=MRoT%^r*}N@^hBhd_&*-SKWHq@0WPBksqo2M)mN!|ra@^`WO>rt zWGO!pGpUbnJ5`jXU(z}WPF+e^sw>fM$Ykx8_>H`$sxZ(LQSIOmQ;vMa+}XOj&0e6rollRZ&+Yfydy1Aw2DHY1>>h$>&@ds!Kb@7lr!_daa|-ls zWkuclWEjXC90Y?0%)@8Yt|XN_JPEnor#(~CkRonAuI=2{9U|$Bcaa>v5ujr+?{7JG z^f~+Q<83d3dtse;X_^lf#`f9IJcVTvDbN9Fw$Q}vB-sOIy3|-hH4W3|$Ifp1au;04o;ZhkhyZ;#aE>AXdiFMCUtQNTbr;LErhcmOs$|FqlA(J(^ z@)P)t>OpQ0(YESdKl>bWX?#F2O+-Q0a6Ns^I7Fg`<{(|Tzap}C7r%>_T{d{ZSwmts zLV>KBJf-D~H&OrewGa4?@uaxZ9D>SM;_(oGUgOo#$`%?yS)GN`cT*M44Nb=R!f-5` zKvR`Sl5>LzH>n%g?z`w*5Z5(IamUxT$Gov*T0jPJ0r(QwNLgA%xXFVXhs;xjo#rev zvow9;QaYz)(~7STX}~QN546aiF7}vF#;&yqU2$PM4UP2gawm_e423;jSm|-C%V>W3 z^|-!=U6MUn_O3Xc(;Ntesr_R;U)SwPUYT@6*Soc82a#cRR zqi4NWZcNV<#qC&9oN^Qh!tJV5u^-i*C-NO!s8*+pc%L3-WQyWapzt)e&ZKNnJe?_@ z%Q~WP@!}4qUa?8>2sheg7L-alWNK z%TJqCP&FyXCum{sEru1KN~<8w!8hnwY}V-@0Gg&GZI#?f6&yFMBl` zTUYKm?!NQhpY%30{-e83-1{)!bXc*K5(SCK6v7Y(G!!vKUF%v z0A;n7DJ>3J?z{BPSxrH2vi56aO9NeO+g!iy7^39Jjdv)bAGho(ZkcZF4|^uO(_~-_ zyg1{kU567jGSe;?g*7!=u&vrr(-1ozI6OQlM$poB54QjlKY8B=%2OgDsp_dZ?LY-? zx#2`7?Oe0IPX*@mh3upd6ZsO`UI)gxsA!SP)se?0)%S+w92+&lyNNug zytc?ckp-VmoU~taN^-1RfG`brCpIi@=0Mc(OC`ZQTYF(Zi1MqRlVuk;V#=h+Bz*P2 zU_VX}6jw91zi**Xav>ctf16m@WgAj+v^?#;=Ua~V&h&HTP88K=ZP`2XxNjv>&1!je z7W-PhBQZa_blOd9&U{2OyJ?2d+Lvk< z*A98OF(>Ua96oh&6`9V?uF{(@RazyM*^o;%&s263GY;jw5-T4m`;e)36vm8@clM<4 z)SwDB<+U5|wzhOplEk@PPI5f(H1URnAcu%_tBVdR>sS?kDm(4?iMw`|hzA&(@NPIzKCd^6mOI8sSSwR%`T>Ns@{G6 za60~Fd7OU6#P*9T635~TYdm^0LkPS~v6Q!2ruc_*U-#gNv>27b{!xoo9*p#^_?zu; zMJpiv*(vN5QLku(pbrsy`qHYwUL8!gHMO`@X`)X}TGxf*QE(s#Y`Q zQIr(H@-&%4Mb{_|pKnUwmTIL)o_FUJ3zeBmJcDvP)GWK(%?lCJtmjzIp6`e`E3>?h z&82R`d$V`cc0DJ!%7^KQ-m*1Dj8s26{BZJ9v;M$Ld8^RriJ@H}3|pgQKg%`J1b*vPKFEYsZl zR53&8-@v1X@YL4qj(7G!^`BjDv&`yL%RwT{#&?r;1BI z`VT?Gs8VDHcz=_`8$@$m(RV*ZEYXJ;nPgl_U)yt9y5k1kPxRGsi1aZo5U<|E?GJ=0 zT)qGJ+_Tz|8(4*tKl~age2-C3Ek|ydEuiT?!JIFzLvMo__zGT}l~D))75oPxSIY4G z5G287(@gB9exnlvw}33QZfh|FbdKQ@S!PS4)f~&54)qUWROn{ztl2UcP3tn)oJLp> zLWFjPpZ;5Fu#uK)8VsYWIpX{rZ|M%&Oelg8vAo=PZZyNVn-y3C10Jx5TL$uU5x zh!E_bd!xY1E@;5Qr3^Mx)qQ7QYgW=UINy{OgT2eFRPfn7UTS=gN+%JgV+a7?&)4VQ~dFas?aaeYmx5#nT2P;~X5$j)#0f=Q%- zG9D0nN@RnwBmR0kD*6}SGncLB^W*HGn*sbsZ)Kty^V;!yDqZ#owEK9gv$ULTjD;w? z!j@3njc5D8NB8>Xqd&GAX`DrEz#(8xnt)%j*rvDo6(X=SgeqM(;PLpN*pXpOA!bqI zz|tpsDZGOXk*F|}fnXSrW(sLg*QGq#E>Mg$Jp5h)T)f$BQ0@>~xoX`JsE%lwxzB^K z35Gz8f(q^UDyWB)g_nv&=rPVhOce~SXxkyeho`ZSUYN`Whpn`-PBaUlYBCBp%Lk%a zuPB3+){bO*>r1tg3N#q0*J@#g$_OFQI&{}3P-uLgMd6T&+n2eEeM zk@B~F|MjXgTv`l!*T~X2p>hYfmRM>K0nTHyBeFpnFig$tdD1j1HuFi?0+jPVcB&r5 zL4V<7Z8_kjk_mu`pn76tfH4~o?6}U(P7ax_ZQAR7^z|bap?7Ba)7|($b@EqQ4Bbom zFDPbWegLz&V!Tw{leo{zM$u{wsa#I1Lh*Hb98VVz(%cgT`&$8-a*KIrIBnI_y*mK0 z=2bGdNN;uk)dzk9#SI{$&2j<3%$Sd7eF%V5Xw9F{&Rn4^OBa`G2r ztf)(Ljvt`5oGDHF2nrLZ1+yC}>-(jwoXA1{))L15sdjwbG55(BaLB*+P3rlpJ4_- z<$P&m-a3>@6dyrhR@qTEdFQqbUf8IWENspGhh!AYtS5X2SF>+yx^y_aI?xFnQm#pLN}mzSz&m z)O$E@T*+@5N|i}rBRYL@TCJ)or}5C4t5rzg*g=8}1@?x`Tf;e;YKRoHzI3ySm}~pd zN^)u5-@tCpF7Af7oz2KW0!FR)i|z;s)iZJFjP$nNYMqJaQCg&{r{N@9l~SkSdmLVk zRh#OdVNaR%sHiDC57BDI0z#hInPxwv07|W-vW|DwL;$E9zgF+SrZjdLCpoxYOlIfJ z)FMsVe1W=bXuNa-0R1*_O_Mr2?LtPN6f?X4kdJr6Y9n}0dV70OqRCfYRT?nwfk2XM4%wxfqXtA@{Kx@V>@P@TS-$JRWFBQXh63qK(jf zd0Gd+WaLyk#Q-e6rPzF7o5^F7eAkQ5SiOPH(Lwhb?@6;*Y#>rq=c&Gct9 zbq0q?qs5RiNIoIbeMe{d%Y%i=@X9NHaqUbkx06{>lfPY;l@`t^t5HRY#(}dM18OVF z;-1tQr>+wLML*>Sg_xPl)7myFLoRXHoKu~rI^Cd*YwYCRQ2K%gBeasO>oG+Gh=*5P zmQ-C%iLRJXX#`288^f`EVegyULB+4+fQ%9#t~i+qdh*KaG~;WHA>Jmzvg$+Nqq9O zR-->_LW3i*PNP@0Os;AOrSP>1Y^}1-*qm~<4{({w*{B}bQ@2VjOci6)>2pnSbqAdo zDW|Di-W|8$zQUzQfy4bxKK6Z)>+V|c1x_!a`c1s1f*!aPZ`%efZ9Mt)u5 z4k+fh_=jvo2pg;HB<^aa)UwAP>-3XcT;1mZ!U$kXjjFM}u@p+xgp=($68C~5;|mJ8 zA$yX)RC?G2I_ERAqHH?==I9%;02iXwaXKJgdH0SmRcXyrtvUU!%&K1oqHU&)oFPdQ zhN1Yyf@X3qvU-|>@G`)v>PeyK!%&;70QG9lIa{7Wt0(^`Fve@gd-+XUi)H{al^w8G znROz_El7yzF<0x0vSj0?DZK!Vx~v@Ab@=`*n0N94a&>ZDHq(4rJ}OY38_2@@4?Mk+ zh*e1*aImr8YR{IPVh3t2pXZUSl{mI20QF8!PMgS&i}r--&mtn>!SG@+dFS&sw~k6m zqk({m=B}Buxww&Vw^*mSjh~td<{O4PQJu5ZAc37bNs`l9P0y6+)hB6MHKrf3A94kIWoOn(aM1Hs2JUy4DJ<>=zUw zWs9d!wNq9eWW zT2fZ~-lfpVrc)a0VgcTnSCcae3#TFbWmdpd3m%2s?3+if5IY^t|DxxI$FUU1GyP%e zj>8-T=%FfU;1)B{drQq~p$5Z1n|DtZu=`sXQClx9X#f zgwxMg0OBE#b?$adFK>DhgyC>tSH>fW6Y1BB!W35eC zxGu-7I^${Ei_RGJPq5pRXH1PW5ox6ow^99(FbKW2O#oqi7pY5#C_yTSW zul0D%=@1kH==3N8gfeRqGUSAc+s}T!nHMj<56@$f8R`{3=^nn~XR|&I1rTynC;ZcX zg!aPP8HPSm^oUB#GBu~n%dcq1z}sK#QhPOWN3VGF$kTjfzlXGxtJXgz@ztzrp;yN= z`>P8Ox7&$ehN8*}3sqX9M;_&iqo=F9Jy?C-4k|lWzE^gHIE+0zK*JffyG&uUu0mT( zgL$p}>5k`T+nsnBdk>KQR)`Dtg@mimt(4nP85B~4^5Tl+U?FOeieX|6$cr=t2y8b@ z3`*o*7MF)=z##|D2L}Rtsx>*Sm?hSJq@9qU7$Ido_UCfNV{!Xovr0e~+1s@&SL@9N zz$J2m!!W|j)v2jiN{HOsS`2P4Q(u?TEByV(Y_~ORqWbbB-w{A`)g)+ToBzW)T}Xgq zJ0HM{IR_x83MlKD!dHF}e(MPNQYtE+%-y03^*M82mS2m`hpV?9x^y`%8kOqnk~IVn zpeC48IX3VFgJ@xV|4fg>kr09X{-Af8G74WFYHiRQ4xLaxy+ zDLWP_4i%5s#2c|{d$D}%5)Rjg7pBL0LcH0;gP{z4I8{{wD~q7_!%MZwZ|F%xdme)7 zV9-PU_FUkRR|*K$6=n~;3ON;?GZ2TI2mbK#FQ2=T%Gr-xzS#na?xb>0WfLlLR{Y?} zIsl8mgEH;5zp~0JWcCBHaNz3o)?33YFr6naRVBl)B7My)K<-odb&K-x$xYGqv@X5X z&nGS05ESJ1T3qhaF2HPIy;t5m+Z`j*#5)9VGHas{XgqG6J*%oqC-y6*3yPBnmkRR+ zn!>R6zyZz3c9U1& zwlLof4Xtmpn$)J6bet;`02q**_aWH4WXMW)-7)|LO5Cr&uTALku9h{eO}(oPI?CfH>{((@^U@2bqGl zW$>u-s*&u__Fz}5Hi~9-PZh+z@D_WQ4BSM9P!6Owi zwNT_61K2ewqwJK%2F4R)#t52c`~P-5l_Gt1O17Fo6x$7smfZ-~S_8=oIkKX3VizWV z+M9Ngy+vK3DtBG3qjens0U?Zv;8N~==M;I}(~90Ea&ReYN5yIf(7H6gywafXoO{6i zHP1WFYWMV>9}(MdE3DKTSKifnrX0D_pz22iSuS%g_%sg*kZ&0TivFup! zWbBn``4LqP5Z)P(nsT@;h6o#m@WtYPgW~@4;;JO41R-0C2Ss6TH3mcidOc8{*Ky=| zqw)`{VnoPnK8Ssvij!eN(A!KbxiO3_G=1m6wy02O8F2m)83*X=ru~TeQpg@J$&hC| z&^SE!=d*wO3h2={n}M7RfY<#(M6A2dAz(!YAac61)+xi$nO{_J*U8y&>A*pOpWdh3idEX^;{&WY6 zuD!Rq928mpBaAOJ8vshwlZa$|aktFf;1++^k4M^0KMsvC^@C8=Bmi`Pq>YaXKwnJ# z?dSCdop>H0hEL@`EdmA@`5A+f%j*VPr)wSu0X})>eOJ(A#ERR>=q%1CsW9{2R|@bT zEGkYqBl7K8S9x7K| z2h7PzT{Klx@u#brn;*rjy7iO*Z3$U_!l@1qZq;#kE>1?1t-4VQpt$%^v}fEA$q#;6 z<}2%hf*S$ukym-4OMwSM2b2P7#bZr@wZhq1%U5A@6AmNpEDj|y+3`3r)C zRjglstI7Q}W_$7g(}^j*{+ZAHzOzneU9jfl3tjyovu(#+!au&o+}jxt*A#m7>(o|> zsku*I+G)-lwg#BJ$t!txo#DkbByis|ClkHp-?==x=a3w{vkJ>o{a$Bm3W0NEP1 z=MuuGX*2-aL2Jh^D^=QAhLzVA8`gg|<6y4US!>DurmJiDr!w}!jM_Bgny9;?ebK(< zs7zpkU@-4)I&u)v63Mc#L*tC@#ocP>^ z=d;xLcFrGJG9J0F>T*3G@MXGO8`@ViQSm=uk_swD9VbIB&&R|r3rFZ@xR5$8s$JyYj(Uu#Z}+DgOv^%GrwyG)U+y^(i!1+)j%@kaSEL>_NfJA}Hd zQR@+Q=Z@5scg4T>iESie1XFnzj-~P5qy=~gfmmSk$tB#{P zl2BEL)oP;36*`{9eW2NScDJO!X+Hj$%oFM<393md!QcS$Cr`C zysZOHB$O4R)xWal{_Mz{iM|@Us%!DoPqsC&j1gTd3kvqT1^8O&DzfF{RoZ&g`p0b0 zrG*bhk_dP2sTKR)n4#5WJ++FpH>nH6w9-W~CSMp` zT&CRE&APhBs9V2^rN{Nu4Obobe&uNCsWkoY`|9wOqYmaICB1VGrw(v}SfeF2T85Gi zoz>xmAAWJ5!^(dbNGN^}r*D{axlVR^UricqU}Jp@CJoJxRI{5 z5*wK%P6bKoKq9%2=L3HK@Pf6p52tj9kYqR+kL#k>Q7#{VFXAkm?2)o7AA9f-pHg-- z8^g&LYu*uZiF%tC_u(Fk`pZLSwRz#F9(}tt?1^h{#cUpgjZ+tv_Yr3V95 zE`vEeo60J-?(g;nIVdDlCDr%z{`GqvTBXG9AnFLUKnEOWQfnuObzvCxox%x$p zJ12ZiTjxKos|2eRV2N%*Ayw~wS5}Qi+Mv8?4go+wy6cg^xn;T!Q}HO$*80!^1xiC` zweEg=f+3CLc?h(bk?WlxeMxooVS?T@XtrXr29$P)EVD*oF2Iz`>n>SR@6GxnmT(Xr zN#0;f;7E`_ROrE*&+f&+RqYBty#uauF=6Pe$EHQijdlwe2(1W9OHj%$AHyM|Rv3WT zSR0WY0qkyX)O1FxeD#K%p|fr$H}vp3bpswOg+Dbg z$Ne>%O6RJ;qvqt~Le-ML_Q8-3P9$hYG%qA{=N6|46w&l_1~< zoctW0IF5C<9NQf%HT_|W_=Ov=TLi~4b^%=PGxh-mv@)~_yKyfiEenm6c$E}_p|w9G z|EvM&EYlX8a^*5Efk(F$f-qb9Es(g>)6EVrB-c$cHUB7H9g;5CD3;3_vV>k z3CcgHMP@_YJbc?QlseOW73yOhFMi&6UMRtbmO>$pLx>j)NZMvyD~j%|7rKsP*%E&I zo3=`$|EeF|?~(BA=*K-3P46Y;9(O%RGEV#e#3O}F5&e63ml6~x>XZ-uk$Q#YjNl)= z7Fa6PN+HwP&3pZJE-{C6HW+DBsa9NIZHJDuH+)NN~iOjcrS$M=MQVFdmZ}3fNpEdySz;D*KHZ7Fv%S5&? zVu_*Br93(7v&7W$xnF=+?$O4rsrg;N*YJNypdwoyCf<|_IUDe3tYAb1?HCl0b23a3 zMx=pk8Y*U+=m^Q%3V=+sk#a2qUPa6KmP5t(LT!wW)chBHXSo8DSw@Tw!;}W4g&2ub z1ZUK@35bKi%1MPXD?rju5YNHfNi5>zu(vzpQdvI_wcYC@i5Gv5V6xJt>?-lgo_S|+ z+K^*oq4V1wa#i+;5X?8tiNs4LoEdM1h_|6Wo6Af z-Ff==kiM{BCxOB+1U3tPc%Ze;fV3A>_HpqKb;_2yxj1-y06^A=Fq{g{_);{p_)&t? z5%r~!5+|UN-_lbD-EQP5@Y#%@pi$PQZ#U9T$%PJI^FSD@sE(Qtx8{x@8!+$Yp_V&$Z^R>P*cCzaVIpbg==ijjP`)F zC1g2U7tqw|49K05OFX1b#3c5O@xzE@u7v_<8JJ8H0U$yKr0mH|mjmeI;pVruBhrY$ z+0?0vWf|a@BTeXqX@N>`fGCWGt$<09o$abA&??d@6#&24j*umjV<{t7##`C|H&70V z@9ujV3v(lG6$mT~T@m5VRnSpx3iuRht*?yATO<7Tm0I2{wfq>?b-W6WRDM!p#mz%e zGF4krXu@Hdsomp-T`6+eijos5b?FB3)<6PExFS?be}9#16I2H+#AQZ6Q5&N63e+Y= z0Ha|&H4re6^$B4JeXWs;R83_23KSbPYEXBm!ucsq%21pryee5&6T9$(1J zcHoZWjNfpY95h}q*>C!x^vV9YTd96e;F7lZ4Indua{vbVSVNdzYA1UY^-&;X0jpt$ za>@fA79lS6+-rAxq4F2e*HKU~cPRa` zs=d%Fs)XF!RnILvtSQ$J+)@In283Bp7abTCq%_+?0kNYZ^-$LwYf=HUyZFQDc@dzr z(spFlwdlN)Zswz?1*YiBZ0?ihbXSrN?Y`U$nKK;v&l3v%oihj zYUp1oCT4Y+}we=acty-Pd*9Y#E&ACq*0*88O7J*|K^z71ApqbZTr4P~J+3z0}{p zas)U2s@LW!l{rA-EA;qe>dW&|LH*u4t`}e{eyM$8;9>hqFoWZfE<=dcn+TC#ck35d zbV14JegITMPu_Em%T_Qya1YRwtSdiOJ#K5LwQlawdhZV(ibkoW##r~UCmKj%+FexY*(?IxIpnT4W1@ZCVo zrAzUT=rlq6RDcx-S|XEOK(zKI26s5*7dYxYGEJ!>18v)^)ma!8oMQfa%l1UlcU=7- z*XXN(?r^w|zy%PyzuG%EJD3XTHe!I{2V9q+QJ#XS@c!%=qD@xjDUbQBfm~7*n;H8R z$rOv~W*}YZ-;&5%NskHO8xVqVJ!fcKwQwH*JisQ-LNxjPlcm_uDmrgKQLMeFWXzbb zKuI2?quR1bIU5h3JEhK2#~HRlN8xI(b`{8XXXCWUG<%73&$3-J6-LU}F2Qxux4Iph zg8-x+J0RqF_0IF60v&akR%gsxq0H?^$g;f?xpyy>PEXGm3CM3u)!E8y;ag*3-dqPF z23zK`+X*hBV?7zM0a`~FfCIiF%btZ2V=a);bG=kTU7XOgi>Jhz{x+Ab5UW7vn0g{& zt8?eP;7BeaR6c@jjz*i{Sf$HhHPPr;z#+R|Y4` z_WSkC9X2Z?WSle1B4p~lEWS$dEjM03UlCkJ@B049qLxP`I#spO zbD3Tp8-3l}W&ml!Cxtey( zB2hl|n7o>#u7k>Ix$4lOH)GbwTMnih>!4?G;NAp4W#A|fnqB23*U4q2(;;s7eK5ps zxyEg|2HF2#M|KP!tzGsNqk8+FHS#K8FV&swyTB63;82)iDxxS9vmk#E7jccv1)Und zfeLdbhIsg4%%aOk7>K$!U6?phwT3E0lOsfbaIFgzzF%`+E51X!7pKOiCZfte02~!8 zPseQ?PY(3YElS3XY-HbwCKlAU-%^EhrU6M=MP&MKKwG>1Qq}<&c~-JjP4x@dq73^- z97l0K;NC3kTPfa$L_99-J*18DtcDfSs~~Y_2TUMJeSUS$tULisa>yOMv!>iJgmy50 zh9#7izM#;~1K%N)oc7D7=H3h?z0ZqUqsUx}A=d|;uVPQ!-%0Qt2l#>fV)`>}`Q#lX zJ!5CD62mXEl7-7J*`i`gCGs7Zn^{-NGe|AtB232+_Xi*7`BX^fnK&I#4&l~IJaDMD zdYJ-#)APBhKBQZ+lxHGNVkY)f==GbP99tCf;oR7Jin&lIgHTL&lp;+AdZafQ+|xZ)?JxQXGAS{Lnn z+i`xI@UB$2(%xE@O8dYoc3t=J?p#fr>%hX04)MigVNpv;w)31xCncj$P2`_IeHES%9f91>O~@={jkqiw1evbz>B{~g!!H(AQ# zpZ?N63ip3`gThB~Rg7|-g&o7Cej-tiRGgmQ+LS0D?f9kj?4Wia6&^DH5{P|1bc<^> z%A{{Z?rF|7f;fB%wFClSr$pTopEc1$|JYE~0n*J_kX*fC_LJ|CfkVz&8b=)~QRNe5 zX3S6v%35>Q$lJ#Sqgb!>8D8lhuhzW!BaR*QN2itQb}IPng2$odh9*_Z*n9;|TFTE5 z4*+U=D+Ilun1{K?O`?vsf8{grE@w<~~?(#mV}MzRot`pP@N zrO{t#QzDm-3ktjhA*ol)Ddd3XNs=zqMheU#qh1A%aOOee4DkWY`j6{wnqZfs9n71N z3f(j`OwBtj&hC9Q7^PFgH+LI&%)%*6GOWf@O}i2Em1{cIB%=f&H}ui5Kb?v{2{aS7oEBb)-Vn0Qc9{=e{OsyHc;{e2JJoPM%wVfDpAtYg8EJP zyPBh1_|gZTS%9E`GY~?MGa7QAdW|j~$tjz`m-p*>y~9X)5FM2$H*s8l4KQFVnD48o zlX>D~v-q5i_s>>)H)6g4(zM;@#T=T)=DuT;#RA1eOy>nRz$IC!sFN@y5?I@DI3DyC zOwd~>g{&bN+t(g*I$+#zm<$^sdkfaHsbm{2)65u3+8}v&YF;R~W`*R7)iogH&ab@y zC#!AN@q2)-TD^G?wXXYpPy}44bmCro>AaaVSM%r<4Vor8*exKpB4JQtduCD?q${~< zuI3ZP^$QigzFBWptR+{W_YD4zChA`TTi{r7GNg%~TqhW>%u01$ETfFu-!r^)*%WGa zNC)OFIhei<=4f~OL3KN0NMh{j65)b3x|PYfhzpLU3bk$C;8?W^bZE}z2r(epS_Nf0 z?aeXpS^v?AT@GmTgGO+m_5)vOztz(^4+PPOSyRMMOlFYb4)P>-XsdN4*6szs!e4Hx#0Xrb%QLbZ4O$uz zmPZQYQVCR)_2rI+?kl9z9kMhI4#A=1;2l7%P5CNjT+=fQ` z_a!f-6R}_z=jf#oD}@8vYw4S7?f~yIClKA>hWIRyhei2XMkv%=+aLp4ZKDsIGWF}g z1v>3vK+|@-0Cj%9ro>c$ip*vm zVU)7i6pO((7ReMz{@K;H+y2$+y4AKe5N7FGMJeW1q5~w+ec;eZEBcj4USDGICH+4y zMF!mb=O`HjL~)aj2-@|5D*i4&I^uMB%@83(?obJ>2Y6%Ue;MbtwO?cSM-%<`CVl@K9=Lu|fO0}_2H?>x zYqT63ut1=_l=CBKs{tDCei9{iV=(TtO@D*3ozI~Yz2_-NDFC0G+f4;Y#8 z0lu$i(Plfjk+sLcFH^{X7Kq=39YNfl2;=|^t{1@S?FE!Kh8*j(bWBMhRAdhv7go2h zU)Mn>&n;!ZjtB#y{>h@J5g_~$v;%$zpCLd3Je?rq0{|Uwp<{Cb@CtDUcUA$Z=S^Je zWr#R#Qz?A{(9Hx;R<^t7t6T-L4p=S5gJPdUVt`b;3Ucy%khF5k2Q7yUdczhO$o`PD zAE-JwQO#9k&H$7F#sgoifuRSKFL5snhv*y730u$9un8RKdx2T61gcrf@B$gv91kL8 z@nTZ6Q9`g#qb;OMVTZ(nRNM>`sP~+3cmc7*pp4+5OArBV9}qLV1a`a$iTll3a+w@5 z5T0{sy9*p+Re+EOcWb=I3QUNN9&WTz!M|>pR|@Il3KbwGi6y+I6jb9?+wdw3HUu?l z&88|Wu|BH4$uf{|hOhE;(wG>!Enq?9#zf!qbt9LR1F(8mddqa00~I^kd^TLrFJ<*4;|rNSITpwT(RR07bM06<}$ zuaHVT0^0?ee*pUVMWt)!J)#z=n^-1!_T&{(q|s7L3OA*QqgTm%(Rg;c?$wdLO#L_>rABLzQkwR`n~%f|GDr7@SKjj_3@5U0JZ`MXD|^7yz^&{g;k6=WWx zp<#e$MSqHO75rqEu8#@$d7?p@dpE<4WUQLys>v#9vw^^Sec&sJ-zI*9n~#rgDKHV= zI>$2pUY})rf-t^-rPPIMe)AoX?NWIIxT=tb_t!T9Qs@SM{Z-BtlC{fg!9Ozi@1@B9`sU?p%(_4B zDvhI#aeFA>&u@aMZuxQk`FYZ#X#f5Q@_Dcn+5?$&rShGR-7k0(l<$Owxs(xQcq^na zr+udcgh@d1@4fs5^n0Bb6(5~nkQhCgxD~)`Zvj4c@!QoGXcc}R8#-LgenR?VQ!Lh|%Zzf+#p{d_Rjt8T8!Qe~ zKU;iH?>_vq)U12yO+b*3)nOpt{5saAST2 zaB%zLO%}FSDwke|zu`yh$A(i+t|9%a6YZQc=S|!}ZcO zT3v3Ji@HTkc;%)bfM!pLA1!WxhZ2vVJ=6n0O>ZVy<7WVDASz0!+4^DNg@; zxEQkQ_XLQD8a#o`KGk$;ty#&pk(Q_WH&1TxZ#5WMUFzh0f0xoBBbp6TbI6eb^J2an zGVESNrv-QCs*V8&HsIhMvoL~L`sjxd@4iB2d){@62o&gVr%?8?U^Q|SurJb9iFiZ@ zeCM0aK5#7)u88ys2o+IZQ~Qxy)%Pr#5_#{8^Re2CNw9n@4Tk1d%#fu7P2ia5mGcWu za~%|X!Srxjg;FaQeILffrh#%(7N#2eI_rAp!ILhHSthvAKrImB9wAJ@@~~%W4wgw* zc^U_qVn?Vnpe+EQ?8Gic6LxDKn=-@Mwiruym4Qqd^46JM6q z;CrVM3OuGWNVmOhrlaETGw9%;TFSP?@)+hve#lPu0n6@jMVXow1|LN@@%Pa_3;U__ zHxAy*%x@4t2jdKQs1K?Cu3zl4=Eh`ksu6 z%bM_5S=X`vvi5cjE&z(>aFZ7TbS8dH-~f9frvx0(&-cEHFHx2-CUnp&`td(mkm9q$t>P(z)~?pPXVVd^2jlLb|v1iyF2q`ix*W|G2cNM4yVaXIgy=BvCvJ7C1olYqnI9RZL&#C}!g?Nh5mL&clScQAy z@KaR2KYTl$!bLGidO$QtXBu_#ZttnF$$AH)a~=oZ(^x6BA2)Pdz;rlWuU?=i>UTO* zpKWb~vB#`7oKM7hjFnRzmIl^G~8%10dDBFmmIU zGcrc(PVuqi)>?4*d5dG~>6I%Fnbo~i`jI2EHxiqJeIo`PP#C^b<8#6pb&H?9+hD`c0y@m_oSAh^?p z1Q}o+VIE%h!K!QiM}I8YNhH4t6WaCB^w6Alpx{!HgDsuA zv9vo-sL1p0NRslup>?=Xr6H{GGjLXe)qsjvt3ik1jgFroe|W>A7CYpX(iS|!m?zLG9{d1-Zj6&hbQsrs)-Fi0Rbc zO4Am7sUKmY~P%!DDKO)X?$dZg6J4!C8 z!Bb8Aq5NZ-Dqyaja~|x8T@M`%SUB(T z6l+T#_(GR?gWI2{KLknD<99g&t8K_Uy2Ky&{U->CTSJqqBILR35t-!4!1X)qSY&^$9b( zmkB!wPp5eO&zI;gy83P)(NMmNLw+$a#fMKzhjHv&HkZpAQ$b=^w>5^c9KZRf76oQzL0g$z)CAmh<=BWw2%8wq&*l&fl5sY=wYiH>Hc$l8)O~a_54P4 zaAh&XHDZRWFNCK+;Zylx>*K#hPRDaBF4`6fzh2Sm!s;%K>GU^3)dymy_Kmx>t?qBs zgQzf#i0WZe2!SuSh&BoZ?$5BA?> zhR^R^JVu>@N|gJJL;GcV#jhulCsLSurrkK*g=&K!Qb zmQngzPY}lZZH9kTW{mpOc6@UHlR&T$C!Gq>((v1^$=rkElKYnM%(V{2-rss(MW zG)K4)fpic7rf1_*A;U4BtT?Am_`HrZ*b+sUCA~-AmOYUehTGbLZUBy1isj z0t`+MaLQvVjq(@k`gkY=szSxdy4mD(66$Ru4sH*pLP0 zF`*M7!MDjCwe>O&1%R!b>i?RWf9dubeFl*)GRfHkt_DJH|qFIc|PxT zhz%8W|DZjH#g?dD7_!dW`K)42Vo(+t@~XoL=GkD@;Yc#>*ud3ocWU^oF^DMW9-eW! zb)Y$KG3-un$Y_AhW~>;ws|b#?@K+3UyPTQ_A5Z&BTkLwG^x*+H*Z@Ka!F7`J`gxwU zXclp&c}aMpN6RW#^H)f8!hc;n>34i*oQC6jh6zlwDk_jU<293O&cH7L+f0g9i<6|`22ZigREh44Sldm2S9#w8>dSSw*zwMlbdZN`p@kbjE! z=Q1@aJkBRRKiN4&%<3>fpa6Va>9>Q9=Skkz%JD)E*+a)5l4nO?I=HmM%MGpVP(3N+70Xn zPq_e$DnZ|sX`iZLIRK#te=bL15!d7#9?~Dk66qV)dlT@SvOfnAKeDA<_ISZSR{l|g zTHeMBumrE!OY0-N&G6ZfTT4OpC zoOCS~@U-itc{^a}4_jegmW^s?A!;)=3ajhzkZ$X6csu{O?|b@-kv{XWofp@)v3k-B zXvn{Xdx}fPpZ1lmHAIRV6lDKuDR99HG{1_-z)0nv94s&%t!*%>x9!KmG~sy_bsXeo;0+Rn*j{V!j-rPA7Ml(z0wZ$^@Sg|u@aQW3`|~P zjO5yrcUC5|@Vk&6@PcP72?l7iIz2$6ZxXNl4R^mc`wMy|`TK`DcK>>lKmOJu@y~e*ckr8$dwOk?C6yMOl}As z4ERYC+5+Zv6Ef-#EFW}2Gxg?+sb1;e!&`oaXsomzSO5AT-pTDd4wpFm|GN~z{|8x$ z|NkTYH`6))=Nif|3aTl3{!`8O)eRN?sF~$s5IW9Kn1n4XS%dtoOSw7lb?`X_kgbKF zGyZqJ$rm3dpABOLE_tpxC}fS_n7)6ii{m6cVj$d7eJ0z%BukpNeo=-)EBIML2T>*sF0?oy5blMyw2 zaai3vsY09HrIfT;h>JZ;`9}+JAvaz`xzf5X^iw2Zoj}#|1TW6^PWSiT=mWkv94M*Q zeNn(`wVXhO81qEes&M7rtlN?ync$sykikLX;~XXcH_gk`12x%M3eaaj9;V~4-}F(M z!m2jp2Qny?iW{>k(O-B?^E4PMx*S5Y>bou*#q|T^1{e+sO>Y5w%rSBY*sByf&|1(` zaRHjXEvV(TXWU>S39{mJr&5zuUti`Ij={Fy2xRuvx_}BHf`Bhl2OJ>VZK+=HH?yh- zL&}A@H7FTm`wEhS%t7*yEKk!d60f`pWL{&@^PHetHB{AkScD zz*WW(VkQw9fs}Zr`0x0v9*39pIm~r-8Ob+^6Wzr?Yc`GWQ)E=o-W0Ztav~R2rL1$` zQhoDm<#4gz%XJV87Z%+B~Y_um=j9)2JOl;u;2Iad{v9 zq@(`3j+}C1pj?~<*J{1&UOq_xpvJ(?R0dudU-TONUIZm;h34Y#3_!F96HhVp3*g$Y zKQYF#PeR`?Z&=B?C}VDcD%V(@B`88a2PC$a%BWH<_peM5HZ>)c=%_d6AvpV>u+wN~ zGSEAC%~0=w^xrrHr22@asQJElydqR-FnVJ~a9A}YxL@RZzmw}8Jo!z8&Fl=wO_a}! zMnjeC5EzV~P`+u&Hh$4k#jlF8V|9Dh1skyI?*D%Bt_2R#Fu$)Z^%xu5o&X&H!qX(U z^{$F?e5(YIxgX**|NNYIc7_x2E?*&jN(YHGhx4v; z;7_{jS$>OutNgm_5L$DgeX!B*KEwoI$a&Qzv0x1M?dfqext`{3Ry6acAQa{P}F(bw?HuoZZ^tlc?z|;-fL_xWie^C^_R z@L3RUX~BElPGg_T5a!tCD3G8;@~obeV4>YFu?raW!-?>-IFhKfNqRwv(2eQ^&N7hf zuWtqp@=d!P2T&bKA3ZIs7+D33V+9OT!0_I;oY!?HF7I!;-YUT#0R&YpzJ{!Zhnapi z=G&=}@rntXP%^MMK8VtcVjP$rt>p|fv%gDRsk_ckFcA??Sm9yBux=>D_LIYN`!&H` zWP%XCZq82kcJ7yysUUHXR1B{v%*w?%oXXdirz_Mqn%tXSR|rUT9@FumcJ2ZEq+j9= z!SZT5SE;S%tJ?>aqj+b3HL`dXx+(97i3`*}mifey`to%&%&R!{`<9oC(J{o4frS;40u3l53I3J6yxOu{f@1s$*ehYzq z(>YY(swtnY%7fvupObx;{U_G4>ZcK{pjNS1#B z$N?kPe>kdTva+LnfB7loS#jfr^YU=d!F^~LSdje&G_KPQey&Pj#8gQff#*W8&|XFr z|5S^T%h9gK(25Sg5Cs#Nx9_m$0M|;#DHWA&D~c%J!%1kdKEEd-R`%31=E<20RflZw z9!_b?U60qN4}_#c&X@+#!>SloC+Q;FxZfzik{ZIlJW%IsUAq9K3TJSFcu_1HA5jE% z9hEIs#G~cCwlbW(ejt+%`m*ji4rr}k+h*Dpi?cF00} z2o?kWmQTd21fnhFEx2q)JB*IZ8sU7X7*~JdY za(1tao;!lLxxu#i+@-#j2ic|Y+?d?u~!>Xg-?cC@cF2AqZ-)HO#vHvO?YZH9L zxIClXRYzX$iK{*Lrm|gNTENgd*i_d*EM6)MiD~`gqb~ zP><*wbU1Z8wOQt#j)DE7Pk65@{{s8Txn^Ji)W6kyT)lsG?}tJE7*b$S>&s`)SLLj6 zi-wING_HNe7Izx?D@3fN61yA)x0P20L2fHpy3C)72~!+@s7w{-y!rRkPK<)PQO`cR z(xlMR7{f^M~?o8yy7SHt~t=ELWPO#~LjJ8cnxo*+HQzi3SBb z?|e(vH;sp7<5BW#b-{lgn>8)PX11L+YkwKvr z7Hy9PziX%pWg0-4e|nV{w?CLis-st#I@g&JBZGy@b+}0eUEt9i3wZSMbnY);>~K%` zR@pNN_UU5+>$E;^+|%Voj2@aBy6%K4!~-*mv_{!pAYH)HlXOEj7wXdJ42w^_P20Vz zrevnyA7!yeyWe|j!3rDFW4U0VKzn{dxR;P1uYyg`S>gght;31p;EBFgTshCdO_$HM z?f#@yZ`I|^H_apQWWOhis50-dZ^MwePzbNl@cncBibp#vrxv0J>c+ zw*k}EEy9X&jv-4wx`tmCYS&*Pixn#{W9|@gH_Gx~r4&GXwgn}%!iB^v_T7d*Vu?k! zE!6w)@H4tcbrkWB6@=n)K3{0}A6Dw?O%8fn(Vj(R{?&zzrp3p7k0;)!^{^(xgp<

Lw|0j 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

G+^bkHfPV`T3y0)Gh4|RDv(CC0e^lIgG49g7 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

)nTo@(X)9%)u*WUqQxRmM5m_hu%3; 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

w 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 z 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%0DaupiCp+0Lm#2 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

oNGgV|vlh75}B>Treo=rv$Ia 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 Date: Thu, 29 May 2025 12:36:48 +0100 Subject: [PATCH 458/755] update documentation page to link to new write-ups --- docs/writeups.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/writeups.rst b/docs/writeups.rst index ba7b3bb1c6..dc6a08ef71 100644 --- a/docs/writeups.rst +++ b/docs/writeups.rst @@ -46,7 +46,7 @@ Conditions of Early Childhood * **Diarrhoea**: Childhood diarrhoea caused by virus or bacteria resulting in dehydration, and the treatments associated. :download:`.docx <./write-ups/Diarrhoea.docx>` -* **Childhood Undernutrition**: Acute and chronic undernutrition and its effects of Wasting and Stunting. :download:`.docx <./write-ups/ChildhoodUndernutrition.docx>` +* **Childhood Undernutrition**: Acute and chronic undernutrition and its effects of Wasting :download:`.docx <./write-ups/Wasting.doc>` and Stunting :download:`.docx <./write-ups/Stunting.docx>`. Communicable Diseases From bb022d48bcf411541bd040a40d3c59fe5641783b Mon Sep 17 00:00:00 2001 From: Tim Hallett <39991060+tbhallett@users.noreply.github.com> Date: Thu, 29 May 2025 13:02:29 +0100 Subject: [PATCH 459/755] extend docstring in equipment --- src/tlo/methods/equipment.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tlo/methods/equipment.py b/src/tlo/methods/equipment.py index be32006813..ae56cd4173 100644 --- a/src/tlo/methods/equipment.py +++ b/src/tlo/methods/equipment.py @@ -27,7 +27,8 @@ class Equipment: running even if equipment is declared is not available. For this reason, the ``HSI_Event`` should declare equipment that is *essential* for the healthcare service in its ``__init__`` method. If the logic inside the ``apply`` method of the ``HSI_Event`` depends on the availability of equipment, then it can find the probability with which - item(s) will be available using :py:meth:`.HSI_Event.probability_all_equipment_available`. + item(s) will be available using :py:meth:`.HSI_Event.probability_all_equipment_available` + (or if all items are available with :py:meth:`.HSI_Event.is_all_declared_equipment_available`. The data on the availability of equipment data refers to the proportion of facilities in a district of a particular level (i.e., the ``Facility_ID``) that do have that piece of equipment. In the model, we do not know From f9c1ef58f089f78cd4d1481476bdb5db3ba04d0c Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 13 Jul 2025 00:44:32 +0100 Subject: [PATCH 460/755] equip: post-merge fix --- src/tlo/methods/equipment.py | 90 +++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/src/tlo/methods/equipment.py b/src/tlo/methods/equipment.py index ae56cd4173..2fa160722c 100644 --- a/src/tlo/methods/equipment.py +++ b/src/tlo/methods/equipment.py @@ -12,44 +12,45 @@ class Equipment: - """This is the equipment class. It maintains a current record of the availability of equipment in the - health system. It is expected that this is instantiated by the :py:class:`~.HealthSystem` module. - - The basic paradigm is that an :py:class:`~.HSI_Event` can declare equipment that is required for delivering the healthcare - service that the ``HSI_Event`` represents. The ``HSI_Event`` uses :py:meth:`HSI_event.add_equipment` to make these declarations, - with reference to the items of equipment that are defined in ``ResourceFile_EquipmentCatalogue.csv``. (These - declaration can be in the form of the descriptor or the equipment item code). These declarations can be used when - the ``HSI_Event`` is created but before it is run (in ``__init__``), or during execution of the ``HSI_Event`` (in :py:meth:`.HSI_Event.apply`). - - As the ``HSI_Event`` can declare equipment that is required before it is run, the HealthSystem *can* use this to - prevent an ``HSI_Event`` running if the equipment declared is not available. Note that for equipment that is declared - whilst the ``HSI_Event`` is running, there are no checks on availability, and the ``HSI_Event`` is allowed to continue - running even if equipment is declared is not available. For this reason, the ``HSI_Event`` should declare equipment - that is *essential* for the healthcare service in its ``__init__`` method. If the logic inside the ``apply`` method - of the ``HSI_Event`` depends on the availability of equipment, then it can find the probability with which - item(s) will be available using :py:meth:`.HSI_Event.probability_all_equipment_available` - (or if all items are available with :py:meth:`.HSI_Event.is_all_declared_equipment_available`. - - The data on the availability of equipment data refers to the proportion of facilities in a district of a - particular level (i.e., the ``Facility_ID``) that do have that piece of equipment. In the model, we do not know - which actual facility the person is attending (there are many actual facilities grouped together into one - ``Facility_ID`` in the model). Therefore, the determination of whether equipment is available is made - probabilistically for the ``HSI_Event`` (i.e., the probability that the actual facility being attended by the - person has the equipment is represented by the proportion of such facilities that do have that equipment). It is - assumed that the probabilities of each item being available are independent of one other (so that the - probability of all items being available is the product of the probabilities for each item). This probabilistic - determination of availability is only done _once_ for the ``HSI_Event``: i.e., if the equipment is determined to - not be available for the instance of the ``HSI_Event``, then it will remain not available if the same event is - re-scheduled / re-entered into the ``HealthSystem`` queue. This represents that if the facility that a particular - person attends for the ``HSI_Event`` does not have the equipment available, then it will still not be available on - another day. - - Where data on availability is not provided for an item, the probability of availability is inferred from the - average availability of other items in that facility ID. Likewise, the probability of an item being available - at a facility ID is inferred from the average availability of that item at other facilities. If an item code is - referred in ``add_equipment`` that is not recognised (not included in :py:attr:`catalogue`), a :py:exc:`UserWarning` is issued, but - that item is then silently ignored. If a facility ID is ever referred that is not recognised (not included in - :py:attr:`master_facilities_list`), an :py:exc:`AssertionError` is raised. + """ + This is the equipment class. It maintains a current record of the availability of equipment in the health system. It + is expected that this is instantiated by the :py:class:`~.HealthSystem` module. + + The basic paradigm is that an :py:class:`~.HSI_Event` can declare equipment that is required for delivering the + healthcare service that the ``HSI_Event`` represents. The ``HSI_Event`` uses :py:meth:`HSI_event.add_equipment` to + make these declarations, with reference to the items of equipment that are defined in + ``ResourceFile_EquipmentCatalogue.csv``. (These declaration can be in the form of the descriptor or the equipment + item code). These declarations can be used when the ``HSI_Event`` is created but before it is run (in ``__init__``), + or during execution of the ``HSI_Event`` (in :py:meth:`.HSI_Event.apply`). + + As the ``HSI_Event`` can declare equipment that is required before it is run, the HealthSystem *can* use this to + prevent an ``HSI_Event`` running if the equipment declared is not available. Note that for equipment that is + declared whilst the ``HSI_Event`` is running, there are no checks on availability, and the ``HSI_Event`` is allowed + to continue running even if equipment is declared is not available. For this reason, the ``HSI_Event`` should + declare equipment that is *essential* for the healthcare service in its ``__init__`` method. If the logic inside the + ``apply`` method of the ``HSI_Event`` depends on the availability of equipment, then it can find the probability + with which item(s) will be available using :py:meth:`.HSI_Event.probability_all_equipment_available` + (or if all items are available with :py:meth:`.HSI_Event.is_all_declared_equipment_available`). + + The data on the availability of equipment data refers to the proportion of facilities in a district of a particular + level (i.e., the ``Facility_ID``) that do have that piece of equipment. In the model, we do not know which actual + facility the person is attending (there are many actual facilities grouped together into one ``Facility_ID`` in the + model). Therefore, the determination of whether equipment is available is made probabilistically for the + ``HSI_Event`` (i.e., the probability that the actual facility being attended by the person has the equipment is + represented by the proportion of such facilities that do have that equipment). It is assumed that the probabilities + of each item being available are independent of one other (so that the probability of all items being available is + the product of the probabilities for each item). This probabilistic determination of availability is only done + _once_ for the ``HSI_Event``: i.e., if the equipment is determined to not be available for the instance of the + ``HSI_Event``, then it will remain not available if the same event is re-scheduled / re-entered into the + ``HealthSystem`` queue. This represents that if the facility that a particular person attends for the ``HSI_Event`` + does not have the equipment available, then it will still not be available on another day. + + Where data on availability is not provided for an item, the probability of availability is inferred from the average + availability of other items in that facility ID. Likewise, the probability of an item being available at a facility + ID is inferred from the average availability of that item at other facilities. If an item code is referred in + ``add_equipment`` that is not recognised (not included in :py:attr:`catalogue`), a :py:exc:`UserWarning` is issued, + but that item is then silently ignored. If a facility ID is ever referred that is not recognised (not included in + :py:attr:`master_facilities_list`), an :py:exc:`AssertionError` is raised. :param catalogue: The database of all recognised item_codes. :param data_availability: Specifies the probability with which each equipment (identified by an ``item_code``) is @@ -57,9 +58,10 @@ class Equipment: and every facility ID in the :py:attr`master_facilities_list`. :param: rng: The random number generator object to use for random numbers. :param availability: Determines the mode availability of the equipment. If 'default' then use the availability - specified in :py:attr:`data_availability`; if 'none', then let no equipment be ever be available; if 'all', then all - equipment is always available. - :param master_facilities_list: The :py:class:`~pandas.DataFrame` with the line-list of all the facilities in the health system. + specified in :py:attr:`data_availability`; if 'none', then let no equipment be ever be available; if 'all', then + all equipment is always available. + :param master_facilities_list: The :py:class:`~pandas.DataFrame` with the line-list of all the facilities in the + health system. """ def __init__( @@ -91,7 +93,6 @@ def __init__( # {facility_id: {item_code: count}}. self._record_of_equipment_used_by_facility_id = defaultdict(Counter) - def on_simulation_end(self): """Things to do when the simulation ends: * Log (to the summary logger) the equipment that has been used. @@ -118,7 +119,10 @@ def _get_equipment_availability_probabilities(self) -> pd.Series: calculation if the equipment availability change event occurs during the simulation. """ dat = self.data_availability.set_index( - [self.data_availability["Facility_ID"].astype(np.int64), self.data_availability["Item_Code"].astype(np.int64)] + [ + self.data_availability["Facility_ID"].astype(np.int64), + self.data_availability["Item_Code"].astype(np.int64), + ] )["Pr_Available"] # Confirm that there is an estimate for every item_code at every facility_id From ef7873d0b5ae4416e22bf8547587667bc702c6fc Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 13 Jul 2025 01:04:22 +0100 Subject: [PATCH 461/755] RF_PriorityRanking_ALLPOLICIES: post-merge fix --- .../ResourceFile_PriorityRanking_ALLPOLICIES/CVD.csv | 4 ++-- .../ClinicallyVulnerable.csv | 4 ++-- .../ResourceFile_PriorityRanking_ALLPOLICIES/Default.csv | 4 ++-- .../ResourceFile_PriorityRanking_ALLPOLICIES/EHP_III.csv | 4 ++-- .../ResourceFile_PriorityRanking_ALLPOLICIES/LCOA_EHP.csv | 4 ++-- .../ResourceFile_PriorityRanking_ALLPOLICIES/Naive.csv | 4 ++-- .../ResourceFile_PriorityRanking_ALLPOLICIES/RMNCH.csv | 4 ++-- .../ResourceFile_PriorityRanking_ALLPOLICIES/Test Mode 1.csv | 4 ++-- .../ResourceFile_PriorityRanking_ALLPOLICIES/Test.csv | 4 ++-- .../VerticalProgrammes.csv | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/CVD.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/CVD.csv index 35391723c3..3c0906dd08 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/CVD.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/CVD.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:99eb5bb3e95438c937cc306efce065e13314503fa42d29f69f43d0e7b7ed55f6 -size 3691 +oid sha256:40d4b437cdedd166e6bd84c47c360739149855388c7975e7ed276c731834cfca +size 3359 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/ClinicallyVulnerable.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/ClinicallyVulnerable.csv index 36a8acb982..c6e6c3cb1d 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/ClinicallyVulnerable.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/ClinicallyVulnerable.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1ecf780918457a52ea696a4d78b2a714461c286524e94ea08ab0786b543f9d3d -size 3335 +oid sha256:9f0c14598fbe3725da6755d45bf8d00f05bbe538abb42b1e609c1f5b69842d11 +size 3358 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Default.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Default.csv index ef406af146..c9b0742ebf 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Default.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Default.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9765f315c5c14e5f05f9f5ad8d44d4a0b199fa646663bced90dfc9b2d435665d -size 3693 +oid sha256:c076ca2a6e70ce7cee960e99178de1bfacda42126af124a49be6b8e5bcd479f9 +size 3720 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/EHP_III.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/EHP_III.csv index 5ea57f975f..7a06c29077 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/EHP_III.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/EHP_III.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d16375b7d09471b7cb8e642ee5ba5950eaea1839344a1d78dbccaaccc2b37af4 -size 3692 +oid sha256:e3fd0d67246dc6ae27beacc591e43503e395e95a9beec122287044b93f36dbb6 +size 3719 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/LCOA_EHP.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/LCOA_EHP.csv index 74e1693f10..298398d749 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/LCOA_EHP.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/LCOA_EHP.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d1dab952563f8c0ea2925abfbdd433bdeeece0cf90618518dc8ce84333f0a1ce -size 3691 +oid sha256:16369f9c92b7cd83b572be19e80164b574d58da7d621ea0ccbedf9dd25c26030 +size 3719 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Naive.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Naive.csv index 3edb46845a..9267d3bbc5 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Naive.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Naive.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:833be1d5561c8a025fc236908c3154591c34f527f949aca66eb0c036c17159f5 -size 3691 +oid sha256:fcf5a393c588e5e2e1529b614222cf1d80f1971f7e438d96c6664d06661bb8f5 +size 3718 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/RMNCH.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/RMNCH.csv index b079737008..f0e63a76d9 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/RMNCH.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/RMNCH.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2270c7abfe61d618393c72f2b8b91e5e83521fad88e346dbd3c50f0c70daca2c -size 3672 +oid sha256:4e059db92156660eaa376b69b3aa1f69aac86350407633d1adaa4d11525c7990 +size 3698 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test Mode 1.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test Mode 1.csv index 4f36332334..97cd845055 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test Mode 1.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test Mode 1.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bff2f55a3697e5d03ee74d1aeb5b665021dabe9b83d32dff5706759b090f3778 -size 3693 +oid sha256:d1436e648ec02f061d40f296e162e3dfc7fbd7a1f9e8edaab51a945b9ac4b761 +size 3720 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test.csv index 377813f49f..ab7834da90 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/Test.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:90c96330accbd06f723fe0f9935e6f66895ea877e91aa99bcb71deaaf16e3d7d -size 3693 +oid sha256:d289dc46da9982d8a8150a25d7a7c7f01495abf3b68fcc66bd6f44529859d0c3 +size 3720 diff --git a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/VerticalProgrammes.csv b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/VerticalProgrammes.csv index 12dcc372ea..f5db7fd5b6 100644 --- a/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/VerticalProgrammes.csv +++ b/resources/healthsystem/priority_policies/ResourceFile_PriorityRanking_ALLPOLICIES/VerticalProgrammes.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:226fc79de5d5391085f1c60171c246016d5825aec65069e17a4305e8ddde1fff -size 3691 +oid sha256:8b61fa0da5cf42f1bcd50ed2a72c0ad98f9d31670e54cd098322d3c41804778a +size 3718 From 0a66dc5398ad06549a00f908b2cfd2d04779251f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 13 Jul 2025 18:32:36 +0100 Subject: [PATCH 462/755] test_wast: call Resource file path from simulation --- tests/test_wasting.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 50e11d01c1..f0af68afe9 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -48,6 +48,7 @@ def get_sim(tmpdir): modules registered. """ sim = Simulation(start_date=start_date, seed=0, + resourcefilepath=resourcefilepath, show_progress_bar=False, log_config={ 'filename': 'tmp', @@ -57,17 +58,16 @@ def get_sim(tmpdir): "tlo.methods.wasting": logging.INFO} }) - sim.register(demography.Demography(resourcefilepath=resourcefilepath), - enhanced_lifestyle.Lifestyle(resourcefilepath=resourcefilepath), - healthsystem.HealthSystem(resourcefilepath=resourcefilepath, - disable=False, + sim.register(demography.Demography(), + enhanced_lifestyle.Lifestyle(), + healthsystem.HealthSystem(disable=False, cons_availability='all', equip_availability='all'), - symptommanager.SymptomManager(resourcefilepath=resourcefilepath), - healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=resourcefilepath), - healthburden.HealthBurden(resourcefilepath=resourcefilepath), - simplified_births.SimplifiedBirths(resourcefilepath=resourcefilepath), - wasting.Wasting(resourcefilepath=resourcefilepath) + symptommanager.SymptomManager(), + healthseekingbehaviour.HealthSeekingBehaviour(), + healthburden.HealthBurden(), + simplified_births.SimplifiedBirths(), + wasting.Wasting() ) return sim @@ -405,10 +405,10 @@ def test_nat_recovery_moderate_wasting(tmpdir): def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpdir): - """ Check the onset of symptoms with uncomplicated SAM, check recovery to MAM with tx when + """ Check the onset of symptoms with uncomplicated SAM, check recovery to MAM with treatment (tx) when the progression to severe wasting is certain, hence no natural recovery from moderate wasting, the natural death due to SAM is certain, hence no natural recovery from severe wasting, - and check natural death canceled w\ tx and symptoms resolved when recovered to MAM with tx. """ + and check natural death canceled with tx and symptoms resolved when recovered to MAM with tx. """ dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) @@ -542,8 +542,8 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd def test_tx_full_recovery_severe_acute_malnutrition_with_complications(tmpdir): - """ Check the onset of symptoms with complicated SAM, check full recovery with tx when - the natural death due to SAM is certain but canceled w\ tx, and symptoms resolved when fully recovered with tx. """ + """ Check the onset of symptoms with complicated SAM, check full recovery with treatment (tx) when the natural + death due to SAM is certain but canceled with tx, and symptoms resolved when fully recovered with tx. """ dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) From 79af973831121982a093a19213091664c131ac2f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 13 Jul 2025 18:33:05 +0100 Subject: [PATCH 463/755] wast: PEP8 --- src/tlo/methods/wasting.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 5971ca65c5..1dd462a3af 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1056,7 +1056,8 @@ def get_min_length(in_recov_how, in_person_id, in_whz): whz = df.at[person_id, 'un_WHZ_category'] assert wasted_days >= get_min_length(recov_how, person_id, whz),\ - (f" The {person_id=} is {wasted_days=} < minimal expected length= {get_min_length(recov_how, person_id, whz)} days " + (f" The {person_id=} is {wasted_days=} < minimal expected length= " + f"{get_min_length(recov_how, person_id, whz)} days " f"when {recov_opt=}.") self.module.wasting_length_tracker[age_group][recov_opt].append(wasted_days) @@ -1824,12 +1825,12 @@ def apply(self, population): if total_per_agegrp_nmb > 0: # get those children who are wasted - mod_wasted_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, - inclusive='left') & (under5s.un_WHZ_category - == '-3<=WHZ<-2')).sum() - sev_wasted_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, - inclusive='left') & (under5s.un_WHZ_category - == 'WHZ<-3')).sum() + mod_wasted_agegrp_nmb = \ + (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, inclusive='left') + & (under5s.un_WHZ_category == '-3<=WHZ<-2')).sum() + sev_wasted_agegrp_nmb = \ + (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, inclusive='left') + & (under5s.un_WHZ_category == 'WHZ<-3')).sum() # add moderate and severe wasting prevalence to the dictionary wasting_prev_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = \ mod_wasted_agegrp_nmb / total_per_agegrp_nmb From 1032106862ddd3208bb4fde7f9f9ddbe559b9090 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 14 Jul 2025 23:21:00 +0100 Subject: [PATCH 464/755] gitattributes: excl resources/**/*.md from LFS --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index e8241c9d42..b52e66556c 100644 --- a/.gitattributes +++ b/.gitattributes @@ -9,3 +9,4 @@ *.xlsx filter=lfs diff=lfs merge=lfs -text *.pickle filter=lfs diff=lfs merge=lfs -text resources/** filter=lfs diff=lfs merge=lfs -text +resources/**/*.md !filter !diff !merge !text From 6954900c233b70cd33ba1acf3012152e56b2540a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 5 Aug 2025 23:55:42 +0200 Subject: [PATCH 465/755] test_wast: more informative name of test --- tests/test_wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index f0af68afe9..679c76b2b8 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -73,7 +73,7 @@ def get_sim(tmpdir): @pytest.mark.slow -def test_basic_run(tmpdir): +def test_integrity_of_properties_of_wasting_module(tmpdir): """ Run the simulation and do some daily checks on dtypes and properties integrity. """ class DummyModule(Module): """ A Dummy module that ensure wasting properties are as expected on a daily basis """ From 82e73055816a8f6a6b4e70eb513b21718e27227d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 6 Aug 2025 00:00:00 +0200 Subject: [PATCH 466/755] test_wast: comment instead of explicit zero-duration definition --- tests/test_wasting.py | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 679c76b2b8..caa425f13a 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -178,14 +178,13 @@ def check_configuration_of_properties(self, population): def test_wasting_incidence(tmpdir): """ Check incidence of wasting is happening as expected. """ # get simulation object: - dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) # get wasting module wmodule = sim.modules['Wasting'] sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) + sim.simulate(end_date=start_date) # zero duration # Reset properties of all individuals so that they are well-nourished df = sim.population.props @@ -216,8 +215,6 @@ def test_report_daly_weights(tmpdir): 2. For an individual with moderate wasting and oedema (expected daly weight is 0.051) 3. For an individual with severe wasting and oedema (expected daly weight is 0.172) 4. For an individual with severe wasting without oedema (expected daly weight is 0.128) """ - - dur = pd.DateOffset(days=0) popsize = 1 sim = get_sim(tmpdir) sim.modules['Demography'].parameters['max_age_initial'] = 4.9 @@ -225,7 +222,7 @@ def test_report_daly_weights(tmpdir): wmodule = sim.modules['Wasting'] sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) + sim.simulate(end_date=start_date) # zero duration # Dict to hold the DALY weights daly_wts = dict() @@ -311,8 +308,6 @@ def test_report_daly_weights(tmpdir): def test_nat_recovery_moderate_wasting(tmpdir): """ Check natural recovery after onset of moderate wasting with MAM diagnosis. """ for am_state_expected in ['MAM', 'SAM']: - - dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) # get wasting module @@ -320,7 +315,7 @@ def test_nat_recovery_moderate_wasting(tmpdir): p = wmodule.parameters sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) + sim.simulate(end_date=start_date) # zero duration sim.event_queue.queue = [] # clear the queue # Get person to use: @@ -409,7 +404,6 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd the progression to severe wasting is certain, hence no natural recovery from moderate wasting, the natural death due to SAM is certain, hence no natural recovery from severe wasting, and check natural death canceled with tx and symptoms resolved when recovered to MAM with tx. """ - dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) # get wasting module @@ -421,7 +415,7 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd p['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) + sim.simulate(end_date=start_date) # zero duration sim.event_queue.queue = [] # clear the queue # Get person to use: @@ -544,7 +538,6 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd def test_tx_full_recovery_severe_acute_malnutrition_with_complications(tmpdir): """ Check the onset of symptoms with complicated SAM, check full recovery with treatment (tx) when the natural death due to SAM is certain but canceled with tx, and symptoms resolved when fully recovered with tx. """ - dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) # get wasting module @@ -556,7 +549,7 @@ def test_tx_full_recovery_severe_acute_malnutrition_with_complications(tmpdir): p['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) + sim.simulate(end_date=start_date) # zero duration sim.event_queue.queue = [] # clear the queue # Get person to use: @@ -658,7 +651,6 @@ def test_nat_death_overwritten_by_tx_death(tmpdir): """ Check if the risk of death when untreated is 100%, the person is scheduled to die due to natural history. But with treatment the natural death is cancelled. Check if also chance to fully recover with treatment is 0%, and risk of death when treated is 100%, the person will die. Test for uncomplicated SAM.""" - dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) # get wasting module @@ -671,7 +663,7 @@ def test_nat_death_overwritten_by_tx_death(tmpdir): p['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) + sim.simulate(end_date=start_date) # zero duration sim.event_queue.queue = [] # clear the queue # Set full recovery with treatment at 0% @@ -769,10 +761,7 @@ def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): """ Show that if recovered with a tx event before the person was going to recover naturally from moderate wasting with moderate or severe acute malnutrition, it causes the episode to end earlier, natural recovery is cancelled. Test for MAM and complicated SAM. """ - for am_state_expected in ['MAM', 'SAM']: - - dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) # get wasting module @@ -780,7 +769,7 @@ def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): p = wmodule.parameters sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) + sim.simulate(end_date=start_date) # zero duration sim.event_queue.queue = [] # clear the queue # Set moderate wasting incidence rate at 100% and rate of progression to severe wasting at 0%. @@ -887,8 +876,6 @@ def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): def test_recovery_before_death_scheduled(tmpdir): """ Show that if a recovery event is run before when a person was going to die, it causes the episode to end without the person dying. """ - - dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) # get wasting module @@ -900,7 +887,7 @@ def test_recovery_before_death_scheduled(tmpdir): p['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) + sim.simulate(end_date=start_date) # zero duration sim.event_queue.queue = [] # clear the queue @@ -1030,13 +1017,12 @@ def test_recovery_before_death_scheduled(tmpdir): def test_no_wasting_after_recent_recovery(tmpdir): """ Test that a person who recovered from wasting 5 days ago does not become wasted again. """ - dur = pd.DateOffset(days=0) popsize = 1000 sim = get_sim(tmpdir) wmodule = sim.modules['Wasting'] sim.make_initial_population(n=popsize) - sim.simulate(end_date=start_date + dur) + sim.simulate(end_date=start_date) # zero duration sim.event_queue.queue = [] # clear the queue # Get person to use: From 5d64d25b6e622a23ce2cb7d3a07e76575ff5a8a6 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 6 Aug 2025 00:21:07 +0200 Subject: [PATCH 467/755] test_wast: use df.at for consistency in single-cell read/write --- tests/test_wasting.py | 106 +++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index caa425f13a..74e337153d 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -234,30 +234,30 @@ def test_report_daly_weights(tmpdir): # 1. Check daly weight for well-nourished person (weight is 0.0) # Reset diagnostic properties - df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' - df.loc[person_id, 'un_am_nutritional_oedema'] = False - df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' + df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' + df.at[person_id, 'un_am_nutritional_oedema'] = False + df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' # Verify diagnosis - an individual should be well wmodule.clinical_acute_malnutrition_state(person_id, df) - assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'well' + assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well' # Report daly weight for this individual daly_weights_reported = wmodule.report_daly_values() # Verify that individual has no daly weight - assert daly_weights_reported.loc[person_id] == 0.0 + assert daly_weights_reported.at[person_id] == 0.0 get_daly_weights = sim.modules['HealthBurden'].get_daly_weight # 2. Check daly weight for person with moderate wasting and oedema (weight is 0.051) # Reset diagnostic properties - df.loc[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' - df.loc[person_id, 'un_am_nutritional_oedema'] = True + df.at[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' + df.at[person_id, 'un_am_nutritional_oedema'] = True # Verify diagnosis - an individual should have SAM wmodule.clinical_acute_malnutrition_state(person_id, df) - assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' + assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' # Report daly weight for this individual daly_weights_reported = wmodule.report_daly_values() @@ -266,16 +266,16 @@ def test_report_daly_weights(tmpdir): daly_wts['mod_wasting_with_oedema'] = get_daly_weights(sequlae_code=461) # Compare the daly weight of this individual with the daly weight obtained from HealthBurden module - assert daly_wts['mod_wasting_with_oedema'] == daly_weights_reported.loc[person_id] + assert daly_wts['mod_wasting_with_oedema'] == daly_weights_reported.at[person_id] # 3. Check daly weight for person with severe wasting and oedema (weight is 0.172) # Reset diagnostic properties - df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' - df.loc[person_id, 'un_am_nutritional_oedema'] = True + df.at[person_id, 'un_WHZ_category'] = 'WHZ<-3' + df.at[person_id, 'un_am_nutritional_oedema'] = True # Verify diagnosis - an individual should have SAM wmodule.clinical_acute_malnutrition_state(person_id, df) - assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' + assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' # Report daly weight for this individual daly_weights_reported = wmodule.report_daly_values() @@ -284,16 +284,16 @@ def test_report_daly_weights(tmpdir): daly_wts['sev_wasting_with_oedema'] = get_daly_weights(sequlae_code=463) # Compare the daly weight of this individual with the daly weight obtained from HealthBurden module - assert daly_wts['sev_wasting_with_oedema'] == daly_weights_reported.loc[person_id] + assert daly_wts['sev_wasting_with_oedema'] == daly_weights_reported.at[person_id] # 4. Check daly weight for person with severe wasting without oedema (weight is 0.128) # Reset diagnosis - df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' - df.loc[person_id, 'un_am_nutritional_oedema'] = False + df.at[person_id, 'un_WHZ_category'] = 'WHZ<-3' + df.at[person_id, 'un_am_nutritional_oedema'] = False # Verify diagnosis - an individual should have SAM wmodule.clinical_acute_malnutrition_state(person_id, df) - assert df.loc[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' + assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' # Report daly weight for this individual daly_weights_reported = wmodule.report_daly_values() @@ -302,7 +302,7 @@ def test_report_daly_weights(tmpdir): daly_wts['sev_wasting_w/o_oedema'] = get_daly_weights(sequlae_code=462) # Compare the daly weight of this individual with the daly weight obtained from HealthBurden module - assert daly_wts['sev_wasting_w/o_oedema'] == daly_weights_reported.loc[person_id] + assert daly_wts['sev_wasting_w/o_oedema'] == daly_weights_reported.at[person_id] def test_nat_recovery_moderate_wasting(tmpdir): @@ -323,12 +323,12 @@ def test_nat_recovery_moderate_wasting(tmpdir): under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] # Reset properties of this individual to be well-nourished - df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not wasted - df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' - df.loc[person_id, 'un_am_nutritional_oedema'] = False - df.loc[person_id, 'un_clinical_acute_malnutrition'] = 'well' # well-nourished - df.loc[person_id, 'un_ever_wasted'] = False - df.loc[person_id, 'un_last_wasting_date_of_onset'] = pd.NaT + df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' # not wasted + df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' + df.at[person_id, 'un_am_nutritional_oedema'] = False + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' # well-nourished + df.at[person_id, 'un_ever_wasted'] = False + df.at[person_id, 'un_last_wasting_date_of_onset'] = pd.NaT # Set moderate wasting incidence rate at 100% and rate of progression to severe wasting at 0%. # (Hence, all children with normal wasting should get onset of moderate wasting and be scheduled for natural @@ -423,10 +423,10 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] # Manually set this individual properties to be well - df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' - df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' - df.loc[person_id, 'un_am_nutritional_oedema'] = False - df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' + df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' + df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' + df.at[person_id, 'un_am_nutritional_oedema'] = False + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' df.at[person_id, 'un_sam_with_complications'] = False df.at[person_id, 'un_sam_death_date'] = pd.NaT @@ -446,7 +446,7 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd polling.apply(sim.population) # Check properties of this individual: should now be moderately wasted - assert df.loc[person_id]['un_WHZ_category'] == '-3<=WHZ<-2' + assert df.at[person_id, 'un_WHZ_category'] == '-3<=WHZ<-2' # Check that there is a Wasting_ProgressionToSevere_Event scheduled for this person: progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) @@ -504,7 +504,7 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd sam_ev.run(squeeze_factor=0.0) # Check death was canceled with tx - assert pd.isnull(df.loc[person_id]['un_sam_death_date']) + assert pd.isnull(df.at[person_id, 'un_sam_death_date']) # Check recovery to MAM due to tx is scheduled assert isinstance(sim.find_events_for_person(person_id)[2][1], Wasting_RecoveryToMAM_Event) @@ -557,8 +557,8 @@ def test_tx_full_recovery_severe_acute_malnutrition_with_complications(tmpdir): under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] # Manually set this individual properties to have SAM - df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' - df.loc[person_id, 'un_last_wasting_date_of_onset'] = sim.date + df.at[person_id, 'un_WHZ_category'] = 'WHZ<-3' + df.at[person_id, 'un_last_wasting_date_of_onset'] = sim.date # Ensure the individual has complications due to SAM p['prob_complications_in_SAM'] = 1.0 @@ -579,7 +579,7 @@ def test_tx_full_recovery_severe_acute_malnutrition_with_complications(tmpdir): # Check death is scheduled assert isinstance(sim.find_events_for_person(person_id)[0][1], Wasting_SevereAcuteMalnutritionDeath_Event) - assert not pd.isnull(df.loc[person_id]['un_sam_death_date']) + assert not pd.isnull(df.at[person_id, 'un_sam_death_date']) # get date of death and death event death_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if isinstance(event_tuple[1], Wasting_SevereAcuteMalnutritionDeath_Event)][0] @@ -612,7 +612,7 @@ def test_tx_full_recovery_severe_acute_malnutrition_with_complications(tmpdir): sam_ev.run(squeeze_factor=0.0) # Check scheduled death was canceled due to tx - assert pd.isnull(df.loc[person_id]['un_sam_death_date']) + assert pd.isnull(df.at[person_id, 'un_sam_death_date']) # Check full recovery due to tx is scheduled assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_FullRecovery_Event) @@ -678,8 +678,8 @@ def test_nat_death_overwritten_by_tx_death(tmpdir): under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] # Manually set this individual properties to have SAM due to severe wasting, hence natural death should be applied - df.loc[person_id, 'un_WHZ_category'] = 'WHZ<-3' - df.loc[person_id, 'un_last_wasting_date_of_onset'] = sim.date + df.at[person_id, 'un_WHZ_category'] = 'WHZ<-3' + df.at[person_id, 'un_last_wasting_date_of_onset'] = sim.date # Assign diagnosis wmodule.clinical_acute_malnutrition_state(person_id, df) @@ -724,7 +724,7 @@ def test_nat_death_overwritten_by_tx_death(tmpdir): # Check death event is scheduled for another day than natural death was scheduled for since there is no recovery # with treatment assert isinstance(sim.find_events_for_person(person_id)[0][1], Wasting_SevereAcuteMalnutritionDeath_Event) - assert df.loc[person_id]['un_sam_death_date'] != nat_death_date + assert df.at[person_id, 'un_sam_death_date'] != nat_death_date # Load list of all death events scheduled for the person death_events_list = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if @@ -786,10 +786,10 @@ def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] # Manually set this individual properties to be well - df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' - df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' - df.loc[person_id, 'un_am_nutritional_oedema'] = False - df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' + df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' + df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' + df.at[person_id, 'un_am_nutritional_oedema'] = False + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' df.at[person_id, 'un_sam_with_complications'] = False df.at[person_id, 'un_sam_death_date'] = pd.NaT @@ -855,9 +855,9 @@ def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): # Check natural recovery is going to be cancelled if am_state_expected == 'MAM': - assert date_of_scheduled_nat_recov in df.loc[person_id, 'un_full_recov_to_cancel'] + assert date_of_scheduled_nat_recov in df.at[person_id, 'un_full_recov_to_cancel'] else: # complicated SAM - assert date_of_scheduled_nat_recov in df.loc[person_id, 'un_recov_to_mam_to_cancel'] + assert date_of_scheduled_nat_recov in df.at[person_id, 'un_recov_to_mam_to_cancel'] # Run the natural recovery, this should have no effect sim.date = date_of_scheduled_nat_recov nat_recov_event.apply(person_id) @@ -906,10 +906,10 @@ def test_recovery_before_death_scheduled(tmpdir): under5s = df.loc[df.is_alive & (df['age_years'] < 5)] person_id = under5s.index[0] # Manually set this individual properties to be well - df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' - df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' - df.loc[person_id, 'un_am_nutritional_oedema'] = False - df.loc[df.is_alive, 'un_clinical_acute_malnutrition'] = 'well' + df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' + df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' + df.at[person_id, 'un_am_nutritional_oedema'] = False + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' df.at[person_id, 'un_sam_with_complications'] = False df.at[person_id, 'un_sam_death_date'] = pd.NaT @@ -1013,7 +1013,7 @@ def test_recovery_before_death_scheduled(tmpdir): # Run the death event that was originally scheduled - this should have no effect and the person should not die sim.date = date_of_scheduled_death death_event.apply(person_id=person_id) - assert df.loc[person_id]['is_alive'] + assert df.at[person_id, 'is_alive'] def test_no_wasting_after_recent_recovery(tmpdir): """ Test that a person who recovered from wasting 5 days ago does not become wasted again. """ @@ -1031,11 +1031,11 @@ def test_no_wasting_after_recent_recovery(tmpdir): person_id = under5s.index[0] # Manually set this individual properties to be well and recovered 5 days ago - df.loc[person_id, 'un_WHZ_category'] = 'WHZ>=-2' - df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' - df.loc[person_id, 'un_am_nutritional_oedema'] = False - df.loc[person_id, 'un_clinical_acute_malnutrition'] = 'well' - df.loc[person_id, 'un_am_recovery_date'] = sim.date - pd.DateOffset(days=5) + df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' + df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' + df.at[person_id, 'un_am_nutritional_oedema'] = False + df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' + df.at[person_id, 'un_am_recovery_date'] = sim.date - pd.DateOffset(days=5) # Set incidence of wasting at 100% wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() @@ -1045,4 +1045,4 @@ def test_no_wasting_after_recent_recovery(tmpdir): polling.apply(sim.population) # Check properties of this individual: should still be well - assert df.loc[person_id]['un_clinical_acute_malnutrition'] == 'well' + assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well' From 99772581fe3d20a7ff367311d4e67321b8224539 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 15 Aug 2025 12:43:21 +0100 Subject: [PATCH 468/755] wasting_analyses: rename analysis_wasting -> calib_analysis_wasting --- ...ysis_wasting.py => calib_analysis_wasting.py} | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) rename src/scripts/wasting_analyses/{analysis_wasting.py => calib_analysis_wasting.py} (98%) diff --git a/src/scripts/wasting_analyses/analysis_wasting.py b/src/scripts/wasting_analyses/calib_analysis_wasting.py similarity index 98% rename from src/scripts/wasting_analyses/analysis_wasting.py rename to src/scripts/wasting_analyses/calib_analysis_wasting.py index b2d5e495e9..739584de0a 100644 --- a/src/scripts/wasting_analyses/analysis_wasting.py +++ b/src/scripts/wasting_analyses/calib_analysis_wasting.py @@ -25,7 +25,6 @@ outputs_path = Path("./outputs/sejjej5@ucl.ac.uk/wasting") legend_fontsize = 12 title_fontsize = 16 -total_draws = 1 #= len(folders) ######################################################################################################################## def create_calib_outcome_csv(sim_results_folder_path_str): @@ -165,6 +164,8 @@ def plot_wasting_incidence(self): # calculate props within the age group plotting = plotting.div(age_gps_total_pop_sizes_df[age], axis=0) plotting = plotting.rename(columns=self.__wasting_types_desc) + # filter data to include only years from 2015 onwards + plotting = plotting.loc[plotting.index >= 2015] # check for invalid values if (plotting < 0).any().any() or (plotting > 1).any().any(): print(f"Warning plot_wasting_incidence: Invalid values detected in plotting data for age group {age}:") @@ -512,7 +513,7 @@ def plot_wasting_prevalence_per_year(self): ).fillna(0) w_prev_calib_and_init_df = pd.merge(init_w_prev_df, w_prev_calib_df, on='date') - w_prev_plot_df = pd.merge(w_prev_df, w_prev_calib_and_init_df, on='date') + w_prev_plot_df = pd.merge(w_prev_df, w_prev_calib_and_init_df, on='date').loc[lambda df: df.index >= 2015] columns_to_plot = [ ['total_init_sev_under5_prop', 'total_init_mod_under5_prop'], ['total_sev_under5_prop', 'total_mod_under5_prop'], @@ -552,7 +553,7 @@ def plot_wasting_prevalence_per_year(self): ax.set_title("Wasting prevalence in children 0-59 months per year", fontsize=title_fontsize-6) ax.set_ylabel('proportion of wasted children in the year') ax.set_xlabel('year') - ax.set_ylim([0, 0.131]) + ax.set_ylim([0, 0.06]) ax.legend(fontsize=legend_fontsize-4) plt.tight_layout() fig_output_name = ('wasting_prevalence_per_year__' + self.datestamp) @@ -691,7 +692,7 @@ def create_plotting_data(df, df_name): fontsize=title_fontsize-1) ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) ax.set_xticklabels(age_groups) - ax.set_ylim([0, 0.16]) + ax.set_ylim([0, 0.12]) ax.legend(fontsize=legend_fontsize) # Adjust the layout to make space for the footnote @@ -704,7 +705,8 @@ def create_plotting_data(df, df_name): plt.tight_layout() fig_output_name = (f'wasting_prevalence_per_each_age_group_{year_calib}__' + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name) + if year_calib in [2015, 2019]: + self.save_fig__store_pdf_file(fig, fig_output_name) # plt.show() def plot_model_gbd_deaths_incl_burnin_period(self): @@ -811,7 +813,7 @@ def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): datestamp = sim_results_folder_name[(len(scenario_filename) + 1):] folders = [name for name in os.listdir(sim_results_folder_path) if \ - os.path.isdir(os.path.join(sim_results_folder_path, name))] + os.path.isdir(os.path.join(sim_results_folder_path, name)) and name.isdigit()] # Create a csv to write down calibration outputs # as bool values indicating whether model outcomes and calibration data intersect @@ -820,7 +822,7 @@ def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): # Analyse each draw # for now, we always have just one run, run 0 run_nmb = 0 - for draw_nmb in range(0, total_draws): + for draw_nmb in range(0, len(folders)): print(f"Analysing {draw_nmb=} ...") time_start = time.time() From 47e78ba82b1caed8bc8e6a1faa71b6dc97301b7a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 18 Aug 2025 11:56:43 +0100 Subject: [PATCH 469/755] test_wast: simplify assert --- tests/test_wasting.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 74e337153d..f94c61b36e 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -355,10 +355,8 @@ def test_nat_recovery_moderate_wasting(tmpdir): assert person['un_last_wasting_date_of_onset'] == sim.date assert pd.isnull(person['un_am_tx_start_date']) assert pd.isnull(person['un_am_recovery_date']) - if am_state_expected == 'MAM': - assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM' - else: - assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM' + assert df.at[person_id, 'un_clinical_acute_malnutrition'] == am_state_expected + # Check that there is a natural recovery event scheduled: # Wasting_FullRecovery_Event if this person has MAM, Wasting_RecoveryToMAM_Event if this person has SAM From d3b8e7f2413e755bb5954c3ad7e54341fb14bae0 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 18 Aug 2025 12:09:28 +0100 Subject: [PATCH 470/755] test_wast: reduce use of shorthands --- tests/test_wasting.py | 48 ++++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index f94c61b36e..450b1c2f61 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -153,7 +153,7 @@ def check_configuration_of_properties(self, population): assert set() == set_of_person_id_in_current_episode_before_recovery.intersection( set_of_person_id_in_current_episode_before_death) - # WHZ standard deviation of -3, MUAC <115mm, and oedema should cause severe acute malnutrition + # WHZ standard deviation of -3, MUAC < 115mm, and oedema should cause severe acute malnutrition whz_index = df.index[df['un_WHZ_category'] == 'WHZ<-3'] muac_index = df.index[df['un_am_MUAC_category'] == '<115mm'] oedema_index = df.index[df['un_am_nutritional_oedema']] @@ -370,7 +370,7 @@ def test_nat_recovery_moderate_wasting(tmpdir): recov_event = recov_event_tuple[1] assert date_of_scheduled_recov > sim.date - # Check no progression to sev wasting is scheduled + # Check no progression to severe wasting is scheduled progress_event_tuple = next((event_tuple for event_tuple in sim.find_events_for_person(person_id) if isinstance(event_tuple[1], Wasting_ProgressionToSevere_Event)), None) assert not progress_event_tuple @@ -398,10 +398,10 @@ def test_nat_recovery_moderate_wasting(tmpdir): def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpdir): - """ Check the onset of symptoms with uncomplicated SAM, check recovery to MAM with treatment (tx) when - the progression to severe wasting is certain, hence no natural recovery from moderate wasting, - the natural death due to SAM is certain, hence no natural recovery from severe wasting, - and check natural death canceled with tx and symptoms resolved when recovered to MAM with tx. """ + """ Check the onset of symptoms with uncomplicated SAM, check recovery to MAM with treatment when the progression to + severe wasting is certain, hence no natural recovery from moderate wasting, the natural death due to SAM is certain + hence no natural recovery from severe wasting, and check natural death canceled with treatment and symptoms resolved + when recovered to MAM with treatment. """ popsize = 1000 sim = get_sim(tmpdir) # get wasting module @@ -434,9 +434,9 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() # Set progress to severe wasting at 100% as well, hence no natural recovery from moderate wasting wmodule.wasting_models.severe_wasting_progression_lm = LinearModel.multiplicative() - # Set complete recovery from SAM to zero. We want those with SAM to recover to MAM with tx + # Set complete recovery from SAM to zero. We want those with SAM to recover to MAM with treatment wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) - # Set prob of death after tx at 0% (hence recovery to MAM w\ tx at 100%) + # Set probability of death after treatment at 0% (hence recovery to MAM with treatment at 100%) p['prob_death_after_SAMcare'] = 0.0 # Run Wasting Polling event to get new incident cases: @@ -501,10 +501,10 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] sam_ev.run(squeeze_factor=0.0) - # Check death was canceled with tx + # Check death was canceled with treatment assert pd.isnull(df.at[person_id, 'un_sam_death_date']) - # Check recovery to MAM due to tx is scheduled + # Check recovery to MAM due to treatment is scheduled assert isinstance(sim.find_events_for_person(person_id)[2][1], Wasting_RecoveryToMAM_Event) # get date of recovery to MAM and the recovery event sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if @@ -534,8 +534,8 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd def test_tx_full_recovery_severe_acute_malnutrition_with_complications(tmpdir): - """ Check the onset of symptoms with complicated SAM, check full recovery with treatment (tx) when the natural - death due to SAM is certain but canceled with tx, and symptoms resolved when fully recovered with tx. """ + """ Check the onset of symptoms with complicated SAM, check full recovery with treatment when the natural death due + to SAM is certain but canceled with treatment, and symptoms resolved when fully recovered with treatment. """ popsize = 1000 sim = get_sim(tmpdir) # get wasting module @@ -560,7 +560,7 @@ def test_tx_full_recovery_severe_acute_malnutrition_with_complications(tmpdir): # Ensure the individual has complications due to SAM p['prob_complications_in_SAM'] = 1.0 - # Set full recovery rate to 100% so that this individual should fully recover with tx + # Set full recovery rate to 100% so that this individual should fully recover with treatment wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel.multiplicative() # Assign diagnosis @@ -609,10 +609,10 @@ def test_tx_full_recovery_severe_acute_malnutrition_with_complications(tmpdir): isinstance(ev[1], HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM)][0] sam_ev.run(squeeze_factor=0.0) - # Check scheduled death was canceled due to tx + # Check scheduled death was canceled due to treatment assert pd.isnull(df.at[person_id, 'un_sam_death_date']) - # Check full recovery due to tx is scheduled + # Check full recovery due to treatment is scheduled assert isinstance(sim.find_events_for_person(person_id)[1][1], Wasting_FullRecovery_Event) # get date of full recovery and the recovery event sam_recovery_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if @@ -666,7 +666,7 @@ def test_nat_death_overwritten_by_tx_death(tmpdir): # Set full recovery with treatment at 0% wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) - # Set death rate with tx at 100%, hence all SAM cases should die with treatment + # Set death rate with treatment at 100%, hence all SAM cases should die with treatment p['prob_death_after_SAMcare'] = 1.0 # Ensure the individual has no complications when SAM occurs p['prob_complications_in_SAM'] = 0.0 @@ -756,7 +756,7 @@ def test_nat_death_overwritten_by_tx_death(tmpdir): def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): - """ Show that if recovered with a tx event before the person was going to recover naturally from moderate wasting + """ Show that if recovered with a treatment event before the person was going to recover naturally from moderate wasting with moderate or severe acute malnutrition, it causes the episode to end earlier, natural recovery is cancelled. Test for MAM and complicated SAM. """ for am_state_expected in ['MAM', 'SAM']: @@ -775,7 +775,7 @@ def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): # recovery.) wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() wmodule.wasting_models.severe_wasting_progression_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) - # Set probs of full recovery from MAM and SAM at 100%, so with tx they always fully recover + # Set probs of full recovery from MAM and SAM at 100%, so with treatment they always fully recover wmodule.wasting_models.acute_malnutrition_recovery_mam_lm = LinearModel.multiplicative() wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel.multiplicative() @@ -824,12 +824,14 @@ def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): wmodule.do_when_am_treatment(person_id, intervention='ITC') assert df.at[person_id, 'un_am_tx_start_date'] == sim.date - # Check full recovery with tx is scheduled before the natural recovery + # Check full recovery with treatment is scheduled before the natural recovery full_recov_events = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if isinstance(event_tuple[1], Wasting_FullRecovery_Event)] assert len(full_recov_events) in [1, 2], "only 1 or 2 full recovery events should be scheduled" - if len(full_recov_events) == 2: # with MAM nat full recovery as well as full recovery with tx - nat_recov_event_tuple = full_recov_events[1] # tx recovery scheduled to happen before recovery with tx + # with MAM natural full recovery as well as full recovery with treatment + if len(full_recov_events) == 2: + # treatment recovery scheduled to happen before recovery with treatment + nat_recov_event_tuple = full_recov_events[1] date_of_scheduled_nat_recov_to_confirm = nat_recov_event_tuple[0] assert date_of_scheduled_nat_recov_to_confirm == date_of_scheduled_nat_recov tx_recov_event_tuple = full_recov_events[0] @@ -838,7 +840,7 @@ def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): assert date_of_scheduled_tx_recov > sim.date assert date_of_scheduled_tx_recov < date_of_scheduled_nat_recov - # Run a recovery event due to tx first + # Run a recovery event due to treatment first sim.date = date_of_scheduled_tx_recov tx_recov_event.apply(person_id) # check properties of this individual, should have recovered today, is not wasted, is well-nourished and alive @@ -979,7 +981,7 @@ def test_recovery_before_death_scheduled(tmpdir): assert isinstance(sim.find_events_for_person(person_id)[2][1], Wasting_SevereAcuteMalnutritionDeath_Event) # Check a date of scheduled death - # we assume OTC tx to be longer than natural recovery from sev. wasting, + # we assume OTC treatment to be longer than natural recovery from sev. wasting, # (if decided in future to change this assumption, the test will need to be updated) assert p['tx_length_weeks_OutpatientSAM'] * 7 > p['duration_of_untreated_sev_wasting'] # hence the death should be scheduled before the natural recovery From 34e12d638ae15887412679a7010d320010c7e14b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 18 Aug 2025 12:18:49 +0100 Subject: [PATCH 471/755] test_wast: clarify rationale for example used in test --- tests/test_wasting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 450b1c2f61..ab9bd3667e 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -1016,7 +1016,8 @@ def test_recovery_before_death_scheduled(tmpdir): assert df.at[person_id, 'is_alive'] def test_no_wasting_after_recent_recovery(tmpdir): - """ Test that a person who recovered from wasting 5 days ago does not become wasted again. """ + """ Test that a person who recovered from wasting 5 days ago does not become wasted again. (The 5-day interval is + used as an example within the assumed 14-day relapse-free window.) """ popsize = 1000 sim = get_sim(tmpdir) wmodule = sim.modules['Wasting'] From fe46b5463674f2518bd907dd5dd81dada34e8711 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 18 Aug 2025 12:21:59 +0100 Subject: [PATCH 472/755] test_wast: PEP8 --- tests/test_wasting.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index ab9bd3667e..c1780351cb 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -756,8 +756,9 @@ def test_nat_death_overwritten_by_tx_death(tmpdir): def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): - """ Show that if recovered with a treatment event before the person was going to recover naturally from moderate wasting - with moderate or severe acute malnutrition, it causes the episode to end earlier, natural recovery is cancelled. + """ Show that if recovered with a treatment event before the person was going to recover naturally from moderate + wasting with moderate or severe acute malnutrition, it causes the episode to end earlier, natural recovery is + cancelled. Test for MAM and complicated SAM. """ for am_state_expected in ['MAM', 'SAM']: popsize = 1000 From 0fa3e91ebb380f965ffff4c0044caa266fc483c5 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 18 Aug 2025 17:57:57 +0100 Subject: [PATCH 473/755] test_wast: refine and correct test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications description --- tests/test_wasting.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index c1780351cb..8402066202 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -398,10 +398,10 @@ def test_nat_recovery_moderate_wasting(tmpdir): def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpdir): - """ Check the onset of symptoms with uncomplicated SAM, check recovery to MAM with treatment when the progression to - severe wasting is certain, hence no natural recovery from moderate wasting, the natural death due to SAM is certain - hence no natural recovery from severe wasting, and check natural death canceled with treatment and symptoms resolved - when recovered to MAM with treatment. """ + """ Assume: untreated SAM causes certain death, no complications occur, incidence and progression to severe wasting + are certain, and treatment prevents death. + Check: child progresses to SAM without complications, death is scheduled but cancelled by treatment, and recovery to + MAM follows treatment. """ popsize = 1000 sim = get_sim(tmpdir) # get wasting module From f3f900ee03e9c42f1251484609a665d7521a2104 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 18 Aug 2025 18:27:33 +0100 Subject: [PATCH 474/755] wast & Wast write-up: units for the incidence rate specified --- docs/write-ups/Wasting.doc | Bin 451994 -> 360253 bytes src/tlo/methods/wasting.py | 5 +++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/write-ups/Wasting.doc b/docs/write-ups/Wasting.doc index 1bec64a5f614ae3b65aedd530459abf45dd7dc49..bcda0eb678b33ee28624f30b474734bd2bd7ed21 100644 GIT binary patch literal 360253 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%0AM#CK(T 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%0Dw~5?B4q7!mN3lNn<2)iOCdTHbEU+ zj-7^vxbFN^G}gSmI)sZ$ReIsGH8vGltx1+dG~P7H)94nQh63rndfxZ8!9VNfwA^#7 z7!}q2$e&ij+$|Io`~1^*CZL@X*aFnz*W>ISO9Q?zkA}gjfQnqS6&t(+qU}eN!iLk3 zM=?fBk};?&BkYzSi7N81>%z>3zr%)#>cnZvZnoG1Q2&$mix;2U<$zRi_1T+PZ#K6Yo1)j_njFe2eO3s;2O3;tD_8Z)AL(0|4|p8^7fRdlRQ% z>E&9D*iT=_KQ}MB!XsbR#W;b~^2b(Vx?+rgM8G_n3S-PDjwclLWg2}jCH#YjkWxta z=bOF6F8y>$0)*1gPoksnB}@a39n5Juh~KGqN?8LMnsrwL+Wee(mm^b8v&@YykaJ@H zqizA*HZEtxXTI5BQZM5P7oST`JHDkvA+eDkjkXvhYo_lyej^1VQP6ky9eSGXTG@a2 zAXK?cZSFZwV54^+A-wsWzXj2z$)-#o-QIV$V?AKTkk%5}fe_oaUQZjMA|_)V;6J@l z(!u6=0k+fO=JM0iCv;%rX!IHYwzk-W0{%zP0oIwexJ%kgP!(TFnX^SzbO;;?01QsAWq~4cT5qei+-Q%%NzhgATKyp z^W8|iS~ZalMOG!k{UhH{nMAf^4e%1TggW{+-?XkO4*FU5hrr^3)FGgVO~T(XP(+V7 z$O0gMSsnduT6GZEQBfa}*mVp4#gZc(=-b)lH@(T5{T~*6x6$7zX3L4AUmS`;|6{ol z!eMZIEMWrRZ7;d^X+tre|5Fj?DSQLs9-5StAd!)Ktz%Yo;y)dAQO5+naP#|jXjhH@ z#Atwo@?Gcp{YBYzYq&^V`qQcm*O%S523~j2f&Xit0LD5`QWQ8kv4fgpKYAj!_g^QO zWqfqDlQP+OU_EMie7Cp$R@O z?Yx0pc>9~Jp3aR&#~7I=b-N(f8#k}}(F<^(lhT#Jk}ar$RM|0Al-cAe+kwB`Jnp=-*(8&DS#?_|KWuW{|Lj!6zx}cBy3RrB zt^Wb-_5*28>bukAo35dP(PJv`1BGjT)qmR$-xak3q^$-Sv-sC_^nZ}X%Zp(j{LF_> zA+e7|uBQ(zy0k@A<4Rs;{*dRQ;^)w6nKBj&DeyqWpG5M+ICbDae#4Z+u<{pd-XFz6 z&8DW7)SZD|ca#tIs$IPI?DSg@Q1#)+|DGn(#A;=3iWkHoQl9?P@IQadYPSy39d+ce zeLLaMEdzIL>m6QFx7dBxrskwFFq?T- z-zzQT_iYks8LDUUWf~9mTAEHsjFLYHmIKpY5Le za$WPj%~19IP&FCxZrggnfxMw$I&4~@6|_5IXu*?&?kiW)pL;s9knSlBV0p=olBFu) z+vA>#*>RSf??t95b|Dz`kJ5>&PX_>&7YNxQ*F|gj|6P2BHPAxQKS!N5=iYF#CTEq5 zNeJCk2Jx9!k#>Pn_{p{VU{ z7rVHNEw;93y(Yt}{ZEtq!c6Nb^xaG!#k}X6%yTmRJ2xv)Q}@J4qz=(y#UraJJ;#;V8h;L_?vqa1h4sQEQYqO@5^wwm zId1C(R{QnHJPcC-N%+(Nh@StVz>J~ZzsuLx)PJ_9taNI4Mio5y!7XMw52}luP^)^yRo-Vi%u>o=2)clSR$<}R!L4A6zqLC`PR_5;&V2~ zZ{AS=*vFA?K~FbRWZ@nM0k;>`Qfxo|seLEpMx=9Y=|36#QH&+t+a}$)>Ug>-)%M+!iO>O8{AId#l1W zCqKALYNoW?7`pZtCqI~FOIfTXO_!8Rg^f7-Ynfh$ADsf>qaKM)qYP?VC5!f#u(TJi z3kCM92xP~-c4D^*r66o%Ic4>D}@P|={b$XIOX1OjXIu|cY8+8um6`p zIEKDLo_SUq?xrJOrmOcde(WhQ%eU;38fu+3gyc3yU9;g+!df9x?`|~wW^(K%PvmfDg89&W zSNz-F)3y-_t>02|O16Y$=P?Xw-AAmh+HXZY;o7P7w`skxt5RHSt)tY611a%@^ueRb#*ygv8agHEKTLVk)o*7dDFW^Nn8o`e^g&|M|9i}7pYKM%vQiebVseKr z^Sp2=a~)QEj<%_4%88-`PbVzzf7;?-*V>6sAhUUXKyV(Q8_wTU1Qbf)?e>93z9s8+ z?HJKXkbtj#$4c*ED!QX>vP&_sqpUTE^o35yX@b^~Q^D}%SJWts9dDXTS3MMD_9Vnj zEf~$&@w%p{qHXT`;M6EXKfOTp{@adQiWR_bYX|)Bx`nq7>$@o{;LBkCdbUSeeVSlr zt|d?!=+(PX0{6|h-A>FGkiLD@-0vUtjE!4WZ`mGth_ci@2EwL8?ep_=t{}{t8!Xqg zrze2{vdeMl1L@LIqY5d-4*j0-LOMvZ&C_2aEIzZoqw>uz1J&NghgQ0Pau-?kCU;1ZpstA~00RWbXmU!#x z9m>kQ`_pR~Liy+9;BUS?IbQRp=@@I^>)f7C>t+8YC?K87OrL>0tGBd;0EPTw5tUi{ zKv1uL+qcoPK*;*|1*I{|57)7pUw}Oqdzd*x_PiI5htQ|jXXl?h0+yL_ftsy3>)SF3 zmo#N7L^D9(*r&%I?!)u&sp(^@N);*%eI`g*aYA_(MuKCvFqBFf_f z-(V{?5C|1YI~qajHug)Kz%UKET(RpKGg_o^Ez?yvKw6dw0fK#cJ!4k+ z4CJ#m5$Inu^{LW9ia#8CX}$S%_VAOUFUoN#LrLI02s%-`LUuoy4siYBwg0_G74zc_ z3ei>req_S51jSP+jslGB`5op4hu7;(Ls7Hs^Oo1&4%Ji^^E)3}c&*Cj=s5f-%4D&Cjh%^dDmiopUV0*lll$kod4bnlN=Ehp%*dZ`|_X5&A-UNn4(e$I$nz zo9GHcaHd?z=b_*?cnV3~8TE|fA#4T6EtFJ$ zrvYK>`HejNZE*(7Qcqm3F8Gn}#mTf}H>@phNj-@%bwj~wp}?tY^AwR|OQAOZtG6qU zhjM-U+D;uME#j0=X(gPaEX~+TD1{0s43&gz2_wUpj+2B?5h1%w_HC?V%qc|(Bg@!k zgqUH>OqhikGv4PJb(Y`nyubH-|9SuM`FK7&&wXFZ_ge1jy6ziV$pDKeq=dcR(^h>_ z3AOtEwv%S|WYIS)+3;Zi=e`>^ufGWlKmT(?Ph7s%Ocj`iRX7SS9s*8FKQa|F{P$HJCxG-GL%6TL35UWCUV%Ig#mU!R%5HxvnYn!ZUg;Dy2EOuy$*=m&$52R}3aY?7H#{cNAz!%MNGi*vaV(7OO^fJUS6yTri4FMUr|02(q6`Jd=$stY%1 zNjb>)FaVxq|1-q^iRh%cYW}M*!(Cdo!@nS;0Hr=s?tGZtFLwZtK}E3KXC3nA7NvW_ z-ER5hm?8heqA2Z1GYB+#CD{Ytz;C7?^w1@Xd~)ef>H&-Xr?iWQsYN*-5;A+7z=EM+ z1raoUUAlU(V5Iuwm0#Qi_6hR8vGkQZK-w#l z!tc~l7x~DV*p+y$Dd8^+I81f@o91p8twiMK{PO~hObBfc6sg&TE4!2xha~?E!ybt2 zg~%QIMye!4qdGTS^jHU#yKCieWrb^*8DMz!2ZcU;I^mqMr6cg9>M~@0@p>W*9?{jw z;r#^0SuOqlM7eq_6*@!b4&r%*1-7w8047F)nCSr~7RKgc00vt|tNf{Sfc$_lvdHFh ztlw;R`zz)-0b=Ji9rKcOf|J{t?f%V3CFQOVlQh9<^RAGz`TP5;67&8fCssbNyPv%~ zdg3n-kzfuWc7@|71a+Z87tyhmb>_`rqFiQy?x_1Li$W3pr2lnz%}faK@%XFAG2P0slMI6)$=TIj=b z!Qc^hUOQB;?mxc*h~bG9N1=%EK10A1;JCD_V1CFCc=ugUh`M=mP z#$%GMk;#63`|3fnV2-t(JDy>UDV5t<-`K)YRO^W@$c>?z5TmYj7 zi>?1RTu}kf(1@KOcWIg5D{~mTgFrZm1neN_6daugeY3lOtAjiG{NjS9wB3Dd3mCUgTLQa(}-#9F^v`sraA$N`rFy3 zfCU0Uy^yj-^ewm6vzOm+%B><}a?=1CI}UgkxOvxnmEQs5vVj*}g0Q9$dqq)D%Hy}{ z)wHKtX2S_XNe2~J@!!$g+2*kKHWg~{Aaf7acg8G#U23`J?;`%fxA)Dj63OTa$xe(} z)ysii$i$E*k>?L)GEziQOJpKQsLTxF9_kU%nQX(I(YHS%c`UF@yp+$thEKF54yAlK z>QJxk!R?Q$@zQr{dR!`MC~)s9{82$bHEGOE@!ACh+qkb|GI;Gm`&#vYl+1hK{T3i% zE43v9^4ymDy6}0+6=nAuF4Jbu+dvQGLf;QywG9x_y+!D)tQrs;@EAf#)m`MMGEXXr z4En=Rhu<>LqA~|TR+Osv_Jij)P|{H$HH(uejTcSicI2K<+Qz^#^@6&o`31$|<4w^U z!Mkfjg{I)JF7U$5JLAz>RbKOX7Dy!zOqcO!%E;0!aQxKUlk4TAL|sqd^ga4h$o%HA z^qH7vTGj~~@AV>bUs?eM$8tiw8em;~FOlk2I$_}_OfDBsBd@QQWDYnkIB7zJ=hP@b{<>J z^#!b9XK-*;KS00nPCTE)91|I^GwF@(A8~OC+fKb|}s2yYvCPyNcejLMg;dz2zg3ZUR8nm-nutCr&B7 z8_e=dB2jm0MIJW1?+EZbrA}o&--(iX3fz=H5TQ05Kb-(62-?5vDuL3TBEvNNew8*0 zqBO18MGQ@AJ;LB@;5jbyhzr_?=Zy`kPZ_7p^kzd|CK)VU57bgSIzJiaOfD>~PmxIo zoPVp%MD`rfut4?=o?%sHM8(8+rs-nY-h#1zO}tTT6}AOT=b@{LiP!2DpJ-bdww+Y2 z7s@y(v|$6UOtv?wdrKz-%$I&l33pCQTd5LhozF6g8YAYmCu=B&v=8FAWZ4q^nbO9$ zD~YosGvm#%vFnyrvSu>CKgf@lx2bLfXTLQn1A%>U!!3#4Yhi!Bn0)jobMktUmSmfb zE>ewpcQVQ4p-T0zddUC2#?_xc>)r3uubO2&rPeP08_r=5vR*Skj#l-gC|Mv$m z3E!%{nl0WE(KI!%)GOzSUZ7*Tus>}kX!>akSSPg`LCq8ujf)xy7!wSI2NYY{L^on${1CFeSv zrqtDi{D+vO2{lxN>{xaEgvxAKA~>^o>GOL14R`_Fn{KudId#raTw!^kxsjs3yjTez zR!66YAcjj_pj)L_!mgM)@!123_S;-W9NvO+$HEfpzZ~#6bZ#93kV&K9Rg8ho5crUy z9|y-ostHL{=0pIV4-@rXZ$&NhM@H(RRf)dMB_ZsBul$ka2LBXEB-PL}_JPBtKp|ih zfAXrE%GKryxFh-u9Was4$-NHN*#m1{v_;7pcKJRu&2)IztuE+_4Ur0%BLf0f> z0UN1_umIQ)4%!{^=Ep-XpV$@CJNFJ&JqDBNNY23QEPg(f`A&w;@^3j4Ctla^tPYtZ zoU%ZbYbl%Y7Y6$>@Q107Fpb68iaY7oz-t!VanEc|D|_>QXl#X#H7pC5;i&=S6Y^o* z1xrfHh&fc#v9zs@bYjd1z?jZH0mf;zBcS1!yxgaYwabg?%Mr3i{FuKfEM2=NoKN>w zVT)4gF* lIqHTCxMroj^-o|6-@P2Bkk9lcS)ig2KGy~@ZnH-F zanDLVJ-Xp+`eL$3)aT8~zvQ>p$fPBFj?8V);%cGg0_7$IUk>T-Y~vftdP*hIz=15H z32&mQoNZT(@FcLsV<9*bFO&KvQ)Z2|^b@qdahsKkC8oPBzxMW_qK_j@7r+q#_x9^{ zyTQEC^v0QiigC?TYP{P6=>TSzt)+%3q^|mkLF;-JWxug;2y{LwZ%ff4`E@Vs&c*N8 z^ay?E7App{yS;+G>%7kRt+4q4_TaW zr+d4lwcC!Hp z{?Ld#IA8JMvS4I6+JsxFzy*MAA6I)&2)3cjat7B2lV}by48TeZdlGOSfl?>N9x1N0 zy_|Qcb6dRGc|dv{((eLctA(|kme;T?)a#f_$774M#;#WIcE|8Tx>ILot+BPfl*veV z)poSyT!JcWm*W69SyP_L{gl{nTxcg7NLsc`=ULH05C2wnuO@q3B1QWy@Tv%ArKx~ z(a;gt{n*95sl`Q#CXiC+WXd2$-N)ly4o(m{tOR%Q}^j zkPV+?VW-cO!l{)y{w$L=cyGS-te%n&#CCq#1`h!Tzm5XBlyqcg`caoQFKC+hI)*2MKzV8(*a=gSMegJdqQ{x=|%m#W1Lg8Jmi* zN(3eLpc)~ngs%3$t(GdqgAXM6@t|9a5)qkZd>LL)&wxB{sOK*6q_jYVYP6F?nJy@a z;dU|em(v{H;Q$jpJ~5a}T~-Lj=#*DixWN$JDdZl+FG8^Az7r3)V_qZ&7xI+RGjp}b ziv*MP>*Rcz&sn^L7!{LN%6UhrxMn4L#EvDvjW8YlfSqt;+zl2kRV4=JHDCg=ogqrnN@s-34pilcrqX1OCg5S-91$X3v^XvQViA zeh{E$t2%GU6@`yasD(2Ir#>XZ$z@ferv2bxrczolwkeu(#P2%yy%;%9CIfMxh=P>bTHW&_>EmCL$%h*^t*Z8!T#chOl*H}%N;yRylPCx zYyx`<`|#oXp~G`vQ&R)iii>=&?67q?M162pkMh!YY;zTS$>aXA@WJu zxHZ-4S!?~1B&6}LtreTNIwkm3MTro|V2pn~_xK@X$eAkgKxi?&aI>Flpc|>%w}KpF z)#rvzm98Gp8opzw6Ag2zrOu!qb9Pv9Fw40U`NznteL;LZr^_3bg0gdYc+y^ClS$F#I9KbfqrlvZ=totVdIuY~mtrI$}+SLb3%um}g@!1>e* zBK|T$z4AP!X3M!+E@4Fij5Gaozhq+9dW)$w=BF)=*2R+f{S0t4DfCxrjKd5e&JT(! zFH-C${p8hb_E4EhmmL8|i-w_O2d{6J8|`I7NR_E@J%7{veYt`DO4kuj&&fI!xhS4M z6f34cM84(FK&qJ=%3?p1+1Nex4x#^AZ=o!8GQav4 zYOQY6WNxZTJ958YD@HzBz&dk|so{kh^{#P#>9&l0m613PrUuduWIC4&xTd-XeApWv z53w|+y%MU9=N`fTLe&k#_x}Xs>VDs2;!)2 zuE2PMZY*t`EnRJTLy=b;uGE2*Mi~`KAEpXkb@E#r3cERuE<|d^FgUTNnnq{Af5dHh zVWcKD^`66NThMtjeUY%$ZC#IY*-rX>+J-Ahk`Waw`O~_AE+xFpHgDDG7IR9Ah}C82 z8d?BkBHq$AF>^PP5G8n`{oFpt3aM>$U`WZ9e93PlYiJN3ZH}&~M!nwqL#0gW`O6*b zom=TH%JHw{j(NWGuk*cJ6P}%V6sMk!>>a!V^+@8R2AHGh=S`|Gn_UHmA<Vw_!y9y!!^k31sl zWtPnBj!ck6*Kifq$vthjWri-L>b4-ti3M|r1HLs9ISy}nZTzV5P&#Hx$_QyuZtmO~ zf8_d&^e^nw#i^T-Hv;(K?<6Wm4Sq?zTwI=$RbZpfej84{krC~)6Jcci-WFU)4y(MRG)O38YKt8_Qa z7fVWXuP4<{YLrAka}ehqq&c##n4vA(E7Pbm&p6KNJzNJF+`aCIK7SnPv@fx)pv30W z`i@F`C#>zPf&rQ$MKW)@1m)7xwbX~zJ21;$1L5zc)@?|2C|Ne{23TW)XRVG%2#ZV- z7G)J?DGtnk0e!6Z6Pe}3-Ot)Wp5MY|QKlcu+tA=$8~qE%d)?E~X+!McLhb_1y$@69 zf7%KqGeFtC$;jkFVYFT8zqHtaiA)GtSG+o9$CI!R+vd_wT z=3wxNS=?Dj7@ytigUc*2=!Ku8m63&6GG^?h0pVDEnwH;|^J>qiGd0UZa%$LMPm|AX zt!OLvlZ}~ooJ{w7?U#w)pk-S8vgVhYhj+H>+?2m`Cdst* z#pp6m*W3Lne*g#taSl2zbS65joM;>5T2fIhuu z3FRDx;N7C|kynj(RN>v|WM`K=!Ar1TxOJo$TO58-@zJ)5ie#mP>^EWt73cDMbLxCc zq`Tg4-;rjyRju8kJNPv0xrMY;!PI)Ycaq*m-^8b&RI?J8;qe@qU4$L+J?C;ev&ccw z8HD#`UtFvk<*noPK(uz{7xEA6xEu2x<$1Is!HqLBz(98MGq=3jc8`@s!x`?akqt!l0uMWnlI7t^IZyEG60Y)fO-)UQjnt4f)POiIzRa}Wucy-u@#Y4q zYgzc;?u$|vMg}s!A0Nxj&u<+GGuQ$Sz7pH>{l4qOMBxm?tYU(uZyu)-9gP-=ETFYz)b3tw1$oa~zco6we1YMQx|ZHMsI3bMyDR zhwaf>>-XiAQdY~W9nabwS4&jJMVc;BGzXq|37;vo%JaMHbakD+SsYA;gV)$Uv~PXLmte8!ErkbQu=3h%@^HE*VMWrz0`*%3Wa zEb3FUm_ZOWZbdUJQ}g2$f-G|DtPfO7Rj%IH3Sa;pLfbOi8a@=e%Ot+u)`tP9*qwr z;9Lf5sN6X!NM1if`GN8R?Uxc5cG7_ekjL}gqpk4SF(YUYrx5Gx^<<}RqPi1{E6bdkoA?tg zafcW`g)!{`xwQ92UUGADyKLayUz&-#H@lAv|MFpLfg`>_H)KhhoV#&7qIjOti5&ty z8Y191vtFpd>Uuoai0z5qKot{P%OK-|G<_$}(*`QgvZ}@M?qQ@g>o?a3qNG(?r+>7u zfU9R%r0bE^xskL6{2n8QeJ`plBx|^H z)Eb1d^F-{Lh9Nu(ui;Agy&-t7W1v(t`ylXX@@#4=uQ1r%&UKOiUe z1iiqyoAvabJjv3U^>Yb;*;yw@pZ zvX&@Cn3wRu-x&?X;%>HVlZE)X);m6wkWJV@0OVqM{5~^5#ja^ffSAE;(U)F`7rTYj zhL$0)u?qT(P*3#?6Qi-#)>eB-{%B)(k@rXg15A0>Ii=|#rz79Fy~a-dS|DB@Q}Fur z>nbgX(l&G}eb+6#=a44Xwr9J1%MOBui#?91XcB`tm#7LXl~Nx0ZmQOL7N$Fmn6WOn zTx&`XF|c`B^FB%jyU!HKCqLXSita zPv1XW!C3>b4J#?)wfFyj9|%{8ODRWJT-oRh{(jcT{B-fDYoY%IP)i30sfjmu<){Dv z9?$>)P)h>@6aWYa2mot~5?cTO0000000000000#L004Jya%3-UWn^h#FKKOIXJs`m zaBgSpyk}UG+qyQ2fE4KFRe9=MH6;lW$N`o9Nze&cR`*uOtS-ntVk^zVUGUf_{>{ypkP{QrDJ6W(m#S?SqAjIga( zhR(gDpSEH^%Y&pa>Md1#1>y&=eAS5hUg2ibzrMM?;ikG0klQTsh$}dUfG6aIVtWJ? zBthXQUFYvR&aTw2(gVdV?6@BLy;nxJ63V6Y#|Zzp|MvhtFPjIHQk5A$HfiRq;AZ*v zbuUTWEGH5OeJN>I|Cx$W67I%}|0g$!d?r267OLyG*oHKFBq*Lbq?yws^#6)f&}j*9Wkx6#e5gUe7I}MOT*#| zv%5h>xq-frmK(&LvWgF!Z7;kNzki5>8ZN&9ufQONWvGUeKUvc%WDl3RID`D9u~Qxp z*<5?I9DY>NwD;sgZ0&-t>x+r*(=BdCUe=R)!9tJE5|z>OwSxTyDoYvmIbiH;P%~oy z*k}AoFvS)2eIF%{j+378+3pc2KY-$fLwk{mKPWBv;=0nb5bxaMQ`>&V_;WUq_e0E> zDwV=gj_-Q05HhRs#d%C&iu3T8D3WcF!OU|&2wBN(EofJ2ZnXU7xms||$SbG1PpPkZ zroBeZw&x=_x8EqDqX9$BmxsdGxe%(6OQ8?7Jlb~|D-rQ7o%*}N9}KG!-Eg@3&PjT} zrk<*-L4ri8r;NKX(r{OmNr??^ovh?St}e074Q#^J#GL*WjHbK0xEwbroqSxj7fVv{3g5Qy61iQDfS-Ll?+ zt~(uTmw5ge4#y$rAZE$=BX@>K}iip`TRbmc$!a;IQ8bX40U6K~rES%5p~FE5X>gDy5Krn5azYm180 zo4`zrIROep^T$ahURn--Yy~*KPa9+4g0?$x!a)QZMTJ zknTpj-1--x=72#hzPd0*bHvf5fqi&$ijlWqdAI6b)Cx(tbO9xgZb!)J2m6oylP5B9 z?NaE!IC;Wz1G4VJ?o(ZBgw?WSCc37hA(VU8+ihgR2P=-NG-(owQ<(K{^Wtar@TPu-nCYvEQF>wI${{z!c{z*dNoCsGb^siWAD8#U9CG%FoO&nuX!+ zRrjvZj9vdizIQ7lCT?Cx4!;tNsY$&A08K!$zfV6JnY1Bgou7X6&Dvu51FS883m8e7=C}5`+ueL|aEgqV!A;OkL zrFxW3G>WntYZ3j>`NmJ;;7@Qd&(&v2cdEAQH%7J-*8$=90b%rpJFrwP)$n6%Fkq2A zQcVmd+d%-%+x&n{em<2VtA4)P{T$T3(cM6&2N-CUH*ssK7B=Bgk6qm>0fG4{aOlb2 zNoMuK%9`IT?WQC0?zZV6y4u^`kKM(ji?(RUEOec9-{~^-`1Nw133|SZyilOVzdA-L z`Oo|k>lO6E2%qR7J&Iu7dv+m^B%i_gxFB>aHrh85l2E02(Shk`yH~~kFPw!0{e!OE=8>;ewqGV zq6pAs^zsaYnRO&0B!Rb6${!yaH|f@Y=qi-Fq9T@4S(Nj0bKs);#k-FxZU>eTjnYmdK zdn|8`id2MCQ=Q!{B*U;_SiE@Aw`<8l^M4d5E-NOJozellJQC~sPal#$es2!o#1_oh ztGsnWq)M!qADR3m9@uy5D57SKEZyAu&II~@dk^_vl#6&+QL!SuKSj^7h(egNcjO)@ zJlNS`isOYR&U;Bbv0?%Z(NLV{-ePHuM^x^=K)tA!@_q72n~$5pt&+OcI@nwyUgG|d z^x9kF{9v+jvN-h+NYi;povU&E~2gKbD2$R8nO)uOD@tdS9>*pm6fDo_WWXBIcI2D=;H9g+ zb?(<|B0!Er&iujVM;yk9->th6g5U1QJ*Eo@*mbjIZi|}D-|wAGe$>Mtj$|OJ zRAKT9I-wx?)pmAgkR&MuJDfy*Hw=j*izcD}iqxj(3W;_kIv||k1ywS&M|a42ne{9{ z6n5sW890Wyk>EpwfR}r4dr!3!Z*j0^LP)oh~7=7 zlHBH(U!wo`kUU9@@cl2(tby&ZIle9rsZ0v>P*G~fcYqr1HRctq>>tCTkFEXzT z*2HeHMDTOtSXgwE+%k5%YuB}i23uheI{yK5(jTi#CBM=)ap!LPSyhh6X7|#vG|$PD z^byG%0FD=0JKh6;7=eB)CI&uMz}60&BMP#_Ktvh&b3mF8o}maz8dX)4cm$jgu`e2} zOQ1KEp)e=ylA5bafNpmdTWi1Anm~|SNl$wkh&|OLn7Sfu$1{9jw&)k8&eu2qPeOqM zbHH89l13oG?c*>^*s@cj5+24#@IyO_CcKDXjX}{ZJN{hBd%wuQ9^=|$4W5qovxGX@ zwdDdo?qpE2l6QADTXpr(ER!<^fp!t$XBFAO`^iY3d)a%pe>C?+KQ~<1Q)Svujf@*F zMNoeH5gYc@RGOjKVDT^Ueg#BqsW=Z4M+!`2A7=vvyDGTBx@Hl}O&i7W0S<zj5jiU?Inw7YXYAtZwBMv-lG*p7gA;c+D!EGP?s?}X^t$CJ zH~-0WIuD5S^QRQ}kOR&MUDLMU6?nSfD-`(Wqa*!_*4Tf6%6txo65S!2)s9eP5V1{H z&bTY+kCuJeqe3y+){_$NU}mRpM!@K9N${&T&Dbr-(ur9Uyhz=4Ey zWvORhc|1f1$K=2?vfl_YtmYqUOIm|ZmzS|P2X#{;pV=;<310=Wa17BO5en8t<|aZz z*`PgNWGED^@zRv`hDMeK)*g8d09#74GUz;{DTboQ<S|5xI=#&Em=z&ciMSDZ3>9s#SeIMSZfv*7@5GqMZwD`bqTk3k zQ6iw(-M5XRhy^|aE$_U@S9K1NWLV*b={H8+x8KEB1D&*DZXF<81@(*cb!l$TLkTs2 z!6?7B7TpnO$#0pWGJ(Caq8>H>1d;LzACY8#%YLcG_(#*mc}RT0m*@z)+DK(#eQ*6{ zI+F&%`jo8_$Y)L8F6iJ_<%Hb2-`{Ud&Lnq2Cvj*~8@!eHYhv>lTH)h8NnT!;0m}SI z_3VR1C~v_2MA);u#ow*wH+S8vfqwQKcBC;IZ7SPbc0OG}&m!!Yf@Ab2Rx-}?q^f3J#}5fa;#`H94{JA-S^ zSMIhm$L;$2@Km~1c5g-ZfY_l25;>f;kjsQQKIbt~(OT3sdGuC;5QvE7p6$t1$eP4b z9Rj&F6|1aQCkDd3rR0Oy`j49Iy$5e0>xHzUMQ$ZSwVk_1%*#)lmD5=UDfmr+z z%lITG#;@QYcK@yrlAjSWc=ub5xRYe*za}_-c^n}0!7y1om9-P=WZTGRrJ&)b<%`_H zKT|MfIu&GtS2<#AN0fDXqKCtZ1GQ6Q z3&w1ru2hTw7W|x@XW2v;#8p;mB5tsShk z=;m-+dIlun<0<5zys9~*6(ex<5geQQuslhBBwAvp1b)vfy;`+<{t3I()Gpi_j3ka3 zD%T8zkEAd^oYaZ&w^9(>#sG2a^+}RZ-)?`pP=T8VP^yP=%^ImG9v|j(f|bAqEa+&wt$H{5&L#OeO>qYFpJa;KNWW1_(X~U8m(+S{lJi^Y zZp{9DDQ`^m(}hSXb{an={WZ22R3nN9{=|n}q(LhpwmNASq&y|e@UtTr$N+ejF8P_Q z$~)E5!P6`U5kFgNxZRq^D&De`LQ!~IOW^TMwC;GGqUE1(W+QL>gdl&W3wj%d4E z7V0k7@-Oy10lTF_pXnj5z0b(FH##sHPO3QUyR&{PKFn$#W0c2wJvYwvGz~R;d^fSY zkP#le#JH~iGt*{>_=Glvkl8)l3~M`!q{2f+}#fgwO^!*;m%1iC7P2Ou$Fy; zz(}eYvYPn%Ykj9pvl+}d+mENwo0KVkt`Je3X$YQVHOa2U0VBI9A;2{uVxlCC9hV-(+#j3knTF_L(oIK}di z&bV4;cIQy~xLYX_6q;Z6glTa^678wqW1L8oLlmE3m6Om_0~23`o;+O%)|KamdGgFU z9JrKvuS2Rz2JAU+P47^ z^JtkcUU)2*!~o7%39QuY(lnYpgjKcOd5(yItk(m;W=pmE+rf8QmecL4zTf{~$iyx` z!?*XoN>7n1eqmO`CQcmQbB9>INdTEY4lCmVXyBVWe4C6G0sz5N?K5=;31r&rGcX!L$JJ&_i7Kx;+#u zQRR<{@fh)f{tYcFavhNv?ej0fI_~2q#|j+_5E^Y#&mJ-i!*WDTba38IW@A;-DJ)rZ zE);<}?PD=4+*(vTIv**U2>+lqD2_@(unj5h0Fvc%GK6gk72&DAe+&m7xcb?|?AN6D ziHya#7oHox!f6rtBj-`;VaZCq#|~4Ygwl4YH$KUr{6Q3Y>Q0RJLw5flNL;5jXxf&< zvDQ0^2cA(6%Y}3fO+*0V#}A2iq72S6BxB{$j#5_ISc6YROJ+;i=66-H9rc(?L=$uW zi`RI7sB}#0gn_Tqz@@Aqc%IL;3@o?AK(vd~1sbW6lR_dxoWk}We%cm9jJsmzjjSfD zc)khg00I35!*~0`9F%BRWi|79ZNS*SjGIH2#D*wF0=r;(kb)|Yfx-&BMC zfnTrACS9Fs%w(364Oq5KxRQQ;wefKzXOZ~wrydn6$>HIH?zGCPOnk}6aGi|!8uE9t zSnAC$#k2^gdoWYe*IVKicI47-srqwYqc%JW4rjM&632zQZL3f$+N{R9VGS~6TY~vf zkmqil>V{^<9k>a8!Hpt&o93Ui^LRSw@5SHkxBK_is2LC_QCH~JN{`Wp2re=33Nw0qPVjJRmx>l5+2MxSDv6o&eOga^j z-$vN@Pl)>;y9Wi%Kv&}Qya*S>_WQ(<5uNuxyUqSk6gCgKI6NM9TI^*Y`a02(wx`}+#Gn} z&knfG!^^H@53&2M=5JqJVy+hQa*&)sQ|umnqL(w`eIlx*W$48rJteQRt=in{9DD#w z>2TPf0q4PvDd66KpAA^;c^E{#yVK%#usSagWn>W`skn7{SRVBIK_c`|2A|@V>|Qs| z1ynAMhn2-GFs2JYhSJW1B{Cn*H8Y@s1GkkBSn**^Y%ZzuLs!eaQ*$#$ScdWzL+y~nd$J1zbKp5V&McGbZPJ{ zh7|1u|0R`m>}v<#s*KN(|rByWj@xz?|pE1VvzEiQ%|H*eKUE@(d{ zcFfLFk@%VERJLYusV!7@S8*97vq&BkuX~5SjW5@qmKf|*QW;L=ak89-ESk`z2}VV( z3Y0g}axxU8>o)Y`y_+zCoW(4+AI0)BPiEp#_!sBml0m0Kx$A+LgCRXEa@X4W^Hr^``9!t8 zqMCi8G9#DL`A&$N-;DqMuj3acK)aNeQ=ihzC+tSfvOQ3{%iwHq7Z|N{04Vp#QOMgXLPJ4|WT8+GNdWbz7wHS@3VwLKP zQ#cw6d_UJK+)Q3Z4J!n@-Ws^8!S0n@j;AlQ8FaqLIqkC;XS88Di+k}}X=gr8G)q*W z2^RVqEcf#_x8AUX>c95AF(OhP_Awnd?rg4ViL@&G1blUYJ=-zR5e+-Txe*IPt{HZz zyDM&p`EZDTh z@|q7vOfCVgShvPqb^i&M%1(yM^Wvf$mRwqPZh7f2hZ`f~J0H*r*r{FqW+`?^CS(SR zjId(Yi7d6k{QhRN#k65fM9wtFVCMN;sXl@gRRTw?dym^OVz(PGL`GM)%Cc}F<|itR zPn}+U6BwM%OB(4pwHPpXpPpn zG4MDrZtz}~^TKr2@zd?7o%G6^x`}2bM)-#eBFTd@@Hn572K4K8hyXv+^s+QFsZ=BejAUOi zG`6~FanIqcGi;h;?#(#j8M(me z@!@iugymC)g26ta&n=6KEd*2tLJkOSJ+Ys6FRzl($z;0^Yo``Q%>B0N-!x!n{P+|! zSQ2Te?Q#lec+_Ke2ppHlupdp!8~1v)8~0J)$QZk#n5{rIT7G-rBAEA^+@MRSnNRn+ zgmlj&F^5kJ`pKMF_a(jOn@F2fWh#spj>nGQIE}It_NEw_ul14${TZeiHkuO1nU2`W ziG01SbvfiX;SB$EKGFKIq9)64_fq^DUHfKC)9A1F4|wA8=+uvY8=5>+T$WwU3pqc* zsjrY?3h8_lG5gQIN?@uzgpTq)J9DoP4cqm-To<)7z8igzcZ=WYeCXfn70Q|$ z0?X1Fh(VW7;vM}wHnhxQ?6z>wiMAQ>*m{3*m{*{{iQa|p2++Q+lhI;|>fQUm?gN>p1=j+kABhcLGGD7#)dpe}%-1%!ey@6nN*;ES=;%3YpT^ez?4!;$QTu z^OH2M;48<`8;O-Tsy_2ymhKMeWH9NA;TY^D*-t8V|n*OAEpg=wZ+hbDk)b?AG@o zf2NM=VBm z^L-2}?I;#wWIT$Df-{be74W>0%UBk9VN+rdD?r2kLJlIa=P8B@-dKZ#ep?n*$durA z%sibd*2hq8s*rI-pMo3dSO^AxoG*f_OflQyJ(gZmmtnC$(Tzx9H)flIrZ1ee+F_6x zAY|&!m5iQ7r_9+V{6bVN*i^5P`NbSlT)@|T*z1mY9AWOE+hu!hLRCW4i8F1kYq(}U zPG8c@eI0A3-t?ZJ#GTyu$qZeo`9z&()QDRL!&(VrZ!pJq!t+T$@k5F20deun6gl!(e?0ctTG*w-V`#iq~bbTCLdUpmh^aJ*On#DE8Yc zX`D4x4V;i%a`J!5kW5zww2tCkFv!7qA*kGy00*MpgvA7<8O-dXh@N z6f(JPyuf4wo~!G&SP$%5FRyTET}~0xQs}O$ps4V^_3CF3$^%8nW%s^H6JVYAKCEf+ zds1TpIcO(-A3&lQAI?VP;S7{E;PL5lTN?62U}&ViTm?cQEmcT0Rqspo0z0J&7`6w(&Y$= z!pr=vIa6cItBe8;+qZ8KdnKm!;?3U=4KKeG`3SY`Nn=bKnO`vn&p3~x+qM~-{TQUT z)u5kT?v+1u>27!tR7gMO6za#_t?K+xmcW;vDQ^jIv8cX8>Pb}c(9OUU=jUAlFcn{j z#_RYW$Mlacs8LPxWDG2)lQOGYtT{xmv$B}BRhT0YI1O%yWM=VGKOtpB?-;j37NYn@ z*oozA=XHvrrqt;bR^Wtk>WjBgJ;ua<1AIK9`#$Ee_G0N~bIhB8;1HM^6S3Umd0%c& zzTFvm4 zdB@G+Jb!Y9bEQVu;W7hJ>7^ikRpNMkfCKeBgCK_VvpBTB&aOkr>Mj zUPpm82qo4(Cq|3|18@dg-r?)B05IxIb^1jY&Xm6g?awyeMYwG;w@eK0aKw?!f*+g6 z%>5D<5$UV*ajzJcW7~vOO@yg$)^C(uzFL>)DQ}f`23tLoDjfG_7v}#)#pD@xQ^_$J zAz4zEPeDEuA=MsAy8($AboMuK!I=DP5G--|%ue0}xSw?IOJ&6jMK2q- z6*OSKuiiuI3sTt|LDUedjLhUe1CCuBmr}>DcIBBGm+f56$q+c%aiQ+zWjwxB`7_Gr zXOR_w0=bkVw_YAD?%lcsoTM!jCh30tq&5&3!c=Fw@|pVKo0c2I!w IB#JGS+dyW zz!ek$^OAFC6Ic)I+SHy3w*8*rcY8b-QKF1Yk=uS7yfwirCG$rt^Nr0%n#a#P6kRLe z6*B!dwCYkaBBO%P4=h1d)~lOu;s*{91cWt&!OS!vL|FqT#-Sk;Jsn^NLUB{mkVq;m z$ptAUl?Z{bIFbm~a${9kitD{wZEv85zm3jpNTRs2K;yb&^DS?KTM9iw5hU{Lahjx& zhBznTXl9NQNEl<#V-VUZit1#q0ujo6%(f8>iEMQlYGhuRt?bY91m1iS>ux%=yF-si@}&p$mx9Bkncp5;_S0mazWPnu!OBFIm5n><eL(RkCQzZ2HVV*y7B{TSJtnlS)%Nf9i zz86FK2K2Q>(R)BJYAz!ziWu7VRJC&WgM#S#Pt;ScS4)4g+>V5yGV<;9TvNT|XG;?_ z8f^1dpwPr-$JK>#gU2Ei1TZnsYe#=kk9;zD_v>ahCH2KnYR%Fhah)ZpbyE*T?L7O^ z->vj9`|~=a;@)gFsWM?^bPx_4JZ$UoUY&+JQnD4abHq4S=u&fYlgTkerc+Ov-u1L0 zp1jS=VB3P>VKE+h+HM1Vy&bUIq#q}B|0sRv}D{5J-AJZxL#tzAQKv=8)`i|XXB&M4TDr!KFC>w1`S=tG_0 zIwej|gZT(n7Ikx{1(s7C+W4KOB`eg^MdtG&rs;%3n20{eXaI%Vx@lK|V>+@NcSQeO zMk8;{Q1-2S?f8VF9kyqI8 zQ`N^9X~ItujPOE~I|vfulFvM7Hrdg8pGDlrX3Xe3OGoBSlYR?Hv=IrjMiCQ9)jnIGr@u07-|55&P&`5TgqG!lweLJE|Nw_7wT_ZmQe!F@W zTyQG!11eE6o@sOtv3T!x{p=%PFzWMtetne=)568^2knF!aC`;y%hVOBdE?ZWB+0u_ zbv2H6XX3~;Po@_;eKVp%%+h(DuU#(8Q#)A~3R%Eehrh(9q$r%ez^6u5AG<5|5u4as z*tRp#1*?^;77-fYe@t2Fe%HwDY-oQ!tdk#Q((PNWkGWa6H*ypaX|_S(aTX&V;9Wj! zzow&eTU4q@d^4wSz020?yvm`o6GoXCbpzfnUre)O+pAk~`4dgX! zK%J8@d^;7pTScsyl4cVx+r=3pO)Hrmw&edcus2#Y^_gaq1y|`((3C3|5zRxZx}Ns! zX$K{Ik4b60GQ$n`c)Mz{IFaYT4wcapnE-u;nho+D55c37o{!I=1gOp}U!KgkYe(Z7 zGz}kpv#m<-4w;7s)y7Q$51_V1i8*CjacH^`D~GB2h@XAo`juf%AWzkdL5#`Bn}`=v zne*K|2?wM5u3^2?D(WdQ@*;TlXEvc-mhsSP>tB?^QHiRHI8R!wWY7L0rH&=SNh=sg z{8$do9tmj+bwWDsII}aR+@?2`xs^MyM3^3I594k)s^SWFdGMI`WUp6vwC$5zxM+3) z>t5qVi3jzqL_?NMbz`fMZ=HNu(-ienpC~-*xd^oIIlwK_l?q92QQ!@pq$#2aL>dnQD#m=#s|nsWzVfab=CRsh}`4HnD5?CPv^mH`7yDqMKQo)b|Ylmal>jFLOg+^r^ zn>mO6{?&&^AGQPZ(l(q?{o0rw<7aFUF-Dt{9OGxmRwcI>*CY0w=ZcxcYMPH=FjUXw z1G5b_epH&(Ck6-QWcl zPW~n{16>|Boq~51Qe=kd&)hdwO~=#0BP9`UgIO{!i1X{I43T2$-l`T#W- zFIX3Mf*QkEF&kWR8XGw26FBoZfqv3B@ndDB=(uA`S?#CI5um9NC;c^K1;=|2H32Mb~Zv_MZ1IR$8Ruv`TrbrATV^QH(S%EWvp+k;IBEppT2w zzYWkfI{}WUNxtIDR#5!-_psxgt7Oe;2|bs*(B9J0n3y51-_IzS#qLU9Sy!>V=HYez zC7HRRRp*Jk6WPt!V=Dh|ccsSkE%PvU;exGg6K63NUmx15Ood!s?RuuMlR}6>vVR+H zBA+@+|21c(U3#e0duB35N^S;nIx^*e-Xg+tE;>j!AEIud{MF@65A z3%j|C`f5_O$DzO6DHX+2t{Rpc9 zfkifUpMu|VjnC^P@!iM(!_>gy8%4KqdhzFpp2Eve^<|1o=#1gQR=rN6Z&RHFzy}51PnN(?R<3?=9eJ12Cg#i=d^i(Ad|7E9?$N(Rh*zzxRw!&y_ zdKY%8qRe`CT^G%r4b!lJDKx9(cNScF4(IP?tO}Mcf2NjAkD(XB;pEmRAFF>)a2Kp6 zqGC5bd-HxT_`$`FxV7i4k|b8690a|nHoZ+&T4>gZ@h6yM7TGm*y@(LI`&-tM4)DPF z!GJrQOFhWt9+SX>FM^azuJ)c^DZGn65hx=8Gf|R<04^zm)*_EKJqUB3X{Y>K7H26n z8>iVXT^FK6ZbWS&Nw+BlMS9Tcyuh{hukWuto5XJI4o9*|v#_g|x6^F?MQbL3NB|)H zW+dyA$IlRozd_{G2mGT_rh8+J-|jClV#yqrWm#JJe%=>e(mt>Irk)Gb#*tm&44LNg z!(I;OaK5R8w}4JbbdT0l<&$ZF4!Oxt?Na{Fu2IrrPS*;kX_a+(hrC@+wNjKD2^Q_6 zjp6Uk8h&L0>MPA5Z??7UmyMqV6A5jS;T=scesq6oIQ=07`~Ic5bGxDoB9bM8?*u>tPTaRGsxJ2+-Eu>!Td{y&6+rl*-yM)+9QWsA^}?0crqk=X2!(Ap%ghZwY0#b6y-5^5l!|2iDW;r#+V|>f<0EnO1`{A2U2Pk}#e4OZA1^Yy zjiRZy~1Fk|h8XjuZ}EdNZfK}@Sy zo;+5R&+v$+aTw{NwIH%~p0;1j%=!I{71)-l_c^gE+h$RaMR(+ClJ9V#YwYn|=u>9o z%e0ldE;I~%OANfc;U)p`>N^2edvP19v0{@N5s99$i&@c0IQ-Z)F#@5zzUq@o@1Dj) zQeh;QCwrbvfq&Mg1rrly$<&yp<%#S(YPg2$EZe^G)9!{z57xD z$vUIeAOe@_>`c$3tAo4OV<)je#UaNO6L^XSjuKf{HE28x`EF->gf9y8)IdCne{;q^ z?44ZbY5JRSqh7bqFM-$|2yb`~IlmgjZg+F^j&C14fhV zEY7{+^Ygz9^6$S4@&^b|B+}}T93u%;KFLSr2Ns!vh0c4FzXFgV1uohjk4spfF5o{9 z<5@PF0D^Va)BBqnDge!fVU|n7-arPN)qcsx6gP8myGAHyPm5UxxIR>PVB@TuiG~fh zRks2L@8|gA9o@*g5QEpq0~j#$E&GE)@5_!Z(?_{aK2)=*c!qmYX-7&~ZlqLba0W;y zZdF#V8^2~CskQf(?hK2kQF-uCPOp!t=z*TpUR!AvQA*E;p6qcwbrOTw7?39?#OZ;C zNA)cMr^|TOy%Ne#17AE^bns#JEHW(jS=d2U&V=Glzh3Du5wjSx2uyyV2u|ef(?`>( z^8VtBa$s7u<+fdAdp{G25Ue#aQGfgChlPtsjB*iErCP{SWV)_k)~+pS?+bHQ1bLNV zYIrs!KDMy2f3Ct%=zPYT6$bC{wp~!x+Y7v>{FirO2)zM9?Yy#LcrT-0 zM28d{9l!zZfq35w(e$5gV{;&%1kiqN{o7L#tckYCx=g5mP+KLjF2j6N@nZVRPeSv7 zB~A9FZwzOoOd^ozDZ!2q$r6D0a-`?ovPj`0@yN6@iODk7zMQJM`=h{&<)+S%Tji_; z*NDsg7viL|AaQvm^FPCDDX~_6G87pdJ6qJxPa0l8b%Se3+p^!dY!L>$f5Az{BzR~0 z{N6lN*ryymSgtdUb7f6|Uhfj4O?XJM?2COVXM8svDv9*mp+;-Hs%-F2b*Mo|S0OI! zlhlZ!?;}Sdtm^Q!d#uZE4?qVM1i3oyhlCSVKC#K5_2p;rdL2fs5<6oXbxYKD2xog; zsZYq4DlMMSKObjQ!8eP1PP8$&K#|~XR%N!GbyApkU8p|yPSj*>aOb02rpwq_yBd~rChIqVA%id=Ysof)iWb4 z2C2@uq({>~-{fvfJUCO)%p()+v1I>IdS&&rwA9YVg>@q#^U-x3J+MKuFm~oUyvdFJ z2l7`A1v&Z7+2+sovemxq2#dgC7Tk|LHS=1E5)>SRLO4b3AsAgxNJtE zvbVGjsi*hY;}$ppw{6 z6%R)L2g?7P9yMeBgnw~e99xVPk7t!~HlE&fsTuDoZN5D9Lh9R+9^ht<+^QZmzm%`? zC(D$ST7f~#*>wJCAP_8gk=J~--4MurqDrOk0^;BD_C_E`Awe)0^~!tmEdiywp5jTN zJa)?CLhj(Y#74P3Z@_qUfeCWzDiSddIDCoiWV9G&Py6{#`$Z8!NIzL|7u z4w$Zd6hd@Ty~V%4?5PN~iegH5+x@?uqGQ<6pX{Iw8Z@y=zU688xiRSKvbs6rG}kJe z`H2f{?a7}k$oSoO$+g`QUxvGPqq>{_>68#i{+(K2nzx@JIT8a`JfFR~tetc$f}Pus zC?3xd1O;xC)_UV)8uSnV-_}z&Os>6dInXQHy}CZ@P%Yvg?J@;MdR$5IjS#NW z^>w|%&5aD7Y3%5p|1I15-yUkzDMyH-WZD}(?JIbKhBacDp39Hcx>?k2)l80D23{PF zHXQHUgp$>*ea@OX-$!FQuckcE)5AjB|2d94cmFr_@yECSUO~@mZBkDoMVf!wI;tl0 z@uySt9{;Q1Lm}{VjSm}ig$=qE(?sC;t_Bu2zmDHJjQ{b=$6k4K7c+jC6N)H1+_sq= z4QdP5p_Q&0^PdTSd&t{wcJl8>{%-9!;mh@3_;GPGDI{)%8+9c1d4m7Ra@sZwGPCPN z=B2}6SN(~wULZH}U+p9;b0e+`rX*YwzmS|ko8~_AH!VgB@BinZZ^wlQ<;2ZZNCsTL zn0&GM;-rt;7uwY_f9_j+gpK`Co9J72>gS*nREc)9@s;S4w!C=Zs?F=sb0GbE3zMu;Y~f7C`MjJR%RWS!4Zu#XNR8XlNe}6WpM1{*cQH?! z`)w^ZTe0t5o?#jSFHY;2LFug#S+4bKQ>Po{81tYDub`aof9h1kcQf9ASJ>WNUY~Fl zC_{YIyIL#CohheJfG);KPx)??t_+19a0k}T_&TNeefGg|sy_lph=^^O-9N{qeA#m- zz`l+&4i2X>B{dVTw@Yhh_8h&B=OfNmVD4?C7jT?X7I|UurcSRZIQQQ5x#5QG`fuoj zbPu$`=r5^B=Sy>K!OBoQY_jszb^~TAKZ0ZZy5{#Pkeo@Rg_BB))YI5DQO)17f(>XOxe9T_2aCunWMp=V@`gI2k%yUp{h9Wb=FkWG= zn@5qHn?5miH5%ynDW$PRf_flHSFV`R>73&uRcnIgHKv^Ab@J#a!QNfW_6VBNXN~ZR3iv5qU*;_Xi!Rqf>8!$f_I0~tIO?S13fQop}Il~H}+Zan^0YZeGc^VHiGmZjM02- zrStlXNp9S^#p~ivQ^CX>tGOo!LwXRu&B_RL8jgC)wmArhDG#ugI}zvWv(3$V@`T4! zO6SkWG<<1L+ekbDXpcu2K8zRdTltTA&d59DC#?!dc8FDs2<+bODTl7U3{3x1!KJ?Y{PC`5x%vFD5y{?FwDTW$~^FOuV((^gTIn) z6JNh0sv1tdJKB7_5Oe7U0@D;lngMR%LHycw&iT_z|6tSU`Ld&|AM;y#UN@{E4@D`u z&U^j95Vm*ne*RA#B7dlhFg-%-qm^dKTpq7opNh8c1@lDU%r<(KFMHQ6l`S7xe{w9{ z{)jLY?|lxA*>X$*PnHAxckhxo8s>?Uaj2TQZ%F^ibP~dlQrm=3*xjsuC@dmaM(z`8 z{6pdLc=6J$k^ER*(1^$`W;L9Wui}MkjM_5%n zBvurzXOYp5(_`f8(GXI_sq96kN&wd_#EM(f;fNx@DgWf@K7(aJ_4WT&INTx9oSjWJl#bYyJ;Xia%p>-&7uunMMqD511B04O z?6O>HcH!tvd=%wgi?b{T9>Q4s>=%pOVsTNtf^ZHEJ))>xZ zob?ViAL*Qyit@vmmyP%|`qenoDJ=}Q&^Eby=vpTzpxFLtB5!}S))dn}9^^ms6c7<$ zb3L`2TX%(LMj9&GbpCPK{bNOqR^7*Vm7mXb$K#k^CsY;yTTJ7t<+EX?8s*V z?TeJ6YAvzEzhp0ndayxsss4;f>s7BkP}OZY*x#Lr?eHzD;J*r=GQOw>K;N3izzmyJ zizOA$o}eSpdu;vK%j3kxHWw*`p6Rlbo{g=KMqM!;4QSnYQ2OWzk*)sZ=3|+Yhr+;v zU?H9r23B(5)!MK6CWg#52fjs09) z9GSi4OCG=^Cc~7r;9gczg2B2fVTwt#xd@Vy@#kDSq89pZ`;L>ou}8=dI$8A?sygFS z8_oxlF^U%04-V$`?eGlhF)e+TKFXg}EStZ{h)=dg#7~88Dd69z7W%q*o91j-v{|i& z!;oF!cJ5e=S%kkyQHfn7C7Lv8^yH&NHC=fL{B!S!)^EEdOZs7-P_Mnn!(*J~H!&TD z&Cj{!@vKG*EWfmLw0z+Xpq0avLHBvycVqgoW>YKPt<%>XI;3{y!lYrZy+=^_=E|r4 z)fu_?Zizgq#^Jrh9{uDG-tJAQx0eXUO4?=Vo$dxZUc;WAQo{JE;op{`S;DRjSin*x zTDr&e+fr*S*s4=;A1aA8$_BoGw5$;?R zbO?Myy2xljz_?1=s~CAH~{>+X|&N70=+8@E9K` zRJ&15x5zGlyzh?l)Fp)G;#(e5Vgh5w%Ei~#bH~x1eC(Q^EyRg?!$M@<(ljx<9J$lB zIPvJUbjRrvXwMu2e8~>K9MY{E4X?gcAzqlkeDAa{G)p|aOTzFB5{tkg`79=i?Z7cKw-ct12jWC)U0Q5;nwr&KcbVND@@3k#Dyih?)Gyabl&)$vWB8+D3|-t8JIr`Z5uGW znR*o30XT3sSM*Y}MdjwJr?1sanygdxvlT@qPxK_qh0d<0T`f>gqM*C{8M-~l4Nzh` zn9@Yo#edM@3A=={fJud3!<%JCw}1{9nT#HW2bc za|NBHREpvkD}AZYLR;nsFL&NXvPC_@zM=W&3q;;_23dFsr5#Biw#|97j7(| zI~BK9*$^rv4z>ruHuEtZC7!FA7?*k4dU9NZr1#OMOCJ+7qmNn71IN6<*Or= z9JK9}N3DEGps1mdihKqS3lu{g#}@Bo7mq(TfBTHh8X)ZoZ7!y({aJv+Ny=Zh8Fzph zJtYRud$e3y{R5l*$-c$`(dS$E;kLkY(nIS2gPv+W{hh_JN;!2aO6?ZRGkL1-m#?&8 zI^P+<6U+cvK&HQYG#yqqDQ&=PO8fLK@0eG&}9Eyui zuz@_o;YA+Eofi;l!gMHa;DL(SSvCZdB?YSN4ocH0C$B{{eRW7Z~t zEks389Npqf&lo@T;E`9U+RY=9PmS9|P#KK;UTvg8>%`9t;>I8pJVrSz8xgn-sKMm5 zfe^9z2M!ENA$%dBuvut}AU|?@Hb0d4NpTo=7|zdTfAiiUX}U@@%6Yl`~l zzA4!!CB+6rSYflu{XG{cerEE^akd>dBpEi17Pa_}9|xTJZLH-xivWPUCLr$Azl2XN zT+M8NGYVt&$Y3O zWy0K+zp(Ey1(@q!4d(W0yDb3&nPr}5X*Bv@c;e87PrbFwb$W?>&<$FSMr8Wwn-cmB zLqjg! zg=ZP&nXYlf{-f?Z2#k^zDl*5q5!9L^&8CiQz0N~m^{$l$( zD-{UYuwf8k?w3=-R=Q4S z9{-JrE_0k~+kSZl!7;#H7_c(jQqFSvRuZ$_*SmY`mNgcC9^lXrYp=E-5sWyg?3>;R z&!8sn`j$V?#iKcGzNDw~zaIc?6#ol7G!bLDsU2*V%)1-ni3Iob=d74=uanehiVXi5 zv~%^m|CJe_>RZIO0;%(dGi!NPZ)0=sGL|9mr~e$Z%++6u6=?FCGh{BCG7OEuh!Mso5b)W|mFUso#u}-;2m-N{BrD$GBxwT=Jg{~0VvD;6$JFXNbz+d<- z4){>`eua)4|cc}kJ@nD|1SvUf~{AjS=P*K^28A*2Kfi+Fl_BIuvlR#hqdnKJ=6It68J}2 z9=?{V5AL%bT)x`75!$zYgDtvV+hROFNZKDlk0aDC+e|Ox^OH(j!YNr~zxvA82(>x= z#AMI&JD$klVAMO~CquS&?9mIK)oIhq*Xexl7>}=+R?GDtkMLrN;99)qbqDpn>7-b3 z{_JTji^Q`)HJL}YK3iI$w9etI3m`3I6*oL~;;$h{zr~8hYlye$ilR9RLf!DPDP2)< zwCJ<^&B^?ZCw*?w(*dLsq=Ls7#j!9_-Pxxp#dX}hn}w3H$hyjN%YIz1Y__V-az`)R(TJGYHi)v6kGGTZe*u&uS{Um%)^tUmp zw`uOSkzT|sQ$vSSbvPfgA28To7EJ%=(d2)9#Ghrws05dCztIr|D}YQ(hAUjk5tt2!Irn6$3#|hz2TPR|JA5XWn_X90QCn+s^vrAd-C_CV zeVCUGpgfK{W6^g%WJFS;+2bsqRzjns92^grp74UV*O#L`3*&>i@N}wANP7zp^ z%=cs`LU$9p3hO&Tm)geAux2`CA#P`+Y7C0_Cwc5`qK2MxWuZGgwx(0pO&W9oQ6z(o z_HJH2QxPzdSv1@~nZTjtGAF=1KOV>%qPS^001%wpo}%dVJM&nxPgaT&tM{qB_MnS! zEg?b-SM9JUoBL#w=(=n|+fXRs?%vWtxV{yx^6(2R5gTie;53*d<89pIe@DM~4d^FG zF<9kL_tVWCBr*wy0Cr#!NJOxMYag*^76FZ0ei#KEMD|y6o_;@cgFSv?C@I=#vX>=P ze7x@TJ<2cOLz6jC{9IpXtumn82^HV7KMaW9^iip^(RK}f0OFmw2Ny=N??cKRfY}C{KOi=AXfMpH1Z_hz}7$xd| zTd&;xxAn>gngHUv2@`OTmXqkmnhElbLR{5hCM~s;HBzJFLIL86=6v*1arQxexVVx- zoD9jb|K+nDH!R!}ZG(<(J!4NmM`*h{Ic$vimqFKp!y-41Q_$~7*IQI>PVGHxdiCDR zNsc?W{ttIgZ=0QN==^`(J%z`^PAEo?5X)r#|HgXc>5o%!HVRTMOl>?YpQBkd%?i7W zVaGK)Z}SI3yww;MB`@21rZ-4gMXljNPBq?q*+OMHBXandx_dJpfbLF?@a)R1CXyva zhrwKXQm7ZOFTS)ylOPmFYha0odvg#jxozq(+o>qEijOmP+eKW79L8W1M6o^YMp;&Od8*t-KT8KkKPz|KA-eR{rc@1PrR|~Bgf}q zOMnkl+6V1O2f*+o!et>ANa0WTwEc5~gdIf_vo{3?&H388$F~2zCX+sDUIEx$8K5je zl9M%dQId1O9^;xdR|j&F|yHrNI`6F zA{17;3th5t7ID>4`#Q^?!edeGLUcsf7rd1lwIlevM`~9bNWCw3Y}7H2*Cn6)ciT?_ zKe30dT1lLg{g5ZQ(WR=LDW;hC>1FisYjKVIy)Ev%<%_k2RaVbJvqM||%q7BFPMx$g z2+bx6w(AIf#P`$^mFQ7P-5&r4F4PK-K+2LsSE5uY7RQR_Ph@2454rBdj-AHK>U)QB zLXK*)k{Yg&|eX%Wzr;}iJ4Zm(%q3MT4fhF!`uI%#h z9$o(Q)*w-y%`sEgd^`z_I*S+Gj?y%GfI}9mZ_&3Nv-J@$X`_(9-dUKg?spz|7gECv zc)@FPN4*^Lgw~_b@!>67=yI3WV_sPKIX6DhLknX_1Hi$Wt{^oG%RBe!MXq{CZK0DZ z6`NBGuSxe(G2LzaYjqLYyLT+>=4)0&YhjGqf{G5cwSFSytJ%{OEfGjuPrfH>^hL&X z_S~UEbCgNB*Mps)rb9I>Lfu?VOb}H5BF&^oJF6o3@#Dj1u4xV~y&GMyOkr?z5Anx~ zuOSI(cskH@TU^O~)Qga<&g6CRd^fj|E(P;pX;$j4R~adK<3h_ zXnB;4p6f%CwD%FqWez_rGTut+tZLk47^7<&rnic_H#*!_;j%tICv{Cfqp{6$gRD0nifnjvN7iL+b~+S>H&l*44#x{I|M&8B)Sh8s zxT1{OnLW`pZ=d^=iPLo5C5-XuSxZ1q(<7i<_9|eF-lf_e43~EWb%cnt`X!<*|e`i?6U33A2sNwK(`pCjt4Cbcg^v zv+2k%-o#OOCCJ0w9p_J=r=n#N^2H>Ks@-uWNO&-_%kYJqI8WOmmwLPkkNv$$jYci} zWcq(kJzk1-WHfx$fr$`j3bfk`&3P{4XkO4Rt9746i_$N^i7Mhu25ky+5RMy2DacMH zeG@Bwl#)*IYh+AtFU2)e7BBLE2iQbR@}kC&F_B4Zl(K)!C~>ZBoS;@Y`SfAYF_U+KG=biOz|Ur=hNUgM-rD89I~ zJIUb?{{yirU5I9nT1vIEvj(#LTt**t7wh4yLb*Dg@ow9eL$@WgFlYYx#ThHUyBGiG z(4zm}7bv^hrdX!4@X{J zyYoz#Ao5czb^2r^f53%vFBShYmFHY;8KK`c_2dDSMuA`QP-ADVG zI3?6mdTmq`njOzV~{zuuWX@yINH7=ZUN z%>`#w@w}3~EsQ@hM2v^v6?F9*gJm_YPP|<=5wxNcby3&PEilKlFK=;py;3NMQA{w1 zNkWt$r!U`NpnW{85qhi3ju3PuJfBg=J4I{(PiO=Q76&4;8Kz4 z`e1)4)Pq55cSaS~83(A{Tn@m^K2kel6!EBL^!|z(+*w6!mbPW;jYXD$*`}&044M$1~LO$4yRJ z+R0n8k@V6j;wmj{`trJ-kxXSl0=t?CkNHs5mY@>oC0ElF8*;Kox8NRo{2?}|cn3d# z^Vur>6ZX4{DogZ97ol+04W&fEEXR9tYK|48hA~o%w$;Cl0jDkV` zS7TU!`Y%DL9_%D5n>e3fOfEi|MZ==vAUnkC5Ni>?S2xYQX7Jz?!p=v1A>1HTxLKe_ zg9@g)*oL)xzAd%46iQPcD!%-=*3#GEsIJ(cD1eeAa*a}3?V*i0AM;7uL{M?Uv(VjS zvsQc8UHVW7l5Wlbr@1Tydzgr#`7tNv_rORl+PFh&Q-Ep*$W5(?(J4snVuce@3}jb) z?T_@Xb0;$r(<$z@(zmQ9XUIXQ2NSBez8;Dl=}@}rVZ56y% zdbxsYTJ!Yi(!w4mNr9R)oLQh1eJpLhJU*W2g-1n}Y8&<>!cMeo*J0&7=H2#6H9kfC z5)}CjNtuhAKyBPi7vNiqAg_v7D!QZmLSCh>i!zSv#cncEiVCQwdSg29R<#p*_D=LZ z!Y>VZs=mc7nkkiRvSr8S89ry4<5sXmj0V$v8!udXS;l~+m&u4-A*ISw(qg#WF~u({ zxoF{KeA|w<-aM&JT#0eDibgqU!Aw7Q%57G?WN%gS5+M=#-DTD`uUYqsa+1O(9Gn1 z(YIOo_{(xgLVCnXr$Dk62fto9u7p^FM66%*#}SIVIoQ;1d8c4`?NEfSic44qDcQ|`(hr8NV;hE)?iVq3HU$l{WdT5Phd z>EW^bI*~g_6&NTBQ@432?vR-;fo7cr>fDVTO&Ls0z&R_W;p^e{8oyDD`P9e2p zX?k-nD|~lJ@Yi~`On{wbvw}AG81yPBN}OESko+23KW$KnwRv(Yl4p*z*)UeTQ(L+R zV;4CuzB@oC#f*TaS+7%yaZ30!X17(c=V3=y7QWBm);>MwY!R>bqH2CO*uqs;{EtkO zJ7Bl=ewel?x`=(EOGn3Mv$oViZK<8NHSh1W+jVS~RbY-)g#4kN;F;h%{AT!^f3;K;P;e)0CY=<}jOwX7 zvIs@XX;jmRZaaxmi3ZIcGm~=F%H{BjG#Ju>S?<9FSCrV&%FJ~vN^-qqLo#s>n~Drx zUM3{me%q|Ox_KWUv~{t%{7#fzjNP8XYCq-TTk4AQ3FCX4a1Y6~dtzL9iG0n@@2b-n zk8hFL`O5E}iwQ9`VTh-EaW^raetvo%1MrO=!#ojMv^FyzFE3H8Q(#r}!N&x&#A+-S z|E|<3m7$aOraStCOZ%Z>&U{T6IWB4X0D_oGKDv$ zJ<^M%uR+68a3U0Pt}k zNL?R7fBW#guWDTj{t6;e=p^rP)>b-22i2awQ*^w{h-+f(*r6}(-jXCEQX4fCk2iWQ zcaakgJyDFjg@RE|N;9hU6t39O8PZ;r7AkPKiR7?dXH_rmqcf($#ld;u=Ovin^{F`v z)8>wsEhQSSVSp3oFzmFJHi70gn+rH!HuyFcu#3x_Nj+}Q%hnX8ZE5B>W+>zk;KwTR z_-5kxW{*Q%O)3%XI~P9nzU3>I63x`;nHq>CNs*0|L|0o3efxD_NEoKyGl;D~L2q&J zoI(%H`8bTeO)1ytBd5PO3u(bKcRB?J&7RefCUsE(trEGOSzW^eZledsFLiH}5mG}0 zGh(Guc!RQTAnd5$VyJDYyn{kYG0p_xSsVz(tm$0yBau$~+at``Mu=c?+m(QfS*GMl z$Df};Zq6Bo*>cdVtEeLvs~7isLvKinY>kkhK))?xn3;Djz33bA0cCL~DVAx%g5V9w z{#@bs$Js`r$BE5N!_{wjhuQFOa88p!bN7TvH`7>rVu{s2@WMtbEG|8vtTc2_-N)O;B#1z$xAZ5lCJ%WUsE#9rhDln0`=d zYsCHzV;C7?d-udOvcdv}O~A95=BxJiicQ-urSJ}$-jJr)JCKyIIg)q5$M*T#59VES zMI%g1ZrJwXpy|M$1PoP>DU_={|NO1rJ!p}uszw|r#GKhcneEXx}&Tl0O z2gl;mtdn#V`fXtChr7wOo2W!)^ODI3%ZZnAeiwBcee{|m`tBxUvdVZ|0nny^=s}$y zz4-$=1mSinETv^j5V$;x=6F6n{Dkw&oO)gpcDH=9I6eh`)tTA%0wHc4u>iq%Kt< zo-Xt$#XIgKib)A(kDaC7zluka7__@hLApm5WDT}6Nfcue+oGA)9{@#21%B64A)ugH6F3%xV z%%6s2VOu%Cf1rxGr@OAr_KkI`TadkGR}7JQwuZP$(SV|mz#{m}`U~1NM6b9bgM}LV z4U>b%L3V>y7~5$LlGYglej5%tdR?0mYfk4;rXg3AU9r~RW&^Db3(w}%i9**f55)%; zx*C<214eTi(r&5ufy^zj7yMb1QX2ubly*1{^1AeEryso}G&!Cq4vyg^i%;j02t9yi zhh(IICFG}m_*RnGF*FWN(wDzj&UgJp|41%>%lJKcAsCO?;@}{j{N<{Di}5Wr{$Cb? zixAroNbR5PzM4KZ@mi5Qad*~$q|5eKg>fCl0#+y#M04@1X-*A+&VX4F8ThA}`f0@7 zMa&uL_>0&XClEqIww;Tva4XPwBTrQMQS% zv|JI02kwGU5yWu`{AmiUf&&@we%F=OIdm}6>?}?}I9c`Z*&i--6W2`{_1j-%2(gpR zk+6s1&@9aK@N@y>Fyu6(?x0C}v4O$uX$)nUKD=v#_DHE&Ij5R>eI3?i-G zhckQOCq>%b+y()nL+B4I2t&oR0hc!9qW7%0_QPL*0#($_PD<`?!Ut*~^M>@i7dlio z(A^%8d1ouuhsWN%R(Sp%#v&I&8mVFZ>|dm7UhUCl9$w9I@MW~`Jrlt+Vp&IKUmy#m z(f%faM;4Udy;^V5vyyY=x4$OhO6>bN4{9G`s%=s<+_^iyHczj490_$j_sqEHhkw_= zEPs-=U6=A$T57_K_v3RdLa5V>vY0yCe($io%r&)ZoDCIu9*(@ z+q8BGuq`gbD+!D1Rr^EVBkY$+Syy{POJIJKEV4e=0#Eg&s?h$XJqEs{=BZczdc#bKifV{*)HwlqTK8c^rE_LlZm2NcLB8mB`Kb3o|L1Q{TSUp#FA z%B{}!ToLcrM;f;6*L1#qxI4D90;eb%w7vzMpRS9#sC(1HKr^dyYsT^UF7ze~a}ax$ zgH|x#E>-Oc%chE9UD=I28t$8uB@Q#O-=9vA;x25i5mhnf z=eyO^n;Y*5)y{A&gOPM&0Bpa0IgkqOI>o=+{RkaU5@K(V03tYNsgd4)x-%8k_;760 zn}U3MzRW@=%6(W~YCEFOI6brW277!MJ&O+%6RumGi9Dp3z`q_C^1xw8frk0^wB1_8 z$5S{s((woWw-CXe;CPm)uM*pFi=>WSKIR0u@Tg~PP7BoAZxcoa)#gws2%j;{ZxsY( z_J|vd(Sa0d&_1Yib=v64c0U=q0d3=NtN3W~-OA!ooMKP4-U~kk`n@;V8sSZh?$P#e z+c@Z61GJK(NP+euWC~!m-`m;r9aBnG2$t(^M%%7Iujb&Joy~`n>%v0jcA&Sez+Pmp zGl^I~5%=ADO2YHG;_Y>0x{lffwY>VSZ+@x73s8gT>bWG$)*{fh1a$qymNjnr zYJnnPH*-U}$8J>AS3}6C8BJh8w-(}1&LX70KO@|*3$1gIEkdsF_}dPjDx(49Eq3oZlWxP&M8QRc8|!9 zuK^ldo1M6P7oKFEkPyt>bNa^OJLte{g$3>mjI4yClBd)lbzot zYHwME6u1lyUm#(1tw^RE^5|n zRO3^$1giySQI24v$ykS4$Z(kzBDn}RnY~N-5<|f=->Z*-vz2H$|sl}M3kJcxK z27dM|P%Peiy07&az{JupLU8Eb_y_(B*4N9)A%Jg>Z9L324o!9_yIW%#4hj~c-}9|P z#ow^vp-JY+`C=rwm@v0ix$xiR_2>D-x4F-xrS{j16?7_)Sa@s?%#9xQs6^N0FFGLq z93)EDj1Kwn#vocMW`myh=`o*wpGak&eys9G=zSxV1(e_Gs_-gcFdtqY0GjmQ#Pude z14bKK$obpDMUu2FYmVxS*FS?OPVT2+XUt-&g?nd6_x0cBgY8t5lE^5TiW%$G4JCut zEHl!SQX6&n4cZEl|EgnunFW+PAy5-zy8Gwh^&h`^=l+n@r~st+$mST=E_`tZZW^Y6%`evj1= zkg>NiAXA473m;;T@?VhU-;ZZNz{M8Ia{%)3y_+oC(1C;^{%>gYvkf2~r;}OOP28Cx zPXgJLTSCiat`KQ+m^|7LPWGkNG9-lQzyW@kJ=CAGi-w(bmc|z5@BHcKUw&gyzxc&B4)ybdzOkrZ%>0c<{Vd~mCiSzjzHzDl zBSO{vfiP%|IoTM>%q$zq#Ax4dl$!IX22bo}O`M2Ltq&2^_y!fb0;vtEtuWa~-J(KZ zwrYP*2ly_TNmhw|uN9234ghx(Ij+fn8ViNH`!Az!GG;#^dhaVUz^-!-5a|ZBXxgaS$abbQ_Qr=p9B&3(!?}@b!X! zMh4X52-rNV$8nNea$_`Sp>q3_AGE!F>_c+M%+BswQI$mb_RvCG@WtO8$Au1&=s5n& z@$yc`E#3>HiIYe)qZ-IRD86 zkZ@q}IBO&5(0}?_0s)qg$?>#%@8$}M+7I*9)_3NTX#8$12`@LP7|7psy}7zbBq6ga zUu9~RSfYrHelfs%$o7MGXlVeh;oGCf^h@jHZ(ToRM&z%HPrSHFj70lcEjYr&fVcqI zJ$4Pwd;`MlUXJZ_M~>xKtxTkr(ET4m8Q+)AMxJn}Kz)A6Qul>DQG*5rrRQwtu5|Eo z1{uN}&KVOFQu=)l*m9pfUZy`5=Xz2xF8<6td7_55VNQC9nXRfHU;12fP(6u$!p2YJlwGFMkPpxqi+GehaAHf4$uns-X>F!j zh@h=93?5M70M33voEKV~steTK8P92?Gx0Gi8WPm7@6)pnlZ2RD+Sw%P@4+a-jVmDl z`O(K?=!RdS_ys4PbM7y}|L(b`7WXgV`O`q(qx%01^FMYNgaCWiK$r9EYfQ#5G+g`> z+@<-qq}>zd^GJ~r5%_CLHo18vC-wK?SkLq-9l<{SCC8&wd z)Wcn>;Kx6TtyI`%G^X-mJCnqo^^?&BIFov;o|h%4n-zAAZ|lGJ6UV5*pUYH`$|2hI zk6`P=e;QL3Fu#|}97-v+d)=$Z(h_wKp=W?h?-JL6JRR94Kh6ZK>nOMGI-O#ZxKYnu z%e=nir4HGc8yzn2T(rst>E5q5v>_M2qS zi5FqA%KUz!$-UOi7myoZ(#la{4(4M{fu7{pV9$i&UrhwCniBF*;Sa*{H)Z|^_{&7N z5>|)AX3~vg=x1C%qCV!ybjN!gKykczD#)uB7rzIk;U9R;<3F6xldV0QTCaJrCQOU) zk)z`w<7XNRml9<3H%%=$txVZPV4O`84VVc1BEKgI>DR{*RI1<7PxnW^WE1J_945k! zA1e%qa~ZwR$LZZ2p;?Tl6tvRstdMKx^H;3)N@jOpW?hso0DzmVOeWXkxuzpQ{;u_} zsXWMq=B}Da<-ph#{mGl7qODT33qpy;_)}Jox*Ej~`*I!&TKPE(I{nn|U%9858yWvm z{k=+wlHIK!5u6LPf2+Jc<$PII+0FOXnnGOf<_+&L z$70pWQogCmCD3!er)iVGkaEiEwAuICBzUcJA*hWwO)TasjLoeZDqkFt2W{l-LhDN0 zhdw`9N&c?=k%}7*vIf7)M2Xn_O%yhhjw_Wn5(V`B-*^9azgw7o^UBLqrtJw)uC0w0 z-R<)9(v0xV!L`dv-&S#|RN9231NlPnjlQoD=6;DOcmcWb$5(eIK(ZS*RixrQSaVo6 z0q*-Q<4NCi+QS|sCl1dK!>hd(oQMJ5(Uc_|uZ($K(fm-P)l88p`?dS-bybrs3+Cwq zw;VS1h91^*Ga^3Wqn$(+-st$ZH1qhifYH?~NY>fsooad{`O&uTvfhG`z#(Im+8^0*WXx=J4}<3owoCa4_6jtggpW2% zp#pzG>=b1~mVy=Cp%xRNYihgNcGHfDa8dh*iD_}&uCX?M*UQ>h^~|^_RyVtoxD|J9 za89SELUSOyt5zHbm?bKI1~5xYwR(jRzr2+f`S;>sxH~`Ujl8V1_T4WB1}b@6B(bW( zmFjduTN6~D`>$?p&7_Hs9EgFO-O7y+&zW+_SN7|d)z zr-Dw+)1&rbPep8|e2A#n>X+CR;%KJY;s>1Ozpy7BEMqfNPQ{q`1q=3{X8;Io%!`oe zbH&yDauAcH)G>m`oj!)^$V0(xm(^>gSkcvFq}8FS%F2K+&{~PKoUfH5vD+gHwU^9d z8bB#K$Gc^J41f2k()nYXleh|XR|UDTcgkvxQDPC-toTF*TPw1o$tXnSVD|?$kf-!~ z5S;*LoX6hgScJMcksOoL6B>T~+YdgOMl%YOZq20EL7Qg&xjG27wa!cK7ggG?=}sHnOv}X@LVvgQp&~w0RJ;Q@#G!N^4BPc+QpZ{^RIK->-gE*XZO41r z?DX<|uDY1sld1VL8o2`r>Qu`rC^QA5z4wIhEA{4>s-) z=K2lbvOhDEQA)l1U7Q08q?XL36@iD`+M40SbAAJa>1q02PJFj|)UwH; z7mIL%Bo6zA&3GQy4P_finD(RQh(QibZ(DWD;4zuJESFA+u(7Qx2CPuZJPh0OqS8G% zx2oq{9nYWf%IjB#3C=1OUdp&}5a^eGi?)X)S>g?q>H?5UKi5OCC>B~XE##&6CPGee zJ~~uf8Raal5(#2Gxr^>30wdm_Ikr=cPZ3nd?DTFwm@gzL`vaJmz3vyK%%K-t2bpQ= zw;aQz+DD1C(He2WZ1gfoI55c+t$_R{66&DVS*zG7X`vd{A_o$P1XFtRf!c$K(QjEM zl~Qg`?_|c-2OrWlR1+S7mayw6q~hrF=`5&Rn!ZohoZIPRA-y$JgX2Mo{w;AbiRpN^ zsl#BbNXMo&xdh`$@nJoA5-IuZa?QJ!n4LcUtyZURTU+(zs|+Mv)@C>IjSe<~<$v1< zwn{(MnIew~%1%_H7qNa4bx~Kgc<$4{`1JHd$6>6F-7Zwkp?4#wQ< z+JX9nJd(QxT@^2i=x-$$&-rQmi&bVg@V1_VlyayU4m#zUZK9ZroN0b8h5yu`)Ry~# zI>?0cWef8y*iTvI%S|UOIw<}totec=A*Gg*v$}7EY~MgZTx#KfMx6_9xdpgi_6HEJ z8%DqrpTFAttYnu3qFC+k=FXSK!v&(gh17`yfa9F|>i#8O<;=X`^-a0V5hoKcaB9KQaQ~z;H6Y9& z&u@M(jxWZ12=8`LzIniTOb-$Xl;FRWwbYxZ-X(nG&q$lSQebR#Ss?YG9>xqLkf$`I zIE6p#N-6n!Zuh!42OPC+S_Q-`Ae5!dNxxuPy#3dc!smR_@1@Q9D1A5f0dky8dv!D| zb%xZ0v+Q{0Lk9U)jvtYhruzHqJ_&d2uAx?t?PwlBV7dte2wk%|cMTe8Y1}tR(jo13|P~D=pjXm z;{eTLAG4-C(Xs~7sPu(%8gnPTO|P`+N07>w9I992{^u2KH&uQZQNH5dlY{+34L9$7 zDW3qjGxe2nN6#CT_-5PiA1O7)y6>RiFl2sj6g*Z8=e{lxKJ$Eci_w8pXdxe-bnC#B z;I~i_0Ca#*>GsP0&r&MC#jTj_U^U;H&K8ZF=7h9&DI**!FqwA{uLtgafY=f^)m}Jr zcAeaQ70o}l@5K5IA7mWh10!=6(Wu8U`;k96clsY>=)oO+;3Zcx|9d05^tFGzM#%Wp z$Q$4f)rRD>yEnAcRr(kcP>hx129a10pe1$rbJLHW8|`Ty&|j?#C|I*@UjDn<-qQ?S zR|atX-!o%+o3}n*9xg9*gDe!gV`X?Y6eQL=+W>I(dn;CCltdzOx z9^TMaI^4;i#)IyIKu~WAn?jOQ)5e6KYN>!M^RuXDlN>nJSlt+n1&k!J0Mz7~Hfj3i z082o$zh*WCG2hX-gmT{L)%&kiX3a=VfC`i@Ku@!Z8TdPnOP+fUr#%S=ZW_MqTt1uU zr!q{F^Ddhs@<2J{8$Ubg`|`&{U5z=XfabgMewp7j;M5;oVg@$PPu^7dvTOql7Dtc2 zm-x-$y*W}uM&Um@*7EZq75ch|porgZ{+2)mNuAQ?bM)~oXTr|{DZ3)lD0|NcacJDkg@A*2jxEsgpG-7hJcEwgukru*%y zN|mh6Pshf%vT0qR{brnDAdLHkTg_ArMM{qX-s=igW`3gh=l#5KvT*UIK)gNK5DuLIQ-4 ze0!s(+Fz@7{Se;;(H;obX5XodUW=y@Tt=j=R&(#a+wYOrLC=vIFPFogqRx4o*Ojbc64bHcS~D*jSLV@a{kB1Zz4A8|yQ~2UXo0GXwWT zK<2eDwoxnp;UF5Bv2zaJRlT>v)Tl^1CRrmFOBe%JjlZ@(haNL#XX(efMyCUg#1SW$ z$*iAqvgyXj!kA$NhS851?CnsDJ}&t9rWBy94XMFE0|Yp`+dZej#Q+RHHYidL7u@ap zhaY!kd5`9$LBtn6y#B7N2pfaa^EsN|qdr5iBJ0!iqK#$4e_8^Ft3Zb?*5+;S8v+3R zH};WhX6sMPer?xY^?xDY>t@%Z{#g;$5@$9-ViXYR`~`}cG2n0hS}y>qe>1CGEH`#8 z6EmQI)H>1JZqy8@9$@GVmN%68S@y>k3B#!ISDA?-ARxP^k*A}nMm2isd`KGy{7*hV zU^CBxYf?eS$uYvX?5#7klwR2glFkAX{+oH7g+Jx3l>GNN-?V@~4a7KtaoU0ZFS&MS zz*s{EtdpgK4ByEo2YOTfw6i~GXi(}Qj0CWY&ib+IW%c{6*MB82Bn~q6bZ~CaICXlH{cz*)ERXm+a0dUzg7qqA>tA8|Ud-I=sW@*3OfUi7 zYE@UcQ$(VBRbFXe_1*72X!2*cGXNekeg;><{M92qbkh~*54jTUlGS6spFaKv>7%n} z$rp^9JiHE96&jWHy}0uMF#GH_MI|r}&cjlYD>*aM8xcF`J-;~szPp)G;&>iOd7UE_ zX8vP0X=Ax|Y;1{VaBB8#WC#DqeBy+2ETw0|x3bKfzvSMPkHkegs!0us8K#?*qAvW0 zv7?<1?au21L-RYOaJ-_^(R6id1`V?5i4(i5rtlk2UUIw>a5}+yBztN(Yq6R#h ze4uLhmUiV$TVMj3YF0PIKx_PyBE(FKw0mPU@)8JRa=Ul|c{5DJA~VR28}b7VOANkb z`g_z3d%S4UDh{hEeC?Uu1ON~EGho>Xe*GKK_xF+Wi~vv10)y_yDIfR=qMYPcbE2j_ z)pHL(pY`MBv6%P`<^ID>cVwl;=jv}ZMW3lE9M6S-Ci%N;8!?C>K!vZxjRAMb@&Zl8 z9yE8<%*(3lvTjxVe=Xup_zw}!!n4~VF8<)se?k)oO7S&_ z1O@cDf8+(5+3#ia*&qvi7e?z8))(YJ!<)!`EHOTlW7HpU!mXzgaNj?q!2PCE^GuKp zek45uhk60J_$(s@*jd?=?;tUh&{qGhC;=>3nSIyUV`?RI<@uq#`pWcf_nF-C$6y1Z zoEqk|b!Vz3%A@96sMI5R?;R=d9McFn(QWtkqwZ>b0kqbS;C9!LBE5C+lO>SpyUDt2 zr~!zOyumjbf2#$M)(QZ7%YBVmZE<4nYqMCfPid1?C)*sN85&#+(J2jWT48NnCg zLg&Hefr>$@>q~g+u?YFyc#J`NL}}fJ?IK6PK0I{=V9m-=@9rB5g^@`!UsfG3s9reR zEokkI(g1syiYS-PQ6-*ays`-Q6Q2kT$Olc9_A;Qw zPzWsIHheQ1Oc?)O+dv+ZmdOD#qYORTnbIshTJ+}Mu=>Z`jEB4K=JzXajkY#X?co10=3ui4f*nBL)Qft;m{mG~hWX?*7;l)44-e>j{p|*;+VMC0Z`yhD zX^L}$J!cPDY24t~{P8_3xs{$W>7ZsX!SCb0WxZ2NB!ZfTI|}35A-mMX5SATj+0taC zOJy9uR|kHUaWg%S8#L9Wfj_RL>t-UREuAzv@xhXin<}uVeKQGs`DE*5=Bs ztotOZW{bM?Mjy1qb;2zp4!7uyUgy)>-ujIxWfBMsYMoHdhp)DXBhG!4aTCda`}qlX z(50Pt+KcVlBUKaS;EUrc(oSG6%>Z_X1|RSD{X)Y&@XR>(ic9(MK?4J+wRl-v!$ho= zFoLs23X{i8={;n|%XU9JT=U1kRp)SnVGcwUUE0!;61o|zMUfkZ;#d49A*qPDQUWY# z(3@ZZ))kiB8@B@)$GLJM#)FkxHgKi|tfZ)pOx-ws{g78Kd?W~|%-B&*Lik%BT@scK z_+xOGwI4X4z&P^M;h5k^SVt)vGN#V?oQ0ek2L24rcPG9I_%k4u0UuZq#>Ex91uO{# zzOHip#V>@4AGGp}H6W2bb%bHMz}Z`OwZzgDsWbD))g}Z+c&dWKUi(-@q~~p%+s!Gg zKLS<=jQG^9p@ed~mjRL~pd|U%6C9aD-?0eT>u){z2w8+cFMxnTTN+ZuQA=G9u|8u3 zUK=UpT+(@^a5>h}&w*08ah%?Nw$Q^bzmlBbadiF71UH}33;(d1;lSnL5gawptq*X_ z(PeU|RDktHH?92!N}Y!($RL(YAE25#@ObT_hN{=JXOg_ahUu53iI*3=R{q1}w= zdB~>{=YI;i(Q~W-Al8P7?CI$I0Na%XWRUqGJ2q?8dU@CfNvo`fw>nwwXVde84%8nG zcimSC-UVCohQRxF7HTp@y5y#ttfI_dX^1ed+r^Pf0lj7 zW{L7gz$`AX%UByLg!qlq_!YAo_dgrRzMaSqT6Z$vTT4-%DbUN3!x4hKfiXn^9gHN~mSiJw$aj z%_lhJJyHB>$zF`55L4V#R~rpRm#>gw6{*$IU>V%`@Ss^6k(uXdBW5u0-mDSu(&y*2 zMgzo!W&O#Mp%k}(F~JeOpcReTHI=nlut9_W?0H4UxQkv7e8&Vy6GS1S7_`1|GZxV+Q_BLIj(brbxvqTRL+lB<2U{5ZTu4f0c4O+Mv-5>9 zwWr^Jw=sIGW?Lr^WZU@|c`Xe`y>uy6udLd@+QHMhHa*RjjG}17K><2gyfv!d0-cQ7&_?MR>Z@k)` zP&sKL>!;^S@a-o=^>`+k*QQxA>$GH!vsSk5;EEXmUA|*7yyQb(n&@GdyDrrW_2P5a zB+}yLYwHS%A}YWG@ZU?IMoMC>Myz&nVynkbc(~QdvA}jQFiQ;YGd{$(hYOQ0BAeFR zIV=P7Yu4XX7M>V90{gtdzM-e=vxeP^i>6$-{TOC0GSkJA{%FzQfxd32@m+JL+|tpP zHDMx%3K}F(pw#Q`P=$xbsaK3~ahX)}=sg(-C$NB(pkn+a5oq*ED)er{5db(}-!`wL{g}dE5kzVbXRV^TV_DPA-QEsexB00|yM4m6 z^HZhP?CET|uB-rgrWZNhu3mI1zJ^R!$`#4bjo(MuJ1~{)5Hw#&so#SZQiX7T)s*t< z)Yf{KkDbmsq$JbsRx$F}<8TI*$D~8a3+!0e02q~*!hFS8%b|x+xyaHe1bU(x#^dmY z#3IY1tXszD*QLt(?mct=e84oP1efle0Yg(V!v^9lLpNh#dCQuEwi`VWKh`XzOMRXQ zZfn`Q^-^vuV9EJmdUE~0ATmJ88UeV$V1>k4C;39H20fD3hA2GLGz`-c+#bJXThg*td6L#M)(>Iw+Vshe-3+fqWE$RE^;-zvM%5zXL9R{7$df$}kuhNd@D%Sf z7|aQBS^>Na@chwQMrl4TSO+ktv-bAx+iyA2C$r8{O7XS;1)kkyBb*;r_PK<8P_V;$ zi$#depyoh)E;W=aB*B-}QJu||dp&<{^ISkHbq5~WDYgXfkB2go!pS;w_IO5U4H7b_ zLDJLn5xU>$qpoPXl;D()ldHLsY|Kf5je=L%c~ta@F*y&B8CtN5iR5(fl`#qhUeN4q z&X%;mmPpsMRpa$v)xe(a?FiexNyy`)&Q5*Q@mTqd_s@YpV;Q$Xbo@Vn;x|OI)VB+D z!&N|2cojb@V~@HJ-RV7JhJI!;VD==4qDY!j%Etxp%$jp#d?DQG>4uR9ewA&7mfT~^ z_QSdn#{KSsr_q$h z1TF^}a`=n*AC){eMH^ntDiW2h(h8|7-UY0mK5De|$Vl>eq)#&Q?OND<8j5$)tbJN7 zEF+ezERpDa@uo2*8R2JcM*@BDFaA!hp&3K0G5aBfHHPug_q~*&N&fHj4DI z#JF5Uy>hGF*?&78aQgPKb=xLLuZES7Pe3chR?3^{ak zZnonR#K6DIdyD_MZ3FI6A)EaW6KmO4>sd=xDZFx>do7jo@fNg_g-pZag%{}A`Fk=@ z=4OYTR0Nwky@dL^r@pLq#9|^OT<%-=j)Zz>Ss+B!1gThkh=JDXY~(?gtCL2KosU!7 z^1k3@>CB)KjAwa#o5GEAO_AD9=eg0vHx{)tnQN{~nj^Qh3h9V}0(|E@+dhGetZ*31 zb3Q`xDLM1=bnz5v&)nBi!RP&AJsP;PHpb}U;gW~CikG1o32kROSQ#kM=?EOBwK)l$!?+Qg6Q~$DxGFS6mQC0%5&aHNR;}Z15ZbSmI^Jt{S!)lAYPgu zGNX={tMUmU>!C_BgqS?tX7V$nj-|%P$Kq(G{uh`uwk;|2EX#>0{{GH@y8DN%0(~Fc zJIdlKc7yLebNC9D*FaY%d%w8FrnyyTSmPPe(r zsG|27I1jTY;}iLb$Iw2pa^cSJx_Hr0sNV+oMN<;C`4WQioZ+9*e3n+nbVtl-NY@K* z6`_1Fu<n$ zqiy|7rW57Lx|dTr#PEJd*3`?GJlQttilF@wyG7ES&3>{#D66HUa|v&W>r{&M`SxME zDa7y!Exks7QI*PZRDACTRM>IX;wOc} ztZVL&XefPXGWZN~Dchq+XvUVH#J6PeGkQ5@emQC`2hX&!BTS-)o*$MT^;0&8)v?#Q zYcjCuEoyGndWi2WVhi+g!lu$wa%sHoLYuNZqZD)qKRb?~=IBDFAK5PMgog%5sLhJa zGj+l8dAmbdoe`F^dZYZFb2sQAuS1=)o&9wBoto=QNf9;r9_^&=J>ugJ^-u1kV6`r@ zokO!qtTUo3^nKbkFRPWjOjoA$8|3nqe28gutM+0#k)Zc=Xu)J;5kAg){0?D>tV7~; zIW&0ADtdDiQG@1b1r_pR@56*-c%0DNfy{!t1RV@}Ad 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. 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 @KoDqGn@G%@j7vD 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�C_2pPiO!%02CAyz$y|&YtQjs_z(a9Onm|XV1b|ieCauwSUb_v{U!em zJn}lPb_D?dj)6erf1rqfrN(wf@{V@)PV`20jwW>9Y^?tchu+A`69Ima9SBGI2Ydlo z^8eum_V#~5Z!G})Qh}%|;DP!Nvpo4Tbnrj350>k^$|7gMTCkhtC&r_7<0DyYbzbW*|K>vq=^-mNs(D0E^2>^gh&%Y^tM*lAb z+n*>v^#&@bf!;|z`ELpgLa_hQg8fev+T6>ZT!9{T4D;{K71;7Og^``jU#|5>2i1r8 ze#iy%0fVX{r!=24dY)t6? zBN_i>0TW78%3l`v04@0E06{PW2G9}$Y7cBYJ!N-$6DOTN5&YjV^PeU_kNmB}|LxuK VQs5AOH8eW#tp;rQDR-a%{6B61DZKyy literal 451994 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

Lw|0j zKh)eSKCSXPlUIC->%aRkkkK@~586yA{bm)9?XJ?2j+u%KKE2NV`9J-F`JxZ(O>-um zU9kFp%rxWxtz7ep$siOQhlL%q;vWxZRGAkgQCqs5yW zBg_^|QxY`mdf zm1d2^F&EusUruaHiN?VRH3Iqf2L2Z_Uq&TzH+4F%-}L@-qRhQRCTIMBB4=op$md&f zYPjCdcb^R7wNzN4zMLkEn>yAt3xPhK?6E!37iRuW*sb+%atZq0nO*trme|MzpDroX znSEi5l_~D>QnYz#lOgi)>HR1tK~dE&&_vn1xpvRM{Wt-rot+a9&zKnJQP7sPnNmG0FPr=`I*40MySV>MCXl-O?lHi6 zm*lUriz&BVb3AaP*c5Brd0d6ZCPj2~D4T+fXFx=Kdx#T0vhB*d$F z;q6KhC%<|);r)sD`)gBgJYa7lf+bXU9FVKI{4mW4cE#2V&NH=aTNY2F z@)kW6J66K7En0uska$>p#t(kdZ-$s^^K>u<{t)#JnLNwR}DbAYDh;g1m>w1XZw z7^SG4;Q3L+Y_@XsTQGI%JCoF-kw;gw*v<4rseXRt&wQ^9h)O9l@KC5Y$+$d!SZI+} zVh^lkQdJD^xTC7Zn20Q+Y!BP-Y#sP(%%xN+=o?a%ZE5_XeY6_i-{k=f{&3R5B~kSz zjS7ze-h+#@yj0|W!ug&oh8Vj?tCQF9x~D3!Uf0psDOPn}_RA6ok!@-4GFzFxqM^^V zM^sOrlBkK_t+O|~#YCYoeN1ad=pH>q7?LHrE%cUg5IKNv9G>v3;0eiBPZ-%w^h$&5 zqIDe-S&nmEWZ_!-qPtFs0^>^55^q2pBAs&68ZQgeKhG}8{A@brgY-H zK@{nlX+~NQ*3B}l#bwbZ>uF$T@3{{z9eVWCZ?vgPM~Bzye%bu&{V(@lqxa%)5gHhB zX^#m%<|-|Slf+x#i3>uPu%G`bCxnn43hZgoy5ru)#r64STjr>~uiHZc3huOV3HP5@ zwOm)q<(Kieq^7MNGUJLPYfhi$+{(S{AZkKPJrH0~4K|PWq_ZzQG~C}iZ@-q4dHU{C z*$ac%r%e1_t6%zec^2uUL1q@iS`E6xeJa%4hW6c2v)a)QZS!_t1I$3-jl37I@C92 z*lrLI7f}H)7)Pt1T`R_W)Wi2BA>1y&Y-76Lr-EVs15YZ(u>6(u=M#V;QdVLzrRQ`vxr*GHye|8=Ag|EiYkKd4xH1({}_(?D{aV?xdKa`?!e)?eldZ4h8dr@GieTb)kNe^7R z3(t)Q0H5F zSjv2f#X~R9&1paWn7#KfjQgaOH#$SQmz|ILQ7PqQ8dh=^PPh1vRXN7raucR1W%`6- zUFW8cj$%WSj$4U5Y*nJ$4$x9qAzrX%PGQPQ_6h@qh?LH}zZgDsTL|!`YE4pTD6{8? zc$m$wEg|5E9W8E_zn#wBQmdD{ls>akk5iabZhbC!_tzJ2IQt6*dI{E8GK+&r|4Zb> z{8?ay{dRC~-Y`2+U)59g7>*0~lHXTPpJv{GxmjVAuPg$B?pCEyNx^VeeDpJA8^QyV zlK1kt=V=Om<33-}B1xCVa*CHC3c#)my4*>(oG>&;x1~IgVRW;O_}hlLN^cd`8V$^_ zWXPB#Xp%+PbdZ#6EVNlr@@|xr9iK4)41i~mll>{&+O&A73MG$*H5f+nm9v!zrvP%e zUR|2%%>rQSaGzmeDm~4$jkliop|qyngfVh#;brr6Ej;eQ=sF06#a*;J?u@{`(EZr!hE$xux|d3eTUgr5f@ z{NZ&rXtT_ssc11i4OM zB1XE!*j`GNn&&g`8n{T#h9`h9pi$mXeXv*+2!lijQfa?szwpB%+i6tyItg~a z)!-lRIM#!a78ge(edeG}E9o{efb!M>Pf?b07FyR5N4+C)StRhYd1&|}>>wVd`?t8IvNC>dd8-<_p}64ZoH%(mzinRnu8{@2>Ed zgsW}->n-xNuy{KFp@z?Sbw;WwaGT%7ViZ$K+XlLg--*%x`OBVLq-#KU`SD_wbuK-8 zp?(;6G`);0VMk(~T<7bXm%Q>7b>*0B3m_=7N2*``5{B^zaVub*K<=W5C`q6n5^n)2 zDMHDz6h^f)zBt-xfRMt0Okf4_K9VFn2LNW7y119^5+p}zJ)!}ycEdswsB1~L@K**L zN<@v(0FGkEgO+WOuGseXF=CsTOb8T3_7eG9L7u3S7j_;fL%SI3fV^OR(^i`sX!l&n*-ym|#CmDYDRMDOlz}s))Lo z@??9u+Adpm5!4HxF$`_vVV;S|L)@49@a~NCug2 ze)Cy@di14pO`wuf9ni7X6Q`=9AcuizP`6-BvbN&_N>{)LQlC=;W3CxcL3*JTNZDQq zBEfMDvco6-LivPG{cmAj9tU=l5b2b8*xu2?wr(8|@d6V(dHX*1vC5&p5O$_e1&SUvH52Qt6tLw)l;|HGO$gkI`qI z49Z+81bL2jz+PE%afXlty`nYY^ZVEw1$3&Dzp}`mRAyt=<)^&6yi>;Sp_<uCNzKSAdF+9D`oDd`H?_7@XFUERz3D-knIm{V4Iz*hK$L-#TbK3k+b3#f>f$hjyw6kmS5wF|KKvgp2zGH86i2z) ze4Dd%fZSd{j%(l?U_;^D-<^i;W1rLIVnJG_YEXV_dR`eySKFDESc(DjE%@z^%8Ncg zurmj9PS7-X{6tSNt^QZS-OIWDOC?X8Lna?6o+!5f3|aBbfPBs36DSWfeXu@WEMG&~ zT=)#@1X=(hLEhR3ZDbuwX-dA8_;ks7hcy&YX#M2 ze~RKj_7`*uGmKB-G=IdBtQC3O!G*?2u*b)jntG*heCo$Xz$L+Y=-I;*sqK3}y_G)= z3?8iQ^(^lU<-cbdN_AVjM(+cGY&hFw|EsQ;3R$szsslh(>S{=Gq22-H=ChEq8wW6q z+k#Rv#M{8c#{p7n&>PTNW<|lFR0y5hykE!Rt-38R*({1L93aVu4d@|#*ajFdudE6y zW2vEB-=!=LsFqxTEvt;D@HRSKL@g-ncT^EByc!?A3DQ;NdLWRR0W|?PAo*W4a7n2H zhIeOE2g>(L%wpb9p4T#P{t>7o=-%(#PS)lDn4r@{`!#_e0$7x|VE$ym zD5(uc0))T*iIz?~;@Yw73FNb6*x9!Tgn#?HoONrA^|^6JE50p|*Z+2t1SB{u`{wKm zJR6#~*F5TKf;?YxWcAn8@O|)0_UQvAU z>l-}IwPHK)`Y3lrFXS_bKq88G00*OYe+yU*9JqjSdurp3PJ3Uq6D^qqn8kh81NC~n z#Y9-p-N==NSE3ESf;02%77*;aK&%De2sr6M%ZIlmybD#gf|?s2-8({f)gG$dq&5Nx zd|K_wVZtFN!OfGl!X@jo4m@_ror@GCoj2_-a^iY!Pxi0 zuZSeAq2*!x_Y;8V1JIf!MnXgu`N5@OQ_SO=8p;bm=b9il0f{RCFGLIlxofmg zsK}i`TEp-XC^HYKHpR8ZS0`}v21s$xlZi);;=ztqNWKUpai*~AMDF^L_|-rG&?U4O zNr3)60>>YWycSoqHrS?177gT=N52ge$h*yy>CF9Llq9{I{3u3_67y4~NG7==7fYEC zDN3~_#xM){EaGJLeJ6evnSe!$+XnOH&^o*7*EDICcux28;;Biv037uH2&|8jWW29^ z2G?n;KKY|6o#Vwutqm21o=s)Uc16zr)C_9CAF%oqNB}qP3_`)fbRFcOPv0LFPOJeR zX?RQFxe&qpKyB-NB&hkw4mVnpF7 zY3L{ZauVxnW!swjjbH6*PG4)jshZ?Ay|o(cU|NR&$vCtO4Ne|k#6bsJ{YhG7@?Ne0 zo)2566&A|GW(P%IH1VzjTfv!En$>D^<7a-rxX?l%=^z@2N((A8^Q;0#DX!n3wRjc! z!i0zP=niv3nWr@KKDTyoj99xEN$gmEy{s8e-Q4g+ER9R`B@ITJ490VojUA;`v`1}= zl@`tKEuC?3+a6JXyVL;*B}lt zAiDbC9eye3Lnik$xTX=aE2~<3v+O9#8hT3;s?s@u|Nf(<#Nf_!y3$`TZ z9YW3@)LJhwC<-JU@A>PU9`TsZ`l-N~p%ulUY;jJ`#g`ztyR&#fNaIYJx1zv70c!@EW5 z1I{;&=<^EiYfiVNzqX$!)IqKpO$yGQN^hs1E~A^9YRr%2I&z1+D{D)1|GgjLBt_FR z-i8MrWMBBw0SZGSCRK#CPj6BlV{J;Q14M7arbyVN?@fo-_CMs8imJ620|wD z()AGJHCtcTsVNjaxNQ>trCvU#z?9;;Gvwhv$Kp0(guKlEf-t9Ij%~P)>pHZ7!(pw&Iie{=m>Dj% zC9y#>>4^R<+qL#0HP=opd(GZ^d8Fw7Apli3pTu2j%B_C!Jj%TXqJCc83 zm!qEd;R(#$yDW4(1GE#Aqy9BhU`kcUdrNTo8ms9AF}7y&wkp>sdZDX&45uq0GQ?F^ zh*>=v<#xmcM4BCKUzuGHI8n3rZ((ut&Ki}2Hg7+??n#7n%2rNp8Cqjr&e~~4MFR<2 z?nmzN(yy3&$i^hpiVn#He&r$>2N#$gEb3L;p;s37#*78WN1MjzS+7S#PnPDmusIVW zL`GH-eD#?-)n%#nbVE9Ew_^}^t#_pM%vNVzgFRV2eeJZq3C~b_+7V#Ml{>9p9aa08 z#X$EtUFIA$rK;|DsH6VkF4;s9%z2^JIH_phA>u&I$0T=+t1kCwh^x=elyZ)Ey+Sy~ zTWk*<;`TZ1n_9OK^J+(+;cG5dn(1^3G90-v?rF4(8Ru)c*;nQdOy<-2cxEw zcAws%@OCaVLF?;dS18mBZF}(hMUoZjE@(cPSbgM~obtfot9Ta%K#~%xj zdSvpr{PCY1^GJ~v%3d_kno29W)3=C5Kg2I675-Ci?BCFnefn&p!gYnvL*Pxal@tzl z{pu5kJlj+6Brow;9aq?>Ipi zt&<6u3M=L`g9VwZYEuUYzMbk(I3W!h75FnSUDasP%x=r9rl(X3Aeuo+9oq|p)Q6%B zeN8g9!(#|Mj_K8M*8w_+Y8|kmKwQ!{iGO^1w9idO1Eg7u!c(sUkFq?@->wua^Q&OQ zQU+q|AoNM!k*1r1IeN{2zdK;M*+3^^cQ1(D8qk%j(@`ZGQ0ExBdaR;zCx9)_Y(ycI z=dF}IXTN@h6db9 zzuHyccBj1~5Xn}w6_NB`O)u@<0@Dg?KnOnzHDG%>-P9tpF?}_1n@XAP#uua|k%`#5 zrg^C5aQNXlXFHdxRonpCW)-d_y)5O@qN3k)9mvjQ=Y)Gah{YnQB^aQ^o8FP-H9+=0 zl=wr*xNOj;iIt&K1BdU#Q0Zp@nTOda5cZbrY&8=r0OI4RHf##ym|9GWxA&4*2(7bj zG+=SbdnsNJ<`pid~LXe)sIT>Iebob)booj$6{TweT z>-V!%kb^rUCQi7LGy-XT=LLYPo>Vq&)w^u3`(3!H{)(E4$a|h#XLUCb=hN3j&IQxJ zM;f^RaaxY=ov96GVY|9PIpgD*lP>|i#o#{FlQ>HD0kEqkAtef}RPdqDl?nL-nU1d` zRs{J5qe|^)oME4Bcc)vy12xkm85!=zO2+$IQk@ z`HYSL2%=vMo;~siM1cgir?Ws4tQ}EH_h#l|uM!;nW|j~$S6|%xreUp$AHdq}XYMxA zB|D9hJ|UCIaKYLS`)YQhN`#X2UeT;Cd|3&7YnH@ zq?T?ZuepBtp?0mOV0L>wg{s!4$wi#_!Y3Ez^8k?Qb>0ku1sWZ3J+d`&0#dnSJw9Jn zg0*pYIYFU|roD%zz;n-Yk+onitslKf$2@Vfv-@gwJ|8IKd=%}_oPmt^BuaVD>D2-kNyZ5hIy54!wd#AJeB zhir(Sk=<7J^p=Fg2159s+Y2(_7)_drX6sM42 zw6w6ROQiBcJHQoWDDG?*a}|~hypiv5y)?qc!xn3`BW7jXJ-My8<>|e(W+BcsB9wja1n6$3bA?&fH2Vv`xCX=MGVBu;px(=Z zH^*i6cnLFA@L@|jZ_6+E>vYH90MOD9XWpf3o>^1Uhui*on-J|)F^vx-7)}1SPWl{< z5eY~16-0DsKkJ9|fFzQXuPtOSw1yfUbgd@$CoBV$C;HqYGu=$P)2^*f**orY%nC=>${k9C3WIm7!M|p9}`W`w`ziW;NTwwm@Q2se! zA^RER8;g--fQYk*P{-o=A$}stI*WpxW2p^Pb-heSIW{$O*))VPrjMi_X*LGuBPKTX z?u0-nsf1P;r16}c9agCttv%#9&XsYE-14iGNRizRThPdzk96`fjPk3H8oA<_NFxLM@+YS(hRSP*=0GlRw#wPME{etS^9EYmE^9Pc!GQ1`+mEG6bRRPI+%@^)D(tZ z7jVV{1y!`;a;01Z&nXcGw)I1dM-Nk4Kx=_~>|N5niyyNOCY>o?wTrao7IDElmMVgd zO{E5<4e3paFUiGXp`_*vmq(x&Yk&Qn?A&S*`bPGOL`eNX=XGG3+DNb}zbDB!;Wnp& zWSR3PVF&pnyVGYQw)#OW!#sSw2gL?m)~OQj|wKS1jNePUj zZgyoa4l>QDe>|x3C6wG=MK$v*d9PP}x+yf1t6d1SMWaDlKEG|+TQN3tK<#>2z?HT3 z&F{w{S3C8DT#8tz%bQ|Ki4YW7+}${S$hQ-Op!&&k!NyPdP3!+&+beJmHnS!?qSJ&Nt z!1AfNOplU|<34Yx&Z#--ku{}jh1QsD8mdg`vApbN)g7ftWz%iE-4vYL{2HNOZ>zqs!k4F;FSVdZ;#Z`~IF&YbhvtuMOvi(p_*rt)G^x zX0~39KKO8hmt1Fe>0*9zQ;~i&g`fAVNJ=|a8G&ulwO4qcO7`sNBkK41TSQzNHXc47 z9ZY_9Ej`Zj)`7)z&c4f)B5QdsGAgR9eZCIoRaatO^uf`sJ8->q1C@=B z)H<`~^K-Fr?u%b0cStZViDMq4d?KAec1)=EAg|)oS{)v!SsLM2o54mm$={&Aa!knY zqN$%A9K(Fsh&9Yz5Xd-zb>|+By|2B;=P(y4N^A`V>8%#jxUtB2^jj^CfIu%Ef8*mg zrgi91d1RB+h5Pp1-A#qW>jlaH0xep(+9n+3A=Gyczath(l<2U2EkeZMRkJIIku2By zPVgqnbwplSo%}cCA@#gqxp{68)Xexg)Ib~KLBfiI&R%eLZTRhDceo})ub%<9dJN!d zDIs})Oxo*<8>Xgs@@|n&*oLj?5DIg6{c0^og@#DaYp8b` zaS8*%qcu=m*AYn2`&M^DYjt$T$|6Ih;^4+qD}E>&MaF`q0Y%Z9D}rN5nKUMB8LE7L z4ESeZu9sD1ZCwK@I6b;&c$RdxB>Bp67k!~eyHGF`{1lbY6aI*jBcs&Fwe+_`vC>c$ ziflK@q*mfc%#H)D16SdHO3MGU?C0ilQOYb-9;&hNY(IOSB$AZ$4e&mEdr=NS8#*OK zbu@>6#JGtqA8!C~DUO>UAmMczK-xOI2_)~XnkBEy+x+c8uG~ixR+Q?kH6x-7ia>;_ z4n{O*KcP}yI|J=!y<3EOcTGZ$vO)gVO8`}bvX$6OFLU;j7c0S`kOxKniWPtUL5`>N zGb&2b4$366=|8C)P%!@nW>2f9GF6};GLI9-N@~Xo#8B*-ErPF264+N{cYj=xiN|Zi z@mZVM5V+*O@^sIs2%BJa{m>fYr}^su$eWO2>Y;Gh0u;t>_+23T$%9`%9U)&e3aAhp zYTfwWGvt4%|3SUEG1DE@asG!IAm`j0uFM8K+VB?uR@2kwK{eAFDy&a!EEz!Yw8i5< zN-xq%?Ip>{j{!7#$2u;=LY5h|k65DiUz;yJw^|WiEQ0hz5gwt^WI$IY_fG5^u_Gu> zLOj+m52bN$!E416-%%;ohwT1@ME(NSABun|gQ4j-Qs}gBY6+Egf!3sTV$w5@^6jIZ z<1G;1=J*5^0=nqyL~zgAzdRFW$<((kaurd(HHI!Vf@~`kT0!-l(bR)2c6jpsTob70 zwe*B9>PVX#XV&@Nn#<2|MkTsFmPNh53+oW<TJ{!+XQPnl-acbv-U9k8cggi6{tj>VDwe+Sk+1lnV}e}VI=4$4EVMM;Y{f4 zegQRDR|kbxz-4(MBN$5A3_;86NoPyv(aMeENbV5f@gW$-W`)#tPjU9`rhh!PhCB}z zX2yx_b9cx4Hf!u4)5NX%a~TO(QX zS55G6RCMvdbUEftm3%;ldx;t!$&0RVzuA&csRk;;&Cq;8U>itNr5-3DrOwVqas_>Sa=LK_Y$E=ONguq6M$3+rEA{kUG^SF~tBBn;ajT zcf0RQVZA(#lJ$lN-&VAK1MRg#I-t5_^^aO0&qYr`slg7#Rcv(z(hi3iqdE#mBLfxI zukHLt6>u!cJUARWw|3_B9n4Q|Eh2p*y0?NHX|pD6wni!8t(kA;QMzq!g|4m6J7!72 z5$ejVyxV)ZP~k;uuUF8_ z3?km`A(+8j@8w($wMFkXY(dj}GO;2ZlukxBV$++PF6xG1czV5dp;BqjE&h%%$hnV2 zbz%M90%>8$cYA7V8SCM(#2^9FavB?^_DAy0TR;TWIUs1f@znKU^c$w=I#3?;qbT zVHiyP4Bi5P6`dWs>)$qaw}*K}WWfh>L;vc$X{VZ75vmXpaLAqzsA#@kgXS)ZGZ57? zuuzlMfg(7hr)+gy+HG(0m^KV~#@u9W56c4%*3481b5BUV=Cxb3VBW>V^F*(m6d(#T z(q#}~?j9_5HH20XKiCl~amHXpW9g6P?|o%DH7R;W=oVJld9RlQ1iY1FX!qipWD?9x zKFcyR)Dz$Lx_Rd5ar#j4>rffb{d7P7l^rD&5TzFT#_WJ7@!o6eXVcoo^;UaU6ap$0 zR|X3&AXi(6Mu@NNw%7Vg?aGhdV}M5b~ubLcC{=>uoj(adrDl$y)@1nmWs zU}z$?SEibLdYtZ!aBRG%aM+GHADIu=2UtWXdoem>dc-!YJl4^UkbW-pN|oxcXIkP; z{TNZ9`sU^HX9bNEIDaS@rW0)z1Dnc_M;#t$3e2_qrfrA5wTf``>2(y19Q zU>plV?E9aH(Q)2hbr}N#6URTPM6AcJnpJ zb|GD@q$|d_INoU0g*#2N(f$hkQj{Z8p28DgTj=OVT%Ov}c|Q8o%D~9-dh%5eP89k` zr^>IJi%@!ZZr5|nI&hbz;u8!+oE&>a7SOye_L|6?j+XY&`6J9C z*z!(2`c&>yGOOq*uvkVY_&XOoSSlf&ArHZb4R5w8*cUE|a39JKblSSrK2>9=CYcJL z2aJq~Xr~|(OD_ts7drlKyHC)Bw>|0fd&4;{%%OHga`+!TWus#0(m}5^uQ}vrpfsJg zhzGI#a7lYux{#>dYx`BrR9dy_UEyPgLa#Y)#XTi*f|UJaSC#$dkN1Bc3(!oRtplRN zr^50pQQqB!LW|5v2T98L>a?mo4GRvuA>(4ad3lrNZ39N;BW(_N(d>q|SJ+Lu9rtgt zvCv8z(5dIt zv*u`M;qaiyAkzP^Av_{qcj0%`HEzEs8;OAljiPA+xzoU)-vw z!?dIUXL;SIW3l}!BPm9!tWHgLvv^OKZBmL)+)aw!BRy*;MICR5x#5vgho{RB8~v7p z&mi>9(;*7=StDH=BrJ|yNf;!Yqk4ugOjZ5|Kqs3HBVh9}=uoOKszGA?JD2fcMkk70 z=*iWU_V&xJs02kuT_X9E^@!rNl>p#~V_Oi)u*&ywRMMj<)!%$QvR$RDd2VXErPWQo zEyJs5LVoa*0h@MfsiqTQhX6HQe7BoW#~d~gRMFOdL^RfC?k$seNdFur{D*yfPxi)& z@4&SI6M#Io=@44#CmI@bv*^y_x#IwddJGzqTq*hR4`1}R3Z;hG|Rdp@j7xM22@%zI^3h|$US8&_? z@Mlnw<|sBrukdt>{8?PLL5n;*(9baA(gRT^WV`p*izLHi-PZaUcwE|_V^#u+^uckk zO9gjN{scuXZN#lJi-q$bHjHyVT=xR&cyeX?0dG96SKOFD9e}uA0SotTI}^vS!*0o%nh;=HvM; zALg@fVf)59?GZc0rThU0F1=?mxoY|-11i)FU0bu|Y48svm|j-GPSWoDaq*1@JWcA` zWhquaCq@8SV~wEL@;#y4EZrDG`1M#KUX#*y$BzOIvhwQp$vzG!e};z@~%c0MT@@-u#X4kh(_@(GSejIj){%TI#slTd_d^9+Lzy zC`5fl+*Ic#NF;rEi<4oWW&pK{Kau8ynND`JXW8@oabrO=4ydA4J>JZlh zH3|CSSUD%zv>08hR+Laj(L9uYQ$kIZowfyx>G+B*Ht@~E&7-DpnysK>ZpW;^T335? zp7n{b&_a0@tg-Kh0E%$(_<8$HR^I-`TB??(&(`kd zf$7)TkPxl&4ERkQmAOL?3I>({TEUZlRBB=JJlN403bQJ_ZQZJ*sI)(l)&Y^V77`E! zCICanFSc$xwDu5@@eeiBpzU-dM8UQsaz1FT`mC{+S2@U24M9wbLEx_mRyLGs=tUfVaiU0ZX7#f!^7d3scEXbDVSG!K;^7>-tZgJM3*s&R9mTu`jO15 zkcO^NxaQ~cp=eQc@O-@b)AJG&iwuh@>FqLXK1X%N!X{tEHEuA2VIOg5QZt$X19Pp+ zod(u&I*)iJdR>(H0FXj8nekS-vq?vrr^Vu{9?{gv#feb7W86%`X=2fhc7xQmZL_Va zqHQB{1@>wFk^9O{+t#LsDN{@Z@#w3Rj{t{R`Es&vQ0K{WGiNedIbEiUbGwX2XWT+1 zM|KK>P**|^|3d4OLkB+I##z$cx6X3TB;?FF{nOzWM&3~6K5fh=7x#1-fQ3)0^{#tl z0gTnN;+_+-GzOYy8riigl^B4;gyFpt?4i45StAc45*Odyuz2S0=eY$@6 zP%_n`f_8T>@m1L6Q!t6%5~Z!}iz98N*qnwe!<#f!sKy1~(EHX%`U52&ihbO#IX1Y-4b!yH>Nql;Pv zKC7Hc=+chuuJv>bPI^DU{1B$JYoAS~(%Dj zaq*tR<$apxUV^zvY|DcjeFA`hW@5{Z=_ySR)_VfM#2I)*HEE0o49} ziUGrFsdlwRX2dz~fdQc^Djjl*YydYYJ9yRZEp2OrXI-G*i@h-|Rm7tA?_7~fyyS66 zIrK^eU)Pmbj5n9=L%)4BSvhJ{DeP7fsiy`~+@n65e|fP@%A_j#L=L`l$CTcMR5a^7 z0hfG=#wW_(eCGMKI3@wo`g?m%CgAU+b3C__FlFFNc4v+@@A)z#cdZ+boA|(YjAC3c zRC}={);x6F?BKcFR~mTB@L4V8=TVN%vrTO&J`d^+I}YDqOk#+8Y02z!Pv)z+Q0_u- zDLuKlp>@a>hKH1r3nP>LGS`z~C8FA8=h)3PT;#Q?8TE-+C(729D$*oGY@L}QxyYiR z^@vQL`HFPf_BcJP>w%{wnl8#`_qcR{voSl`MvrnPVhloy~&+{Z{hnwA;N%QICAjMKs=ds{^ z`$543dYO-%gV(w%r})@=OM5c*J@epDR??^#P--6Nd8$`YCqq^!#F61POIi@LWu&=Q z;E89QWht0E3r`N3x>A>Jp70Z-R2)ebJ`Sv(Yqv7BVfk|d2*>Bym@7k^hoqo+T@Lo` zd97J;&H}9EB_Ba$mUT8E7q`c?e%@&Rin?QiFE=CYJuKT>9>#`un`g*3|9xWWTXK-nkJTK4N6e{8~_6{9o zkO_}EUZmZ7;~m?=3)b7_27=y#=p29sidl>cBGy4E8PJDJ9PV8%1tGxtWi%(anD}z9%=jF7{ zs1uG=M-KX?QyX?bkHa=mHIruyRr@dC!_u-bXdL9Y^ zPHJ}v(itHBoVjHIWQ76WX92f=XJ=xFa~1+K1dAuuFist@3gD`B$6bZV@*6J&e4WvK z-tlqrv6%FMvH)+Rr=6JbDb~~})?}=KR!HB@fjT%AQOuGyZocgvz6U&?G1Ns3unn2F zSSL+JQsu<&FEZ~ocCsFVp)6hfcyH#)@Tmfp1l;sH8L=}htf_VtW~?308m4C7q&iO| z=5$T;jhR2P8dI1^V{UIKceVxxcY-DK>}49^1O2{-5_vq{&>H zOBqSLd&mIoP~l?TWbR~+q1_2E`pxDlN9MVV%;lZvB)#Q2xH@_IWSB<1e2*AC+n4Gq zSSVIT>DI%v(AIhTwv{w2w7wGVnQco!OCR$M!IMH^4{dXbScnVqwm;l1IW(brMIv0x z$=>RAMi}2yey`{3Y+oLPQjX6^lX_CJ_iKvj7J2ncac#S?W8C&a0YieV`6j7Nkt9jh z4bLu1tuRx5mn`-s237GDd1*^OIy><7qBizL0Ok0ujm9Ag4291)#7d7UZx@*KFnZSc z4inN%f37ahYGB4Znorg`M2s=c6=zU$htA^oxz+S35jYvY8W$zH_rAp%QGrq{SKwoO zFgTo%lww`S&T}|?Q5&s5sV5WFabQwN9tP3v$H5lS<2)NTON@X?xmoK5sw}*q3tv4Uq(=-g- zR0jjy>B&X{J*hZ{GzD;=PM|Zt*e4UZd1l5_s^owY)N zQQX3&nJh<_FGlAQKe&j*rM=y4@{H=CqCnk-NX8<+39R)(+WBZ>chW2}hsPIlSX+)M znihP_*jyQ?@;-nmL8vmqbC3T4_0oV8F1pOj z?1E^@r&cHwCxq!q>n+)gR}t&Y1>Rykb(*g+`NRvDN|Ff(TxlKO%`seORQPsg-G=K6 zNh+pixqkQY)I21x&a&BELTtUfvd4I1mAPZw5+3Z%I?ny_UX5JePTe97X88nfEk`C#lBIGDLDE-(!fZbNN#8?hV=t~7hpJvgKiABPh#MvIHn=ax7MXC_ zjpLqN$|XLftfIiQlcG-;#u=oFsQsB=?B?iYSK9g051VdkTTqctKqTUMKdz!pC5#Kh zcc6SJpxhKdw<7S8C0AxYhWYDm8l$q0&I#YB^X6+yG>l}pUr?bQ6jVJ(Fg||ujka-#j-77e4ik0^BQL*m65>@*%#CVj49AAYtra%6F_{p8$6$@FDNy0`wKj?xOK z@#8u2;wlQ{2iwEZ`$R-iS7Wb|N4z0T_YePKy-){eR z$p0U`+bq9r)NI?#r@|4qZ5!1@PIb#skp*ekZ`2a?m59Xg^aO z9>(5lH1o%g70ePfZhYQ4iDm>h0+FRUNj-h1QI|XO=a;TJqk$5?eJaXvNN~iOcNWDE zlTwbehl|)*2thCY?1Qd%6ysI6O+WQu%jOMYY)(MUGrCml8Xq$qi@a!R6o>ub=Q8X{ zK=VCfRhn}*~VAQ6= zYt{d;pSe;cNlkHn4iN5f9{sYxWJZ~HsJG(-f*UjMGNxu8XqxmT^Hk~jNd9(tsm9x( z)kwD7@lxcDaBT*eJSt9|=Gg|INCZQ>{kzsl#NIKi^SG0y(CTk)*!{uzXM_MD;5;FU{dTXH7QIpOpKyje{s%AgbUtCv|rF|IGh z{bU+)K2JOu1rSCKzOrFoA|c|0-w|AcXGfvW;nNarfQG6}U1l}4=dh1?C3Szb2*uYo z&Iq?nmti3B+S`F6q+9lBxV|UsmJCcBVlxeaM6Fca8%>KirXdsh?foZOx#B)>nx}VSY;@l_``w&_lF&c4fR1e@&xMr z>hhxDNw|!pJyOK_Spo0;@_0l*O5}zobMJ@dmzIg)-qy%^$Uk4}Pe5C-@H>JV%f^~6 zJ_5(~1;&MVawwd9$dT;K-^lj+&lWT9C;;v@OJ4^DTA@|yVtoJf1?NEe1C=rQB5rJv z1*+oF%Z{SXb5oeUn1}uSQ9ggzzkDFvhPKYsX2yzst&if)&4n@8m_Mx_)i{m^+4okX_FRek-3i@II0@?V z%j&s$)$WK|HeHxa`9GYe7tpO5!

G+^bkHfPV`T3y0)Gh4|RDv(CC0e^lIgG49g7 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 Date: Mon, 18 Aug 2025 18:43:50 +0100 Subject: [PATCH 475/755] wast: added defs and explained abbreviations for clinical acute malnutrition categories; corrected category order in 'un_clinical_acute_malnutrition' --- src/tlo/methods/wasting.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 71f0d89c2f..9995040ae3 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -169,10 +169,14 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'un_last_wasting_date_of_onset': Property(Types.DATE, 'date of onset of last episode of wasting'), # Properties related to clinical acute malnutrition + # clinical acute malnutrition states based on WHZ and/or MUAC and/or nutritional oedema: + # - severe acute malnutrition (SAM): severe wasting (WHZ < -3) and/or MUAC < 115 mm and/or nutritional oedema + # - moderate acute malnutrition (MAM): moderate wasting (-3 <= WHZ < -2) and/or 115 mm <= MUAC < 125 mm + # - well-nourished (well): no wasting (WHZ >= -2) and MUAC >= 125 mm 'un_clinical_acute_malnutrition': Property(Types.CATEGORICAL, 'clinical acute malnutrition state ' 'based on WHZ and/or MUAC and/or nutritional ' 'oedema', - categories=['MAM', 'SAM', 'well']), + categories=['SAM', 'MAM', 'well']), 'un_am_nutritional_oedema': Property(Types.BOOL, 'nutritional oedema present in acute malnutrition' ' episode'), 'un_am_MUAC_category': Property(Types.CATEGORICAL, 'MUAC measurement categories, based on WHO ' From 9544b3ae11bf6693cea1646a39e67e0378609b54 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 18 Aug 2025 18:53:06 +0100 Subject: [PATCH 476/755] wast: declared nmb_of_days_in_avg_month; explained adjustment of monthly severe wasting incidence --- src/tlo/methods/wasting.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 9995040ae3..d57f201943 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -270,9 +270,14 @@ def initialise_population(self, population): df = population.props p = self.parameters - # Adjust monthly severe wasting incidence to the duration of untreated moderate wasting - p['progression_severe_wasting_by_agegp'] = \ - [s/30.4375*p['duration_of_untreated_mod_wasting'] for s in p['progression_severe_wasting_monthly_by_agegp']] + # As monthly incidence was calibrated, but progression from moderate to severe wasting occurs in simulations in + # duration_of_untreated_mod_wasting days, we need to: + # adjust monthly severe wasting incidence to the duration of untreated moderate wasting + nmb_of_days_in_avg_month = 30.4375 + p['progression_severe_wasting_by_agegp'] = [ + s / nmb_of_days_in_avg_month * p['duration_of_untreated_mod_wasting'] + for s in p['progression_severe_wasting_monthly_by_agegp'] + ] logger.debug( key="progression_severe_wasting_by_agegp", data="A progression_severe_wasting_monthly_by_agegp adjusted to the duration of untreated moderate wasting:" From cbbb577ce2a3e5d42c2fe5aeff51f813d51a73a4 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 21 Aug 2025 00:55:53 +0100 Subject: [PATCH 477/755] wast & test_wast: last wasting onset days set to random days before sim initialised based on wasting duration, and within previous month before incidence event; use rng consistently as acronym --- src/tlo/methods/wasting.py | 142 +++++++++++++++++++++++-------------- tests/test_wasting.py | 21 ++++-- 2 files changed, 102 insertions(+), 61 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index d57f201943..5fb9ded7e9 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -269,6 +269,7 @@ def initialise_population(self, population): """ df = population.props p = self.parameters + rng = self.rng # As monthly incidence was calibrated, but progression from moderate to severe wasting occurs in simulations in # duration_of_untreated_mod_wasting days, we need to: @@ -312,19 +313,42 @@ def initialise_population(self, population): under5s_index = under5s.index # apply prevalence of wasting init_wasting_bool = self.wasting_models.init_wasting_prevalence_lm.predict( - under5s, rng=self.rng, squeeze_single_row_output=False + under5s, rng=rng, squeeze_single_row_output=False ) wasted = under5s.loc[init_wasting_bool] - wasted_index = wasted.index - df.loc[wasted_index, 'un_last_wasting_date_of_onset'] = self.sim.date - df.loc[wasted_index, 'un_ever_wasted'] = True # categorise into moderate (-3 <= WHZ < -2) or severe (WHZ < -3) wasting init_sev_wasting_bool = self.wasting_models.init_severe_wasting_among_wasted_lm.predict( - wasted, rng=self.rng, squeeze_single_row_output=False + wasted, rng=rng, squeeze_single_row_output=False ) df.loc[init_sev_wasting_bool.index, 'un_WHZ_category'] = np.where( init_sev_wasting_bool, 'WHZ<-3', '-3<=WHZ<-2' ) + wasted_index = wasted.index + wasted_severity = df.loc[wasted_index, 'un_WHZ_category'] + assert wasted_severity.isin(['WHZ<-3', '-3<=WHZ<-2']).all(), \ + f"Not all wasted individuals have 'un_WHZ_category' set as 'WHZ<-3' or '-3<=WHZ<-2'. " \ + f"Invalid indices: {wasted_severity[~wasted_severity.isin(['WHZ<-3', '-3<=WHZ<-2'])].index.tolist()}" + # set date of wasting onset + def get_onset_day(whz_category: str): + """Returns the onset day for a wasting episode based on the WHZ category. + + For moderate wasting ('-3<=WHZ<-2'), returns a random onset day within the duration of untreated moderate + wasting. For severe wasting ('WHZ<-3'), returns a random onset day after the moderate wasting period, within + the duration of untreated severe wasting. + """ + if whz_category == '-3<=WHZ<-2': + min_days_onset = 0 + max_days_onset = self.length_of_untreated_wasting('-3<=WHZ<-2') + return self.sim.date - DateOffset(days=rng.randint(min_days_onset, max_days_onset - 1)) + elif whz_category == 'WHZ<-3': + min_days_onset = self.length_of_untreated_wasting('-3<=WHZ<-2') + max_days_onset = min_days_onset + self.length_of_untreated_wasting('WHZ<-3') + return self.sim.date - DateOffset(days=rng.randint(min_days_onset, max_days_onset - 1)) + else: + return None + + df.loc[wasted_index, 'un_last_wasting_date_of_onset'] = [get_onset_day(whz) for whz in wasted_severity] + df.loc[wasted_index, 'un_ever_wasted'] = True # ----------------------------------------------------------------------------------------------------- # # # # # Give MUAC category, presence of oedema, and determine acute malnutrition state # # # # @@ -387,6 +411,7 @@ def muac_cutoff_by_WHZ(self, idx, whz): """ df = self.sim.population.props p = self.parameters + rng = self.rng # ----- MUAC distribution among severely wasted (WHZ < -3) ------ if whz == 'WHZ<-3': @@ -394,9 +419,9 @@ def muac_cutoff_by_WHZ(self, idx, whz): prop_severe_wasting_with_muac_between_115and125mm = 1 - p['proportion_WHZ<-3_with_MUAC<115mm'] df.loc[idx, 'un_am_MUAC_category'] = df.loc[idx].apply( - lambda x: self.rng.choice(['<115mm', '[115-125)mm'], - p=[p['proportion_WHZ<-3_with_MUAC<115mm'], - prop_severe_wasting_with_muac_between_115and125mm]), + lambda x: rng.choice(['<115mm', '[115-125)mm'], + p=[p['proportion_WHZ<-3_with_MUAC<115mm'], + prop_severe_wasting_with_muac_between_115and125mm]), axis=1 ) @@ -406,10 +431,10 @@ def muac_cutoff_by_WHZ(self, idx, whz): 1 - p['proportion_-3<=WHZ<-2_with_MUAC<115mm'] - p['proportion_-3<=WHZ<-2_with_MUAC_[115-125)mm'] df.loc[idx, 'un_am_MUAC_category'] = df.loc[idx].apply( - lambda x: self.rng.choice(['<115mm', '[115-125)mm', '>=125mm'], - p=[p['proportion_-3<=WHZ<-2_with_MUAC<115mm'], - p['proportion_-3<=WHZ<-2_with_MUAC_[115-125)mm'], - prop_moderate_wasting_with_muac_over_125mm]), + lambda x: rng.choice(['<115mm', '[115-125)mm', '>=125mm'], + p=[p['proportion_-3<=WHZ<-2_with_MUAC<115mm'], + p['proportion_-3<=WHZ<-2_with_MUAC_[115-125)mm'], + prop_moderate_wasting_with_muac_over_125mm]), axis=1 ) @@ -427,10 +452,10 @@ def muac_cutoff_by_WHZ(self, idx, whz): prob_normal_whz_with_muac_over_115mm - prob_normal_whz_with_muac_over_125mm df.loc[idx, 'un_am_MUAC_category'] = df.loc[idx].apply( - lambda x: self.rng.choice(['<115mm', '[115-125)mm', '>=125mm'], - p=[prob_normal_whz_with_muac_less_than_115mm, - prob_normal_whz_with_muac_between_115and125mm, - prob_normal_whz_with_muac_over_125mm]), + lambda x: rng.choice(['<115mm', '[115-125)mm', '>=125mm'], + p=[prob_normal_whz_with_muac_less_than_115mm, + prob_normal_whz_with_muac_between_115and125mm, + prob_normal_whz_with_muac_over_125mm]), axis=1 ) @@ -443,6 +468,7 @@ def nutritional_oedema_present(self, idx): return df = self.sim.population.props p = self.parameters + rng = self.rng # Knowing the prevalence of nutritional oedema in under 5 population, # apply the probability of oedema in WHZ < -2 @@ -451,8 +477,8 @@ def nutritional_oedema_present(self, idx): children_without_wasting = idx.intersection(df.index[df.un_WHZ_category == 'WHZ>=-2']) # oedema among wasted children - oedema_in_wasted_children = self.rng.random_sample(size=len( - children_with_wasting)) < p['proportion_WHZ<-2_with_oedema'] + oedema_in_wasted_children = \ + rng.random_sample(size=len(children_with_wasting)) < p['proportion_WHZ<-2_with_oedema'] df.loc[children_with_wasting, 'un_am_nutritional_oedema'] = oedema_in_wasted_children # oedema among non-wasted children @@ -462,8 +488,8 @@ def nutritional_oedema_present(self, idx): # P(oedema & WHZ>=-2) / P(WHZ>=-2) = P(oedema) * [1 - P(WHZ<-2|oedema)] / P(WHZ>=-2) proportion_normal_whz_with_oedema = \ p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) / p['proportion_normal_whz'] - oedema_in_non_wasted = self.rng.random_sample(size=len( - children_without_wasting)) < proportion_normal_whz_with_oedema + oedema_in_non_wasted = \ + rng.random_sample(size=len( children_without_wasting)) < proportion_normal_whz_with_oedema df.loc[children_without_wasting, 'un_am_nutritional_oedema'] = oedema_in_non_wasted def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): @@ -476,6 +502,7 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): """ df = pop_dataframe p = self.parameters + rng = self.rng whz = df.at[person_id, 'un_WHZ_category'] muac = df.at[person_id, 'un_am_MUAC_category'] @@ -503,13 +530,13 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM': # Determine if SAM episode has complications - if self.rng.random_sample() < p['prob_complications_in_SAM']: + if rng.random_sample() < p['prob_complications_in_SAM']: df.at[person_id, 'un_sam_with_complications'] = True else: df.at[person_id, 'un_sam_with_complications'] = False # Determine whether the SAM leads to death death_due_to_sam = self.wasting_models.death_due_to_sam_lm.predict( - df.loc[[person_id]], rng=self.rng + df.loc[[person_id]], rng=rng ) if death_due_to_sam: outcome_date = self.date_of_death_for_untreated_sam() @@ -545,31 +572,26 @@ def get_consumables_for_each_treatment(self): get_item_code("SAM medicines"): 1} return _cons_codes - def date_of_outcome_for_untreated_wasting(self, whz_category): + def length_of_untreated_wasting(self, whz_category): """ - Helper function to determine the duration of the wasting episode to get date of outcome (recovery, progression, - or death). + Helper function to determine the duration of the wasting episode in days. :param whz_category: 'WHZ<-3', or '-3<=WHZ<-2' - :return: date of outcome, which can be recovery to no wasting, progression to severe wasting, or death due to - SAM in cases of moderate wasting; or recovery to moderate wasting or death due to SAM in cases of severe wasting + :return: duration (number of days) of wasting episode, until recovery to no wasting, progression to severe + wasting, from moderate wasting; or recovery to moderate wasting or death due to SAM in cases of severe + wasting """ p = self.parameters - # moderate wasting (for progression to severe, or recovery to no wasting) ----- if whz_category == '-3<=WHZ<-2': - # Allocate the duration of the moderate wasting episode - duration_mod_wasting = int(max(p['min_days_duration_of_wasting'], p['duration_of_untreated_mod_wasting'])) - # Allocate a date of outcome (death, progression, or recovery) - date_of_outcome = self.sim.date + DateOffset(days=duration_mod_wasting) - return date_of_outcome + # return the duration of moderate wasting episode + return int(max(p['min_days_duration_of_wasting'], p['duration_of_untreated_mod_wasting'])) - # severe wasting (recovery to moderate wasting) ----- elif whz_category == 'WHZ<-3': - # determine the duration of severe wasting episode - duration_sev_wasting = int(max(p['min_days_duration_of_wasting'], p['duration_of_untreated_sev_wasting'])) - # Allocate a date of outcome (death, progression, or recovery) - date_of_outcome = self.sim.date + DateOffset(days=duration_sev_wasting) - return date_of_outcome + # return the duration of severe wasting episode + return int(max(p['min_days_duration_of_wasting'], p['duration_of_untreated_sev_wasting'])) + + else: + return None def date_of_death_for_untreated_sam(self): """ @@ -646,6 +668,7 @@ def wasting_clinical_symptoms(self, person_id) -> None: :param person_id: """ df = self.sim.population.props + if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': return @@ -735,6 +758,7 @@ def do_when_am_treatment(self, person_id, intervention) -> None: """ df = self.sim.population.props p = self.parameters + rng = self.rng # natural progression or recovery is cancelled with the tx and the outcome is fully driven by tx self.cancel_future_event(person_id, event_type=Wasting_ProgressionToSevere_Event) @@ -756,7 +780,7 @@ def do_when_am_treatment(self, person_id, intervention) -> None: # otherwise, it is decided probabilistically whether the person fully recovers or remains MAM else: mam_full_recovery = self.wasting_models.acute_malnutrition_recovery_mam_lm.predict( - df.loc[[person_id]], self.rng + df.loc[[person_id]], rng ) if mam_full_recovery: @@ -780,7 +804,7 @@ def do_when_am_treatment(self, person_id, intervention) -> None: outcome_date = (self.sim.date + DateOffset(weeks=p['tx_length_weeks_InpatientSAM'])) sam_full_recovery = self.wasting_models.acute_malnutrition_recovery_sam_lm.predict( - df.loc[[person_id]], self.rng + df.loc[[person_id]], rng ) if sam_full_recovery: df.at[person_id, 'un_am_discharge_date'] = outcome_date @@ -796,11 +820,11 @@ def do_when_am_treatment(self, person_id, intervention) -> None: ) else: - outcome = self.rng.choice(['recovery_to_mam', 'death'], - p=[ - 1-self.parameters['prob_death_after_SAMcare'], - self.parameters['prob_death_after_SAMcare'] - ]) + outcome = rng.choice(['recovery_to_mam', 'death'], + p=[ + 1-self.parameters['prob_death_after_SAMcare'], + self.parameters['prob_death_after_SAMcare'] + ]) if outcome == 'death': self.sim.schedule_event( event=Wasting_SevereAcuteMalnutritionDeath_Event(module=self, person_id=person_id), @@ -821,7 +845,6 @@ def cancel_future_event(self, person_id, event_type) -> None: :param person_id: :param event_type: which event type to cancel """ - df = self.sim.population.props event_tuples = [event_tuple for event_tuple in self.sim.find_events_for_person(person_id) @@ -877,7 +900,11 @@ def apply(self, population): mod_wasting_new_cases_idx = mod_wasting_new_cases.index # update the properties for new cases of wasted children df.loc[mod_wasting_new_cases_idx, 'un_ever_wasted'] = True - df.loc[mod_wasting_new_cases_idx, 'un_last_wasting_date_of_onset'] = self.sim.date + days_in_month = (self.sim.date - pd.DateOffset(days=1)).days_in_month + df.loc[mod_wasting_new_cases_idx, 'un_last_wasting_date_of_onset'] = ( + self.sim.date - pd.to_timedelta(rng.randint(1, days_in_month, size=len(mod_wasting_new_cases_idx)), + unit='D') + ) # initiate moderate wasting df.loc[mod_wasting_new_cases_idx, 'un_WHZ_category'] = '-3<=WHZ<-2' # ------------------------------------------------------------------------------------------- @@ -890,10 +917,9 @@ def apply(self, population): # clear symptoms if not SAM) self.module.clinical_signs_acute_malnutrition(mod_wasting_new_cases_idx) # ------------------------------------------------------------------------------------------- + duration_of_untreated_mod_wasting = self.module.length_of_untreated_wasting('-3<=WHZ<-2') - outcome_date = self.module.date_of_outcome_for_untreated_wasting(whz_category='-3<=WHZ<-2') - - # # # PROGRESS TO SEVERE WASTING # # # # # # # # # # # # # # # # # # + # # # PROGRESSION TO SEVERE WASTING # # # # # # # # # # # # # # # # # # # Determine those that will progress to severe wasting (WHZ < -3) and schedule progression event --------- progression_severe_wasting_bool = self.module.wasting_models.severe_wasting_progression_lm.predict( df.loc[mod_wasting_new_cases_idx], rng=rng, squeeze_single_row_output=False @@ -901,6 +927,8 @@ def apply(self, population): for person_id in mod_wasting_new_cases_idx[progression_severe_wasting_bool]: # schedule severe wasting WHZ < -3 onset after duration of untreated moderate wasting + outcome_date = \ + df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_of_untreated_mod_wasting) self.sim.schedule_event( event=Wasting_ProgressionToSevere_Event(module=self.module, person_id=person_id), date=outcome_date ) @@ -908,6 +936,8 @@ def apply(self, population): # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # Schedule recovery for those not progressing to severe wasting --------- for person_id in mod_wasting_new_cases_idx[~progression_severe_wasting_bool]: + outcome_date = \ + df.at[person_id, 'un_last_wasting_date_of_onset'] + DateOffset(days=duration_of_untreated_mod_wasting) if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM': # schedule full recovery after duration of moderate wasting self.sim.schedule_event(event=Wasting_FullRecovery_Event( @@ -963,7 +993,8 @@ def apply(self, person_id): if pd.isnull(df.at[person_id, 'un_sam_death_date']): # # # SEVERE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # # # Schedule recovery tom MAM from SAM for those not dying due to SAM - outcome_date = self.module.date_of_outcome_for_untreated_wasting(whz_category='WHZ<-3') + duration_of_untreated_sev_wasting = self.module.length_of_untreated_wasting('WHZ<-3') + outcome_date = self.sim.date + DateOffset(days=duration_of_untreated_sev_wasting) self.sim.schedule_event(event=Wasting_RecoveryToMAM_Event( module=self.module, person_id=person_id), date=outcome_date) # else: death due to SAM scheduled earlier, i.e. natural progression @@ -1180,7 +1211,8 @@ def get_min_length(in_recov_how, in_person_id, in_whz): person_id=person_id, disease_module=self.module ) - outcome_date = self.module.date_of_outcome_for_untreated_wasting(whz_category='-3<=WHZ<-2') + duration_of_untreated_mod_wasting = self.module.length_of_untreated_wasting('-3<=WHZ<-2') + outcome_date = self.sim.date + DateOffset(days=duration_of_untreated_mod_wasting) progression_severe_wasting_bool = self.module.wasting_models.severe_wasting_progression_lm.predict( df.loc[[person_id]], rng=rng ) @@ -1701,7 +1733,9 @@ def apply(self, population): f"Some incident cases trying to be logged on {self.sim.date=} from the day of last log "\ f"{self.date_last_run=} or before." - logger.info(key='wasting_incidence_count', data=inc_df.to_dict()) + logger.info(key='wasting_incidence_count', data=inc_df.to_dict(), + description="Moderate wasting incidence cases are logged for the previous month, while severe " + "wasting incidence cases are logged for the current month.") # Reset the incidence tracker and the date_last_run self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 8402066202..1f10ac7d50 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -202,11 +202,13 @@ def test_wasting_incidence(tmpdir): polling = Wasting_IncidencePoll(wmodule) polling.apply(sim.population) - # Check properties of individuals: should now be moderately wasted + # Check properties of individuals: should now be moderately wasted with onset in previous month under5s = df.loc[df.is_alive & (df['age_years'] < 5)] assert all(under5s['un_ever_wasted']) assert (under5s['un_WHZ_category'].eq('-3<=WHZ<-2')).all() - assert (under5s['un_last_wasting_date_of_onset'].eq(sim.date)).all() + days_in_month = (sim.date - pd.DateOffset(days=1)).days_in_month + assert (under5s['un_last_wasting_date_of_onset'] < sim.date).all() and \ + (under5s['un_last_wasting_date_of_onset'] >= sim.date - pd.to_timedelta(days_in_month, unit='D')).all() def test_report_daly_weights(tmpdir): @@ -348,16 +350,18 @@ def test_nat_recovery_moderate_wasting(tmpdir): polling = Wasting_IncidencePoll(module=wmodule) polling.apply(sim.population) - # Check properties of this individual: should now be moderately wasted with MAM or SAM respectively + # Check properties of this individual: should now be moderately wasted with MAM or SAM respectively and + # onset in previous month person = df.loc[person_id] assert person['un_ever_wasted'] assert person['un_WHZ_category'] == '-3<=WHZ<-2' - assert person['un_last_wasting_date_of_onset'] == sim.date + days_in_month = (sim.date - pd.DateOffset(days=1)).days_in_month + assert (person['un_last_wasting_date_of_onset'] < sim.date) and \ + (person['un_last_wasting_date_of_onset'] >= sim.date - pd.to_timedelta(days_in_month, unit='D')) assert pd.isnull(person['un_am_tx_start_date']) assert pd.isnull(person['un_am_recovery_date']) assert df.at[person_id, 'un_clinical_acute_malnutrition'] == am_state_expected - # Check that there is a natural recovery event scheduled: # Wasting_FullRecovery_Event if this person has MAM, Wasting_RecoveryToMAM_Event if this person has SAM if am_state_expected == 'MAM': @@ -918,16 +922,19 @@ def test_recovery_before_death_scheduled(tmpdir): polling = Wasting_IncidencePoll(module=wmodule) polling.apply(sim.population) - # Check properties of this individual: should now be moderately wasted + # Check properties of this individual: should now be moderately wasted with onset in previous month person = df.loc[person_id] assert person['un_ever_wasted'] assert person['un_WHZ_category'] == '-3<=WHZ<-2' assert person['un_clinical_acute_malnutrition'] != 'well' assert not df.at[person_id, 'un_sam_with_complications'] - assert person['un_last_wasting_date_of_onset'] == sim.date + days_in_month = (sim.date - pd.DateOffset(days=1)).days_in_month + assert (person['un_last_wasting_date_of_onset'] < sim.date) and \ + (person['un_last_wasting_date_of_onset'] >= sim.date - pd.to_timedelta(days_in_month, unit='D')) assert pd.isnull(person['un_am_tx_start_date']) assert pd.isnull(person['un_am_recovery_date']) assert pd.isnull(person['un_sam_death_date']) # no death due to untreated SAM + # Check that there is a Wasting_ProgressionToSevere_Event scheduled for this person progression_event_tuple = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if isinstance(event_tuple[1], Wasting_ProgressionToSevere_Event)][0] From d600e3883a662ad2345c807c4ec168ef5a08d3b0 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 25 Aug 2025 12:17:13 +0100 Subject: [PATCH 478/755] Stunting write-up: correct the extension doc->docx --- docs/write-ups/Stunting.doc | Bin 801165 -> 0 bytes docs/write-ups/Stunting.docx | 3 +++ 2 files changed, 3 insertions(+) delete mode 100644 docs/write-ups/Stunting.doc create mode 100644 docs/write-ups/Stunting.docx diff --git a/docs/write-ups/Stunting.doc b/docs/write-ups/Stunting.doc deleted file mode 100644 index 99534a537441fcb10d857a6dc8ca9e4b08173340..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 801165 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

vogm7M-=8t1{bt_{!(p7c2kL4v#4zu%UrhAU56y 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 a_fO611$~jY{Bk0j&#}B)!~n2X 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%0DU4WD+?WQatTem@qPU1ChCV^ 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�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

+|O@6HFZm-k$g+ve*J$8#5D+DnZ}|vV|LSD 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

9-=W6nnHykDihX|eeyc-8RZEje`#?={rg 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,mkUZX+KK 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%0AeCU6jOO>9^GlsLex7wA&mm+Q2?Z@?g!5GjYb) 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%0D7KNLIC q{<~OS|4R7ltLEUgXO*Wr><@#b2_^Zh^!?c505Ztlq5}E21pWt+C80?G diff --git a/docs/write-ups/Stunting.docx b/docs/write-ups/Stunting.docx new file mode 100644 index 0000000000..f44aac3d66 --- /dev/null +++ b/docs/write-ups/Stunting.docx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e7377d88b85e99866dd34d5e8540bf53047456dd99fce05029cfe62fe0c507bf +size 801165 From 882db51b7bf9ae306f20ca3f72bb0c8f73e5d6e8 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 25 Aug 2025 13:38:24 +0100 Subject: [PATCH 479/755] Wasting write-up: correct the extension doc->docx --- docs/write-ups/Wasting.doc | Bin 360253 -> 0 bytes docs/write-ups/Wasting.docx | 3 +++ 2 files changed, 3 insertions(+) delete mode 100644 docs/write-ups/Wasting.doc create mode 100644 docs/write-ups/Wasting.docx diff --git a/docs/write-ups/Wasting.doc b/docs/write-ups/Wasting.doc deleted file mode 100644 index bcda0eb678b33ee28624f30b474734bd2bd7ed21..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 360253 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%0AM#CK(T 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%0Dw~5?B4q7!mN3lNn<2)iOCdTHbEU+ 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 IB#JGS+dyW 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%0DNfy{!t1RV@}Ad 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. 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 @KoDqGn@G%@j7vD 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�C_2pPiO!%02CAyz$y|&YtQjs_z(a9Onm|XV1b|ieCauwSUb_v{U!em zJn}lPb_D?dj)6erf1rqfrN(wf@{V@)PV`20jwW>9Y^?tchu+A`69Ima9SBGI2Ydlo z^8eum_V#~5Z!G})Qh}%|;DP!Nvpo4Tbnrj350>k^$|7gMTCkhtC&r_7<0DyYbzbW*|K>vq=^-mNs(D0E^2>^gh&%Y^tM*lAb z+n*>v^#&@bf!;|z`ELpgLa_hQg8fev+T6>ZT!9{T4D;{K71;7Og^``jU#|5>2i1r8 ze#iy%0fVX{r!=24dY)t6? zBN_i>0TW78%3l`v04@0E06{PW2G9}$Y7cBYJ!N-$6DOTN5&YjV^PeU_kNmB}|LxuK VQs5AOH8eW#tp;rQDR-a%{6B61DZKyy diff --git a/docs/write-ups/Wasting.docx b/docs/write-ups/Wasting.docx new file mode 100644 index 0000000000..ca62f23058 --- /dev/null +++ b/docs/write-ups/Wasting.docx @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d331fd8af336a10d8199b056a0a4ea16a0c37f0045d4cd7d9136b98ce63e732e +size 360253 From 48ad8fdbf6ec9972c0a16d5a8170681f1a7b5afc Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 31 Aug 2025 17:20:54 +0100 Subject: [PATCH 480/755] wast: logging event updated to run on January 1st each year --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 5fb9ded7e9..ba6e50f411 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -365,7 +365,7 @@ def initialise_simulation(self, sim): sim.schedule_event(Wasting_InitLoggingEvent(self), sim.date) sim.schedule_event(Wasting_InitiateGrowthMonitoring(self), sim.date) sim.schedule_event(Wasting_IncidencePoll(self), sim.date + DateOffset(months=1)) - sim.schedule_event(Wasting_LoggingEvent(self), sim.date + DateOffset(years=1) - DateOffset(days=1)) + sim.schedule_event(Wasting_LoggingEvent(self), sim.date + DateOffset(years=1)) # Retrieve the consumables codes and amounts of the consumables used self.cons_codes = self.get_consumables_for_each_treatment() From 8c2941b5bfc649da4ef3872dbbb13f7c63081c18 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 1 Sep 2025 18:43:15 +0100 Subject: [PATCH 481/755] wast & test_wast: updated treatment parameter naming; docstrings improved --- src/tlo/methods/wasting.py | 171 ++++++++++++++++++++++++++----------- tests/test_wasting.py | 4 +- 2 files changed, 123 insertions(+), 52 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index ba6e50f411..0e12a82d80 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -136,7 +136,7 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.LIST, 'growth monitoring frequency (days) for age categories '), 'growth_monitoring_attendance_prob_agecat': Parameter( Types.LIST, 'probability to attend the growth monitoring for age categories'), - # recovery due to treatment/interventions + # recovery due to treatment 'recovery_rate_with_soy_RUSF': Parameter( Types.REAL, 'probability of recovery from MAM following treatment with soy RUSF'), 'recovery_rate_with_CSB++': Parameter( @@ -156,7 +156,7 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'tx_length_weeks_InpatientSAM': Parameter( Types.REAL, 'number of weeks the patient receives treatment in the Inpatient Care for complicated' ' SAM before being discharged if they do not die beforehand'), - # treatment/intervention outcomes + # treatment impacts 'prob_death_after_SAMcare': Parameter( Types.REAL, 'probability of dying from SAM after receiving care if not fully recovered'), } @@ -244,14 +244,16 @@ def __init__(self, name=None): def read_parameters(self, resourcefilepath: Optional[Path] = None): """ - :param data_folder: path to a folder supplied to the simulation containing data csv files + * 1) Reads the ResourceFile + * 2) Registers the Symptom """ - # Read parameters from the resource file + + # 1) Read parameters from the resource file self.load_parameters_from_dataframe( read_csv_files(resourcefilepath / 'ResourceFile_Wasting', files='parameters') ) - # Register wasting symptom (weight loss) in Symptoms Manager with high odds of seeking care + # 2) Register wasting symptom (weight loss) in Symptoms Manager with high odds of seeking care self.sim.modules["SymptomManager"].register_symptom( Symptom( name=self.wasting_symptom, @@ -261,7 +263,7 @@ def read_parameters(self, resourcefilepath: Optional[Path] = None): def initialise_population(self, population): """ - Set our property values for the initial population. This method is called by the simulation when creating + Sets the property values for the initial population. This method is called by the simulation when creating the initial population, and is responsible for assigning initial values, for every individual, of those properties 'owned' by this module, i.e. those declared in the PROPERTIES dictionary above. @@ -328,13 +330,17 @@ def initialise_population(self, population): assert wasted_severity.isin(['WHZ<-3', '-3<=WHZ<-2']).all(), \ f"Not all wasted individuals have 'un_WHZ_category' set as 'WHZ<-3' or '-3<=WHZ<-2'. " \ f"Invalid indices: {wasted_severity[~wasted_severity.isin(['WHZ<-3', '-3<=WHZ<-2'])].index.tolist()}" + # set date of wasting onset def get_onset_day(whz_category: str): - """Returns the onset day for a wasting episode based on the WHZ category. + """ + Returns the onset day for a wasting episode based on the WHZ category. For moderate wasting ('-3<=WHZ<-2'), returns a random onset day within the duration of untreated moderate wasting. For severe wasting ('WHZ<-3'), returns a random onset day after the moderate wasting period, within the duration of untreated severe wasting. + + :param whz_category: """ if whz_category == '-3<=WHZ<-2': min_days_onset = 0 @@ -356,10 +362,13 @@ def get_onset_day(whz_category: str): self.clinical_signs_acute_malnutrition(under5s_index) def initialise_simulation(self, sim): - """Prepares for simulation. Schedules: - * the first growth monitoring to happen straight away, scheduled monthly to detect new cases for treatment. - * the main incidence polling event. + """ + Prepares for simulation. Schedules: + * the first growth monitoring to happen straight away, scheduled monthly to detect new cases for treatment, + * the main incidence polling event, * the main logging event. + + :param sim: """ sim.schedule_event(Wasting_InitLoggingEvent(self), sim.date) @@ -371,11 +380,12 @@ def initialise_simulation(self, sim): self.cons_codes = self.get_consumables_for_each_treatment() def on_birth(self, mother_id, child_id): - """Initialise properties for a newborn individual. - :param mother_id: the mother for this child - :param child_id: the new child """ + Initialises properties for a newborn individual. + :param mother_id: the mother's id of this child + :param child_id: the id of the newborn child + """ df = self.sim.population.props # Set initial properties @@ -401,13 +411,17 @@ def on_birth(self, mother_id, child_id): priority=2, topen=self.sim.date + pd.DateOffset(days=1) ) - def muac_cutoff_by_WHZ(self, idx, whz): + def muac_cutoff_by_WHZ(self, idx, whz) -> None: """ - Proportion of MUAC < 115 mm in WHZ < -3 and -3 <= WHZ < -2, - and proportion of wasted children with oedematous malnutrition (kwashiorkor, marasmic kwashiorkor) + Determines the MUAC (Mid-Upper Arm Circumference) category for each individual specified in `idx`, based on a + shared WHZ (Weight-for-Height Z-score) category `whz`. + The MUAC categories are: '<115mm', '[115–125)mm', and '>=125mm'. + + Assigns the MUAC categories determined to the 'un_am_MUAC_category' property for each corresponding individual + in the population DataFrame. - :param idx: index of children ages 6-59 months or person_id - :param whz: weight for height category + :param idx: Indices of individuals in the population DataFrame to assess for MUAC category. + :param whz: WHZ category shared by the individuals ('WHZ<-3', '-3<=WHZ<-2', 'WHZ>=-2'). """ df = self.sim.population.props p = self.parameters @@ -461,8 +475,13 @@ def muac_cutoff_by_WHZ(self, idx, whz): def nutritional_oedema_present(self, idx): """ - This function applies the probability of nutritional oedema present in wasting and non-wasted cases - :param idx: index of children under 5, or person_id + Determines the presence of nutritional oedema for each individual specified in `idx`, based on their respective + WHZ (Weight-for-Height Z-score) category. + + Assigns the result (True/False) to the `un_am_nutritional_oedema` property for each corresponding individual in + the population DataFrame. + + :param idx: Indices of individuals in the population DataFrame to assess for nutritional oedema presence. """ if len(idx) == 0: return @@ -494,11 +513,33 @@ def nutritional_oedema_present(self, idx): def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): """ - This function will determine the clinical acute malnutrition status (MAM, SAM) based on anthropometric indices - and presence of nutritional oedema (Kwashiorkor); And help determine whether the individual will have medical - complications, applicable to SAM cases only, requiring inpatient care. - :param person_id: individual id - :param pop_dataframe: population dataframe + Determines + * the clinical acute malnutrition status ('well', 'MAM', 'SAM') for the individual specified by + `person_id`, based on their anthropometric indices (WHZ and MUAC category) and presence of nutritional oedema. + * whether the individual has medical complications requiring inpatient care, applicable to SAM cases only. + + Assigns for the corresponding individual in the population DataFrame: + ------- + * 'un_clinical_acute_malnutrition': the determined clinical acute malnutrition status ('well', 'MAM', 'SAM') + * 'un_sam_with_complications': the determined value of presence of medical complications (True/False) + + For well cases + * 'un_am_treatment_type': remains 'not_applicable' + + For non-well cases, i.e. those who developed 'MAM' or 'SAM' + * 'un_am_treatment_type': 'none', i.e. they start with no treatment + * 'un_am_recovery_date' property is reset to NaT + + For the SAM cases + * wasting symptom is applied + * it is determined whether SAM leads to death, and if it does, the Death event is scheduled and the date of + death is assigned to the 'un_sam_death_date' property + + For non-SAM cases + * the wasting symptom is cleared + + :param person_id: individual's id + :param pop_dataframe: population DataFrame """ df = pop_dataframe p = self.parameters @@ -557,7 +598,9 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): and (df.at[person_id, 'un_sam_with_complications'])), f'{person_id=} has MAM with complications.' def get_consumables_for_each_treatment(self): - """Get the item_code and amount administrated for all consumables for each treatment.""" + """ + Get the item_code and amount administrated for all consumables for each treatment. + """ # ### Get item codes from item names and define number of units per case here get_item_code = self.sim.modules['HealthSystem'].get_item_code_from_item_name @@ -575,6 +618,7 @@ def get_consumables_for_each_treatment(self): def length_of_untreated_wasting(self, whz_category): """ Helper function to determine the duration of the wasting episode in days. + :param whz_category: 'WHZ<-3', or '-3<=WHZ<-2' :return: duration (number of days) of wasting episode, until recovery to no wasting, progression to severe wasting, from moderate wasting; or recovery to moderate wasting or death due to SAM in cases of severe @@ -597,6 +641,7 @@ def date_of_death_for_untreated_sam(self): """ Helper function to determine date of death, assuming it occurs earlier than the progression/recovery from any wasting, moderate or severe. + :return: date of death """ p = self.parameters @@ -612,6 +657,7 @@ def clinical_signs_acute_malnutrition(self, idx): When WHZ changed, update other anthropometric indices and clinical signs (MUAC, oedema) that determine the clinical state of acute malnutrition. If SAM, update medical complications. If not SAM, clear symptoms. This will include both wasted and non-wasted children with other signs of acute malnutrition. + :param idx: index of children or person_id less than 5 years old """ df = self.sim.population.props @@ -639,6 +685,7 @@ def report_daly_values(self): experienced by persons in the previous month. Only rows for alive-persons must be returned. The names of the series of columns is taken to be the label of the cause of this disability. It will be recorded by the healthburden module as _. + :return: current daly values for everyone alive """ # Dict to hold the DALY weights @@ -664,7 +711,8 @@ def report_daly_values(self): def wasting_clinical_symptoms(self, person_id) -> None: """ - assign clinical symptoms to the new acute malnutrition case + Assigns clinical symptoms to the new acute malnutrition case + :param person_id: """ df = self.sim.population.props @@ -688,7 +736,21 @@ def do_at_generic_first_appt( schedule_hsi_event: HSIEventScheduler, **kwargs, ) -> None: - + """ + Handles a generic first appointment for a child under 5 years old. + + If the child is not currently being treated for wasting and has not already attended a generic first appointment + or growth monitoring on the same day: + * Performs an acute malnutrition assessment. If acute malnutrition is detected, schedules HSI for the + appropriate treatment enrolment. + * Updates the 'un_last_nonemergency_appt_date' property for the individual in the population DataFrame. + + :param person_id: ID of the individual attending the appointment + :param symptoms: list of symptoms present for the individual + :param individual_properties: properties of the individual relevant to the appointment + :param schedule_hsi_event: scheduler for health system interaction events + :param kwargs: additional keyword arguments + """ df = self.sim.population.props # if person not under 5 or currently treated or non-emerg. appt went through today already, acute malnutrition @@ -705,7 +767,7 @@ def do_at_generic_first_appt( ) return - #or if HSI was already scheduled due to growth monitoring, won't be checked for acute malnutrition again + # if HSI was already scheduled due to growth monitoring, won't be checked for acute malnutrition again hsi_event_scheduled = [ ev for ev in self.sim.modules["HealthSystem"].find_events_for_person(person_id) @@ -723,11 +785,11 @@ def do_at_generic_first_appt( clinical_am = individual_properties['un_clinical_acute_malnutrition'] complications = individual_properties['un_sam_with_complications'] - # No intervention if well + # No treatment if well if clinical_am == 'well': return - # SFP intervention if diagnosed as MAM + # SFP if diagnosed as MAM elif clinical_am == 'MAM': # schedule HSI for supplementary feeding program for MAM schedule_hsi_event( @@ -736,43 +798,51 @@ def do_at_generic_first_appt( elif clinical_am == 'SAM': - # OTP intervention if diagnosed as uncomplicated SAM + # OTP if diagnosed as uncomplicated SAM if not complications: # schedule HSI for supplementary feeding program for MAM schedule_hsi_event( hsi_event=HSI_Wasting_OutpatientTherapeuticProgramme_SAM(module=self, person_id=person_id), priority=0, topen=self.sim.date) - # ITC intervention if diagnosed as complicated SAM + # ITC if diagnosed as complicated SAM if complications: # schedule HSI for supplementary feeding program for MAM schedule_hsi_event( hsi_event=HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM(module=self, person_id=person_id), priority=0, topen=self.sim.date) - def do_when_am_treatment(self, person_id, intervention) -> None: + def do_when_am_treatment(self, person_id, treatment) -> None: """ - This function will apply the linear model of recovery based on intervention given - :param person_id: - :param intervention: + Cancels any scheduled natural outcome for the individual; outcomes are now determined solely by the treatment. + Processes the specified treatment, determines the outcome, and if appropriate, schedules an outcome event and/or + an enrolment for a follow-up treatment. + + Updates individual's properties in the population DataFrame: + * `un_am_tx_start_date` + * `un_am_discharge_date` + * `un_sam_death_date` (if applicable) + + :param person_id: ID of the individual receiving treatment + :param treatment: type of treatment being applied ('CSB++', 'standard_RUTF', etc.) """ df = self.sim.population.props p = self.parameters rng = self.rng - # natural progression or recovery is cancelled with the tx and the outcome is fully driven by tx + # natural progression or recovery is cancelled with the treatment and the outcome is fully driven by treatment self.cancel_future_event(person_id, event_type=Wasting_ProgressionToSevere_Event) self.cancel_future_event(person_id, event_type=Wasting_FullRecovery_Event) self.cancel_future_event(person_id, event_type=Wasting_RecoveryToMAM_Event) # Set the date when the treatment is provided: df.at[person_id, 'un_am_tx_start_date'] = self.sim.date - # Reset tx discharge date + # Reset treatment discharge date df.at[person_id, 'un_am_discharge_date'] = pd.NaT - # Cancel natural death due to SAM with tx + # Cancel natural death due to SAM with treatment df.at[person_id, 'un_sam_death_date'] = pd.NaT - if intervention == 'SFP': + if treatment == 'SFP': outcome_date = self.sim.date + DateOffset(weeks=p['tx_length_weeks_SuppFeedingMAM']) # follow-up SFP in a recovered person leads to discharge through "full recovery" if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well': @@ -797,8 +867,8 @@ def do_when_am_treatment(self, person_id, intervention) -> None: priority=0, topen=outcome_date) return - elif intervention in ['OTP', 'ITC']: - if intervention == 'OTP': + elif treatment in ['OTP', 'ITC']: + if treatment == 'OTP': outcome_date = (self.sim.date + DateOffset(weeks=p['tx_length_weeks_OutpatientSAM'])) else: outcome_date = (self.sim.date + DateOffset(weeks=p['tx_length_weeks_InpatientSAM'])) @@ -842,6 +912,7 @@ def do_when_am_treatment(self, person_id, intervention) -> None: def cancel_future_event(self, person_id, event_type) -> None: """ This function will add dates of recovery and/or progression events that need to be canceled. + :param person_id: :param event_type: which event type to cancel """ @@ -1403,17 +1474,17 @@ def schedule_tx_by_diagnosis(hsi_event): # for now, perfect diagnosing is assumed diagnosis = df.at[person_id, 'un_clinical_acute_malnutrition'] - # No intervention if diagnosed as well + # No treatment if diagnosed as well if diagnosis == 'well': return - # SFP intervention if diagnosed as MAM + # SFP if diagnosed as MAM elif diagnosis == 'MAM': schedule_tx_by_diagnosis(HSI_Wasting_SupplementaryFeedingProgramme_MAM) elif (diagnosis == 'SAM') and (not complications): - # OTP intervention if diagnosed as uncomplicated SAM + # OTP if diagnosed as uncomplicated SAM schedule_tx_by_diagnosis(HSI_Wasting_OutpatientTherapeuticProgramme_SAM) else: # (diagnosis == 'SAM') and complications: - # ITC intervention if diagnosed as complicated SAM + # ITC if diagnosed as complicated SAM schedule_tx_by_diagnosis(HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM) def did_not_run(self): @@ -1461,7 +1532,7 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data='consumables are available') # Record that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'CSB++' - self.module.do_when_am_treatment(person_id, intervention='SFP') + self.module.do_when_am_treatment(person_id, treatment='SFP') else: logger.debug(key='debug', data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") @@ -1512,7 +1583,7 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data='consumables are available.') # Record that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' - self.module.do_when_am_treatment(person_id, intervention='OTP') + self.module.do_when_am_treatment(person_id, treatment='OTP') else: logger.debug(key='debug', data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") @@ -1558,7 +1629,7 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data='consumables available, so use it.') # Record that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'inpatient_care' - self.module.do_when_am_treatment(person_id, intervention='ITC') + self.module.do_when_am_treatment(person_id, treatment='ITC') else: logger.debug(key='debug', data=f"Consumable(s) not available, hence {self.TREATMENT_ID} cannot be provided.") diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 1f10ac7d50..373244cac2 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -824,9 +824,9 @@ def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): # Start appropriate treatment if am_state_expected == 'MAM': - wmodule.do_when_am_treatment(person_id, intervention='SFP') + wmodule.do_when_am_treatment(person_id, treatment='SFP') else: # complicated SAM - wmodule.do_when_am_treatment(person_id, intervention='ITC') + wmodule.do_when_am_treatment(person_id, treatment='ITC') assert df.at[person_id, 'un_am_tx_start_date'] == sim.date # Check full recovery with treatment is scheduled before the natural recovery From 2e29665f3fd813218831e4f2c24f8e98b701bcd6 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 1 Sep 2025 18:57:33 +0100 Subject: [PATCH 482/755] wast: create a daly-weights lookup for efficiency --- src/tlo/methods/wasting.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 0e12a82d80..1661e7eff3 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -208,6 +208,7 @@ class Wasting(Module, GenericFirstAppointmentsMixin): def __init__(self, name=None): super().__init__(name=name) + self.daly_wts = dict() # dict to hold the DALY weights self.wasting_models = None # wasting states self.wasting_states = self.PROPERTIES["un_WHZ_category"].categories @@ -245,7 +246,8 @@ def __init__(self, name=None): def read_parameters(self, resourcefilepath: Optional[Path] = None): """ * 1) Reads the ResourceFile - * 2) Registers the Symptom + * 2) Declares the DALY weights + * 3) Registers the Symptom """ # 1) Read parameters from the resource file @@ -253,7 +255,14 @@ def read_parameters(self, resourcefilepath: Optional[Path] = None): read_csv_files(resourcefilepath / 'ResourceFile_Wasting', files='parameters') ) - # 2) Register wasting symptom (weight loss) in Symptoms Manager with high odds of seeking care + # 2) Get the DALY weights + get_daly_weight = self.sim.modules['HealthBurden'].get_daly_weight + + self.daly_wts['mod_wasting_with_oedema'] = get_daly_weight(sequlae_code=461) + self.daly_wts['sev_wasting_w/o_oedema'] = get_daly_weight(sequlae_code=462) + self.daly_wts['sev_wasting_with_oedema'] = get_daly_weight(sequlae_code=463) + + # 3) Register wasting symptom (weight loss) in Symptoms Manager with high odds of seeking care self.sim.modules["SymptomManager"].register_symptom( Symptom( name=self.wasting_symptom, @@ -688,25 +697,16 @@ def report_daly_values(self): :return: current daly values for everyone alive """ - # Dict to hold the DALY weights - daly_wts = dict() - df = self.sim.population.props - # Get DALY weights - get_daly_weight = self.sim.modules['HealthBurden'].get_daly_weight - - daly_wts['mod_wasting_with_oedema'] = get_daly_weight(sequlae_code=461) - daly_wts['sev_wasting_w/o_oedema'] = get_daly_weight(sequlae_code=462) - daly_wts['sev_wasting_with_oedema'] = get_daly_weight(sequlae_code=463) total_daly_values = pd.Series(data=0.0, index=df.index[df.is_alive]) total_daly_values.loc[df.is_alive & (df.un_WHZ_category == 'WHZ<-3') & - df.un_am_nutritional_oedema] = daly_wts['sev_wasting_with_oedema'] + df.un_am_nutritional_oedema] = self.daly_wts['sev_wasting_with_oedema'] total_daly_values.loc[df.is_alive & (df.un_WHZ_category == 'WHZ<-3') & - (~df.un_am_nutritional_oedema)] = daly_wts['sev_wasting_w/o_oedema'] + (~df.un_am_nutritional_oedema)] = self.daly_wts['sev_wasting_w/o_oedema'] total_daly_values.loc[df.is_alive & (df.un_WHZ_category == '-3<=WHZ<-2') & - df.un_am_nutritional_oedema] = daly_wts['mod_wasting_with_oedema'] + df.un_am_nutritional_oedema] = self.daly_wts['mod_wasting_with_oedema'] return total_daly_values def wasting_clinical_symptoms(self, person_id) -> None: From 67735907a42b1a44e0bba17f21fd77ed207a548b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 1 Sep 2025 22:47:28 +0100 Subject: [PATCH 483/755] wast: improve a debug message --- src/tlo/methods/wasting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 1661e7eff3..a8b1805180 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -762,8 +762,8 @@ def do_at_generic_first_appt( if self.sim.date == individual_properties['un_last_nonemergency_appt_date']: logger.debug( key="multiple non-emergency appts on same day", - data=f"A non-emerg. appt runs again on the same date {self.sim.date=} for the {person_id=}. " - "All DOs related to wasting are cancelled." + data=f"A non-emergency appointment is scheduled again on the same date for {person_id=}. " + "Acute malnutrition assessment cancelled as it has already been performed." ) return From f878541fbf7b03875a842b0a38d12903a678fb3f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 1 Sep 2025 23:03:53 +0100 Subject: [PATCH 484/755] wast: add logic to track acute malnutrition being already assessed today (avoid use of find_events_for_person) --- src/tlo/methods/wasting.py | 45 +++++++++++++++----------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index a8b1805180..41225778e0 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -201,9 +201,11 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'to be canceled for the person'), 'un_progression_to_cancel': Property(Types.LIST, 'list of dates of scheduled progression to severe ' 'wasting to be canceled for the person'), - # Property to avoid double non-emergency appt on the same date + # Properties to avoid double acute malnutrition assessment 'un_last_nonemergency_appt_date': Property(Types.DATE, 'last date of generic non-emergency first ' 'appointment'), + 'un_last_growth_monitoring_appt_date': Property(Types.DATE, 'last date of growth-monitoring ' + 'appointment'), } def __init__(self, name=None): @@ -315,6 +317,7 @@ def initialise_population(self, population): df.loc[df.is_alive, 'un_progression_to_cancel'] = \ df.loc[df.is_alive, 'un_progression_to_cancel'].apply(lambda x: []) # df.loc[df.is_alive, 'un_last_nonemergency_appt_date']= pd.NaT + # df.loc[df.is_alive, 'un_last_growth_monitoring_appt_date']= pd.NaT # initialise wasting linear models. self.wasting_models = WastingModels(self) @@ -413,6 +416,7 @@ def on_birth(self, mother_id, child_id): df.at[child_id, 'un_full_recov_to_cancel'] = [] df.at[child_id, 'un_progression_to_cancel'] = [] # df.at[child_id, 'un_last_nonemergency_appt_date']= pd.NaT + # df.at[child_id, 'un_last_growth_monitoring_appt_date']= pd.NaT # initiate growth monitoring from day 1 self.sim.modules['HealthSystem'].schedule_hsi_event( @@ -753,12 +757,13 @@ def do_at_generic_first_appt( """ df = self.sim.population.props - # if person not under 5 or currently treated or non-emerg. appt went through today already, acute malnutrition - # will not be assessed during this appt + # if person not under 5, or currently treated, or acute malnutrition already assessed, + # it will not be assessed (again) if (individual_properties['age_years'] >= 5) or \ (individual_properties['un_last_wasting_date_of_onset'] < individual_properties['un_am_tx_start_date'] < self.sim.date) or \ - (self.sim.date == individual_properties['un_last_nonemergency_appt_date']): + (self.sim.date == individual_properties['un_last_nonemergency_appt_date']) or \ + (self.sim.date == individual_properties['un_last_growth_monitoring_appt_date']): if self.sim.date == individual_properties['un_last_nonemergency_appt_date']: logger.debug( key="multiple non-emergency appts on same day", @@ -767,17 +772,6 @@ def do_at_generic_first_appt( ) return - # if HSI was already scheduled due to growth monitoring, won't be checked for acute malnutrition again - hsi_event_scheduled = [ - ev - for ev in self.sim.modules["HealthSystem"].find_events_for_person(person_id) - if isinstance(ev[1], (HSI_Wasting_SupplementaryFeedingProgramme_MAM, - HSI_Wasting_OutpatientTherapeuticProgramme_SAM, - HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM)) - ] - if hsi_event_scheduled: - return - # track the date of the last non-emergency appt df.at[person_id, 'un_last_nonemergency_appt_date'] = self.sim.date @@ -1429,26 +1423,23 @@ def get_monitoring_frequency_days(age): # TODO: as stated above, for now we schedule next monitoring for all children, even those sent for treatment schedule_next_monitoring() - # but if they are currently treated, the growth monitoring will not go through + # if person currently treated, or acute malnutrition already assessed, + # it will not be assessed (again) # TODO: later could be scheduled for monitoring within the tx to use the resources if (df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[person_id, 'un_am_tx_start_date'] < - self.sim.date): - return - # or if HSI was already scheduled due to care-seeking, no need to attend the growth monitoring - hsi_event_scheduled = [ - ev - for ev in self.sim.modules["HealthSystem"].find_events_for_person(person_id) - if isinstance(ev[1], (HSI_Wasting_SupplementaryFeedingProgramme_MAM, - HSI_Wasting_OutpatientTherapeuticProgramme_SAM, - HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM)) - ] - if hsi_event_scheduled: + self.sim.date) or \ + (self.sim.date == df.at[person_id, 'un_last_nonemergency_appt_date']): return # the person may not attend the appt if not self.attendance: return + # Acute malnutrition assessment + # ### + # track the date of the last growth-monitoring appt + df.at[person_id, 'un_last_growth_monitoring_appt_date'] = self.sim.date + available_equipment = [] for equip in ['Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape']: available = rng.random_sample() < HSI_Event.probability_all_equipment_available(self, equip) From 1771c29b548f97f9fda13ed8097d0d9edd6829e0 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 1 Sep 2025 23:20:36 +0100 Subject: [PATCH 485/755] wast: minor (correct a comment) --- src/tlo/methods/wasting.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 41225778e0..7e1d1dc486 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -407,10 +407,10 @@ def on_birth(self, mother_id, child_id): df.at[child_id, 'un_clinical_acute_malnutrition'] = 'well' df.at[child_id, 'un_am_nutritional_oedema'] = False df.at[child_id, 'un_am_MUAC_category'] = '>=125mm' - # df.loc[df.is_alive, 'un_sam_death_date'] = pd.NaT - # df.loc[df.is_alive, 'un_am_recovery_date'] = pd.NaT - # df.loc[df.is_alive, 'un_am_discharge_date'] = pd.NaT - # df.loc[df.is_alive, 'un_am_tx_start_date'] = pd.NaT + # df.at[child_id, 'un_sam_death_date'] = pd.NaT + # df.at[child_id, 'un_am_recovery_date'] = pd.NaT + # df.at[child_id, 'un_am_discharge_date'] = pd.NaT + # df.at[child_id, 'un_am_tx_start_date'] = pd.NaT df.at[child_id, 'un_am_treatment_type'] = 'not_applicable' df.at[child_id, 'un_recov_to_mam_to_cancel'] = [] df.at[child_id, 'un_full_recov_to_cancel'] = [] From 346ec4d6d7aa69798ce9f0a9f2028e896cbdfea8 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 2 Sep 2025 15:28:54 +0100 Subject: [PATCH 486/755] wast & test_wast: update handling of natural recovery/progression cancellation --- src/tlo/methods/wasting.py | 138 +++++++++++++++++-------------------- tests/test_wasting.py | 37 ++++++---- 2 files changed, 84 insertions(+), 91 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 7e1d1dc486..92f36b1ed4 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -194,13 +194,13 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'none', 'not_applicable']), 'un_am_discharge_date': Property(Types.DATE, 'planned discharge date from current treatment ' 'when recovery will happen if not yet recovered'), - # Properties to help cancel events - 'un_recov_to_mam_to_cancel': Property(Types.LIST, 'list of dates of scheduled natural recovery to be ' - 'canceled for the person'), - 'un_full_recov_to_cancel': Property(Types.LIST, 'list of dates of scheduled recovery with tx ' - 'to be canceled for the person'), - 'un_progression_to_cancel': Property(Types.LIST, 'list of dates of scheduled progression to severe ' - 'wasting to be canceled for the person'), + # Dates on which the events should occur + 'un_recov_to_mam_date': Property(Types.DATE, 'date on which recovery from severe to moderate acute ' + 'malnutrition (SAM to MAM) should occur'), + 'un_full_recov_date': Property(Types.DATE, 'date on which the full recovery for the person should ' + 'occur'), + 'un_progression_date': Property(Types.DATE, 'date on which the progression from moderate to severe ' + 'wasting for the person should occur'), # Properties to avoid double acute malnutrition assessment 'un_last_nonemergency_appt_date': Property(Types.DATE, 'last date of generic non-emergency first ' 'appointment'), @@ -310,12 +310,9 @@ def initialise_population(self, population): # df.loc[df.is_alive, 'un_am_discharge_date'] = pd.NaT # df.loc[df.is_alive, 'un_am_tx_start_date'] = pd.NaT df.loc[df.is_alive, 'un_am_treatment_type'] = 'not_applicable' - df.loc[df.is_alive, 'un_recov_to_mam_to_cancel'] = \ - df.loc[df.is_alive, 'un_recov_to_mam_to_cancel'].apply(lambda x: []) - df.loc[df.is_alive, 'un_full_recov_to_cancel'] = \ - df.loc[df.is_alive, 'un_full_recov_to_cancel'].apply(lambda x: []) - df.loc[df.is_alive, 'un_progression_to_cancel'] = \ - df.loc[df.is_alive, 'un_progression_to_cancel'].apply(lambda x: []) + # df.loc[df.is_alive, 'un_recov_to_mam_date'] = pd.NaT + # df.loc[df.is_alive, 'un_full_recov_date'] = pd.NaT + # df.loc[df.is_alive, 'un_progression_date'] = pd.NaT # df.loc[df.is_alive, 'un_last_nonemergency_appt_date']= pd.NaT # df.loc[df.is_alive, 'un_last_growth_monitoring_appt_date']= pd.NaT @@ -412,9 +409,9 @@ def on_birth(self, mother_id, child_id): # df.at[child_id, 'un_am_discharge_date'] = pd.NaT # df.at[child_id, 'un_am_tx_start_date'] = pd.NaT df.at[child_id, 'un_am_treatment_type'] = 'not_applicable' - df.at[child_id, 'un_recov_to_mam_to_cancel'] = [] - df.at[child_id, 'un_full_recov_to_cancel'] = [] - df.at[child_id, 'un_progression_to_cancel'] = [] + # df.at[child_id, 'un_recov_to_mam_date'] = pd.NaT + # df.at[child_id, 'un_full_recov_date'] = pd.NaT + # df.at[child_id, 'un_progression_date'] = pd.NaT # df.at[child_id, 'un_last_nonemergency_appt_date']= pd.NaT # df.at[child_id, 'un_last_growth_monitoring_appt_date']= pd.NaT @@ -808,7 +805,7 @@ def do_at_generic_first_appt( def do_when_am_treatment(self, person_id, treatment) -> None: """ - Cancels any scheduled natural outcome for the individual; outcomes are now determined solely by the treatment. + Cancels any scheduled natural outcome for the individual; outcome is now determined solely by the treatment. Processes the specified treatment, determines the outcome, and if appropriate, schedules an outcome event and/or an enrolment for a follow-up treatment. @@ -824,17 +821,17 @@ def do_when_am_treatment(self, person_id, treatment) -> None: p = self.parameters rng = self.rng - # natural progression or recovery is cancelled with the treatment and the outcome is fully driven by treatment - self.cancel_future_event(person_id, event_type=Wasting_ProgressionToSevere_Event) - self.cancel_future_event(person_id, event_type=Wasting_FullRecovery_Event) - self.cancel_future_event(person_id, event_type=Wasting_RecoveryToMAM_Event) + # Cancel any scheduled natural outcome (natural recovery, progression, or death) with treatment, + # the outcome will be determined by treatment + df.at[person_id, 'un_recov_to_mam_date'] = pd.NaT + df.at[person_id, 'un_full_recov_date'] = pd.NaT + df.at[person_id, 'un_progression_date'] = pd.NaT + df.at[person_id, 'un_sam_death_date'] = pd.NaT + # Reset treatment discharge date + df.at[person_id, 'un_am_discharge_date'] = pd.NaT # Set the date when the treatment is provided: df.at[person_id, 'un_am_tx_start_date'] = self.sim.date - # Reset treatment discharge date - df.at[person_id, 'un_am_discharge_date'] = pd.NaT - # Cancel natural death due to SAM with treatment - df.at[person_id, 'un_sam_death_date'] = pd.NaT if treatment == 'SFP': outcome_date = self.sim.date + DateOffset(weeks=p['tx_length_weeks_SuppFeedingMAM']) @@ -848,12 +845,13 @@ def do_when_am_treatment(self, person_id, treatment) -> None: ) if mam_full_recovery: - # set discharge date and schedule recovery for that day + # set discharge date and schedule full recovery for that day df.at[person_id, 'un_am_discharge_date'] = outcome_date self.sim.schedule_event( event=Wasting_FullRecovery_Event(module=self, person_id=person_id), - date=(df.at[person_id, 'un_am_discharge_date']) + date=outcome_date ) + df.at[person_id, "un_full_recov_date"] = outcome_date else: # remained MAM, send for another SFP self.sim.modules['HealthSystem'].schedule_hsi_event( @@ -871,12 +869,13 @@ def do_when_am_treatment(self, person_id, treatment) -> None: df.loc[[person_id]], rng ) if sam_full_recovery: + # set discharge date and schedule full recovery for that day df.at[person_id, 'un_am_discharge_date'] = outcome_date - # schedule full recovery self.sim.schedule_event( event=Wasting_FullRecovery_Event(module=self, person_id=person_id), date=outcome_date ) + df.at[person_id, "un_full_recov_date"] = outcome_date # send for follow-up treatment for MAM self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), @@ -895,39 +894,15 @@ def do_when_am_treatment(self, person_id, treatment) -> None: date=outcome_date ) df.at[person_id, 'un_sam_death_date'] = outcome_date - else: # recovery to MAM and send for treatment for MAM + else: # schedule recovery to MAM and send for follow-up SFP df.at[person_id, 'un_am_discharge_date'] = outcome_date self.sim.schedule_event(event=Wasting_RecoveryToMAM_Event(module=self, person_id=person_id), date=outcome_date) + df.at[person_id, "un_recov_to_mam_date"] = outcome_date self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_SupplementaryFeedingProgramme_MAM(module=self, person_id=person_id), priority=0, topen=outcome_date) - def cancel_future_event(self, person_id, event_type) -> None: - """ - This function will add dates of recovery and/or progression events that need to be canceled. - - :param person_id: - :param event_type: which event type to cancel - """ - df = self.sim.population.props - - event_tuples = [event_tuple for event_tuple in self.sim.find_events_for_person(person_id) - if isinstance(event_tuple[1], event_type)] - if event_tuples: - dates = [event_tuple[0] for event_tuple in event_tuples] - event_type_map = { - Wasting_RecoveryToMAM_Event: 'un_recov_to_mam_to_cancel', - Wasting_FullRecovery_Event: 'un_full_recov_to_cancel', - Wasting_ProgressionToSevere_Event: 'un_progression_to_cancel' - } - - # add dates of natural history events to be cancelled due to tx, the health outcome will be driven by the tx - for date in dates: - df.at[person_id, event_type_map[event_type]].append(date) - - # else: event_type not scheduled, hence no need to cancel any - class Wasting_IncidencePoll(RegularEvent, PopulationScopeEventMixin): """ Regular event that determines new cases of wasting (WHZ < -2) to the under-5 population, and schedules @@ -997,6 +972,7 @@ def apply(self, population): self.sim.schedule_event( event=Wasting_ProgressionToSevere_Event(module=self.module, person_id=person_id), date=outcome_date ) + df.at[person_id, "un_progression_date"] = outcome_date # # # MODERATE WASTING NATURAL RECOVERY # # # # # # # # # # # # # # # Schedule recovery for those not progressing to severe wasting --------- @@ -1007,10 +983,12 @@ def apply(self, population): # schedule full recovery after duration of moderate wasting self.sim.schedule_event(event=Wasting_FullRecovery_Event( module=self.module, person_id=person_id), date=outcome_date) + df.at[person_id, "un_full_recov_date"] = outcome_date else: # == SAM # schedule recovery to MAM after duration of moderate wasting self.sim.schedule_event(event=Wasting_RecoveryToMAM_Event( module=self.module, person_id=person_id), date=outcome_date) + df.at[person_id, "un_recov_to_mam_date"] = outcome_date class Wasting_ProgressionToSevere_Event(Event, IndividualScopeEventMixin): """ @@ -1026,21 +1004,21 @@ def __init__(self, module, person_id): def apply(self, person_id): df = self.sim.population.props # shortcut to the dataframe - # if person is already dead or not under 5 or not moderately wasted or is currently treated, the progression - # should not happen + # if the person is already dead, or not under 5, or not moderately wasted, or is currently treated, + # or progression should not occur today; + # the progression will NOT happen if ( (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'age_exact_years'] >= 5) or (df.at[person_id, 'un_WHZ_category'] != '-3<=WHZ<-2') or (df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[person_id, 'un_am_tx_start_date'] < - self.sim.date) + self.sim.date) or + (df.at[person_id, "un_progression_date"] != self.sim.date) ): return - # if natural progression to severe wasting cancelled as person received tx, hence is not happening - if self.sim.date in df.at[person_id, 'un_progression_to_cancel']: - df.at[person_id, 'un_progression_to_cancel'].remove(self.sim.date) - return + # Reset the progression date + df.at[person_id, "un_progression_date"] = pd.NaT # # # INCIDENCE OF SEVERE WASTING # # # # # # # # # # # # # # # # # # # # # # Continue with progression to severe if not treated/recovered @@ -1062,6 +1040,7 @@ def apply(self, person_id): outcome_date = self.sim.date + DateOffset(days=duration_of_untreated_sev_wasting) self.sim.schedule_event(event=Wasting_RecoveryToMAM_Event( module=self.module, person_id=person_id), date=outcome_date) + df.at[person_id, "un_recov_to_mam_date"] = outcome_date # else: death due to SAM scheduled earlier, i.e. natural progression class Wasting_SevereAcuteMalnutritionDeath_Event(Event, IndividualScopeEventMixin): @@ -1097,9 +1076,9 @@ def apply(self, person_id): cause='Severe Acute Malnutrition', originating_module=self.module) # else: - # death is not happening as the person already recovered and didn't get wasted again since, - # or discharge_date is set, hence the person should recover due to tx, or the death was canceled due to tx, - # or the death was canceled due to tx, but scheduled for later as will die with tx anyway + # Death does not occur because the person has already recovered and has not become wasted again, + # or a discharge date is set (indicating recovery due to treatment), + # or the death event was canceled or rescheduled due to treatment. class Wasting_FullRecovery_Event(Event, IndividualScopeEventMixin): """ @@ -1120,16 +1099,15 @@ def apply(self, person_id): else: recov_how = 'tx' - # if already died, should not recover - if not df.at[person_id, 'is_alive']: - return - - # if the natural recovery was cancelled, will not recover now, the outcome will be driven by tx - if self.sim.date in df.at[person_id, 'un_full_recov_to_cancel']: - df.at[person_id, 'un_full_recov_to_cancel'].remove(self.sim.date) + # if the person is already dead, or full recovery should not occur today; + # the recovery will NOT happen + if ( + (not df.at[person_id, 'is_alive']) or + (df.at[person_id, "un_full_recov_date"] != self.sim.date) + ): return - # if not well (i.e. NOT already fully recovered with SAM tx, and send here from follow-up MAM tx) + # if not well (i.e. occurs as result of OTP/ITC, not a follow-up SFP) if df.at[person_id, 'un_WHZ_category'] != 'WHZ>=-2': if df.at[person_id, 'un_WHZ_category'] == '-3<=WHZ<-2': recov_opt = f"mod_{df.at[person_id, 'un_clinical_acute_malnutrition']}_{recov_how}_full_recov" @@ -1173,6 +1151,7 @@ def get_min_length(in_recov_how, in_person_id, in_whz): df.at[person_id, 'un_am_nutritional_oedema'] = False # no oedema df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' # normal MUAC df.at[person_id, 'un_sam_with_complications'] = False + df.at[person_id, "un_full_recov_date"] = pd.NaT df.at[person_id, 'un_sam_death_date'] = pd.NaT df.at[person_id, 'un_am_tx_start_date'] = pd.NaT df.at[person_id, 'un_am_treatment_type'] = 'not_applicable' @@ -1206,9 +1185,13 @@ def apply(self, person_id): if (not df.at[person_id, 'is_alive']) or (df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM'): return - # if the natural recovery was cancelled, will not recover to MAM now, the outcome will be driven by tx - if self.sim.date in df.at[person_id, 'un_recov_to_mam_to_cancel']: - df.at[person_id, 'un_recov_to_mam_to_cancel'].remove(self.sim.date) + # if the person is already dead, or recovered, or recovery to MAM should not occur today; + # the recovery will NOT happen + if ( + (not df.at[person_id, "is_alive"]) or + (df.at[person_id, "un_clinical_acute_malnutrition"] != "SAM") or + (df.at[person_id, "un_recov_to_mam_date"] != self.sim.date) + ): return # For cases with normal WHZ and other acute malnutrition signs: @@ -1266,9 +1249,10 @@ def get_min_length(in_recov_how, in_person_id, in_whz): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' df.at[person_id, 'un_am_nutritional_oedema'] = False df.at[person_id, 'un_sam_with_complications'] = False + df.at[person_id, "un_recov_to_mam_date"] = pd.NaT df.at[person_id, 'un_sam_death_date'] = pd.NaT # death is cancelled if was scheduled - df.at[person_id, 'un_am_tx_start_date'] = pd.NaT # Start without treatment, treatment will be applied with HSI if care sought + df.at[person_id, 'un_am_tx_start_date'] = pd.NaT df.at[person_id, 'un_am_treatment_type'] = 'none' # this will clear all wasting symptoms (applicable for SAM, not MAM) @@ -1285,8 +1269,10 @@ def get_min_length(in_recov_how, in_person_id, in_whz): # natural history (if not treated) if df.at[person_id, 'un_WHZ_category'] == '-3<=WHZ<-2' and progression_severe_wasting_bool: self.sim.schedule_event(Wasting_ProgressionToSevere_Event(self.module, person_id), outcome_date) + df.at[person_id, "un_progression_date"] = outcome_date else: self.sim.schedule_event(Wasting_FullRecovery_Event(self.module, person_id), outcome_date) + df.at[person_id, "un_full_recov_date"] = outcome_date class Wasting_InitiateGrowthMonitoring(Event, PopulationScopeEventMixin): # TODO: maybe will be updated to integrate monitoring of < 1y old in epi module, and on birth schedule to be diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 373244cac2..4266a7488e 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -776,7 +776,7 @@ def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): sim.event_queue.queue = [] # clear the queue # Set moderate wasting incidence rate at 100% and rate of progression to severe wasting at 0%. - # (Hence, all children with normal wasting should get onset of moderate wasting and be scheduled for natural + # (Hence, all children with no wasting should get onset of moderate wasting and be scheduled for natural # recovery.) wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() wmodule.wasting_models.severe_wasting_progression_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) @@ -832,13 +832,18 @@ def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): # Check full recovery with treatment is scheduled before the natural recovery full_recov_events = [event_tuple for event_tuple in sim.find_events_for_person(person_id) if isinstance(event_tuple[1], Wasting_FullRecovery_Event)] - assert len(full_recov_events) in [1, 2], "only 1 or 2 full recovery events should be scheduled" - # with MAM natural full recovery as well as full recovery with treatment - if len(full_recov_events) == 2: - # treatment recovery scheduled to happen before recovery with treatment + if am_state_expected == 'MAM': + assert len(full_recov_events) == 2, (f"Two full recovery events should be scheduled (natural and following " + f"treatment), but {len(full_recov_events)} is/are scheduled.") + # check the natural full recovery is at position 1; + # hence full recovery following treatment will always be at position 0 nat_recov_event_tuple = full_recov_events[1] date_of_scheduled_nat_recov_to_confirm = nat_recov_event_tuple[0] assert date_of_scheduled_nat_recov_to_confirm == date_of_scheduled_nat_recov + else: # complicated SAM + assert len(full_recov_events) == 1, (f"One full recovery event should be scheduled (following treatment)," + f"but {len(full_recov_events)} is/are scheduled.") + # full recovery following treatment at position 0 tx_recov_event_tuple = full_recov_events[0] date_of_scheduled_tx_recov = tx_recov_event_tuple[0] tx_recov_event = tx_recov_event_tuple[1] @@ -860,9 +865,9 @@ def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): # Check natural recovery is going to be cancelled if am_state_expected == 'MAM': - assert date_of_scheduled_nat_recov in df.at[person_id, 'un_full_recov_to_cancel'] + assert pd.isnull(person['un_full_recov_date']) else: # complicated SAM - assert date_of_scheduled_nat_recov in df.at[person_id, 'un_recov_to_mam_to_cancel'] + assert pd.isnull(person["un_recov_to_mam_date"]) # Run the natural recovery, this should have no effect sim.date = date_of_scheduled_nat_recov nat_recov_event.apply(person_id) @@ -879,15 +884,15 @@ def test_tx_recovery_before_nat_recovery_moderate_wasting_scheduled(tmpdir): def test_recovery_before_death_scheduled(tmpdir): - """ Show that if a recovery event is run before when a person was going to die, it causes the episode to end without - the person dying. """ + """ Test that if a recovery event following a treatment occurs before a scheduled death due to untreated SAM, the + person recovers and does not die.""" popsize = 1000 sim = get_sim(tmpdir) # get wasting module wmodule = sim.modules['Wasting'] p = wmodule.parameters - # Set death due to untreated SAM at 0% for all, hence always scheduled natural recovery from SAM + # Set death due to untreated SAM at 0% for all, so natural recovery from SAM is always scheduled p['base_death_rate_untreated_SAM'] = 0.0 p['rr_death_rate_by_agegp'] = [1, 1, 1, 1, 1, 1] @@ -895,13 +900,12 @@ def test_recovery_before_death_scheduled(tmpdir): sim.simulate(end_date=start_date) # zero duration sim.event_queue.queue = [] # clear the queue - # Set moderate wasting incidence, progression to severe wasting, and death rate after SAM care at 100% wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() wmodule.wasting_models.severe_wasting_progression_lm = LinearModel.multiplicative() p['prob_death_after_SAMcare'] = 1.0 - # Set full recovery with SAM care at 0% (and as 100% death rate after SAM care, no recovery to MAM), - # hence they will always die with SAM care + # Set full recovery with SAM care at 0%. With a 100% death rate after SAM care, there will be no recovery to MAM; + # all individuals will die after receiving SAM care. wmodule.wasting_models.acute_malnutrition_recovery_sam_lm = LinearModel(LinearModelType.MULTIPLICATIVE, 0.0) # Ensure the individual has no complications when SAM occurs p['prob_complications_in_SAM'] = 0.0 @@ -962,8 +966,7 @@ def test_recovery_before_death_scheduled(tmpdir): # Run health seeking behavior and ensure non-emergency event is scheduled hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) hsp.run() - - # Check non-emergency care event is scheduled + # check non-emergency care event is scheduled assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) @@ -1004,6 +1007,7 @@ def test_recovery_before_death_scheduled(tmpdir): assert date_of_scheduled_death > date_of_scheduled_nat_recov # Run a full recovery event (it is not scheduled though) + df.at[person_id, 'un_full_recov_date'] = sim.date full_recov_event = Wasting_FullRecovery_Event(person_id=person_id, module=wmodule) full_recov_event.apply(person_id=person_id) @@ -1016,6 +1020,9 @@ def test_recovery_before_death_scheduled(tmpdir): assert not person['un_sam_with_complications'] assert person['un_am_recovery_date'] == sim.date assert pd.isnull(person['un_sam_death_date']) + assert pd.isnull(person['un_recov_to_mam_date']) + assert pd.isnull(person['un_full_recov_date']) + assert pd.isnull(person['un_progression_date']) assert person['is_alive'] # Run the death event that was originally scheduled - this should have no effect and the person should not die From 15eadb6f3efe870162348c848ad69f068331e474 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 10 Sep 2025 15:06:17 +0100 Subject: [PATCH 487/755] wast: determining if patient will attend to growth monitoring moved to `__init__` --- src/tlo/methods/wasting.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 92f36b1ed4..95b9a47277 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1333,30 +1333,27 @@ def __init__(self, module, person_id): super().__init__(module, person_id=person_id) assert isinstance(module, Wasting) - self.attendance = None - self.TREATMENT_ID = "Undernutrition_GrowthMonitoring" self.ACCEPTED_FACILITY_LEVEL = '1a' - @property - def EXPECTED_APPT_FOOTPRINT(self): - """Return the expected appointment footprint based on attendance at the HSI event.""" rng = self.module.rng p = self.module.parameters person_age = self.sim.population.props.loc[self.target].age_exact_years - - # TODO: for now assumed general attendance prob for <1 y old, - # later may be excluded from here and be dealt with within epi module def get_attendance_prob(age): if age < 1: - return p['growth_monitoring_attendance_prob_agecat'][0] + return p["growth_monitoring_attendance_prob_agecat"][0] if age <= 2: - return p['growth_monitoring_attendance_prob_agecat'][1] + return p["growth_monitoring_attendance_prob_agecat"][1] else: - return p['growth_monitoring_attendance_prob_agecat'][2] + return p["growth_monitoring_attendance_prob_agecat"][2] + self.attendance = rng.random_sample() < get_attendance_prob(person_age) + @property + def EXPECTED_APPT_FOOTPRINT(self): + """Return the expected appointment footprint based on attendance at the HSI event.""" + # TODO: for now assumed general attendance prob for <1 y old, + # later may be excluded from here and be dealt with within epi module # perform growth monitoring if attending - self.attendance = rng.random_sample() < get_attendance_prob(person_age) if self.attendance: return self.make_appt_footprint({'Under5OPD': 1}) else: @@ -1409,6 +1406,10 @@ def get_monitoring_frequency_days(age): # TODO: as stated above, for now we schedule next monitoring for all children, even those sent for treatment schedule_next_monitoring() + # the person may not attend the appt + if not self.attendance: + return + # if person currently treated, or acute malnutrition already assessed, # it will not be assessed (again) # TODO: later could be scheduled for monitoring within the tx to use the resources @@ -1417,10 +1418,6 @@ def get_monitoring_frequency_days(age): (self.sim.date == df.at[person_id, 'un_last_nonemergency_appt_date']): return - # the person may not attend the appt - if not self.attendance: - return - # Acute malnutrition assessment # ### # track the date of the last growth-monitoring appt From 367b1b029c5ce05aa54dbe6130421dc95d4ac0a8 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 10 Sep 2025 15:29:42 +0100 Subject: [PATCH 488/755] wast: add all equipment (not conditional on whether it is available or not) --- src/tlo/methods/wasting.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 95b9a47277..79baf085f8 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1423,12 +1423,8 @@ def get_monitoring_frequency_days(age): # track the date of the last growth-monitoring appt df.at[person_id, 'un_last_growth_monitoring_appt_date'] = self.sim.date - available_equipment = [] - for equip in ['Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape']: - available = rng.random_sample() < HSI_Event.probability_all_equipment_available(self, equip) - if available: - available_equipment.append(equip) - self.add_equipment(set(available_equipment)) + # Add required equipment + self.add_equipment({'Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape'}) def schedule_tx_by_diagnosis(hsi_event): self.sim.modules['HealthSystem'].schedule_hsi_event( From 27abe73909d343387704764c080181beb903e087 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 10 Sep 2025 16:04:50 +0100 Subject: [PATCH 489/755] wast: rm redundant pass statements in did_not_run methods --- src/tlo/methods/wasting.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 79baf085f8..18f62b1f9f 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1461,7 +1461,6 @@ def did_not_run(self): logger.debug(key="HSI_Wasting_GrowthMonitoring", data="HSI_Wasting_GrowthMonitoring: did not run" ) - pass class HSI_Wasting_SupplementaryFeedingProgramme_MAM(HSI_Event, IndividualScopeEventMixin): @@ -1509,7 +1508,6 @@ def apply(self, person_id, squeeze_factor): def did_not_run(self): logger.debug(key='debug', data=f'{self.TREATMENT_ID}: did not run') - pass class HSI_Wasting_OutpatientTherapeuticProgramme_SAM(HSI_Event, IndividualScopeEventMixin): @@ -1560,7 +1558,6 @@ def apply(self, person_id, squeeze_factor): def did_not_run(self): logger.debug(key='debug', data=f'{self.TREATMENT_ID}: did not run') - pass class HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM(HSI_Event, IndividualScopeEventMixin): From ef87f993df12eba109c11df5ef24b61996a170e4 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 10 Sep 2025 16:09:50 +0100 Subject: [PATCH 490/755] wast: initialise HSI event footprint using built-in function --- src/tlo/methods/wasting.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 18f62b1f9f..9a4737b709 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1471,14 +1471,9 @@ class HSI_Wasting_SupplementaryFeedingProgramme_MAM(HSI_Event, IndividualScopeEv def __init__(self, module, person_id): super().__init__(module, person_id=person_id) - # Get a blank footprint and then edit to define call on resources - # of this treatment event - the_appt_footprint = self.sim.modules["HealthSystem"].get_blank_appt_footprint() - the_appt_footprint['Under5OPD'] = 1 # This requires one outpatient - # Define the necessary information for an HSI self.TREATMENT_ID = 'Undernutrition_Feeding_Supplementary' - self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint + self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({"Under5OPD": 1}) self.ACCEPTED_FACILITY_LEVEL = '1a' self.ALERT_OTHER_DISEASES = [] @@ -1518,14 +1513,9 @@ class HSI_Wasting_OutpatientTherapeuticProgramme_SAM(HSI_Event, IndividualScopeE def __init__(self, module, person_id): super().__init__(module, person_id=person_id) - # Get a blank footprint and then edit to define call on resources - # of this treatment event - the_appt_footprint = self.sim.modules["HealthSystem"].get_blank_appt_footprint() - the_appt_footprint['U5Malnutr'] = 1 - # Define the necessary information for an HSI self.TREATMENT_ID = 'Undernutrition_Feeding_Outpatient' - self.EXPECTED_APPT_FOOTPRINT = the_appt_footprint + self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({"U5Malnutr": 1}) self.ACCEPTED_FACILITY_LEVEL = '1a' self.ALERT_OTHER_DISEASES = [] From 0e5adb46edb5c48a7891f914f237f1853a1c6bfa Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 10 Sep 2025 16:11:24 +0100 Subject: [PATCH 491/755] wast: rm deprecated ALERT_OTHER_DISEASES declarations --- src/tlo/methods/wasting.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 9a4737b709..51d455bb5f 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1475,7 +1475,6 @@ def __init__(self, module, person_id): self.TREATMENT_ID = 'Undernutrition_Feeding_Supplementary' self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({"Under5OPD": 1}) self.ACCEPTED_FACILITY_LEVEL = '1a' - self.ALERT_OTHER_DISEASES = [] def apply(self, person_id, squeeze_factor): assert isinstance(self.module, Wasting) @@ -1517,7 +1516,6 @@ def __init__(self, module, person_id): self.TREATMENT_ID = 'Undernutrition_Feeding_Outpatient' self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({"U5Malnutr": 1}) self.ACCEPTED_FACILITY_LEVEL = '1a' - self.ALERT_OTHER_DISEASES = [] def apply(self, person_id, squeeze_factor): assert isinstance(self.module, Wasting) @@ -1562,7 +1560,6 @@ def __init__(self, module, person_id): self.TREATMENT_ID = 'Undernutrition_Feeding_Inpatient' self.EXPECTED_APPT_FOOTPRINT = self.make_appt_footprint({"U5Malnutr": 1}) self.ACCEPTED_FACILITY_LEVEL = '2' - self.ALERT_OTHER_DISEASES = [] self.BEDDAYS_FOOTPRINT = self.make_beddays_footprint({'general_bed': 7}) def apply(self, person_id, squeeze_factor): From 0da656e432ad5016718e7d5ce6aa63a4b5dd4d50 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 10 Sep 2025 16:45:48 +0100 Subject: [PATCH 492/755] wast: fnc instead of Event to schedule growth monitoring for all under-5 children on initiation --- src/tlo/methods/wasting.py | 94 ++++++++++++++++---------------------- 1 file changed, 40 insertions(+), 54 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 51d455bb5f..52f8b0ae4d 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -373,17 +373,21 @@ def get_onset_day(whz_category: str): def initialise_simulation(self, sim): """ Prepares for simulation. Schedules: - * the first growth monitoring to happen straight away, scheduled monthly to detect new cases for treatment, - * the main incidence polling event, - * the main logging event. + * the logging of initial values, + * the first monthly incidence polling event, + * the first annual logging event, + * the first growth monitoring for all children under 5. + + Initiates growth monitoring for all children under 5. :param sim: """ sim.schedule_event(Wasting_InitLoggingEvent(self), sim.date) - sim.schedule_event(Wasting_InitiateGrowthMonitoring(self), sim.date) sim.schedule_event(Wasting_IncidencePoll(self), sim.date + DateOffset(months=1)) sim.schedule_event(Wasting_LoggingEvent(self), sim.date + DateOffset(years=1)) + # Schedule growth monitoring for all children under 5 + self.schedule_growth_monitoring_on_initiation() # Retrieve the consumables codes and amounts of the consumables used self.cons_codes = self.get_consumables_for_each_treatment() @@ -421,6 +425,37 @@ def on_birth(self, mother_id, child_id): priority=2, topen=self.sim.date + pd.DateOffset(days=1) ) + def schedule_growth_monitoring_on_initiation(self): + """ + Schedules HSI_Wasting_GrowthMonitoring for all under-5 children at simulation initiation for a random day within + the age-dependent frequency. + """ + df = self.sim.population.props + p = self.parameters + rng = self.rng + + under5_idx = df.index[df.is_alive & (df.age_exact_years < 5)] + + def get_monitoring_frequency_days(age): + if age < 1: + return p["growth_monitoring_frequency_days_agecat"][0] + elif age <= 2: + return p["growth_monitoring_frequency_days_agecat"][1] + else: + return p["growth_monitoring_frequency_days_agecat"][2] + + # schedule monitoring within age-dependent frequency + for person_id in under5_idx: + next_event_days = rng.randint( + 0, max(0, (get_monitoring_frequency_days(df.at[person_id, "age_exact_years"]) - 2)) + ) + if (df.at[person_id, "age_exact_years"] + (next_event_days / 365.25)) < 5: + self.sim.modules["HealthSystem"].schedule_hsi_event( + hsi_event=HSI_Wasting_GrowthMonitoring(module=self, person_id=person_id), + priority=2, + topen=self.sim.date + pd.DateOffset(days=next_event_days), + ) + def muac_cutoff_by_WHZ(self, idx, whz) -> None: """ Determines the MUAC (Mid-Upper Arm Circumference) category for each individual specified in `idx`, based on a @@ -1274,54 +1309,6 @@ def get_min_length(in_recov_how, in_person_id, in_whz): self.sim.schedule_event(Wasting_FullRecovery_Event(self.module, person_id), outcome_date) df.at[person_id, "un_full_recov_date"] = outcome_date -class Wasting_InitiateGrowthMonitoring(Event, PopulationScopeEventMixin): - # TODO: maybe will be updated to integrate monitoring of < 1y old in epi module, and on birth schedule to be - # monitored within wasting module only when > 1y old - """ - Event that schedules HSI_Wasting_GrowthMonitoring for all under-5 children for a random day within the age-dependent - frequency. - """ - - def __init__(self, module): - """Runs only once, when simulation is initiated. - :param module: the module that created this event - """ - super().__init__(module) - assert isinstance(module, Wasting) - - def apply(self, population): - """Apply this event to the population. - :param population: the current population - """ - - df = population.props - rng = self.module.rng - p = self.module.parameters - - # TODO: including treated children? (until there is growth monitoring with tx and scheduled post-tx, yes) - under5_idx = df.index[df.is_alive & (df.age_exact_years < 5)] - # and ~df.un_am_treatment_type.isin(['standard_RUTF', 'soy_RUSF', 'CSB++', 'inpatient_care']) - - def get_monitoring_frequency_days(age): - # TODO: maybe in future 0-1 to be dealt with within epi module - if age < 1: - return p['growth_monitoring_frequency_days_agecat'][0] - elif age <= 2: - return p['growth_monitoring_frequency_days_agecat'][1] - else: - return p['growth_monitoring_frequency_days_agecat'][2] - - # schedule monitoring within age-dependent frequency - for person_id in under5_idx: - next_event_days = \ - rng.randint(0, max(0, (get_monitoring_frequency_days(df.at[person_id, 'age_exact_years']) - 2))) - if (df.at[person_id, 'age_exact_years'] + (next_event_days / 365.25)) < 5: - self.sim.modules['HealthSystem'].schedule_hsi_event( - hsi_event=HSI_Wasting_GrowthMonitoring(module=self.module, person_id=person_id), - priority=2, topen=self.sim.date + pd.DateOffset(days=next_event_days) - ) - - class HSI_Wasting_GrowthMonitoring(HSI_Event, IndividualScopeEventMixin): """ Attendance is determined for the HSI. If the child attends, measurements with available equipment are performed for that child. Based on these measurements, the child can be diagnosed as well/MAM/(un)complicated SAM and @@ -1363,7 +1350,6 @@ def apply(self, person_id, squeeze_factor): logger.debug(key='debug', data='This is HSI_Wasting_GrowthMonitoring') df = self.sim.population.props - rng = self.module.rng p = self.module.parameters # TODO: Will they be monitored during the treatment? Can we assume, that after the treatment they will be @@ -1411,7 +1397,7 @@ def get_monitoring_frequency_days(age): return # if person currently treated, or acute malnutrition already assessed, - # it will not be assessed (again) + # acute malnutrition will not be assessed (again) # TODO: later could be scheduled for monitoring within the tx to use the resources if (df.at[person_id, 'un_last_wasting_date_of_onset'] < df.at[person_id, 'un_am_tx_start_date'] < self.sim.date) or \ From adacf9b869b2e0978daf73f0a9d17415bd4576c2 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 10 Sep 2025 17:05:55 +0100 Subject: [PATCH 493/755] 2K scenarios: add new SQ_1y, and SQ_2y scenarios, 1 draw, 1 run --- .../2K/scenario_wasting_full_model_SQ_1y.py | 60 +++++++++++++++++++ .../2K/scenario_wasting_full_model_SQ_2ys.py | 60 +++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 src/scripts/wasting_analyses/scenarios/2K/scenario_wasting_full_model_SQ_1y.py create mode 100644 src/scripts/wasting_analyses/scenarios/2K/scenario_wasting_full_model_SQ_2ys.py diff --git a/src/scripts/wasting_analyses/scenarios/2K/scenario_wasting_full_model_SQ_1y.py b/src/scripts/wasting_analyses/scenarios/2K/scenario_wasting_full_model_SQ_1y.py new file mode 100644 index 0000000000..1668b4d03a --- /dev/null +++ b/src/scripts/wasting_analyses/scenarios/2K/scenario_wasting_full_model_SQ_1y.py @@ -0,0 +1,60 @@ +""" +This file defines a scenario for wasting analysis. + +It can be submitted on Azure Batch by running: + + tlo batch-submit src/scripts/wasting_analyses/scenarios/2K/scenario_wasting_full_model_SQ_2y.py + +or locally using: + + tlo scenario-run src/scripts/wasting_analyses/scenarios/2K/scenario_wasting_full_model_SQ_2y.py +""" +# import itertools +import warnings + +from tlo import Date, logging +from tlo.analysis.utils import get_parameters_for_status_quo +from tlo.methods.fullmodel import fullmodel +from tlo.scenario import BaseScenario + +# capture warnings during simulation run +warnings.simplefilter('default', (UserWarning, RuntimeWarning)) + + +class WastingAnalysis(BaseScenario): + + def __init__(self): + super().__init__( + seed=0, + start_date=Date(year=2010, month=1, day=1), + end_date=Date(year=2011, month=1, day=2), + initial_population_size=2_000, + number_of_draws=1, + runs_per_draw=1, + ) + + def log_configuration(self): + return { + 'filename': 'wasting_analysis__full_model_SQ', + 'directory': './outputs/wasting_analysis', + "custom_levels": { # Customise the output of specific loggers + "tlo.methods.demography": logging.INFO, + "tlo.methods.healthburden": logging.INFO, + 'tlo.methods.healthsystem.summary': logging.INFO, + "tlo.methods.population": logging.INFO, + "tlo.methods.wasting": logging.DEBUG, + '*': logging.WARNING + } + } + + def modules(self): + return fullmodel() + + # Keeping Status Quo parameters + def draw_parameters(self, draw_number, rng): + return get_parameters_for_status_quo() + +if __name__ == '__main__': + from tlo.cli import scenario_run + + scenario_run([__file__]) diff --git a/src/scripts/wasting_analyses/scenarios/2K/scenario_wasting_full_model_SQ_2ys.py b/src/scripts/wasting_analyses/scenarios/2K/scenario_wasting_full_model_SQ_2ys.py new file mode 100644 index 0000000000..1668b4d03a --- /dev/null +++ b/src/scripts/wasting_analyses/scenarios/2K/scenario_wasting_full_model_SQ_2ys.py @@ -0,0 +1,60 @@ +""" +This file defines a scenario for wasting analysis. + +It can be submitted on Azure Batch by running: + + tlo batch-submit src/scripts/wasting_analyses/scenarios/2K/scenario_wasting_full_model_SQ_2y.py + +or locally using: + + tlo scenario-run src/scripts/wasting_analyses/scenarios/2K/scenario_wasting_full_model_SQ_2y.py +""" +# import itertools +import warnings + +from tlo import Date, logging +from tlo.analysis.utils import get_parameters_for_status_quo +from tlo.methods.fullmodel import fullmodel +from tlo.scenario import BaseScenario + +# capture warnings during simulation run +warnings.simplefilter('default', (UserWarning, RuntimeWarning)) + + +class WastingAnalysis(BaseScenario): + + def __init__(self): + super().__init__( + seed=0, + start_date=Date(year=2010, month=1, day=1), + end_date=Date(year=2011, month=1, day=2), + initial_population_size=2_000, + number_of_draws=1, + runs_per_draw=1, + ) + + def log_configuration(self): + return { + 'filename': 'wasting_analysis__full_model_SQ', + 'directory': './outputs/wasting_analysis', + "custom_levels": { # Customise the output of specific loggers + "tlo.methods.demography": logging.INFO, + "tlo.methods.healthburden": logging.INFO, + 'tlo.methods.healthsystem.summary': logging.INFO, + "tlo.methods.population": logging.INFO, + "tlo.methods.wasting": logging.DEBUG, + '*': logging.WARNING + } + } + + def modules(self): + return fullmodel() + + # Keeping Status Quo parameters + def draw_parameters(self, draw_number, rng): + return get_parameters_for_status_quo() + +if __name__ == '__main__': + from tlo.cli import scenario_run + + scenario_run([__file__]) From 3b722dff3e5bb080b6efcafc0ed1799017f90a51 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 10 Sep 2025 18:36:49 +0100 Subject: [PATCH 494/755] [skip ci] wast: minor (update logging docstring to reflect logs are done on the first day of year) --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 52f8b0ae4d..d5cc51b8b3 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1716,7 +1716,7 @@ class Wasting_LoggingEvent(RegularEvent, PopulationScopeEventMixin): of wasting cases at recovery point since the previous logging, the prevalence proportions at the time of logging, and population sizes at the time of logging. Analysis scripts expect that the frequency of this logging event is once per year. Logs are expected to happen on - the last day of each year. + the first day of each year. """ def __init__(self, module): From 1306cf172f472dda696514d0c6dca659a7bba809 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 10 Sep 2025 18:54:37 +0100 Subject: [PATCH 495/755] [skip ci] wast: minor (rm redundant docstring in initialise_simulation fnc) --- src/tlo/methods/wasting.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index d5cc51b8b3..074e3eabdc 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -378,8 +378,6 @@ def initialise_simulation(self, sim): * the first annual logging event, * the first growth monitoring for all children under 5. - Initiates growth monitoring for all children under 5. - :param sim: """ From 804ebc86ffe86da44968587fd51d1bb64b30e688 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 17 Sep 2025 22:40:39 +0100 Subject: [PATCH 496/755] wast: rm last redundant pass statement in did_not_run method --- src/tlo/methods/wasting.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 074e3eabdc..a9cd3c7527 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1574,7 +1574,6 @@ def apply(self, person_id, squeeze_factor): def did_not_run(self): logger.debug(key='debug', data=f'{self.TREATMENT_ID}: did not run') - pass class WastingModels: From 47ead060ecb5299649efb6604d64747644caa675 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 19 Sep 2025 18:30:52 +0100 Subject: [PATCH 497/755] [skip ci] wast: join init and annual loggings --- src/tlo/methods/wasting.py | 340 +++++++++++++++---------------------- 1 file changed, 135 insertions(+), 205 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index a9cd3c7527..0efd0eb27b 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -9,7 +9,7 @@ import pandas as pd from scipy.stats import norm -from tlo import DateOffset, Module, Parameter, Property, Types, logging +from tlo import Date, DateOffset, Module, Parameter, Property, Types, logging from tlo.events import Event, IndividualScopeEventMixin, PopulationScopeEventMixin, RegularEvent from tlo.lm import LinearModel, LinearModelType, Predictor from tlo.methods import Metadata @@ -373,17 +373,14 @@ def get_onset_day(whz_category: str): def initialise_simulation(self, sim): """ Prepares for simulation. Schedules: - * the logging of initial values, - * the first monthly incidence polling event, * the first annual logging event, + * the first monthly incidence polling event, * the first growth monitoring for all children under 5. :param sim: """ - - sim.schedule_event(Wasting_InitLoggingEvent(self), sim.date) + sim.schedule_event(Wasting_LoggingEvent(self), sim.date) sim.schedule_event(Wasting_IncidencePoll(self), sim.date + DateOffset(months=1)) - sim.schedule_event(Wasting_LoggingEvent(self), sim.date + DateOffset(years=1)) # Schedule growth monitoring for all children under 5 self.schedule_growth_monitoring_on_initiation() @@ -1711,7 +1708,9 @@ class Wasting_LoggingEvent(RegularEvent, PopulationScopeEventMixin): """ This Event logs the number of incident cases that have occurred since the previous logging event, the average length of wasting cases at recovery point since the previous logging, the prevalence proportions at the time of logging, - and population sizes at the time of logging. + and population sizes at the time of logging. At initiation only prevalence proportions and population sizes are + logged. + Analysis scripts expect that the frequency of this logging event is once per year. Logs are expected to happen on the first day of each year. """ @@ -1728,136 +1727,139 @@ def apply(self, population): df = self.sim.population.props p = self.module.parameters - # ----- INCIDENCE LOG ---------------- - # Convert the list of timestamps into a number of timestamps - # and check that all the dates have occurred since self.date_last_run - inc_df = pd.DataFrame(index=self.module.wasting_incident_case_tracker.keys(), - columns=self.module.wasting_states) - for age_grp in self.module.wasting_incident_case_tracker.keys(): - for state in self.module.wasting_states: - inc_df.loc[age_grp, state] = len(self.module.wasting_incident_case_tracker[age_grp][state]) - assert all(date >= self.date_last_run for - date in self.module.wasting_incident_case_tracker[age_grp][state]), \ - f"Some incident cases trying to be logged on {self.sim.date=} from the day of last log "\ - f"{self.date_last_run=} or before." - - logger.info(key='wasting_incidence_count', data=inc_df.to_dict(), - description="Moderate wasting incidence cases are logged for the previous month, while severe " - "wasting incidence cases are logged for the current month.") - - # Reset the incidence tracker and the date_last_run - self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) - self.date_last_run = self.sim.date - - # ----- LENGTH LOG ---------------- - # Convert the list of lengths to an avg length - # and check that all the lengths are positive - length_df = pd.DataFrame(index=self.module.wasting_length_tracker.keys(), - columns=self.module.recovery_options) - for age_grp in self.module.wasting_length_tracker.keys(): - for recov_opt in self.module.recovery_options: - if self.module.wasting_length_tracker[age_grp][recov_opt]: - length_df.loc[age_grp, recov_opt] = (sum(self.module.wasting_length_tracker[age_grp][recov_opt]) / - len(self.module.wasting_length_tracker[age_grp][recov_opt])) - else: - length_df.loc[age_grp, recov_opt] = 0 - assert not np.isnan(length_df.loc[age_grp, recov_opt]),\ - f'There is an empty length for {age_grp=}, {recov_opt=}.' - - if recov_opt in ['mod_MAM_nat_full_recov', 'mod_SAM_nat_recov_to_MAM']: - assert all(length >= (p['duration_of_untreated_mod_wasting'] - 1) for length in - self.module.wasting_length_tracker[age_grp][recov_opt]),\ - f"{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < "\ - f"{(p['duration_of_untreated_mod_wasting'] - 1)=}; {age_grp=}, {recov_opt=}" - elif recov_opt in ['sev_SAM_nat_recov_to_MAM']: - assert all(length >= - (p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] - 2) for - length in self.module.wasting_length_tracker[age_grp][recov_opt]),\ - (f"{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < duration of " - "(mod + sev wast - 2): " - f"{(p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] - 2)=} " - f"days; {age_grp=}, {recov_opt=}") - elif recov_opt in ['mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', 'mod_SAM_tx_recov_to_MAM', - 'sev_SAM_tx_full_recov', 'sev_SAM_tx_recov_to_MAM']: - if recov_opt == 'mod_MAM_tx_full_recov': - min_length = (p['tx_length_weeks_SuppFeedingMAM'] * 7) - 1 - else: - min_length = \ - (min(p['tx_length_weeks_OutpatientSAM'], p['tx_length_weeks_InpatientSAM']) * 7) - 1 - - assert all(length >= min_length for length in - self.module.wasting_length_tracker[age_grp][recov_opt]), \ - f'{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < ' \ - f'{min_length=} days; {age_grp=}, {recov_opt=}' - - assert recov_opt in self.module.recovery_options, f'\nInvalid {recov_opt=}.' - - # Reset the length tracker - self.module.wasting_length_tracker = copy.deepcopy(self.module.wasting_length_tracker_blank) - under5s = df.loc[df.is_alive & (df.age_exact_years < 5)] above5s = df.loc[df.is_alive & (df.age_exact_years >= 5)] - for age_ys in range(6): - age_grp = self.module.age_grps.get(age_ys, '5+y') - - # get those children who are wasted - if age_ys < 5: - mod_wasted_whole_ys_agegrp = under5s[( - under5s.age_years.between(age_ys, age_ys + 1, inclusive='left') & - (under5s.un_WHZ_category == '-3<=WHZ<-2') - )] - sev_wasted_whole_ys_agegrp = under5s[( - under5s.age_years.between(age_ys, age_ys + 1, inclusive='left') & - (under5s.un_WHZ_category == 'WHZ<-3') - )] - else: - mod_wasted_whole_ys_agegrp = above5s[( - above5s.un_WHZ_category == '-3<=WHZ<-2' - )] - sev_wasted_whole_ys_agegrp = above5s[( - above5s.un_WHZ_category == 'WHZ<-3' - )] - mod_wasted_whole_ys_agegrp = mod_wasted_whole_ys_agegrp.copy() - mod_wasted_whole_ys_agegrp.loc[:, 'wasting_length'] = \ - (self.sim.date - mod_wasted_whole_ys_agegrp['un_last_wasting_date_of_onset']).dt.days - sev_wasted_whole_ys_agegrp = sev_wasted_whole_ys_agegrp.copy() - sev_wasted_whole_ys_agegrp.loc[:, 'wasting_length'] = \ - (self.sim.date - sev_wasted_whole_ys_agegrp['un_last_wasting_date_of_onset']).dt.days - if len(mod_wasted_whole_ys_agegrp) > 0: - assert not np.isnan(mod_wasted_whole_ys_agegrp['wasting_length']).any(),\ - ("There is at least one NaN length.\n" - f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") - assert all(length > 0 for length in mod_wasted_whole_ys_agegrp['wasting_length']),\ - ("There is at least one zero length.\n" - f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") - length_df.loc[age_grp, 'mod_not_yet_recovered'] = ( - sum(mod_wasted_whole_ys_agegrp['wasting_length']) / - len(mod_wasted_whole_ys_agegrp['wasting_length']) - ) - else: - length_df.loc[age_grp, 'mod_not_yet_recovered'] = 0 - assert not np.isnan(length_df.loc[age_grp, 'mod_not_yet_recovered']), \ - f"The avg {length_df.loc[age_grp, 'mod_not_yet_recovered']=} for {age_grp=} is empty." - - if len(sev_wasted_whole_ys_agegrp) > 0: - assert not np.isnan(sev_wasted_whole_ys_agegrp['wasting_length']).any(), \ - ("There is at least one NaN length.\n" - f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") - - assert all(length > 0 for length in sev_wasted_whole_ys_agegrp['wasting_length']), \ - ("There is at least one zero length.\n" - f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") - length_df.loc[age_grp, 'sev_not_yet_recovered'] = ( - sum(sev_wasted_whole_ys_agegrp['wasting_length']) / - len(sev_wasted_whole_ys_agegrp['wasting_length']) - ) - else: - length_df.loc[age_grp, 'sev_not_yet_recovered'] = 0 - assert not np.isnan(length_df.loc[age_grp, 'sev_not_yet_recovered']), \ - f"The avg {length_df.loc[age_grp, 'sev_not_yet_recovered']=} for {age_grp=} is empty." + if self.sim.date > Date(year=2010, month=1, day=1): + + # ----- INCIDENCE LOG ---------------- + # Convert the list of timestamps into a number of timestamps + # and check that all the dates have occurred since self.date_last_run + inc_df = pd.DataFrame(index=self.module.wasting_incident_case_tracker.keys(), + columns=self.module.wasting_states) + for age_grp in self.module.wasting_incident_case_tracker.keys(): + for state in self.module.wasting_states: + inc_df.loc[age_grp, state] = len(self.module.wasting_incident_case_tracker[age_grp][state]) + assert all(date >= self.date_last_run for + date in self.module.wasting_incident_case_tracker[age_grp][state]), \ + f"Some incident cases trying to be logged on {self.sim.date=} from the day of last log "\ + f"{self.date_last_run=} or before." + + logger.info(key='wasting_incidence_count', data=inc_df.to_dict(), + description="Moderate wasting incidence cases are logged for the previous month, while severe " + "wasting incidence cases are logged for the current month.") + + # Reset the incidence tracker and the date_last_run + self.module.wasting_incident_case_tracker = copy.deepcopy(self.module.wasting_incident_case_tracker_blank) + self.date_last_run = self.sim.date + + # ----- LENGTH LOG ---------------- + # Convert the list of lengths to an avg length + # and check that all the lengths are positive + length_df = pd.DataFrame(index=self.module.wasting_length_tracker.keys(), + columns=self.module.recovery_options) + for age_grp in self.module.wasting_length_tracker.keys(): + for recov_opt in self.module.recovery_options: + if self.module.wasting_length_tracker[age_grp][recov_opt]: + length_df.loc[age_grp, recov_opt] = \ + (sum(self.module.wasting_length_tracker[age_grp][recov_opt]) / + len(self.module.wasting_length_tracker[age_grp][recov_opt])) + else: + length_df.loc[age_grp, recov_opt] = 0 + assert not np.isnan(length_df.loc[age_grp, recov_opt]),\ + f'There is an empty length for {age_grp=}, {recov_opt=}.' + + if recov_opt in ['mod_MAM_nat_full_recov', 'mod_SAM_nat_recov_to_MAM']: + assert all(length >= (p['duration_of_untreated_mod_wasting'] - 1) for length in + self.module.wasting_length_tracker[age_grp][recov_opt]),\ + f"{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < "\ + f"{(p['duration_of_untreated_mod_wasting'] - 1)=}; {age_grp=}, {recov_opt=}" + elif recov_opt in ['sev_SAM_nat_recov_to_MAM']: + assert all(length >= + (p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] - 2) + for length in self.module.wasting_length_tracker[age_grp][recov_opt]),\ + (f"{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < duration " + "of (mod + sev wast - 2): " + f"{(p['duration_of_untreated_mod_wasting'] + p['duration_of_untreated_sev_wasting'] - 2)=}" + f" days; {age_grp=}, {recov_opt=}") + elif recov_opt in ['mod_MAM_tx_full_recov', 'mod_SAM_tx_full_recov', 'mod_SAM_tx_recov_to_MAM', + 'sev_SAM_tx_full_recov', 'sev_SAM_tx_recov_to_MAM']: + if recov_opt == 'mod_MAM_tx_full_recov': + min_length = (p['tx_length_weeks_SuppFeedingMAM'] * 7) - 1 + else: + min_length = \ + (min(p['tx_length_weeks_OutpatientSAM'], p['tx_length_weeks_InpatientSAM']) * 7) - 1 + + assert all(length >= min_length for length in + self.module.wasting_length_tracker[age_grp][recov_opt]), \ + f'{self.module.wasting_length_tracker[age_grp][recov_opt]=} contains length(s) < ' \ + f'{min_length=} days; {age_grp=}, {recov_opt=}' + + assert recov_opt in self.module.recovery_options, f'\nInvalid {recov_opt=}.' + + # Reset the length tracker + self.module.wasting_length_tracker = copy.deepcopy(self.module.wasting_length_tracker_blank) + + for age_ys in range(6): + age_grp = self.module.age_grps.get(age_ys, '5+y') - logger.info(key='wasting_length_avg', data=length_df.to_dict()) + # get those children who are wasted + if age_ys < 5: + mod_wasted_whole_ys_agegrp = under5s[( + under5s.age_years.between(age_ys, age_ys + 1, inclusive='left') & + (under5s.un_WHZ_category == '-3<=WHZ<-2') + )] + sev_wasted_whole_ys_agegrp = under5s[( + under5s.age_years.between(age_ys, age_ys + 1, inclusive='left') & + (under5s.un_WHZ_category == 'WHZ<-3') + )] + else: + mod_wasted_whole_ys_agegrp = above5s[( + above5s.un_WHZ_category == '-3<=WHZ<-2' + )] + sev_wasted_whole_ys_agegrp = above5s[( + above5s.un_WHZ_category == 'WHZ<-3' + )] + mod_wasted_whole_ys_agegrp = mod_wasted_whole_ys_agegrp.copy() + mod_wasted_whole_ys_agegrp.loc[:, 'wasting_length'] = \ + (self.sim.date - mod_wasted_whole_ys_agegrp['un_last_wasting_date_of_onset']).dt.days + sev_wasted_whole_ys_agegrp = sev_wasted_whole_ys_agegrp.copy() + sev_wasted_whole_ys_agegrp.loc[:, 'wasting_length'] = \ + (self.sim.date - sev_wasted_whole_ys_agegrp['un_last_wasting_date_of_onset']).dt.days + if len(mod_wasted_whole_ys_agegrp) > 0: + assert not np.isnan(mod_wasted_whole_ys_agegrp['wasting_length']).any(),\ + ("There is at least one NaN length.\n" + f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") + assert all(length > 0 for length in mod_wasted_whole_ys_agegrp['wasting_length']),\ + ("There is at least one zero length.\n" + f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") + length_df.loc[age_grp, 'mod_not_yet_recovered'] = ( + sum(mod_wasted_whole_ys_agegrp['wasting_length']) / + len(mod_wasted_whole_ys_agegrp['wasting_length']) + ) + else: + length_df.loc[age_grp, 'mod_not_yet_recovered'] = 0 + assert not np.isnan(length_df.loc[age_grp, 'mod_not_yet_recovered']), \ + f"The avg {length_df.loc[age_grp, 'mod_not_yet_recovered']=} for {age_grp=} is empty." + + if len(sev_wasted_whole_ys_agegrp) > 0: + assert not np.isnan(sev_wasted_whole_ys_agegrp['wasting_length']).any(), \ + ("There is at least one NaN length.\n" + f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") + + assert all(length > 0 for length in sev_wasted_whole_ys_agegrp['wasting_length']), \ + ("There is at least one zero length.\n" + f"{mod_wasted_whole_ys_agegrp['wasting_length']=} for {age_grp=}") + length_df.loc[age_grp, 'sev_not_yet_recovered'] = ( + sum(sev_wasted_whole_ys_agegrp['wasting_length']) / + len(sev_wasted_whole_ys_agegrp['wasting_length']) + ) + else: + length_df.loc[age_grp, 'sev_not_yet_recovered'] = 0 + assert not np.isnan(length_df.loc[age_grp, 'sev_not_yet_recovered']), \ + f"The avg {length_df.loc[age_grp, 'sev_not_yet_recovered']=} for {age_grp=} is empty." + + logger.info(key='wasting_length_avg', data=length_df.to_dict()) # ----- PREVALENCE LOG ---------------- # Wasting totals (prevalence & pop size at logging time) @@ -1900,7 +1902,6 @@ def apply(self, population): pop_sizes_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = 0 # log prevalence & pop size for children above 5y - above5s = df.loc[df.is_alive & (df.age_exact_years >= 5)] assert (len(under5s) + len(above5s)) == len(df.loc[df.is_alive]), \ ("The numbers of persons under and above 5 don't sum to all alive person, when logging on" f"{self.sim.date=}.") @@ -1926,74 +1927,3 @@ def apply(self, population): # log pop sizes logger.info(key='pop sizes', data=pop_sizes_dict) - - -class Wasting_InitLoggingEvent(Event, PopulationScopeEventMixin): - """ - This Event logs initial prevalence proportions of moderate and severe wasting, and initial population sizes. - """ - - def __init__(self, module): - # This event to occur every year - super().__init__(module) - assert isinstance(module, Wasting) - - def apply(self, population): - df = self.sim.population.props - - # ----- PREVALENCE LOG ---------------- - # Wasting totals (prevalence & pop size at logging time) - # declare a dictionary that will hold proportions of wasting prevalence per each age group - wasting_prev_dict: Dict[str, Any] = dict() - # declare a dictionary that will hold pop sizes - pop_sizes_dict: Dict[str, Any] = dict() - - under5s = df.loc[df.is_alive & (df.age_exact_years < 5)] - # loop through different age groups and get proportions of wasting prevalence per each age group - for low_bound_mos, high_bound_mos in [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)]: # in months - low_bound_age_in_years = low_bound_mos / 12.0 - high_bound_age_in_years = (1 + high_bound_mos) / 12.0 - # get those children who are wasted - mod_wasted_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, - inclusive='left') & (under5s.un_WHZ_category - == '-3<=WHZ<-2')).sum() - sev_wasted_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, - inclusive='left') & (under5s.un_WHZ_category - == 'WHZ<-3')).sum() - total_per_agegrp_nmb = (under5s.age_exact_years.between(low_bound_age_in_years, high_bound_age_in_years, - inclusive='left')).sum() - # add moderate and severe wasting prevalence to the dictionary - wasting_prev_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = mod_wasted_agegrp_nmb / total_per_agegrp_nmb - wasting_prev_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = sev_wasted_agegrp_nmb / total_per_agegrp_nmb - # add pop sizes to the dataframe - pop_sizes_dict[f'mod__{low_bound_mos}_{high_bound_mos}mo'] = mod_wasted_agegrp_nmb - pop_sizes_dict[f'sev__{low_bound_mos}_{high_bound_mos}mo'] = sev_wasted_agegrp_nmb - pop_sizes_dict[f'total__{low_bound_mos}_{high_bound_mos}mo'] = total_per_agegrp_nmb - # log prevalence & pop size for children above 5y - above5s = df.loc[df.is_alive & (df.age_exact_years >= 5)] - assert (len(under5s) + len(above5s)) == len(df.loc[df.is_alive]), \ - ("The numbers of persons under and above 5 don't sum to all alive person, when logging at" - "sim initiation.") - mod_wasted_above5_nmb = (above5s.un_WHZ_category == '-3<=WHZ<-2').sum() - sev_wasted_above5_nmb = (above5s.un_WHZ_category == 'WHZ<-3').sum() - wasting_prev_dict['mod__5y+'] = mod_wasted_above5_nmb / len(above5s) - wasting_prev_dict['sev__5y+'] = sev_wasted_above5_nmb / len(above5s) - pop_sizes_dict['mod__5y+'] = mod_wasted_above5_nmb - pop_sizes_dict['sev__5y+'] = sev_wasted_above5_nmb - pop_sizes_dict['total__5y+'] = len(above5s) - - # add to dictionary proportion of all moderately/severely wasted children under 5 years - mod_under5_nmb = (under5s.un_WHZ_category == '-3<=WHZ<-2').sum() - sev_under5_nmb = (under5s.un_WHZ_category == 'WHZ<-3').sum() - wasting_prev_dict['total_mod_under5_prop'] = mod_under5_nmb / len(under5s) - wasting_prev_dict['total_sev_under5_prop'] = sev_under5_nmb / len(under5s) - pop_sizes_dict['mod__under5'] = mod_under5_nmb - pop_sizes_dict['sev__under5'] = sev_under5_nmb - pop_sizes_dict['total__under5'] = len(under5s) - - # log wasting prevalence - logger.info(key='wasting_init_prevalence_props', data=wasting_prev_dict) - - # log pop sizes - logger.info(key='init pop sizes', data=pop_sizes_dict) - From 4d72c6d9413041cd9b06889735d18a9540a3e010 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 19 Sep 2025 22:51:25 +0100 Subject: [PATCH 498/755] test_wast: force any symptoms to lead to health-care seeking --- tests/test_wasting.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 4266a7488e..eca5b68b5c 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -58,17 +58,16 @@ def get_sim(tmpdir): "tlo.methods.wasting": logging.INFO} }) - sim.register(demography.Demography(), - enhanced_lifestyle.Lifestyle(), - healthsystem.HealthSystem(disable=False, - cons_availability='all', - equip_availability='all'), - symptommanager.SymptomManager(), - healthseekingbehaviour.HealthSeekingBehaviour(), - healthburden.HealthBurden(), - simplified_births.SimplifiedBirths(), - wasting.Wasting() - ) + sim.register( + demography.Demography(), + enhanced_lifestyle.Lifestyle(), + healthsystem.HealthSystem(disable=False, cons_availability="all", equip_availability="all"), + symptommanager.SymptomManager(), + healthseekingbehaviour.HealthSeekingBehaviour(force_any_symptom_to_lead_to_healthcareseeking=True), + healthburden.HealthBurden(), + simplified_births.SimplifiedBirths(), + wasting.Wasting(), + ) return sim From 0503da4f0640c9eaff9736ee2eab8a963763f811 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sat, 20 Sep 2025 00:16:41 +0100 Subject: [PATCH 499/755] wast, test_wast, RF_Wast/pars: updated relapse logic to account for incidence occurring on any day in the previous month; replaced hardcoded 14-day restriction with parameter min_days_to_relapse --- resources/ResourceFile_Wasting/parameters.csv | 4 ++-- src/tlo/methods/wasting.py | 16 ++++++++++++---- tests/test_wasting.py | 7 +++++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/resources/ResourceFile_Wasting/parameters.csv b/resources/ResourceFile_Wasting/parameters.csv index 9bc5227141..a6af18e0e3 100644 --- a/resources/ResourceFile_Wasting/parameters.csv +++ b/resources/ResourceFile_Wasting/parameters.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c5df0060605083f532e16b51703ce0ac825f8e55020503ed39b45454f3361b1f -size 4747 +oid sha256:6463c77cd93c5b1301393dcfb3b7d4205fd5b0daf79ba6f3f4d478b9185b20c0 +size 4772 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 0efd0eb27b..ce5a947952 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -63,6 +63,10 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'prev_init_sev_by_agegp': Parameter( Types.LIST, 'initial severe wasting (WHZ < -3) prevalence in 2010 by age groups'), # incidence + 'min_days_to_relapse': Parameter( + Types.REAL, 'minimum days to relapse: the incidence of another wasting episode in the previous ' + 'month cannot occur if recovery happened fewer than this number of days before the start of ' + 'that month'), 'base_overall_inc_rate_wasting': Parameter( Types.REAL, 'base overall monthly moderate wasting incidence rate ' '(probability per child aged <0.5 years per month)'), @@ -954,15 +958,20 @@ def apply(self, population): :param population: the current population """ df = population.props + p = self.module.parameters rng = self.module.rng # # # INCIDENCE OF MODERATE WASTING # # # # # # # # # # # # # # # # # # # # # - # Determine who will be onset with wasting among those who are alive, under 5, currently do not have acute - # malnutrition, are not being treated, and did not recover in the last 14 days + # Determine who developed wasting among those who are alive, under 5, currently do not have acute + # malnutrition, are not being treated, and did not recover later than min_days_to_relapse before the start + # of the previous month (incidence can occur on any day within the previous month) + days_in_month = (self.sim.date - pd.DateOffset(days=1)).days_in_month not_am_or_treated_or_recently_recovered =\ df.loc[df.is_alive & (df.age_exact_years < 5) & (df.un_clinical_acute_malnutrition == 'well') & (df.un_am_tx_start_date.isna()) & - (df.un_am_recovery_date.isna() | (df.un_am_recovery_date < self.sim.date - pd.DateOffset(days=14)))] + (df.un_am_recovery_date.isna() | + (df.un_am_recovery_date < self.sim.date - pd.DateOffset(days=(p['min_days_to_relapse'] + + days_in_month))))] incidence_of_wasting_bool = \ self.module.wasting_models.wasting_incidence_lm.predict(not_am_or_treated_or_recently_recovered, rng=rng) @@ -970,7 +979,6 @@ def apply(self, population): mod_wasting_new_cases_idx = mod_wasting_new_cases.index # update the properties for new cases of wasted children df.loc[mod_wasting_new_cases_idx, 'un_ever_wasted'] = True - days_in_month = (self.sim.date - pd.DateOffset(days=1)).days_in_month df.loc[mod_wasting_new_cases_idx, 'un_last_wasting_date_of_onset'] = ( self.sim.date - pd.to_timedelta(rng.randint(1, days_in_month, size=len(mod_wasting_new_cases_idx)), unit='D') diff --git a/tests/test_wasting.py b/tests/test_wasting.py index eca5b68b5c..d920fc26f4 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -1031,10 +1031,11 @@ def test_recovery_before_death_scheduled(tmpdir): def test_no_wasting_after_recent_recovery(tmpdir): """ Test that a person who recovered from wasting 5 days ago does not become wasted again. (The 5-day interval is - used as an example within the assumed 14-day relapse-free window.) """ + used as an example within the assumed min_days_to_relapse-day relapse-free window.) """ popsize = 1000 sim = get_sim(tmpdir) wmodule = sim.modules['Wasting'] + p = wmodule.parameters sim.make_initial_population(n=popsize) sim.simulate(end_date=start_date) # zero duration @@ -1046,11 +1047,13 @@ def test_no_wasting_after_recent_recovery(tmpdir): person_id = under5s.index[0] # Manually set this individual properties to be well and recovered 5 days ago + nmb_days_recovered_ago_to_test_no_relapse = 5 + assert nmb_days_recovered_ago_to_test_no_relapse <= p['min_days_to_relapse'] df.at[person_id, 'un_WHZ_category'] = 'WHZ>=-2' df.at[person_id, 'un_am_MUAC_category'] = '>=125mm' df.at[person_id, 'un_am_nutritional_oedema'] = False df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' - df.at[person_id, 'un_am_recovery_date'] = sim.date - pd.DateOffset(days=5) + df.at[person_id, 'un_am_recovery_date'] = sim.date - pd.DateOffset(days=nmb_days_recovered_ago_to_test_no_relapse) # Set incidence of wasting at 100% wmodule.wasting_models.wasting_incidence_lm = LinearModel.multiplicative() From 3d4892c57a0104ec30235d4df9a7277da95a3715 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 23 Sep 2025 21:01:40 +0100 Subject: [PATCH 500/755] test_wast: make non-emergency care event assertions order-independent (other HS events may be scheduled for the person); update hsi_event_scheduled->tx_hsi_event_scheduled to be more clear --- tests/test_wasting.py | 55 +++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index d920fc26f4..e8b38c44f5 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -485,21 +485,21 @@ def test_tx_recovery_to_MAM_severe_acute_malnutrition_without_complications(tmpd hsp.run() # Check non-emergency care event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - # run the created instance of HSI_GenericNonEmergencyFirstAppt and check care was sought + assert any(isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + for ev in sim.modules['HealthSystem'].find_events_for_person(person_id)) + # run the created instance of HSI_GenericNonEmergencyFirstAppt ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) - # Check HSI event is scheduled - hsi_event_scheduled = [ + # Check OTP treatment HSI event is scheduled + tx_hsi_event_scheduled = [ ev for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM) ] - assert 1 == len(hsi_event_scheduled) - # run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM and check care was sought + assert 1 == len(tx_hsi_event_scheduled) + # run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM)][0] sam_ev.run(squeeze_factor=0.0) @@ -592,20 +592,20 @@ def test_tx_full_recovery_severe_acute_malnutrition_with_complications(tmpdir): hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) hsp.run() # check non-emergency care event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - - # Run the created instance of HSI_GenericNonEmergencyFirstAppt and check care was sought + assert any(isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + for ev in sim.modules['HealthSystem'].find_events_for_person(person_id)) + # run the created instance of HSI_GenericNonEmergencyFirstAppt and check care was sought ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) - # check HSI event for complicated SAM is scheduled - hsi_event_scheduled = [ + + # Check ITC treatment HSI event for complicated SAM is scheduled + tx_hsi_event_scheduled = [ ev for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) if isinstance(ev[1], HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM) ] - assert 1 == len(hsi_event_scheduled) + assert 1 == len(tx_hsi_event_scheduled) # Run the created instance of HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if @@ -702,20 +702,20 @@ def test_nat_death_overwritten_by_tx_death(tmpdir): hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) hsp.run() # check non-emergency care event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - - # Run the created instance of HSI_GenericNonEmergencyFirstAppt + assert any(isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + for ev in sim.modules['HealthSystem'].find_events_for_person(person_id)) + # run the created instance of HSI_GenericNonEmergencyFirstAppt ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) - # check outpatient care event is scheduled for uncomplicated SAM - hsi_event_scheduled = [ + + # Check OTP treatment event is scheduled for uncomplicated SAM + tx_hsi_event_scheduled = [ ev for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM) ] - assert 1 == len(hsi_event_scheduled) + assert 1 == len(tx_hsi_event_scheduled) # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) @@ -966,21 +966,20 @@ def test_recovery_before_death_scheduled(tmpdir): hsp = HealthSeekingBehaviourPoll(sim.modules['HealthSeekingBehaviour']) hsp.run() # check non-emergency care event is scheduled - assert isinstance(sim.modules['HealthSystem'].find_events_for_person(person_id)[0][1], - hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) - - # Run the created instance of HSI_GenericNonEmergencyFirstAppt and check care was sought + assert any(isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt) + for ev in sim.modules['HealthSystem'].find_events_for_person(person_id)) + # run the created instance of HSI_GenericNonEmergencyFirstAppt and check care was sought ge = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if isinstance(ev[1], hsi_generic_first_appts.HSI_GenericNonEmergencyFirstAppt)][0] ge.run(squeeze_factor=0.0) - # Check outpatient care event is scheduled - hsi_event_scheduled = [ + # Check OTP treatment event is scheduled + tx_hsi_event_scheduled = [ ev for ev in sim.modules["HealthSystem"].find_events_for_person(person_id) if isinstance(ev[1], HSI_Wasting_OutpatientTherapeuticProgramme_SAM) ] - assert 1 == len(hsi_event_scheduled) + assert 1 == len(tx_hsi_event_scheduled) # Run the created instance of HSI_Wasting_OutpatientTherapeuticProgramme_SAM sam_ev = [ev[1] for ev in sim.modules['HealthSystem'].find_events_for_person(person_id) if From 0350e00700b7a23573fdc1d09c63c71f15660cba Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 24 Sep 2025 13:57:55 +0100 Subject: [PATCH 501/755] stunting: add comment clarifying absence of CAUSES_OF_DEATH and CAUSES_OF_DISABILITY --- src/tlo/methods/stunting.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tlo/methods/stunting.py b/src/tlo/methods/stunting.py index 7c2d83cc40..a911b4c0cf 100644 --- a/src/tlo/methods/stunting.py +++ b/src/tlo/methods/stunting.py @@ -48,6 +48,10 @@ class Stunting(Module, GenericFirstAppointmentsMixin): Metadata.USES_HEALTHSYSTEM, } + # No CAUSES_OF_DEATH or CAUSES_OF_DISABILITY assigned as per GBD 2019 + # (impact captured indirectly, through increased risk of diarrhoea and obstructed labour + # — see diarrhoea and labour modules) + PARAMETERS = { # Prevalence of stunting by age group at initiation 'prev_HAZ_distribution_age_0_5mo': Parameter( From 635ebf91ac455fb29e6928f719d6f43dc2e7dbb6 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 24 Sep 2025 23:24:57 +0100 Subject: [PATCH 502/755] RF_Wast/pars: update growth monitoring attendance probabilities based on our estimates (as REF or data from Malawi MOH was not obtained) --- resources/ResourceFile_Wasting/parameters.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting/parameters.csv b/resources/ResourceFile_Wasting/parameters.csv index a6af18e0e3..c4a80b2320 100644 --- a/resources/ResourceFile_Wasting/parameters.csv +++ b/resources/ResourceFile_Wasting/parameters.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6463c77cd93c5b1301393dcfb3b7d4205fd5b0daf79ba6f3f4d478b9185b20c0 -size 4772 +oid sha256:a0394ee6f29b556883d15a4b6badb10ac5f12e5b5e46b2a5ca02b300e63938a4 +size 4960 From 53f60716059eb25a83509188f435d7075b13a9cc Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 25 Sep 2025 01:41:27 +0100 Subject: [PATCH 503/755] wast: par descriptions updated --- src/tlo/methods/wasting.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index ce5a947952..93204565f7 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -153,13 +153,14 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'care'), 'tx_length_weeks_SuppFeedingMAM': Parameter( Types.REAL, 'number of weeks the patient receives treatment in the Supplementary Feeding ' - 'Programme for MAM before being discharged'), + 'Programme (SFP) for MAM, including the final supply provided at discharge'), 'tx_length_weeks_OutpatientSAM': Parameter( Types.REAL, 'number of weeks the patient receives treatment in the Outpatient Therapeutic ' - 'Programme for uncomplicated SAM before being discharged if they do not die beforehand'), + 'Programme (OTP) for uncomplicated SAM, including the final supply provided at discharge'), 'tx_length_weeks_InpatientSAM': Parameter( - Types.REAL, 'number of weeks the patient receives treatment in the Inpatient Care for complicated' - ' SAM before being discharged if they do not die beforehand'), + Types.REAL, 'number of weeks the patient receives treatment in the Inpatient Therapeutic Care ' + '(ITC) for complicated SAM---modelled to include the Rehabilitation Phase, ie to cover OTP as ' + 'well'), # treatment impacts 'prob_death_after_SAMcare': Parameter( Types.REAL, 'probability of dying from SAM after receiving care if not fully recovered'), From 893e90cbc2940f14dd76a6c3efc64ed5c68195d9 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 25 Sep 2025 01:57:32 +0100 Subject: [PATCH 504/755] wast: age groups for growth monitoring attendance in line with REF --- src/tlo/methods/wasting.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 93204565f7..029da48953 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -439,7 +439,7 @@ def schedule_growth_monitoring_on_initiation(self): def get_monitoring_frequency_days(age): if age < 1: return p["growth_monitoring_frequency_days_agecat"][0] - elif age <= 2: + elif age < 2: return p["growth_monitoring_frequency_days_agecat"][1] else: return p["growth_monitoring_frequency_days_agecat"][2] @@ -1333,7 +1333,7 @@ def __init__(self, module, person_id): def get_attendance_prob(age): if age < 1: return p["growth_monitoring_attendance_prob_agecat"][0] - if age <= 2: + if age < 2: return p["growth_monitoring_attendance_prob_agecat"][1] else: return p["growth_monitoring_attendance_prob_agecat"][2] @@ -1377,7 +1377,7 @@ def get_monitoring_frequency_days(age): # TODO: in future maybe 0-1 to be dealt with within epi module if age < 1: return p['growth_monitoring_frequency_days_agecat'][0] - elif age <= 2: + elif age < 2: return p['growth_monitoring_frequency_days_agecat'][1] else: return p['growth_monitoring_frequency_days_agecat'][2] From 284c5cf80e33ec46ae8db4246150c30607af2c8f Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 25 Sep 2025 01:58:39 +0100 Subject: [PATCH 505/755] Wast write-up: updated to latest version of module --- docs/write-ups/Wasting.docx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/write-ups/Wasting.docx b/docs/write-ups/Wasting.docx index ca62f23058..7c9f2e8d1d 100644 --- a/docs/write-ups/Wasting.docx +++ b/docs/write-ups/Wasting.docx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d331fd8af336a10d8199b056a0a4ea16a0c37f0045d4cd7d9136b98ce63e732e -size 360253 +oid sha256:b5e9f6459a867ae7c079a0558ae6f47fed819ada04425985f00da891d3cfd602 +size 362838 From d740f1d83f76e11d93c4abc3403d6d3f8cc53158 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 26 Sep 2025 12:09:05 +0100 Subject: [PATCH 506/755] RF_Wast/pars: add parameter labels --- resources/ResourceFile_Wasting/parameters.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/ResourceFile_Wasting/parameters.csv b/resources/ResourceFile_Wasting/parameters.csv index c4a80b2320..6945a702b9 100644 --- a/resources/ResourceFile_Wasting/parameters.csv +++ b/resources/ResourceFile_Wasting/parameters.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a0394ee6f29b556883d15a4b6badb10ac5f12e5b5e46b2a5ca02b300e63938a4 -size 4960 +oid sha256:d88c588a4a330f5e0b3122344e57d040bc0c2b8117ca0182136d521f13e1e2f2 +size 7486 From 2cb491bc4e421ac34c9129a5b7c0d912eba88f42 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 26 Sep 2025 22:11:59 +0100 Subject: [PATCH 507/755] wast: equipment for measurements logged at tx admission, conditionally on consumables being available (otherwise no admission to tx, hence no measurement assessment performed) --- src/tlo/methods/wasting.py | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 029da48953..d09b4bf85a 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1475,16 +1475,18 @@ def apply(self, person_id, squeeze_factor): if not df.at[person_id, 'is_alive']: return - # Do here whatever happens to an individual during the admission for the treatment - # ~~~~~~~~~~~~~~~~~~~~~~ - # Perform measurements (height/length), weight, MUAC - self.add_equipment({'Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape'}) - # Check and log availability of consumables if self.get_consumables(item_codes=self.module.cons_codes['SFP']): logger.debug(key='debug', data='consumables are available') + + # Admission for the treatment + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + # Perform measurements (height/length), weight, MUAC + self.add_equipment({"Height Pole (Stadiometer)", "Weighing scale", "MUAC tape"}) # Record that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'CSB++' + # Perform the treatment: cancel natural recovery/progression, + # then determine and schedule the outcome following treatment self.module.do_when_am_treatment(person_id, treatment='SFP') else: logger.debug(key='debug', @@ -1517,18 +1519,18 @@ def apply(self, person_id, squeeze_factor): if not df.at[person_id, 'is_alive']: return - # Do here whatever happens to an individual during the admission for the treatment - # ~~~~~~~~~~~~~~~~~~~~~~ - # Perform measurements (height/length), weight, MUAC - self.add_equipment({'Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape'}) - # Check and log availability of consumables if self.get_consumables( item_codes=self.module.cons_codes['OTP'], optional_item_codes=self.module.cons_codes['OTP_opt'] ): - logger.debug(key='debug', data='consumables are available.') + # Admission for the treatment + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + # Perform measurements (height/length), weight, MUAC + self.add_equipment({"Height Pole (Stadiometer)", "Weighing scale", "MUAC tape"}) # Record that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' + # Perform the treatment: cancel natural recovery/progression, + # then determine and schedule the outcome following treatment self.module.do_when_am_treatment(person_id, treatment='OTP') else: logger.debug(key='debug', @@ -1561,18 +1563,18 @@ def apply(self, person_id, squeeze_factor): if not df.at[person_id, 'is_alive']: return - # Do here whatever happens to an individual during the admission for the treatment - # ~~~~~~~~~~~~~~~~~~~~~~ - # Perform measurements (height/length, weight, MUAC) - self.add_equipment({'Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape'}) - # Check and log availability of consumables if self.get_consumables( item_codes=self.module.cons_codes['ITC'], optional_item_codes=self.module.cons_codes['ITC_opt'] ): - logger.debug(key='debug', data='consumables available, so use it.') + # Admission for the treatment + # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + # Perform measurements (height/length), weight, MUAC + self.add_equipment({"Height Pole (Stadiometer)", "Weighing scale", "MUAC tape"}) # Record that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'inpatient_care' + # Perform the treatment: cancel natural recovery/progression, + # then determine and schedule the outcome following treatment self.module.do_when_am_treatment(person_id, treatment='ITC') else: logger.debug(key='debug', From e27a6e3efa7cdfe2e9d50beda1ab1ef602aeef38 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 26 Sep 2025 23:08:48 +0100 Subject: [PATCH 508/755] wast: add additional equipment identified in #1431 --- src/tlo/methods/wasting.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index d09b4bf85a..9b5e547e46 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1414,7 +1414,7 @@ def get_monitoring_frequency_days(age): df.at[person_id, 'un_last_growth_monitoring_appt_date'] = self.sim.date # Add required equipment - self.add_equipment({'Height Pole (Stadiometer)', 'Weighing scale', 'MUAC tape'}) + self.add_equipment({"Height Pole (Stadiometer)", "Weighing scale", "MUAC tape", "Development milestone charts"}) def schedule_tx_by_diagnosis(hsi_event): self.sim.modules['HealthSystem'].schedule_hsi_event( @@ -1481,8 +1481,9 @@ def apply(self, person_id, squeeze_factor): # Admission for the treatment # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - # Perform measurements (height/length), weight, MUAC - self.add_equipment({"Height Pole (Stadiometer)", "Weighing scale", "MUAC tape"}) + # Perform measurements (height/length), weight, MUAC and log equipment required for the treatment + self.add_equipment({"Height Pole (Stadiometer)", "Weighing scale", "MUAC tape", + "Development milestone charts", "Measuring Cup", "Mixing Bowls"}) # Record that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'CSB++' # Perform the treatment: cancel natural recovery/progression, @@ -1526,7 +1527,8 @@ def apply(self, person_id, squeeze_factor): # Admission for the treatment # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Perform measurements (height/length), weight, MUAC - self.add_equipment({"Height Pole (Stadiometer)", "Weighing scale", "MUAC tape"}) + self.add_equipment({"Height Pole (Stadiometer)", "Weighing scale", "MUAC tape", + "Development milestone charts"}) # Record that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'standard_RUTF' # Perform the treatment: cancel natural recovery/progression, @@ -1570,7 +1572,8 @@ def apply(self, person_id, squeeze_factor): # Admission for the treatment # ~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Perform measurements (height/length), weight, MUAC - self.add_equipment({"Height Pole (Stadiometer)", "Weighing scale", "MUAC tape"}) + self.add_equipment({"Height Pole (Stadiometer)", "Weighing scale", "MUAC tape", + "Development milestone charts"}) # Record that the treatment is provided: df.at[person_id, 'un_am_treatment_type'] = 'inpatient_care' # Perform the treatment: cancel natural recovery/progression, From c48c715ea463795e695ee0af68846cac0308e9ee Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 28 Sep 2025 17:59:48 +0100 Subject: [PATCH 509/755] RF_Wast/pars, Wast write-up: min_days_duration_of_wasting set to 31 (lowest bound from 95%CIs for both durations) --- docs/write-ups/Wasting.docx | 4 ++-- resources/ResourceFile_Wasting/parameters.csv | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/write-ups/Wasting.docx b/docs/write-ups/Wasting.docx index 7c9f2e8d1d..b91f006c72 100644 --- a/docs/write-ups/Wasting.docx +++ b/docs/write-ups/Wasting.docx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b5e9f6459a867ae7c079a0558ae6f47fed819ada04425985f00da891d3cfd602 -size 362838 +oid sha256:769b33b3314b9110506f658caf961ad2c1253e346e2b6a7ddeb2366643960913 +size 362666 diff --git a/resources/ResourceFile_Wasting/parameters.csv b/resources/ResourceFile_Wasting/parameters.csv index 6945a702b9..d1806b3ac4 100644 --- a/resources/ResourceFile_Wasting/parameters.csv +++ b/resources/ResourceFile_Wasting/parameters.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d88c588a4a330f5e0b3122344e57d040bc0c2b8117ca0182136d521f13e1e2f2 -size 7486 +oid sha256:b6b2e2e066c8cc12cbb2c0837f77d440b4524f75275cbe6122ede372b103d566 +size 7539 From f4e5964e4a4e3c50aa52a509d41d0fe0900f3654 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 28 Sep 2025 18:02:49 +0100 Subject: [PATCH 510/755] wast: reset progression date to sev wast for cases destined to die if left untreated --- src/tlo/methods/wasting.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 9b5e547e46..433ab17c12 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -631,6 +631,7 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): date=outcome_date ) df.at[person_id, 'un_sam_death_date'] = outcome_date + df.at[person_id, 'un_progression_date'] = pd.NaT else: df.at[person_id, 'un_sam_with_complications'] = False From e22e8a4e5237d3cb8db6886f3ec3245f5aa25ae6 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 29 Sep 2025 02:32:05 +0100 Subject: [PATCH 511/755] wast, RF_Wast/pars, & Wast write-up: growth monitoring updated according to a new REF (1st visit recommended on day 42, updated frequency and attendance probs) --- docs/write-ups/Wasting.docx | 4 ++-- resources/ResourceFile_Wasting/parameters.csv | 4 ++-- src/tlo/methods/wasting.py | 7 +++++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/write-ups/Wasting.docx b/docs/write-ups/Wasting.docx index b91f006c72..113cc8a605 100644 --- a/docs/write-ups/Wasting.docx +++ b/docs/write-ups/Wasting.docx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:769b33b3314b9110506f658caf961ad2c1253e346e2b6a7ddeb2366643960913 -size 362666 +oid sha256:7ec024c43e5023458e1cc76fc00d65306ce7f40111e56c4057374b318cbcd63b +size 361806 diff --git a/resources/ResourceFile_Wasting/parameters.csv b/resources/ResourceFile_Wasting/parameters.csv index d1806b3ac4..95f1bf062a 100644 --- a/resources/ResourceFile_Wasting/parameters.csv +++ b/resources/ResourceFile_Wasting/parameters.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b6b2e2e066c8cc12cbb2c0837f77d440b4524f75275cbe6122ede372b103d566 -size 7539 +oid sha256:a49184233ca621578abaf7da15f98960b941185f46aafe2c226581720a7c3374 +size 7120 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 433ab17c12..a4c07676a5 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -136,6 +136,8 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'proportion_normal_whz': Parameter( Types.REAL, 'proportion of children under 5 with no wasting (WHZ >= -2)'), # detection + 'growth_monitoring_first': Parameter( + Types.INT, 'recommended age (in days) for first growth monitoring visit'), 'growth_monitoring_frequency_days_agecat': Parameter( Types.LIST, 'growth monitoring frequency (days) for age categories '), 'growth_monitoring_attendance_prob_agecat': Parameter( @@ -400,6 +402,7 @@ def on_birth(self, mother_id, child_id): :param child_id: the id of the newborn child """ df = self.sim.population.props + p = self.parameters # Set initial properties df.at[child_id, 'un_ever_wasted'] = False @@ -419,10 +422,10 @@ def on_birth(self, mother_id, child_id): # df.at[child_id, 'un_last_nonemergency_appt_date']= pd.NaT # df.at[child_id, 'un_last_growth_monitoring_appt_date']= pd.NaT - # initiate growth monitoring from day 1 + # initiate growth monitoring self.sim.modules['HealthSystem'].schedule_hsi_event( hsi_event=HSI_Wasting_GrowthMonitoring(module=self, person_id=child_id), - priority=2, topen=self.sim.date + pd.DateOffset(days=1) + priority=2, topen=self.sim.date + pd.DateOffset(days=p['growth_monitoring_first']) ) def schedule_growth_monitoring_on_initiation(self): From 9572e42e004c9506021d11ba156d2a634fef1d34 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 19 May 2025 18:46:35 +0100 Subject: [PATCH 512/755] scenario_wast_min_model: 30K pop --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 9d07b970d4..53fffe99e3 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=1, runs_per_draw=1, ) From e5e3a3b7f20f92716ef5e1fd4d5a735ebfdcb527 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 19 May 2025 22:52:16 +0100 Subject: [PATCH 513/755] calib_scenario_wast_min_mod: pars around previously calibrated values --- ...ibration_scenario_wasting_minimal_model.py | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 src/scripts/wasting_analyses/scenarios/calibration_scenario_wasting_minimal_model.py diff --git a/src/scripts/wasting_analyses/scenarios/calibration_scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/calibration_scenario_wasting_minimal_model.py new file mode 100644 index 0000000000..0bd6fd7832 --- /dev/null +++ b/src/scripts/wasting_analyses/scenarios/calibration_scenario_wasting_minimal_model.py @@ -0,0 +1,122 @@ +""" +This file defines a scenario for wasting analysis. + +It can be submitted on Azure Batch by running: + + tlo batch-submit src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py + +or locally using: + + tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py + + +After several iterations of simulations, a range of values for the calibrated parameters was identified and tested. +From these, the best-calibrated values were selected for the module. +""" + + + +import itertools +import warnings + +from tlo import Date, logging +from tlo.methods import ( + alri, + demography, + diarrhoea, + enhanced_lifestyle, + epi, + healthburden, + healthseekingbehaviour, + healthsystem, + hiv, + simplified_births, + stunting, + symptommanager, + tb, + wasting, +) +from tlo.scenario import BaseScenario + +# capture warnings during simulation run +warnings.simplefilter('default', (UserWarning, RuntimeWarning)) + + +class WastingAnalysis(BaseScenario): + + def __init__(self): + super().__init__( + seed=0, + start_date=Date(year=2010, month=1, day=1), + end_date=Date(year=2031, month=1, day=1), + initial_population_size=30_000, + number_of_draws=81, + runs_per_draw=1, + ) + + def log_configuration(self): + return { + 'filename': 'wasting_analysis__minimal_model', + 'directory': './outputs/wasting_analysis', + "custom_levels": { # Customise the output of specific loggers + "tlo.methods.demography": logging.INFO, + "tlo.methods.population": logging.INFO, + "tlo.methods.wasting": logging.DEBUG, + '*': logging.WARNING + } + } + + def modules(self): + return [demography.Demography(resourcefilepath=self.resources), + healthsystem.HealthSystem(resourcefilepath=self.resources, + service_availability=['*'], use_funded_or_actual_staffing='actual', + mode_appt_constraints=1, + cons_availability='default', beds_availability='default', + equip_availability='all'), + healthseekingbehaviour.HealthSeekingBehaviour(resourcefilepath=self.resources), + healthburden.HealthBurden(resourcefilepath=self.resources), + symptommanager.SymptomManager(resourcefilepath=self.resources, spurious_symptoms=True), + enhanced_lifestyle.Lifestyle(resourcefilepath=self.resources), + simplified_births.SimplifiedBirths(resourcefilepath=self.resources), + hiv.Hiv(resourcefilepath=self.resources), + tb.Tb(resourcefilepath=self.resources), + epi.Epi(resourcefilepath=self.resources), + alri.Alri(resourcefilepath=self.resources), + diarrhoea.Diarrhoea(resourcefilepath=self.resources), + stunting.Stunting(resourcefilepath=self.resources), + wasting.Wasting(resourcefilepath=self.resources)] + + def draw_parameters(self, draw_number, rng): + base_death_rate_untreated_sam__draws = [0.033, 0.030, 0.027] + mod_wast_incidence__coef = [0.45, 0.40, 0.35] + # base mod wast incidence rate calibrated with bathtub model + base_overall_mod_wast_inc_rate_bathtub = 0.019 + # relative risks for age groups of mod wast incidence rates calibrated with bathtub model + # rr_inc_rate_wasting_by_agegp = [1.00, 1.22, 1.71, 0.30, 0.40, 0.26] --- as in RFWast/parameters + progression_to_sev_wast__coef = [0.88, 1.00, 1.12] + # progression rates to severe wast calibrated with bathtub model + progression_severe_wasting_monthly_props_by_agegp = [0.3082, 0.8614, 0.4229, 0.4337, 0.2508, 0.3321] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.07, 0.10, 0.13] + + pars_combinations = list(itertools.product( + base_death_rate_untreated_sam__draws, + mod_wast_incidence__coef, + progression_to_sev_wast__coef, + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam + )) + + return { + 'Wasting': { + 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], + 'base_overall_inc_rate_wasting': base_overall_mod_wast_inc_rate_bathtub * pars_combinations[draw_number][1] , + 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ + s in progression_severe_wasting_monthly_props_by_agegp], + 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / + (1-0.738)) + } + } + +if __name__ == '__main__': + from tlo.cli import scenario_run + + scenario_run([__file__]) From 57fb143ce67c38d97280c2cbc5fb7d1413381fdd Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 19 May 2025 23:46:02 +0100 Subject: [PATCH 514/755] scenario_wast_min_mod: Scaling up growth monitoring attendance scenarios --- .../scenario_wasting_minimal_model.py | 45 +++++++------------ 1 file changed, 16 insertions(+), 29 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 53fffe99e3..7230b46c18 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -43,8 +43,8 @@ def __init__(self): start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), initial_population_size=30_000, - number_of_draws=1, - runs_per_draw=1, + number_of_draws=4, + runs_per_draw=10, ) def log_configuration(self): @@ -79,35 +79,22 @@ def modules(self): stunting.Stunting(resourcefilepath=self.resources), wasting.Wasting(resourcefilepath=self.resources)] + # Scaling up growth monitoring attendance scenarios def draw_parameters(self, draw_number, rng): - # Using default parameters in all cases - return {} + ### growth_monitoring_attendance_probs by age categories + # < 1 year + attendance_prob_below1y = 0.76 + # 1-2 years + attendance_prob_1to2y = [0.14, 0.20, 0.25, 1.00] + # > 2 years + attendance_prob_above2y = [0.50, 0.55, 0.50, 1.00] - # def draw_parameters(self, draw_number, rng): - # base_death_rate_untreated_sam__draws = [0.030, 0.023, 0.017, 0.010] - # mod_wast_incidence__coef = [0.7, 0.6, 0.5, 0.4] - # base_overall_mod_wast_inc_rate = 0.019 - # progression_to_sev_wast__coef = [1.0, 1.25, 1.5] - # progression_severe_wasting_monthly_props_by_agegp = [0.3082, 0.8614, 0.4229, 0.4337, 0.2508, 0.3321] - # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.1, 0.17, 0.23, 0.3] - # - # pars_combinations = list(itertools.product( - # base_death_rate_untreated_sam__draws, - # mod_wast_incidence__coef, - # progression_to_sev_wast__coef, - # prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam - # )) - # - # return { - # 'Wasting': { - # 'base_death_rate_untreated_SAM': pars_combinations[draw_number][0], - # 'base_overall_inc_rate_wasting': base_overall_mod_wast_inc_rate * pars_combinations[draw_number][1] , - # 'progression_severe_wasting_monthly_by_agegp': [s * pars_combinations[draw_number][2] for \ - # s in progression_severe_wasting_monthly_props_by_agegp], - # 'prob_death_after_SAMcare': ((pars_combinations[draw_number][0] * pars_combinations[draw_number][3]) / - # (1-0.738)) - # } - # } + return { + 'Wasting': { + 'growth_monitoring_attendance_prob_agecat': + [attendance_prob_below1y, attendance_prob_1to2y[draw_number], attendance_prob_above2y[draw_number]] + } + } if __name__ == '__main__': from tlo.cli import scenario_run From 77b947d53a30dceebf4bc7c6f9eea9b0db4b8929 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 20 May 2025 01:28:10 +0100 Subject: [PATCH 515/755] wast, RF_Wast/params, test_wast: interv scaling up growth monitoring attendance --- resources/ResourceFile_Wasting/parameters.csv | 4 +-- src/tlo/methods/wasting.py | 13 +++++++-- tests/test_wasting.py | 29 +++++++++++++++++++ 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/resources/ResourceFile_Wasting/parameters.csv b/resources/ResourceFile_Wasting/parameters.csv index 95f1bf062a..d9ea6c27d6 100644 --- a/resources/ResourceFile_Wasting/parameters.csv +++ b/resources/ResourceFile_Wasting/parameters.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a49184233ca621578abaf7da15f98960b941185f46aafe2c226581720a7c3374 -size 7120 +oid sha256:b4ab9558a630a14311f34b17013dd76dcc0f00f562dd3c8630803dc988e5449f +size 7287 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index a4c07676a5..705eb511ca 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -142,7 +142,7 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.LIST, 'growth monitoring frequency (days) for age categories '), 'growth_monitoring_attendance_prob_agecat': Parameter( Types.LIST, 'probability to attend the growth monitoring for age categories'), - # recovery due to treatment + # treatment 'recovery_rate_with_soy_RUSF': Parameter( Types.REAL, 'probability of recovery from MAM following treatment with soy RUSF'), 'recovery_rate_with_CSB++': Parameter( @@ -163,9 +163,15 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.REAL, 'number of weeks the patient receives treatment in the Inpatient Therapeutic Care ' '(ITC) for complicated SAM---modelled to include the Rehabilitation Phase, ie to cover OTP as ' 'well'), - # treatment impacts 'prob_death_after_SAMcare': Parameter( Types.REAL, 'probability of dying from SAM after receiving care if not fully recovered'), + # interventions + 'interv_start_year': Parameter( + Types.INT, 'the year when the interventions are activated by overwriting the relevant ' + 'parameters.'), + 'interv_growth_monitoring_attendance_prob_agecat': Parameter( + Types.LIST, 'probability to attend the growth monitoring for age categories following the ' + 'activation of the intervention(s).'), } PROPERTIES = { @@ -383,6 +389,7 @@ def initialise_simulation(self, sim): * the first annual logging event, * the first monthly incidence polling event, * the first growth monitoring for all children under 5. + * Activation ('SWITCH ON') of interventions. :param sim: """ @@ -390,6 +397,8 @@ def initialise_simulation(self, sim): sim.schedule_event(Wasting_IncidencePoll(self), sim.date + DateOffset(months=1)) # Schedule growth monitoring for all children under 5 self.schedule_growth_monitoring_on_initiation() + sim.schedule_event(Wasting_ActivateInterventionsEvent(self), + Date(year=self.parameters['interv_start_year'], month=1, day=1)) # Retrieve the consumables codes and amounts of the consumables used self.cons_codes = self.get_consumables_for_each_treatment() diff --git a/tests/test_wasting.py b/tests/test_wasting.py index e8b38c44f5..473c8f98f9 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -27,6 +27,7 @@ from tlo.methods.wasting import ( HSI_Wasting_InpatientTherapeuticCare_ComplicatedSAM, HSI_Wasting_OutpatientTherapeuticProgramme_SAM, + Wasting_ActivateInterventionsEvent, Wasting_FullRecovery_Event, Wasting_IncidencePoll, Wasting_ProgressionToSevere_Event, @@ -1063,3 +1064,31 @@ def test_no_wasting_after_recent_recovery(tmpdir): # Check properties of this individual: should still be well assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well' + +def test_default_interv_pars(tmpdir): + """ Test that default values of intervention parameters are the same as the parameters prior the intervention. """ + sim = get_sim(tmpdir) + wmodule = sim.modules['Wasting'] + p = wmodule.parameters + + assert p['growth_monitoring_attendance_prob_agecat'] == p['interv_growth_monitoring_attendance_prob_agecat'], \ + ("The parameters 'growth_monitoring_attendance_prob_agecat' and " + "'interv_growth_monitoring_attendance_prob_agecat' do not match.") + +def test_interventions_activation(tmpdir): + """ Test that Wasting_ActivateInterventionsEvent correctly overwrites parameters. """ + sim = get_sim(tmpdir) + wmodule = sim.modules['Wasting'] + p = wmodule.parameters + + # Ensure the parameters differ from original value to test overwriting + p['interv_growth_monitoring_attendance_prob_agecat'] = [0.9, 0.8, 0.7] + assert p['growth_monitoring_attendance_prob_agecat'] != p['interv_growth_monitoring_attendance_prob_agecat'] + + # Apply the interventions activation event + activation_event = Wasting_ActivateInterventionsEvent(wmodule) + activation_event.apply(sim.population) + + # Verify that the parameters have been overwritten + assert p['growth_monitoring_attendance_prob_agecat'] == p['interv_growth_monitoring_attendance_prob_agecat'], \ + "The parameter was not correctly overwritten by the activation event." From e00ba1d8a035f18dd2c375d3d57a877b374541a4 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 20 May 2025 01:31:09 +0100 Subject: [PATCH 516/755] scenario_wast_min_model: 4K pop; 4 draws--scaling up growth monitoring attendance, incl SQ (set up with intev_ param); 10 runs --- .../scenarios/scenario_wasting_minimal_model.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index 7230b46c18..f802bafea0 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + initial_population_size=4_000, number_of_draws=4, runs_per_draw=10, ) @@ -91,7 +91,7 @@ def draw_parameters(self, draw_number, rng): return { 'Wasting': { - 'growth_monitoring_attendance_prob_agecat': + 'interv_growth_monitoring_attendance_prob_agecat': [attendance_prob_below1y, attendance_prob_1to2y[draw_number], attendance_prob_above2y[draw_number]] } } From 7cc6c4dd1180c608484cb810ab23557093283cb8 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 20 May 2025 17:27:28 +0100 Subject: [PATCH 517/755] calib_scenario_wast_min_model: nicer values around previously calibrated paras --- .../calibration_scenario_wasting_minimal_model.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/calibration_scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/calibration_scenario_wasting_minimal_model.py index 0bd6fd7832..cd7bba4d91 100644 --- a/src/scripts/wasting_analyses/scenarios/calibration_scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/calibration_scenario_wasting_minimal_model.py @@ -87,16 +87,16 @@ def modules(self): wasting.Wasting(resourcefilepath=self.resources)] def draw_parameters(self, draw_number, rng): - base_death_rate_untreated_sam__draws = [0.033, 0.030, 0.027] - mod_wast_incidence__coef = [0.45, 0.40, 0.35] + base_death_rate_untreated_sam__draws = [0.04, 0.03, 0.02] + mod_wast_incidence__coef = [0.5, 0.4, 0.3] # base mod wast incidence rate calibrated with bathtub model base_overall_mod_wast_inc_rate_bathtub = 0.019 # relative risks for age groups of mod wast incidence rates calibrated with bathtub model # rr_inc_rate_wasting_by_agegp = [1.00, 1.22, 1.71, 0.30, 0.40, 0.26] --- as in RFWast/parameters - progression_to_sev_wast__coef = [0.88, 1.00, 1.12] + progression_to_sev_wast__coef = [0.75, 1.0, 1.25] # progression rates to severe wast calibrated with bathtub model progression_severe_wasting_monthly_props_by_agegp = [0.3082, 0.8614, 0.4229, 0.4337, 0.2508, 0.3321] - prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.07, 0.10, 0.13] + prob_death_after_SAMcare__as_prop_of_death_rate_untreated_sam = [0.05, 0.1, 0.15] pars_combinations = list(itertools.product( base_death_rate_untreated_sam__draws, From df4b4c3f9fd6f3bfb3a67cd08d125de770eadb3a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 20 May 2025 21:46:41 +0100 Subject: [PATCH 518/755] new scenario_analysis_wasting: starting with calib_analysis_wast script to be rewritten for scenario analysis --- .../scenario_analysis_wasting.py | 864 ++++++++++++++++++ 1 file changed, 864 insertions(+) create mode 100644 src/scripts/wasting_analyses/scenario_analysis_wasting.py diff --git a/src/scripts/wasting_analyses/scenario_analysis_wasting.py b/src/scripts/wasting_analyses/scenario_analysis_wasting.py new file mode 100644 index 0000000000..739584de0a --- /dev/null +++ b/src/scripts/wasting_analyses/scenario_analysis_wasting.py @@ -0,0 +1,864 @@ +""" +An analysis file for the wasting module (so far only for 1 run, 1 draw) +""" +# %% Import statements +import glob +import gzip +import os +import shutil +import time +from pathlib import Path + +import numpy as np +import pandas as pd +from matplotlib import pyplot as plt +from PyPDF2 import PdfReader, PdfWriter +from scipy import stats + +from tlo.analysis.utils import compare_number_of_deaths, get_scenario_outputs, parse_log_file + +# start time of the whole analysis +total_time_start = time.time() + +# ####### TO SET ####################################################################################################### +scenario_filename = 'wasting_analysis__minimal_model' +outputs_path = Path("./outputs/sejjej5@ucl.ac.uk/wasting") +legend_fontsize = 12 +title_fontsize = 16 +######################################################################################################################## + +def create_calib_outcome_csv(sim_results_folder_path_str): + """ + Creates a new empty csv file with the header if it doesn't exist yet. + :return: + """ + csv_file_name = str(sim_results_folder_path_str).replace(str(outputs_path), '').lstrip('/') + \ + "_model_calib-data_intersect_bool" + csv_file_path = sim_results_folder_path_str / f"{csv_file_name}.csv" + + if not csv_file_path.exists(): + age_groups = [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)] + calib_ys = [2015, 2019] + wast_type_agegp = [f'{wast_type}_wast__{low_bound}_{high_bound}mo' for wast_type in ['any', 'sev'] for + low_bound, high_bound in age_groups] + year_wast_age_grps = [f'{year}__{wast_age_grp}' for year in calib_ys for wast_age_grp in wast_type_agegp] + sum_year_prev_calib_points = [f'{year}__sum_prev_calib_points' for year in calib_ys] + + with open(csv_file_path, 'w') as csv_file: + csv_file.write( + 'draw,run,' + ','.join(year_wast_age_grps) + ',deaths_2010_2014,deaths_2015_2019,' + + ','.join(sum_year_prev_calib_points) + ',sum_prev_calib_points,sum_all_calib_points\n' + ) + +class WastingAnalyses: + """ + This class looks at plotting all important outputs from the wasting module + """ + + def __init__(self, sim_results_folder_path_str, in_datestamp, in_draw_nmb, in_run_nmb, in_png=False): + self.outcomes_folder_path = sim_results_folder_path_str + self.datestamp = in_datestamp + self.draw_nmb = in_draw_nmb + self.run_nmb = in_run_nmb + self.png = in_png, """bool indicating whether we want to save all figures not only as pdf, but also as png""" + + sim_results_folder_draw_x_run_0_path_str = sim_results_folder_path_str + f'/{draw_nmb}/{run_nmb}/' + sim_results_file_name_prefix = scenario_filename + sim_results_file_name_extension = '.log.gz' + gz_results_file_path = \ + Path(glob.glob(os.path.join(sim_results_folder_draw_x_run_0_path_str, + f"{sim_results_file_name_prefix}*{sim_results_file_name_extension}"))[0]) + + # Path to the decompressed .log file + self.__log_file_path = gz_results_file_path.with_suffix('') + # Decompress the .log.gz file + with gzip.open(gz_results_file_path, 'rb') as f_in: + with open(self.__log_file_path, 'wb') as f_out: + shutil.copyfileobj(f_in, f_out) + + # parse wasting logs + self.__w_logs_dict = parse_log_file(self.__log_file_path)['tlo.methods.wasting'] + # TODO: Why it prints the messages from parse_log_file() twice? + # parse scaling factor log + # self.__scaling_factor = \ + # parse_log_file(self.__log_file_path)['tlo.methods.population']['scaling_factor'].set_index('date').loc[ + # '2010-01-01', 'scaling_factor' + # ] + + # wasting types description + self.__wasting_types_desc = {'WHZ<-3': 'severe wasting', + '-3<=WHZ<-2': 'moderate wasting', + 'WHZ>=-2': 'no wasting'} + + self.fig_files = [] + + cycle = plt.rcParams['axes.prop_cycle'].by_key()['color'] + # # define colo(u)rs to use: + self.__colors_model = { + 'severe wasting': cycle[0], # #1f77b4 + 'moderate wasting': cycle[1], # #ff7f0e + 'SAM': '#B372B7', + 'MAM': '#D1BCD2', + } + self.__colors_data = { + 'severe wasting': '#82C1EC', + 'moderate wasting': '#C71E1E', + } + self.__colors_init_data = { + 'severe wasting': '#0E53EA', + 'moderate wasting': '#FFA783', + } + + def save_fig__store_pdf_file(self, fig, fig_output_name: str) -> None: + full_path_and_file_name = self.outcomes_folder_path + f'/{self.draw_nmb}/{self.run_nmb}/' + fig_output_name + \ + f'_{self.draw_nmb}_{self.run_nmb}' + if self.png: #TODO: doesn't seem to be working + fig.savefig(full_path_and_file_name + '.png', format='png') + fig.savefig(full_path_and_file_name + '.pdf', format='pdf') + self.fig_files.append(full_path_and_file_name + '.pdf') + + def plot_wasting_incidence(self): + """ plot the incidence of wasting over time """ + w_inc_df = self.__w_logs_dict['wasting_incidence_count'] + w_inc_df = w_inc_df.set_index(w_inc_df.date.dt.year) + w_inc_df = w_inc_df.drop(columns='date') + # check no incidence of well-nourished + all_zeros = w_inc_df['WHZ>=-2'].apply(lambda x: all(value == 0 for value in x.values())) + assert all(all_zeros) + w_inc_df = w_inc_df[["WHZ<-3", "-3<=WHZ<-2"]] + + pop_sizes_df = self.__w_logs_dict['pop sizes'] + pop_sizes_df = pop_sizes_df.set_index(pop_sizes_df.date.dt.year) + pop_sizes_df = pop_sizes_df.drop(columns='date') + po_sizes_to_keep = [col for col in pop_sizes_df.columns if + col.startswith('total__') and col not in ['total__under5']] + age_gps_total_pop_sizes_df = pop_sizes_df[po_sizes_to_keep].copy() + age_gps_total_pop_sizes_df['0y'] = \ + age_gps_total_pop_sizes_df['total__0_5mo'] + age_gps_total_pop_sizes_df['total__6_11mo'] + age_gps_total_pop_sizes_df = age_gps_total_pop_sizes_df.drop(columns=['total__0_5mo', 'total__6_11mo']) + age_gps_total_pop_sizes_df = age_gps_total_pop_sizes_df.rename(columns={ + 'total__12_23mo': '1y', + 'total__24_35mo': '2y', + 'total__36_47mo': '3y', + 'total__48_59mo': '4y', + 'total__5y+': '5+y' + }) + + # get age_years, doesn't matter what wasting category you choose, + # they all have same age groups + age_years = list(w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys()) + # age_years.remove('5+y') + + _row_counter = 0 + _col_counter = 0 + # plot setup + fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 6)) + axes[1, 2].axis('off') # 5+y has no data (no new cases in 5+y), its space is used to display the label + for age in age_years: + plotting = pd.DataFrame() + for state in w_inc_df.columns: + plotting[state] = \ + w_inc_df.apply(lambda row: row[state][age], axis=1) + # remove sev cases from mod cases (all sev cases went through mod state) + plotting["-3<=WHZ<-2"] = plotting.apply(lambda row: max(row["-3<=WHZ<-2"] - row["WHZ<-3"], 0), axis=1) + # calculate props within the age group + plotting = plotting.div(age_gps_total_pop_sizes_df[age], axis=0) + plotting = plotting.rename(columns=self.__wasting_types_desc) + # filter data to include only years from 2015 onwards + plotting = plotting.loc[plotting.index >= 2015] + # check for invalid values + if (plotting < 0).any().any() or (plotting > 1).any().any(): + print(f"Warning plot_wasting_incidence: Invalid values detected in plotting data for age group {age}:") + print(plotting) + + ax = plotting.plot(kind='bar', stacked=True, + ax=axes[_row_counter, _col_counter], + title=f"{age} old")#, + #ylim=[0, 1]) + show_legend = (_row_counter == 1 and _col_counter == 2) + # show_x_axis_label = (_row_counter == 0 and _col_counter == 2) + if show_legend: + ax.legend(loc='center', fontsize=legend_fontsize) + ax.set_title('') + else: + ax.get_legend().remove() + # if show_x_axis_label: + # ax.set_xlabel('Year') # TODO: this is not working + ax.set_xlabel('year') + ax.set_ylabel('proportion (within age group)') + # move to another row + if _col_counter == 2: + _row_counter += 1 + _col_counter = -1 + _col_counter += 1 # increment column counter + fig.suptitle('Annual incidence of wasting among the age group', fontsize=title_fontsize) #, weight='bold') + fig.tight_layout() + fig_output_name = ('wasting_incidence__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) + # plt.show() + + # def plot_wasting_incidence_mod_to_sev_props(self): + # """ plot the incidence of wasting over time """ + # w_inc_df = self.__w_logs_dict['wasting_incidence_count'] + # w_inc_df = w_inc_df.set_index(w_inc_df.date.dt.year) + # w_inc_df = w_inc_df.drop(columns='date') + # # check no incidence of well-nourished + # all_zeros = w_inc_df['WHZ>=-2'].apply(lambda x: all(value == 0 for value in x.values())) + # assert all(all_zeros) + # w_inc_df = w_inc_df[["WHZ<-3", "-3<=WHZ<-2"]] + # # get age_years, doesn't matter what wasting category you choose, + # # they all have same age groups + # age_years = list(w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys( + # + # )) + # age_years.remove('5+y') + # + # _row_counter = 0 + # _col_counter = 0 + # # plot setup + # fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 6)) + # fig.delaxes(axes[1, 2]) + # for _age in age_years: + # new_df = pd.DataFrame() + # for state in w_inc_df.columns: + # new_df[state] = \ + # w_inc_df.apply(lambda row: row[state][_age], axis=1) + # # convert into proportions + # new_df = new_df.apply(lambda _row: _row / _row.sum(), axis=1) + # plotting = new_df.rename(columns=self.__wasting_types_desc) + # ax = plotting.plot(kind='bar', stacked=True, + # ax=axes[_row_counter, _col_counter], + # title=f"incidence of wasting in {_age} old", + # ylim=[0, 1]) + # ax.legend(loc='lower right') + # ax.set_xlabel('year') + # ax.set_ylabel('proportion') + # # move to another row + # if _col_counter == 2: + # _row_counter += 1 + # _col_counter = -1 + # _col_counter += 1 # increment column counter + # + # handles, labels = axes[1, 1].get_legend_handles_labels() + # fig.legend(handles, labels, loc='center left', bbox_to_anchor=(1.05, 0.5)) + # fig_output_name = ('wasting_incidence_mod_to_sev_props__' + self.datestamp) + # fig.tight_layout() + # self.save_fig__store_pdf_file(fig, fig_output_name) + # # plt.show() + + def plot_wasting_length(self): + """ plot the average length of wasting over time """ + + if 'wasting_length_avg' in self.__w_logs_dict: + w_length_df = self.__w_logs_dict['wasting_length_avg'] + w_length_df = w_length_df.set_index(w_length_df.date.dt.year) + w_length_df = w_length_df.drop(columns='date') + # get age_years, doesn't matter from which dict + age_years = list(w_length_df.loc[w_length_df.index[0], 'mod_MAM_tx_full_recov'].keys()) + # age_years.remove('5+y') + w_length_df = w_length_df.loc[:, ['mod_MAM_nat_full_recov', + 'mod_SAM_nat_full_recov', 'mod_SAM_nat_recov_to_MAM', + 'sev_SAM_nat_full_recov', 'sev_SAM_nat_recov_to_MAM', + 'mod_MAM_tx/nat_full_recov', + 'mod_SAM_tx_full_recov', 'mod_SAM_tx/nat_recov_to_MAM', + 'sev_SAM_tx_full_recov', 'sev_SAM_tx/nat_recov_to_MAM', + 'mod_not_yet_recovered', + 'sev_not_yet_recovered']] + + for recov_opt in w_length_df.columns: + _row_counter = 0 + _col_counter = 0 + # plot setup + fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 7)) + # axes[1, 2].axis('off') # 5+y has no data (no new cases in 5+y), its space is used to display the label + for _age in age_years: + plotting = pd.DataFrame() + # dict to dataframe + plotting[recov_opt] = \ + w_length_df.apply(lambda row: row[recov_opt][_age], axis=1) + + if recov_opt.startswith("mod_"): + colour_to_use = self.__colors_model['moderate wasting'] + y_upper_lim = 355 + else: + colour_to_use = self.__colors_model['severe wasting'] + y_upper_lim = 1000 + if recov_opt.endswith("not_yet_recovered"): + y_upper_lim = 4000 + + ax = plotting.plot(kind='bar', stacked=False, + ax=axes[_row_counter, _col_counter], + title=f"length of wasting in {_age} old", + color=colour_to_use, + ylim=[0, y_upper_lim]) + # show_legend = (_row_counter == 0 and _col_counter == 0) + # # show_x_axis_label = (_row_counter == 0 and _col_counter == 2) + # if show_legend: + # ax.legend(loc='upper right', bbox_to_anchor=(0.5, 1.2), + # fancybox=True, shadow=True, ncol=5) + # else: + ax.get_legend().remove() + # if show_x_axis_label: + # ax.set_xlabel('Year') # TODO: this is not working + ax.set_xlabel('year') + ax.set_ylabel('avg length of wasting (days)') + # move to another row + if _col_counter == 2: + _row_counter += 1 + _col_counter = -1 + _col_counter += 1 # increment column counter + + fig.suptitle(f'{recov_opt}', fontsize=16) + # Adjust layout to make room for the suptitle + fig.tight_layout(rect=[0, 0, 1, 0.95]) + fig_output_name = ('wasting_length__' + recov_opt + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) + # plt.show(`) + + def plot_wasting_initial_overall_prevalence(self): + """ plot wasting prevalence of all age groups for the year 2010. Proportions are obtained by getting a total + number of children wasted (moderately and severely) divided by the total number of children less than 5 years""" + + ## Prevalence at 2010, ie data from the same source used to draw initial prevalence by age group + w_prev_calib_data_years_only_df = pd.DataFrame({ + 'sev_wast_calib': [0.015], + 'mod_wast_calib': [0.025] + }, index=[2010]) + date_range = pd.Index([2010], name='date') + w_prev_calib = pd.DataFrame(index=date_range) + # filling missing values with 0 + w_prev_calib_df = w_prev_calib.merge( + w_prev_calib_data_years_only_df, left_index=True, right_index=True, how='left' + ).fillna(0) + + ## Initial prevalence at the beginning of 2010 - model + init_w_prev_2010_only_df = self.__w_logs_dict["wasting_init_prevalence_props"] + init_w_prev_2010_only_df = init_w_prev_2010_only_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']].rename( + columns={'total_sev_under5_prop': 'total_init_sev_under5_prop', 'total_mod_under5_prop': 'total_init_mod_under5_prop'} + ) + init_w_prev_2010_only_df = init_w_prev_2010_only_df.set_index(init_w_prev_2010_only_df.date.dt.year) + init_w_prev_2010_only_df = init_w_prev_2010_only_df.drop(columns='date') + init_w_prev_2010_only_df = init_w_prev_2010_only_df.loc[[2010]] + init_w_prev_df = pd.DataFrame(index=date_range) + # filling missing values with 0 + init_w_prev_df = init_w_prev_df.merge( + init_w_prev_2010_only_df, left_index=True, right_index=True, how='left' + ).fillna(0) + + w_prev_calib_and_init_df = pd.merge(init_w_prev_df, w_prev_calib_df, on='date') + columns_to_plot = [ + ['total_init_sev_under5_prop', 'total_init_mod_under5_prop'], + ['sev_wast_calib', 'mod_wast_calib'], + ] + colors_to_plot = { + 'total_init_sev_under5_prop': self.__colors_init_data['severe wasting'], + 'total_init_mod_under5_prop': self.__colors_init_data['moderate wasting'], + 'sev_wast_calib': self.__colors_data['severe wasting'], + 'mod_wast_calib': self.__colors_data['moderate wasting'], + } + labels_to_plot = { + 'total_init_sev_under5_prop': 'severe wasting (initial)', + 'total_init_mod_under5_prop': 'moderate wasting (initial)', + 'sev_wast_calib': 'severe wasting (data)', + 'mod_wast_calib': 'moderate wasting (data)', + } + + fig, ax = plt.subplots() + bar_spots = len(columns_to_plot) + bar_width = 0.3 / bar_spots + pos = np.arange(len(w_prev_calib_and_init_df)) + dodge_offsets = np.linspace(-bar_spots * bar_width / 2, bar_spots * bar_width / 2, bar_spots, endpoint=False) + for columns, offset in zip(columns_to_plot, dodge_offsets): + bottom = 0 + for col in ([columns] if isinstance(columns, str) else columns): + ax.bar(pos + offset, w_prev_calib_and_init_df[col], bottom=bottom, width=bar_width, align='edge', + label=labels_to_plot[col], color=colors_to_plot[col]) + bottom += w_prev_calib_and_init_df[col] + ax.set_xticks(pos) + ax.set_xticklabels(w_prev_calib_and_init_df.index, rotation=90) + ax.set_title(r"Overall wasting prevalence $\bf{at}$ $\bf{initiation}$ (2010)", fontsize=title_fontsize-1) + ax.set_ylabel('proportion of wasted children in the year') + ax.set_xlabel('year') + ax.set_ylim([0, 0.131]) + ax.legend(fontsize=legend_fontsize) + plt.tight_layout() + fig_output_name = ('wasting_initial_overall_prevalence__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) + # plt.show() + + def plot_wasting_initial_prevalence_by_age_group(self): + """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of + children wasted in a particular age-group divided by the total number of children per that age-group""" + + # Initial prevalence at the beginning of 2010 - model + w_prev_df = self.__w_logs_dict["wasting_init_prevalence_props"] + w_prev_df = w_prev_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) + w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) + w_prev_df = w_prev_df.drop(columns='date') + + # 2010 prevalence calibration data + # TODO: load data_2010 from the resource file: + # resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' + data_2010 = { + 'wasted_calib': [7.0, 13.0, 12.7, 2.4, 2.7, 1.9, 0.0], + 'sev_wast_calib': [2.1, 7.1, 4.7, 0.9, 0.7, 0.6, 0.0] + } + data_2010['mod_wast_calib'] = \ + [(w - s)/100 for w, s in zip(data_2010['wasted_calib'], data_2010['sev_wast_calib'])] + data_2010['sev_wast_calib'] = \ + [s/100 for s in data_2010['sev_wast_calib']] + + # Prepare plotting data + plotting_model = {'severe wasting': {}, 'moderate wasting': {}} + for col in w_prev_df.columns: + prefix, age_group = col.split('__') + if prefix == 'sev': + plotting_model['severe wasting'][age_group] = w_prev_df[col].values[0] + elif prefix == 'mod': + plotting_model['moderate wasting'][age_group] = w_prev_df[col].values[0] + plotting_model = pd.DataFrame(plotting_model) + + plotting_calib = {'severe wasting': {}, 'moderate wasting': {}} + age_groups = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] + for i, age_group in enumerate(age_groups): + plotting_calib['severe wasting'][age_group] = data_2010['sev_wast_calib'][i] + plotting_calib['moderate wasting'][age_group] = data_2010['mod_wast_calib'][i] + plotting_calib = pd.DataFrame(plotting_calib) + + plotting_model = plotting_model.reindex(age_groups) + plotting_calib = plotting_calib.reindex(age_groups) + + # Plot wasting prevalence + fig, ax = plt.subplots(figsize=(10, 6)) + bar_width = 0.35 + # Set positions of bars on x-axis + r1 = range(len(plotting_model)) + r2 = [x + bar_width for x in r1] + + # Plot the first set of bars (model data) + ax.bar(r1, plotting_model['severe wasting'], + color=self.__colors_init_data['severe wasting'], width=bar_width, + label='severe wasting (initial)') + ax.bar(r1, plotting_model['moderate wasting'], bottom=plotting_model['severe wasting'], + color=self.__colors_init_data['moderate wasting'], width=bar_width, + label='moderate wasting (initial)') + + # Plot the second set of bars (calibration data) + ax.bar(r2, plotting_calib['severe wasting'], + color=self.__colors_data['severe wasting'], width=bar_width, + label='severe wasting (data)') + ax.bar(r2, plotting_calib['moderate wasting'], bottom=plotting_calib['severe wasting'], + color=self.__colors_data['moderate wasting'], width=bar_width, + label='moderate wasting (data)') + + ax.set_xlabel('age group') + ax.set_ylabel('proportion') + ax.set_title( + r"Wasting prevalence in children 0-59 months per each age group $\bf{at}$ $\bf{initiation}$ (2010)", + fontsize=title_fontsize-1) + ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) + ax.set_xticklabels(age_groups) + ax.set_ylim([0, 0.16]) + ax.legend(fontsize=legend_fontsize) + + # Adjust the layout to make space for the footnote + plt.subplots_adjust(top=0.15) # Adjust the top margin + # Add footnote + fig.figure.text(0.43, 0.95, + "proportion = number of wasted children in the age group " + "/ total number of children in the age group", + ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) + plt.tight_layout() + fig_output_name = ('wasting_initial_prevalence_per_each_age_group__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) + # plt.show() + + def plot_wasting_prevalence_per_year(self): + """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of + children wasted divide by the total number of children less than 5 years""" + + ## Prevalence at some years - data (2010 are the data used to draw initial prevalence) + # TODO: add calibration data into the resource file: + # resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' + # and load here and for initial overall prev from the RF + w_prev_calib_data_years_only_df = pd.DataFrame({ + 'sev_wast_calib': [0.015, 0.011, 0.006, 0.007], + 'mod_wast_calib': [0.025, 0.027, 0.021, 0.019] + }, index=[2010, 2013, 2015, 2019]) + date_range = pd.Index(range(2010, 2031), name='date') + w_prev_calib = pd.DataFrame(index=date_range) + # filling missing values with 0 + w_prev_calib_df = w_prev_calib.merge( + w_prev_calib_data_years_only_df, left_index=True, right_index=True, how='left' + ).fillna(0) + + ## Prevalence at the end of years - model + w_prev_df = self.__w_logs_dict["wasting_prevalence_props"] + w_prev_df = w_prev_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']] + w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) + w_prev_df = w_prev_df.drop(columns='date') + + ## Initial prevalence at the beginning of 2010 - model + init_w_prev_2010_only_df = self.__w_logs_dict["wasting_init_prevalence_props"] + init_w_prev_2010_only_df = init_w_prev_2010_only_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']].rename( + columns={'total_sev_under5_prop': 'total_init_sev_under5_prop', 'total_mod_under5_prop': 'total_init_mod_under5_prop'} + ) + init_w_prev_2010_only_df = init_w_prev_2010_only_df.set_index(init_w_prev_2010_only_df.date.dt.year) + init_w_prev_2010_only_df = init_w_prev_2010_only_df.drop(columns='date') + init_w_prev_2010_only_df = init_w_prev_2010_only_df.loc[[2010]] + init_w_prev_df = pd.DataFrame(index=date_range) + # filling missing values with 0 + init_w_prev_df = init_w_prev_df.merge( + init_w_prev_2010_only_df, left_index=True, right_index=True, how='left' + ).fillna(0) + + w_prev_calib_and_init_df = pd.merge(init_w_prev_df, w_prev_calib_df, on='date') + w_prev_plot_df = pd.merge(w_prev_df, w_prev_calib_and_init_df, on='date').loc[lambda df: df.index >= 2015] + columns_to_plot = [ + ['total_init_sev_under5_prop', 'total_init_mod_under5_prop'], + ['total_sev_under5_prop', 'total_mod_under5_prop'], + ['sev_wast_calib', 'mod_wast_calib'], + ] + colors_to_plot = { + 'total_sev_under5_prop': self.__colors_model['severe wasting'], + 'total_mod_under5_prop': self.__colors_model['moderate wasting'], + 'sev_wast_calib': self.__colors_data['severe wasting'], + 'mod_wast_calib': self.__colors_data['moderate wasting'], + 'total_init_sev_under5_prop': self.__colors_init_data['severe wasting'], + 'total_init_mod_under5_prop': self.__colors_init_data['moderate wasting'] + + } + labels_to_plot = { + 'total_sev_under5_prop': 'severe wasting (model)', + 'total_mod_under5_prop': 'moderate wasting (model)', + 'sev_wast_calib': 'severe wasting (data)', + 'mod_wast_calib': 'moderate wasting (data)', + 'total_init_sev_under5_prop': 'severe wasting (initial)', + 'total_init_mod_under5_prop': 'moderate wasting (initial)' + } + + fig, ax = plt.subplots() + bar_spots = len(columns_to_plot) + bar_width = 0.8 / bar_spots + pos = np.arange(len(w_prev_plot_df)) + dodge_offsets = np.linspace(-bar_spots * bar_width / 2, bar_spots * bar_width / 2, bar_spots, endpoint=False) + for columns, offset in zip(columns_to_plot, dodge_offsets): + bottom = 0 + for col in ([columns] if isinstance(columns, str) else columns): + ax.bar(pos + offset, w_prev_plot_df[col], bottom=bottom, width=bar_width, align='edge', + label=labels_to_plot[col], color=colors_to_plot[col]) + bottom += w_prev_plot_df[col] + ax.set_xticks(pos) + ax.set_xticklabels(w_prev_plot_df.index, rotation=90) + ax.set_title("Wasting prevalence in children 0-59 months per year", fontsize=title_fontsize-6) + ax.set_ylabel('proportion of wasted children in the year') + ax.set_xlabel('year') + ax.set_ylim([0, 0.06]) + ax.legend(fontsize=legend_fontsize-4) + plt.tight_layout() + fig_output_name = ('wasting_prevalence_per_year__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) + # plt.show() + + def plot_wasting_prevalence_by_age_group(self): + """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of + children wasted in a particular age-group divided by the total number of children per that age-group""" + + age_groups = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] + + # ### Calibration Data + # Load calibration data from CSV file + wasting_calib_data_path = resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' + wasting_calib_data_df = pd.read_csv(wasting_calib_data_path, index_col='year') + + # Recalculate data to proportions (0 to 1) and separate mod wast as (wasted - sev wast) + wasting_calib_data_df['mod_wast_calib'] = \ + (wasting_calib_data_df['prev any wast (%)'] - wasting_calib_data_df['prev severe wast (%)']) / 100 + wasting_calib_data_df['sev_wast_calib'] = wasting_calib_data_df['prev severe wast (%)'] / 100 + + # Pivot the data to get the required format + w_prev_calib_data_df = wasting_calib_data_df.pivot(columns='age_group (months)', + values=['mod_wast_calib', 'sev_wast_calib']) + w_prev_calib_data_df.columns = [f'{col[0][:3]}__{col[1]}' for col in w_prev_calib_data_df.columns] + + # Load calibration sample sizes from CSV file + sample_sizes_calib_data_df = wasting_calib_data_df.pivot(columns='age_group (months)', values='sample_size') + sample_sizes_calib_data_df = sample_sizes_calib_data_df.reindex(columns=age_groups) + + # ### Model Outcomes + # Load modelled prevalence proportions + w_prev_model_df = self.__w_logs_dict["wasting_prevalence_props"] + w_prev_model_df = w_prev_model_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) + w_prev_model_df = w_prev_model_df.set_index(w_prev_model_df.date.dt.year) + w_prev_model_df = w_prev_model_df.drop(columns='date') + + # Load modelled population sizes + pop_sizes_model_df = self.__w_logs_dict['pop sizes'] + pop_sizes_model_df = pop_sizes_model_df.set_index(pop_sizes_model_df.date.dt.year).rename_axis('year') + pop_sizes_model_df = pop_sizes_model_df.drop(columns='date') + pop_sizes_model_df = pop_sizes_model_df.filter(like='total__').rename( + lambda x: x.replace('total__', ''), axis=1 + )[age_groups] + + for year_calib in w_prev_calib_data_df.index: + w_prev_calib_data_year_df = w_prev_calib_data_df.loc[w_prev_calib_data_df.index == year_calib] + w_prev_model_year_df = w_prev_model_df.loc[w_prev_model_df.index == year_calib] + + def create_plotting_data(df, df_name): + plotting = {'severe wasting': {}, 'moderate wasting': {}, 'any wasting': {}} + for col in df.columns: + prefix, agegp = col.split('__') + if prefix == 'sev': + plotting['severe wasting'][agegp] = df[col].values[0] + elif prefix == 'mod': + plotting['moderate wasting'][agegp] = df[col].values[0] + plotting['any wasting'][agegp] = df[col].values[0] + df[f'sev__{agegp}'].values[0] + plotting_df = pd.DataFrame(plotting) + assert set(plotting_df.index) == set(age_groups),\ + f"age groups in {df_name} are not in line with the age_groups." + plotting_df = plotting_df.reindex(age_groups) + return plotting_df + + # Create plotting data for both dataframes + plotting_model = create_plotting_data(w_prev_model_year_df, 'w_prev_model_year_df') + plotting_calib = create_plotting_data(w_prev_calib_data_year_df, 'w_prev_calib_data_year_df') + + # Calculate 95% confidence intervals for both + sample_sizes_calib_data_year = sample_sizes_calib_data_df.loc[year_calib, :] + sample_sizes_model_year = pop_sizes_model_df.loc[year_calib, :] + + confidence_level = 0.95 + z_score = stats.norm.ppf(1 - (1 - confidence_level) / 2) + + calib_data_margin_of_error_any_wast = [] + calib_data_margin_of_error_sev_wast = [] + for p, n in zip(plotting_calib['any wasting'].reindex(age_groups[:-1]), sample_sizes_calib_data_year[:-1]): + calib_data_margin_of_error_any_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) + for p, n in \ + zip(plotting_calib['severe wasting'].reindex(age_groups[:-1]),sample_sizes_calib_data_year[:-1]): + calib_data_margin_of_error_sev_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) + model_margin_of_error_any_wast = [] + model_margin_of_error_sev_wast = [] + for p, n in zip(plotting_model['any wasting'].reindex(age_groups[:-1]), sample_sizes_model_year[:-1]): + model_margin_of_error_any_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) + for p, n in zip(plotting_model['severe wasting'].reindex(age_groups[:-1]), sample_sizes_model_year[:-1]): + model_margin_of_error_sev_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) + + # ##### + # Plot wasting prevalence + fig, ax = plt.subplots(figsize=(10, 6)) + bar_width = 0.35 + # Set positions of bars on x-axis + r1 = range(len(plotting_model)) + r2 = [x + bar_width for x in r1] + + # Plot the first set of bars (model data) + ax.bar(r1, plotting_model['severe wasting'], + color=self.__colors_model['severe wasting'], width=bar_width, + label='severe wasting (model)') + ax.bar(r1, plotting_model['moderate wasting'], bottom=plotting_model['severe wasting'], + color=self.__colors_model['moderate wasting'], width=bar_width, + label='moderate wasting (model)') + + # Add the confidence intervals + for i, age_group in enumerate(age_groups[0:len(age_groups)-1]): + ax.errorbar(r1[i], plotting_model['any wasting'][age_group], + yerr=[model_margin_of_error_any_wast[i]], + capsize=5, fmt='none', color='black') + ax.errorbar(r1[i], plotting_model['severe wasting'][age_group], + yerr=[model_margin_of_error_sev_wast[i]], + capsize=5, fmt='none', color='white') + + # Plot the second set of bars (calibration data) + ax.bar(r2, plotting_calib['severe wasting'], + color=self.__colors_data['severe wasting'], width=bar_width, + label='severe wasting (data)') + ax.bar(r2, plotting_calib['moderate wasting'], bottom=plotting_calib['severe wasting'], + color=self.__colors_data['moderate wasting'], width=bar_width, + label='moderate wasting (data)') + + # Add the confidence intervals + for i, age_group in enumerate(age_groups[0:len(age_groups)-1]): + ax.errorbar(r2[i], plotting_calib['any wasting'][age_group], + yerr=[calib_data_margin_of_error_any_wast[i]], + capsize=5, fmt='none', color='black') + ax.errorbar(r2[i], plotting_calib['severe wasting'][age_group], + yerr=[calib_data_margin_of_error_sev_wast[i]], + capsize=5, fmt='none', color='white') + + ax.set_xlabel('age group') + ax.set_ylabel('proportion') + ax.set_title(f"Wasting prevalence in children 0-59 months per each age group in {year_calib}", + fontsize=title_fontsize-1) + ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) + ax.set_xticklabels(age_groups) + ax.set_ylim([0, 0.12]) + ax.legend(fontsize=legend_fontsize) + + # Adjust the layout to make space for the footnote + plt.subplots_adjust(top=0.15) # Adjust the bottom margin + # Add footnote + fig.figure.text(0.43, 0.95, + "proportion = number of wasted children in the age group " + "/ total number of children in the age group", + ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) + + plt.tight_layout() + fig_output_name = (f'wasting_prevalence_per_each_age_group_{year_calib}__' + self.datestamp) + if year_calib in [2015, 2019]: + self.save_fig__store_pdf_file(fig, fig_output_name) + # plt.show() + + def plot_model_gbd_deaths_incl_burnin_period(self): + """ compare model and GBD deaths 2010-2014 & 2015-2019 """ + death_compare = \ + compare_number_of_deaths(self.__log_file_path, resources_path) + fig, ax = plt.subplots(figsize=(10, 6)) + # cause of death as of GBD 2019 'Protein-energy malnutrition' was labeled as 'Childhood Undernutrition' in + # wasting module + plot_df = death_compare.loc[(['2010-2014', '2015-2019'], + slice(None), ['0-4'], 'Childhood Undernutrition' + )].groupby('period').sum() + plotting = plot_df.loc[['2010-2014', '2015-2019']] + ax = plotting['model'].plot.bar(label='Model', ax=ax, rot=0) + ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, + yerr=[plotting.GBD_lower, plotting.GBD_upper], + fmt='o', color='#000', label="GBD") + + ax.set_title('Average direct deaths per year due to severe acute malnutrition in children under 5', fontsize=title_fontsize-1) + ax.set_xlabel("time period") + ax.set_ylabel("number of deaths") + ax.legend(loc='upper center', fontsize=legend_fontsize) + fig.tight_layout() + # Adjust the layout to make space for the footnote + plt.subplots_adjust(bottom=0.15) # Adjust the bottom margin + # Add footnote + fig.figure.text(0.5, 0.02, + "Model output against Global Burden of Diseases (GBD) study data", + ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) + fig_output_name = ('model_gbd_deaths_incl_burnin__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) + # plt.show() + + def plot_model_gbd_deaths_excl_burnin_period(self): + """ compare model and GBD deaths 2015-2019 """ + death_compare = \ + compare_number_of_deaths(self.__log_file_path, resources_path) + fig, ax = plt.subplots(figsize=(10, 6)) + # cause of death as of GBD 2019 'Protein-energy malnutrition' was labeled as 'Childhood Undernutrition' in + # wasting module + plot_df = death_compare.loc[(['2015-2019'], + slice(None), ['0-4'], 'Childhood Undernutrition' + )].groupby('period').sum() + plotting = plot_df.loc[['2015-2019']] + ax = plotting['model'].plot.bar(label='Model', ax=ax, rot=0) + ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, + yerr=[plotting.GBD_lower, plotting.GBD_upper], + fmt='o', color='#000', label="GBD") + + ax.set_title('Average direct deaths per year due to severe acute malnutrition in children under 5', + fontsize=title_fontsize - 1) + ax.set_xlabel("time period") + ax.set_ylabel("number of deaths") + ax.legend(loc='upper right', fontsize=legend_fontsize) + fig.tight_layout() + # Adjust the layout to make space for the footnote + plt.subplots_adjust(bottom=0.15) # Adjust the bottom margin + # Add footnote + fig.figure.text(0.5, 0.02, + "Model output against Global Burden of Diseases (GBD) study data", + ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) + fig_output_name = ('model_gbd_deaths_excl_burnin__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name) + # plt.show() + + def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): + + output_file_path = \ + in_outcome_figs_folder / f'wasting_all_figures__{self.datestamp}_{self.draw_nmb}_{self.run_nmb}.pdf' + # Remove the existing output file if it exists to ensure a clean start + if os.path.exists(output_file_path): + os.remove(output_file_path) + + # Assert that the file doesn't exist anymore after removal + assert not os.path.exists(output_file_path), "The file was not successfully removed." + + # Merge the PDF files + # Create a PDF writer object + pdf_writer = PdfWriter() + + # Iterate through the figure files and add each to the writer + for fig_file in self.fig_files: + pdf_reader = PdfReader(fig_file) + for page_num in range(len(pdf_reader.pages)): + page = pdf_reader.pages[page_num] + pdf_writer.add_page(page) + + # Write the merged PDF to a file + with open(output_file_path, 'wb') as out_file: + pdf_writer.write(out_file) + + +if __name__ == "__main__": + + # Path to the resource files used by the disease and intervention methods + resources_path = Path("./resources") + + # Find sim_results_folder_path associated with a given batch_file (and get most recent [-1]) + sim_results_folder_path = get_scenario_outputs(scenario_filename, outputs_path)[-1] + sim_results_folder_name = sim_results_folder_path.name + # Get the datestamp + assert sim_results_folder_name.startswith(scenario_filename + '-'),\ + "The scenario output name does not correspond with the set scenario_filename." + datestamp = sim_results_folder_name[(len(scenario_filename) + 1):] + + folders = [name for name in os.listdir(sim_results_folder_path) if \ + os.path.isdir(os.path.join(sim_results_folder_path, name)) and name.isdigit()] + + # Create a csv to write down calibration outputs + # as bool values indicating whether model outcomes and calibration data intersect + create_calib_outcome_csv(sim_results_folder_path) + + # Analyse each draw + # for now, we always have just one run, run 0 + run_nmb = 0 + for draw_nmb in range(0, len(folders)): + print(f"Analysing {draw_nmb=} ...") + time_start = time.time() + + # initialise the wasting class + wasting_analyses = WastingAnalyses(str(sim_results_folder_path), datestamp, draw_nmb, run_nmb) + + # plot wasting incidence + wasting_analyses.plot_wasting_incidence() + + # plot wasting incidence mod:sev proportions + # wasting_analyses.plot_wasting_incidence_mod_to_sev_props() + + # plot wasting length + # wasting_analyses.plot_wasting_length() + + # plot initial wasting prevalence + wasting_analyses.plot_wasting_initial_overall_prevalence() + wasting_analyses.plot_wasting_initial_prevalence_by_age_group() + + # plot prevalence through simulation + wasting_analyses.plot_wasting_prevalence_per_year() + wasting_analyses.plot_wasting_prevalence_by_age_group() + + # plot wasting deaths as compared to GBD deaths + # wasting_analyses.plot_model_gbd_deaths_incl_burnin_period() + wasting_analyses.plot_model_gbd_deaths_excl_burnin_period() + + # ### Save all figures in one pdf + outcome_figs_folder = sim_results_folder_path / '_outcome_figures' + outcome_figs_folder.mkdir(parents=True, exist_ok=True) + wasting_analyses.plot_all_figs_in_one_pdf(outcome_figs_folder) + + time_end = time.time() + print(f"... finished in (s): {(time_end - time_start)}") + + total_time_end = time.time() + print(f"total running time (s): {(total_time_end - total_time_start)}") + + From 8b71c41e083cd2dbf2d67cd4cefd668901b7ea79 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 20 May 2025 22:10:43 +0100 Subject: [PATCH 519/755] scenario_analysis_wast: 1) each draw and each run generating an outcome pdf --- .../scenario_analysis_wasting.py | 105 +++++++----------- 1 file changed, 43 insertions(+), 62 deletions(-) diff --git a/src/scripts/wasting_analyses/scenario_analysis_wasting.py b/src/scripts/wasting_analyses/scenario_analysis_wasting.py index 739584de0a..ffb79c8834 100644 --- a/src/scripts/wasting_analyses/scenario_analysis_wasting.py +++ b/src/scripts/wasting_analyses/scenario_analysis_wasting.py @@ -22,40 +22,18 @@ # ####### TO SET ####################################################################################################### scenario_filename = 'wasting_analysis__minimal_model' -outputs_path = Path("./outputs/sejjej5@ucl.ac.uk/wasting") +outputs_path = Path("./outputs/sejjej5@ucl.ac.uk/wasting/scenarios") +scenario_type = 'GM' # GM stands for scaling up Growth Monitoring attendance legend_fontsize = 12 title_fontsize = 16 ######################################################################################################################## -def create_calib_outcome_csv(sim_results_folder_path_str): +class WastingScenarioAnalyses: """ - Creates a new empty csv file with the header if it doesn't exist yet. - :return: - """ - csv_file_name = str(sim_results_folder_path_str).replace(str(outputs_path), '').lstrip('/') + \ - "_model_calib-data_intersect_bool" - csv_file_path = sim_results_folder_path_str / f"{csv_file_name}.csv" - - if not csv_file_path.exists(): - age_groups = [(0, 5), (6, 11), (12, 23), (24, 35), (36, 47), (48, 59)] - calib_ys = [2015, 2019] - wast_type_agegp = [f'{wast_type}_wast__{low_bound}_{high_bound}mo' for wast_type in ['any', 'sev'] for - low_bound, high_bound in age_groups] - year_wast_age_grps = [f'{year}__{wast_age_grp}' for year in calib_ys for wast_age_grp in wast_type_agegp] - sum_year_prev_calib_points = [f'{year}__sum_prev_calib_points' for year in calib_ys] - - with open(csv_file_path, 'w') as csv_file: - csv_file.write( - 'draw,run,' + ','.join(year_wast_age_grps) + ',deaths_2010_2014,deaths_2015_2019,' + - ','.join(sum_year_prev_calib_points) + ',sum_prev_calib_points,sum_all_calib_points\n' - ) - -class WastingAnalyses: - """ - This class looks at plotting all important outputs from the wasting module + This class looks at plotting all important outcomes from the scenario runs. """ - def __init__(self, sim_results_folder_path_str, in_datestamp, in_draw_nmb, in_run_nmb, in_png=False): + def __init__(self, in_scenario_type, sim_results_folder_path_str, in_datestamp, in_draw_nmb, in_run_nmb, in_png=False): self.outcomes_folder_path = sim_results_folder_path_str self.datestamp = in_datestamp self.draw_nmb = in_draw_nmb @@ -804,56 +782,59 @@ def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): # Path to the resource files used by the disease and intervention methods resources_path = Path("./resources") - # Find sim_results_folder_path associated with a given batch_file (and get most recent [-1]) - sim_results_folder_path = get_scenario_outputs(scenario_filename, outputs_path)[-1] - sim_results_folder_name = sim_results_folder_path.name + # Find scenario_results_folder_path associated with a given batch_file (and get most recent [-1]) + scenario_outputs_path = Path(outputs_path / scenario_type) + scenario_results_folder_path = get_scenario_outputs(scenario_filename, scenario_outputs_path)[-1] + scenario_results_folder_name = scenario_results_folder_path.name # Get the datestamp - assert sim_results_folder_name.startswith(scenario_filename + '-'),\ + assert scenario_results_folder_name.startswith(scenario_filename + '-'),\ "The scenario output name does not correspond with the set scenario_filename." - datestamp = sim_results_folder_name[(len(scenario_filename) + 1):] + datestamp = scenario_results_folder_name[(len(scenario_filename) + 1):] - folders = [name for name in os.listdir(sim_results_folder_path) if \ - os.path.isdir(os.path.join(sim_results_folder_path, name)) and name.isdigit()] + draws_folders = [name for name in os.listdir(scenario_results_folder_path) if \ + os.path.isdir(os.path.join(scenario_results_folder_path, name)) and name.isdigit()] - # Create a csv to write down calibration outputs - # as bool values indicating whether model outcomes and calibration data intersect - create_calib_outcome_csv(sim_results_folder_path) + draw0_folder_path = os.path.join(scenario_results_folder_path, '0') - # Analyse each draw - # for now, we always have just one run, run 0 - run_nmb = 0 - for draw_nmb in range(0, len(folders)): + runs_folders = [name for name in os.listdir(draw0_folder_path) if \ + os.path.isdir(os.path.join(draw0_folder_path, name))] + + # Analyse each draw with stochasticity given by runs + for draw_nmb in range(0, len(draws_folders)): print(f"Analysing {draw_nmb=} ...") time_start = time.time() - # initialise the wasting class - wasting_analyses = WastingAnalyses(str(sim_results_folder_path), datestamp, draw_nmb, run_nmb) + for run_nmb in range(0, len(runs_folders)): + + # initialise the wasting class + wast_scenario_analyses = \ + WastingScenarioAnalyses(scenario_type, str(scenario_results_folder_path), datestamp, draw_nmb, run_nmb) - # plot wasting incidence - wasting_analyses.plot_wasting_incidence() + # plot wasting incidence + wast_scenario_analyses.plot_wasting_incidence() - # plot wasting incidence mod:sev proportions - # wasting_analyses.plot_wasting_incidence_mod_to_sev_props() + # plot wasting incidence mod:sev proportions + # wasting_analyses.plot_wasting_incidence_mod_to_sev_props() - # plot wasting length - # wasting_analyses.plot_wasting_length() + # plot wasting length + # wasting_analyses.plot_wasting_length() - # plot initial wasting prevalence - wasting_analyses.plot_wasting_initial_overall_prevalence() - wasting_analyses.plot_wasting_initial_prevalence_by_age_group() + # plot initial wasting prevalence + wast_scenario_analyses.plot_wasting_initial_overall_prevalence() + wast_scenario_analyses.plot_wasting_initial_prevalence_by_age_group() - # plot prevalence through simulation - wasting_analyses.plot_wasting_prevalence_per_year() - wasting_analyses.plot_wasting_prevalence_by_age_group() + # plot prevalence through simulation + wast_scenario_analyses.plot_wasting_prevalence_per_year() + wast_scenario_analyses.plot_wasting_prevalence_by_age_group() - # plot wasting deaths as compared to GBD deaths - # wasting_analyses.plot_model_gbd_deaths_incl_burnin_period() - wasting_analyses.plot_model_gbd_deaths_excl_burnin_period() + # plot wasting deaths as compared to GBD deaths + # wasting_analyses.plot_model_gbd_deaths_incl_burnin_period() + wast_scenario_analyses.plot_model_gbd_deaths_excl_burnin_period() - # ### Save all figures in one pdf - outcome_figs_folder = sim_results_folder_path / '_outcome_figures' - outcome_figs_folder.mkdir(parents=True, exist_ok=True) - wasting_analyses.plot_all_figs_in_one_pdf(outcome_figs_folder) + # ### Save all figures in one pdf + outcome_figs_folder = scenario_results_folder_path / '_outcome_figures' + outcome_figs_folder.mkdir(parents=True, exist_ok=True) + wast_scenario_analyses.plot_all_figs_in_one_pdf(outcome_figs_folder) time_end = time.time() print(f"... finished in (s): {(time_end - time_start)}") From c1fa69b0af6d8e06a6d0b74c9675871fb64e5818 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 20 May 2025 22:26:48 +0100 Subject: [PATCH 520/755] scenario_analysis_wast: 2) runs added into the draw analysis --- .../scenario_analysis_wasting.py | 68 ++++++++++--------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/src/scripts/wasting_analyses/scenario_analysis_wasting.py b/src/scripts/wasting_analyses/scenario_analysis_wasting.py index ffb79c8834..8b9dfad5e6 100644 --- a/src/scripts/wasting_analyses/scenario_analysis_wasting.py +++ b/src/scripts/wasting_analyses/scenario_analysis_wasting.py @@ -33,13 +33,22 @@ class WastingScenarioAnalyses: This class looks at plotting all important outcomes from the scenario runs. """ - def __init__(self, in_scenario_type, sim_results_folder_path_str, in_datestamp, in_draw_nmb, in_run_nmb, in_png=False): - self.outcomes_folder_path = sim_results_folder_path_str + def __init__(self, in_scenario_type, sim_results_folder_path_str, in_datestamp, in_draw_nmb, in_png=False): + self.outcomes_draw_folder_path_str = sim_results_folder_path_str self.datestamp = in_datestamp self.draw_nmb = in_draw_nmb - self.run_nmb = in_run_nmb + self.run_nmb = 0 self.png = in_png, """bool indicating whether we want to save all figures not only as pdf, but also as png""" + draw_folder_path = os.path.join(Path(scenario_results_folder_path), str(self.draw_nmb)) + + runs_folders = [name for name in os.listdir(draw_folder_path) if \ + os.path.isdir(os.path.join(draw_folder_path, name))] + + for run_nmb in range(0, len(runs_folders)): + print(f"{run_nmb=}") + print("draw analysis continues ...") + sim_results_folder_draw_x_run_0_path_str = sim_results_folder_path_str + f'/{draw_nmb}/{run_nmb}/' sim_results_file_name_prefix = scenario_filename sim_results_file_name_extension = '.log.gz' @@ -88,7 +97,7 @@ def __init__(self, in_scenario_type, sim_results_folder_path_str, in_datestamp, } def save_fig__store_pdf_file(self, fig, fig_output_name: str) -> None: - full_path_and_file_name = self.outcomes_folder_path + f'/{self.draw_nmb}/{self.run_nmb}/' + fig_output_name + \ + full_path_and_file_name = self.outcomes_draw_folder_path_str + f'/{self.draw_nmb}/{self.run_nmb}/' + fig_output_name + \ f'_{self.draw_nmb}_{self.run_nmb}' if self.png: #TODO: doesn't seem to be working fig.savefig(full_path_and_file_name + '.png', format='png') @@ -794,47 +803,40 @@ def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): draws_folders = [name for name in os.listdir(scenario_results_folder_path) if \ os.path.isdir(os.path.join(scenario_results_folder_path, name)) and name.isdigit()] - draw0_folder_path = os.path.join(scenario_results_folder_path, '0') - - runs_folders = [name for name in os.listdir(draw0_folder_path) if \ - os.path.isdir(os.path.join(draw0_folder_path, name))] - # Analyse each draw with stochasticity given by runs for draw_nmb in range(0, len(draws_folders)): print(f"Analysing {draw_nmb=} ...") time_start = time.time() - for run_nmb in range(0, len(runs_folders)): - - # initialise the wasting class - wast_scenario_analyses = \ - WastingScenarioAnalyses(scenario_type, str(scenario_results_folder_path), datestamp, draw_nmb, run_nmb) + # initialise the wasting class + wast_scenario_analyses = \ + WastingScenarioAnalyses(scenario_type, str(scenario_results_folder_path), datestamp, draw_nmb) - # plot wasting incidence - wast_scenario_analyses.plot_wasting_incidence() + # plot wasting incidence + wast_scenario_analyses.plot_wasting_incidence() - # plot wasting incidence mod:sev proportions - # wasting_analyses.plot_wasting_incidence_mod_to_sev_props() + # plot wasting incidence mod:sev proportions + # wasting_analyses.plot_wasting_incidence_mod_to_sev_props() - # plot wasting length - # wasting_analyses.plot_wasting_length() + # plot wasting length + # wasting_analyses.plot_wasting_length() - # plot initial wasting prevalence - wast_scenario_analyses.plot_wasting_initial_overall_prevalence() - wast_scenario_analyses.plot_wasting_initial_prevalence_by_age_group() + # plot initial wasting prevalence + wast_scenario_analyses.plot_wasting_initial_overall_prevalence() + wast_scenario_analyses.plot_wasting_initial_prevalence_by_age_group() - # plot prevalence through simulation - wast_scenario_analyses.plot_wasting_prevalence_per_year() - wast_scenario_analyses.plot_wasting_prevalence_by_age_group() + # plot prevalence through simulation + wast_scenario_analyses.plot_wasting_prevalence_per_year() + wast_scenario_analyses.plot_wasting_prevalence_by_age_group() - # plot wasting deaths as compared to GBD deaths - # wasting_analyses.plot_model_gbd_deaths_incl_burnin_period() - wast_scenario_analyses.plot_model_gbd_deaths_excl_burnin_period() + # plot wasting deaths as compared to GBD deaths + # wasting_analyses.plot_model_gbd_deaths_incl_burnin_period() + wast_scenario_analyses.plot_model_gbd_deaths_excl_burnin_period() - # ### Save all figures in one pdf - outcome_figs_folder = scenario_results_folder_path / '_outcome_figures' - outcome_figs_folder.mkdir(parents=True, exist_ok=True) - wast_scenario_analyses.plot_all_figs_in_one_pdf(outcome_figs_folder) + # ### Save all figures in one pdf + outcome_figs_folder = scenario_results_folder_path / '_outcome_figures' + outcome_figs_folder.mkdir(parents=True, exist_ok=True) + wast_scenario_analyses.plot_all_figs_in_one_pdf(outcome_figs_folder) time_end = time.time() print(f"... finished in (s): {(time_end - time_start)}") From 9f478d55b33543adbda1d4f4291fb154bd948d1c Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 21 May 2025 11:57:59 +0100 Subject: [PATCH 521/755] analysis_utility_function: utility function script prepared by Joe saved and will be modified for the wasting analyses --- .../analysis_utility_functions.py | 313 ++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 src/scripts/wasting_analyses/analysis_utility_functions.py diff --git a/src/scripts/wasting_analyses/analysis_utility_functions.py b/src/scripts/wasting_analyses/analysis_utility_functions.py new file mode 100644 index 0000000000..16869c068d --- /dev/null +++ b/src/scripts/wasting_analyses/analysis_utility_functions.py @@ -0,0 +1,313 @@ +import numpy as np +import scipy.stats as st +from matplotlib import pyplot as plt + +from tlo.analysis.utils import extract_results + +plt.style.use('seaborn-darkgrid') + +"""This file contains functions used for wasting analyses to extract data, derive outcomes and generate plots. +(It is based on analysis_utility_function prepared by Joe for maternal_perinatal_analyses.)""" + + +def return_95_CI_across_runs(df, sim_years): + """Returns a list of lists from an outcome DF containing the mean and 95%CI values for that outcome over time. + The first list containins the mean value of a given outcome per year across runs, the second contains the smaller + value of the 95% CI and the third list contains the larger value of the 95% Ci""" + + year_means = list() + lower_CI = list() + upper_CI = list() + + for year in sim_years: + if year in df.index: + row = df.loc[year] + year_means.append(row.mean()) + ci = st.t.interval(0.95, len(row) - 1, loc=np.mean(row), scale=st.sem(row)) + lower_CI.append(ci[0]) + upper_CI.append(ci[1]) + else: + year_means.append(0) + lower_CI.append(0) + upper_CI.append(0) + + return [year_means, lower_CI, upper_CI] + + +def get_mean_95_CI_from_list(list_item): + """Returns the mean and 95% CI of data in a provided list""" + ci = st.t.interval(0.95, len(list_item) - 1, loc=np.mean(list_item), scale=st.sem(list_item)) + result = [np.mean(list_item), ci[0], ci[1]] + return result + + +def get_mean_from_columns(df, function): + """Returns mean value for each column in a provided data frame""" + values = list() + for col in df: + if function == 'avg': + values.append(np.mean(df[col])) + else: + values.append(sum(df[col])) + return values + + +def line_graph_with_ci_and_target_rate(sim_years, data, target_data_dict, ylim, y_label, title, + graph_location, file_name): + """Outputs and saves line plot of an outcome over time, including uncertainty, in addition to a pre-determined + calibration target""" + fig, ax = plt.subplots() + ax.plot(sim_years, data[0], label="Model", color='deepskyblue') + ax.fill_between(sim_years, data[1], data[2], label="95% CI", color='b', alpha=.1) + + if target_data_dict['double']: + plt.errorbar(target_data_dict['first']['year'], target_data_dict['first']['value'], + label=target_data_dict['first']['label'], yerr=target_data_dict['first']['ci'], + fmt='o', color='darkseagreen', ecolor='green', elinewidth=3, capsize=0) + plt.errorbar(target_data_dict['second']['year'], target_data_dict['second']['value'], + label=target_data_dict['second']['label'], yerr=target_data_dict['second']['ci'], + fmt='o', color='darkseagreen', ecolor='green', elinewidth=3, capsize=0) + + elif not target_data_dict['double']: + plt.errorbar(target_data_dict['first']['year'], target_data_dict['first']['value'], + label=target_data_dict['first']['label'], yerr=target_data_dict['first']['ci'], + fmt='o', color='darkseagreen', ecolor='green', elinewidth=3, capsize=0) + + plt.xlabel('Year') + plt.ylabel(y_label) + plt.title(title) + ax.set(ylim=(0, ylim)) + plt.xticks(sim_years, labels=sim_years, rotation=45, fontsize=8) + plt.gca().set_ylim(bottom=0) + plt.legend() + plt.savefig(f'{graph_location}/{file_name}.png') + plt.show() + + +def simple_line_chart_with_target(sim_years, model_rate, target_rate, y_title, title, file_name, graph_location): + """Outputs and saves line plot of an outcome over time in addition to a pre-determined + calibration target""" + plt.plot(sim_years, model_rate, 'o-g', label="Model", color='deepskyblue') + plt.plot(sim_years, target_rate, 'o-g', label="Target rate", color='darkseagreen') + plt.ylabel(y_title) + plt.xlabel('Year') + plt.title(title) + plt.gca().set_ylim(bottom=0) + plt.legend() + plt.savefig(f'{graph_location}/{file_name}.png') + plt.show() + + +def simple_line_chart_with_ci(sim_years, data, y_title, title, file_name, graph_location): + """Outputs and saves line plot of an outcome over time, including uncertainty""" + fig, ax = plt.subplots() + ax.plot(sim_years, data[0], label="Model (mean)", color='deepskyblue') + ax.fill_between(sim_years, data[1], data[2], color='b', alpha=.1, label="95% CI") + plt.ylabel(y_title) + plt.xlabel('Year') + plt.title(title) + plt.legend() + plt.gca().set_ylim(bottom=0) + plt.grid(True) + plt.savefig(f'{graph_location}/{file_name}.png') + plt.show() + + +def simple_bar_chart(model_rates, x_title, y_title, title, file_name, sim_years, graph_location): + """Outputs a simple bar chart over time""" + bars = sim_years + x_pos = np.arange(len(bars)) + plt.bar(x_pos, model_rates, label="Model", color='thistle') + plt.xticks(x_pos, bars, rotation=90) + plt.xlabel(x_title) + plt.ylabel(y_title) + plt.title(title) + plt.legend() + plt.savefig(f'{graph_location}/{file_name}.png') + plt.show() + + +def comparison_graph_multiple_scenarios_multi_level_dict(colours, intervention_years, data_dict, key, y_label, title, + graph_location, save_name): + """Outputs and saves line plot of an outcome over time, including uncertainty, in addition to a pre-determined + calibration target. Data from the model is provided as a dictionary with multiple entries""" + fig, ax = plt.subplots() + + for k, colour in zip(data_dict, colours): + ax.plot(intervention_years, data_dict[k][key][0], label=k, color=colour) + ax.fill_between(intervention_years, data_dict[k][key][1], data_dict[k][key][2], color=colour, alpha=.1) + + plt.ylabel(y_label) + plt.xlabel('Year') + plt.title(title) + + if 'nmr' in key: + plt.gca().set_ylim(bottom=0, top=25) + elif 'sbr' in key: + plt.gca().set_ylim(bottom=0, top=20) + else: + plt.gca().set_ylim(bottom=0) + + plt.legend() + plt.xticks(intervention_years, labels=intervention_years, rotation=45, fontsize=8) + plt.savefig(f'./{graph_location}/{save_name}.png', bbox_inches='tight') + plt.show() + + +def comparison_bar_chart_multiple_bars(data, dict_name, intervention_years, colours, y_title, title, + plot_destination_folder, save_name): + """Outputs a barchart comparing two data sources""" + + N = len(intervention_years) + ind = np.arange(N) + if len(data.keys()) > 3: + width = 0.15 + else: + width = 0.2 + + x_ticks = list() + for x in range(len(intervention_years)): + x_ticks.append(x) + + for k, position, colour in zip(data, [ind - width, ind, ind + width, ind + width * 2, ind + width * 3], + colours): + ci = [(x - y) / 2 for x, y in zip(data[k][dict_name][2], data[k][dict_name][1])] + plt.bar(position, data[k][dict_name][0], width, label=k, yerr=ci, color=colour) + + plt.ylabel(y_title) + plt.xlabel('Years') + plt.title(title) + plt.legend(loc='best') + plt.xticks(x_ticks, labels=intervention_years) + plt.savefig(f'{plot_destination_folder}/{save_name}.png') + plt.show() + + +# =========================== FUNCTIONS RETURNING DATA FROM MULTIPLE SCENARIOS ======================================= +def get_modules_maternal_complication_dataframes(results_folder): + """Returns a dataframe from a scenario file which contains the number of maternal complications by type per year + for a given python script""" + comp_dfs = dict() + + for module in ['pregnancy_supervisor', 'labour', 'postnatal_supervisor']: + c_df = extract_results( + results_folder, + module=f"tlo.methods.{module}", + key="maternal_complication", + custom_generate_series=( + lambda df_: df_.assign(year=df_['date'].dt.year).groupby(['year', 'type'])['person'].count()), + do_scaling=True + ) + complications_df = c_df.fillna(0) + + comp_dfs[module] = complications_df + + return comp_dfs + + +def get_modules_neonatal_complication_dataframes(results_folder): + """Returns a dataframe from a scenario file which contains the number of neonatal complications by type per year + for a given python script""" + comp_dfs = dict() + + for module in ['newborn_outcomes', 'postnatal_supervisor']: + n_df = extract_results( + results_folder, + module=f"tlo.methods.{module}", + key="newborn_complication", + custom_generate_series=( + lambda df_: df_.assign(year=df_['date'].dt.year).groupby(['year', 'type'])['newborn'].count()), + do_scaling=True + ) + complications_df = n_df.fillna(0) + + comp_dfs[module] = complications_df + + return comp_dfs + + +def return_birth_data_from_multiple_scenarios(results_folders, sim_years, intervention_years): + """ Extracts data relating to births from a series of pre-specified scenario files""" + + def extract_births(folder): + br = extract_results( + folder, + module="tlo.methods.demography", + key="on_birth", + custom_generate_series=( + lambda df: df.assign( + year=df['date'].dt.year).groupby(['year'])['year'].count()), + do_scaling=True + ) + births_results = br.fillna(0) + total_births_per_year = return_95_CI_across_runs(births_results, sim_years) + + int_df = births_results.loc[intervention_years[0]: intervention_years[-1]] + int_births_per_year = return_95_CI_across_runs(int_df, intervention_years) + + agg_births_data = get_mean_from_columns(births_results.loc[intervention_years[0]: intervention_years[-1]], + 'agg') + agg_births = get_mean_95_CI_from_list(agg_births_data) + + return {'total_births': total_births_per_year, + 'int_births': int_births_per_year, + 'agg_births': agg_births, + 'births_data_frame': births_results} + + return {k: extract_births(results_folders[k]) for k in results_folders} + + +def return_pregnancy_data_from_multiple_scenarios(results_folders, sim_years, intervention_years): + """ Extracts data relating to pregnancies from a series of pre-specified scenario files""" + + def extract_pregnancies(folder): + pr = extract_results( + folder, + module="tlo.methods.contraception", + key="pregnancy", + custom_generate_series=( + lambda df: df.assign(year=df['date'].dt.year).groupby(['year'])['year'].count()), + do_scaling=True + ) + preg_results = pr.fillna(0) + total_pregnancies_per_year = return_95_CI_across_runs(preg_results, sim_years) + total_pregnancies_per_year_int = return_95_CI_across_runs( + preg_results.loc[intervention_years[0]: intervention_years[-1]], intervention_years) + + agg_preg_data = get_mean_from_columns(preg_results.loc[intervention_years[0]: intervention_years[-1]], 'agg') + agg_preg = get_mean_95_CI_from_list(agg_preg_data) + + return {'total_preg': total_pregnancies_per_year, + 'int_preg': total_pregnancies_per_year_int, + 'agg_preg': agg_preg, + 'preg_data_frame': preg_results} + + return {k: extract_pregnancies(results_folders[k]) for k in results_folders} + + +def get_completed_pregnancies_from_multiple_scenarios(comps_df, birth_dict, results_folder): + """Sums the number of pregnancies that have ended in a given year including ectopic pregnancies, + abortions, stillbirths and births""" + + ansb_df = extract_results( + results_folder, + module="tlo.methods.pregnancy_supervisor", + key="antenatal_stillbirth", + custom_generate_series=( + lambda df: df.assign( + year=df['date'].dt.year).groupby(['year'])['year'].count()), + do_scaling=True + ) + + eu = comps_df['pregnancy_supervisor'].loc[(slice(None), 'ectopic_unruptured'), slice(None)] + eu_f = eu.droplevel(1) + + ia = comps_df['pregnancy_supervisor'].loc[(slice(None), 'induced_abortion'), slice(None)] + ia_f = ia.droplevel(1) + + sa = comps_df['pregnancy_supervisor'].loc[(slice(None), 'spontaneous_abortion'), slice(None)] + sa_f = sa.droplevel(1) + + comp_preg_data_frame = eu_f + ia_f + sa_f + ansb_df + birth_dict['births_data_frame'] + + return {'comp_preg_data_frame': comp_preg_data_frame} From ee0dc8c87762d8f070f41fa347c476c106c4866b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 21 May 2025 13:21:27 +0100 Subject: [PATCH 522/755] scenario_wast_min_model: 30K pop; 4 draws (GM scenarios); 10 runs --- .../scenarios/scenario_wasting_minimal_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py index f802bafea0..d973fc9b9b 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_minimal_model.py @@ -42,7 +42,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=4, runs_per_draw=10, ) From 1ee72a95d595f3cf37b00cb4a40ca7d085f1e18c Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 26 May 2025 18:24:35 +0100 Subject: [PATCH 523/755] scenario_analysis_wasting renamed to -> intervention_analysis_wasting --- ...nario_analysis_wasting.py => intervention_analysis_wasting.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/scripts/wasting_analyses/{scenario_analysis_wasting.py => intervention_analysis_wasting.py} (100%) diff --git a/src/scripts/wasting_analyses/scenario_analysis_wasting.py b/src/scripts/wasting_analyses/intervention_analysis_wasting.py similarity index 100% rename from src/scripts/wasting_analyses/scenario_analysis_wasting.py rename to src/scripts/wasting_analyses/intervention_analysis_wasting.py From 8bb22669fe7d7add1d071285619f519681be43d7 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 26 May 2025 18:24:35 +0100 Subject: [PATCH 524/755] run_interventions_analysis_wasting (to run analysis of multiple interventions, under different assumptions, and compare to Status Quo outcomes) --- .../run_interventions_analysis_wasting.py | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 src/scripts/wasting_analyses/run_interventions_analysis_wasting.py diff --git a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py new file mode 100644 index 0000000000..9c186d677f --- /dev/null +++ b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py @@ -0,0 +1,84 @@ +""" +An analysis file for the wasting module to compare outcomes of one intervention under multiple assumptions. +""" +# %% Import statements +import analysis_utility_functions_wast +import glob +import gzip +import os +import shutil +import time +from pathlib import Path + +import numpy as np +import pandas as pd +from matplotlib import pyplot as plt +from PyPDF2 import PdfReader, PdfWriter +from scipy import stats + +from tlo.analysis.utils import compare_number_of_deaths, get_scenario_outputs, parse_log_file + +# start time of the whole analysis +total_time_start = time.time() + +# ####### TO SET ####################################################################################################### +# Create dicts for the intervention scenarios. 'Interv_abbrev': {'Intervention scenario title/abbreviation': draw_nmb} +scenarios_dict = {'GM': {'Status Quo': 0, 'GM_all': 1, 'GM_1-2': 2, 'GM_FullAttend': 3}} +# Set the intervention to be analysed, and for which years they were simulated +intervs_of_interest = ['GM'] +intervention_years = list(range(2026, 2031)) +# Which years to plot (from post burn-in period) +plot_years = list(range(2015, 2031)) +# Plot settings +legend_fontsize = 12 +title_fontsize = 16 + +# Where to find the modelled intervention scenarios +interv_scenarios_folder_path = Path("./outputs/sejjej5@ucl.ac.uk/wasting/scenarios") +# Files names prefix +scenario_filename_prefix = 'wasting_analysis__minimal_model' +# Where to save the outcomes +outputs_path = Path("./outputs/sejjej5@ucl.ac.uk/wasting/scenarios/outcomes") +######################################################################################################################## + +def run_interventions_analysis_wasting(outputspath:Path, plotyears:list, interventionyears:list, + intervs_ofinterest:list) -> None: + """ + This function saves outcomes from analyses conducted for the Janoušková et al. (2025) paper on acute malnutrition. + + The analyses examine the impact of improved screening or treatment coverage. Outcomes from a single intervention, + evaluated under multiple assumptions, are compared with each other and with outcomes from a status quo scenario. + + :param outputspath: path to the directory to save output plots/tables + :param plotyears: the years to be included in the plots/tables + :param interventionyears: the years during which an intervention is implemented (if any) + :param intervs_ofinterest: list of interventions being analysed; + (GM = growth monitoring, CS = care-seeking, FS = food supplements) + """ + + # Find the most recent folders containing results for each intervention of interest + iterv_folders_dict = { + interv: get_scenario_outputs( + scenario_filename_prefix, Path(interv_scenarios_folder_path / interv) + )[-1] for interv in intervs_of_interest + } + # Define folders for each scenario + scenario_folders = { + interv: { + scen_name: Path(iterv_folders_dict[interv] / str(scen_draw_nmb)) + for scen_name, scen_draw_nmb in scenarios_dict[interv].items() + } + for interv in intervs_of_interest + } + + # ---------------------------------------- NEONATAL AND UNDER-5 MORTALITY ---------------------------------------- # + # Extract outcome data + + +# ---------------- # +# RUN THE ANALYSIS # +# ---------------- # +run_interventions_analysis_wasting(outputs_path, plot_years, intervention_years, intervs_of_interest) + +total_time_end = time.time() +print(f"total running time (s): {(total_time_end - total_time_start)}") From b3fa1ae94e0a92ece703cc568c536c869e156748 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 27 May 2025 00:21:38 +0100 Subject: [PATCH 525/755] interv_analysis_wast: runs anlayses nested in draw analysis (to prepare for runs being plotted as the stochasticity range within a draw analysis) --- .../intervention_analysis_wasting.py | 1080 +++++++++-------- 1 file changed, 541 insertions(+), 539 deletions(-) diff --git a/src/scripts/wasting_analyses/intervention_analysis_wasting.py b/src/scripts/wasting_analyses/intervention_analysis_wasting.py index 8b9dfad5e6..0dd4fa50ba 100644 --- a/src/scripts/wasting_analyses/intervention_analysis_wasting.py +++ b/src/scripts/wasting_analyses/intervention_analysis_wasting.py @@ -30,41 +30,40 @@ class WastingScenarioAnalyses: """ - This class looks at plotting all important outcomes from the scenario runs. + This class enables plotting of all important outcomes for a single scenario (i.e. one draw) with each run being + plotted separately. """ def __init__(self, in_scenario_type, sim_results_folder_path_str, in_datestamp, in_draw_nmb, in_png=False): self.outcomes_draw_folder_path_str = sim_results_folder_path_str self.datestamp = in_datestamp self.draw_nmb = in_draw_nmb - self.run_nmb = 0 self.png = in_png, """bool indicating whether we want to save all figures not only as pdf, but also as png""" draw_folder_path = os.path.join(Path(scenario_results_folder_path), str(self.draw_nmb)) - runs_folders = [name for name in os.listdir(draw_folder_path) if \ - os.path.isdir(os.path.join(draw_folder_path, name))] - - for run_nmb in range(0, len(runs_folders)): - print(f"{run_nmb=}") - print("draw analysis continues ...") - - sim_results_folder_draw_x_run_0_path_str = sim_results_folder_path_str + f'/{draw_nmb}/{run_nmb}/' - sim_results_file_name_prefix = scenario_filename - sim_results_file_name_extension = '.log.gz' - gz_results_file_path = \ - Path(glob.glob(os.path.join(sim_results_folder_draw_x_run_0_path_str, - f"{sim_results_file_name_prefix}*{sim_results_file_name_extension}"))[0]) - - # Path to the decompressed .log file - self.__log_file_path = gz_results_file_path.with_suffix('') - # Decompress the .log.gz file - with gzip.open(gz_results_file_path, 'rb') as f_in: - with open(self.__log_file_path, 'wb') as f_out: - shutil.copyfileobj(f_in, f_out) - - # parse wasting logs - self.__w_logs_dict = parse_log_file(self.__log_file_path)['tlo.methods.wasting'] + os.path.isdir(os.path.join(draw_folder_path, name)) and name.isdigit()] + self.total_runs = len(runs_folders) + + self.__w_logs_dict = {} + for run_nmb in range(0, self.total_runs): + print(f"run {run_nmb} ...") + sim_results_folder_draw_run_path_str = sim_results_folder_path_str + f'/{draw_nmb}/{run_nmb}/' + sim_results_file_name_prefix = scenario_filename + sim_results_file_name_extension = '.log.gz' + gz_results_file_path = Path(glob.glob(os.path.join(sim_results_folder_draw_run_path_str, + f"{sim_results_file_name_prefix}*{sim_results_file_name_extension}"))[0]) + + # Path to the decompressed .log file + self.__log_file_path = gz_results_file_path.with_suffix('') + # Decompress the .log.gz file + with gzip.open(gz_results_file_path, 'rb') as f_in: + with open(self.__log_file_path, 'wb') as f_out: + shutil.copyfileobj(f_in, f_out) + + # Parse wasting logs for each run + self.__w_logs_dict[run_nmb] = parse_log_file(self.__log_file_path)['tlo.methods.wasting'] + # TODO: Why it prints the messages from parse_log_file() twice? # parse scaling factor log # self.__scaling_factor = \ @@ -96,9 +95,9 @@ def __init__(self, in_scenario_type, sim_results_folder_path_str, in_datestamp, 'moderate wasting': '#FFA783', } - def save_fig__store_pdf_file(self, fig, fig_output_name: str) -> None: - full_path_and_file_name = self.outcomes_draw_folder_path_str + f'/{self.draw_nmb}/{self.run_nmb}/' + fig_output_name + \ - f'_{self.draw_nmb}_{self.run_nmb}' + def save_fig__store_pdf_file(self, fig, fig_output_name: str, run_nmb) -> None: + full_path_and_file_name = self.outcomes_draw_folder_path_str + f'/{self.draw_nmb}/{run_nmb}/' + fig_output_name + \ + f'_{self.draw_nmb}_{run_nmb}' if self.png: #TODO: doesn't seem to be working fig.savefig(full_path_and_file_name + '.png', format='png') fig.savefig(full_path_and_file_name + '.pdf', format='pdf') @@ -106,83 +105,84 @@ def save_fig__store_pdf_file(self, fig, fig_output_name: str) -> None: def plot_wasting_incidence(self): """ plot the incidence of wasting over time """ - w_inc_df = self.__w_logs_dict['wasting_incidence_count'] - w_inc_df = w_inc_df.set_index(w_inc_df.date.dt.year) - w_inc_df = w_inc_df.drop(columns='date') - # check no incidence of well-nourished - all_zeros = w_inc_df['WHZ>=-2'].apply(lambda x: all(value == 0 for value in x.values())) - assert all(all_zeros) - w_inc_df = w_inc_df[["WHZ<-3", "-3<=WHZ<-2"]] - - pop_sizes_df = self.__w_logs_dict['pop sizes'] - pop_sizes_df = pop_sizes_df.set_index(pop_sizes_df.date.dt.year) - pop_sizes_df = pop_sizes_df.drop(columns='date') - po_sizes_to_keep = [col for col in pop_sizes_df.columns if - col.startswith('total__') and col not in ['total__under5']] - age_gps_total_pop_sizes_df = pop_sizes_df[po_sizes_to_keep].copy() - age_gps_total_pop_sizes_df['0y'] = \ - age_gps_total_pop_sizes_df['total__0_5mo'] + age_gps_total_pop_sizes_df['total__6_11mo'] - age_gps_total_pop_sizes_df = age_gps_total_pop_sizes_df.drop(columns=['total__0_5mo', 'total__6_11mo']) - age_gps_total_pop_sizes_df = age_gps_total_pop_sizes_df.rename(columns={ - 'total__12_23mo': '1y', - 'total__24_35mo': '2y', - 'total__36_47mo': '3y', - 'total__48_59mo': '4y', - 'total__5y+': '5+y' - }) - - # get age_years, doesn't matter what wasting category you choose, - # they all have same age groups - age_years = list(w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys()) - # age_years.remove('5+y') - - _row_counter = 0 - _col_counter = 0 - # plot setup - fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 6)) - axes[1, 2].axis('off') # 5+y has no data (no new cases in 5+y), its space is used to display the label - for age in age_years: - plotting = pd.DataFrame() - for state in w_inc_df.columns: - plotting[state] = \ - w_inc_df.apply(lambda row: row[state][age], axis=1) - # remove sev cases from mod cases (all sev cases went through mod state) - plotting["-3<=WHZ<-2"] = plotting.apply(lambda row: max(row["-3<=WHZ<-2"] - row["WHZ<-3"], 0), axis=1) - # calculate props within the age group - plotting = plotting.div(age_gps_total_pop_sizes_df[age], axis=0) - plotting = plotting.rename(columns=self.__wasting_types_desc) - # filter data to include only years from 2015 onwards - plotting = plotting.loc[plotting.index >= 2015] - # check for invalid values - if (plotting < 0).any().any() or (plotting > 1).any().any(): - print(f"Warning plot_wasting_incidence: Invalid values detected in plotting data for age group {age}:") - print(plotting) - - ax = plotting.plot(kind='bar', stacked=True, - ax=axes[_row_counter, _col_counter], - title=f"{age} old")#, - #ylim=[0, 1]) - show_legend = (_row_counter == 1 and _col_counter == 2) - # show_x_axis_label = (_row_counter == 0 and _col_counter == 2) - if show_legend: - ax.legend(loc='center', fontsize=legend_fontsize) - ax.set_title('') - else: - ax.get_legend().remove() - # if show_x_axis_label: - # ax.set_xlabel('Year') # TODO: this is not working - ax.set_xlabel('year') - ax.set_ylabel('proportion (within age group)') - # move to another row - if _col_counter == 2: - _row_counter += 1 - _col_counter = -1 - _col_counter += 1 # increment column counter - fig.suptitle('Annual incidence of wasting among the age group', fontsize=title_fontsize) #, weight='bold') - fig.tight_layout() - fig_output_name = ('wasting_incidence__' + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name) - # plt.show() + for run_nmb in range(0, self.total_runs): + w_inc_df = self.__w_logs_dict[run_nmb]['wasting_incidence_count'] + w_inc_df = w_inc_df.set_index(w_inc_df.date.dt.year) + w_inc_df = w_inc_df.drop(columns='date') + # check no incidence of well-nourished + all_zeros = w_inc_df['WHZ>=-2'].apply(lambda x: all(value == 0 for value in x.values())) + assert all(all_zeros) + w_inc_df = w_inc_df[["WHZ<-3", "-3<=WHZ<-2"]] + + pop_sizes_df = self.__w_logs_dict[run_nmb]['pop sizes'] + pop_sizes_df = pop_sizes_df.set_index(pop_sizes_df.date.dt.year) + pop_sizes_df = pop_sizes_df.drop(columns='date') + po_sizes_to_keep = [col for col in pop_sizes_df.columns if + col.startswith('total__') and col not in ['total__under5']] + age_gps_total_pop_sizes_df = pop_sizes_df[po_sizes_to_keep].copy() + age_gps_total_pop_sizes_df['0y'] = \ + age_gps_total_pop_sizes_df['total__0_5mo'] + age_gps_total_pop_sizes_df['total__6_11mo'] + age_gps_total_pop_sizes_df = age_gps_total_pop_sizes_df.drop(columns=['total__0_5mo', 'total__6_11mo']) + age_gps_total_pop_sizes_df = age_gps_total_pop_sizes_df.rename(columns={ + 'total__12_23mo': '1y', + 'total__24_35mo': '2y', + 'total__36_47mo': '3y', + 'total__48_59mo': '4y', + 'total__5y+': '5+y' + }) + + # get age_years, doesn't matter what wasting category you choose, + # they all have same age groups + age_years = list(w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys()) + # age_years.remove('5+y') + + _row_counter = 0 + _col_counter = 0 + # plot setup + fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 6)) + axes[1, 2].axis('off') # 5+y has no data (no new cases in 5+y), its space is used to display the label + for age in age_years: + plotting = pd.DataFrame() + for state in w_inc_df.columns: + plotting[state] = \ + w_inc_df.apply(lambda row: row[state][age], axis=1) + # remove sev cases from mod cases (all sev cases went through mod state) + plotting["-3<=WHZ<-2"] = plotting.apply(lambda row: max(row["-3<=WHZ<-2"] - row["WHZ<-3"], 0), axis=1) + # calculate props within the age group + plotting = plotting.div(age_gps_total_pop_sizes_df[age], axis=0) + plotting = plotting.rename(columns=self.__wasting_types_desc) + # filter data to include only years from 2015 onwards + plotting = plotting.loc[plotting.index >= 2015] + # check for invalid values + if (plotting < 0).any().any() or (plotting > 1).any().any(): + print(f"Warning plot_wasting_incidence: Invalid values detected in plotting data for age group {age}:") + print(plotting) + + ax = plotting.plot(kind='bar', stacked=True, + ax=axes[_row_counter, _col_counter], + title=f"{age} old")#, + #ylim=[0, 1]) + show_legend = (_row_counter == 1 and _col_counter == 2) + # show_x_axis_label = (_row_counter == 0 and _col_counter == 2) + if show_legend: + ax.legend(loc='center', fontsize=legend_fontsize) + ax.set_title('') + else: + ax.get_legend().remove() + # if show_x_axis_label: + # ax.set_xlabel('Year') # TODO: this is not working + ax.set_xlabel('year') + ax.set_ylabel('proportion (within age group)') + # move to another row + if _col_counter == 2: + _row_counter += 1 + _col_counter = -1 + _col_counter += 1 # increment column counter + fig.suptitle('Annual incidence of wasting among the age group', fontsize=title_fontsize) #, weight='bold') + fig.tight_layout() + fig_output_name = ('wasting_incidence__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) + # plt.show() # def plot_wasting_incidence_mod_to_sev_props(self): # """ plot the incidence of wasting over time """ @@ -230,7 +230,7 @@ def plot_wasting_incidence(self): # fig.legend(handles, labels, loc='center left', bbox_to_anchor=(1.05, 0.5)) # fig_output_name = ('wasting_incidence_mod_to_sev_props__' + self.datestamp) # fig.tight_layout() - # self.save_fig__store_pdf_file(fig, fig_output_name) + # self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) # # plt.show() def plot_wasting_length(self): @@ -299,339 +299,122 @@ def plot_wasting_length(self): # Adjust layout to make room for the suptitle fig.tight_layout(rect=[0, 0, 1, 0.95]) fig_output_name = ('wasting_length__' + recov_opt + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name) + self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) # plt.show(`) def plot_wasting_initial_overall_prevalence(self): """ plot wasting prevalence of all age groups for the year 2010. Proportions are obtained by getting a total number of children wasted (moderately and severely) divided by the total number of children less than 5 years""" - - ## Prevalence at 2010, ie data from the same source used to draw initial prevalence by age group - w_prev_calib_data_years_only_df = pd.DataFrame({ - 'sev_wast_calib': [0.015], - 'mod_wast_calib': [0.025] - }, index=[2010]) - date_range = pd.Index([2010], name='date') - w_prev_calib = pd.DataFrame(index=date_range) - # filling missing values with 0 - w_prev_calib_df = w_prev_calib.merge( - w_prev_calib_data_years_only_df, left_index=True, right_index=True, how='left' - ).fillna(0) - - ## Initial prevalence at the beginning of 2010 - model - init_w_prev_2010_only_df = self.__w_logs_dict["wasting_init_prevalence_props"] - init_w_prev_2010_only_df = init_w_prev_2010_only_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']].rename( - columns={'total_sev_under5_prop': 'total_init_sev_under5_prop', 'total_mod_under5_prop': 'total_init_mod_under5_prop'} - ) - init_w_prev_2010_only_df = init_w_prev_2010_only_df.set_index(init_w_prev_2010_only_df.date.dt.year) - init_w_prev_2010_only_df = init_w_prev_2010_only_df.drop(columns='date') - init_w_prev_2010_only_df = init_w_prev_2010_only_df.loc[[2010]] - init_w_prev_df = pd.DataFrame(index=date_range) - # filling missing values with 0 - init_w_prev_df = init_w_prev_df.merge( - init_w_prev_2010_only_df, left_index=True, right_index=True, how='left' - ).fillna(0) - - w_prev_calib_and_init_df = pd.merge(init_w_prev_df, w_prev_calib_df, on='date') - columns_to_plot = [ - ['total_init_sev_under5_prop', 'total_init_mod_under5_prop'], - ['sev_wast_calib', 'mod_wast_calib'], - ] - colors_to_plot = { - 'total_init_sev_under5_prop': self.__colors_init_data['severe wasting'], - 'total_init_mod_under5_prop': self.__colors_init_data['moderate wasting'], - 'sev_wast_calib': self.__colors_data['severe wasting'], - 'mod_wast_calib': self.__colors_data['moderate wasting'], - } - labels_to_plot = { - 'total_init_sev_under5_prop': 'severe wasting (initial)', - 'total_init_mod_under5_prop': 'moderate wasting (initial)', - 'sev_wast_calib': 'severe wasting (data)', - 'mod_wast_calib': 'moderate wasting (data)', - } - - fig, ax = plt.subplots() - bar_spots = len(columns_to_plot) - bar_width = 0.3 / bar_spots - pos = np.arange(len(w_prev_calib_and_init_df)) - dodge_offsets = np.linspace(-bar_spots * bar_width / 2, bar_spots * bar_width / 2, bar_spots, endpoint=False) - for columns, offset in zip(columns_to_plot, dodge_offsets): - bottom = 0 - for col in ([columns] if isinstance(columns, str) else columns): - ax.bar(pos + offset, w_prev_calib_and_init_df[col], bottom=bottom, width=bar_width, align='edge', - label=labels_to_plot[col], color=colors_to_plot[col]) - bottom += w_prev_calib_and_init_df[col] - ax.set_xticks(pos) - ax.set_xticklabels(w_prev_calib_and_init_df.index, rotation=90) - ax.set_title(r"Overall wasting prevalence $\bf{at}$ $\bf{initiation}$ (2010)", fontsize=title_fontsize-1) - ax.set_ylabel('proportion of wasted children in the year') - ax.set_xlabel('year') - ax.set_ylim([0, 0.131]) - ax.legend(fontsize=legend_fontsize) - plt.tight_layout() - fig_output_name = ('wasting_initial_overall_prevalence__' + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name) - # plt.show() - - def plot_wasting_initial_prevalence_by_age_group(self): - """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of - children wasted in a particular age-group divided by the total number of children per that age-group""" - - # Initial prevalence at the beginning of 2010 - model - w_prev_df = self.__w_logs_dict["wasting_init_prevalence_props"] - w_prev_df = w_prev_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) - w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) - w_prev_df = w_prev_df.drop(columns='date') - - # 2010 prevalence calibration data - # TODO: load data_2010 from the resource file: - # resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' - data_2010 = { - 'wasted_calib': [7.0, 13.0, 12.7, 2.4, 2.7, 1.9, 0.0], - 'sev_wast_calib': [2.1, 7.1, 4.7, 0.9, 0.7, 0.6, 0.0] - } - data_2010['mod_wast_calib'] = \ - [(w - s)/100 for w, s in zip(data_2010['wasted_calib'], data_2010['sev_wast_calib'])] - data_2010['sev_wast_calib'] = \ - [s/100 for s in data_2010['sev_wast_calib']] - - # Prepare plotting data - plotting_model = {'severe wasting': {}, 'moderate wasting': {}} - for col in w_prev_df.columns: - prefix, age_group = col.split('__') - if prefix == 'sev': - plotting_model['severe wasting'][age_group] = w_prev_df[col].values[0] - elif prefix == 'mod': - plotting_model['moderate wasting'][age_group] = w_prev_df[col].values[0] - plotting_model = pd.DataFrame(plotting_model) - - plotting_calib = {'severe wasting': {}, 'moderate wasting': {}} - age_groups = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] - for i, age_group in enumerate(age_groups): - plotting_calib['severe wasting'][age_group] = data_2010['sev_wast_calib'][i] - plotting_calib['moderate wasting'][age_group] = data_2010['mod_wast_calib'][i] - plotting_calib = pd.DataFrame(plotting_calib) - - plotting_model = plotting_model.reindex(age_groups) - plotting_calib = plotting_calib.reindex(age_groups) - - # Plot wasting prevalence - fig, ax = plt.subplots(figsize=(10, 6)) - bar_width = 0.35 - # Set positions of bars on x-axis - r1 = range(len(plotting_model)) - r2 = [x + bar_width for x in r1] - - # Plot the first set of bars (model data) - ax.bar(r1, plotting_model['severe wasting'], - color=self.__colors_init_data['severe wasting'], width=bar_width, - label='severe wasting (initial)') - ax.bar(r1, plotting_model['moderate wasting'], bottom=plotting_model['severe wasting'], - color=self.__colors_init_data['moderate wasting'], width=bar_width, - label='moderate wasting (initial)') - - # Plot the second set of bars (calibration data) - ax.bar(r2, plotting_calib['severe wasting'], - color=self.__colors_data['severe wasting'], width=bar_width, - label='severe wasting (data)') - ax.bar(r2, plotting_calib['moderate wasting'], bottom=plotting_calib['severe wasting'], - color=self.__colors_data['moderate wasting'], width=bar_width, - label='moderate wasting (data)') - - ax.set_xlabel('age group') - ax.set_ylabel('proportion') - ax.set_title( - r"Wasting prevalence in children 0-59 months per each age group $\bf{at}$ $\bf{initiation}$ (2010)", - fontsize=title_fontsize-1) - ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) - ax.set_xticklabels(age_groups) - ax.set_ylim([0, 0.16]) - ax.legend(fontsize=legend_fontsize) - - # Adjust the layout to make space for the footnote - plt.subplots_adjust(top=0.15) # Adjust the top margin - # Add footnote - fig.figure.text(0.43, 0.95, - "proportion = number of wasted children in the age group " - "/ total number of children in the age group", - ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) - plt.tight_layout() - fig_output_name = ('wasting_initial_prevalence_per_each_age_group__' + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name) - # plt.show() - - def plot_wasting_prevalence_per_year(self): - """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of - children wasted divide by the total number of children less than 5 years""" - - ## Prevalence at some years - data (2010 are the data used to draw initial prevalence) - # TODO: add calibration data into the resource file: - # resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' - # and load here and for initial overall prev from the RF - w_prev_calib_data_years_only_df = pd.DataFrame({ - 'sev_wast_calib': [0.015, 0.011, 0.006, 0.007], - 'mod_wast_calib': [0.025, 0.027, 0.021, 0.019] - }, index=[2010, 2013, 2015, 2019]) - date_range = pd.Index(range(2010, 2031), name='date') - w_prev_calib = pd.DataFrame(index=date_range) - # filling missing values with 0 - w_prev_calib_df = w_prev_calib.merge( - w_prev_calib_data_years_only_df, left_index=True, right_index=True, how='left' - ).fillna(0) - - ## Prevalence at the end of years - model - w_prev_df = self.__w_logs_dict["wasting_prevalence_props"] - w_prev_df = w_prev_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']] - w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) - w_prev_df = w_prev_df.drop(columns='date') - - ## Initial prevalence at the beginning of 2010 - model - init_w_prev_2010_only_df = self.__w_logs_dict["wasting_init_prevalence_props"] - init_w_prev_2010_only_df = init_w_prev_2010_only_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']].rename( - columns={'total_sev_under5_prop': 'total_init_sev_under5_prop', 'total_mod_under5_prop': 'total_init_mod_under5_prop'} - ) - init_w_prev_2010_only_df = init_w_prev_2010_only_df.set_index(init_w_prev_2010_only_df.date.dt.year) - init_w_prev_2010_only_df = init_w_prev_2010_only_df.drop(columns='date') - init_w_prev_2010_only_df = init_w_prev_2010_only_df.loc[[2010]] - init_w_prev_df = pd.DataFrame(index=date_range) - # filling missing values with 0 - init_w_prev_df = init_w_prev_df.merge( - init_w_prev_2010_only_df, left_index=True, right_index=True, how='left' - ).fillna(0) - - w_prev_calib_and_init_df = pd.merge(init_w_prev_df, w_prev_calib_df, on='date') - w_prev_plot_df = pd.merge(w_prev_df, w_prev_calib_and_init_df, on='date').loc[lambda df: df.index >= 2015] - columns_to_plot = [ - ['total_init_sev_under5_prop', 'total_init_mod_under5_prop'], - ['total_sev_under5_prop', 'total_mod_under5_prop'], - ['sev_wast_calib', 'mod_wast_calib'], + for run_nmb in range(0, self.total_runs): + ## Prevalence at 2010, ie data from the same source used to draw initial prevalence by age group + w_prev_calib_data_years_only_df = pd.DataFrame({ + 'sev_wast_calib': [0.015], + 'mod_wast_calib': [0.025] + }, index=[2010]) + date_range = pd.Index([2010], name='date') + w_prev_calib = pd.DataFrame(index=date_range) + # filling missing values with 0 + w_prev_calib_df = w_prev_calib.merge( + w_prev_calib_data_years_only_df, left_index=True, right_index=True, how='left' + ).fillna(0) + + ## Initial prevalence at the beginning of 2010 - model + init_w_prev_2010_only_df = self.__w_logs_dict[run_nmb]["wasting_init_prevalence_props"] + init_w_prev_2010_only_df = init_w_prev_2010_only_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']].rename( + columns={'total_sev_under5_prop': 'total_init_sev_under5_prop', 'total_mod_under5_prop': 'total_init_mod_under5_prop'} + ) + init_w_prev_2010_only_df = init_w_prev_2010_only_df.set_index(init_w_prev_2010_only_df.date.dt.year) + init_w_prev_2010_only_df = init_w_prev_2010_only_df.drop(columns='date') + init_w_prev_2010_only_df = init_w_prev_2010_only_df.loc[[2010]] + init_w_prev_df = pd.DataFrame(index=date_range) + # filling missing values with 0 + init_w_prev_df = init_w_prev_df.merge( + init_w_prev_2010_only_df, left_index=True, right_index=True, how='left' + ).fillna(0) + + w_prev_calib_and_init_df = pd.merge(init_w_prev_df, w_prev_calib_df, on='date') + columns_to_plot = [ + ['total_init_sev_under5_prop', 'total_init_mod_under5_prop'], + ['sev_wast_calib', 'mod_wast_calib'], ] - colors_to_plot = { - 'total_sev_under5_prop': self.__colors_model['severe wasting'], - 'total_mod_under5_prop': self.__colors_model['moderate wasting'], - 'sev_wast_calib': self.__colors_data['severe wasting'], - 'mod_wast_calib': self.__colors_data['moderate wasting'], - 'total_init_sev_under5_prop': self.__colors_init_data['severe wasting'], - 'total_init_mod_under5_prop': self.__colors_init_data['moderate wasting'] - - } - labels_to_plot = { - 'total_sev_under5_prop': 'severe wasting (model)', - 'total_mod_under5_prop': 'moderate wasting (model)', - 'sev_wast_calib': 'severe wasting (data)', - 'mod_wast_calib': 'moderate wasting (data)', - 'total_init_sev_under5_prop': 'severe wasting (initial)', - 'total_init_mod_under5_prop': 'moderate wasting (initial)' - } - - fig, ax = plt.subplots() - bar_spots = len(columns_to_plot) - bar_width = 0.8 / bar_spots - pos = np.arange(len(w_prev_plot_df)) - dodge_offsets = np.linspace(-bar_spots * bar_width / 2, bar_spots * bar_width / 2, bar_spots, endpoint=False) - for columns, offset in zip(columns_to_plot, dodge_offsets): - bottom = 0 - for col in ([columns] if isinstance(columns, str) else columns): - ax.bar(pos + offset, w_prev_plot_df[col], bottom=bottom, width=bar_width, align='edge', - label=labels_to_plot[col], color=colors_to_plot[col]) - bottom += w_prev_plot_df[col] - ax.set_xticks(pos) - ax.set_xticklabels(w_prev_plot_df.index, rotation=90) - ax.set_title("Wasting prevalence in children 0-59 months per year", fontsize=title_fontsize-6) - ax.set_ylabel('proportion of wasted children in the year') - ax.set_xlabel('year') - ax.set_ylim([0, 0.06]) - ax.legend(fontsize=legend_fontsize-4) - plt.tight_layout() - fig_output_name = ('wasting_prevalence_per_year__' + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name) - # plt.show() + colors_to_plot = { + 'total_init_sev_under5_prop': self.__colors_init_data['severe wasting'], + 'total_init_mod_under5_prop': self.__colors_init_data['moderate wasting'], + 'sev_wast_calib': self.__colors_data['severe wasting'], + 'mod_wast_calib': self.__colors_data['moderate wasting'], + } + labels_to_plot = { + 'total_init_sev_under5_prop': 'severe wasting (initial)', + 'total_init_mod_under5_prop': 'moderate wasting (initial)', + 'sev_wast_calib': 'severe wasting (data)', + 'mod_wast_calib': 'moderate wasting (data)', + } + + fig, ax = plt.subplots() + bar_spots = len(columns_to_plot) + bar_width = 0.3 / bar_spots + pos = np.arange(len(w_prev_calib_and_init_df)) + dodge_offsets = np.linspace(-bar_spots * bar_width / 2, bar_spots * bar_width / 2, bar_spots, endpoint=False) + for columns, offset in zip(columns_to_plot, dodge_offsets): + bottom = 0 + for col in ([columns] if isinstance(columns, str) else columns): + ax.bar(pos + offset, w_prev_calib_and_init_df[col], bottom=bottom, width=bar_width, align='edge', + label=labels_to_plot[col], color=colors_to_plot[col]) + bottom += w_prev_calib_and_init_df[col] + ax.set_xticks(pos) + ax.set_xticklabels(w_prev_calib_and_init_df.index, rotation=90) + ax.set_title(r"Overall wasting prevalence $\bf{at}$ $\bf{initiation}$ (2010)", fontsize=title_fontsize-1) + ax.set_ylabel('proportion of wasted children in the year') + ax.set_xlabel('year') + ax.set_ylim([0, 0.131]) + ax.legend(fontsize=legend_fontsize) + plt.tight_layout() + fig_output_name = ('wasting_initial_overall_prevalence__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) + # plt.show() - def plot_wasting_prevalence_by_age_group(self): + def plot_wasting_initial_prevalence_by_age_group(self): """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of children wasted in a particular age-group divided by the total number of children per that age-group""" + for run_nmb in range(0, self.total_runs): + # Initial prevalence at the beginning of 2010 - model + w_prev_df = self.__w_logs_dict[run_nmb]["wasting_init_prevalence_props"] + w_prev_df = w_prev_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) + w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) + w_prev_df = w_prev_df.drop(columns='date') + + # 2010 prevalence calibration data + # TODO: load data_2010 from the resource file: + # resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' + data_2010 = { + 'wasted_calib': [7.0, 13.0, 12.7, 2.4, 2.7, 1.9, 0.0], + 'sev_wast_calib': [2.1, 7.1, 4.7, 0.9, 0.7, 0.6, 0.0] + } + data_2010['mod_wast_calib'] = \ + [(w - s)/100 for w, s in zip(data_2010['wasted_calib'], data_2010['sev_wast_calib'])] + data_2010['sev_wast_calib'] = \ + [s/100 for s in data_2010['sev_wast_calib']] + + # Prepare plotting data + plotting_model = {'severe wasting': {}, 'moderate wasting': {}} + for col in w_prev_df.columns: + prefix, age_group = col.split('__') + if prefix == 'sev': + plotting_model['severe wasting'][age_group] = w_prev_df[col].values[0] + elif prefix == 'mod': + plotting_model['moderate wasting'][age_group] = w_prev_df[col].values[0] + plotting_model = pd.DataFrame(plotting_model) + + plotting_calib = {'severe wasting': {}, 'moderate wasting': {}} + age_groups = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] + for i, age_group in enumerate(age_groups): + plotting_calib['severe wasting'][age_group] = data_2010['sev_wast_calib'][i] + plotting_calib['moderate wasting'][age_group] = data_2010['mod_wast_calib'][i] + plotting_calib = pd.DataFrame(plotting_calib) + + plotting_model = plotting_model.reindex(age_groups) + plotting_calib = plotting_calib.reindex(age_groups) - age_groups = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] - - # ### Calibration Data - # Load calibration data from CSV file - wasting_calib_data_path = resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' - wasting_calib_data_df = pd.read_csv(wasting_calib_data_path, index_col='year') - - # Recalculate data to proportions (0 to 1) and separate mod wast as (wasted - sev wast) - wasting_calib_data_df['mod_wast_calib'] = \ - (wasting_calib_data_df['prev any wast (%)'] - wasting_calib_data_df['prev severe wast (%)']) / 100 - wasting_calib_data_df['sev_wast_calib'] = wasting_calib_data_df['prev severe wast (%)'] / 100 - - # Pivot the data to get the required format - w_prev_calib_data_df = wasting_calib_data_df.pivot(columns='age_group (months)', - values=['mod_wast_calib', 'sev_wast_calib']) - w_prev_calib_data_df.columns = [f'{col[0][:3]}__{col[1]}' for col in w_prev_calib_data_df.columns] - - # Load calibration sample sizes from CSV file - sample_sizes_calib_data_df = wasting_calib_data_df.pivot(columns='age_group (months)', values='sample_size') - sample_sizes_calib_data_df = sample_sizes_calib_data_df.reindex(columns=age_groups) - - # ### Model Outcomes - # Load modelled prevalence proportions - w_prev_model_df = self.__w_logs_dict["wasting_prevalence_props"] - w_prev_model_df = w_prev_model_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) - w_prev_model_df = w_prev_model_df.set_index(w_prev_model_df.date.dt.year) - w_prev_model_df = w_prev_model_df.drop(columns='date') - - # Load modelled population sizes - pop_sizes_model_df = self.__w_logs_dict['pop sizes'] - pop_sizes_model_df = pop_sizes_model_df.set_index(pop_sizes_model_df.date.dt.year).rename_axis('year') - pop_sizes_model_df = pop_sizes_model_df.drop(columns='date') - pop_sizes_model_df = pop_sizes_model_df.filter(like='total__').rename( - lambda x: x.replace('total__', ''), axis=1 - )[age_groups] - - for year_calib in w_prev_calib_data_df.index: - w_prev_calib_data_year_df = w_prev_calib_data_df.loc[w_prev_calib_data_df.index == year_calib] - w_prev_model_year_df = w_prev_model_df.loc[w_prev_model_df.index == year_calib] - - def create_plotting_data(df, df_name): - plotting = {'severe wasting': {}, 'moderate wasting': {}, 'any wasting': {}} - for col in df.columns: - prefix, agegp = col.split('__') - if prefix == 'sev': - plotting['severe wasting'][agegp] = df[col].values[0] - elif prefix == 'mod': - plotting['moderate wasting'][agegp] = df[col].values[0] - plotting['any wasting'][agegp] = df[col].values[0] + df[f'sev__{agegp}'].values[0] - plotting_df = pd.DataFrame(plotting) - assert set(plotting_df.index) == set(age_groups),\ - f"age groups in {df_name} are not in line with the age_groups." - plotting_df = plotting_df.reindex(age_groups) - return plotting_df - - # Create plotting data for both dataframes - plotting_model = create_plotting_data(w_prev_model_year_df, 'w_prev_model_year_df') - plotting_calib = create_plotting_data(w_prev_calib_data_year_df, 'w_prev_calib_data_year_df') - - # Calculate 95% confidence intervals for both - sample_sizes_calib_data_year = sample_sizes_calib_data_df.loc[year_calib, :] - sample_sizes_model_year = pop_sizes_model_df.loc[year_calib, :] - - confidence_level = 0.95 - z_score = stats.norm.ppf(1 - (1 - confidence_level) / 2) - - calib_data_margin_of_error_any_wast = [] - calib_data_margin_of_error_sev_wast = [] - for p, n in zip(plotting_calib['any wasting'].reindex(age_groups[:-1]), sample_sizes_calib_data_year[:-1]): - calib_data_margin_of_error_any_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) - for p, n in \ - zip(plotting_calib['severe wasting'].reindex(age_groups[:-1]),sample_sizes_calib_data_year[:-1]): - calib_data_margin_of_error_sev_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) - model_margin_of_error_any_wast = [] - model_margin_of_error_sev_wast = [] - for p, n in zip(plotting_model['any wasting'].reindex(age_groups[:-1]), sample_sizes_model_year[:-1]): - model_margin_of_error_any_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) - for p, n in zip(plotting_model['severe wasting'].reindex(age_groups[:-1]), sample_sizes_model_year[:-1]): - model_margin_of_error_sev_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) - - # ##### # Plot wasting prevalence fig, ax = plt.subplots(figsize=(10, 6)) bar_width = 0.35 @@ -641,20 +424,11 @@ def create_plotting_data(df, df_name): # Plot the first set of bars (model data) ax.bar(r1, plotting_model['severe wasting'], - color=self.__colors_model['severe wasting'], width=bar_width, - label='severe wasting (model)') + color=self.__colors_init_data['severe wasting'], width=bar_width, + label='severe wasting (initial)') ax.bar(r1, plotting_model['moderate wasting'], bottom=plotting_model['severe wasting'], - color=self.__colors_model['moderate wasting'], width=bar_width, - label='moderate wasting (model)') - - # Add the confidence intervals - for i, age_group in enumerate(age_groups[0:len(age_groups)-1]): - ax.errorbar(r1[i], plotting_model['any wasting'][age_group], - yerr=[model_margin_of_error_any_wast[i]], - capsize=5, fmt='none', color='black') - ax.errorbar(r1[i], plotting_model['severe wasting'][age_group], - yerr=[model_margin_of_error_sev_wast[i]], - capsize=5, fmt='none', color='white') + color=self.__colors_init_data['moderate wasting'], width=bar_width, + label='moderate wasting (initial)') # Plot the second set of bars (calibration data) ax.bar(r2, plotting_calib['severe wasting'], @@ -664,126 +438,354 @@ def create_plotting_data(df, df_name): color=self.__colors_data['moderate wasting'], width=bar_width, label='moderate wasting (data)') - # Add the confidence intervals - for i, age_group in enumerate(age_groups[0:len(age_groups)-1]): - ax.errorbar(r2[i], plotting_calib['any wasting'][age_group], - yerr=[calib_data_margin_of_error_any_wast[i]], - capsize=5, fmt='none', color='black') - ax.errorbar(r2[i], plotting_calib['severe wasting'][age_group], - yerr=[calib_data_margin_of_error_sev_wast[i]], - capsize=5, fmt='none', color='white') - ax.set_xlabel('age group') ax.set_ylabel('proportion') - ax.set_title(f"Wasting prevalence in children 0-59 months per each age group in {year_calib}", - fontsize=title_fontsize-1) + ax.set_title( + r"Wasting prevalence in children 0-59 months per each age group $\bf{at}$ $\bf{initiation}$ (2010)", + fontsize=title_fontsize-1) ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) ax.set_xticklabels(age_groups) - ax.set_ylim([0, 0.12]) + ax.set_ylim([0, 0.16]) ax.legend(fontsize=legend_fontsize) # Adjust the layout to make space for the footnote - plt.subplots_adjust(top=0.15) # Adjust the bottom margin + plt.subplots_adjust(top=0.15) # Adjust the top margin # Add footnote fig.figure.text(0.43, 0.95, "proportion = number of wasted children in the age group " "/ total number of children in the age group", ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) + plt.tight_layout() + fig_output_name = ('wasting_initial_prevalence_per_each_age_group__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) + # plt.show() + def plot_wasting_prevalence_per_year(self): + """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of + children wasted divide by the total number of children less than 5 years""" + for run_nmb in range(0, self.total_runs): + ## Prevalence at some years - data (2010 are the data used to draw initial prevalence) + # TODO: add calibration data into the resource file: + # resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' + # and load here and for initial overall prev from the RF + w_prev_calib_data_years_only_df = pd.DataFrame({ + 'sev_wast_calib': [0.015, 0.011, 0.006, 0.007], + 'mod_wast_calib': [0.025, 0.027, 0.021, 0.019] + }, index=[2010, 2013, 2015, 2019]) + date_range = pd.Index(range(2010, 2031), name='date') + w_prev_calib = pd.DataFrame(index=date_range) + # filling missing values with 0 + w_prev_calib_df = w_prev_calib.merge( + w_prev_calib_data_years_only_df, left_index=True, right_index=True, how='left' + ).fillna(0) + + ## Prevalence at the end of years - model + w_prev_df = self.__w_logs_dict[run_nmb]["wasting_prevalence_props"] + w_prev_df = w_prev_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']] + w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) + w_prev_df = w_prev_df.drop(columns='date') + + ## Initial prevalence at the beginning of 2010 - model + init_w_prev_2010_only_df = self.__w_logs_dict[run_nmb]["wasting_init_prevalence_props"] + init_w_prev_2010_only_df = init_w_prev_2010_only_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']].rename( + columns={'total_sev_under5_prop': 'total_init_sev_under5_prop', 'total_mod_under5_prop': 'total_init_mod_under5_prop'} + ) + init_w_prev_2010_only_df = init_w_prev_2010_only_df.set_index(init_w_prev_2010_only_df.date.dt.year) + init_w_prev_2010_only_df = init_w_prev_2010_only_df.drop(columns='date') + init_w_prev_2010_only_df = init_w_prev_2010_only_df.loc[[2010]] + init_w_prev_df = pd.DataFrame(index=date_range) + # filling missing values with 0 + init_w_prev_df = init_w_prev_df.merge( + init_w_prev_2010_only_df, left_index=True, right_index=True, how='left' + ).fillna(0) + + w_prev_calib_and_init_df = pd.merge(init_w_prev_df, w_prev_calib_df, on='date') + w_prev_plot_df = pd.merge(w_prev_df, w_prev_calib_and_init_df, on='date').loc[lambda df: df.index >= 2015] + columns_to_plot = [ + ['total_init_sev_under5_prop', 'total_init_mod_under5_prop'], + ['total_sev_under5_prop', 'total_mod_under5_prop'], + ['sev_wast_calib', 'mod_wast_calib'], + ] + colors_to_plot = { + 'total_sev_under5_prop': self.__colors_model['severe wasting'], + 'total_mod_under5_prop': self.__colors_model['moderate wasting'], + 'sev_wast_calib': self.__colors_data['severe wasting'], + 'mod_wast_calib': self.__colors_data['moderate wasting'], + 'total_init_sev_under5_prop': self.__colors_init_data['severe wasting'], + 'total_init_mod_under5_prop': self.__colors_init_data['moderate wasting'] + + } + labels_to_plot = { + 'total_sev_under5_prop': 'severe wasting (model)', + 'total_mod_under5_prop': 'moderate wasting (model)', + 'sev_wast_calib': 'severe wasting (data)', + 'mod_wast_calib': 'moderate wasting (data)', + 'total_init_sev_under5_prop': 'severe wasting (initial)', + 'total_init_mod_under5_prop': 'moderate wasting (initial)' + } + + fig, ax = plt.subplots() + bar_spots = len(columns_to_plot) + bar_width = 0.8 / bar_spots + pos = np.arange(len(w_prev_plot_df)) + dodge_offsets = np.linspace(-bar_spots * bar_width / 2, bar_spots * bar_width / 2, bar_spots, endpoint=False) + for columns, offset in zip(columns_to_plot, dodge_offsets): + bottom = 0 + for col in ([columns] if isinstance(columns, str) else columns): + ax.bar(pos + offset, w_prev_plot_df[col], bottom=bottom, width=bar_width, align='edge', + label=labels_to_plot[col], color=colors_to_plot[col]) + bottom += w_prev_plot_df[col] + ax.set_xticks(pos) + ax.set_xticklabels(w_prev_plot_df.index, rotation=90) + ax.set_title("Wasting prevalence in children 0-59 months per year", fontsize=title_fontsize-6) + ax.set_ylabel('proportion of wasted children in the year') + ax.set_xlabel('year') + ax.set_ylim([0, 0.06]) + ax.legend(fontsize=legend_fontsize-4) plt.tight_layout() - fig_output_name = (f'wasting_prevalence_per_each_age_group_{year_calib}__' + self.datestamp) - if year_calib in [2015, 2019]: - self.save_fig__store_pdf_file(fig, fig_output_name) + fig_output_name = ('wasting_prevalence_per_year__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) # plt.show() + def plot_wasting_prevalence_by_age_group(self): + """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of + children wasted in a particular age-group divided by the total number of children per that age-group""" + for run_nmb in range(0, self.total_runs): + age_groups = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] + + # ### Calibration Data + # Load calibration data from CSV file + wasting_calib_data_path = resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' + wasting_calib_data_df = pd.read_csv(wasting_calib_data_path, index_col='year') + + # Recalculate data to proportions (0 to 1) and separate mod wast as (wasted - sev wast) + wasting_calib_data_df['mod_wast_calib'] = \ + (wasting_calib_data_df['prev any wast (%)'] - wasting_calib_data_df['prev severe wast (%)']) / 100 + wasting_calib_data_df['sev_wast_calib'] = wasting_calib_data_df['prev severe wast (%)'] / 100 + + # Pivot the data to get the required format + w_prev_calib_data_df = wasting_calib_data_df.pivot(columns='age_group (months)', + values=['mod_wast_calib', 'sev_wast_calib']) + w_prev_calib_data_df.columns = [f'{col[0][:3]}__{col[1]}' for col in w_prev_calib_data_df.columns] + + # Load calibration sample sizes from CSV file + sample_sizes_calib_data_df = wasting_calib_data_df.pivot(columns='age_group (months)', values='sample_size') + sample_sizes_calib_data_df = sample_sizes_calib_data_df.reindex(columns=age_groups) + + # ### Model Outcomes + # Load modelled prevalence proportions + w_prev_model_df = self.__w_logs_dict[run_nmb]["wasting_prevalence_props"] + w_prev_model_df = w_prev_model_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) + w_prev_model_df = w_prev_model_df.set_index(w_prev_model_df.date.dt.year) + w_prev_model_df = w_prev_model_df.drop(columns='date') + + # Load modelled population sizes + pop_sizes_model_df = self.__w_logs_dict[run_nmb]['pop sizes'] + pop_sizes_model_df = pop_sizes_model_df.set_index(pop_sizes_model_df.date.dt.year).rename_axis('year') + pop_sizes_model_df = pop_sizes_model_df.drop(columns='date') + pop_sizes_model_df = pop_sizes_model_df.filter(like='total__').rename( + lambda x: x.replace('total__', ''), axis=1 + )[age_groups] + + for year_calib in w_prev_calib_data_df.index: + w_prev_calib_data_year_df = w_prev_calib_data_df.loc[w_prev_calib_data_df.index == year_calib] + w_prev_model_year_df = w_prev_model_df.loc[w_prev_model_df.index == year_calib] + + def create_plotting_data(df, df_name): + plotting = {'severe wasting': {}, 'moderate wasting': {}, 'any wasting': {}} + for col in df.columns: + prefix, agegp = col.split('__') + if prefix == 'sev': + plotting['severe wasting'][agegp] = df[col].values[0] + elif prefix == 'mod': + plotting['moderate wasting'][agegp] = df[col].values[0] + plotting['any wasting'][agegp] = df[col].values[0] + df[f'sev__{agegp}'].values[0] + plotting_df = pd.DataFrame(plotting) + assert set(plotting_df.index) == set(age_groups),\ + f"age groups in {df_name} are not in line with the age_groups." + plotting_df = plotting_df.reindex(age_groups) + return plotting_df + + # Create plotting data for both dataframes + plotting_model = create_plotting_data(w_prev_model_year_df, 'w_prev_model_year_df') + plotting_calib = create_plotting_data(w_prev_calib_data_year_df, 'w_prev_calib_data_year_df') + + # Calculate 95% confidence intervals for both + sample_sizes_calib_data_year = sample_sizes_calib_data_df.loc[year_calib, :] + sample_sizes_model_year = pop_sizes_model_df.loc[year_calib, :] + + confidence_level = 0.95 + z_score = stats.norm.ppf(1 - (1 - confidence_level) / 2) + + calib_data_margin_of_error_any_wast = [] + calib_data_margin_of_error_sev_wast = [] + for p, n in zip(plotting_calib['any wasting'].reindex(age_groups[:-1]), sample_sizes_calib_data_year[:-1]): + calib_data_margin_of_error_any_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) + for p, n in \ + zip(plotting_calib['severe wasting'].reindex(age_groups[:-1]),sample_sizes_calib_data_year[:-1]): + calib_data_margin_of_error_sev_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) + model_margin_of_error_any_wast = [] + model_margin_of_error_sev_wast = [] + for p, n in zip(plotting_model['any wasting'].reindex(age_groups[:-1]), sample_sizes_model_year[:-1]): + model_margin_of_error_any_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) + for p, n in zip(plotting_model['severe wasting'].reindex(age_groups[:-1]), sample_sizes_model_year[:-1]): + model_margin_of_error_sev_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) + + # ##### + # Plot wasting prevalence + fig, ax = plt.subplots(figsize=(10, 6)) + bar_width = 0.35 + # Set positions of bars on x-axis + r1 = range(len(plotting_model)) + r2 = [x + bar_width for x in r1] + + # Plot the first set of bars (model data) + ax.bar(r1, plotting_model['severe wasting'], + color=self.__colors_model['severe wasting'], width=bar_width, + label='severe wasting (model)') + ax.bar(r1, plotting_model['moderate wasting'], bottom=plotting_model['severe wasting'], + color=self.__colors_model['moderate wasting'], width=bar_width, + label='moderate wasting (model)') + + # Add the confidence intervals + for i, age_group in enumerate(age_groups[0:len(age_groups)-1]): + ax.errorbar(r1[i], plotting_model['any wasting'][age_group], + yerr=[model_margin_of_error_any_wast[i]], + capsize=5, fmt='none', color='black') + ax.errorbar(r1[i], plotting_model['severe wasting'][age_group], + yerr=[model_margin_of_error_sev_wast[i]], + capsize=5, fmt='none', color='white') + + # Plot the second set of bars (calibration data) + ax.bar(r2, plotting_calib['severe wasting'], + color=self.__colors_data['severe wasting'], width=bar_width, + label='severe wasting (data)') + ax.bar(r2, plotting_calib['moderate wasting'], bottom=plotting_calib['severe wasting'], + color=self.__colors_data['moderate wasting'], width=bar_width, + label='moderate wasting (data)') + + # Add the confidence intervals + for i, age_group in enumerate(age_groups[0:len(age_groups)-1]): + ax.errorbar(r2[i], plotting_calib['any wasting'][age_group], + yerr=[calib_data_margin_of_error_any_wast[i]], + capsize=5, fmt='none', color='black') + ax.errorbar(r2[i], plotting_calib['severe wasting'][age_group], + yerr=[calib_data_margin_of_error_sev_wast[i]], + capsize=5, fmt='none', color='white') + + ax.set_xlabel('age group') + ax.set_ylabel('proportion') + ax.set_title(f"Wasting prevalence in children 0-59 months per each age group in {year_calib}", + fontsize=title_fontsize-1) + ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) + ax.set_xticklabels(age_groups) + ax.set_ylim([0, 0.12]) + ax.legend(fontsize=legend_fontsize) + + # Adjust the layout to make space for the footnote + plt.subplots_adjust(top=0.15) # Adjust the bottom margin + # Add footnote + fig.figure.text(0.43, 0.95, + "proportion = number of wasted children in the age group " + "/ total number of children in the age group", + ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) + + plt.tight_layout() + fig_output_name = (f'wasting_prevalence_per_each_age_group_{year_calib}__' + self.datestamp) + if year_calib in [2015, 2019]: + self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) + # plt.show() + def plot_model_gbd_deaths_incl_burnin_period(self): """ compare model and GBD deaths 2010-2014 & 2015-2019 """ - death_compare = \ - compare_number_of_deaths(self.__log_file_path, resources_path) - fig, ax = plt.subplots(figsize=(10, 6)) - # cause of death as of GBD 2019 'Protein-energy malnutrition' was labeled as 'Childhood Undernutrition' in - # wasting module - plot_df = death_compare.loc[(['2010-2014', '2015-2019'], - slice(None), ['0-4'], 'Childhood Undernutrition' - )].groupby('period').sum() - plotting = plot_df.loc[['2010-2014', '2015-2019']] - ax = plotting['model'].plot.bar(label='Model', ax=ax, rot=0) - ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, - yerr=[plotting.GBD_lower, plotting.GBD_upper], - fmt='o', color='#000', label="GBD") - - ax.set_title('Average direct deaths per year due to severe acute malnutrition in children under 5', fontsize=title_fontsize-1) - ax.set_xlabel("time period") - ax.set_ylabel("number of deaths") - ax.legend(loc='upper center', fontsize=legend_fontsize) - fig.tight_layout() - # Adjust the layout to make space for the footnote - plt.subplots_adjust(bottom=0.15) # Adjust the bottom margin - # Add footnote - fig.figure.text(0.5, 0.02, - "Model output against Global Burden of Diseases (GBD) study data", - ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) - fig_output_name = ('model_gbd_deaths_incl_burnin__' + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name) - # plt.show() + for run_nmb in range(0, self.total_runs): + death_compare = \ + compare_number_of_deaths(self.__log_file_path, resources_path) + fig, ax = plt.subplots(figsize=(10, 6)) + # cause of death as of GBD 2019 'Protein-energy malnutrition' was labeled as 'Childhood Undernutrition' in + # wasting module + plot_df = death_compare.loc[(['2010-2014', '2015-2019'], + slice(None), ['0-4'], 'Childhood Undernutrition' + )].groupby('period').sum() + plotting = plot_df.loc[['2010-2014', '2015-2019']] + ax = plotting['model'].plot.bar(label='Model', ax=ax, rot=0) + ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, + yerr=[plotting.GBD_lower, plotting.GBD_upper], + fmt='o', color='#000', label="GBD") + + ax.set_title('Average direct deaths per year due to severe acute malnutrition in children under 5', fontsize=title_fontsize-1) + ax.set_xlabel("time period") + ax.set_ylabel("number of deaths") + ax.legend(loc='upper center', fontsize=legend_fontsize) + fig.tight_layout() + # Adjust the layout to make space for the footnote + plt.subplots_adjust(bottom=0.15) # Adjust the bottom margin + # Add footnote + fig.figure.text(0.5, 0.02, + "Model output against Global Burden of Diseases (GBD) study data", + ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) + fig_output_name = ('model_gbd_deaths_incl_burnin__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) + # plt.show() def plot_model_gbd_deaths_excl_burnin_period(self): """ compare model and GBD deaths 2015-2019 """ - death_compare = \ - compare_number_of_deaths(self.__log_file_path, resources_path) - fig, ax = plt.subplots(figsize=(10, 6)) - # cause of death as of GBD 2019 'Protein-energy malnutrition' was labeled as 'Childhood Undernutrition' in - # wasting module - plot_df = death_compare.loc[(['2015-2019'], - slice(None), ['0-4'], 'Childhood Undernutrition' - )].groupby('period').sum() - plotting = plot_df.loc[['2015-2019']] - ax = plotting['model'].plot.bar(label='Model', ax=ax, rot=0) - ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, - yerr=[plotting.GBD_lower, plotting.GBD_upper], - fmt='o', color='#000', label="GBD") - - ax.set_title('Average direct deaths per year due to severe acute malnutrition in children under 5', - fontsize=title_fontsize - 1) - ax.set_xlabel("time period") - ax.set_ylabel("number of deaths") - ax.legend(loc='upper right', fontsize=legend_fontsize) - fig.tight_layout() - # Adjust the layout to make space for the footnote - plt.subplots_adjust(bottom=0.15) # Adjust the bottom margin - # Add footnote - fig.figure.text(0.5, 0.02, - "Model output against Global Burden of Diseases (GBD) study data", - ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) - fig_output_name = ('model_gbd_deaths_excl_burnin__' + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name) - # plt.show() + for run_nmb in range(0, self.total_runs): + death_compare = \ + compare_number_of_deaths(self.__log_file_path, resources_path) + fig, ax = plt.subplots(figsize=(10, 6)) + # cause of death as of GBD 2019 'Protein-energy malnutrition' was labeled as 'Childhood Undernutrition' in + # wasting module + plot_df = death_compare.loc[(['2015-2019'], + slice(None), ['0-4'], 'Childhood Undernutrition' + )].groupby('period').sum() + plotting = plot_df.loc[['2015-2019']] + ax = plotting['model'].plot.bar(label='Model', ax=ax, rot=0) + ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, + yerr=[plotting.GBD_lower, plotting.GBD_upper], + fmt='o', color='#000', label="GBD") + + ax.set_title('Average direct deaths per year due to severe acute malnutrition in children under 5', + fontsize=title_fontsize - 1) + ax.set_xlabel("time period") + ax.set_ylabel("number of deaths") + ax.legend(loc='upper right', fontsize=legend_fontsize) + fig.tight_layout() + # Adjust the layout to make space for the footnote + plt.subplots_adjust(bottom=0.15) # Adjust the bottom margin + # Add footnote + fig.figure.text(0.5, 0.02, + "Model output against Global Burden of Diseases (GBD) study data", + ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) + fig_output_name = ('model_gbd_deaths_excl_burnin__' + self.datestamp) + self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) + # plt.show() def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): - - output_file_path = \ - in_outcome_figs_folder / f'wasting_all_figures__{self.datestamp}_{self.draw_nmb}_{self.run_nmb}.pdf' - # Remove the existing output file if it exists to ensure a clean start - if os.path.exists(output_file_path): - os.remove(output_file_path) - - # Assert that the file doesn't exist anymore after removal - assert not os.path.exists(output_file_path), "The file was not successfully removed." - - # Merge the PDF files - # Create a PDF writer object - pdf_writer = PdfWriter() - - # Iterate through the figure files and add each to the writer - for fig_file in self.fig_files: - pdf_reader = PdfReader(fig_file) - for page_num in range(len(pdf_reader.pages)): - page = pdf_reader.pages[page_num] - pdf_writer.add_page(page) - - # Write the merged PDF to a file - with open(output_file_path, 'wb') as out_file: - pdf_writer.write(out_file) + for run_nmb in range(0, self.total_runs): + output_file_path = \ + in_outcome_figs_folder / f'wasting_all_figures__{self.datestamp}_{self.draw_nmb}_{run_nmb}.pdf' + # Remove the existing output file if it exists to ensure a clean start + if os.path.exists(output_file_path): + os.remove(output_file_path) + + # Assert that the file doesn't exist anymore after removal + assert not os.path.exists(output_file_path), "The file was not successfully removed." + + # Merge the PDF files + # Create a PDF writer object + pdf_writer = PdfWriter() + + # Iterate through the figure files and add each to the writer + for fig_file in self.fig_files: + pdf_reader = PdfReader(fig_file) + for page_num in range(len(pdf_reader.pages)): + page = pdf_reader.pages[page_num] + pdf_writer.add_page(page) + + # Write the merged PDF to a file + with open(output_file_path, 'wb') as out_file: + pdf_writer.write(out_file) if __name__ == "__main__": From ee0666fdd795c24782de94cff070b9c446072db4 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 27 May 2025 00:23:29 +0100 Subject: [PATCH 526/755] interv_analysis_wast: leaving this as preliminary results plotting separately single draw and run, new analysis script created---run_interventions_analysis_wasting --- src/scripts/wasting_analyses/intervention_analysis_wasting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/intervention_analysis_wasting.py b/src/scripts/wasting_analyses/intervention_analysis_wasting.py index 0dd4fa50ba..098b4b0b30 100644 --- a/src/scripts/wasting_analyses/intervention_analysis_wasting.py +++ b/src/scripts/wasting_analyses/intervention_analysis_wasting.py @@ -1,5 +1,6 @@ """ -An analysis file for the wasting module (so far only for 1 run, 1 draw) +This is a preliminary analysis script for the wasting module, displaying outcomes separately for each run and draw. +The full analysis is conducted using the run_interventions_analysis_wasting.py script. """ # %% Import statements import glob From a5a4c31688c254f510e04c22918f3799d6c3e858 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 27 May 2025 10:14:29 +0100 Subject: [PATCH 527/755] run_interv_analysis_wast & analysis_utility_fncs_wast: define folders to extract data from --- ....py => analysis_utility_functions_wast.py} | 20 +++++++++++++++++++ .../run_interventions_analysis_wasting.py | 7 ++++++- 2 files changed, 26 insertions(+), 1 deletion(-) rename src/scripts/wasting_analyses/{analysis_utility_functions.py => analysis_utility_functions_wast.py} (93%) diff --git a/src/scripts/wasting_analyses/analysis_utility_functions.py b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py similarity index 93% rename from src/scripts/wasting_analyses/analysis_utility_functions.py rename to src/scripts/wasting_analyses/analysis_utility_functions_wast.py index 16869c068d..5234e240a0 100644 --- a/src/scripts/wasting_analyses/analysis_utility_functions.py +++ b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py @@ -9,6 +9,26 @@ """This file contains functions used for wasting analyses to extract data, derive outcomes and generate plots. (It is based on analysis_utility_function prepared by Joe for maternal_perinatal_analyses.)""" +def extract_death_data_frames_and_outcomes(folder, birth_df): + print(f"{folder=}") + # All deaths occurring during the first 28 days of life are extracted + + # neonatal_mortality = extract_results( + # folder, + # module="tlo.methods.demography.detail", + # key="properties_of_deceased_persons", + # custom_generate_series=( + # lambda df: df.loc[(df['age_days'] < 29)].assign( + # year=df['date'].dt.year).groupby(['year'])['year'].count()), + # do_scaling=True) + # neo_deaths = nd.fillna(0) + # neo_deaths_int = neo_deaths.loc[intervention_years[0]: intervention_years[-1]] + # return + +################################################### ABOVE my functions ################################################# + +################################################### BELOW Joe's functions ############################################### + def return_95_CI_across_runs(df, sim_years): """Returns a list of lists from an outcome DF containing the mean and 95%CI values for that outcome over time. diff --git a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py index 9c186d677f..39c0265d1e 100644 --- a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py +++ b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py @@ -72,7 +72,12 @@ def run_interventions_analysis_wasting(outputspath:Path, plotyears:list, interve } # ---------------------------------------- NEONATAL AND UNDER-5 MORTALITY ---------------------------------------- # - # Extract outcome data + # Extract neonatal and under-5 death data from each of the scenario files + print() + empty_df = pd.DataFrame() # TODO need to be replaced by births_dict[scen_folder]['births_data_frame']) + death_data = {scen_name: analysis_utility_functions_wast.extract_death_data_frames_and_outcomes(scen_folder, empty_df) + for interv, scenarios in scenario_folders.items() for scen_name, scen_folder in scenarios.items()} + # ---------------- # From 6ba13e179468d5a664d3e4475f3cd113351970b0 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 30 May 2025 16:18:10 +0100 Subject: [PATCH 528/755] run_interv_analysis_wast & analysis_utility_fncs_wast: extract births and deaths data --- .../analysis_utility_functions_wast.py | 422 +++++------------- .../run_interventions_analysis_wasting.py | 41 +- 2 files changed, 141 insertions(+), 322 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py index 5234e240a0..55233a9ef1 100644 --- a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py +++ b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py @@ -1,4 +1,5 @@ import numpy as np +import pandas as pd import scipy.stats as st from matplotlib import pyplot as plt @@ -9,325 +10,118 @@ """This file contains functions used for wasting analyses to extract data, derive outcomes and generate plots. (It is based on analysis_utility_function prepared by Joe for maternal_perinatal_analyses.)""" -def extract_death_data_frames_and_outcomes(folder, birth_df): - print(f"{folder=}") - # All deaths occurring during the first 28 days of life are extracted - - # neonatal_mortality = extract_results( - # folder, - # module="tlo.methods.demography.detail", - # key="properties_of_deceased_persons", - # custom_generate_series=( - # lambda df: df.loc[(df['age_days'] < 29)].assign( - # year=df['date'].dt.year).groupby(['year'])['year'].count()), - # do_scaling=True) - # neo_deaths = nd.fillna(0) - # neo_deaths_int = neo_deaths.loc[intervention_years[0]: intervention_years[-1]] - # return - -################################################### ABOVE my functions ################################################# - -################################################### BELOW Joe's functions ############################################### - - -def return_95_CI_across_runs(df, sim_years): - """Returns a list of lists from an outcome DF containing the mean and 95%CI values for that outcome over time. - The first list containins the mean value of a given outcome per year across runs, the second contains the smaller - value of the 95% CI and the third list contains the larger value of the 95% Ci""" - - year_means = list() - lower_CI = list() - upper_CI = list() - - for year in sim_years: - if year in df.index: - row = df.loc[year] - year_means.append(row.mean()) - ci = st.t.interval(0.95, len(row) - 1, loc=np.mean(row), scale=st.sem(row)) - lower_CI.append(ci[0]) - upper_CI.append(ci[1]) - else: - year_means.append(0) - lower_CI.append(0) - upper_CI.append(0) - - return [year_means, lower_CI, upper_CI] - - -def get_mean_95_CI_from_list(list_item): - """Returns the mean and 95% CI of data in a provided list""" - ci = st.t.interval(0.95, len(list_item) - 1, loc=np.mean(list_item), scale=st.sem(list_item)) - result = [np.mean(list_item), ci[0], ci[1]] - return result - - -def get_mean_from_columns(df, function): - """Returns mean value for each column in a provided data frame""" - values = list() - for col in df: - if function == 'avg': - values.append(np.mean(df[col])) - else: - values.append(sum(df[col])) - return values - - -def line_graph_with_ci_and_target_rate(sim_years, data, target_data_dict, ylim, y_label, title, - graph_location, file_name): - """Outputs and saves line plot of an outcome over time, including uncertainty, in addition to a pre-determined - calibration target""" - fig, ax = plt.subplots() - ax.plot(sim_years, data[0], label="Model", color='deepskyblue') - ax.fill_between(sim_years, data[1], data[2], label="95% CI", color='b', alpha=.1) - - if target_data_dict['double']: - plt.errorbar(target_data_dict['first']['year'], target_data_dict['first']['value'], - label=target_data_dict['first']['label'], yerr=target_data_dict['first']['ci'], - fmt='o', color='darkseagreen', ecolor='green', elinewidth=3, capsize=0) - plt.errorbar(target_data_dict['second']['year'], target_data_dict['second']['value'], - label=target_data_dict['second']['label'], yerr=target_data_dict['second']['ci'], - fmt='o', color='darkseagreen', ecolor='green', elinewidth=3, capsize=0) - - elif not target_data_dict['double']: - plt.errorbar(target_data_dict['first']['year'], target_data_dict['first']['value'], - label=target_data_dict['first']['label'], yerr=target_data_dict['first']['ci'], - fmt='o', color='darkseagreen', ecolor='green', elinewidth=3, capsize=0) - - plt.xlabel('Year') - plt.ylabel(y_label) - plt.title(title) - ax.set(ylim=(0, ylim)) - plt.xticks(sim_years, labels=sim_years, rotation=45, fontsize=8) - plt.gca().set_ylim(bottom=0) - plt.legend() - plt.savefig(f'{graph_location}/{file_name}.png') - plt.show() - - -def simple_line_chart_with_target(sim_years, model_rate, target_rate, y_title, title, file_name, graph_location): - """Outputs and saves line plot of an outcome over time in addition to a pre-determined - calibration target""" - plt.plot(sim_years, model_rate, 'o-g', label="Model", color='deepskyblue') - plt.plot(sim_years, target_rate, 'o-g', label="Target rate", color='darkseagreen') - plt.ylabel(y_title) - plt.xlabel('Year') - plt.title(title) - plt.gca().set_ylim(bottom=0) - plt.legend() - plt.savefig(f'{graph_location}/{file_name}.png') - plt.show() - - -def simple_line_chart_with_ci(sim_years, data, y_title, title, file_name, graph_location): - """Outputs and saves line plot of an outcome over time, including uncertainty""" - fig, ax = plt.subplots() - ax.plot(sim_years, data[0], label="Model (mean)", color='deepskyblue') - ax.fill_between(sim_years, data[1], data[2], color='b', alpha=.1, label="95% CI") - plt.ylabel(y_title) - plt.xlabel('Year') - plt.title(title) - plt.legend() - plt.gca().set_ylim(bottom=0) - plt.grid(True) - plt.savefig(f'{graph_location}/{file_name}.png') - plt.show() - - -def simple_bar_chart(model_rates, x_title, y_title, title, file_name, sim_years, graph_location): - """Outputs a simple bar chart over time""" - bars = sim_years - x_pos = np.arange(len(bars)) - plt.bar(x_pos, model_rates, label="Model", color='thistle') - plt.xticks(x_pos, bars, rotation=90) - plt.xlabel(x_title) - plt.ylabel(y_title) - plt.title(title) - plt.legend() - plt.savefig(f'{graph_location}/{file_name}.png') - plt.show() - - -def comparison_graph_multiple_scenarios_multi_level_dict(colours, intervention_years, data_dict, key, y_label, title, - graph_location, save_name): - """Outputs and saves line plot of an outcome over time, including uncertainty, in addition to a pre-determined - calibration target. Data from the model is provided as a dictionary with multiple entries""" - fig, ax = plt.subplots() - - for k, colour in zip(data_dict, colours): - ax.plot(intervention_years, data_dict[k][key][0], label=k, color=colour) - ax.fill_between(intervention_years, data_dict[k][key][1], data_dict[k][key][2], color=colour, alpha=.1) - - plt.ylabel(y_label) - plt.xlabel('Year') - plt.title(title) - - if 'nmr' in key: - plt.gca().set_ylim(bottom=0, top=25) - elif 'sbr' in key: - plt.gca().set_ylim(bottom=0, top=20) - else: - plt.gca().set_ylim(bottom=0) - - plt.legend() - plt.xticks(intervention_years, labels=intervention_years, rotation=45, fontsize=8) - plt.savefig(f'./{graph_location}/{save_name}.png', bbox_inches='tight') - plt.show() - - -def comparison_bar_chart_multiple_bars(data, dict_name, intervention_years, colours, y_title, title, - plot_destination_folder, save_name): - """Outputs a barchart comparing two data sources""" - - N = len(intervention_years) - ind = np.arange(N) - if len(data.keys()) > 3: - width = 0.15 - else: - width = 0.2 - - x_ticks = list() - for x in range(len(intervention_years)): - x_ticks.append(x) - - for k, position, colour in zip(data, [ind - width, ind, ind + width, ind + width * 2, ind + width * 3], - colours): - ci = [(x - y) / 2 for x, y in zip(data[k][dict_name][2], data[k][dict_name][1])] - plt.bar(position, data[k][dict_name][0], width, label=k, yerr=ci, color=colour) - - plt.ylabel(y_title) - plt.xlabel('Years') - plt.title(title) - plt.legend(loc='best') - plt.xticks(x_ticks, labels=intervention_years) - plt.savefig(f'{plot_destination_folder}/{save_name}.png') - plt.show() - - -# =========================== FUNCTIONS RETURNING DATA FROM MULTIPLE SCENARIOS ======================================= -def get_modules_maternal_complication_dataframes(results_folder): - """Returns a dataframe from a scenario file which contains the number of maternal complications by type per year - for a given python script""" - comp_dfs = dict() - - for module in ['pregnancy_supervisor', 'labour', 'postnatal_supervisor']: - c_df = extract_results( - results_folder, - module=f"tlo.methods.{module}", - key="maternal_complication", - custom_generate_series=( - lambda df_: df_.assign(year=df_['date'].dt.year).groupby(['year', 'type'])['person'].count()), - do_scaling=True - ) - complications_df = c_df.fillna(0) - - comp_dfs[module] = complications_df - - return comp_dfs - - -def get_modules_neonatal_complication_dataframes(results_folder): - """Returns a dataframe from a scenario file which contains the number of neonatal complications by type per year - for a given python script""" - comp_dfs = dict() - - for module in ['newborn_outcomes', 'postnatal_supervisor']: - n_df = extract_results( - results_folder, - module=f"tlo.methods.{module}", - key="newborn_complication", - custom_generate_series=( - lambda df_: df_.assign(year=df_['date'].dt.year).groupby(['year', 'type'])['newborn'].count()), - do_scaling=True +def return_mean_95_CI_across_runs(df: pd.DataFrame) -> pd.DataFrame: + """ + Returns a DataFrame with mean, lower CI, and upper CI for each year and each draw across runs. + The output DataFrame is structured with row index ['year'] and column index ['draw'], where each cell contains + a list of [mean, lower_ci, upper_ci]. + """ + result = pd.DataFrame(index=df.index, columns=df.columns.get_level_values('draw').unique()) + + for year in df.index: + row = df.loc[year] + ci = row.groupby(level='draw').apply( + lambda x: st.t.interval(0.95, len(x) - 1, loc=np.mean(x), scale=st.sem(x)) ) - complications_df = n_df.fillna(0) - - comp_dfs[module] = complications_df - - return comp_dfs - - -def return_birth_data_from_multiple_scenarios(results_folders, sim_years, intervention_years): - """ Extracts data relating to births from a series of pre-specified scenario files""" - - def extract_births(folder): - br = extract_results( - folder, - module="tlo.methods.demography", - key="on_birth", - custom_generate_series=( - lambda df: df.assign( - year=df['date'].dt.year).groupby(['year'])['year'].count()), - do_scaling=True - ) - births_results = br.fillna(0) - total_births_per_year = return_95_CI_across_runs(births_results, sim_years) - - int_df = births_results.loc[intervention_years[0]: intervention_years[-1]] - int_births_per_year = return_95_CI_across_runs(int_df, intervention_years) - - agg_births_data = get_mean_from_columns(births_results.loc[intervention_years[0]: intervention_years[-1]], - 'agg') - agg_births = get_mean_95_CI_from_list(agg_births_data) - - return {'total_births': total_births_per_year, - 'int_births': int_births_per_year, - 'agg_births': agg_births, - 'births_data_frame': births_results} - - return {k: extract_births(results_folders[k]) for k in results_folders} - - -def return_pregnancy_data_from_multiple_scenarios(results_folders, sim_years, intervention_years): - """ Extracts data relating to pregnancies from a series of pre-specified scenario files""" - - def extract_pregnancies(folder): - pr = extract_results( - folder, - module="tlo.methods.contraception", - key="pregnancy", - custom_generate_series=( - lambda df: df.assign(year=df['date'].dt.year).groupby(['year'])['year'].count()), - do_scaling=True + result.loc[year] = row.groupby(level='draw').mean().combine( + ci, lambda mean, ci_interval: [mean, ci_interval[0], ci_interval[1]] ) - preg_results = pr.fillna(0) - total_pregnancies_per_year = return_95_CI_across_runs(preg_results, sim_years) - total_pregnancies_per_year_int = return_95_CI_across_runs( - preg_results.loc[intervention_years[0]: intervention_years[-1]], intervention_years) - - agg_preg_data = get_mean_from_columns(preg_results.loc[intervention_years[0]: intervention_years[-1]], 'agg') - agg_preg = get_mean_95_CI_from_list(agg_preg_data) - return {'total_preg': total_pregnancies_per_year, - 'int_preg': total_pregnancies_per_year_int, - 'agg_preg': agg_preg, - 'preg_data_frame': preg_results} - - return {k: extract_pregnancies(results_folders[k]) for k in results_folders} - - -def get_completed_pregnancies_from_multiple_scenarios(comps_df, birth_dict, results_folder): - """Sums the number of pregnancies that have ended in a given year including ectopic pregnancies, - abortions, stillbirths and births""" + return result - ansb_df = extract_results( - results_folder, - module="tlo.methods.pregnancy_supervisor", - key="antenatal_stillbirth", +def extract_birth_data_frames_and_outcomes(folder, years_of_interest, intervention_years) -> dict: + """ + :param folder: the folder from which the outcome data will be extracted + :param years_of_interest: years for which we want to extract the data + :param intervention_years: out of the years of interest, during which years was intervention implemented (if any) + :return: dictionary with list of lists with means, lower_CI, and upper_CI for all years of interest of + (1) total_births, (2) interv_births; and a dataframe (3) with births counts for years of interests as simulated + for draws and runs. + """ + + births_df = extract_results( + folder, + module="tlo.methods.demography", + key="on_birth", custom_generate_series=( lambda df: df.assign( year=df['date'].dt.year).groupby(['year'])['year'].count()), do_scaling=True - ) - - eu = comps_df['pregnancy_supervisor'].loc[(slice(None), 'ectopic_unruptured'), slice(None)] - eu_f = eu.droplevel(1) - - ia = comps_df['pregnancy_supervisor'].loc[(slice(None), 'induced_abortion'), slice(None)] - ia_f = ia.droplevel(1) - - sa = comps_df['pregnancy_supervisor'].loc[(slice(None), 'spontaneous_abortion'), slice(None)] - sa_f = sa.droplevel(1) - - comp_preg_data_frame = eu_f + ia_f + sa_f + ansb_df + birth_dict['births_data_frame'] - - return {'comp_preg_data_frame': comp_preg_data_frame} + ).fillna(0) + births_df = births_df.loc[years_of_interest[0]:years_of_interest[-1]] + + births_mean_ci_per_year_per_draw_df = return_mean_95_CI_across_runs(births_df) + + interv_births_df = births_df.loc[intervention_years[0]:intervention_years[-1]] + interv_births_per_year_per_draw_df = return_mean_95_CI_across_runs(interv_births_df) + + return {'births_df': births_df, + 'births_mean_ci_df': births_mean_ci_per_year_per_draw_df, + 'interv_births_df': interv_births_df, # TODO: check when and how is this used, is it really worth to return this? + 'interv_births_mean_ci_df': interv_births_per_year_per_draw_df} + +def extract_death_data_frames_and_outcomes(folder, births_df, years_of_interest, intervention_years): + # ### NEONATAL MORTALITY + # Extract all deaths occurring during the first 28 days of life + neonatal_deaths_df = extract_results( + folder, + module="tlo.methods.demography.detail", + key="properties_of_deceased_persons", + custom_generate_series=( + lambda df: df.loc[(df['age_days'] < 29)].assign( + year=df['date'].dt.year).groupby(['year'])['year'].count()), + do_scaling=True).fillna(0) + neonatal_deaths_df = neonatal_deaths_df.loc[years_of_interest[0]:years_of_interest[-1]] + + neo_deaths_mean_ci_per_year_per_draw_df = return_mean_95_CI_across_runs(neonatal_deaths_df) + + interv_neo_deaths_df = neonatal_deaths_df.loc[intervention_years[0]:intervention_years[-1]] + interv_neo_deaths_per_year_per_draw_df = return_mean_95_CI_across_runs(interv_neo_deaths_df) + + # # TODO: rm prints when no longer needed + # print("\nYears, and (Draws, Runs) with no neonatal death:") + # no_neo_deaths = [(neonatal_deaths.index[row], neonatal_deaths.columns[col]) for row, col in + # zip(*np.where(neonatal_deaths == 0.0))] + # print(f"{no_neo_deaths}") + # # + + # ### UNDER-5 MORTALITY + # Extract all deaths occurring during the first 5 years of life + under5_deaths_df = extract_results( + folder, + module="tlo.methods.demography.detail", + key="properties_of_deceased_persons", + custom_generate_series=( + lambda df: df.loc[(df['age_exact_years'] < 5)].assign( + year=df['date'].dt.year).groupby(['year'])['year'].count()), + do_scaling=True).fillna(0) + under5_deaths_df = under5_deaths_df.loc[years_of_interest[0]:years_of_interest[-1]] + + under5_deaths_mean_ci_per_year_per_draw_df = return_mean_95_CI_across_runs(under5_deaths_df) + + interv_under5_deaths_df = under5_deaths_df.loc[intervention_years[0]:intervention_years[-1]] + interv_under5_deaths_per_year_per_draw_df = return_mean_95_CI_across_runs(interv_under5_deaths_df) + + # NEONATAL MORTALITY RATE (NMR), i.e. the number of deaths of infants under 28 days old per 1,000 live births + nmr_df = (neonatal_deaths_df / births_df) * 1000 + nmr_per_year_per_draw_df = return_mean_95_CI_across_runs(nmr_df) + + return {'neo_deaths_df': neonatal_deaths_df, + 'neo_deaths_mean_ci_df': neo_deaths_mean_ci_per_year_per_draw_df, + 'interv_neo_deaths_df': interv_neo_deaths_df, # TODO: check when and how is this used, is it really worth to return this? + 'interv_neo_deaths_mean_ci_df': interv_neo_deaths_per_year_per_draw_df, + 'under5_deaths_df': under5_deaths_df, + 'under5_deaths_mean_ci_df': under5_deaths_mean_ci_per_year_per_draw_df, + 'interv_under5_deaths_df': interv_under5_deaths_df, + 'interv_under5_deaths_mean_ci_df': interv_under5_deaths_per_year_per_draw_df, + 'neonatal_mort_rate_df': nmr_df, + 'neo_mort_rate_mean_ci_df': nmr_per_year_per_draw_df} + + # # TODO: rm prints when no longer needed + # print("\nYears, and (Draws, Runs) with no under 5 death:") + # no_under5_deaths = [(under5_deaths.index[row], under5_deaths.columns[col]) for row, col in + # zip(*np.where(under5_deaths == 0.0))] + # print(f"{no_under5_deaths}") + # # + + # def plot_neonatal_mortality_multiple_scenario(): diff --git a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py index 39c0265d1e..619cd1692f 100644 --- a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py +++ b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py @@ -1,6 +1,7 @@ """ An analysis file for the wasting module to compare outcomes of one intervention under multiple assumptions. """ + # %% Import statements import analysis_utility_functions_wast import glob @@ -23,9 +24,10 @@ # ####### TO SET ####################################################################################################### # Create dicts for the intervention scenarios. 'Interv_abbrev': {'Intervention scenario title/abbreviation': draw_nmb} -scenarios_dict = {'GM': {'Status Quo': 0, 'GM_all': 1, 'GM_1-2': 2, 'GM_FullAttend': 3}} +scenarios_dict = {'GM': {'Status Quo': 0, 'GM_all': 1, 'GM_1-2': 2, 'GM_FullAttend': 3}, + 'GM2': {'GM_all': 1, 'GM_1-2': 2, 'GM_FullAttend': 3}} # Set the intervention to be analysed, and for which years they were simulated -intervs_of_interest = ['GM'] +intervs_of_interest = ['GM', 'GM2'] intervention_years = list(range(2026, 2031)) # Which years to plot (from post burn-in period) plot_years = list(range(2015, 2031)) @@ -71,14 +73,37 @@ def run_interventions_analysis_wasting(outputspath:Path, plotyears:list, interve for interv in intervs_of_interest } + pd.set_option('display.max_columns', None) # Show all columns + pd.set_option('display.max_rows', None) # Show all rows + pd.set_option('display.max_colwidth', None) # Show full content of each row # ---------------------------------------- NEONATAL AND UNDER-5 MORTALITY ---------------------------------------- # - # Extract neonatal and under-5 death data from each of the scenario files + # Extract birth outcomes for each intervention to calculate mortality as number of deaths per 1,000 live births + birth_outcomes = { + interv: analysis_utility_functions_wast.extract_birth_data_frames_and_outcomes(iterv_folders_dict[interv], + plotyears, interventionyears) + for interv in scenario_folders + } + # TODO: rm + # print("\nBIRTH OUTCOMES") + # for interv in birth_outcomes.keys(): + # print(f"### {interv=}") + # for outcome in birth_outcomes[interv]: + # print(f"{outcome}:\n{birth_outcomes[interv][outcome]}") + # + # Extract neonatal and under-5 death data for each intervention print() - empty_df = pd.DataFrame() # TODO need to be replaced by births_dict[scen_folder]['births_data_frame']) - death_data = {scen_name: analysis_utility_functions_wast.extract_death_data_frames_and_outcomes(scen_folder, empty_df) - for interv, scenarios in scenario_folders.items() for scen_name, scen_folder in scenarios.items()} - - + death_outcomes = { + interv: analysis_utility_functions_wast.extract_death_data_frames_and_outcomes( + iterv_folders_dict[interv], birth_outcomes[interv]['births_df'], plotyears, interventionyears + ) for interv in scenario_folders + } + # TODO: rm + # print("\nDEATH OUTCOMES") + # for interv in death_outcomes.keys(): + # print(f"### {interv=}") + # for outcome in death_outcomes[interv]: + # print(f"{outcome}:\n{death_outcomes[interv][outcome]}") + # # ---------------- # # RUN THE ANALYSIS # From d36cfea81c4a9a2e6f906c7abe95fa156c5de329 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Fri, 30 May 2025 22:55:58 +0100 Subject: [PATCH 529/755] run_interv_analysis_wast & analysis_utility_fncs_wast: plot Neonatal & Under-5 mortality rates (!a bug included more neonatal deaths than under-5 deaths) --- .../analysis_utility_functions_wast.py | 75 +++++++++++++++++-- .../run_interventions_analysis_wasting.py | 22 ++++-- 2 files changed, 83 insertions(+), 14 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py index 55233a9ef1..47c01ec387 100644 --- a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py +++ b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py @@ -2,6 +2,7 @@ import pandas as pd import scipy.stats as st from matplotlib import pyplot as plt +from pathlib import Path from tlo.analysis.utils import extract_results @@ -78,6 +79,11 @@ def extract_death_data_frames_and_outcomes(folder, births_df, years_of_interest, interv_neo_deaths_df = neonatal_deaths_df.loc[intervention_years[0]:intervention_years[-1]] interv_neo_deaths_per_year_per_draw_df = return_mean_95_CI_across_runs(interv_neo_deaths_df) + # NEONATAL MORTALITY RATE (NMR), i.e. the number of deaths of infants up to 28 days old per 1,000 live births + nmr_df = (neonatal_deaths_df / births_df) * 1000 + nmr_per_year_per_draw_df = return_mean_95_CI_across_runs(nmr_df) + + # # TODO: rm prints when no longer needed # print("\nYears, and (Draws, Runs) with no neonatal death:") # no_neo_deaths = [(neonatal_deaths.index[row], neonatal_deaths.columns[col]) for row, col in @@ -102,20 +108,22 @@ def extract_death_data_frames_and_outcomes(folder, births_df, years_of_interest, interv_under5_deaths_df = under5_deaths_df.loc[intervention_years[0]:intervention_years[-1]] interv_under5_deaths_per_year_per_draw_df = return_mean_95_CI_across_runs(interv_under5_deaths_df) - # NEONATAL MORTALITY RATE (NMR), i.e. the number of deaths of infants under 28 days old per 1,000 live births - nmr_df = (neonatal_deaths_df / births_df) * 1000 - nmr_per_year_per_draw_df = return_mean_95_CI_across_runs(nmr_df) + # UNDER-5 MORTALITY RATE, i.e. the number of deaths of children under 5 years old per 1,000 live births + under5mr_df = (under5_deaths_df / births_df) * 1000 + under5mr_per_year_per_draw_df = return_mean_95_CI_across_runs(under5mr_df) return {'neo_deaths_df': neonatal_deaths_df, 'neo_deaths_mean_ci_df': neo_deaths_mean_ci_per_year_per_draw_df, 'interv_neo_deaths_df': interv_neo_deaths_df, # TODO: check when and how is this used, is it really worth to return this? 'interv_neo_deaths_mean_ci_df': interv_neo_deaths_per_year_per_draw_df, + 'neonatal_mort_rate_df': nmr_df, + 'neo_mort_rate_mean_ci_df': nmr_per_year_per_draw_df, 'under5_deaths_df': under5_deaths_df, 'under5_deaths_mean_ci_df': under5_deaths_mean_ci_per_year_per_draw_df, 'interv_under5_deaths_df': interv_under5_deaths_df, 'interv_under5_deaths_mean_ci_df': interv_under5_deaths_per_year_per_draw_df, - 'neonatal_mort_rate_df': nmr_df, - 'neo_mort_rate_mean_ci_df': nmr_per_year_per_draw_df} + 'under5_mort_rate_df': under5mr_df, + 'under5_mort_rate_mean_ci_df': under5mr_per_year_per_draw_df} # # TODO: rm prints when no longer needed # print("\nYears, and (Draws, Runs) with no under 5 death:") @@ -124,4 +132,59 @@ def extract_death_data_frames_and_outcomes(folder, births_df, years_of_interest, # print(f"{no_under5_deaths}") # # - # def plot_neonatal_mortality_multiple_scenario(): +def get_scen_colour(scen_name: str) -> str: + return { + 'Status Quo': '#F7F77D', + 'GM_FullAttend': '#4575B4', + 'GM_all': '#BDEBF7', + 'GM_1-2': '#91BFDB', + 'CS_10': '#B5D784', + 'FS_full': '#A90251', + 'FS_plus10': '#D4898E' + }.get(scen_name) + +def plot_mortality__by_interv_multiple_settings(cohort: str, scenarios_dict: dict, intervs_of_interest: list, + plot_years: list, data_dict: dict, outputs_path: Path) -> None: + + def plot_scenarios(scenarios_to_plot): + for scen_name, draw in scenarios_to_plot.items(): + scen_colour = get_scen_colour(scen_name) + scen_data = data_dict[interv][outcome][draw] + + means, ci_lower, ci_upper = zip(*scen_data.values.flatten()) + + ax.plot(plot_years, means, label=scen_name, color=scen_colour) + ax.fill_between(plot_years, ci_lower, ci_upper, + color=scen_colour, alpha=.1) + + # outcome to plot + assert cohort in ['Neonatal', 'Under-5'],\ + f"Invalid value for 'cohort': expected 'Neonatal' or 'Under-5'. Received {cohort} instead." + + if cohort == 'Neonatal': + outcome = 'neo_mort_rate_mean_ci_df' + target = 12 + ylim_top = 270 #25 + else: #cohort == 'Under-5': + outcome = 'under5_mort_rate_mean_ci_df' + target = 25 + ylim_top = 270 #60 + + for interv in intervs_of_interest: + + fig, ax = plt.subplots() + plot_scenarios(scenarios_dict[interv]) + plot_scenarios(scenarios_dict['SQ']) + + plt.axhline(y=target, color='black', linestyle='--', linewidth=1) + plt.text(x=plot_years[-1] + 1, y=target, s='SDG\n3.2 target', color='black', va='center', ha='left', fontsize=8) + plt.ylabel(f'{cohort} Deaths per 1,000 Live Births') + plt.xlabel('Year') + plt.title(f'{cohort} Mortality Rate: multiple settings of {interv} intervention') + + plt.gca().set_ylim(bottom=0, top=ylim_top) + + plt.legend() + plt.xticks(plot_years, labels=plot_years, rotation=45, fontsize=8) + plt.savefig(outputs_path / f'{cohort}_mort_rate_{interv}_multiple_settings.png', bbox_inches='tight') + plt.show() diff --git a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py index 619cd1692f..7633bd6b1a 100644 --- a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py +++ b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py @@ -24,8 +24,9 @@ # ####### TO SET ####################################################################################################### # Create dicts for the intervention scenarios. 'Interv_abbrev': {'Intervention scenario title/abbreviation': draw_nmb} -scenarios_dict = {'GM': {'Status Quo': 0, 'GM_all': 1, 'GM_1-2': 2, 'GM_FullAttend': 3}, - 'GM2': {'GM_all': 1, 'GM_1-2': 2, 'GM_FullAttend': 3}} +scenarios_dict = {'SQ': {'Status Quo': 0}, + 'GM': {'GM_all': 1, 'GM_1-2': 2, 'GM_FullAttend': 3}, + 'GM2': {'GM_all': 1, 'GM_1-2': 2}} # Set the intervention to be analysed, and for which years they were simulated intervs_of_interest = ['GM', 'GM2'] intervention_years = list(range(2026, 2031)) @@ -40,7 +41,7 @@ # Files names prefix scenario_filename_prefix = 'wasting_analysis__minimal_model' # Where to save the outcomes -outputs_path = Path("./outputs/sejjej5@ucl.ac.uk/wasting/scenarios/outcomes") +outputs_path = Path("./outputs/sejjej5@ucl.ac.uk/wasting/scenarios/_outcomes") ######################################################################################################################## def run_interventions_analysis_wasting(outputspath:Path, plotyears:list, interventionyears:list, @@ -98,13 +99,18 @@ def run_interventions_analysis_wasting(outputspath:Path, plotyears:list, interve ) for interv in scenario_folders } # TODO: rm - # print("\nDEATH OUTCOMES") - # for interv in death_outcomes.keys(): - # print(f"### {interv=}") - # for outcome in death_outcomes[interv]: - # print(f"{outcome}:\n{death_outcomes[interv][outcome]}") + print("\nDEATH OUTCOMES") + for interv in death_outcomes.keys(): + print(f"### {interv=}") + for outcome in death_outcomes[interv]: + print(f"{outcome}:\n{death_outcomes[interv][outcome]}") # + for cohort in ['Neonatal', 'Under-5']: + analysis_utility_functions_wast.plot_mortality__by_interv_multiple_settings( + cohort, scenarios_dict, intervs_of_interest, plot_years, death_outcomes, outputs_path + ) + # ---------------- # # RUN THE ANALYSIS # # ---------------- # From db191eec8ae21ab6ae89449bfa0c09ddf6b96946 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 4 Jun 2025 13:59:30 +0100 Subject: [PATCH 530/755] wast: log wasting episodes lengths only at debug level --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 705eb511ca..5ec872fc7b 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -1886,7 +1886,7 @@ def apply(self, population): assert not np.isnan(length_df.loc[age_grp, 'sev_not_yet_recovered']), \ f"The avg {length_df.loc[age_grp, 'sev_not_yet_recovered']=} for {age_grp=} is empty." - logger.info(key='wasting_length_avg', data=length_df.to_dict()) + logger.debug(key='wasting_length_avg', data=length_df.to_dict()) # ----- PREVALENCE LOG ---------------- # Wasting totals (prevalence & pop size at logging time) From b90f66effcb89012975a9b14b5ef3dc98a97a931 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 4 Jun 2025 14:26:42 +0100 Subject: [PATCH 531/755] scenario_wast_full_model(SQ|GM): new (to log deaths from all modules) --- .../scenario_wasting_full_model_GM.py | 72 +++++++++++++++++++ .../scenario_wasting_full_model_SQ.py | 59 +++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py create mode 100644 src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py new file mode 100644 index 0000000000..221df45911 --- /dev/null +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py @@ -0,0 +1,72 @@ +""" +This file defines a scenario for wasting analysis. + +It can be submitted on Azure Batch by running: + + tlo batch-submit src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py + +or locally using: + + tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py +""" +# import itertools +import warnings + +from tlo import Date, logging +from tlo.analysis.utils import get_parameters_for_status_quo +from tlo.methods.fullmodel import fullmodel +from tlo.scenario import BaseScenario + +# capture warnings during simulation run +warnings.simplefilter('default', (UserWarning, RuntimeWarning)) + + +class WastingAnalysis(BaseScenario): + + def __init__(self): + super().__init__( + seed=0, + start_date=Date(year=2010, month=1, day=1), + end_date=Date(year=2031, month=1, day=1), + initial_population_size=4_000, + number_of_draws=3, + runs_per_draw=10, + ) + + def log_configuration(self): + return { + 'filename': 'wasting_analysis__minimal_model', + 'directory': './outputs/wasting_analysis', + "custom_levels": { # Customise the output of specific loggers + "tlo.methods.demography": logging.INFO, + "tlo.methods.population": logging.INFO, + "tlo.methods.wasting": logging.INFO, + '*': logging.WARNING + } + } + + def modules(self): + return fullmodel(resourcefilepath=self.resources, + module_kwargs=get_parameters_for_status_quo()) + + # Scaling up growth monitoring (GM) attendance scenarios + def draw_parameters(self, draw_number, rng): + ### growth_monitoring_attendance_probs by age categories + # < 1 year + attendance_prob_below1y = 0.76 + # 1-2 years + attendance_prob_1to2y = [0.20, 0.25, 1.00] + # > 2 years + attendance_prob_above2y = [0.55, 0.50, 1.00] + + return { + 'Wasting': { + 'interv_growth_monitoring_attendance_prob_agecat': + [attendance_prob_below1y, attendance_prob_1to2y[draw_number], attendance_prob_above2y[draw_number]] + } + } + +if __name__ == '__main__': + from tlo.cli import scenario_run + + scenario_run([__file__]) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py new file mode 100644 index 0000000000..60c653a834 --- /dev/null +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py @@ -0,0 +1,59 @@ +""" +This file defines a scenario for wasting analysis. + +It can be submitted on Azure Batch by running: + + tlo batch-submit src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py + +or locally using: + + tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py +""" +# import itertools +import warnings + +from tlo import Date, logging +from tlo.analysis.utils import get_parameters_for_status_quo +from tlo.methods.fullmodel import fullmodel +from tlo.scenario import BaseScenario + +# capture warnings during simulation run +warnings.simplefilter('default', (UserWarning, RuntimeWarning)) + + +class WastingAnalysis(BaseScenario): + + def __init__(self): + super().__init__( + seed=0, + start_date=Date(year=2010, month=1, day=1), + end_date=Date(year=2031, month=1, day=1), + initial_population_size=4_000, + number_of_draws=1, + runs_per_draw=10, + ) + + def log_configuration(self): + return { + 'filename': 'wasting_analysis__minimal_model', + 'directory': './outputs/wasting_analysis', + "custom_levels": { # Customise the output of specific loggers + "tlo.methods.demography": logging.INFO, + "tlo.methods.population": logging.INFO, + "tlo.methods.wasting": logging.INFO, + '*': logging.WARNING + } + } + + def modules(self): + return fullmodel(resourcefilepath=self.resources, + module_kwargs=get_parameters_for_status_quo()) + + # Keeping Status Quo parameters + def draw_parameters(self, draw_number, rng): + return + +if __name__ == '__main__': + from tlo.cli import scenario_run + + scenario_run([__file__]) From 5b05adacb6f821b346f209d286734e6ba1ab497b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 8 Jun 2025 21:47:55 +0100 Subject: [PATCH 532/755] analysis_utility_fncs_wast: Fix slicing of data by year indexes --- .../analysis_utility_functions_wast.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py index 47c01ec387..ed7adb3c59 100644 --- a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py +++ b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py @@ -49,11 +49,11 @@ def extract_birth_data_frames_and_outcomes(folder, years_of_interest, interventi year=df['date'].dt.year).groupby(['year'])['year'].count()), do_scaling=True ).fillna(0) - births_df = births_df.loc[years_of_interest[0]:years_of_interest[-1]] + births_df = births_df.loc[years_of_interest] births_mean_ci_per_year_per_draw_df = return_mean_95_CI_across_runs(births_df) - interv_births_df = births_df.loc[intervention_years[0]:intervention_years[-1]] + interv_births_df = births_df.loc[intervention_years] interv_births_per_year_per_draw_df = return_mean_95_CI_across_runs(interv_births_df) return {'births_df': births_df, @@ -72,18 +72,17 @@ def extract_death_data_frames_and_outcomes(folder, births_df, years_of_interest, lambda df: df.loc[(df['age_days'] < 29)].assign( year=df['date'].dt.year).groupby(['year'])['year'].count()), do_scaling=True).fillna(0) - neonatal_deaths_df = neonatal_deaths_df.loc[years_of_interest[0]:years_of_interest[-1]] + neonatal_deaths_df = neonatal_deaths_df.loc[years_of_interest] neo_deaths_mean_ci_per_year_per_draw_df = return_mean_95_CI_across_runs(neonatal_deaths_df) - interv_neo_deaths_df = neonatal_deaths_df.loc[intervention_years[0]:intervention_years[-1]] + interv_neo_deaths_df = neonatal_deaths_df.loc[intervention_years] interv_neo_deaths_per_year_per_draw_df = return_mean_95_CI_across_runs(interv_neo_deaths_df) # NEONATAL MORTALITY RATE (NMR), i.e. the number of deaths of infants up to 28 days old per 1,000 live births nmr_df = (neonatal_deaths_df / births_df) * 1000 nmr_per_year_per_draw_df = return_mean_95_CI_across_runs(nmr_df) - # # TODO: rm prints when no longer needed # print("\nYears, and (Draws, Runs) with no neonatal death:") # no_neo_deaths = [(neonatal_deaths.index[row], neonatal_deaths.columns[col]) for row, col in @@ -101,11 +100,11 @@ def extract_death_data_frames_and_outcomes(folder, births_df, years_of_interest, lambda df: df.loc[(df['age_exact_years'] < 5)].assign( year=df['date'].dt.year).groupby(['year'])['year'].count()), do_scaling=True).fillna(0) - under5_deaths_df = under5_deaths_df.loc[years_of_interest[0]:years_of_interest[-1]] + under5_deaths_df = under5_deaths_df.loc[years_of_interest] under5_deaths_mean_ci_per_year_per_draw_df = return_mean_95_CI_across_runs(under5_deaths_df) - interv_under5_deaths_df = under5_deaths_df.loc[intervention_years[0]:intervention_years[-1]] + interv_under5_deaths_df = under5_deaths_df.loc[intervention_years] interv_under5_deaths_per_year_per_draw_df = return_mean_95_CI_across_runs(interv_under5_deaths_df) # UNDER-5 MORTALITY RATE, i.e. the number of deaths of children under 5 years old per 1,000 live births From 8e12e3cc2f2b248c073760bc8e40fc5cbf5ce3e4 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 8 Jun 2025 21:51:12 +0100 Subject: [PATCH 533/755] run_interv_analysis_wast: use input par not outer scope var within the fnc --- .../run_interventions_analysis_wasting.py | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py index 7633bd6b1a..4b2b948a8c 100644 --- a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py +++ b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py @@ -26,7 +26,7 @@ # Create dicts for the intervention scenarios. 'Interv_abbrev': {'Intervention scenario title/abbreviation': draw_nmb} scenarios_dict = {'SQ': {'Status Quo': 0}, 'GM': {'GM_all': 1, 'GM_1-2': 2, 'GM_FullAttend': 3}, - 'GM2': {'GM_all': 1, 'GM_1-2': 2}} + 'GM2': {'GM_all': 1, 'GM_1-2': 2, 'GM_FullAttend': 3}} # Set the intervention to be analysed, and for which years they were simulated intervs_of_interest = ['GM', 'GM2'] intervention_years = list(range(2026, 2031)) @@ -63,7 +63,7 @@ def run_interventions_analysis_wasting(outputspath:Path, plotyears:list, interve iterv_folders_dict = { interv: get_scenario_outputs( scenario_filename_prefix, Path(interv_scenarios_folder_path / interv) - )[-1] for interv in intervs_of_interest + )[-1] for interv in intervs_ofinterest } # Define folders for each scenario scenario_folders = { @@ -71,7 +71,7 @@ def run_interventions_analysis_wasting(outputspath:Path, plotyears:list, interve scen_name: Path(iterv_folders_dict[interv] / str(scen_draw_nmb)) for scen_name, scen_draw_nmb in scenarios_dict[interv].items() } - for interv in intervs_of_interest + for interv in intervs_ofinterest } pd.set_option('display.max_columns', None) # Show all columns @@ -90,25 +90,26 @@ def run_interventions_analysis_wasting(outputspath:Path, plotyears:list, interve # print(f"### {interv=}") # for outcome in birth_outcomes[interv]: # print(f"{outcome}:\n{birth_outcomes[interv][outcome]}") + # print() # + # Extract neonatal and under-5 death data for each intervention - print() death_outcomes = { interv: analysis_utility_functions_wast.extract_death_data_frames_and_outcomes( iterv_folders_dict[interv], birth_outcomes[interv]['births_df'], plotyears, interventionyears ) for interv in scenario_folders } # TODO: rm - print("\nDEATH OUTCOMES") - for interv in death_outcomes.keys(): - print(f"### {interv=}") - for outcome in death_outcomes[interv]: - print(f"{outcome}:\n{death_outcomes[interv][outcome]}") - # + # print("\nDEATH OUTCOMES") + # for interv in death_outcomes.keys(): + # print(f"### {interv=}") + # for outcome in death_outcomes[interv]: + # print(f"{outcome}:\n{death_outcomes[interv][outcome]}") + # # for cohort in ['Neonatal', 'Under-5']: analysis_utility_functions_wast.plot_mortality__by_interv_multiple_settings( - cohort, scenarios_dict, intervs_of_interest, plot_years, death_outcomes, outputs_path + cohort, scenarios_dict, intervs_ofinterest, plotyears, death_outcomes, outputspath ) # ---------------- # From 6bd34d94cf6309e81cc4d30b9d67834699e6bd62 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 8 Jun 2025 23:37:05 +0100 Subject: [PATCH 534/755] scenario_wast_full_model_(SQ|GM): 30K pop --- .../scenarios/scenario_wasting_full_model_GM.py | 2 +- .../scenarios/scenario_wasting_full_model_SQ.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py index 221df45911..9a00053b60 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py @@ -28,7 +28,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=3, runs_per_draw=10, ) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py index 60c653a834..30823b39e6 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py @@ -28,7 +28,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=1, runs_per_draw=10, ) From 247fa7a8b81e653e994a3e867f43a0a118bf99b0 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Sun, 8 Jun 2025 23:41:20 +0100 Subject: [PATCH 535/755] analysis_utility_fncs_wast: fix data extraction (years taken from data filtered by age --- .../analysis_utility_functions_wast.py | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py index ed7adb3c59..9c97d78e3c 100644 --- a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py +++ b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py @@ -69,8 +69,12 @@ def extract_death_data_frames_and_outcomes(folder, births_df, years_of_interest, module="tlo.methods.demography.detail", key="properties_of_deceased_persons", custom_generate_series=( - lambda df: df.loc[(df['age_days'] < 29)].assign( - year=df['date'].dt.year).groupby(['year'])['year'].count()), + lambda df: (filtered_by_age := df.loc[df['age_days'] < 29]) + .assign(year=filtered_by_age['date'].dt.year) + .groupby(['year'])['year'] + .count() + .reindex(df['date'].dt.year.unique(), fill_value=0) + ), do_scaling=True).fillna(0) neonatal_deaths_df = neonatal_deaths_df.loc[years_of_interest] @@ -97,9 +101,13 @@ def extract_death_data_frames_and_outcomes(folder, births_df, years_of_interest, module="tlo.methods.demography.detail", key="properties_of_deceased_persons", custom_generate_series=( - lambda df: df.loc[(df['age_exact_years'] < 5)].assign( - year=df['date'].dt.year).groupby(['year'])['year'].count()), - do_scaling=True).fillna(0) + lambda df: (filtered_by_age := df.loc[df['age_exact_years'] < 5]) + .assign(year=filtered_by_age['date'].dt.year) + .groupby(['year'])['year'] + .count() + .reindex(df['date'].dt.year.unique(), fill_value=0) + ), + do_scaling = True).fillna(0) under5_deaths_df = under5_deaths_df.loc[years_of_interest] under5_deaths_mean_ci_per_year_per_draw_df = return_mean_95_CI_across_runs(under5_deaths_df) From 7c123a51c6e547258c74a87a4fd13e9996a32fb0 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 9 Jun 2025 00:28:16 +0100 Subject: [PATCH 536/755] run_interv_analysis_wast & analysis_utility_fncs_wast: fix SQ plotting, add timestamps to outcome file names, update for full model sims --- .../analysis_utility_functions_wast.py | 27 +++++++---- .../run_interventions_analysis_wasting.py | 47 +++++++++++-------- 2 files changed, 46 insertions(+), 28 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py index 9c97d78e3c..ba6f51a048 100644 --- a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py +++ b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py @@ -150,13 +150,15 @@ def get_scen_colour(scen_name: str) -> str: 'FS_plus10': '#D4898E' }.get(scen_name) -def plot_mortality__by_interv_multiple_settings(cohort: str, scenarios_dict: dict, intervs_of_interest: list, - plot_years: list, data_dict: dict, outputs_path: Path) -> None: +def plot_mortality__by_interv_multiple_settings(cohort: str, interv_timestamps_dict: dict, scenarios_dict: dict, + intervs_of_interest: list, plot_years: list, data_dict: dict, + outputs_path: Path) -> None: - def plot_scenarios(scenarios_to_plot): + def plot_scenarios(plot_interv, plot_outcome): + scenarios_to_plot = scenarios_dict[plot_interv] for scen_name, draw in scenarios_to_plot.items(): scen_colour = get_scen_colour(scen_name) - scen_data = data_dict[interv][outcome][draw] + scen_data = data_dict[plot_interv][plot_outcome][draw] means, ci_lower, ci_upper = zip(*scen_data.values.flatten()) @@ -171,20 +173,21 @@ def plot_scenarios(scenarios_to_plot): if cohort == 'Neonatal': outcome = 'neo_mort_rate_mean_ci_df' target = 12 - ylim_top = 270 #25 + ylim_top = 30 # 25 else: #cohort == 'Under-5': outcome = 'under5_mort_rate_mean_ci_df' target = 25 - ylim_top = 270 #60 + ylim_top = 100 #60 for interv in intervs_of_interest: fig, ax = plt.subplots() - plot_scenarios(scenarios_dict[interv]) - plot_scenarios(scenarios_dict['SQ']) + plot_scenarios(interv, outcome) + plot_scenarios('SQ', outcome) plt.axhline(y=target, color='black', linestyle='--', linewidth=1) plt.text(x=plot_years[-1] + 1, y=target, s='SDG\n3.2 target', color='black', va='center', ha='left', fontsize=8) + plt.text(x=plot_years[0] - 1, y=target, s=target, color='black', va='center', ha='right', fontsize=8) plt.ylabel(f'{cohort} Deaths per 1,000 Live Births') plt.xlabel('Year') plt.title(f'{cohort} Mortality Rate: multiple settings of {interv} intervention') @@ -193,5 +196,11 @@ def plot_scenarios(scenarios_to_plot): plt.legend() plt.xticks(plot_years, labels=plot_years, rotation=45, fontsize=8) - plt.savefig(outputs_path / f'{cohort}_mort_rate_{interv}_multiple_settings.png', bbox_inches='tight') + + # TODO: extract from iterv_folders_dict[interv] the suffix after the prefix (scenario_filename_prefix = 'wasting_analysis__minimal_model') + plt.savefig( + outputs_path / f"{cohort}_mort_rate_{interv}_multiple_settings__" + f"{interv_timestamps_dict[interv]}__{interv_timestamps_dict['SQ']}.png", + bbox_inches='tight' + ) plt.show() diff --git a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py index 4b2b948a8c..1a412df7fc 100644 --- a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py +++ b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py @@ -39,7 +39,7 @@ # Where to find the modelled intervention scenarios interv_scenarios_folder_path = Path("./outputs/sejjej5@ucl.ac.uk/wasting/scenarios") # Files names prefix -scenario_filename_prefix = 'wasting_analysis__minimal_model' +scenario_filename_prefix = 'wasting_analysis__full_model' # Where to save the outcomes outputs_path = Path("./outputs/sejjej5@ucl.ac.uk/wasting/scenarios/_outcomes") ######################################################################################################################## @@ -59,19 +59,27 @@ def run_interventions_analysis_wasting(outputspath:Path, plotyears:list, interve (GM = growth monitoring, CS = care-seeking, FS = food supplements) """ - # Find the most recent folders containing results for each intervention of interest + # Find the most recent folders containing results for each intervention + interventions = intervs_ofinterest + ['SQ'] iterv_folders_dict = { interv: get_scenario_outputs( scenario_filename_prefix, Path(interv_scenarios_folder_path / interv) - )[-1] for interv in intervs_ofinterest + )[-1] for interv in interventions } + interv_timestamps_dict = { + interv: get_scenario_outputs( + scenario_filename_prefix, Path(interv_scenarios_folder_path / interv) + )[-1].name.split(f"{scenario_filename_prefix}_{interv}-")[-1] + for interv in interventions + } + print(f"{interv_timestamps_dict=}") # Define folders for each scenario scenario_folders = { interv: { scen_name: Path(iterv_folders_dict[interv] / str(scen_draw_nmb)) for scen_name, scen_draw_nmb in scenarios_dict[interv].items() } - for interv in intervs_ofinterest + for interv in interventions } pd.set_option('display.max_columns', None) # Show all columns @@ -79,37 +87,38 @@ def run_interventions_analysis_wasting(outputspath:Path, plotyears:list, interve pd.set_option('display.max_colwidth', None) # Show full content of each row # ---------------------------------------- NEONATAL AND UNDER-5 MORTALITY ---------------------------------------- # # Extract birth outcomes for each intervention to calculate mortality as number of deaths per 1,000 live births - birth_outcomes = { + print("\nbirth outcomes calculation ...") + birth_outcomes_dict = { interv: analysis_utility_functions_wast.extract_birth_data_frames_and_outcomes(iterv_folders_dict[interv], plotyears, interventionyears) for interv in scenario_folders } # TODO: rm # print("\nBIRTH OUTCOMES") - # for interv in birth_outcomes.keys(): + # for interv in birth_outcomes_dict.keys(): # print(f"### {interv=}") - # for outcome in birth_outcomes[interv]: - # print(f"{outcome}:\n{birth_outcomes[interv][outcome]}") - # print() + # for outcome in birth_outcomes_dict[interv]: + # print(f"{outcome}:\n{birth_outcomes_dict[interv][outcome]}") # - # Extract neonatal and under-5 death data for each intervention - death_outcomes = { + print("\ndeath outcomes calculation ...") + death_outcomes_dict = { interv: analysis_utility_functions_wast.extract_death_data_frames_and_outcomes( - iterv_folders_dict[interv], birth_outcomes[interv]['births_df'], plotyears, interventionyears + iterv_folders_dict[interv], birth_outcomes_dict[interv]['births_df'], plotyears, interventionyears ) for interv in scenario_folders } # TODO: rm - # print("\nDEATH OUTCOMES") - # for interv in death_outcomes.keys(): - # print(f"### {interv=}") - # for outcome in death_outcomes[interv]: - # print(f"{outcome}:\n{death_outcomes[interv][outcome]}") - # # + print("\nDEATH OUTCOMES") + for interv in death_outcomes_dict.keys(): + print(f"### {interv=}") + for outcome in death_outcomes_dict[interv]: + print(f"{outcome}:\n{death_outcomes_dict[interv][outcome]}") + # for cohort in ['Neonatal', 'Under-5']: analysis_utility_functions_wast.plot_mortality__by_interv_multiple_settings( - cohort, scenarios_dict, intervs_ofinterest, plotyears, death_outcomes, outputspath + cohort, interv_timestamps_dict, scenarios_dict, intervs_ofinterest, plotyears, death_outcomes_dict, + outputspath ) # ---------------- # From 2bec02e908494759ed48a4622c78b732bb5f096d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 9 Jun 2025 01:00:10 +0100 Subject: [PATCH 537/755] rm old analysis script --- .../intervention_analysis_wasting.py | 850 ------------------ 1 file changed, 850 deletions(-) delete mode 100644 src/scripts/wasting_analyses/intervention_analysis_wasting.py diff --git a/src/scripts/wasting_analyses/intervention_analysis_wasting.py b/src/scripts/wasting_analyses/intervention_analysis_wasting.py deleted file mode 100644 index 098b4b0b30..0000000000 --- a/src/scripts/wasting_analyses/intervention_analysis_wasting.py +++ /dev/null @@ -1,850 +0,0 @@ -""" -This is a preliminary analysis script for the wasting module, displaying outcomes separately for each run and draw. -The full analysis is conducted using the run_interventions_analysis_wasting.py script. -""" -# %% Import statements -import glob -import gzip -import os -import shutil -import time -from pathlib import Path - -import numpy as np -import pandas as pd -from matplotlib import pyplot as plt -from PyPDF2 import PdfReader, PdfWriter -from scipy import stats - -from tlo.analysis.utils import compare_number_of_deaths, get_scenario_outputs, parse_log_file - -# start time of the whole analysis -total_time_start = time.time() - -# ####### TO SET ####################################################################################################### -scenario_filename = 'wasting_analysis__minimal_model' -outputs_path = Path("./outputs/sejjej5@ucl.ac.uk/wasting/scenarios") -scenario_type = 'GM' # GM stands for scaling up Growth Monitoring attendance -legend_fontsize = 12 -title_fontsize = 16 -######################################################################################################################## - -class WastingScenarioAnalyses: - """ - This class enables plotting of all important outcomes for a single scenario (i.e. one draw) with each run being - plotted separately. - """ - - def __init__(self, in_scenario_type, sim_results_folder_path_str, in_datestamp, in_draw_nmb, in_png=False): - self.outcomes_draw_folder_path_str = sim_results_folder_path_str - self.datestamp = in_datestamp - self.draw_nmb = in_draw_nmb - self.png = in_png, """bool indicating whether we want to save all figures not only as pdf, but also as png""" - - draw_folder_path = os.path.join(Path(scenario_results_folder_path), str(self.draw_nmb)) - runs_folders = [name for name in os.listdir(draw_folder_path) if \ - os.path.isdir(os.path.join(draw_folder_path, name)) and name.isdigit()] - self.total_runs = len(runs_folders) - - self.__w_logs_dict = {} - for run_nmb in range(0, self.total_runs): - print(f"run {run_nmb} ...") - sim_results_folder_draw_run_path_str = sim_results_folder_path_str + f'/{draw_nmb}/{run_nmb}/' - sim_results_file_name_prefix = scenario_filename - sim_results_file_name_extension = '.log.gz' - gz_results_file_path = Path(glob.glob(os.path.join(sim_results_folder_draw_run_path_str, - f"{sim_results_file_name_prefix}*{sim_results_file_name_extension}"))[0]) - - # Path to the decompressed .log file - self.__log_file_path = gz_results_file_path.with_suffix('') - # Decompress the .log.gz file - with gzip.open(gz_results_file_path, 'rb') as f_in: - with open(self.__log_file_path, 'wb') as f_out: - shutil.copyfileobj(f_in, f_out) - - # Parse wasting logs for each run - self.__w_logs_dict[run_nmb] = parse_log_file(self.__log_file_path)['tlo.methods.wasting'] - - # TODO: Why it prints the messages from parse_log_file() twice? - # parse scaling factor log - # self.__scaling_factor = \ - # parse_log_file(self.__log_file_path)['tlo.methods.population']['scaling_factor'].set_index('date').loc[ - # '2010-01-01', 'scaling_factor' - # ] - - # wasting types description - self.__wasting_types_desc = {'WHZ<-3': 'severe wasting', - '-3<=WHZ<-2': 'moderate wasting', - 'WHZ>=-2': 'no wasting'} - - self.fig_files = [] - - cycle = plt.rcParams['axes.prop_cycle'].by_key()['color'] - # # define colo(u)rs to use: - self.__colors_model = { - 'severe wasting': cycle[0], # #1f77b4 - 'moderate wasting': cycle[1], # #ff7f0e - 'SAM': '#B372B7', - 'MAM': '#D1BCD2', - } - self.__colors_data = { - 'severe wasting': '#82C1EC', - 'moderate wasting': '#C71E1E', - } - self.__colors_init_data = { - 'severe wasting': '#0E53EA', - 'moderate wasting': '#FFA783', - } - - def save_fig__store_pdf_file(self, fig, fig_output_name: str, run_nmb) -> None: - full_path_and_file_name = self.outcomes_draw_folder_path_str + f'/{self.draw_nmb}/{run_nmb}/' + fig_output_name + \ - f'_{self.draw_nmb}_{run_nmb}' - if self.png: #TODO: doesn't seem to be working - fig.savefig(full_path_and_file_name + '.png', format='png') - fig.savefig(full_path_and_file_name + '.pdf', format='pdf') - self.fig_files.append(full_path_and_file_name + '.pdf') - - def plot_wasting_incidence(self): - """ plot the incidence of wasting over time """ - for run_nmb in range(0, self.total_runs): - w_inc_df = self.__w_logs_dict[run_nmb]['wasting_incidence_count'] - w_inc_df = w_inc_df.set_index(w_inc_df.date.dt.year) - w_inc_df = w_inc_df.drop(columns='date') - # check no incidence of well-nourished - all_zeros = w_inc_df['WHZ>=-2'].apply(lambda x: all(value == 0 for value in x.values())) - assert all(all_zeros) - w_inc_df = w_inc_df[["WHZ<-3", "-3<=WHZ<-2"]] - - pop_sizes_df = self.__w_logs_dict[run_nmb]['pop sizes'] - pop_sizes_df = pop_sizes_df.set_index(pop_sizes_df.date.dt.year) - pop_sizes_df = pop_sizes_df.drop(columns='date') - po_sizes_to_keep = [col for col in pop_sizes_df.columns if - col.startswith('total__') and col not in ['total__under5']] - age_gps_total_pop_sizes_df = pop_sizes_df[po_sizes_to_keep].copy() - age_gps_total_pop_sizes_df['0y'] = \ - age_gps_total_pop_sizes_df['total__0_5mo'] + age_gps_total_pop_sizes_df['total__6_11mo'] - age_gps_total_pop_sizes_df = age_gps_total_pop_sizes_df.drop(columns=['total__0_5mo', 'total__6_11mo']) - age_gps_total_pop_sizes_df = age_gps_total_pop_sizes_df.rename(columns={ - 'total__12_23mo': '1y', - 'total__24_35mo': '2y', - 'total__36_47mo': '3y', - 'total__48_59mo': '4y', - 'total__5y+': '5+y' - }) - - # get age_years, doesn't matter what wasting category you choose, - # they all have same age groups - age_years = list(w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys()) - # age_years.remove('5+y') - - _row_counter = 0 - _col_counter = 0 - # plot setup - fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 6)) - axes[1, 2].axis('off') # 5+y has no data (no new cases in 5+y), its space is used to display the label - for age in age_years: - plotting = pd.DataFrame() - for state in w_inc_df.columns: - plotting[state] = \ - w_inc_df.apply(lambda row: row[state][age], axis=1) - # remove sev cases from mod cases (all sev cases went through mod state) - plotting["-3<=WHZ<-2"] = plotting.apply(lambda row: max(row["-3<=WHZ<-2"] - row["WHZ<-3"], 0), axis=1) - # calculate props within the age group - plotting = plotting.div(age_gps_total_pop_sizes_df[age], axis=0) - plotting = plotting.rename(columns=self.__wasting_types_desc) - # filter data to include only years from 2015 onwards - plotting = plotting.loc[plotting.index >= 2015] - # check for invalid values - if (plotting < 0).any().any() or (plotting > 1).any().any(): - print(f"Warning plot_wasting_incidence: Invalid values detected in plotting data for age group {age}:") - print(plotting) - - ax = plotting.plot(kind='bar', stacked=True, - ax=axes[_row_counter, _col_counter], - title=f"{age} old")#, - #ylim=[0, 1]) - show_legend = (_row_counter == 1 and _col_counter == 2) - # show_x_axis_label = (_row_counter == 0 and _col_counter == 2) - if show_legend: - ax.legend(loc='center', fontsize=legend_fontsize) - ax.set_title('') - else: - ax.get_legend().remove() - # if show_x_axis_label: - # ax.set_xlabel('Year') # TODO: this is not working - ax.set_xlabel('year') - ax.set_ylabel('proportion (within age group)') - # move to another row - if _col_counter == 2: - _row_counter += 1 - _col_counter = -1 - _col_counter += 1 # increment column counter - fig.suptitle('Annual incidence of wasting among the age group', fontsize=title_fontsize) #, weight='bold') - fig.tight_layout() - fig_output_name = ('wasting_incidence__' + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) - # plt.show() - - # def plot_wasting_incidence_mod_to_sev_props(self): - # """ plot the incidence of wasting over time """ - # w_inc_df = self.__w_logs_dict['wasting_incidence_count'] - # w_inc_df = w_inc_df.set_index(w_inc_df.date.dt.year) - # w_inc_df = w_inc_df.drop(columns='date') - # # check no incidence of well-nourished - # all_zeros = w_inc_df['WHZ>=-2'].apply(lambda x: all(value == 0 for value in x.values())) - # assert all(all_zeros) - # w_inc_df = w_inc_df[["WHZ<-3", "-3<=WHZ<-2"]] - # # get age_years, doesn't matter what wasting category you choose, - # # they all have same age groups - # age_years = list(w_inc_df.loc[w_inc_df.index[0], 'WHZ<-3'].keys( - # - # )) - # age_years.remove('5+y') - # - # _row_counter = 0 - # _col_counter = 0 - # # plot setup - # fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 6)) - # fig.delaxes(axes[1, 2]) - # for _age in age_years: - # new_df = pd.DataFrame() - # for state in w_inc_df.columns: - # new_df[state] = \ - # w_inc_df.apply(lambda row: row[state][_age], axis=1) - # # convert into proportions - # new_df = new_df.apply(lambda _row: _row / _row.sum(), axis=1) - # plotting = new_df.rename(columns=self.__wasting_types_desc) - # ax = plotting.plot(kind='bar', stacked=True, - # ax=axes[_row_counter, _col_counter], - # title=f"incidence of wasting in {_age} old", - # ylim=[0, 1]) - # ax.legend(loc='lower right') - # ax.set_xlabel('year') - # ax.set_ylabel('proportion') - # # move to another row - # if _col_counter == 2: - # _row_counter += 1 - # _col_counter = -1 - # _col_counter += 1 # increment column counter - # - # handles, labels = axes[1, 1].get_legend_handles_labels() - # fig.legend(handles, labels, loc='center left', bbox_to_anchor=(1.05, 0.5)) - # fig_output_name = ('wasting_incidence_mod_to_sev_props__' + self.datestamp) - # fig.tight_layout() - # self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) - # # plt.show() - - def plot_wasting_length(self): - """ plot the average length of wasting over time """ - - if 'wasting_length_avg' in self.__w_logs_dict: - w_length_df = self.__w_logs_dict['wasting_length_avg'] - w_length_df = w_length_df.set_index(w_length_df.date.dt.year) - w_length_df = w_length_df.drop(columns='date') - # get age_years, doesn't matter from which dict - age_years = list(w_length_df.loc[w_length_df.index[0], 'mod_MAM_tx_full_recov'].keys()) - # age_years.remove('5+y') - w_length_df = w_length_df.loc[:, ['mod_MAM_nat_full_recov', - 'mod_SAM_nat_full_recov', 'mod_SAM_nat_recov_to_MAM', - 'sev_SAM_nat_full_recov', 'sev_SAM_nat_recov_to_MAM', - 'mod_MAM_tx/nat_full_recov', - 'mod_SAM_tx_full_recov', 'mod_SAM_tx/nat_recov_to_MAM', - 'sev_SAM_tx_full_recov', 'sev_SAM_tx/nat_recov_to_MAM', - 'mod_not_yet_recovered', - 'sev_not_yet_recovered']] - - for recov_opt in w_length_df.columns: - _row_counter = 0 - _col_counter = 0 - # plot setup - fig, axes = plt.subplots(nrows=2, ncols=3, sharex=True, sharey=True, figsize=(10, 7)) - # axes[1, 2].axis('off') # 5+y has no data (no new cases in 5+y), its space is used to display the label - for _age in age_years: - plotting = pd.DataFrame() - # dict to dataframe - plotting[recov_opt] = \ - w_length_df.apply(lambda row: row[recov_opt][_age], axis=1) - - if recov_opt.startswith("mod_"): - colour_to_use = self.__colors_model['moderate wasting'] - y_upper_lim = 355 - else: - colour_to_use = self.__colors_model['severe wasting'] - y_upper_lim = 1000 - if recov_opt.endswith("not_yet_recovered"): - y_upper_lim = 4000 - - ax = plotting.plot(kind='bar', stacked=False, - ax=axes[_row_counter, _col_counter], - title=f"length of wasting in {_age} old", - color=colour_to_use, - ylim=[0, y_upper_lim]) - # show_legend = (_row_counter == 0 and _col_counter == 0) - # # show_x_axis_label = (_row_counter == 0 and _col_counter == 2) - # if show_legend: - # ax.legend(loc='upper right', bbox_to_anchor=(0.5, 1.2), - # fancybox=True, shadow=True, ncol=5) - # else: - ax.get_legend().remove() - # if show_x_axis_label: - # ax.set_xlabel('Year') # TODO: this is not working - ax.set_xlabel('year') - ax.set_ylabel('avg length of wasting (days)') - # move to another row - if _col_counter == 2: - _row_counter += 1 - _col_counter = -1 - _col_counter += 1 # increment column counter - - fig.suptitle(f'{recov_opt}', fontsize=16) - # Adjust layout to make room for the suptitle - fig.tight_layout(rect=[0, 0, 1, 0.95]) - fig_output_name = ('wasting_length__' + recov_opt + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) - # plt.show(`) - - def plot_wasting_initial_overall_prevalence(self): - """ plot wasting prevalence of all age groups for the year 2010. Proportions are obtained by getting a total - number of children wasted (moderately and severely) divided by the total number of children less than 5 years""" - for run_nmb in range(0, self.total_runs): - ## Prevalence at 2010, ie data from the same source used to draw initial prevalence by age group - w_prev_calib_data_years_only_df = pd.DataFrame({ - 'sev_wast_calib': [0.015], - 'mod_wast_calib': [0.025] - }, index=[2010]) - date_range = pd.Index([2010], name='date') - w_prev_calib = pd.DataFrame(index=date_range) - # filling missing values with 0 - w_prev_calib_df = w_prev_calib.merge( - w_prev_calib_data_years_only_df, left_index=True, right_index=True, how='left' - ).fillna(0) - - ## Initial prevalence at the beginning of 2010 - model - init_w_prev_2010_only_df = self.__w_logs_dict[run_nmb]["wasting_init_prevalence_props"] - init_w_prev_2010_only_df = init_w_prev_2010_only_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']].rename( - columns={'total_sev_under5_prop': 'total_init_sev_under5_prop', 'total_mod_under5_prop': 'total_init_mod_under5_prop'} - ) - init_w_prev_2010_only_df = init_w_prev_2010_only_df.set_index(init_w_prev_2010_only_df.date.dt.year) - init_w_prev_2010_only_df = init_w_prev_2010_only_df.drop(columns='date') - init_w_prev_2010_only_df = init_w_prev_2010_only_df.loc[[2010]] - init_w_prev_df = pd.DataFrame(index=date_range) - # filling missing values with 0 - init_w_prev_df = init_w_prev_df.merge( - init_w_prev_2010_only_df, left_index=True, right_index=True, how='left' - ).fillna(0) - - w_prev_calib_and_init_df = pd.merge(init_w_prev_df, w_prev_calib_df, on='date') - columns_to_plot = [ - ['total_init_sev_under5_prop', 'total_init_mod_under5_prop'], - ['sev_wast_calib', 'mod_wast_calib'], - ] - colors_to_plot = { - 'total_init_sev_under5_prop': self.__colors_init_data['severe wasting'], - 'total_init_mod_under5_prop': self.__colors_init_data['moderate wasting'], - 'sev_wast_calib': self.__colors_data['severe wasting'], - 'mod_wast_calib': self.__colors_data['moderate wasting'], - } - labels_to_plot = { - 'total_init_sev_under5_prop': 'severe wasting (initial)', - 'total_init_mod_under5_prop': 'moderate wasting (initial)', - 'sev_wast_calib': 'severe wasting (data)', - 'mod_wast_calib': 'moderate wasting (data)', - } - - fig, ax = plt.subplots() - bar_spots = len(columns_to_plot) - bar_width = 0.3 / bar_spots - pos = np.arange(len(w_prev_calib_and_init_df)) - dodge_offsets = np.linspace(-bar_spots * bar_width / 2, bar_spots * bar_width / 2, bar_spots, endpoint=False) - for columns, offset in zip(columns_to_plot, dodge_offsets): - bottom = 0 - for col in ([columns] if isinstance(columns, str) else columns): - ax.bar(pos + offset, w_prev_calib_and_init_df[col], bottom=bottom, width=bar_width, align='edge', - label=labels_to_plot[col], color=colors_to_plot[col]) - bottom += w_prev_calib_and_init_df[col] - ax.set_xticks(pos) - ax.set_xticklabels(w_prev_calib_and_init_df.index, rotation=90) - ax.set_title(r"Overall wasting prevalence $\bf{at}$ $\bf{initiation}$ (2010)", fontsize=title_fontsize-1) - ax.set_ylabel('proportion of wasted children in the year') - ax.set_xlabel('year') - ax.set_ylim([0, 0.131]) - ax.legend(fontsize=legend_fontsize) - plt.tight_layout() - fig_output_name = ('wasting_initial_overall_prevalence__' + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) - # plt.show() - - def plot_wasting_initial_prevalence_by_age_group(self): - """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of - children wasted in a particular age-group divided by the total number of children per that age-group""" - for run_nmb in range(0, self.total_runs): - # Initial prevalence at the beginning of 2010 - model - w_prev_df = self.__w_logs_dict[run_nmb]["wasting_init_prevalence_props"] - w_prev_df = w_prev_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) - w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) - w_prev_df = w_prev_df.drop(columns='date') - - # 2010 prevalence calibration data - # TODO: load data_2010 from the resource file: - # resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' - data_2010 = { - 'wasted_calib': [7.0, 13.0, 12.7, 2.4, 2.7, 1.9, 0.0], - 'sev_wast_calib': [2.1, 7.1, 4.7, 0.9, 0.7, 0.6, 0.0] - } - data_2010['mod_wast_calib'] = \ - [(w - s)/100 for w, s in zip(data_2010['wasted_calib'], data_2010['sev_wast_calib'])] - data_2010['sev_wast_calib'] = \ - [s/100 for s in data_2010['sev_wast_calib']] - - # Prepare plotting data - plotting_model = {'severe wasting': {}, 'moderate wasting': {}} - for col in w_prev_df.columns: - prefix, age_group = col.split('__') - if prefix == 'sev': - plotting_model['severe wasting'][age_group] = w_prev_df[col].values[0] - elif prefix == 'mod': - plotting_model['moderate wasting'][age_group] = w_prev_df[col].values[0] - plotting_model = pd.DataFrame(plotting_model) - - plotting_calib = {'severe wasting': {}, 'moderate wasting': {}} - age_groups = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] - for i, age_group in enumerate(age_groups): - plotting_calib['severe wasting'][age_group] = data_2010['sev_wast_calib'][i] - plotting_calib['moderate wasting'][age_group] = data_2010['mod_wast_calib'][i] - plotting_calib = pd.DataFrame(plotting_calib) - - plotting_model = plotting_model.reindex(age_groups) - plotting_calib = plotting_calib.reindex(age_groups) - - # Plot wasting prevalence - fig, ax = plt.subplots(figsize=(10, 6)) - bar_width = 0.35 - # Set positions of bars on x-axis - r1 = range(len(plotting_model)) - r2 = [x + bar_width for x in r1] - - # Plot the first set of bars (model data) - ax.bar(r1, plotting_model['severe wasting'], - color=self.__colors_init_data['severe wasting'], width=bar_width, - label='severe wasting (initial)') - ax.bar(r1, plotting_model['moderate wasting'], bottom=plotting_model['severe wasting'], - color=self.__colors_init_data['moderate wasting'], width=bar_width, - label='moderate wasting (initial)') - - # Plot the second set of bars (calibration data) - ax.bar(r2, plotting_calib['severe wasting'], - color=self.__colors_data['severe wasting'], width=bar_width, - label='severe wasting (data)') - ax.bar(r2, plotting_calib['moderate wasting'], bottom=plotting_calib['severe wasting'], - color=self.__colors_data['moderate wasting'], width=bar_width, - label='moderate wasting (data)') - - ax.set_xlabel('age group') - ax.set_ylabel('proportion') - ax.set_title( - r"Wasting prevalence in children 0-59 months per each age group $\bf{at}$ $\bf{initiation}$ (2010)", - fontsize=title_fontsize-1) - ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) - ax.set_xticklabels(age_groups) - ax.set_ylim([0, 0.16]) - ax.legend(fontsize=legend_fontsize) - - # Adjust the layout to make space for the footnote - plt.subplots_adjust(top=0.15) # Adjust the top margin - # Add footnote - fig.figure.text(0.43, 0.95, - "proportion = number of wasted children in the age group " - "/ total number of children in the age group", - ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) - plt.tight_layout() - fig_output_name = ('wasting_initial_prevalence_per_each_age_group__' + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) - # plt.show() - - def plot_wasting_prevalence_per_year(self): - """ plot wasting prevalence of all age groups per year. Proportions are obtained by getting a total number of - children wasted divide by the total number of children less than 5 years""" - for run_nmb in range(0, self.total_runs): - ## Prevalence at some years - data (2010 are the data used to draw initial prevalence) - # TODO: add calibration data into the resource file: - # resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' - # and load here and for initial overall prev from the RF - w_prev_calib_data_years_only_df = pd.DataFrame({ - 'sev_wast_calib': [0.015, 0.011, 0.006, 0.007], - 'mod_wast_calib': [0.025, 0.027, 0.021, 0.019] - }, index=[2010, 2013, 2015, 2019]) - date_range = pd.Index(range(2010, 2031), name='date') - w_prev_calib = pd.DataFrame(index=date_range) - # filling missing values with 0 - w_prev_calib_df = w_prev_calib.merge( - w_prev_calib_data_years_only_df, left_index=True, right_index=True, how='left' - ).fillna(0) - - ## Prevalence at the end of years - model - w_prev_df = self.__w_logs_dict[run_nmb]["wasting_prevalence_props"] - w_prev_df = w_prev_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']] - w_prev_df = w_prev_df.set_index(w_prev_df.date.dt.year) - w_prev_df = w_prev_df.drop(columns='date') - - ## Initial prevalence at the beginning of 2010 - model - init_w_prev_2010_only_df = self.__w_logs_dict[run_nmb]["wasting_init_prevalence_props"] - init_w_prev_2010_only_df = init_w_prev_2010_only_df[['date', 'total_sev_under5_prop', 'total_mod_under5_prop']].rename( - columns={'total_sev_under5_prop': 'total_init_sev_under5_prop', 'total_mod_under5_prop': 'total_init_mod_under5_prop'} - ) - init_w_prev_2010_only_df = init_w_prev_2010_only_df.set_index(init_w_prev_2010_only_df.date.dt.year) - init_w_prev_2010_only_df = init_w_prev_2010_only_df.drop(columns='date') - init_w_prev_2010_only_df = init_w_prev_2010_only_df.loc[[2010]] - init_w_prev_df = pd.DataFrame(index=date_range) - # filling missing values with 0 - init_w_prev_df = init_w_prev_df.merge( - init_w_prev_2010_only_df, left_index=True, right_index=True, how='left' - ).fillna(0) - - w_prev_calib_and_init_df = pd.merge(init_w_prev_df, w_prev_calib_df, on='date') - w_prev_plot_df = pd.merge(w_prev_df, w_prev_calib_and_init_df, on='date').loc[lambda df: df.index >= 2015] - columns_to_plot = [ - ['total_init_sev_under5_prop', 'total_init_mod_under5_prop'], - ['total_sev_under5_prop', 'total_mod_under5_prop'], - ['sev_wast_calib', 'mod_wast_calib'], - ] - colors_to_plot = { - 'total_sev_under5_prop': self.__colors_model['severe wasting'], - 'total_mod_under5_prop': self.__colors_model['moderate wasting'], - 'sev_wast_calib': self.__colors_data['severe wasting'], - 'mod_wast_calib': self.__colors_data['moderate wasting'], - 'total_init_sev_under5_prop': self.__colors_init_data['severe wasting'], - 'total_init_mod_under5_prop': self.__colors_init_data['moderate wasting'] - - } - labels_to_plot = { - 'total_sev_under5_prop': 'severe wasting (model)', - 'total_mod_under5_prop': 'moderate wasting (model)', - 'sev_wast_calib': 'severe wasting (data)', - 'mod_wast_calib': 'moderate wasting (data)', - 'total_init_sev_under5_prop': 'severe wasting (initial)', - 'total_init_mod_under5_prop': 'moderate wasting (initial)' - } - - fig, ax = plt.subplots() - bar_spots = len(columns_to_plot) - bar_width = 0.8 / bar_spots - pos = np.arange(len(w_prev_plot_df)) - dodge_offsets = np.linspace(-bar_spots * bar_width / 2, bar_spots * bar_width / 2, bar_spots, endpoint=False) - for columns, offset in zip(columns_to_plot, dodge_offsets): - bottom = 0 - for col in ([columns] if isinstance(columns, str) else columns): - ax.bar(pos + offset, w_prev_plot_df[col], bottom=bottom, width=bar_width, align='edge', - label=labels_to_plot[col], color=colors_to_plot[col]) - bottom += w_prev_plot_df[col] - ax.set_xticks(pos) - ax.set_xticklabels(w_prev_plot_df.index, rotation=90) - ax.set_title("Wasting prevalence in children 0-59 months per year", fontsize=title_fontsize-6) - ax.set_ylabel('proportion of wasted children in the year') - ax.set_xlabel('year') - ax.set_ylim([0, 0.06]) - ax.legend(fontsize=legend_fontsize-4) - plt.tight_layout() - fig_output_name = ('wasting_prevalence_per_year__' + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) - # plt.show() - - def plot_wasting_prevalence_by_age_group(self): - """ Plot wasting prevalence per each age group. Proportions are obtained by getting a total number of - children wasted in a particular age-group divided by the total number of children per that age-group""" - for run_nmb in range(0, self.total_runs): - age_groups = ['0_5mo', '6_11mo', '12_23mo', '24_35mo', '36_47mo', '48_59mo', '5y+'] - - # ### Calibration Data - # Load calibration data from CSV file - wasting_calib_data_path = resources_path / 'ResourceFile_Wasting/wasting_prevalence_and_sample_size.csv' - wasting_calib_data_df = pd.read_csv(wasting_calib_data_path, index_col='year') - - # Recalculate data to proportions (0 to 1) and separate mod wast as (wasted - sev wast) - wasting_calib_data_df['mod_wast_calib'] = \ - (wasting_calib_data_df['prev any wast (%)'] - wasting_calib_data_df['prev severe wast (%)']) / 100 - wasting_calib_data_df['sev_wast_calib'] = wasting_calib_data_df['prev severe wast (%)'] / 100 - - # Pivot the data to get the required format - w_prev_calib_data_df = wasting_calib_data_df.pivot(columns='age_group (months)', - values=['mod_wast_calib', 'sev_wast_calib']) - w_prev_calib_data_df.columns = [f'{col[0][:3]}__{col[1]}' for col in w_prev_calib_data_df.columns] - - # Load calibration sample sizes from CSV file - sample_sizes_calib_data_df = wasting_calib_data_df.pivot(columns='age_group (months)', values='sample_size') - sample_sizes_calib_data_df = sample_sizes_calib_data_df.reindex(columns=age_groups) - - # ### Model Outcomes - # Load modelled prevalence proportions - w_prev_model_df = self.__w_logs_dict[run_nmb]["wasting_prevalence_props"] - w_prev_model_df = w_prev_model_df.drop(columns={'total_mod_under5_prop', 'total_sev_under5_prop'}) - w_prev_model_df = w_prev_model_df.set_index(w_prev_model_df.date.dt.year) - w_prev_model_df = w_prev_model_df.drop(columns='date') - - # Load modelled population sizes - pop_sizes_model_df = self.__w_logs_dict[run_nmb]['pop sizes'] - pop_sizes_model_df = pop_sizes_model_df.set_index(pop_sizes_model_df.date.dt.year).rename_axis('year') - pop_sizes_model_df = pop_sizes_model_df.drop(columns='date') - pop_sizes_model_df = pop_sizes_model_df.filter(like='total__').rename( - lambda x: x.replace('total__', ''), axis=1 - )[age_groups] - - for year_calib in w_prev_calib_data_df.index: - w_prev_calib_data_year_df = w_prev_calib_data_df.loc[w_prev_calib_data_df.index == year_calib] - w_prev_model_year_df = w_prev_model_df.loc[w_prev_model_df.index == year_calib] - - def create_plotting_data(df, df_name): - plotting = {'severe wasting': {}, 'moderate wasting': {}, 'any wasting': {}} - for col in df.columns: - prefix, agegp = col.split('__') - if prefix == 'sev': - plotting['severe wasting'][agegp] = df[col].values[0] - elif prefix == 'mod': - plotting['moderate wasting'][agegp] = df[col].values[0] - plotting['any wasting'][agegp] = df[col].values[0] + df[f'sev__{agegp}'].values[0] - plotting_df = pd.DataFrame(plotting) - assert set(plotting_df.index) == set(age_groups),\ - f"age groups in {df_name} are not in line with the age_groups." - plotting_df = plotting_df.reindex(age_groups) - return plotting_df - - # Create plotting data for both dataframes - plotting_model = create_plotting_data(w_prev_model_year_df, 'w_prev_model_year_df') - plotting_calib = create_plotting_data(w_prev_calib_data_year_df, 'w_prev_calib_data_year_df') - - # Calculate 95% confidence intervals for both - sample_sizes_calib_data_year = sample_sizes_calib_data_df.loc[year_calib, :] - sample_sizes_model_year = pop_sizes_model_df.loc[year_calib, :] - - confidence_level = 0.95 - z_score = stats.norm.ppf(1 - (1 - confidence_level) / 2) - - calib_data_margin_of_error_any_wast = [] - calib_data_margin_of_error_sev_wast = [] - for p, n in zip(plotting_calib['any wasting'].reindex(age_groups[:-1]), sample_sizes_calib_data_year[:-1]): - calib_data_margin_of_error_any_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) - for p, n in \ - zip(plotting_calib['severe wasting'].reindex(age_groups[:-1]),sample_sizes_calib_data_year[:-1]): - calib_data_margin_of_error_sev_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) - model_margin_of_error_any_wast = [] - model_margin_of_error_sev_wast = [] - for p, n in zip(plotting_model['any wasting'].reindex(age_groups[:-1]), sample_sizes_model_year[:-1]): - model_margin_of_error_any_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) - for p, n in zip(plotting_model['severe wasting'].reindex(age_groups[:-1]), sample_sizes_model_year[:-1]): - model_margin_of_error_sev_wast.append(z_score * np.sqrt((p * (1 - p)) / n)) - - # ##### - # Plot wasting prevalence - fig, ax = plt.subplots(figsize=(10, 6)) - bar_width = 0.35 - # Set positions of bars on x-axis - r1 = range(len(plotting_model)) - r2 = [x + bar_width for x in r1] - - # Plot the first set of bars (model data) - ax.bar(r1, plotting_model['severe wasting'], - color=self.__colors_model['severe wasting'], width=bar_width, - label='severe wasting (model)') - ax.bar(r1, plotting_model['moderate wasting'], bottom=plotting_model['severe wasting'], - color=self.__colors_model['moderate wasting'], width=bar_width, - label='moderate wasting (model)') - - # Add the confidence intervals - for i, age_group in enumerate(age_groups[0:len(age_groups)-1]): - ax.errorbar(r1[i], plotting_model['any wasting'][age_group], - yerr=[model_margin_of_error_any_wast[i]], - capsize=5, fmt='none', color='black') - ax.errorbar(r1[i], plotting_model['severe wasting'][age_group], - yerr=[model_margin_of_error_sev_wast[i]], - capsize=5, fmt='none', color='white') - - # Plot the second set of bars (calibration data) - ax.bar(r2, plotting_calib['severe wasting'], - color=self.__colors_data['severe wasting'], width=bar_width, - label='severe wasting (data)') - ax.bar(r2, plotting_calib['moderate wasting'], bottom=plotting_calib['severe wasting'], - color=self.__colors_data['moderate wasting'], width=bar_width, - label='moderate wasting (data)') - - # Add the confidence intervals - for i, age_group in enumerate(age_groups[0:len(age_groups)-1]): - ax.errorbar(r2[i], plotting_calib['any wasting'][age_group], - yerr=[calib_data_margin_of_error_any_wast[i]], - capsize=5, fmt='none', color='black') - ax.errorbar(r2[i], plotting_calib['severe wasting'][age_group], - yerr=[calib_data_margin_of_error_sev_wast[i]], - capsize=5, fmt='none', color='white') - - ax.set_xlabel('age group') - ax.set_ylabel('proportion') - ax.set_title(f"Wasting prevalence in children 0-59 months per each age group in {year_calib}", - fontsize=title_fontsize-1) - ax.set_xticks([r + bar_width / 2 for r in range(len(plotting_model))]) - ax.set_xticklabels(age_groups) - ax.set_ylim([0, 0.12]) - ax.legend(fontsize=legend_fontsize) - - # Adjust the layout to make space for the footnote - plt.subplots_adjust(top=0.15) # Adjust the bottom margin - # Add footnote - fig.figure.text(0.43, 0.95, - "proportion = number of wasted children in the age group " - "/ total number of children in the age group", - ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) - - plt.tight_layout() - fig_output_name = (f'wasting_prevalence_per_each_age_group_{year_calib}__' + self.datestamp) - if year_calib in [2015, 2019]: - self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) - # plt.show() - - def plot_model_gbd_deaths_incl_burnin_period(self): - """ compare model and GBD deaths 2010-2014 & 2015-2019 """ - for run_nmb in range(0, self.total_runs): - death_compare = \ - compare_number_of_deaths(self.__log_file_path, resources_path) - fig, ax = plt.subplots(figsize=(10, 6)) - # cause of death as of GBD 2019 'Protein-energy malnutrition' was labeled as 'Childhood Undernutrition' in - # wasting module - plot_df = death_compare.loc[(['2010-2014', '2015-2019'], - slice(None), ['0-4'], 'Childhood Undernutrition' - )].groupby('period').sum() - plotting = plot_df.loc[['2010-2014', '2015-2019']] - ax = plotting['model'].plot.bar(label='Model', ax=ax, rot=0) - ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, - yerr=[plotting.GBD_lower, plotting.GBD_upper], - fmt='o', color='#000', label="GBD") - - ax.set_title('Average direct deaths per year due to severe acute malnutrition in children under 5', fontsize=title_fontsize-1) - ax.set_xlabel("time period") - ax.set_ylabel("number of deaths") - ax.legend(loc='upper center', fontsize=legend_fontsize) - fig.tight_layout() - # Adjust the layout to make space for the footnote - plt.subplots_adjust(bottom=0.15) # Adjust the bottom margin - # Add footnote - fig.figure.text(0.5, 0.02, - "Model output against Global Burden of Diseases (GBD) study data", - ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) - fig_output_name = ('model_gbd_deaths_incl_burnin__' + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) - # plt.show() - - def plot_model_gbd_deaths_excl_burnin_period(self): - """ compare model and GBD deaths 2015-2019 """ - for run_nmb in range(0, self.total_runs): - death_compare = \ - compare_number_of_deaths(self.__log_file_path, resources_path) - fig, ax = plt.subplots(figsize=(10, 6)) - # cause of death as of GBD 2019 'Protein-energy malnutrition' was labeled as 'Childhood Undernutrition' in - # wasting module - plot_df = death_compare.loc[(['2015-2019'], - slice(None), ['0-4'], 'Childhood Undernutrition' - )].groupby('period').sum() - plotting = plot_df.loc[['2015-2019']] - ax = plotting['model'].plot.bar(label='Model', ax=ax, rot=0) - ax.errorbar(x=plotting['model'].index, y=plotting.GBD_mean, - yerr=[plotting.GBD_lower, plotting.GBD_upper], - fmt='o', color='#000', label="GBD") - - ax.set_title('Average direct deaths per year due to severe acute malnutrition in children under 5', - fontsize=title_fontsize - 1) - ax.set_xlabel("time period") - ax.set_ylabel("number of deaths") - ax.legend(loc='upper right', fontsize=legend_fontsize) - fig.tight_layout() - # Adjust the layout to make space for the footnote - plt.subplots_adjust(bottom=0.15) # Adjust the bottom margin - # Add footnote - fig.figure.text(0.5, 0.02, - "Model output against Global Burden of Diseases (GBD) study data", - ha="center", fontsize=10, bbox={"facecolor": "gray", "alpha": 0.3, "pad": 5}) - fig_output_name = ('model_gbd_deaths_excl_burnin__' + self.datestamp) - self.save_fig__store_pdf_file(fig, fig_output_name, run_nmb) - # plt.show() - - def plot_all_figs_in_one_pdf(self, in_outcome_figs_folder): - for run_nmb in range(0, self.total_runs): - output_file_path = \ - in_outcome_figs_folder / f'wasting_all_figures__{self.datestamp}_{self.draw_nmb}_{run_nmb}.pdf' - # Remove the existing output file if it exists to ensure a clean start - if os.path.exists(output_file_path): - os.remove(output_file_path) - - # Assert that the file doesn't exist anymore after removal - assert not os.path.exists(output_file_path), "The file was not successfully removed." - - # Merge the PDF files - # Create a PDF writer object - pdf_writer = PdfWriter() - - # Iterate through the figure files and add each to the writer - for fig_file in self.fig_files: - pdf_reader = PdfReader(fig_file) - for page_num in range(len(pdf_reader.pages)): - page = pdf_reader.pages[page_num] - pdf_writer.add_page(page) - - # Write the merged PDF to a file - with open(output_file_path, 'wb') as out_file: - pdf_writer.write(out_file) - - -if __name__ == "__main__": - - # Path to the resource files used by the disease and intervention methods - resources_path = Path("./resources") - - # Find scenario_results_folder_path associated with a given batch_file (and get most recent [-1]) - scenario_outputs_path = Path(outputs_path / scenario_type) - scenario_results_folder_path = get_scenario_outputs(scenario_filename, scenario_outputs_path)[-1] - scenario_results_folder_name = scenario_results_folder_path.name - # Get the datestamp - assert scenario_results_folder_name.startswith(scenario_filename + '-'),\ - "The scenario output name does not correspond with the set scenario_filename." - datestamp = scenario_results_folder_name[(len(scenario_filename) + 1):] - - draws_folders = [name for name in os.listdir(scenario_results_folder_path) if \ - os.path.isdir(os.path.join(scenario_results_folder_path, name)) and name.isdigit()] - - # Analyse each draw with stochasticity given by runs - for draw_nmb in range(0, len(draws_folders)): - print(f"Analysing {draw_nmb=} ...") - time_start = time.time() - - # initialise the wasting class - wast_scenario_analyses = \ - WastingScenarioAnalyses(scenario_type, str(scenario_results_folder_path), datestamp, draw_nmb) - - # plot wasting incidence - wast_scenario_analyses.plot_wasting_incidence() - - # plot wasting incidence mod:sev proportions - # wasting_analyses.plot_wasting_incidence_mod_to_sev_props() - - # plot wasting length - # wasting_analyses.plot_wasting_length() - - # plot initial wasting prevalence - wast_scenario_analyses.plot_wasting_initial_overall_prevalence() - wast_scenario_analyses.plot_wasting_initial_prevalence_by_age_group() - - # plot prevalence through simulation - wast_scenario_analyses.plot_wasting_prevalence_per_year() - wast_scenario_analyses.plot_wasting_prevalence_by_age_group() - - # plot wasting deaths as compared to GBD deaths - # wasting_analyses.plot_model_gbd_deaths_incl_burnin_period() - wast_scenario_analyses.plot_model_gbd_deaths_excl_burnin_period() - - # ### Save all figures in one pdf - outcome_figs_folder = scenario_results_folder_path / '_outcome_figures' - outcome_figs_folder.mkdir(parents=True, exist_ok=True) - wast_scenario_analyses.plot_all_figs_in_one_pdf(outcome_figs_folder) - - time_end = time.time() - print(f"... finished in (s): {(time_end - time_start)}") - - total_time_end = time.time() - print(f"total running time (s): {(total_time_end - total_time_start)}") - - From 7e1894d5e1de6c6436091bd2f95f1320b5b3b506 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 9 Jun 2025 01:02:01 +0100 Subject: [PATCH 538/755] run_interv_analysis_wast & analysis_utility_fncs_wast: PEP8 --- .../analysis_utility_functions_wast.py | 3 ++- .../run_interventions_analysis_wasting.py | 12 ++---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py index ba6f51a048..6345a06eaf 100644 --- a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py +++ b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py @@ -1,8 +1,9 @@ +from pathlib import Path + import numpy as np import pandas as pd import scipy.stats as st from matplotlib import pyplot as plt -from pathlib import Path from tlo.analysis.utils import extract_results diff --git a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py index 1a412df7fc..1119e21226 100644 --- a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py +++ b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py @@ -3,21 +3,13 @@ """ # %% Import statements -import analysis_utility_functions_wast -import glob -import gzip -import os -import shutil import time from pathlib import Path -import numpy as np +import analysis_utility_functions_wast import pandas as pd -from matplotlib import pyplot as plt -from PyPDF2 import PdfReader, PdfWriter -from scipy import stats -from tlo.analysis.utils import compare_number_of_deaths, get_scenario_outputs, parse_log_file +from tlo.analysis.utils import get_scenario_outputs # start time of the whole analysis total_time_start = time.time() From 7f61007d474e8721cfce696b251351211c44752a Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 9 Jun 2025 21:29:07 +0100 Subject: [PATCH 539/755] scenario_wast_full_model_(SQ|GM): update name for local output --- .../scenarios/scenario_wasting_full_model_GM.py | 2 +- .../scenarios/scenario_wasting_full_model_SQ.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py index 9a00053b60..0e905f8b90 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py @@ -35,7 +35,7 @@ def __init__(self): def log_configuration(self): return { - 'filename': 'wasting_analysis__minimal_model', + 'filename': 'wasting_analysis__full_model_GM', 'directory': './outputs/wasting_analysis', "custom_levels": { # Customise the output of specific loggers "tlo.methods.demography": logging.INFO, diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py index 30823b39e6..6909913085 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py @@ -35,7 +35,7 @@ def __init__(self): def log_configuration(self): return { - 'filename': 'wasting_analysis__minimal_model', + 'filename': 'wasting_analysis__full_model_SQ', 'directory': './outputs/wasting_analysis', "custom_levels": { # Customise the output of specific loggers "tlo.methods.demography": logging.INFO, From c95ff60dd617bc1685f08450a5634a509e1226fb Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 9 Jun 2025 22:42:58 +0100 Subject: [PATCH 540/755] wast, test_wast, pars: add care-seeking for MAM cases intervention --- resources/ResourceFile_Wasting/parameters.csv | 4 +- src/tlo/methods/wasting.py | 32 ++++++++---- tests/test_wasting.py | 52 ++++++++++++++++++- 3 files changed, 75 insertions(+), 13 deletions(-) diff --git a/resources/ResourceFile_Wasting/parameters.csv b/resources/ResourceFile_Wasting/parameters.csv index d9ea6c27d6..3424ad43e9 100644 --- a/resources/ResourceFile_Wasting/parameters.csv +++ b/resources/ResourceFile_Wasting/parameters.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b4ab9558a630a14311f34b17013dd76dcc0f00f562dd3c8630803dc988e5449f -size 7287 +oid sha256:3cd5c1221c93a5e01927261c1bd6a5857d2385572b03b2edb53abb0ccce865fc +size 7708 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 5ec872fc7b..68631ca0c8 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -142,6 +142,8 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.LIST, 'growth monitoring frequency (days) for age categories '), 'growth_monitoring_attendance_prob_agecat': Parameter( Types.LIST, 'probability to attend the growth monitoring for age categories'), + 'seeking_care_MAM_prob': Parameter( + Types.REAL, 'probability of recognising symptoms and seeking care in MAM cases'), # treatment 'recovery_rate_with_soy_RUSF': Parameter( Types.REAL, 'probability of recovery from MAM following treatment with soy RUSF'), @@ -168,10 +170,13 @@ class Wasting(Module, GenericFirstAppointmentsMixin): # interventions 'interv_start_year': Parameter( Types.INT, 'the year when the interventions are activated by overwriting the relevant ' - 'parameters.'), + 'parameters'), 'interv_growth_monitoring_attendance_prob_agecat': Parameter( - Types.LIST, 'probability to attend the growth monitoring for age categories following the ' - 'activation of the intervention(s).'), + Types.LIST, 'probability to attend the growth monitoring for age categories following the ' + 'activation of the intervention'), + 'interv_seeking_care_MAM_prob': Parameter( + Types.REAL, 'probability of recognising symptoms and seeking care in MAM cases following the ' + 'activation of the intervention'), } PROPERTIES = { @@ -609,6 +614,10 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): # if person well if (whz == 'WHZ>=-2') and (muac == '>=125mm') and (not oedema_presence): df.at[person_id, 'un_clinical_acute_malnutrition'] = 'well' + # clear all wasting symptoms + self.sim.modules["SymptomManager"].clear_symptoms( + person_id=person_id, disease_module=self + ) # if person not well else: # start without treatment @@ -625,6 +634,14 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): # otherwise moderate acute malnutrition (MAM) else: df.at[person_id, 'un_clinical_acute_malnutrition'] = 'MAM' + # apply symptoms to certain MAM cases + if self.rng.random_sample() < p['seeking_care_MAM_prob']: + self.wasting_clinical_symptoms(person_id=person_id) + else: + # clear all wasting symptoms + self.sim.modules["SymptomManager"].clear_symptoms( + person_id=person_id, disease_module=self + ) if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'SAM': # Determine if SAM episode has complications @@ -647,10 +664,6 @@ def clinical_acute_malnutrition_state(self, person_id, pop_dataframe): else: df.at[person_id, 'un_sam_with_complications'] = False - # clear all wasting symptoms - self.sim.modules["SymptomManager"].clear_symptoms( - person_id=person_id, disease_module=self - ) assert not ((df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM') and (df.at[person_id, 'un_sam_with_complications'])), f'{person_id=} has MAM with complications.' @@ -765,11 +778,10 @@ def wasting_clinical_symptoms(self, person_id) -> None: :param person_id: """ df = self.sim.population.props - - if df.at[person_id, 'un_clinical_acute_malnutrition'] != 'SAM': + if df.at[person_id, 'un_clinical_acute_malnutrition'] == 'well': return - # apply wasting symptoms to the new SAM case + # apply wasting symptoms to the new acute malnutrition case self.sim.modules["SymptomManager"].change_symptom( person_id=person_id, symptom_string=self.wasting_symptom, diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 473c8f98f9..5b9b6a68c0 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -1034,6 +1034,7 @@ def test_no_wasting_after_recent_recovery(tmpdir): used as an example within the assumed min_days_to_relapse-day relapse-free window.) """ popsize = 1000 sim = get_sim(tmpdir) + # get wasting module wmodule = sim.modules['Wasting'] p = wmodule.parameters @@ -1068,6 +1069,7 @@ def test_no_wasting_after_recent_recovery(tmpdir): def test_default_interv_pars(tmpdir): """ Test that default values of intervention parameters are the same as the parameters prior the intervention. """ sim = get_sim(tmpdir) + # get wasting module wmodule = sim.modules['Wasting'] p = wmodule.parameters @@ -1075,9 +1077,13 @@ def test_default_interv_pars(tmpdir): ("The parameters 'growth_monitoring_attendance_prob_agecat' and " "'interv_growth_monitoring_attendance_prob_agecat' do not match.") + assert p['seeking_care_MAM_prob'] == p['interv_seeking_care_MAM_prob'], \ + "The parameters 'seeking_care_MAM_prob' and 'interv_seeking_care_MAM_prob' do not match." + def test_interventions_activation(tmpdir): """ Test that Wasting_ActivateInterventionsEvent correctly overwrites parameters. """ sim = get_sim(tmpdir) + # get wasting module wmodule = sim.modules['Wasting'] p = wmodule.parameters @@ -1091,4 +1097,48 @@ def test_interventions_activation(tmpdir): # Verify that the parameters have been overwritten assert p['growth_monitoring_attendance_prob_agecat'] == p['interv_growth_monitoring_attendance_prob_agecat'], \ - "The parameter was not correctly overwritten by the activation event." + ("The parameter 'growth_monitoring_attendance_prob_agecat' was not correctly overwritten by the activation " + "event.") + +def test_symptoms_with_MAM(tmpdir): + """ If 0% MAM cases are seeking care, after interventions activated, a person who becomes MAM will have no symptoms + assigned. """ + dur = pd.DateOffset(days=1) + popsize = 1000 + sim = get_sim(tmpdir) + # get wasting module + wmodule = sim.modules['Wasting'] + p = wmodule.parameters + + sim.make_initial_population(n=popsize) + sim.simulate(end_date=start_date + dur) + + # Get person to use and set their acute malnutrtion indicators to MAM: + df = sim.population.props + under5s = df.loc[df.is_alive & (df['age_years'] < 5)] + person_id = under5s.index[0] + df.loc[person_id, 'un_WHZ_category'] = '-3<=WHZ<-2' # moderately wasted + df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' + df.loc[person_id, 'un_am_nutritional_oedema'] = False + + # ### If no care-seeking MAM cases, the symptoms are never assigned to them + p['interv_seeking_care_MAM_prob'] = 0.0 + activation_event = Wasting_ActivateInterventionsEvent(wmodule) + activation_event.apply(sim.population) + assert p['seeking_care_MAM_prob'] == p['interv_seeking_care_MAM_prob'], \ + "The parameter 'seeking_care_MAM_prob' was not correctly overwritten by the activation event." + wmodule.clinical_acute_malnutrition_state(person_id, df) + assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM' + # Verify no symptoms are assigned + assert not sim.modules['SymptomManager'].has_what(person_id=person_id) + + # ### If all MAM cases are seeking cares, the symptoms are always assigned to them + p['interv_seeking_care_MAM_prob'] = 1.0 + activation_event = Wasting_ActivateInterventionsEvent(wmodule) + activation_event.apply(sim.population) + assert p['seeking_care_MAM_prob'] == p['interv_seeking_care_MAM_prob'], \ + "The parameter 'seeking_care_MAM_prob' was not correctly overwritten by the activation event." + wmodule.clinical_acute_malnutrition_state(person_id, df) + assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM' + # Verify symptoms are assigned + assert sim.modules['SymptomManager'].has_what(person_id=person_id) From 5ef30df47d4c8081d819ffc305a8300021083e05 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 9 Jun 2025 23:13:16 +0100 Subject: [PATCH 541/755] scenario_wast_full_model_(SQ|GM): 4K pop; & new scenario_wast_full_model_CS; scenario..._GM: parameter entry modified --- .../scenario_wasting_full_model_CS.py | 70 +++++++++++++++++++ .../scenario_wasting_full_model_GM.py | 17 +++-- .../scenario_wasting_full_model_SQ.py | 2 +- 3 files changed, 79 insertions(+), 10 deletions(-) create mode 100644 src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py new file mode 100644 index 0000000000..18d026e4f7 --- /dev/null +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py @@ -0,0 +1,70 @@ +""" +This file defines a scenario for wasting analysis. + +It can be submitted on Azure Batch by running: + + tlo batch-submit src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py + +or locally using: + + tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py +""" +# import itertools +import warnings + +from tlo import Date, logging +from tlo.analysis.utils import get_parameters_for_status_quo +from tlo.methods.fullmodel import fullmodel +from tlo.scenario import BaseScenario + +# capture warnings during simulation run +warnings.simplefilter('default', (UserWarning, RuntimeWarning)) + + +class WastingAnalysis(BaseScenario): + + def __init__(self): + super().__init__( + seed=0, + start_date=Date(year=2010, month=1, day=1), + end_date=Date(year=2031, month=1, day=1), + initial_population_size=4_000, + number_of_draws=3, + runs_per_draw=10, + ) + + def log_configuration(self): + return { + 'filename': 'wasting_analysis__full_model_CS', + 'directory': './outputs/wasting_analysis', + "custom_levels": { # Customise the output of specific loggers + "tlo.methods.demography": logging.INFO, + "tlo.methods.population": logging.INFO, + "tlo.methods.wasting": logging.INFO, + '*': logging.WARNING + } + } + + def modules(self): + return fullmodel(resourcefilepath=self.resources, + module_kwargs=get_parameters_for_status_quo()) + + # Scaling up care-seeking (CS) scenarios + def draw_parameters(self, draw_number, rng): + ### prob of care seeking for MAM cases + care_seek_prob = [ + 0.1, + 0.3, + 0.5 + ] + + return { + 'Wasting': { + 'interv_seeking_care_MAM_prob': care_seek_prob[draw_number] + } + } + +if __name__ == '__main__': + from tlo.cli import scenario_run + + scenario_run([__file__]) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py index 0e905f8b90..3b9948bee2 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py @@ -28,7 +28,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + initial_population_size=4_000, number_of_draws=3, runs_per_draw=10, ) @@ -52,17 +52,16 @@ def modules(self): # Scaling up growth monitoring (GM) attendance scenarios def draw_parameters(self, draw_number, rng): ### growth_monitoring_attendance_probs by age categories - # < 1 year - attendance_prob_below1y = 0.76 - # 1-2 years - attendance_prob_1to2y = [0.20, 0.25, 1.00] - # > 2 years - attendance_prob_above2y = [0.55, 0.50, 1.00] + # < 1 year, 1-2 years, and > 2 years + attendance_probs_by_agecat = [ + [0.76, 0.20, 0.55], + [0.76, 0.25, 0.50], + [0.76, 1.00, 1.00] + ] return { 'Wasting': { - 'interv_growth_monitoring_attendance_prob_agecat': - [attendance_prob_below1y, attendance_prob_1to2y[draw_number], attendance_prob_above2y[draw_number]] + 'interv_growth_monitoring_attendance_prob_agecat': attendance_probs_by_agecat[draw_number] } } diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py index 6909913085..b4910126d4 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py @@ -28,7 +28,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, + initial_population_size=4_000, number_of_draws=1, runs_per_draw=10, ) From e4e5541615c798c0bce5ab4e69e1ae17d83c07aa Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 10 Jun 2025 12:43:44 +0100 Subject: [PATCH 542/755] scenario_wast_full_model_(SQ|GM|CS): 30K pop --- .../scenarios/scenario_wasting_full_model_CS.py | 2 +- .../scenarios/scenario_wasting_full_model_GM.py | 2 +- .../scenarios/scenario_wasting_full_model_SQ.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py index 18d026e4f7..157f051cc0 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py @@ -28,7 +28,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=3, runs_per_draw=10, ) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py index 3b9948bee2..505db0644e 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py @@ -28,7 +28,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=3, runs_per_draw=10, ) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py index b4910126d4..6909913085 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_SQ.py @@ -28,7 +28,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=1, runs_per_draw=10, ) From 339481a07dd0eb2997235d98d9a362a6b92b4924 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 10 Jun 2025 17:14:58 +0100 Subject: [PATCH 543/755] def test_symptoms_with_MAM() -- before interventions being activated, symptoms are not assigned (as default care-seeking set to 0) --- tests/test_wasting.py | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/tests/test_wasting.py b/tests/test_wasting.py index 5b9b6a68c0..6c2158c325 100644 --- a/tests/test_wasting.py +++ b/tests/test_wasting.py @@ -1121,18 +1121,15 @@ def test_symptoms_with_MAM(tmpdir): df.loc[person_id, 'un_am_MUAC_category'] = '>=125mm' df.loc[person_id, 'un_am_nutritional_oedema'] = False - # ### If no care-seeking MAM cases, the symptoms are never assigned to them - p['interv_seeking_care_MAM_prob'] = 0.0 - activation_event = Wasting_ActivateInterventionsEvent(wmodule) - activation_event.apply(sim.population) - assert p['seeking_care_MAM_prob'] == p['interv_seeking_care_MAM_prob'], \ - "The parameter 'seeking_care_MAM_prob' was not correctly overwritten by the activation event." + # ### Before the intervention is activated, symptoms are never assigned to MAM cases + # This part of the test only makes sense when seeking_care_MAM_prob is set to 0.0 by default. + assert p['seeking_care_MAM_prob'] == 0.0 wmodule.clinical_acute_malnutrition_state(person_id, df) assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM' # Verify no symptoms are assigned assert not sim.modules['SymptomManager'].has_what(person_id=person_id) - # ### If all MAM cases are seeking cares, the symptoms are always assigned to them + # ### If all MAM cases are seeking care, the symptoms are always assigned to them p['interv_seeking_care_MAM_prob'] = 1.0 activation_event = Wasting_ActivateInterventionsEvent(wmodule) activation_event.apply(sim.population) @@ -1142,3 +1139,20 @@ def test_symptoms_with_MAM(tmpdir): assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM' # Verify symptoms are assigned assert sim.modules['SymptomManager'].has_what(person_id=person_id) + + # reset symptoms + sim.modules["SymptomManager"].clear_symptoms( + person_id=person_id, disease_module=wmodule + ) + assert not sim.modules['SymptomManager'].has_what(person_id=person_id) + + # ### If no MAM cases are seeking care, the symptoms are never assigned to them + p['interv_seeking_care_MAM_prob'] = 0.0 + activation_event = Wasting_ActivateInterventionsEvent(wmodule) + activation_event.apply(sim.population) + assert p['seeking_care_MAM_prob'] == p['interv_seeking_care_MAM_prob'], \ + "The parameter 'seeking_care_MAM_prob' was not correctly overwritten by the activation event." + wmodule.clinical_acute_malnutrition_state(person_id, df) + assert df.at[person_id, 'un_clinical_acute_malnutrition'] == 'MAM' + # Verify no symptoms are assigned + assert not sim.modules['SymptomManager'].has_what(person_id=person_id) From 04edd2d3f65a5cf4d07d0c742bd853e73e2edf2d Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 10 Jun 2025 17:16:47 +0100 Subject: [PATCH 544/755] run_intervs_analysis_wast & analysis_utility_fncs_wast: minor (update scenarios_dict and colours) --- .../wasting_analyses/analysis_utility_functions_wast.py | 4 +++- .../wasting_analyses/run_interventions_analysis_wasting.py | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py index 6345a06eaf..6d5344ee2f 100644 --- a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py +++ b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py @@ -142,11 +142,13 @@ def extract_death_data_frames_and_outcomes(folder, births_df, years_of_interest, def get_scen_colour(scen_name: str) -> str: return { - 'Status Quo': '#F7F77D', + 'Status Quo': '#F12AE5', 'GM_FullAttend': '#4575B4', 'GM_all': '#BDEBF7', 'GM_1-2': '#91BFDB', 'CS_10': '#B5D784', + 'CS_30': '#61B93C', + 'CS_50': '#2D7918', 'FS_full': '#A90251', 'FS_plus10': '#D4898E' }.get(scen_name) diff --git a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py index 1119e21226..1e96203ca7 100644 --- a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py +++ b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py @@ -17,10 +17,10 @@ # ####### TO SET ####################################################################################################### # Create dicts for the intervention scenarios. 'Interv_abbrev': {'Intervention scenario title/abbreviation': draw_nmb} scenarios_dict = {'SQ': {'Status Quo': 0}, - 'GM': {'GM_all': 1, 'GM_1-2': 2, 'GM_FullAttend': 3}, - 'GM2': {'GM_all': 1, 'GM_1-2': 2, 'GM_FullAttend': 3}} + 'GM': {'GM_all': 0, 'GM_1-2': 1, 'GM_FullAttend': 2}, + 'CS': {'CS_10': 0, 'CS_30': 1, 'CS_50': 2}} # Set the intervention to be analysed, and for which years they were simulated -intervs_of_interest = ['GM', 'GM2'] +intervs_of_interest = ['GM', 'CS'] intervention_years = list(range(2026, 2031)) # Which years to plot (from post burn-in period) plot_years = list(range(2015, 2031)) From 807540fa041e1840f747f9fbaa10b4e0e1d02db7 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 10 Jun 2025 17:46:12 +0100 Subject: [PATCH 545/755] scen_wast_full_model_GM: 7 runs of draw '0', 4K pop --- .../scenarios/scenario_wasting_full_model_GM.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py index 505db0644e..9376ae9255 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py @@ -28,9 +28,9 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, - number_of_draws=3, - runs_per_draw=10, + initial_population_size=4_000, + number_of_draws=1, + runs_per_draw=7, ) def log_configuration(self): From 3a500b8f74ae0ed9aea3ec95491b77dc15c83ed3 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 10 Jun 2025 23:05:51 +0100 Subject: [PATCH 546/755] scen_wast_full_model_CS: 100% MAM cases seeking care; 4K pop --- .../scenarios/scenario_wasting_full_model_CS.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py index 157f051cc0..b7a343a488 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py @@ -28,8 +28,8 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, - number_of_draws=3, + initial_population_size=4_000, + number_of_draws=1, runs_per_draw=10, ) @@ -52,10 +52,13 @@ def modules(self): # Scaling up care-seeking (CS) scenarios def draw_parameters(self, draw_number, rng): ### prob of care seeking for MAM cases + # care_seek_prob = [ + # 0.1, + # 0.3, + # 0.5 + # ] care_seek_prob = [ - 0.1, - 0.3, - 0.5 + 1.0 ] return { From a8475553f8594b0eca47ace1bf59301f62ed972c Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 11 Jun 2025 11:39:35 +0100 Subject: [PATCH 547/755] scen_wast_full_model_CS: 100% MAM cases seeking care; 4K pop (a hack to handle draw_parameters() not working with one par given) --- .../scenarios/scenario_wasting_full_model_CS.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py index b7a343a488..64cf2db39a 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py @@ -58,7 +58,7 @@ def draw_parameters(self, draw_number, rng): # 0.5 # ] care_seek_prob = [ - 1.0 + 1.0, 1.01 ] return { From d77847fb0127595fd8337e3de17491c791610152 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 11 Jun 2025 18:35:04 +0100 Subject: [PATCH 548/755] scen_wast_full_model_CS: 100% MAM cases seeking care; 30K pop --- .../scenarios/scenario_wasting_full_model_CS.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py index 64cf2db39a..93354502dc 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py @@ -28,7 +28,7 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=1, runs_per_draw=10, ) From df50bec8f1c27febbc655f08a0b04df1469317bf Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 11 Jun 2025 18:35:25 +0100 Subject: [PATCH 549/755] wast_analysis: add CS_100 scenario --- .../wasting_analyses/analysis_utility_functions_wast.py | 7 ++++--- .../run_interventions_analysis_wasting.py | 8 +++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py index 6d5344ee2f..03b5207fe5 100644 --- a/src/scripts/wasting_analyses/analysis_utility_functions_wast.py +++ b/src/scripts/wasting_analyses/analysis_utility_functions_wast.py @@ -146,9 +146,10 @@ def get_scen_colour(scen_name: str) -> str: 'GM_FullAttend': '#4575B4', 'GM_all': '#BDEBF7', 'GM_1-2': '#91BFDB', - 'CS_10': '#B5D784', + 'CS_10': '#9FFD17', 'CS_30': '#61B93C', - 'CS_50': '#2D7918', + 'CS_50': '#2D945F', + 'CS_100': '#266714', 'FS_full': '#A90251', 'FS_plus10': '#D4898E' }.get(scen_name) @@ -176,7 +177,7 @@ def plot_scenarios(plot_interv, plot_outcome): if cohort == 'Neonatal': outcome = 'neo_mort_rate_mean_ci_df' target = 12 - ylim_top = 30 # 25 + ylim_top = 40 #25 else: #cohort == 'Under-5': outcome = 'under5_mort_rate_mean_ci_df' target = 25 diff --git a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py index 1e96203ca7..7b100e1247 100644 --- a/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py +++ b/src/scripts/wasting_analyses/run_interventions_analysis_wasting.py @@ -16,9 +16,11 @@ # ####### TO SET ####################################################################################################### # Create dicts for the intervention scenarios. 'Interv_abbrev': {'Intervention scenario title/abbreviation': draw_nmb} -scenarios_dict = {'SQ': {'Status Quo': 0}, - 'GM': {'GM_all': 0, 'GM_1-2': 1, 'GM_FullAttend': 2}, - 'CS': {'CS_10': 0, 'CS_30': 1, 'CS_50': 2}} +scenarios_dict = { + 'SQ': {'Status Quo': 0}, + 'GM': {'GM_all': 0, 'GM_1-2': 1, 'GM_FullAttend': 2}, + 'CS': {'CS_10': 0, 'CS_30': 1, 'CS_50': 2, 'CS_100': 3} +} # Set the intervention to be analysed, and for which years they were simulated intervs_of_interest = ['GM', 'CS'] intervention_years = list(range(2026, 2031)) From 8a22ee69a389b1f4f900c4ecb846ec83478c0b15 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 11 Jun 2025 21:31:22 +0100 Subject: [PATCH 550/755] scenario_wast_full_model_GM: 5 runs of draw '0', 30K pop --- .../scenarios/scenario_wasting_full_model_GM.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py index 9376ae9255..210a7751d9 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_GM.py @@ -28,9 +28,9 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=4_000, + initial_population_size=30_000, number_of_draws=1, - runs_per_draw=7, + runs_per_draw=5, ) def log_configuration(self): From 148f2e976f1c57076d0a0a9835083b604211fb22 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Thu, 12 Jun 2025 11:15:35 +0100 Subject: [PATCH 551/755] scenario_wast_full_model_CS: short, small pop - to test submission script with pars --- ..._wasting_full_model_CS_totestsubmission.py | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS_totestsubmission.py diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS_totestsubmission.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS_totestsubmission.py new file mode 100644 index 0000000000..a57405b529 --- /dev/null +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS_totestsubmission.py @@ -0,0 +1,73 @@ +""" +This file defines a scenario for wasting analysis. + +It can be submitted on Azure Batch by running: + + tlo batch-submit src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py + +or locally using: + + tlo scenario-run src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py +""" +# import itertools +import warnings + +from tlo import Date, logging +from tlo.analysis.utils import get_parameters_for_status_quo +from tlo.methods.fullmodel import fullmodel +from tlo.scenario import BaseScenario + +# capture warnings during simulation run +warnings.simplefilter('default', (UserWarning, RuntimeWarning)) + + +class WastingAnalysis(BaseScenario): + + def __init__(self): + super().__init__( + seed=0, + start_date=Date(year=2010, month=1, day=1), + end_date=Date(year=2011, month=1, day=1), + initial_population_size=2_000, + number_of_draws=2, + runs_per_draw=3, + ) + + def log_configuration(self): + return { + 'filename': 'wasting_analysis__full_model_CS', + 'directory': './outputs/wasting_analysis', + "custom_levels": { # Customise the output of specific loggers + "tlo.methods.demography": logging.INFO, + "tlo.methods.population": logging.INFO, + "tlo.methods.wasting": logging.INFO, + '*': logging.WARNING + } + } + + def modules(self): + return fullmodel(resourcefilepath=self.resources, + module_kwargs=get_parameters_for_status_quo()) + + # Scaling up care-seeking (CS) scenarios + def draw_parameters(self, draw_number, rng): + ### prob of care seeking for MAM cases + # care_seek_prob = [ + # 0.1, + # 0.3, + # 0.5 + # ] + care_seek_prob = [ + 0.5, 1.0 + ] + + return { + 'Wasting': { + 'interv_seeking_care_MAM_prob': care_seek_prob[draw_number] + } + } + +if __name__ == '__main__': + from tlo.cli import scenario_run + + scenario_run([__file__]) From b46017c7631cae4632c71a8f4b333790d4515a85 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Mon, 16 Jun 2025 19:33:53 +0100 Subject: [PATCH 552/755] scenario_wast_full_model_CS: 4K pop, 2 draws, 3 runs - to test submission script with pars --- .../scenarios/scenario_wasting_full_model_CS.py | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py index 93354502dc..5264969edb 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py @@ -28,9 +28,9 @@ def __init__(self): seed=0, start_date=Date(year=2010, month=1, day=1), end_date=Date(year=2031, month=1, day=1), - initial_population_size=30_000, - number_of_draws=1, - runs_per_draw=10, + initial_population_size=4_000, + number_of_draws=2, + runs_per_draw=3, ) def log_configuration(self): @@ -52,14 +52,10 @@ def modules(self): # Scaling up care-seeking (CS) scenarios def draw_parameters(self, draw_number, rng): ### prob of care seeking for MAM cases + care_seek_prob = [0.1, 0.3, 0.5, 1.0] # care_seek_prob = [ - # 0.1, - # 0.3, - # 0.5 + # 1.0, 1.01 # ] - care_seek_prob = [ - 1.0, 1.01 - ] return { 'Wasting': { From 55fa472a0ad954bdd87eb5534ecbc89427025247 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 17 Jun 2025 00:34:45 +0100 Subject: [PATCH 553/755] wast_analyses/submission_scripts: creating submission scripts with pars --- .../submission_scripts/job_script.sh | 36 ++++++++++++ .../submit-TEMPLATE_without_pars.sh | 55 +++++++++++++++++++ .../submission_scripts/submit_job.sh | 22 ++++++++ 3 files changed, 113 insertions(+) create mode 100644 src/scripts/wasting_analyses/submission_scripts/job_script.sh create mode 100644 src/scripts/wasting_analyses/submission_scripts/submit-TEMPLATE_without_pars.sh create mode 100644 src/scripts/wasting_analyses/submission_scripts/submit_job.sh diff --git a/src/scripts/wasting_analyses/submission_scripts/job_script.sh b/src/scripts/wasting_analyses/submission_scripts/job_script.sh new file mode 100644 index 0000000000..9a24ea36b9 --- /dev/null +++ b/src/scripts/wasting_analyses/submission_scripts/job_script.sh @@ -0,0 +1,36 @@ +#!/bin/bash -l + +# Parameters passed from submit_job.sh +SCENARIO=$1 +TIME=$2 +MEMORY=$3 +DRAWS=$4 +RUNS=$5 + +# Determine the task number and create the task-specific directory +taskNumber="$SGE_TASK_ID" +thisRun=$(awk -v n="$taskNumber" "BEGIN { for (i=0; i<"$DRAWS"; i++) for (j=0; j<"$RUNS"; j++) if (++count==n) print i, j }") +drawNumber=$(( (taskNumber - 1) / RUNS )) +runNumber=$(( (taskNumber - 1) % RUNS )) + +# Output directory setup +mainOutputDir="$HOME/Scratch/thanzi/TLOmodel-outputs/${JOB_NAME}-${JOB_ID}" +outputDir="$mainOutputDir/${drawNumber}/${runNumber}" +mkdir -p "$outputDir" + +# Load and activate python environment +module load python3/3.11 +source ~/thanzi/venv-tlo/bin/activate +cd ~/thanzi/TLOmodel + +# *** Run the specified scenario with resource usage measurement +/usr/bin/time --verbose tlo scenario-run --draw $thisRun --output-dir "$outputDir" \ +  src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_${SCENARIO}_totestsubmission.py + +# Parse and compress logs +tlo parse-log "$outputDir" +gzip "$outputDir"/*.log + +# Move and rename .o and .e files +mv "$HOME/Scratch/thanzi/TLOmodel-outputs/${JOB_NAME}.o${JOB_ID}.${taskNumber}" "$outputDir/${JOB_NAME}.o${JOB_ID}.$((taskNumber - 1))" +mv "$HOME/Scratch/thanzi/TLOmodel-outputs/${JOB_NAME}.e${JOB_ID}.${taskNumber}" "$outputDir/${JOB_NAME}.e${JOB_ID}.$((taskNumber - 1))" diff --git a/src/scripts/wasting_analyses/submission_scripts/submit-TEMPLATE_without_pars.sh b/src/scripts/wasting_analyses/submission_scripts/submit-TEMPLATE_without_pars.sh new file mode 100644 index 0000000000..94a4b9c3a4 --- /dev/null +++ b/src/scripts/wasting_analyses/submission_scripts/submit-TEMPLATE_without_pars.sh @@ -0,0 +1,55 @@ +#!/bin/bash -l + +############ JOB CONFIG + +# *** Request for the most reasonable minimum you can, up to 72 hours. This specifies 24 hours +#$ -l h_rt=15:0:0 + +# *** Request for the most reasonable minimum of memory you can. This specifies 16 GB +#$ -l mem=16G + +# *** Personal job name identifier +#$ -N wasting_analysis__full_model_XX + +# *** Put in your username below +#$ -wd /home/sejjej5/Scratch/thanzi/TLOmodel-outputs + +# *** Setup the job array: 1-(no. of draws * no. of runs) e.g. if 3 draws, 3 runs: 1-9 +#$ -t 1-10 + +# *** Email notifications +#$ -m beas +#$ -M sejjej5@ucl.ac.uk + +############ END OF JOB CONFIG + +# *** Specify number of draws & runs +numberOfDraws=1 +numberOfRuns=10 + +# Create the main output directory +mainOutputDir="$HOME/Scratch/thanzi/TLOmodel-outputs/${JOB_NAME}-${JOB_ID}" +mkdir -p "$mainOutputDir" + +# Determine the task number and create the task-specific directory +taskNumber="$SGE_TASK_ID" +thisRun=$(awk -v n="$taskNumber" "BEGIN { for (i=0; i<"$numberOfDraws"; i++) for (j=0; j<"$numberOfRuns"; j++) if (++count==n) print i, j }") +drawNumber=$(echo $thisRun | awk "{print \$1}") +runNumber=$(echo $thisRun | awk "{print \$2}") +outputDir="$mainOutputDir/${drawNumber}/${runNumber}" +mkdir -p "$outputDir" + +# Load and activate python environment +module load python3/3.11 +source ~/thanzi/venv-tlo/bin/activate + +cd ~/thanzi/TLOmodel + +# *** Run the specified scenario with resource usage measurement +/usr/bin/time --verbose tlo scenario-run --draw $thisRun --output-dir "$outputDir" src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_XX.py +tlo parse-log "$outputDir" +gzip "$outputDir"/*.log + +# Move and rename the .o and .e files to the task-specific directory +mv "$HOME/Scratch/thanzi/TLOmodel-outputs/${JOB_NAME}.o${JOB_ID}.${taskNumber}" "$outputDir/${JOB_NAME}.o${JOB_ID}.$((taskNumber - 1))" +mv "$HOME/Scratch/thanzi/TLOmodel-outputs/${JOB_NAME}.e${JOB_ID}.${taskNumber}" "$outputDir/${JOB_NAME}.e${JOB_ID}.$((taskNumber - 1))" diff --git a/src/scripts/wasting_analyses/submission_scripts/submit_job.sh b/src/scripts/wasting_analyses/submission_scripts/submit_job.sh new file mode 100644 index 0000000000..0ac91ec92e --- /dev/null +++ b/src/scripts/wasting_analyses/submission_scripts/submit_job.sh @@ -0,0 +1,22 @@ + +#!/bin/bash + +set -x + +# Read parameters +SCENARIO=$1 +TIME=$2 +MEMORY=$3 +DRAWS=$4 +RUNS=$5 + +# Calculate number of jobs +JOBS=$((DRAWS * RUNS)) + +# Submit the job array with parameters +qsub -t 1-${JOBS} -N wasting_analysis__full_model_${SCENARIO} \ + -l h_rt=${TIME}:0:0 -l mem=${MEMORY} \ + -wd /home/sejjej5/Scratch/thanzi/TLOmodel-outputs \ + -m beas -M sejjej5@ucl.ac.uk \ + job_script.sh $SCENARIO $TIME $MEMORY $DRAWS $RUNS + From 28c2007da4e607cff6a9f8fcbb0e68dc65390c14 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 17 Jun 2025 16:02:03 +0100 Subject: [PATCH 554/755] wast_analyses/submission_scripts: save the working version (note: 1h 1G is not enough not even for 1 year sim of 2K pop) --- src/scripts/wasting_analyses/submission_scripts/job_script.sh | 2 +- src/scripts/wasting_analyses/submission_scripts/submit_job.sh | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/scripts/wasting_analyses/submission_scripts/job_script.sh b/src/scripts/wasting_analyses/submission_scripts/job_script.sh index 9a24ea36b9..9c8b87436b 100644 --- a/src/scripts/wasting_analyses/submission_scripts/job_script.sh +++ b/src/scripts/wasting_analyses/submission_scripts/job_script.sh @@ -25,7 +25,7 @@ cd ~/thanzi/TLOmodel # *** Run the specified scenario with resource usage measurement /usr/bin/time --verbose tlo scenario-run --draw $thisRun --output-dir "$outputDir" \ -  src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_${SCENARIO}_totestsubmission.py + src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_${SCENARIO}_totestsubmission.py # Parse and compress logs tlo parse-log "$outputDir" diff --git a/src/scripts/wasting_analyses/submission_scripts/submit_job.sh b/src/scripts/wasting_analyses/submission_scripts/submit_job.sh index 0ac91ec92e..838365dba2 100644 --- a/src/scripts/wasting_analyses/submission_scripts/submit_job.sh +++ b/src/scripts/wasting_analyses/submission_scripts/submit_job.sh @@ -19,4 +19,3 @@ qsub -t 1-${JOBS} -N wasting_analysis__full_model_${SCENARIO} \ -wd /home/sejjej5/Scratch/thanzi/TLOmodel-outputs \ -m beas -M sejjej5@ucl.ac.uk \ job_script.sh $SCENARIO $TIME $MEMORY $DRAWS $RUNS - From cb3363cc42ed0caab7c3c64071a0de2f5b917d14 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 17 Jun 2025 16:03:30 +0100 Subject: [PATCH 555/755] scenario_wasting_full_model_CS: 2 draws, 10 runs 4K pop to the new submission script(s) --- .../scenarios/scenario_wasting_full_model_CS.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py index 5264969edb..24b9c3669a 100644 --- a/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py +++ b/src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_CS.py @@ -30,7 +30,7 @@ def __init__(self): end_date=Date(year=2031, month=1, day=1), initial_population_size=4_000, number_of_draws=2, - runs_per_draw=3, + runs_per_draw=10, ) def log_configuration(self): From 31583ef501b2a6f74f8af16dabcf54a75a61389b Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 17 Jun 2025 16:16:57 +0100 Subject: [PATCH 556/755] wast_analyses/submission_scripts: job_script updated to run the actual scenarios (not just a testing one) --- src/scripts/wasting_analyses/submission_scripts/job_script.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/wasting_analyses/submission_scripts/job_script.sh b/src/scripts/wasting_analyses/submission_scripts/job_script.sh index 9c8b87436b..89f0183926 100644 --- a/src/scripts/wasting_analyses/submission_scripts/job_script.sh +++ b/src/scripts/wasting_analyses/submission_scripts/job_script.sh @@ -25,7 +25,7 @@ cd ~/thanzi/TLOmodel # *** Run the specified scenario with resource usage measurement /usr/bin/time --verbose tlo scenario-run --draw $thisRun --output-dir "$outputDir" \ - src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_${SCENARIO}_totestsubmission.py + src/scripts/wasting_analyses/scenarios/scenario_wasting_full_model_${SCENARIO}.py # Parse and compress logs tlo parse-log "$outputDir" From 372b42373ed079ebc0902c4a43ba293cd614fabd Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Tue, 17 Jun 2025 16:19:16 +0100 Subject: [PATCH 557/755] wast_analyses/submission_scripts: create a submit_job script which would allow to pass parameters with the names --- .../submit_job_with_pars_by_names.sh | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/scripts/wasting_analyses/submission_scripts/submit_job_with_pars_by_names.sh diff --git a/src/scripts/wasting_analyses/submission_scripts/submit_job_with_pars_by_names.sh b/src/scripts/wasting_analyses/submission_scripts/submit_job_with_pars_by_names.sh new file mode 100644 index 0000000000..5af9ed35b8 --- /dev/null +++ b/src/scripts/wasting_analyses/submission_scripts/submit_job_with_pars_by_names.sh @@ -0,0 +1,52 @@ + +#!/bin/bash + +set -x + +# Default values (optional, if needed) +SCENARIO="" +TIME="" +MEMORY="" +DRAWS="" +RUNS="" + +# Parse named arguments in NAME=value format +for ARG in "$@"; do + case $ARG in + SCENARIO=*) + SCENARIO="${ARG#*=}" + ;; + TIME=*) + TIME="${ARG#*=}" + ;; + MEMORY=*) + MEMORY="${ARG#*=}" + ;; + DRAWS=*) + DRAWS="${ARG#*=}" + ;; + RUNS=*) + RUNS="${ARG#*=}" + ;; + *) + echo "Unknown parameter: $ARG" + exit 1 + ;; + esac +done + +# Validate required arguments +if [[ -z "$SCENARIO" || -z "$TIME" || -z "$MEMORY" || -z "$DRAWS" || -z "$RUNS" ]]; then + echo "Usage: $0 SCENARIO= TIME=

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 literal 0 HcmV?d00001 From 1fa152411b2e79c2a322342832cafdd90186cd1e Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 7 May 2025 01:49:55 +0100 Subject: [PATCH 451/755] wast: module, pars, and properties descriptions updated; minor (comments) --- src/tlo/methods/wasting.py | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 8b7e1bd17f..bb543c5269 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -32,11 +32,7 @@ # --------------------------------------------------------------------------- class Wasting(Module, GenericFirstAppointmentsMixin): """ - This module applies the prevalence of wasting at the population-level, based on the Malawi DHS Survey 2015-2016. - The definitions: - - moderate wasting: weight_for_height Z-score (WHZ) < -2 SD from the reference mean - - severe wasting: weight_for_height Z-score (WHZ) < -3 SD from the reference mean - + This module simulates natural history, detection, and treatment of acute malnutrition in children under 5 years old. """ INIT_DEPENDENCIES = {'Demography', 'SymptomManager', 'NewbornOutcomes', 'HealthBurden'} @@ -139,25 +135,27 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.LIST, 'probability to attend the growth monitoring for age categories'), # recovery due to treatment/interventions 'recovery_rate_with_soy_RUSF': Parameter( - Types.REAL, 'probability of recovery from wasting following treatment with soy RUSF'), + Types.REAL, 'probability of recovery from MAM following treatment with soy RUSF'), 'recovery_rate_with_CSB++': Parameter( - Types.REAL, 'probability of recovery from wasting following treatment with CSB++'), + Types.REAL, 'probability of recovery from MAM following treatment with CSB++'), 'recovery_rate_with_standard_RUTF': Parameter( - Types.REAL, 'probability of recovery from wasting following treatment with standard RUTF'), + Types.REAL, 'probability of recovery from uncomplicated SAM following treatment with standard' + 'RUTF'), 'recovery_rate_with_inpatient_care': Parameter( - Types.REAL, 'probability of recovery from wasting following treatment with inpatient care'), + Types.REAL, 'probability of recovery from complicated SAM following treatment via inpatient ' + 'care'), 'tx_length_weeks_SuppFeedingMAM': Parameter( Types.REAL, 'number of weeks the patient receives treatment in the Supplementary Feeding ' 'Programme for MAM before being discharged'), 'tx_length_weeks_OutpatientSAM': Parameter( Types.REAL, 'number of weeks the patient receives treatment in the Outpatient Therapeutic ' - 'Programme for SAM before being discharged if they do not die beforehand'), + 'Programme for uncomplicated SAM before being discharged if they do not die beforehand'), 'tx_length_weeks_InpatientSAM': Parameter( Types.REAL, 'number of weeks the patient receives treatment in the Inpatient Care for complicated' ' SAM before being discharged if they do not die beforehand'), # treatment/intervention outcomes 'prob_death_after_SAMcare': Parameter( - Types.REAL, 'probability of dying from SAM after receiving care'), + Types.REAL, 'probability of dying from SAM after receiving care if not fully recovered'), } PROPERTIES = { @@ -172,8 +170,8 @@ class Wasting(Module, GenericFirstAppointmentsMixin): 'based on WHZ and/or MUAC and/or nutritional ' 'oedema', categories=['MAM', 'SAM', 'well']), - 'un_am_nutritional_oedema': Property(Types.BOOL, 'bilateral pitting oedema present in wasting ' - 'episode'), + 'un_am_nutritional_oedema': Property(Types.BOOL, 'nutritional oedema present in acute malnutrition' + ' episode'), 'un_am_MUAC_category': Property(Types.CATEGORICAL, 'MUAC measurement categories, based on WHO ' 'cut-offs', categories=['<115mm', '[115-125)mm', '>=125mm']), @@ -383,7 +381,7 @@ def muac_cutoff_by_WHZ(self, idx, whz): df = self.sim.population.props p = self.parameters - # ----- MUAC distribution for severe wasting (WHZ < -3) ------ + # ----- MUAC distribution among severely wasted (WHZ < -3) ------ if whz == 'WHZ<-3': # for severe wasting assumed no MUAC >= 125mm prop_severe_wasting_with_muac_between_115and125mm = 1 - p['proportion_WHZ<-3_with_MUAC<115mm'] @@ -395,7 +393,7 @@ def muac_cutoff_by_WHZ(self, idx, whz): axis=1 ) - # ----- MUAC distribution for moderate wasting (-3 <= WHZ < -2) ------ + # ----- MUAC distribution among moderately wasted (-3 <= WHZ < -2) ------ if whz == '-3<=WHZ<-2': prop_moderate_wasting_with_muac_over_125mm = \ 1 - p['proportion_-3<=WHZ<-2_with_MUAC<115mm'] - p['proportion_-3<=WHZ<-2_with_MUAC_[115-125)mm'] @@ -408,7 +406,7 @@ def muac_cutoff_by_WHZ(self, idx, whz): axis=1 ) - # ----- MUAC distribution for WHZ >= -2 ----- + # ----- MUAC distribution among non-wasted WHZ >= -2 ----- if whz == 'WHZ>=-2': muac_distribution_in_well_group = norm(loc=p['MUAC_distribution_WHZ>=-2'][0], From 00e3d0e636165950533e1128c14fb8674982aa39 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 7 May 2025 11:38:41 +0100 Subject: [PATCH 452/755] wast: consumables for ITC updated --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index bb543c5269..3535b2225e 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -533,7 +533,7 @@ def get_consumables_for_each_treatment(self): _cons_codes['OTP'] = {get_item_code("Therapeutic spread, sachet 92g/CAR-150"): 20 * 7} _cons_codes['OTP_opt'] = {get_item_code("SAM medicines"): 1} _cons_codes['ITC'] = {get_item_code("F-75 therapeutic milk, 102.5 g"): 102.5 * 24, - get_item_code("Therapeutic spread, sachet 92g/CAR-150"): 3 * 4} + get_item_code("Therapeutic spread, sachet 92g/CAR-150"): 3 * 4 + 20 * 7} _cons_codes['ITC_opt'] = {get_item_code("SAM medicines"): 1} return _cons_codes From 3c29e04164df336d09ea0b1e5b193595f7896f24 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 7 May 2025 12:03:30 +0100 Subject: [PATCH 453/755] wast & Wast write-up: additional amount of RUTF issued here for ITC (but actually provided with OTP), hence non-essential for being admitted to ITC --- docs/write-ups/Wasting.doc | Bin 360099 -> 360654 bytes src/tlo/methods/wasting.py | 6 +++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/write-ups/Wasting.doc b/docs/write-ups/Wasting.doc index 3f76356d00ab855cb0f7cf22f2f1e10ee92384ed..a8950d3cb797e0e2d691d860fbe1392d4d8725a9 100644 GIT binary patch delta 38963 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 z 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 delta 38529 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 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 3535b2225e..f87bba0fff 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -533,9 +533,9 @@ def get_consumables_for_each_treatment(self): _cons_codes['OTP'] = {get_item_code("Therapeutic spread, sachet 92g/CAR-150"): 20 * 7} _cons_codes['OTP_opt'] = {get_item_code("SAM medicines"): 1} _cons_codes['ITC'] = {get_item_code("F-75 therapeutic milk, 102.5 g"): 102.5 * 24, - get_item_code("Therapeutic spread, sachet 92g/CAR-150"): 3 * 4 + 20 * 7} - _cons_codes['ITC_opt'] = {get_item_code("SAM medicines"): 1} - + get_item_code("Therapeutic spread, sachet 92g/CAR-150"): 3 * 4} + _cons_codes['ITC_opt'] = {get_item_code("Therapeutic spread, sachet 92g/CAR-150"): 20 * 7, + get_item_code("SAM medicines"): 1} return _cons_codes def date_of_outcome_for_untreated_wasting(self, whz_category): From aad57d3aa0e150eff3eb445c96d2ab3db6fa5496 Mon Sep 17 00:00:00 2001 From: Eva Janouskova Date: Wed, 14 May 2025 14:47:50 +0100 Subject: [PATCH 454/755] wast & RFWast/pars: prop of normal whz added as a par --- resources/ResourceFile_Wasting/parameters.csv | 4 ++-- src/tlo/methods/wasting.py | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/resources/ResourceFile_Wasting/parameters.csv b/resources/ResourceFile_Wasting/parameters.csv index 8c90a4eed6..9bc5227141 100644 --- a/resources/ResourceFile_Wasting/parameters.csv +++ b/resources/ResourceFile_Wasting/parameters.csv @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:dcfb4341b4a2bf174b50990d49ea04ba6b265f70fe850415b08e4412dde9aa4f -size 4674 +oid sha256:c5df0060605083f532e16b51703ce0ac825f8e55020503ed39b45454f3361b1f +size 4747 diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index f87bba0fff..89034aaa70 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -128,6 +128,8 @@ class Wasting(Module, GenericFirstAppointmentsMixin): Types.REAL, 'proportion of individuals with wasting (moderate or severe) who have oedema'), 'proportion_oedema_with_WHZ<-2': Parameter( Types.REAL, 'proportion of individuals with oedema who are wasted (moderately or severely)'), + 'proportion_normal_whz': Parameter( + Types.REAL, 'proportion of children under 5 with no wasting (WHZ >= -2)'), # detection 'growth_monitoring_frequency_days_agecat': Parameter( Types.LIST, 'growth monitoring frequency (days) for age categories '), @@ -201,7 +203,6 @@ class Wasting(Module, GenericFirstAppointmentsMixin): def __init__(self, name=None, resourcefilepath=None): super().__init__(name) - self.prob_normal_whz = None self.wasting_models = None self.resourcefilepath = resourcefilepath # wasting states @@ -316,9 +317,6 @@ def initialise_population(self, population): init_sev_wasting_bool, 'WHZ<-3', '-3<=WHZ<-2' ) - # calculate approximation of probability of having normal WHZ in children under 5 to be used later - self.prob_normal_whz = \ - len(under5s_index.intersection(df.index[df.un_WHZ_category == 'WHZ>=-2'])) / len(under5s_index) # ----------------------------------------------------------------------------------------------------- # # # # # Give MUAC category, presence of oedema, and determine acute malnutrition state # # # # # # # # and, in SAM cases, determine presence of complications and eventually schedule death # # # # @@ -454,7 +452,7 @@ def nutritional_oedema_present(self, idx): # proportion_normalWHZ_with_oedema: P(oedema|WHZ>=-2) = # P(oedema & WHZ>=-2) / P(WHZ>=-2) = P(oedema) * [1 - P(WHZ<-2|oedema)] / P(WHZ>=-2) proportion_normal_whz_with_oedema = \ - p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) / self.prob_normal_whz + p['prevalence_nutritional_oedema'] * (1 - p['proportion_oedema_with_WHZ<-2']) / p['proportion_normal_whz'] oedema_in_non_wasted = self.rng.random_sample(size=len( children_without_wasting)) < proportion_normal_whz_with_oedema df.loc[children_without_wasting, 'un_am_nutritional_oedema'] = oedema_in_non_wasted From 849a06326ad2f73d6554b4fe82d7a8b6ca91df42 Mon Sep 17 00:00:00 2001 From: Eva Janouskova <48157464+EvaJanouskova@users.noreply.github.com> Date: Wed, 28 May 2025 15:20:24 +0200 Subject: [PATCH 455/755] wast: start monthly incidence poll 1 mo after sim initiated --- src/tlo/methods/wasting.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tlo/methods/wasting.py b/src/tlo/methods/wasting.py index 89034aaa70..4dc3905c09 100644 --- a/src/tlo/methods/wasting.py +++ b/src/tlo/methods/wasting.py @@ -331,7 +331,7 @@ def initialise_simulation(self, sim): sim.schedule_event(Wasting_InitLoggingEvent(self), sim.date) sim.schedule_event(Wasting_InitiateGrowthMonitoring(self), sim.date) - sim.schedule_event(Wasting_IncidencePoll(self), sim.date + DateOffset(months=3)) + sim.schedule_event(Wasting_IncidencePoll(self), sim.date + DateOffset(months=1)) sim.schedule_event(Wasting_LoggingEvent(self), sim.date + DateOffset(years=1) - DateOffset(days=1)) # Retrieve the consumables codes and amounts of the consumables used From b04eb4aad6dc72d6df751f9aaaf40124c0b3e90e Mon Sep 17 00:00:00 2001 From: Tim Hallett <39991060+tbhallett@users.noreply.github.com> Date: Thu, 29 May 2025 12:29:45 +0100 Subject: [PATCH 456/755] remove cover sheet from stunting module resource file --- resources/ResourceFile_Stunting/Cover Sheet.csv | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 resources/ResourceFile_Stunting/Cover Sheet.csv diff --git a/resources/ResourceFile_Stunting/Cover Sheet.csv b/resources/ResourceFile_Stunting/Cover Sheet.csv deleted file mode 100644 index e6593c8b83..0000000000 --- a/resources/ResourceFile_Stunting/Cover Sheet.csv +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7b380c25531d9812f741db00374dd542caf42a7710364e4681de089828403b00 -size 496 From ce5c1649e47b1f8890af0bc1cbd7e91bc2a39101 Mon Sep 17 00:00:00 2001 From: Tim Hallett <39991060+tbhallett@users.noreply.github.com> Date: Thu, 29 May 2025 12:33:58 +0100 Subject: [PATCH 457/755] editd to wasting write-up: * remove link to private google doc * remove section on bathtub model (this was our internal check) * change title --- docs/write-ups/Wasting.doc | Bin 360654 -> 451994 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/write-ups/Wasting.doc b/docs/write-ups/Wasting.doc index a8950d3cb797e0e2d691d860fbe1392d4d8725a9..1bec64a5f614ae3b65aedd530459abf45dd7dc49 100644 GIT binary patch literal 451994 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