44import numpy as np
55from datetime import timedelta
66from typing import List
7+ import random
78
89import pytz
910
@@ -211,13 +212,15 @@ def pop_and_allocate_resource(self, task_id: str, num_allocated_tasks: int):
211212 return r_id , r_avail_at
212213
213214 def execute_task (self , c_event : EnabledEvent ):
214- r_id , r_avail_at = self .pop_and_allocate_resource (c_event .task_id , 1 )
215-
216- r_avail_at = max (c_event .enabled_at , r_avail_at )
217- avail_datetime = self ._datetime_from (r_avail_at )
218- is_working , _ = self .sim_setup .get_resource_calendar (r_id ).is_working_datetime (avail_datetime )
219- if not is_working :
220- r_avail_at = r_avail_at + self .sim_setup .next_resting_time (r_id , avail_datetime )
215+ if self .sim_setup .multitask_info is None :
216+ r_id , r_avail_at = self .pop_and_allocate_resource (c_event .task_id , 1 )
217+ r_avail_at = max (c_event .enabled_at , r_avail_at )
218+ avail_datetime = self ._datetime_from (r_avail_at )
219+ is_working , _ = self .sim_setup .get_resource_calendar (r_id ).is_working_datetime (avail_datetime )
220+ if not is_working :
221+ r_avail_at = r_avail_at + self .sim_setup .next_resting_time (r_id , avail_datetime )
222+ else :
223+ r_id , r_avail_at = self .allocate_multitasking_resource (c_event )
221224
222225 full_evt = TaskEvent (
223226 c_event .p_case ,
@@ -231,13 +234,16 @@ def execute_task(self, c_event: EnabledEvent):
231234
232235 self .log_info .add_event_info (c_event .p_case , full_evt , self .sim_setup .resources_map [r_id ].cost_per_hour )
233236
234- r_next_available = full_evt .completed_at
237+ if self .sim_setup .multitask_info is None :
238+ r_next_available = full_evt .completed_at
235239
236- if self .sim_resources [r_id ].switching_time > 0 :
237- r_next_available += self .sim_setup .next_resting_time (r_id , full_evt .completed_datetime )
240+ if self .sim_resources [r_id ].switching_time > 0 :
241+ r_next_available += self .sim_setup .next_resting_time (r_id , full_evt .completed_datetime )
238242
239- self .resource_queue .update_resource_availability (r_id , r_next_available )
240- self .sim_resources [r_id ].worked_time += full_evt .ideal_duration
243+ self .resource_queue .update_resource_availability (r_id , r_next_available )
244+ self .sim_resources [r_id ].worked_time += full_evt .ideal_duration
245+ else :
246+ self .release_multitasking_resource (r_id , full_evt , r_avail_at )
241247
242248 self .update_attributes (c_event )
243249 self .log_writer .add_csv_row (self .get_csv_row_data (full_evt ))
@@ -247,6 +253,67 @@ def execute_task(self, c_event: EnabledEvent):
247253
248254 return completed_at , completed_datetime
249255
256+ def allocate_multitasking_resource (self , c_event : EnabledEvent ):
257+ r_id , r_avail_at = self .resource_queue .pop_resource_for (c_event .task_id )
258+
259+ candidates = [[r_id , r_avail_at ]]
260+ while r_avail_at is not None and r_avail_at <= c_event .enabled_at :
261+ r_id , r_avail_at = self .resource_queue .pop_resource_for (c_event .task_id )
262+ if r_id is not None :
263+ candidates .append ([r_id , r_avail_at ])
264+
265+ if len (candidates ) > 1 :
266+ i = random .randint (0 , len (candidates ) - 1 )
267+ [r_id , r_avail_at ] = candidates [i ]
268+ for j in range (0 , len (candidates )):
269+ if j != i :
270+ self .resource_queue .update_resource_availability (candidates [j ][0 ], candidates [j ][1 ])
271+ elif r_id is None and len (candidates ) == 1 :
272+ [r_id , r_avail_at ] = candidates [0 ]
273+
274+ # best_r, best_avail = r_id, r_avail_at
275+ # while r_avail_at is not None and r_avail_at <= c_event.enabled_at:
276+ # c_workload = self.sim_setup.multitask_info.workload_diff(r_id, c_event.task_id)
277+ # if c_workload > max_workload_diff:
278+ # candidates.append([best_r, best_avail])
279+ # best_r, best_avail = r_id, r_avail_at
280+ # max_workload_diff = c_workload
281+ # else:
282+ # candidates.append([r_id, r_avail_at])
283+ # r_id, r_avail_at = self.resource_queue.pop_resource_for(c_event.task_id)
284+
285+ # print(f'Selected: {best_r, best_avail}')
286+ # if 'Loan Officer' in best_r and len(candidates) > 1:
287+ # print("hola")
288+ # if len(candidates) > 0:
289+ # # for r in candidates:
290+ # # print(r)
291+ # # print("-------------------------------------")
292+ # for j in range(0, len(candidates)):
293+ # self.resource_queue.update_resource_availability(candidates[j][0], candidates[j][1])
294+ #
295+ # r_id, r_avail_at = best_r, best_avail
296+ # self.sim_resources[r_id].allocated_tasks += 1
297+ if c_event .enabled_at > r_avail_at :
298+ next_avail_at = c_event .enabled_at
299+ avail_datetime = self ._datetime_from (next_avail_at )
300+ is_working , _ = self .sim_setup .get_resource_calendar (r_id ).is_working_datetime (avail_datetime )
301+ if not is_working :
302+ r_avail_at = r_avail_at + self .sim_setup .next_resting_time (r_id , avail_datetime )
303+
304+ return r_id , r_avail_at
305+
306+ def release_multitasking_resource (self , r_id : str , full_evt : TaskEvent , r_init_avail ):
307+ completed_dt = self ._datetime_from (full_evt .completed_at )
308+ self .sim_setup .multitask_info .allocate_task_to (r_id , full_evt .task_id , completed_dt )
309+ r_next_avail = r_init_avail
310+ if not self .sim_setup .multitask_info .can_get_new_tasks (r_id , completed_dt ):
311+ last_time = self .sim_setup .multitask_info .release_tasks_from (r_id , completed_dt )
312+ r_next_avail += self .sim_setup .next_resting_time (r_id , last_time )
313+
314+ self .resource_queue .update_resource_availability (r_id , r_next_avail )
315+ self .sim_resources [r_id ].worked_time += full_evt .ideal_duration
316+
250317 def update_attributes (self , current_event ):
251318 event_attributes = self .sim_setup .all_attributes .event_attributes .attributes
252319 global_event_attributes = self .sim_setup .all_attributes .global_event_attributes .attributes
@@ -623,7 +690,7 @@ def run_simulation(
623690 diffsim_info .set_starting_datetime (starting_at_datetime )
624691
625692 if stat_out_path is None and log_out_path is None :
626- return run_simpy_simulation (diffsim_info , None , None )
693+ return run_simpy_simulation (diffsim_info , None , None , fixed_arrival_times )
627694
628695 csv_writer_config = {
629696 'delimiter' : ',' ,
0 commit comments