Skip to content

Improving Performance (And Functionality) of HealthSystem Module

Matt Graham edited this page Jun 28, 2021 · 8 revisions

For discussion with Matt/Asif, 7th June 2021

Ideas for improving performance

  • Computing Squeeze-Factors (lines 1349-1381) (The squeeze factor is the "sf = (total time requested of healthcare workers / total time available of healthcare workers) -1"):
    • Do not recompute squeeze factors if an HSI has a different APPT_FOOTPRINT to that in it's EXPECTED_APPT_FOOTPRINT (lines 1410-1422). This is a rare occurrence and it is not necessary from the 'squeeze factors' to be recomputed for minor updates.
    • Computing of squeeze-factors does not need to be exact as done currently: it can simply be to the level of whether the squeeze is "any" (sf > 0) or "none" (sf <= 0).
    • Computing of squeeze-factors does not need to be at all when running in mode=0
  • Things arising from get_appt_footprint_as_time_request (per discussion on Matt's earlier PR: https://github.com/UCL/TLOmodel/pull/287):
    • To update get_appt_footprint_as_time_request to return a dict rather than pandas.Series and update the downstream code which calls it to work with dict objects rather than Series.
    • Potentially precomputing the sums of time taken for each officer for each combination of appointment and facility types.
    • Changing the data structure used to store the appointment footprint for each HSI event to be a list (or similar) with only the relevant entries rather than a dictionary with 1 / 0 values to indicate appointment types being included or not.
  • Avoid re-computing things about the HSI if it is held-over from a previous day. If an HSI is not run, the information computed about it (time requested of which health care workers at which facility) is lost and must be recomputed the next day. It would seem better if this information was computed once and stored inside the HSI itself.
  • Define a properties in main df (simulation.population.props) for the facilities to which person has access to avoid having to work out this out all the time. It's done currently in healthsystem.py at line 663 for each HSI. This is inefficient as this information is stable for the person over their entire lifetime.
  • The Generic Appointments (see hsi_generic_first_appts.py) run many times each day (but hopefully not multiple times for the same person on any one day). Almost all (all?) of these are set following onset of symptoms (see healthseekingbehaviour.py line 255-292) Would it be more efficient to make this more like a population event, wherein a list of person_ids is collected and the HSI_GenericFirstApptAtFacilityLevelX is run once (looping through each person inside the event itself).

An all-consuming Mega Change

A lot of the above would become less important with this (quite desirable to me) mega-change:

  • A declaration of HSI_Events by modules prior the start of the simulation. Each module is responsible for a handful of different types of HSI_Event, and the configuration of these is known prior to the start of simulation (with exception of the associated person_id and facility_level (and so the Facility_IDs at which the HSI_Event will occur). If these could be declared in advance of the simulation running, then:
    • The (time-consuming) conversion of the EXPECTED_APPT_FOOTPRINT to the time required of each type of Health Worker could be computed once only.
    • The properties of all HSI could be inspected easily (e.g. see difficulties of doing this here: https://github.com/UCL/TLOmodel/issues/255). This is useful for:
      • documentation
      • systematically excluding from runs each type of HSI (or a set of HSI) in order to estimate its "specific health benefit".

Necessary Improvements To Functionality

  • If the HSI runs and has a different APPT_FOOTPRINT to that in it's EXPECTED_APPT_FOOTPRINT (line 1405), then let the logged usage of healthcare worker time reflect this. (This is a rare occurrence). Currently, nothing comes back from calling event.run() (https://github.com/UCL/TLOmodel/issues/291)

  • Log facility_level of each run HSI and (create analysis script to display summaries of time consumed of each HCW at each level) (per issue: https://github.com/UCL/TLOmodel/issues/169)

  • Incorporate 'scaling' of healthsystem capabilities (through capabilities_coefficient (?) to match population size. (per issue: https://github.com/UCL/TLOmodel/issues/169)

  • Demonstrate and test performance of different modes of constraints in health systems with toy examples (per issue: https://github.com/UCL/TLOmodel/issues/169)

  • Modularise/Vecotrize the Generic HSI: to make run each day and to people in batches. And to make it easier to manage all the disease modules editing this. Perhaps sending in function handles, and conditions. (Currently there is a lot of editing and dependency in this file and it needs to be cleaned up such that disease modules register the logic that they would like the generic first appt to do for them: sending function handles etc.) (per issue: https://github.com/UCL/TLOmodel/issues/169)

  • Need to report on the impact of removing each HSI, or set of HSI, on health gains (to isolate effect of each HSI).

Non-Essential Improvements to Functionality

  • Modularise-out the three components of the module: health-care worker time, bed-days (in progress) and consumables. (per issue: https://github.com/UCL/TLOmodel/issues/169)

  • Communication between the HealthSystem module and the HSI_Event is done in a different way for each resource being tracked. It may be nice to unify these in some way!

    • Consumables: the HSI_Event requests the consumables at run-time (using request_consumables or via the helper function get_all_consumables)
    • Squeeze-factors: these are passed to the HSI_Event run it's run as an argument to its member function apply
    • Bed-Days: this is written into a @property called bed_days_allocated_to_this_event.
  • The system for alerting other modules (broadcast_healthsystem_interaction line 514) is not used and can be removed

  • Consumables: differentiate between optional and essential, whereby optional consumables are logged, but are immaterial to a signal computed on whether all 'non-optional' consumables are available.

(Line references are wrt master at time of writing.)

Clone this wiki locally