Skip to content

Commit 2bb6f43

Browse files
Fix to read in Legacy versus Updated Consumables RF (#1791)
* fix script to read in legacy or updated consumable availability resource file * fix tests and preseve module contract --------- Co-authored-by: Tim Hallett <39991060+tbhallett@users.noreply.github.com>
1 parent 3392066 commit 2bb6f43

File tree

2 files changed

+74
-17
lines changed

2 files changed

+74
-17
lines changed

src/tlo/methods/healthsystem.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,8 @@ class HealthSystem(Module):
207207
"consumables in the merged 1b/2 facility level."
208208
),
209209
"availability_estimates": Parameter(
210-
Types.DATA_FRAME, "Estimated availability of consumables in the LMIS dataset."
210+
Types.DICT, "Estimated availability of consumables in the LMIS dataset. Dict contains all the databases "
211+
"that might be selected using `data_source_for_cons_availability_estimates`"
211212
),
212213
"cons_availability": Parameter(
213214
Types.STRING,
@@ -646,18 +647,12 @@ def read_parameters(self, resourcefilepath: Optional[Path] = None):
646647
dtype={"Item_Code": int, "is_diagnostic": bool, "is_medicine": bool, "is_other": bool},
647648
).set_index("Item_Code")
648649

649-
# Choose to read-in the updated availabilty estimates or the legacy availability estimates
650-
if self.parameters["data_source_for_cons_availability_estimates"] == 'original':
651-
filename_for_cons_availability_estimates = "ResourceFile_Consumables_availability_small_original.csv"
652-
elif self.parameters["data_source_for_cons_availability_estimates"] == 'updated':
653-
filename_for_cons_availability_estimates = "ResourceFile_Consumables_availability_small.csv"
654-
else:
655-
raise ValueError("data_source_for_cons_availability_estimates should be either 'original' or 'updated'")
656-
657-
self.parameters["availability_estimates"] = pd.read_csv(
658-
path_to_resourcefiles_for_healthsystem / "consumables" / filename_for_cons_availability_estimates
659-
)
660-
650+
def read_consumables(filename):
651+
return pd.read_csv(path_to_resourcefiles_for_healthsystem / "consumables" / filename)
652+
self.parameters["availability_estimates"] = {
653+
"original": read_consumables("ResourceFile_Consumables_availability_small_original.csv"),
654+
"updated": read_consumables("ResourceFile_Consumables_availability_small.csv"),
655+
}
661656

662657
# Data on the number of beds available of each type by facility_id
663658
self.parameters["BedCapacity"] = pd.read_csv(
@@ -797,11 +792,14 @@ def pre_initialise_population(self):
797792
self.bed_days = BedDays(hs_module=self, availability=self.get_beds_availability())
798793
self.bed_days.pre_initialise_population()
799794

795+
# Confirm availability data for consumables
796+
_availability_data = self.update_consumables_availability_to_represent_merging_of_levels_1b_and_2(
797+
self.parameters["availability_estimates"][self.parameters["data_source_for_cons_availability_estimates"]]
798+
)
799+
800800
# Initialise the Consumables class
801801
self.consumables = Consumables(
802-
availability_data=self.update_consumables_availability_to_represent_merging_of_levels_1b_and_2(
803-
self.parameters["availability_estimates"]
804-
),
802+
availability_data=_availability_data,
805803
item_code_designations=self.parameters["consumables_item_designations"],
806804
rng=rng_for_consumables,
807805
availability=self.get_cons_availability(),

tests/test_consumables.py

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,8 @@ def initialise_simulation(self, sim):
354354
)
355355

356356
if data is not None:
357-
sim.modules['HealthSystem'].parameters['availability_estimates'] = data
357+
sim.modules['HealthSystem'].parameters['data_source_for_cons_availability_estimates'] = 'data'
358+
sim.modules['HealthSystem'].parameters['availability_estimates'] = {'data' :data}
358359

359360
sim.make_initial_population(n=100)
360361

@@ -707,3 +708,61 @@ def test_consumables_availability_modes_that_depend_on_designations(seed):
707708
assert isinstance(comparison, bool), 'Comparison went wrong: {availability=}'
708709
assert not consumables._prob_item_codes_available.equals(default_consumables_availability), \
709710
f"No change in actual avaialbility when: {availability=}"
711+
712+
713+
def test_switch_between_different_cons_availability_databases(seed):
714+
"""Check that option to change consumable availability data source works as expected"""
715+
716+
# Import the 'raw' datasets for consumables availability
717+
path_to_files = resourcefilepath / 'healthsystem' / 'consumables'
718+
options_for_availability = {
719+
'original': pd.read_csv(path_to_files / 'ResourceFile_Consumables_availability_small_original.csv'),
720+
'updated': pd.read_csv(path_to_files / 'ResourceFile_Consumables_availability_small.csv'),
721+
}
722+
723+
# Sample availability of the raw datasets, where we know they are different:
724+
_facility_id = 2
725+
_month = 1
726+
def get_sample_availability(df):
727+
return df.loc[
728+
(df.Facility_ID == _facility_id) & (df.month == _month),
729+
['item_code', 'available_prop']
730+
].set_index('item_code')['available_prop'].to_dict()
731+
sample_availability_in_raw_data = {k : get_sample_availability(v) for k, v in options_for_availability.items()}
732+
733+
# Confirm that the samples from these two raw datasets are different
734+
assert sample_availability_in_raw_data['original'] != sample_availability_in_raw_data['updated']
735+
736+
# Use different options (swithced after module registration) and confirm that the live data being used in the
737+
# module matches the intended raw data
738+
for which_option in options_for_availability.keys():
739+
sim = Simulation(
740+
start_date=Date(2010, 1, 1),
741+
seed=seed,
742+
resourcefilepath=resourcefilepath
743+
)
744+
745+
746+
# Register the core modules
747+
sim.register(
748+
demography.Demography(),
749+
healthsystem.HealthSystem(),
750+
)
751+
752+
# Make the decision to switch following module registration
753+
sim.modules['HealthSystem'].parameters['cons_availability'] = 'default'
754+
sim.modules['HealthSystem'].parameters['data_source_for_cons_availability_estimates'] = which_option
755+
756+
# Initialise the simulation and capture the 'live' data being used in the Consumables module
757+
sim.make_initial_population(n=100)
758+
sim.simulate(end_date=sim.start_date)
759+
hs = sim.modules['HealthSystem']
760+
consumables_live_data = hs.consumables._availability_data
761+
762+
# check availability actually held by consumables class during simulation matches intended data source
763+
sample_availability_in_live_data = consumables_live_data.loc[
764+
(consumables_live_data.Facility_ID == _facility_id) & (consumables_live_data.month == _month),
765+
['item_code', 'available_prop']
766+
].set_index('item_code')['available_prop'].to_dict()
767+
768+
assert sample_availability_in_live_data == sample_availability_in_raw_data[which_option]

0 commit comments

Comments
 (0)