single_run_process + sub-cycles#

The simulation takes a number of sub_processes, grouped in a SequentialActivity, that is executed while a stop condition is not yet met. The example is basically a single_run_process, but now the loading and unloading steps are made up of subcycles that are executed a fixed number of times.

For this example we work with the following sub processes:

  • pre cycle activity

  • sailing empty

  • repeat loading 5 times

    • pre loading activity

    • loading

    • post loading activity

  • sailing full

  • repeat unloading 5 times

    • pre unloading activity

    • unloading

    • post unloading activity

  • post cycle activity

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": 100,
                  "level": 50
                 }
# 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": 50,
                "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": 0.00001,
                 "unloading_rate": 0.00001,
                 "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: loading
sub_processes_loading =[
    model.BasicActivity(
        env=my_env,
        name="pre loading activity",
        registry=registry,
        duration=100,
        additional_logs=[vessel01],
    ),
    model.ShiftAmountActivity(
        env=my_env,
        name="loading",
        registry=registry,
        processor=vessel01,
        origin=from_site,
        destination=vessel01,
        amount=1,
        duration=1000,
    ),
    model.BasicActivity(
        env=my_env,
        name="post loading activity",
        registry=registry,
        duration=100,
        additional_logs=[vessel01],
    ),
]

# create a 'sequential activity' that is made up of the 'sub_processes'
sequential_activity_loading = model.SequentialActivity(
            env=my_env,
            name="sequential_activity_loading_subcycle",
            registry=registry,
            sub_processes=sub_processes_loading,
        )

# create a repeat activity that executes the 'sequential activity' a fixed number of times 
repeat_loading_activity = model.RepeatActivity(
    env=my_env,
    name="repeat_sequential_activity_loading_subcycle",
    registry=registry,
    sub_processes=[sequential_activity_loading],
    repetitions=5
)
# create a list of the sub processes: unloading
sub_processes_unloading =[
    model.BasicActivity(
        env=my_env,
        name="pre unloading activity",
        registry=registry,
        duration=100,
        additional_logs=[vessel01],
    ),
    model.ShiftAmountActivity(
        env=my_env,
        name="unloading",
        registry=registry,
        processor=vessel01,
        origin=vessel01,
        destination=to_site,
        amount=1,
        duration=1000,
    ),
    model.BasicActivity(
        env=my_env,
        name="post unloading activity",
        registry=registry,
        duration=100,
        additional_logs=[vessel01],
    ),
]

# create a 'sequential activity' that is made up of the 'sub_processes'
sequential_activity_unloading = model.SequentialActivity(
            env=my_env,
            name="sequential_activity_unloading_subcycle",
            registry=registry,
            sub_processes=sub_processes_unloading,
        )

# create a repeat activity that executes the 'sequential activity' a fixed number of times 
repeat_unloading_activity = model.RepeatActivity(
    env=my_env,
    name="repeat_sequential_activity_unloading_subcycle",
    registry=registry,
    sub_processes=[sequential_activity_unloading],
    repetitions=5
)
# create a list of the sub processes: cycle
sub_processes = [
    model.BasicActivity(
        env=my_env,
        name="pre cycle activity",
        registry=registry,
        duration=100,
        additional_logs=[vessel01],
    ),
    model.MoveActivity(
        env=my_env,
        name="sailing empty",
        registry=registry,
        mover=vessel01,
        destination=from_site,
        duration=500,
    ),
    repeat_loading_activity,
    model.MoveActivity(
        env=my_env,
        name="sailing full",
        registry=registry,
        mover=vessel01,
        duration=500,
        destination=to_site,
    ),
    repeat_unloading_activity,
    model.BasicActivity(
        env=my_env,
        name="post cycle activity",
        registry=registry,
        duration=100,
        additional_logs=[vessel01],
    ),
]

# create a 'sequential activity' that is made up of the 'sub_processes'
sequential_activity = model.SequentialActivity(
    env=my_env,
    name="sequential_activity_subcycle",
    registry=registry,
    sub_processes=sub_processes,
)

# create a while activity that executes the 'sequential activity' while the stop condition is not triggered 
while_activity = model.WhileActivity(
    env=my_env,
    name="while_sequential_activity_subcycle",
    registry=registry,
    sub_processes=[sequential_activity],
    condition_event=[{"type": "container", "concept": to_site, "state": "full"}],
)

4. Register processes and run simpy#

model.register_processes([while_activity])
my_env.run()

5. Inspect results#

5.1 Inspect logs#

plot.get_log_dataframe(vessel01, [while_activity])
Activity Timestamp ActivityState container level geometry type ref
0 pre cycle activity 1970-01-01 00:00:00 START 0.0 POINT (4.18055556 52.18664444) additional log 682d457f-8bf6-416d-92c8-d60e605295fa
1 pre cycle activity 1970-01-01 00:01:40 STOP 0.0 POINT (4.18055556 52.18664444) additional log 682d457f-8bf6-416d-92c8-d60e605295fa
2 sailing empty 1970-01-01 00:01:40 START 0.0 POINT (4.18055556 52.18664444) NaN NaN
3 sailing empty 1970-01-01 00:10:00 STOP 0.0 POINT (4.18055556 52.18664444) NaN NaN
4 pre loading activity 1970-01-01 00:10:00 START 0.0 POINT (4.18055556 52.18664444) additional log 5dd67294-ffd0-408d-ae19-d0819b527d78
... ... ... ... ... ... ... ...
675 unloading 1970-01-02 12:36:40 STOP 0.0 POINT (4.25222222 52.11428333) NaN NaN
676 post unloading activity 1970-01-02 12:36:40 START 0.0 POINT (4.25222222 52.11428333) additional log 0cfa8ee5-791d-4d8e-94dc-af833b72bb63
677 post unloading activity 1970-01-02 12:38:20 STOP 0.0 POINT (4.25222222 52.11428333) additional log 0cfa8ee5-791d-4d8e-94dc-af833b72bb63
678 post cycle activity 1970-01-02 12:38:20 START 0.0 POINT (4.25222222 52.11428333) additional log 9800ac61-7dfd-41e8-855a-3d4ad45b21ce
679 post cycle activity 1970-01-02 12:40:00 STOP 0.0 POINT (4.25222222 52.11428333) additional log 9800ac61-7dfd-41e8-855a-3d4ad45b21ce

680 rows × 7 columns

5.2 Visualise gantt charts#

plot.get_gantt_chart([while_activity, sequential_activity, *sub_processes])
plot.get_gantt_chart([vessel01, from_site, to_site],id_map=[while_activity])

5.3 Visualise container volume developments#

fig = plot.get_step_chart([vessel01, from_site, to_site])
../_images/99847bd0e22cdc5d034e010e726043d21c374b1b2fb66a5a37ccd8923ce9fb53.png