Beispiel #1
0
    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)
Beispiel #2
0
    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)
Beispiel #4
0
 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)
Beispiel #5
0
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()
Beispiel #6
0
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()
Beispiel #7
0
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)"
Beispiel #8
0
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)
Beispiel #10
0
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
Beispiel #11
0
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()
Beispiel #12
0
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()
Beispiel #13
0
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))
Beispiel #15
0
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()
Beispiel #17
0
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')