Simpy 容器问题

Simpy Container Questions

完全披露:我是一名可能搞砸了一些约定、符号和最佳实践的学生。我热烈欢迎反馈。

我正在尝试实施 SimPy 文档中的加油站示例版本,附于此处:

Covers:

- Resources: Resource
- Resources: Container
- Waiting for other processes

Scenario:
  A gas station has a limited number of gas pumps that share a common
  fuel reservoir. Cars randomly arrive at the gas station, request one
  of the fuel pumps and start refueling from that reservoir.

  A gas station control process observes the gas station's fuel level
  and calls a tank truck for refueling if the station's level drops
  below a threshold.


import itertools
import random

import simpy


RANDOM_SEED = 42
GAS_STATION_SIZE = 200     # liters
THRESHOLD = 10             # Threshold for calling the tank truck (in %)
FUEL_TANK_SIZE = 50        # liters
FUEL_TANK_LEVEL = [5, 25]  # Min/max levels of fuel tanks (in liters)
REFUELING_SPEED = 2        # liters / second
TANK_TRUCK_TIME = 300      # Seconds it takes the tank truck to arrive
T_INTER = [30, 300]        # Create a car every [min, max] seconds
SIM_TIME = 1000            # Simulation time in seconds


def car(name, env, gas_station, fuel_pump):
    """A car arrives at the gas station for refueling.

    It requests one of the gas station's fuel pumps and tries to get the
    desired amount of gas from it. If the stations reservoir is
    depleted, the car has to wait for the tank truck to arrive.

    """
    fuel_tank_level = random.randint(*FUEL_TANK_LEVEL)
    print('%s arriving at gas station at %.1f' % (name, env.now))
    with gas_station.request() as req:
        start = env.now
        # Request one of the gas pumps
        yield req

        # Get the required amount of fuel
        liters_required = FUEL_TANK_SIZE - fuel_tank_level
        yield fuel_pump.get(liters_required)

        # The "actual" refueling process takes some time
        yield env.timeout(liters_required / REFUELING_SPEED)

        print('%s finished refueling in %.1f seconds.' % (name,
                                                          env.now - start))


def gas_station_control(env, fuel_pump):
    """Periodically check the level of the *fuel_pump* and call the tank
    truck if the level falls below a threshold."""
    while True:
        if fuel_pump.level / fuel_pump.capacity * 100 < THRESHOLD:
            # We need to call the tank truck now!
            print('Calling tank truck at %d' % env.now)
            # Wait for the tank truck to arrive and refuel the station
            yield env.process(tank_truck(env, fuel_pump))

        yield env.timeout(10)  # Check every 10 seconds


def tank_truck(env, fuel_pump):
    """Arrives at the gas station after a certain delay and refuels it."""
    yield env.timeout(TANK_TRUCK_TIME)
    print('Tank truck arriving at time %d' % env.now)
    amount = fuel_pump.capacity - fuel_pump.level
    print('Tank truck refuelling %.1f liters.' % amount)
    yield fuel_pump.put(amount)


def car_generator(env, gas_station, fuel_pump):
    """Generate new cars that arrive at the gas station."""
    for i in itertools.count():
        yield env.timeout(random.randint(*T_INTER))
        env.process(car('Car %d' % i, env, gas_station, fuel_pump))


# Setup and start the simulation
print('Gas Station refuelling')
random.seed(RANDOM_SEED)

# Create environment and start processes
env = simpy.Environment()
gas_station = simpy.Resource(env, 2)
fuel_pump = simpy.Container(env, GAS_STATION_SIZE, init=GAS_STATION_SIZE)
env.process(gas_station_control(env, fuel_pump))
env.process(car_generator(env, gas_station, fuel_pump))

# Execute!
env.run(until=SIM_TIME)

我最大的挫败感是试图实施某种方式将容器交给油罐车,这样在加油站补充其汽油库存(通过油罐车)时,没有汽车可以加油).我试图在汽车定义中放置 if 语句来检查加油站燃料库存的状态或在 gas_station_control 条件中的循环被触发时产生资源,但没有成功。

我的场景是: 在设定的时间范围内随机选择 3 辆汽车。加油站的容量是1.5罐汽油,一辆汽车抽一车油需要3个小时。一旦那辆车离开,我需要为我的加油站储油罐加满油,这需要 4 个小时(如果油位=.5 @ 0.25 loads/hour 的速率,则需要 6 个小时才能加满所有 1.5 个油箱)。我还需要确保,如果当前没有汽车在排队等候,我应该重新给蓄水池加水,不管我是否超出了汽车可能停靠的当前时间范围。我需要确保记录每辆车在队列中等待的时间。

我仍然不确定你想做什么。为什么在卡车补充集装箱时汽车不能有待处理的请求?这些请求不会阻止卡车添加到容器中。

无论如何,我尝试了一下,这就是我的想法

在此版本中,当汽车到达加油站时,它会检查容器中是否有足够的汽油为汽车加油。如果是这样,它将发出容器请求。如果没有,它将等待卡车到达并在加油站补充,然后提出容器请求。汽车知道补货何时完成,因为我在 gas_station 中添加了一个 replenish_event ,当卡车完成补货时,卡车会触发它。如果汽车需要等待,它可以屈服于此事件。请注意,超过一辆车可以屈服于此事件。

"""
Covers:

- Resources: Resource
- Resources: Container
- Waiting for other processes

Scenario:
  A gas station has a limited number of gas pumps that share a common
  fuel reservoir. Cars randomly arrive at the gas station, request one
  of the fuel pumps and start refueling from that reservoir.

  A gas station control process observes the gas station's fuel level
  and calls a tank truck for refueling if the station's level drops
  below a threshold.

Updated my Michel R. Gibbs
Car does not make a request for gas amount unless it can get full amount.
If cannot get full amount, will wait for truck to replenish before making request
"""

import itertools
import random

import simpy


RANDOM_SEED = 42
GAS_STATION_SIZE = 200     # liters
THRESHOLD = 10             # Threshold for calling the tank truck (in %)
FUEL_TANK_SIZE = 50        # liters
FUEL_TANK_LEVEL = [5, 25]  # Min/max levels of fuel tanks (in liters)
REFUELING_SPEED = 2        # liters / second
TANK_TRUCK_TIME = 300      # Seconds it takes the tank truck to arrive
T_INTER = [30, 300]        # Create a car every [min, max] seconds
SIM_TIME = 2000            # Simulation time in seconds
REPLENISHMENT_SPEED = 20   # linters / second for tanker truck to refill gas staiion


def car(name, env, gas_station, fuel_pump, replenish_event):
    """A car arrives at the gas station for refueling.

    It requests one of the gas station's fuel pumps and tries to get the
    desired amount of gas from it. If the stations reservoir is
    depleted, the car has to wait for the tank truck to arrive.

    """
    fuel_tank_level = random.randint(*FUEL_TANK_LEVEL)
    print('%s arriving at gas station at %.1f' % (name, env.now))
    with gas_station.request() as req:
        start = env.now
        # Request one of the gas pumps
        yield req
        print('%s exit queue and started pumping gas at %.1f' % (name, env.now))
        # Get the required amount of fuel
        liters_required = FUEL_TANK_SIZE - fuel_tank_level
        
        # check if amount is available
        while liters_required > fuel_pump.level:
            # use a while in case another car uses up the replenishment

            # wait for truck
            print('%s waiting for fuel truck before starting to pump %.1f' % (name, env.now))
            yield replenish_event

        yield fuel_pump.get(liters_required)

        # The "actual" refueling process takes some time
        yield env.timeout(liters_required / REFUELING_SPEED)

        print('%s finished refueling in %.1f seconds.' % (name,
                                                          env.now - start))


def gas_station_control(env, gas_station, fuel_pump):
    """
    Periodically check the level of the *fuel_pump* and call the tank
    truck if the level falls below a threshold.
    """
    
    gas_station.replenish_event = env.event()
    while True:
        if fuel_pump.level / fuel_pump.capacity * 100 < THRESHOLD:
            # We need to call the tank truck now!
            print('Calling tank truck at %d' % env.now)
            env.process(tank_truck(env, fuel_pump, gas_station.replenish_event))

            # yield until replenishment is finished
            yield gas_station.replenish_event

            # reset event for next replenishment
            gas_station.replenish_event = env.event()

        yield env.timeout(10)  # Check every 10 seconds


def tank_truck(env, fuel_pump, replenish_event):
    """
    Arrives at the gas station after a certain delay and refuels it.
    """
    yield env.timeout(TANK_TRUCK_TIME)
    print('Tank truck arriving at time %d' % env.now)
    
    amount = fuel_pump.capacity - fuel_pump.level
    replem_time = amount / REPLENISHMENT_SPEED
    yield env.timeout(replem_time)

    print('Tank truck replenshied %.1f liters at time %.1f.' % (amount, env.now))
    yield fuel_pump.put(amount)

    # let any listeners know replenishment is done
    replenish_event.succeed()


def car_generator(env, gas_station, fuel_pump):
    """
    Generate new cars that arrive at the gas station.
    """
    for i in itertools.count():
        yield env.timeout(random.randint(*T_INTER))
        env.process(car('Car %d' % i, env, gas_station, fuel_pump, gas_station.replenish_event))


# Setup and start the simulation
print('Gas Station refuelling')
random.seed(RANDOM_SEED)

# Create environment and start processes
env = simpy.Environment()
gas_station = simpy.Resource(env, 2)
fuel_pump = simpy.Container(env, GAS_STATION_SIZE, init=GAS_STATION_SIZE)
env.process(gas_station_control(env, gas_station, fuel_pump))
env.process(car_generator(env, gas_station, fuel_pump))

# Execute!
env.run(until=SIM_TIME)