Skip to content

Commit 1dea058

Browse files
committed
Allow for multiple options in the GlobalTaskShifting resource file. This will be required for comparing scenarios
1 parent a2490a4 commit 1dea058

File tree

3 files changed

+72
-33
lines changed

3 files changed

+72
-33
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
version https://git-lfs.github.com/spec/v1
2-
oid sha256:cd5b508bfbb7b430cc05f116fd92df79e4663aff9d480e4ebd94dfa73530677e
3-
size 420
2+
oid sha256:df273f1a413b6d6c2cc81f392aa62e00fea78f67631d2bc802a78e3474a7356d
3+
size 426

src/tlo/methods/healthsystem.py

+58-18
Original file line numberDiff line numberDiff line change
@@ -564,9 +564,14 @@ class HealthSystem(Module):
564564
" the dynamic_HR_scaling_factor"
565565
),
566566

567-
'include_task_shifting': Parameter(
568-
Types.BOOL, "Decide whether to allow for task-shifting in mode 2"
569-
),
567+
'global_task_shifting_mode': Parameter(
568+
Types.STRING, "Name of global task-shifting mode adopted"),
569+
570+
'global_task_shifting': Parameter(
571+
Types.DICT, "Global task-shifting policy adopted by the health care system. It includes a list of the officers"
572+
" eligible for task shifting. For each of those officers, it specifies which officers"
573+
" can take over the officer's tasks, and a factor explaining how the originally scheduled time "
574+
" should be scaled if performed by a different officer."),
570575

571576
'tclose_overwrite': Parameter(
572577
Types.INT, "Decide whether to overwrite tclose variables assigned by disease modules"),
@@ -603,7 +608,7 @@ def __init__(
603608
beds_availability: Optional[str] = None,
604609
randomise_queue: bool = True,
605610
ignore_priority: bool = False,
606-
include_task_shifting: bool = False,
611+
global_task_shifting_mode: Optional[str] = None,
607612
policy_name: Optional[str] = None,
608613
capabilities_coefficient: Optional[float] = None,
609614
use_funded_or_actual_staffing: Optional[str] = None,
@@ -665,14 +670,6 @@ def __init__(
665670
assert not (ignore_priority and policy_name is not None), (
666671
'Cannot adopt a priority policy if the priority will be then ignored'
667672
)
668-
669-
# Global task-shifting options. The key in the dictionary refers to the officer
670-
# eligible for task shifting, while the values refer to the officers that can take
671-
# over the officer's tasks. The numbers refer to the factor by which appt time will
672-
# have to be scaled if task is performed by alternative officer.
673-
self.global_task_shifting = {
674-
'Pharmacy': (['Nursing_and_Midwifery', 'Clinical'], [1.5,1]),
675-
}
676673

677674
self.disable = disable
678675
self.disable_and_reject_all = disable_and_reject_all
@@ -689,8 +686,6 @@ def __init__(
689686

690687
self.ignore_priority = ignore_priority
691688

692-
self.include_task_shifting = include_task_shifting
693-
694689
# This default value will be overwritten if assumed policy is not None
695690
self.lowest_priority_considered = 2
696691

@@ -701,6 +696,8 @@ def __init__(
701696
'VerticalProgrammes', 'ClinicallyVulnerable', 'EHP_III',
702697
'LCOA_EHP']
703698
self.arg_policy_name = policy_name
699+
700+
self.arg_global_task_shifting_mode = global_task_shifting_mode
704701

705702
self.tclose_overwrite = None
706703
self.tclose_days_offset_overwrite = None
@@ -833,6 +830,11 @@ def read_parameters(self, data_folder):
833830
self.parameters['priority_rank'] = pd.read_excel(path_to_resourcefiles_for_healthsystem / 'priority_policies' /
834831
'ResourceFile_PriorityRanking_ALLPOLICIES.xlsx',
835832
sheet_name=None)
833+
834+
self.parameters['global_task_shifting'] = pd.read_excel(path_to_resourcefiles_for_healthsystem / 'human_resources'/
835+
'task_shifting'/'ResourceFile_GlobalTaskShifting.xlsx',
836+
sheet_name=None)
837+
836838

837839
self.parameters['const_HR_scaling_table']: Dict = pd.read_excel(
838840
path_to_resourcefiles_for_healthsystem /
@@ -887,6 +889,9 @@ def pre_initialise_population(self):
887889

888890
# Set up framework for considering a priority policy
889891
self.setup_priority_policy()
892+
893+
# Set up framework for considering a global task-shifting policy
894+
self.setup_global_task_shifting(self.parameters['global_task_shifting_mode'])
890895

891896

892897
def initialise_population(self, population):
@@ -988,6 +993,37 @@ def setup_priority_policy(self):
988993
self.list_fasttrack.append(('hv_diagnosed', 'FT_if_Hivdiagnosed'))
989994
if 'Tb' in self.sim.modules:
990995
self.list_fasttrack.append(('tb_diagnosed', 'FT_if_tbdiagnosed'))
996+
997+
def setup_global_task_shifting(self,mode):
998+
999+
# Select the global task shifting mode to be considered
1000+
self.global_task_shifting_mode = self.get_global_task_shifting_mode_initial()
1001+
1002+
# Load relevant sheet from resource file
1003+
df = self.parameters['global_task_shifting'][self.global_task_shifting_mode]
1004+
1005+
self.global_task_shifting = {}
1006+
1007+
# Iterate through the rows of the DataFrame and populate the dictionary
1008+
for index, row in df.iterrows():
1009+
officer = row['Officer']
1010+
alternative_officers = row['Alternative_officer'].split(',')
1011+
time_factor_str = str(row['Time_factor'])
1012+
1013+
# Split the string into a list of floats
1014+
time_factors = [float(factor) for factor in time_factor_str.split(',')]
1015+
1016+
# Create the entry in the dictionary
1017+
self.global_task_shifting[officer] = (alternative_officers, time_factors)
1018+
1019+
if len(self.global_task_shifting) == 0:
1020+
self.include_task_shifting = False
1021+
else:
1022+
self.include_task_shifting = True
1023+
1024+
# Print the resulting dictionary
1025+
print("self.global_task_shifting =", self.global_task_shifting)
1026+
9911027

9921028
def process_human_resources_files(self, use_funded_or_actual_staffing: str):
9931029
"""Create the data-structures needed from the information read into the parameters."""
@@ -1324,6 +1360,14 @@ def get_priority_policy_initial(self) -> str:
13241360
return self.parameters['policy_name'] \
13251361
if self.arg_policy_name is None \
13261362
else self.arg_policy_name
1363+
1364+
def get_global_task_shifting_mode_initial(self) -> str:
1365+
"""Returns `priority_policy`. (Should be equal to what is specified by the parameter, but
1366+
overwrite with what was provided in argument if an argument was specified -- provided for backward
1367+
compatibility/debugging.)"""
1368+
return self.parameters['global_task_shifting_mode'] \
1369+
if self.arg_global_task_shifting_mode is None \
1370+
else self.arg_global_task_shifting_mode
13271371

13281372
def load_priority_policy(self, policy):
13291373

@@ -2922,7 +2966,6 @@ class HealthSystemChangeParameters(Event, PopulationScopeEventMixin):
29222966
"""Event that causes certain internal parameters of the HealthSystem to be changed; specifically:
29232967
* `mode_appt_constraints`
29242968
* `ignore_priority`
2925-
* `include_task_shifting`
29262969
* `capabilities_coefficient`
29272970
* `cons_availability`
29282971
* `beds_availability`
@@ -2939,9 +2982,6 @@ def apply(self, population):
29392982

29402983
if 'ignore_priority' in self._parameters:
29412984
self.module.ignore_priority = self._parameters['ignore_priority']
2942-
2943-
if 'include_task_shifting' in self._parameters:
2944-
self.module.include_task_shifting = self._parameters['include_task_shifting']
29452985

29462986
if 'capabilities_coefficient' in self._parameters:
29472987
self.module.capabilities_coefficient = self._parameters['capabilities_coefficient']

tests/test_healthsystem.py

+12-13
Original file line numberDiff line numberDiff line change
@@ -1258,15 +1258,13 @@ def test_HealthSystemChangeParameters(seed, tmpdir):
12581258
initial_parameters = {
12591259
'mode_appt_constraints': 0,
12601260
'ignore_priority': False,
1261-
'include_task_shifting': False,
12621261
'capabilities_coefficient': 0.5,
12631262
'cons_availability': 'all',
12641263
'beds_availability': 'default',
12651264
}
12661265
new_parameters = {
12671266
'mode_appt_constraints': 2,
12681267
'ignore_priority': True,
1269-
'include_task_shifting': True,
12701268
'capabilities_coefficient': 1.0,
12711269
'cons_availability': 'none',
12721270
'beds_availability': 'none',
@@ -1282,7 +1280,6 @@ def apply(self, population):
12821280
_params = dict()
12831281
_params['mode_appt_constraints'] = hs.mode_appt_constraints
12841282
_params['ignore_priority'] = hs.ignore_priority
1285-
_params['include_task_shifting'] = hs.include_task_shifting
12861283
_params['capabilities_coefficient'] = hs.capabilities_coefficient
12871284
_params['cons_availability'] = hs.consumables.cons_availability
12881285
_params['beds_availability'] = hs.bed_days.availability
@@ -2003,7 +2000,7 @@ def simulate(task_shifting_option, Ntarget):
20032000
healthsystem.HealthSystem(resourcefilepath=resourcefilepath,
20042001
capabilities_coefficient=1.0,
20052002
mode_appt_constraints=2,
2006-
include_task_shifting=task_shifting_option,
2003+
global_task_shifting_mode=task_shifting_option,
20072004
ignore_priority=False,
20082005
randomise_queue=True,
20092006
policy_name="",
@@ -2055,14 +2052,16 @@ def simulate(task_shifting_option, Ntarget):
20552052
nursing_task_time = hsi1.expected_time_requests['FacilityID_' + str(facID) + '_Officer_Nursing_and_Midwifery']
20562053
clinical_task_time = hsi1.expected_time_requests['FacilityID_' + str(facID) + '_Officer_Clinical']
20572054

2058-
# Check that first choice of task-shifting officer for Pharmacy is Nursing_and_Midwifery, and get their factor
2059-
assert 'Nursing_and_Midwifery' == sim.modules['HealthSystem'].global_task_shifting.get('Pharmacy')[0][0]
2060-
nursing_task_shift_factor = sim.modules['HealthSystem'].global_task_shifting.get('Pharmacy')[1][0]
2055+
if task_shifting_option == 'default':
2056+
nursing_task_shift_factor = 0
2057+
else:
2058+
assert 'Nursing_and_Midwifery' == sim.modules['HealthSystem'].global_task_shifting.get('Pharmacy')[0][0]
2059+
nursing_task_shift_factor = sim.modules['HealthSystem'].global_task_shifting.get('Pharmacy')[1][0]
20612060

20622061
# Always set Pharmacy capabilities to zero. Set Clinical and Nursing capabilities such that Ntarget appointments
20632062
# can be delivered by relying on task-shifting from Nursing only. Setting Clinical time to Ntarget x clinical_task_time
20642063
# checks that when task-shifting first option (nurses) where always preferentially chosen over second.
2065-
# one (clinicians)
2064+
# one (clinicians)
20662065
sim.modules['HealthSystem']._daily_capabilities['FacilityID_' + str(facID) + '_Officer_Pharmacy'] = 0.0
20672066
sim.modules['HealthSystem']._daily_capabilities['FacilityID_' + str(facID) + '_Officer_Clinical'] = Ntarget*(clinical_task_time)
20682067
sim.modules['HealthSystem']._daily_capabilities['FacilityID_' + str(facID) + '_Officer_Nursing_and_Midwifery'] = Ntarget*(nursing_task_time + nursing_task_shift_factor*pharmacy_task_time)
@@ -2080,14 +2079,14 @@ def simulate(task_shifting_option, Ntarget):
20802079
# appointments can be performed iff using task-shifting
20812080
Ntarget = 50
20822081

2083-
# Allow for task-shifting to take place, and check that all Ntarget events could run, even if Pharmacy
2082+
# Allow for task-shifting to take place (by adopting the naive mode), and check that all Ntarget events could run, even if Pharmacy
20842083
# capabilities were set to zero,
2085-
hs_output = simulate(task_shifting_option=True, Ntarget=Ntarget)
2084+
hs_output = simulate(task_shifting_option='naive', Ntarget=Ntarget)
20862085
assert hs_output['did_run'].sum() == Ntarget
20872086

2088-
# Do not allow for task-shifting to take place, and check that as a result no events could run, since
2089-
# Pharmacy capabilities were set to zero.
2090-
hs_output = simulate(task_shifting_option=False, Ntarget=Ntarget)
2087+
# Do not allow for task-shifting to take place (by adopting the default mode), and check that as a
2088+
# result no events could run, since Pharmacy capabilities were set to zero.
2089+
hs_output = simulate(task_shifting_option='default', Ntarget=Ntarget)
20912090
assert hs_output['did_run'].sum() == 0
20922091

20932092

0 commit comments

Comments
 (0)