Skip to content

Weather Disruptions Module#1790

Draft
RachelMurray-Watson wants to merge 69 commits intomasterfrom
rmw/climate_change_module
Draft

Weather Disruptions Module#1790
RachelMurray-Watson wants to merge 69 commits intomasterfrom
rmw/climate_change_module

Conversation

@RachelMurray-Watson
Copy link
Copy Markdown
Collaborator

@RachelMurray-Watson RachelMurray-Watson commented Jan 29, 2026

This PR aims to develop a separate "WeatherDisruptions" module. This modularizes code developed in rmw/climate_change_switch and rmw/climate_troubleshoot_LHS.

The module aims to do the following:

  1. Assign individuals facilities based on their districts*
  2. Read in data on the weather disruptions**
  3. Determine whether a disruption will occur (and consequence e.g. reseeking healthcare)
  4. Feed this back to the health system
  5. Log disrupted HSIs by district
  • This is a necessary but, also, distinct functionality that could instead be included in the demography module.
    ** Currently these are csv files with the proportion of ANC appointments disrupted for each facility by month. @marghe-molaro previously suggested saving the coefficients of the ANC model instead and doing the LM each time. This will probably save us space (as we would only need the details for each facility to be loaded in) but it seems more computationally intensive (as would need to look up all details for each facility and do calculation each time a HSI is processed).

To Do:

  • Framework of WeatherDisruptions module
  • Parameter file separated from health system file
  • Tests of functionality
  • Decide on points * and ** above
  • Add new logging to HealthBurden module

…n code developed in rmw/climate_change_switch and rmw/climate_troubleshoot_LHS.
@marghe-molaro
Copy link
Copy Markdown
Collaborator

Hi @RachelMurray-Watson,

Great to see this being formalised this way!

Just a few comments:

  1. Agreed
  2. You can initialise the disruption dfs upon initialisation of the module based on the specified coefficients without any repercussions on simulation runtime. (Basically, instead of reading in your 'look up' climate disruption df, you 'create it' based on the coefficients and any other relevant info (e.g. climate projections, facility location, ...) upon initialisation - unless I am missing something)
    Advantages:
  • Reduce resource files required (now you only need the climate projections)
  • Make your assumptions around how climate relates to disruptions more explicit (i.e. you declare coefficients explicitly) and therefore amenable to modifications later on;

@RachelMurray-Watson
Copy link
Copy Markdown
Collaborator Author

Hi @RachelMurray-Watson,

Great to see this being formalised this way!

Just a few comments:

  1. Agreed
  2. You can initialise the disruption dfs upon initialisation of the module based on the specified coefficients without any repercussions on simulation runtime. (Basically, instead of reading in your 'look up' climate disruption df, you 'create it' based on the coefficients and any other relevant info (e.g. climate projections, facility location, ...) upon initialisation - unless I am missing something)
    Advantages:
  • Reduce resource files required (now you only need the climate projections)
  • Make your assumptions around how climate relates to disruptions more explicit (i.e. you declare coefficients explicitly) and therefore amenable to modifications later on;

Ah I see! I misinterpreted what you meant initially. Grand so, I can do it that way.

@RachelMurray-Watson
Copy link
Copy Markdown
Collaborator Author

Hi @RachelMurray-Watson,
Great to see this being formalised this way!
Just a few comments:

  1. Agreed
  2. You can initialise the disruption dfs upon initialisation of the module based on the specified coefficients without any repercussions on simulation runtime. (Basically, instead of reading in your 'look up' climate disruption df, you 'create it' based on the coefficients and any other relevant info (e.g. climate projections, facility location, ...) upon initialisation - unless I am missing something)
    Advantages:
  • Reduce resource files required (now you only need the climate projections)
  • Make your assumptions around how climate relates to disruptions more explicit (i.e. you declare coefficients explicitly) and therefore amenable to modifications later on;

Ah I see! I misinterpreted what you meant initially. Grand so, I can do it that way.

Actually @marghe-molaro I am unsure it does reduce the files, as for each scenario I still need to read in the precipitation files (which still gives one for model for each scenario). However, for your point about transparency, I think it is still worthwhile.

@marghe-molaro
Copy link
Copy Markdown
Collaborator

Hi @RachelMurray-Watson,
Great to see this being formalised this way!
Just a few comments:

  1. Agreed
  2. You can initialise the disruption dfs upon initialisation of the module based on the specified coefficients without any repercussions on simulation runtime. (Basically, instead of reading in your 'look up' climate disruption df, you 'create it' based on the coefficients and any other relevant info (e.g. climate projections, facility location, ...) upon initialisation - unless I am missing something)
    Advantages:
  • Reduce resource files required (now you only need the climate projections)
  • Make your assumptions around how climate relates to disruptions more explicit (i.e. you declare coefficients explicitly) and therefore amenable to modifications later on;

Ah I see! I misinterpreted what you meant initially. Grand so, I can do it that way.

Actually @marghe-molaro I am unsure it does reduce the files, as for each scenario I still need to read in the precipitation files (which still gives one for model for each scenario). However, for your point about transparency, I think it is still worthwhile.

Oh I see, so before you weren't loading the precipitation files at all, only the pre-computed disruptions in that scenario?

I think this way is still more future-proof, because later on you might want to link precipitation to a number of other things (e.g. specific risks to flooding, food security, etc) as well as making assumptions more explicit. But point taken!

…rameters needed to determine (a) drop in HSI appointments (from linear model) and (b) if disruption will occur, nature of disruption. Additionally including the precipitation files for 245 low/medium/high models
…ded for the weather disruptions). Uses code from rmw/climate_health_switch and rmw/climate_troublesheet_LHS. Also records population by district.
Renamed files for clarity
In params file for WeatherDisruptions, removed duplicated params
Also renamed first column for read-in by csv files
Initial code for LM *not working yet*
… added in the South West predictor

Added index to ensure the first 12 months were used, then skipped (2024, so needed to calculate lag)
…dded to the queue, but all gandled internally to the module.

Updated too so that the list is not just essential equipment, but "meets all conditions" (not weatehr disrupted, has equipment).
Added reset of counters (could all go into one log??)

Changed linear model to remove month - see not on parameter commit

Handling on NAN

Added check_for_hsi_disruption check if conditions are met, to call the linear model to calculate the disruptions

_handle_disruption determines if the disruption is supply or demand side, if mode 2, deducts from daily capabilities

_determine_reschudling handles the healthcare seeking behaviour post-disruption

_calculate_delay determines what the number of days delay there will be
# Conflicts:
#	src/tlo/methods/healthsystem.py
Also add in handling of climate disruptions in mode 2
RachelMurray-Watson and others added 28 commits March 6, 2026 16:40
Added in tests of logging, scale factors, assigning facilities, mode 2 capabilities reduction
Added in tests of logging, scale factors, assigning facilities, mode 2 capabilities reduction
…erested in disruptions, i.e. decrease in attendance, only).
…lth/year) structure; move district tracking to separate 5-level dataframes to preserve existing test compatibility
Also updated local_run_analysis to be self-contained.
Removed unused import of weather_disruptions from tlo.methods.
@RachelMurray-Watson
Copy link
Copy Markdown
Collaborator Author

I think this is finally ready for its initial review @marghe-molaro !

Copy link
Copy Markdown
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'm just including a few comments for now.

Main thing to note at present is that this PR seems to be introducing a large number of potentially unwanted changes to the HealthSystem (e.g. removing all module parameters)

# We should have 21 age range categories
assert len(AGE_RANGE_CATEGORIES) == 21

# Here we declare parameters for this module. Each parameter has a name, data type,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Wondering why this description was removed in this PR?

categories=['SET_AT_RUNTIME']
),

# Facility level assignments; categories are set in `pre_initialise_population`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

In an ideal world, we would look up facility levels declared in the HS module and then declare this dynamically. e.g. if in the HS facility levels declared are facility_levels = ["0", "1a", "1b", "2", "3"], you would create an array of properties, called something like assigned_real_facility_for_facility_level, and populate it later based on of length facility_levels, where assigned_real_facility_for_facility_level[0] refers to facility level facility_level[0]. Might not be the time to do this now, but could you add a note on this on the HealthSystem review doc?

)

# Map each TLO facility level to the facility types it encompasses
facility_levels_types = {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Similarly to comment above, this should come from the HS, i.e. not be redefined here. Not sure why you need this info?

_district_of_residence = df.at[_id_inherit_from, 'district_of_residence']
_region_of_residence = df.at[_id_inherit_from, 'region_of_residence']

# Inherit facility assignments from parent
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This seems a bit verbose/unnecessary if only used here, you can just call directly?

'cause': str(cause),
'label': self.causes_of_death[cause].label,
'person_id': individual_id,
'district_of_residence': person['district_of_residence'],
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this a change that we want to bring into master for sure? Or more relevant to your particular analysis?

symptommanager,
tb,
wasting,
weather_disruptions,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm not actually 100% sure we want the weather_disruptions to be included in the full model for now. I think a user interested in including them could more simply invoke the fullmodel and add the weather_disruptions module in the scenario file, unless we want to make weather disruptions a standard component of the full model. @tbhallett is better placed to advise.

If we do want to include this module in the full model, I suggest always including it and then declaring a parameter in that module e.g. include_weather_disruptions to decide whether they are considered or not. I think use_simplified_births option when invoking the full model is mainly used to ensure mutually exclusive sets of modules (simplified births vs everything else maternity/neonatal related) are not included at the same time

@@ -404,44 +404,6 @@ def __init__(
disable_and_reject_all: bool = False,
hsi_event_count_log_period: Optional[str] = "month",
):
"""
Copy link
Copy Markdown
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, it looks like you are removing all the HealthSystem parameters here, but not re-adding them? It must be a weird git glitch

@@ -544,20 +506,12 @@ def __init__(

self._hsi_event_count_log_period = hsi_event_count_log_period
if hsi_event_count_log_period in {"day", "month", "year", "simulation"}:
# Counters for binning HSI events run (by unique integer keys) over
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It looks like there are a lot of comments that are being removed from the HealthSystem module...just wondering why?

original_call = next_event_tuple.hsi_event.expected_time_requests
_priority = next_event_tuple.priority

# Check if any of the officers required have run out.
climate_disrupted = False
if 'WeatherDisruptions' in self.sim.modules:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Going back to the 'fullmodel' comment: this would be suboptimal because this would always be true by default. But if following my first suggestion (i.e. we don't need the WeatherDisruptions in the fullmodel) then absolutely fine

self.sim.modules['WeatherDisruptions'].check_hsi_for_disruption(
hsi_event_item=next_event_tuple,
current_date=self.sim.date
) if 'WeatherDisruptions' in self.sim.modules else (False, False)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Same as above

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.

3 participants