Skip to content

Integrating weather events into TLO#1604

Draft
RachelMurray-Watson wants to merge 328 commits intomasterfrom
rmw/climate_change_switch
Draft

Integrating weather events into TLO#1604
RachelMurray-Watson wants to merge 328 commits intomasterfrom
rmw/climate_change_switch

Conversation

@RachelMurray-Watson
Copy link
Collaborator

@RachelMurray-Watson RachelMurray-Watson commented Mar 5, 2025

This PR aims to integrate weather-mediated disruptions into the TLO model. As the disruptions are mediated at the level of a facility, each individual in the model must be "assigned" to facilities of different levels within their region of interest.

Assumptions:

  • Have the projected disruptions to ANC care; assume this translates to disruptions in other services
  • Mode 1 (?)
  • Disruption happens at point of healthcare provision, not in healthcare seeking behaviour
  • There's a (weighted) coin toss at the point of processing the HSI event to see if the event goes ahead, based on the proportion of deficit of ANC services from linear model paper
  • Appointments are cancelled, not postponed
  • Added in logging by region

Copy link
Collaborator

@marghe-molaro marghe-molaro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a quick look at the changes to the HealthSystem, please let me know if any of my comments are unclear!

# And for each indiviudal level event, check to see if there are projected disruptions due to precipitation.
if self.module.services_affected_precip != 'none' and year > 2025:
for item in list_of_individual_hsi_event_tuples_due_today_that_have_essential_equipment:
facility_used = self.sim.population.props.at[item.hsi_event.target, 'level_1a']
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is only 'level_1a' considered here? The facility at which HSI is being delivered might not necessarily be at this level

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hang-over from previous code; thanks for spotting!

if self.module.services_affected_precip != 'none' and year > 2025:
for item in list_of_individual_hsi_event_tuples_due_today_that_have_essential_equipment:
facility_used = self.sim.population.props.at[item.hsi_event.target, 'level_1a']
if facility_used in self.module.parameters['projected_precip_disruptions']['Facility_ID'].values:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand correctly, 'Facility_ID' here refers to real facilities. Since 'Facility_ID' is already used in the model to indicate modelled/aggregated facilities, I would use a different name if possible - e.g. RealFacility_ID? - to avoid confusion

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might also be clearer to separate the mapping of the modelled and real facilities from the climate considerations, so have dictionaries in the health system ready to be invoked where:
Real_to_Modelled_Facility_Mapping = {RealFacility_ID : Facility_ID}
and
Modelled_to_Real_Facility_Mapping = {Facility_ID : [RealFacility_ID, RealFacility_ID, ...]}


# Try to run the list of individual-level events that have their essential equipment
# And for each indiviudal level event, check to see if there are projected disruptions due to precipitation.
if self.module.services_affected_precip != 'none' and year > 2025:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if not None?

The type of service provided by the HSI under consideration doesn't seem to be accounted for currently (meaning only the 'none' or 'all' services being disrupted is currently under consideration, so I would remove the 'anc' option for now

'service'] == self.module.services_affected_precip),
'disruption'
]
if len(prob_disruption) > 0:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused, why is the prob_distribution not a single value?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So am I, unsure why I left that there!

assert isinstance(prob_disruption, (int, float)), "prob_disruption must be an int or float"

if np.random.binomial(1, prob_disruption) == 1: # success is delayed appointment
list_of_individual_hsi_event_tuples_due_today_that_have_essential_equipment.remove(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The coin toss to check precipitation disruption should be done before adding the item to the list_of_individual_hsi_event_tuples_due_today_that_have_essential_equipment , rather than adding+removing

Call 'equipment is available' (cond A) and 'event is disrupted by precipitation (cond B), then:
If cond A=False:
call never_ran()
elif A=True:
check cond B
if B=False:
add to list_of_individual_hsi_event_tuples_due_today_that_have_essential_equipment
else:
invoke did_not_run(), and add to hold over list

In this respect, would be good to rename list_of_individual_hsi_event_tuples_due_today_that_have_essential_equipment with something more generic, like list_of_individual_hsi_event_tuples_meeting_all_conditions, or something along those lines

if np.random.binomial(1, prob_disruption) == 1: # success is delayed appointment
list_of_individual_hsi_event_tuples_due_today_that_have_essential_equipment.remove(
item) # Remove item from list? Should I create a seperate list?
self.module.call_and_record_never_ran_hsi_event(hsi_event=item.hsi_event,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the event has been postponed, rather than completely cancelled, we should not be calling "call_and_record_never_ran_hsi_event" on it, rather we should be adding it to the "hold_over" queue, but first calling "did_not_run()" fnc on it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per conversation 27th March 2025, decided to "just" cancel all appointments pending further nuancing of healthcare seeking behaviour.

assert climate_model_ensemble_model in ('lowest', 'mean', 'highest')
self.climate_model_ensemble_model = climate_model_ensemble_model

assert services_affected_precip in (None, 'none', 'ANC', 'all')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currently only 'none' or 'all' is considered, so remove ANC option for now

Added option for mode 2 analysis
added in vmin and vmax again for clarity
Check which have significantly different plots
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants