def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) config = self.env.config self.add_connections('tanker_company') self.arrival_interval = config.get('gas_station.arrival_interval', 60) station_capacity = config.get('gas_station.capacity', 200) self.reservoir = Pool(self.env, capacity=station_capacity, init=station_capacity) self.auto_probe('reservoir', log={}) threshold_pct = config.get('gas_station.threshold_pct', 10) self.reservoir_low_water = threshold_pct * station_capacity / 100 self.pump_rate = config.get('gas_station.pump_rate', 2) num_pumps = config.get('gas_station.pumps', 2) self.fuel_pumps = Resource(self.env, capacity=num_pumps) self.auto_probe('fuel_pumps', log={}) self.car_capacity = config.get('car.capacity', 50) self.car_level_range = config.get('car.level', [5, 25]) # A gas station has two persistent processes. One to monitor the # reservoir level and one that models the arrival of cars at the # station. Desmod starts these processes before simulation phase. self.add_processes(self._monitor_reservoir, self._traffic_generator)
def __init__(self, *args, **kwargs): super().__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 = Pool(self.env, tank_capacity) # This auto_probe() call uses the self.tank Pool get/put hooks so 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 __init__(self, *args, **kwargs): super(GasStation, self).__init__(*args, **kwargs) config = self.env.config self.add_connections('tanker_company') self.arrival_interval = config.get('gas_station.arrival_interval', 60) station_capacity = config.get('gas_station.capacity', 200) self.reservoir = Pool( self.env, capacity=station_capacity, init=station_capacity ) self.auto_probe('reservoir', log={}) threshold_pct = config.get('gas_station.threshold_pct', 10) self.reservoir_low_water = threshold_pct * station_capacity / 100 self.pump_rate = config.get('gas_station.pump_rate', 2) num_pumps = config.get('gas_station.pumps', 2) self.fuel_pumps = Resource(self.env, capacity=num_pumps) self.auto_probe('fuel_pumps', log={}) self.car_capacity = config.get('car.capacity', 50) self.car_level_range = config.get('car.level', [5, 25]) # A gas station has two persistent processes. One to monitor the # reservoir level and one that models the arrival of cars at the # station. Desmod starts these processes before simulation phase. self.add_processes(self._monitor_reservoir, self._traffic_generator)
def __init__(self, *args, **kwargs): super(TopTest, self).__init__(*args, **kwargs) self.container = simpy.Container(self.env) self.resource = simpy.Resource(self.env) self.queue = Queue(self.env) self.pool = Pool(self.env) self.a = CompA(self) self.b = CompB(self) hints = {} if self.env.config['sim.log.enable']: hints['log'] = {'level': 'INFO'} if self.env.config['sim.vcd.enable']: hints['vcd'] = {} if self.env.config['sim.db.enable']: hints['db'] = {} self.auto_probe('container', **hints) self.auto_probe('resource', **hints) self.auto_probe('queue', **hints) self.auto_probe('pool', **hints) self.trace_some = self.get_trace_function('something', vcd={'var_type': 'real'}, log={'level': 'INFO'}) self.trace_other = self.get_trace_function('otherthing', vcd={ 'var_type': 'integer', 'init': ('z', 'z'), 'size': (8, 8) }) self.add_process(self.loop)
def test_pool_get_zero(env): pool = Pool(env, capacity=5, hard_cap=True) def consumer(env): yield pool.get(0) env.process(consumer(env)) with raises(ValueError): env.run()
def test_pool_put_zero(env): pool = Pool(env, capacity=5, hard_cap=True) def producer(env): yield pool.put(0) env.process(producer(env)) with raises(ValueError): env.run()
def test_pool_check_str(env): pool = Pool(env, name='bar', capacity=5) def producer(env, amount): yield env.timeout(1) yield pool.put(amount) env.process(producer(env, 1)) env.run() assert str(pool) == "Pool: name=bar level=1 capacity=5)"
def test_pool_overflow(env): pool = Pool(env, capacity=5, hard_cap=True) def producer(env): yield env.timeout(1) for i in range(1, 5): yield pool.put(i) yield env.timeout(1) env.process(producer(env)) with raises(OverflowError): env.run()
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 = Pool(self.env, tank_capacity) # This auto_probe() call uses the self.tank Pool get/put hooks so 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 test_pool_when_full_any(env): pool = Pool(env, capacity=9) result = [] def producer(env): yield env.timeout(1) for i in range(1, 6): yield pool.put(i) yield env.timeout(1) def consumer(env): yield env.timeout(5) for i in range(1, 3): msg = yield pool.get(i) assert msg == i def full_waiter(env): yield pool.when_full() assert env.now == 4 assert pool.level == 10 result.append('full') def any_waiter(env): yield pool.when_any() assert env.now == 1 result.append('any') def new_waiter(env): yield pool.when_new() assert env.now == 1 result.append('new') env.process(producer(env)) env.process(consumer(env)) env.process(full_waiter(env)) env.process(any_waiter(env)) env.process(any_waiter(env)) env.process(new_waiter(env)) env.run() assert pool.level assert pool.is_full assert pool.remaining == pool.capacity - pool.level assert not pool.is_empty assert 'full' in result assert 'new' in result assert result.count('any') == 2
def test_pool(env): pool = Pool(env, capacity=2) def producer(amount, wait): yield env.timeout(wait) yield pool.put(amount) def consumer(expected_amount, wait): yield env.timeout(wait) msg = yield pool.get(expected_amount) assert msg == expected_amount env.process(producer(1, 0)) env.process(producer(2, 1)) env.process(consumer(1, 0)) env.process(consumer(2, 1)) env.process(consumer(2, 2)) env.process(producer(1, 2)) env.process(producer(1, 3)) env.run()
def test_pool_get_more(env): pool = Pool(env, capacity=6, name='foo') def producer(env): yield pool.put(1) yield env.timeout(1) yield pool.put(1) def consumer(env, amount1, amount2): amount = yield pool.get(amount1) assert amount == amount1 amount = yield pool.get(amount2) # should fail yield amount env.process(producer(env)) env.process(consumer(env, 1, 10)) with raises(AssertionError, match="Amount {} greater than pool's {} capacity {}".format( 10, 'foo', 6)): env.run()
def test_pool_cancel(env): pool = Pool(env) event_cancel = pool.get(2) event_cancel.cancel() event_full = pool.when_full() event_full.cancel() event_any = pool.when_any() event_any.cancel() event_new = pool.when_new() event_new.cancel() env.run() assert pool.level == 0 assert not event_cancel.triggered assert not event_full.triggered assert not event_any.triggered assert not event_new.triggered
class GasStation(Component): """A gas station has a fuel reservoir shared among several fuel pumps. The gas station has a traffic generator process that causes cars to arrive to fill up their tanks. As the cars fill up, the reservoir's level goes down. When the level goes below a critical threshold, the gas station makes a request to the tanker company for a tanker truck to refill the reservoir. """ base_name = 'station' def __init__(self, *args, **kwargs): super(GasStation, self).__init__(*args, **kwargs) config = self.env.config self.add_connections('tanker_company') self.arrival_interval = config.get('gas_station.arrival_interval', 60) station_capacity = config.get('gas_station.capacity', 200) self.reservoir = Pool( self.env, capacity=station_capacity, init=station_capacity ) self.auto_probe('reservoir', log={}) threshold_pct = config.get('gas_station.threshold_pct', 10) self.reservoir_low_water = threshold_pct * station_capacity / 100 self.pump_rate = config.get('gas_station.pump_rate', 2) num_pumps = config.get('gas_station.pumps', 2) self.fuel_pumps = Resource(self.env, capacity=num_pumps) self.auto_probe('fuel_pumps', log={}) self.car_capacity = config.get('car.capacity', 50) self.car_level_range = config.get('car.level', [5, 25]) # A gas station has two persistent processes. One to monitor the # reservoir level and one that models the arrival of cars at the # station. Desmod starts these processes before simulation phase. self.add_processes(self._monitor_reservoir, self._traffic_generator) @property def reservoir_pct(self): return self.reservoir.level / self.reservoir.capacity * 100 def _monitor_reservoir(self): """Periodically monitor reservoir level. The a request is made to the tanker company when the reservoir falls below a critical threshold. """ while True: yield self.reservoir.when_at_most(self.reservoir_low_water) done_event = self.env.event() yield self.tanker_company.request_truck(self, done_event) yield done_event def _traffic_generator(self): """Model the sporadic arrival of cars to the gas station.""" for i in count(): interval = self.env.rand.expovariate(1 / self.arrival_interval) yield self.env.timeout(interval) self.env.process(self._car(i)) def _car(self, i): """Model a car transacting fuel.""" with self.fuel_pumps.request() as pump_req: self.info('car{} awaiting pump'.format(i)) yield pump_req self.info('car{} at pump'.format(i)) car_level = self.env.rand.randint(*self.car_level_range) amount = self.car_capacity - car_level t0 = self.env.now for _ in range(amount): yield self.reservoir.get(1) yield self.env.timeout(1 / self.pump_rate) pump_time = self.env.now - t0 self.info('car{} pumped {}L in {:.0f}s'.format( i, amount, pump_time))
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().__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 = Pool(self.env, tank_capacity) # This auto_probe() call uses the self.tank Pool get/put hooks so 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( f'refilled {self.tank.capacity}L in {pump_time:.0f}s') gas_station, done_event = yield self._instructions.get() self.info(f'traveling to {gas_station.name}') travel_time = self.env.rand.expovariate(1 / self.avg_travel) yield self.env.timeout(travel_time) self.info(f'arrived at {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()
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 = Pool(self.env, tank_capacity) # This auto_probe() call uses the self.tank Pool get/put hooks so 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()
class GasStation(Component): """A gas station has a fuel reservoir shared among several fuel pumps. The gas station has a traffic generator process that causes cars to arrive to fill up their tanks. As the cars fill up, the reservoir's level goes down. When the level goes below a critical threshold, the gas station makes a request to the tanker company for a tanker truck to refill the reservoir. """ base_name = 'station' def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) config = self.env.config self.add_connections('tanker_company') self.arrival_interval = config.get('gas_station.arrival_interval', 60) station_capacity = config.get('gas_station.capacity', 200) self.reservoir = Pool(self.env, capacity=station_capacity, init=station_capacity) self.auto_probe('reservoir', log={}) threshold_pct = config.get('gas_station.threshold_pct', 10) self.reservoir_low_water = threshold_pct * station_capacity / 100 self.pump_rate = config.get('gas_station.pump_rate', 2) num_pumps = config.get('gas_station.pumps', 2) self.fuel_pumps = Resource(self.env, capacity=num_pumps) self.auto_probe('fuel_pumps', log={}) self.car_capacity = config.get('car.capacity', 50) self.car_level_range = config.get('car.level', [5, 25]) # A gas station has two persistent processes. One to monitor the # reservoir level and one that models the arrival of cars at the # station. Desmod starts these processes before simulation phase. self.add_processes(self._monitor_reservoir, self._traffic_generator) @property def reservoir_pct(self): return self.reservoir.level / self.reservoir.capacity * 100 def _monitor_reservoir(self): """Periodically monitor reservoir level. The a request is made to the tanker company when the reservoir falls below a critical threshold. """ while True: yield self.reservoir.when_at_most(self.reservoir_low_water) done_event = self.env.event() yield self.tanker_company.request_truck(self, done_event) yield done_event def _traffic_generator(self): """Model the sporadic arrival of cars to the gas station.""" for i in count(): interval = self.env.rand.expovariate(1 / self.arrival_interval) yield self.env.timeout(interval) self.env.process(self._car(i)) def _car(self, i): """Model a car transacting fuel.""" with self.fuel_pumps.request() as pump_req: self.info(f'car{i} awaiting pump') yield pump_req self.info(f'car{i} at pump') car_level = self.env.rand.randint(*self.car_level_range) amount = self.car_capacity - car_level t0 = self.env.now for _ in range(amount): yield self.reservoir.get(1) yield self.env.timeout(1 / self.pump_rate) pump_time = self.env.now - t0 self.info(f'car{i} pumped {amount}L in {pump_time:.0f}s')