@@ -541,6 +541,19 @@ class HealthSystem(Module):
541
541
" the priority, and on which categories of individuals classify for fast-tracking "
542
542
" for specific treatments" ),
543
543
544
+ 'const_HR_scaling_table' : Parameter (
545
+ Types .DICT , "Factors by which capabilities of medical officer categories at different levels will be"
546
+ "scaled at the start of the simulation to simulate a number of effects (e.g. absenteeism,"
547
+ "boosting of specific medical cadres, etc). This is the imported from an"
548
+ "Excel workbook: keys are the worksheet names and values are the worksheets in "
549
+ "the format of pd.DataFrames." ),
550
+
551
+ 'const_HR_scaling_mode' : Parameter (
552
+ Types .STRING , "Mode of HR scaling considered at the start of the simulation. Options are default"
553
+ " (capabilities are scaled by a constaint factor of 1), data (factors informed by survey data),"
554
+ "and custom (user can freely set these factors as parameters in the analysis)." ,
555
+ ),
556
+
544
557
'tclose_overwrite' : Parameter (
545
558
Types .INT , "Decide whether to overwrite tclose variables assigned by disease modules" ),
546
559
@@ -794,8 +807,22 @@ def read_parameters(self, data_folder):
794
807
'ResourceFile_PriorityRanking_ALLPOLICIES.xlsx' ,
795
808
sheet_name = None )
796
809
810
+ self .parameters ['const_HR_scaling_table' ]: Dict = pd .read_excel (
811
+ path_to_resourcefiles_for_healthsystem /
812
+ "human_resources" /
813
+ "const_HR_scaling" /
814
+ "ResourceFile_const_HR_scaling.xlsx" ,
815
+ sheet_name = None # all sheets read in
816
+ )
817
+
818
+
797
819
def pre_initialise_population (self ):
798
820
"""Generate the accessory classes used by the HealthSystem and pass to them the data that has been read."""
821
+
822
+ # Ensure the mode of HR scaling to be considered in included in the tables loaded
823
+ assert self .parameters ['const_HR_scaling_mode' ] in self .parameters ['const_HR_scaling_table' ], \
824
+ f"Value of `const_HR_scaling_mode` not recognised: { self .parameters ['const_HR_scaling_mode' ]} "
825
+
799
826
# Create dedicated RNGs for separate functions done by the HealthSystem module
800
827
self .rng_for_hsi_queue = np .random .RandomState (self .rng .randint (2 ** 31 - 1 ))
801
828
self .rng_for_dx = np .random .RandomState (self .rng .randint (2 ** 31 - 1 ))
@@ -834,6 +861,7 @@ def pre_initialise_population(self):
834
861
# Set up framework for considering a priority policy
835
862
self .setup_priority_policy ()
836
863
864
+
837
865
def initialise_population (self , population ):
838
866
self .bed_days .initialise_population (population .props )
839
867
@@ -932,6 +960,8 @@ def setup_priority_policy(self):
932
960
def process_human_resources_files (self , use_funded_or_actual_staffing : str ):
933
961
"""Create the data-structures needed from the information read into the parameters."""
934
962
963
+
964
+
935
965
# * Define Facility Levels
936
966
self ._facility_levels = set (self .parameters ['Master_Facilities_List' ]['Facility_Level' ]) - {'5' }
937
967
assert self ._facility_levels == {'0' , '1a' , '1b' , '2' , '3' , '4' } # todo soft code this?
@@ -1031,6 +1061,28 @@ def process_human_resources_files(self, use_funded_or_actual_staffing: str):
1031
1061
# never available.)
1032
1062
self ._officers_with_availability = set (self ._daily_capabilities .index [self ._daily_capabilities > 0 ])
1033
1063
1064
+ def adjust_for_const_HR_scaling (self , df : pd .DataFrame ) -> pd .DataFrame :
1065
+ """Adjust the Daily_Capabilities pd.DataFrame to account for assumptions about scaling of HR resources"""
1066
+
1067
+ # Get the set of scaling_factors that are specified by the 'const_HR_scaling_mode' assumption
1068
+ const_HR_scaling_factor = self .parameters ['const_HR_scaling_table' ][self .parameters ['const_HR_scaling_mode' ]]
1069
+ const_HR_scaling_factor = const_HR_scaling_factor .set_index ('Officer_Category' )
1070
+
1071
+ level_conversion = {"1a" : "L1a_Av_Mins_Per_Day" , "1b" : "L1b_Av_Mins_Per_Day" ,
1072
+ "2" : "L2_Av_Mins_Per_Day" , "0" : "L0_Av_Mins_Per_Day" , "3" : "L3_Av_Mins_Per_Day" ,
1073
+ "4" : "L4_Av_Mins_Per_Day" , "5" : "L5_Av_Mins_Per_Day" }
1074
+
1075
+ scaler = df [['Officer_Category' , 'Facility_Level' ]].apply (
1076
+ lambda row : const_HR_scaling_factor .loc [row ['Officer_Category' ], level_conversion [row ['Facility_Level' ]]],
1077
+ axis = 1
1078
+ )
1079
+
1080
+ # Apply scaling to 'Total_Mins_Per_Day'
1081
+ df ['Total_Mins_Per_Day' ] *= scaler
1082
+
1083
+ return df
1084
+
1085
+
1034
1086
def format_daily_capabilities (self , use_funded_or_actual_staffing : str ) -> pd .Series :
1035
1087
"""
1036
1088
This will updates the dataframe for the self.parameters['Daily_Capabilities'] so as to include
@@ -1044,7 +1096,10 @@ def format_daily_capabilities(self, use_funded_or_actual_staffing: str) -> pd.Se
1044
1096
1045
1097
# Get the capabilities data imported (according to the specified underlying assumptions).
1046
1098
capabilities = pool_capabilities_at_levels_1b_and_2 (
1047
- self .parameters [f'Daily_Capabilities_{ use_funded_or_actual_staffing } ' ])
1099
+ self .adjust_for_const_HR_scaling (
1100
+ self .parameters [f'Daily_Capabilities_{ use_funded_or_actual_staffing } ' ]
1101
+ )
1102
+ )
1048
1103
capabilities = capabilities .rename (columns = {'Officer_Category' : 'Officer_Type_Code' }) # neaten
1049
1104
1050
1105
# Create dataframe containing background information about facility and officer types
0 commit comments