I am relatively new to Python and very new to Simpy. I am trying to build a model of a hospital system that:
- Has roughly 20 resources (units) where each resource has a capacity of 5 to 50 (beds)
- Not all units can serve the same patients. They have specialties.
- When a patient needs a bed, the hospital requests 1 bed from roughly 5 of the 20 units.
So, what I want to do is make a request against multiple Unit resources and only capture 1 bed from 1 available Unit. After many iterations, I think I have found a way of doing this but my approach feels overly complicated.
Below I am showing code using the conditional AnyOf of Simpy. The way AnyOf works is if more than 1 resource has the availability, then more than 1 resource will be captured. So, after the AnyOf request, I release any extra captured beds and cancel any requests still pending.
Is there an easier approach?
from dataclasses import dataclass
import simpy
from simpy.events import AnyOf, Event
import random
@dataclass
class Unit():
env: simpy.Environment()
identifier: str
capacity: int = 1
def __post_init__(self):
self.beds: simpy.Resource = simpy.Resource(env, self.capacity)
def make_request(env, units: list[Unit]):
# create a list of simpy request events for unit 1, 3 and 5
# purpose is to put in a conditional request
any_of_request: list[Event] = []
request_to_unit_dictionary = {}
random_pool_size = random.randint(1, 5)
for x in range(random_pool_size):
random_unit = random.randint(0, 9)
unit = units[random_unit]
res_request = unit.beds.request()
request_to_unit_dictionary[res_request] = unit
any_of_request.append(res_request)
get_one_bed_request = AnyOf(env, any_of_request)
captured_units = yield get_one_bed_request
# how do i determine what unit was captured by the request?
# it is possible that both resources are avaliable
# and both request get filled
captured_requests = list(captured_units.keys())
captured_request = captured_requests[0]
captured_unit: Unit = request_to_unit_dictionary[captured_request]
print(captured_unit)
# if I understand correctly, if I only want 1 request then
# release any "extra" captures
for r in captured_requests:
if r != captured_request:
r.resource.release(r)
# cancel any of the request not captured.
for r in any_of_request:
if r not in captured_requests:
r.cancel()
env = simpy.Environment()
# create 10 units, each with 1 capacity for this example
units: list[Unit] = []
for x in range(1, 10):
units.append(Unit(identifier=f'unit{x}', env=env, capacity=1))
env.process(make_request(env, units))
env.process(make_request(env, units))
env.process(make_request(env, units))
env.process(make_request(env, units))
env.run()
Thanks, Dan