Resource

Resources are a powerful way of process interaction.

A resource has always a capacity (which can be zero and even negative). This capacity will be specified at time of creation, but may change over time. There are two of types resources:

  • standard resources, where each claim is associated with a component (the claimer). It is not necessary that the claimed quantities are integer.
  • anonymous resources, where only the claimed quantity is registered. This is most useful for dealing with levels, lengths, etc.

Resources are defined like

clerks = Resource('clerks', capacity=3)

And then a component can request a clerk

yield self.request(clerks)  # request 1 from clerks

It is also possible to request for more resources at once

yield self.request(clerks,(assistance,2))  # request 1 from clerks AND 2 from assistance

Resources have a queue requesters containing all components trying to claim from the resource. And a queue claimers containing all components claiming from the resource (not for anonymous resources).

It is possible to release a quantity from a resource with c.release(), e.g.

self.release(r)  # releases all claimed quantity from r
self.release((r,2))  # release quantity 2 from r

Alternatively, it is possible to release from a resource directly, e.g.

r.release()  # releases the total quantity from all claiming components
r.release(10)  # releases 10 from the resource; only valid for anonymous resources

After a release, all requesting components will be checked whether their claim can be honored.

Resources have a number monitors:

  • claimers().length
  • claimers().length_of_stay
  • requesters().length
  • requesters().length_of_stay
  • claimed_quantity
  • available_quantity
  • capacity
  • occupancy (=claimed_quantity / capacity)

By default, all monitors are enabled.

With r.print_statistics() the key statistics of these all monitors are printed.

E.g.:

Statistics of clerk at     50000.000
                                                                     all    excl.zero         zero
-------------------------------------------- -------------- ------------ ------------ ------------
Length of requesters of clerk                duration          50000        48499.381     1500.619
                                             mean                  8.427        8.687
                                             std.deviation         4.852        4.691

                                             minimum               0            1
                                             median                9           10
                                             90% percentile       14           14
                                             95% percentile       16           16
                                             maximum              21           21

Length of stay in requesters of clerk        entries            4995         4933           62
                                             mean                 84.345       85.405
                                             std.deviation        48.309       47.672

                                             minimum               0            0.006
                                             median               94.843       95.411
                                             90% percentile      142.751      142.975
                                             95% percentile      157.467      157.611
                                             maximum             202.153      202.153

Length of claimers of clerk                  duration          50000        50000            0
                                             mean                  2.996        2.996
                                             std.deviation         0.068        0.068

                                             minimum               1            1
                                             median                3            3
                                             90% percentile        3            3
                                             95% percentile        3            3
                                             maximum               3            3

Length of stay in claimers of clerk          entries            4992         4992            0
                                             mean                 30           30
                                             std.deviation         0.000        0.000

                                             minimum              30.000       30.000
                                             median               30           30
                                             90% percentile       30           30
                                             95% percentile       30           30
                                             maximum              30.000       30.000

Capacity of clerk                            duration          50000        50000            0
                                             mean                  3            3
                                             std.deviation         0            0

                                             minimum               3            3
                                             median                3            3
                                             90% percentile        3            3
                                             95% percentile        3            3
                                             maximum               3            3

Available quantity of clerk                  duration          50000          187.145    49812.855
                                             mean                  0.004        1.078
                                             std.deviation         0.068        0.268

                                             minimum               0            1
                                             median                0            1
                                             90% percentile        0            1
                                             95% percentile        0            2
                                             maximum               2            2

Claimed quantity of clerk                    duration          50000        50000            0
                                             mean                  2.996        2.996
                                             std.deviation         0.068        0.068

                                             minimum               1            1
                                             median                3            3
                                             90% percentile        3            3
                                             95% percentile        3            3
                                             maximum               3            3

Occupancy of clerks                          duration          50000        50000            0
                                             mean                  0.999        0.999
                                             std.deviation         0.023        0.023

                                             minimum               0.333        0.333
                                             median                1            1
                                             90% percentile        1            1
                                             95% percentile        1            1
                                             maximum               1            1

With r.print_info() a summary of the contents of the queues can be printed.

E.g.

Resource 0x112e8f0b8
  name=clerk
  capacity=3
  requesting component(s):
    customer.4995        quantity=1
    customer.4996        quantity=1
  claimed_quantity=3
  claimed by:
    customer.4992        quantity=1
    customer.4993        quantity=1
    customer.4994        quantity=1

The capacity may be changed with r.set_capacity(x). Note that this may lead to requesting components to be honored.

Querying of the capacity, claimed quantity, available quantity and occupancy can be done via the label monitors: r.capacity(), r.claimed_quantity(), r.available_quantity() and r.occupancy()

If the capacity of a resource is constant, which is very common, the mean occupancy can be found with

r.occupancy.mean()

When the capacity changes over time, it is recommended to use

occupancy = r.claimed_quantity.mean() / r.capacity.mean()

to obtain the mean occupancy.

Note that the occupancy is set to 0 if the capacity of the resource is <= 0.

Additional methods for anonymous resources

For anonymous resources, it may be not allowed to exceed the capacity and have a component wait for enough (claimed) capacity to be available. That may be accomplished by using a negative quantity in the self.request call.

Alternatively, it possible to use the Component.put method, where quantities of anonymous resources are negated. For symmetry reasons, salabim also offers the Component.get() method, which is behaves exactly like Component.request.

The model below illustrates the use of get and put.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#  Gas station.py
import salabim as sim

#  based on SimPy example model

GAS_STATION_SIZE = 200.0  # liters
THRESHOLD = 25.0  # Threshold for calling the tank truck (in %)
FUEL_TANK_SIZE = 50.0  # liters
# Min/max levels of fuel tanks (in liters)
FUEL_TANK_LEVEL = sim.Uniform(5, 25)
REFUELING_SPEED = 2.0  # liters / second
TANK_TRUCK_TIME = 300.0  # Seconds it takes the tank truck to arrive
T_INTER = sim.Uniform(10, 100)  # Create a car every [min, max] seconds
SIM_TIME = 200000  # Simulation time in seconds


class Car(sim.Component):
    """
    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.

    """

    def process(self):
        fuel_tank_level = int(FUEL_TANK_LEVEL.sample())
        yield self.request(gas_station)
        liters_required = FUEL_TANK_SIZE - fuel_tank_level
        if (fuel_pump.available_quantity() - liters_required) / fuel_pump.capacity() * 100 < THRESHOLD:
            TankTruck()
        yield self.get((fuel_pump, liters_required))
        yield self.hold(liters_required / REFUELING_SPEED)


class TankTruck(sim.Component):
    def process(self):
        yield self.hold(TANK_TRUCK_TIME)
        amount = fuel_pump.claimed_quantity()
        yield self.put((fuel_pump, amount))


class CarGenerator(sim.Component):
    """
    Generate new cars that arrive at the gas station.
    """

    def process(self):
        while True:
            yield self.hold(T_INTER.sample())
            Car()


# Setup and start the simulation
env = sim.Environment(trace=False)
print("Gas Station refuelling")

# Create environment and start processes
gas_station = sim.Resource("gas_station", 2)
fuel_pump = sim.Resource("fuel_pump", capacity=GAS_STATION_SIZE, anonymous=True)
tank_truck = TankTruck()
CarGenerator()

env.run(SIM_TIME)

fuel_pump.capacity.print_histogram()
fuel_pump.claimed_quantity.print_histogram()
fuel_pump.available_quantity.print_histogram()


gas_station.requesters().length.print_histogram()
gas_station.requesters().length_of_stay.print_histogram(30, 0, 10)