WhileActivity + ShiftAmountActivity#

The combination of a model.WhileActivity with a model.ShiftAmountActivity can be used to represent the loading or unloading of a vessel, where coordination of the process is represented on the granularity of the amount shifted in one iteration. In this particular example we define the time it takes to shift an amount of 1, and define a WhileActivity that executes this activity until the vessel container is full.

0. Import libraries#

import datetime, time
import simpy

import shapely.geometry
import pandas as pd

import openclsim.core as core
import openclsim.model as model
import openclsim.plot as plot

1. Initialise simpy environment#

# setup environment
simulation_start = 0
my_env = simpy.Environment(initial_time=simulation_start)

2. Define object classes#

# create a Site object based on desired mixin classes
Site = type(
    "Site",
    (
        core.Identifiable,
        core.Log,
        core.Locatable,
        core.HasContainer,
        core.HasResource,
    ),
    {},
)

# create a TransportProcessingResource object based on desired mixin classes
TransportProcessingResource = type(
    "TransportProcessingResource",
    (
        core.ContainerDependentMovable,
        core.Processor,
        core.HasResource,
        core.LoadingFunction,
        core.UnloadingFunction,
        core.Identifiable,
        core.Log,
    ),
    {},
)

3. Create objects#

3.1. Create site object(s)#

# prepare input data for from_site
location_from_site = shapely.geometry.Point(4.18055556, 52.18664444)
data_from_site = {"env": my_env,
                  "name": "from_site",
                  "geometry": location_from_site,
                  "capacity": 10,
                  "level": 10
                 }
# instantiate from_site 
from_site = Site(**data_from_site)

# prepare input data for to_site
location_to_site = shapely.geometry.Point(4.25222222, 52.11428333)
data_to_site = {"env": my_env,
                "name": "to_site",
                "geometry": location_to_site,
                "capacity": 10,
                "level": 0
               }
# instantiate to_site 
to_site = Site(**data_to_site)

3.2. Create vessel object(s)#

# prepare input data for vessel_01
data_vessel01 = {"env": my_env,
                 "name": "vessel01",
                 "geometry": location_from_site, 
                 "loading_rate": 1,
                 "unloading_rate": 1,
                 "capacity": 5,
                 "compute_v": lambda x: 10
               }
# instantiate vessel_01 
vessel01 = TransportProcessingResource(**data_vessel01)

3.3 Create activity/activities#

# initialise registry
registry = {}
# create a list of the sub processes
sub_processes = [
    model.ShiftAmountActivity(
        env=my_env,
        name="Shift 1 amount of payload",
        registry=registry,
        processor=vessel01,
        origin=from_site,
        destination=vessel01,
        amount=1,
        duration=20,
    )
]

# create a 'while activity' that is made up of the 'sub_processes'
while_activity = model.WhileActivity(
    env=my_env,
    name="while_activity",
    registry=registry,
    sub_processes=sub_processes,
    condition_event=[{"type": "container", "concept": vessel01, "state": "full"}],
)

We execute the sub_processes (i.c. ShiftAmount) until the container of vessel01 is full.

4. Register processes and run simpy#

# initate the simpy processes defined in the 'while activity' and run simpy
model.register_processes([while_activity])
my_env.run()

5. Inspect results#

5.1 Inspect logs#

The container of vessel01 has a capacity of 5. The shift amount activity shifts 1 amount of payload in 20 time untis. We can see from the log that the shift amount activity was executed 5 times. The simulation ends at 100 time units, when the vessel01 container level is 5.

display(plot.get_log_dataframe(vessel01, [while_activity, *sub_processes]))
Activity Timestamp ActivityState container level geometry
0 Shift 1 amount of payload 1970-01-01 00:00:00 START 0.0 POINT (4.18055556 52.18664444)
1 Shift 1 amount of payload 1970-01-01 00:00:20 STOP 1.0 POINT (4.18055556 52.18664444)
2 Shift 1 amount of payload 1970-01-01 00:00:20 START 1.0 POINT (4.18055556 52.18664444)
3 Shift 1 amount of payload 1970-01-01 00:00:40 STOP 2.0 POINT (4.18055556 52.18664444)
4 Shift 1 amount of payload 1970-01-01 00:00:40 START 2.0 POINT (4.18055556 52.18664444)
5 Shift 1 amount of payload 1970-01-01 00:01:00 STOP 3.0 POINT (4.18055556 52.18664444)
6 Shift 1 amount of payload 1970-01-01 00:01:00 START 3.0 POINT (4.18055556 52.18664444)
7 Shift 1 amount of payload 1970-01-01 00:01:20 STOP 4.0 POINT (4.18055556 52.18664444)
8 Shift 1 amount of payload 1970-01-01 00:01:20 START 4.0 POINT (4.18055556 52.18664444)
9 Shift 1 amount of payload 1970-01-01 00:01:40 STOP 5.0 POINT (4.18055556 52.18664444)
display(plot.get_log_dataframe(while_activity, [while_activity, *sub_processes]))
Activity Timestamp ActivityState type ref
0 while_activity 1970-01-01 00:00:00 START NaN NaN
1 while_activity 1970-01-01 00:00:00 START subprocess 523d9c53-aeaa-4cbb-89a8-9c1b477ac52f
2 while_activity 1970-01-01 00:00:20 STOP subprocess 523d9c53-aeaa-4cbb-89a8-9c1b477ac52f
3 while_activity 1970-01-01 00:00:20 START subprocess 523d9c53-aeaa-4cbb-89a8-9c1b477ac52f
4 while_activity 1970-01-01 00:00:40 STOP subprocess 523d9c53-aeaa-4cbb-89a8-9c1b477ac52f
5 while_activity 1970-01-01 00:00:40 START subprocess 523d9c53-aeaa-4cbb-89a8-9c1b477ac52f
6 while_activity 1970-01-01 00:01:00 STOP subprocess 523d9c53-aeaa-4cbb-89a8-9c1b477ac52f
7 while_activity 1970-01-01 00:01:00 START subprocess 523d9c53-aeaa-4cbb-89a8-9c1b477ac52f
8 while_activity 1970-01-01 00:01:20 STOP subprocess 523d9c53-aeaa-4cbb-89a8-9c1b477ac52f
9 while_activity 1970-01-01 00:01:20 START subprocess 523d9c53-aeaa-4cbb-89a8-9c1b477ac52f
10 while_activity 1970-01-01 00:01:40 STOP subprocess 523d9c53-aeaa-4cbb-89a8-9c1b477ac52f
11 while_activity 1970-01-01 00:01:40 STOP NaN NaN

5.2 Visualise gantt charts#

plot.get_gantt_chart([while_activity, *sub_processes, vessel01])

5.3 Inspect objects#

We can inspect the resulting levels of the container objects in vessel01 and from_site as follows.

vessel01.container.get_level()
5.0
from_site.container.get_level()
5