Question: I am currently working on a model which simulates a delivery process throughout an operating day in simpy. The deliveries are conducted by riders which are delivering one package at a time. The packages need to be delivered within a certain time window. In addition, the system deals with fluctuating demand throughout the day. Therefore, I would like to adapt the number of employees available to the system matching the fluctuating demand on an hourly basis. I modelled the riders as a resource with a certain capacity. Is there any possibility to adjust the capacity of the resource during a simulation run or are there other ways to model the riders with my system? I already looked for possible solution within the simpy documentation, examples or other posts. However, I was not successful yet. Thus, for any advice or possible solutions I would be very grateful! Thank you in advance.

Answer: Use a store instead of a resource. Resources has a fix number of resources. Stores works a bit like a bit more like a queue backed with a list with a optional max capacity. To reduce then number in the store, just stop putting the object back into the store. So is a example I wrapped a store with a class to manage the number of riders. """ Simple demo of a pool of riders delivering packages where the number of riders can change over time Idel riders are keep in a store that is wrapped in a class to manage the number of riders Programmer Michael R. Gibbs """ import simpy import random class Rider(): """ quick class to track the riders that deliver packages """ # tracks the next id to be assigned to a rider next_id = 1 def __init__(self): self.id = Rider.next_id Rider.next_id += 1 class Pack(): """ quick class to track the packages """ # tracks the next id to be assigned to a pack next_id = 1 def __init__(self): self.id = Pack.next_id Pack.next_id += 1 class RiderPool(): """ Pool of riders where the number of riders can be changed """ def __init__(self, env, start_riders=10): self.env = env # tracks the number of riders we need self.target_cnt = start_riders # tracks the number of riders we have self.curr_cnt = start_riders # the store idle riders self.riders = simpy.Store(env) # stores do not start with objects like resource pools do. # need to add riders yourself as part of set up self.riders.items = [Rider() for _ in range(start_riders)] def add_rider(self): """ Add a rider to the pool """ self.target_cnt += 1 if self.curr_cnt < self.target_cnt: # need to add a rider to the pool to get to the target rider = Rider() self.riders.put(rider) self.curr_cnt += 1 print(f'{env.now:0.2f} rider {rider.id} added') else: # already have enough riders, # must have tried to reduce the rider pool while all riders were busy # In effect we are cancelling a previous remove rider call print(f'{env.now:0.2f} keeping rider scheduled to be removed instead of adding') def remove_rider(self): """ Remove a rider from the pool If all the riders are busy, the actual removal of a rider will happen when a that rider finishes it current task and is tried to be put/returned back into the pool """ self.target_cnt -= 1 if self.curr_cnt > self.target_cnt: if len(self.riders.items) > 0: # we have a idle rider that we can remove now rider = yield self.riders.get() self.curr_cnt -= 1 print(f'{env.now:0.2f} rider {rider.id} removed from store') else: # wait for a rider to be put back to the pool pass def get(self): """ Get a rider from the pool returns a get request that can be yield to, not a rider """ rider_req = self.riders.get() return rider_req def put(self, rider): """ put a rider pack into the pool """ if self.curr_cnt <= self.target_cnt: # still need the rider self.riders.put(rider) else: # have tool many riders, do not add back to pool self.curr_cnt -= 1 print(f'{env.now:0.2f} rider {rider.id} removed on return to pool') def gen_packs(env, riders): """ generates the arrival of packages to be delivered by riders """ while True: yield env.timeout(random.randint(1,4)) pack = Pack() env.process(ship_pack(env, pack, riders)) def ship_pack(env, pack, riders): """ The process of a rider delivering a packages """ print(f'{env.now:0.2f} pack {pack.id} getting rider') rider = yield riders.get() print(f'{env.now:0.2f} pack {pack.id} has rider {rider.id}') # trip time yield env.timeout(random.randint(5,22)) riders.put(rider) print(f'{env.now:0.2f} pack {pack.id} delivered') def rider_sched(env, riders): """ Changes the number of riders in rider pool over time """ yield env.timeout(30) # time to remove a few riders print(f'{env.now:0.2f} -- reducing riders') print(f'{env.now:0.2f} -- request queue len {len(riders.riders.get_queue)}') print(f'{env.now:0.2f} -- rider store len {len(riders.riders.items)}') for _ in range(5): env.process(riders.remove_rider()) yield env.timeout(60) # time to add back some riders print(f'{env.now:0.2f} -- adding riders ') for _ in range(2): riders.add_rider() # run the model env = simpy.Environment() riders = RiderPool(env, 10) env.process(gen_packs(env, riders)) env.process(rider_sched(env, riders)) env.run(100) print(f'{env.now:0.2f} -- end rider count {riders.target_cnt}')