class CheckoutLane(Component): base_name = 'lane' def __init__(self, *args, **kwargs): super(CheckoutLane, self).__init__(*args, **kwargs) self.queue = Queue(self.env) self.auto_probe('queue', vcd={}) self.add_process(self.checkout) def __lt__(self, other): return self.queue.size < other.queue.size def enqueue(self, num_items, done_event): return self.queue.put((num_items, done_event)) def checkout(self): scan_dist = partial(self.env.rand.expovariate, 1 / self.env.config['grocery.scan_time']) while True: num_items, done_event = yield self.queue.get() for n in range(num_items): yield self.env.timeout(scan_dist()) done_event.succeed()
class TankerTruck(Component): """Tanker trucks carry fuel to gas stations. Each tanker truck has a queue of gas stations it must visit. When the truck's tank becomes empty, it must go refill itself. """ base_name = 'truck' def __init__(self, *args, **kwargs): super(TankerTruck, self).__init__(*args, **kwargs) self.pump_rate = self.env.config.get('tanker.pump_rate', 10) self.avg_travel = self.env.config.get('tanker.travel_time', 600) tank_capacity = self.env.config.get('tanker.capacity', 200) self.tank = Container(self.env, tank_capacity) # This auto_probe() call causes the self.tank Container to be # monkey-patched such that whenever it's level changes, the new level # is noted in the log. self.auto_probe('tank', log={}) # The parent TankerCompany enqueues instructions to this queue. self._instructions = Queue(self.env) # Declare a persistant process to be started at simulation-time. self.add_process(self._dispatch_loop) def dispatch(self, gas_station, done_event): """Append dispatch instructions to the truck's queue.""" return self._instructions.put((gas_station, done_event)) def _dispatch_loop(self): """This is the tanker truck's main behavior. Travel, pump, refill...""" while True: if not self.tank.level: self.info('going for refill') # Desmod simulation environments come equipped with a # random.Random() instance seeded based on the 'sim.seed' # configuration key. travel_time = self.env.rand.expovariate(1 / self.avg_travel) yield self.env.timeout(travel_time) self.info('refilling') pump_time = self.tank.capacity / self.pump_rate yield self.env.timeout(pump_time) yield self.tank.put(self.tank.capacity) self.info('refilled {}L in {:.0f}s'.format( self.tank.capacity, pump_time)) gas_station, done_event = yield self._instructions.get() self.info('traveling to {}'.format(gas_station.name)) travel_time = self.env.rand.expovariate(1 / self.avg_travel) yield self.env.timeout(travel_time) self.info('arrived at {}'.format(gas_station.name)) while self.tank.level and (gas_station.reservoir.level < gas_station.reservoir.capacity): yield self.env.timeout(1 / self.pump_rate) yield gas_station.reservoir.put(1) yield self.tank.get(1) self.info('done pumping') done_event.succeed()