@@ -554,14 +554,24 @@ class HealthSystem(Module):
554
554
"and custom (user can freely set these factors as parameters in the analysis)." ,
555
555
),
556
556
557
- 'dynamic_HR_scaling_factor' : Parameter (
558
- Types .REAL , "Factor by which HR capabilities are scaled at regular intervals of 1 year (in addition to the"
559
- " [optional] scaling with population size (controlled by `scale_HR_by_popsize`"
557
+ 'yearly_HR_scaling' : Parameter (
558
+ Types .DICT , "Factors by which HR capabilities are scaled. "
559
+ "Each sheet specifies a 'mode' for dynamic HR scaling. The mode to use is determined by the "
560
+ "parameter `yearly_HR_scaling_mode`. Each sheet must have the same format, including the same "
561
+ "column headers. On each sheet, the first row (for `2010`, when the simulation starts) "
562
+ "specifies the initial configuration: `dynamic_HR_scaling_factor` (float) is the factor by "
563
+ "which all human resoucres capabilities and multiplied; `scale_HR_by_popsize` (bool) specifies "
564
+ "whether the capabilities should (also) grow by the factor by which the population has grown in"
565
+ " the last year. Each subsequent row specifies a year where there should be a CHANGE in the "
566
+ "configuration. If there are no further rows, then there is no change. But, for example, an"
567
+ " additional row of the form ```2015, 1.05, TRUE``` would mean that on 1st January of 2015, "
568
+ "2016, 2017, ....(and the rest of the simulation), the capabilities would increase by the "
569
+ "product of 1.05 and by the ratio of the population size to that in the year previous."
560
570
),
561
571
562
- 'scale_HR_by_popsize ' : Parameter (
563
- Types .BOOL , "Decide whether to scale HR capabilities by population size every year. Can be used as well as "
564
- " the dynamic_HR_scaling_factor "
572
+ 'yearly_HR_scaling_mode ' : Parameter (
573
+ Types .STRING , "Specifies which of the policies in yearly_HR_scaling should be adopted. This corresponds to "
574
+ "a worksheet of the file `ResourceFile_dynamic_HR_scaling.xlsx`. "
565
575
),
566
576
567
577
'tclose_overwrite' : Parameter (
@@ -685,6 +695,7 @@ def __init__(
685
695
'LCOA_EHP' ]
686
696
self .arg_policy_name = policy_name
687
697
698
+
688
699
self .tclose_overwrite = None
689
700
self .tclose_days_offset_overwrite = None
690
701
@@ -820,19 +831,36 @@ def read_parameters(self, data_folder):
820
831
self .parameters ['const_HR_scaling_table' ]: Dict = pd .read_excel (
821
832
path_to_resourcefiles_for_healthsystem /
822
833
"human_resources" /
823
- "const_HR_scaling " /
834
+ "scaling_capabilities " /
824
835
"ResourceFile_const_HR_scaling.xlsx" ,
825
836
sheet_name = None # all sheets read in
826
837
)
838
+ # Ensure the mode of HR scaling to be considered in included in the tables loaded
839
+ assert self .parameters ['const_HR_scaling_mode' ] in self .parameters ['const_HR_scaling_table' ], \
840
+ f"Value of `const_HR_scaling_mode` not recognised: { self .parameters ['const_HR_scaling_mode' ]} "
841
+
842
+ self .parameters ['yearly_HR_scaling' ]: Dict = pd .read_excel (
843
+ path_to_resourcefiles_for_healthsystem /
844
+ "human_resources" /
845
+ "scaling_capabilities" /
846
+ "ResourceFile_dynamic_HR_scaling.xlsx" ,
847
+ sheet_name = None , # all sheets read in
848
+ dtype = {
849
+ 'year' : int ,
850
+ 'dynamic_HR_scaling_factor' : float ,
851
+ 'scale_HR_by_popsize' : bool
852
+ } # Ensure that these column are read as the right type
853
+ )
854
+ # Ensure the mode of yearly HR scaling to be considered in included in the tables loaded
855
+ assert self .parameters ['yearly_HR_scaling_mode' ] in self .parameters ['yearly_HR_scaling' ], \
856
+ f"Value of `yearly_HR_scaling` not recognised: { self .parameters ['yearly_HR_scaling_mode' ]} "
857
+ # Ensure that a value for the year at the start of the simulation is provided.
858
+ assert all (2010 in sheet ['year' ].values for sheet in self .parameters ['yearly_HR_scaling' ].values ())
827
859
828
860
829
861
def pre_initialise_population (self ):
830
862
"""Generate the accessory classes used by the HealthSystem and pass to them the data that has been read."""
831
863
832
- # Ensure the mode of HR scaling to be considered in included in the tables loaded
833
- assert self .parameters ['const_HR_scaling_mode' ] in self .parameters ['const_HR_scaling_table' ], \
834
- f"Value of `const_HR_scaling_mode` not recognised: { self .parameters ['const_HR_scaling_mode' ]} "
835
-
836
864
# Create dedicated RNGs for separate functions done by the HealthSystem module
837
865
self .rng_for_hsi_queue = np .random .RandomState (self .rng .randint (2 ** 31 - 1 ))
838
866
self .rng_for_dx = np .random .RandomState (self .rng .randint (2 ** 31 - 1 ))
@@ -914,10 +942,10 @@ def initialise_simulation(self, sim):
914
942
sim .schedule_event (HealthSystemChangeMode (self ),
915
943
Date (self .parameters ["year_mode_switch" ], 1 , 1 ))
916
944
917
- # Schedule recurring event which will rescale daily capabilities at regular intervals.
918
- # The first event scheduled will only be used to update self.last_year_pop_size parameter ,
919
- # actual scaling will only take effect from 2011 onwards
920
- sim .schedule_event (DynamicRescalingHRCapabilities (self ), Date (sim .date ) + pd . DateOffset ( years = 1 ) )
945
+ # Schedule recurring event which will rescale daily capabilities ( at yearly intervals) .
946
+ # The first event scheduled for the start of the simulation is only used to update self.last_year_pop_size,
947
+ # whilst the actual scaling will only take effect from 2011 onwards.
948
+ sim .schedule_event (DynamicRescalingHRCapabilities (self ), Date (sim .date ))
921
949
922
950
def on_birth (self , mother_id , child_id ):
923
951
self .bed_days .on_birth (self .sim .population .props , mother_id , child_id )
@@ -2861,27 +2889,42 @@ class DynamicRescalingHRCapabilities(RegularEvent, PopulationScopeEventMixin):
2861
2889
""" This event exists to scale the daily capabilities assumed at fixed time intervals"""
2862
2890
def __init__ (self , module ):
2863
2891
super ().__init__ (module , frequency = DateOffset (years = 1 ))
2864
- self .last_year_pop_size = self .current_pop_size # store population size at initiation (when this class is
2865
- # created)
2892
+ self .last_year_pop_size = self .current_pop_size # will store population size at initiation (when this class is
2893
+ # created, at the start of the simulation)
2894
+
2895
+ # Store the sequence of updates as a dict of the form
2896
+ # {<year_of_change>: {`dynamic_HR_scaling_factor`: float, `scale_HR_by_popsize`: bool}}
2897
+ self .scaling_values = self .module .parameters ['yearly_HR_scaling' ][
2898
+ self .module .parameters ['yearly_HR_scaling_mode' ]].set_index ("year" ).to_dict ("index" )
2866
2899
2867
2900
@property
2868
2901
def current_pop_size (self ) -> float :
2869
2902
"""Returns current population size"""
2870
2903
df = self .sim .population .props
2871
2904
return df .is_alive .sum ()
2872
2905
2873
- def apply (self , population ):
2906
+ def _get_most_recent_year_specified_for_a_change_in_configuration (self ) -> int :
2907
+ """Get the most recent year (in the past), for which there is an entry in `parameters['yearly_HR_scaling']`."""
2908
+ years = np .array (list (self .scaling_values .keys ()))
2909
+ return years [years <= self .sim .date .year ].max ()
2874
2910
2911
+ def apply (self , population ):
2912
+ """Do the scaling on the capabilities based on instruction that is in force at this time."""
2913
+ # Get current population size
2875
2914
this_year_pop_size = self .current_pop_size
2876
2915
2877
- # Rescale by fixed amount
2878
- self .module ._daily_capabilities *= self .module .parameters ['dynamic_HR_scaling_factor' ]
2916
+ # Get the configuration to apply now (the latest entry in the `parameters['yearly_HR_scaling']`)
2917
+ config = self .scaling_values .get (self ._get_most_recent_year_specified_for_a_change_in_configuration ())
2918
+
2919
+ # ... Do the rescaling specified for this year by the specified factor
2920
+ self .module ._daily_capabilities *= config ['dynamic_HR_scaling_factor' ]
2879
2921
2880
- # Rescale daily capabilities by population size, if this option is included
2881
- if self . module . parameters ['scale_HR_by_popsize' ]:
2882
- self .module ._daily_capabilities *= this_year_pop_size / self .last_year_pop_size
2922
+ # ... If requested, also do the scaling for the population growth that has occurred since the last year
2923
+ if config ['scale_HR_by_popsize' ]:
2924
+ self .module ._daily_capabilities *= this_year_pop_size / self .last_year_pop_size
2883
2925
2884
- self .last_year_pop_size = this_year_pop_size # Save for next year
2926
+ # Save current population size as that for 'last year'.
2927
+ self .last_year_pop_size = this_year_pop_size
2885
2928
2886
2929
2887
2930
class HealthSystemChangeMode (RegularEvent , PopulationScopeEventMixin ):
0 commit comments