feeder concept#

This notebook shows how to implement a basic feeder concept. This scenario has two vessels:

  • transporter01: a vessel that transports the material from from_site, the source of the cargo, to to_site, the site where the cargo should be installed, and

  • installer01: a vessel that waits at the installation site for material and installs it.

Thus, we also need two processes - one for each vessel. In this notebook the hand over of cargo is done from the transporter01 to installer01.

NB1: in this example there are two types of cargo: Cargo_1 and Cargo_2. This means that the vessels and sites have to have multistore containers that can contain these different cargos.

NB2: For now we only implemented the transport and installation process for Cargo_1. In fact only a quantity of one is shifted each cycle. An example of sequential execution of two types fo cargo transfer is found in in the next example.

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.HasMultiContainer,
        core.HasResource,
    ),
    {},
)

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

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,
                  "store_capacity": 4,
                  "initials": [
                               {"id": "Cargo_1", "level": 5, "capacity": 10},
                               {"id": "Cargo_2", "level": 5, "capacity": 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,
                "store_capacity": 4,
                "initials": [
                            {"id": "Cargo_1", "level": 0, "capacity": 5},
                            {"id": "Cargo_2", "level": 0, "capacity": 5},
                           ]
               }

# instantiate to_site 
to_site = Site(**data_to_site)

3.2. Create vessel object(s)#

# prepare input data for transporter01
data_transporter01 = {"env": my_env,
                      "name": "transporter01",
                      "geometry": location_from_site, 
                      "loading_rate": 1,
                      "unloading_rate": 1,
                      "store_capacity": 4,
                      "compute_v": lambda x: 10,
                      "initials": [
                                   {"id": "Cargo_1", "level": 0, "capacity": 2},
                                   {"id": "Cargo_2", "level": 0, "capacity": 2},
                                  ],
                     }
# instantiate transporter01 
transporter01 = TransportProcessingResource(**data_transporter01)

# prepare input data for installer01
data_installer01 = {"env": my_env,
                    "name": "installer01",
                    "geometry": location_from_site, 
                    "loading_rate": 1,
                    "unloading_rate": 1,
                    "store_capacity": 4,
                    "compute_v": lambda x: 10,
                    "initials": [
                                 {"id": "Cargo_1", "level": 0, "capacity": 1},
                                 {"id": "Cargo_2", "level": 0, "capacity": 1},
                                ],
                   }
# instantiate installer01 
installer01 = TransportProcessingResource(**data_installer01)

3.3 Create activity/activities#

# initialise registry
registry = {}

3.3.1 Create transporter activity#

# create a list of the sub processes: transport to installation site
sub_processes =[
    model.MoveActivity(
        env=my_env,
        name="sailing empty",
        registry=registry,
        mover=transporter01,
        destination=from_site,
    ),
    model.ShiftAmountActivity(
        env=my_env,
        name="loading Cargo_1",
        registry=registry,
        processor=transporter01,
        origin=from_site,
        destination=transporter01,
        amount=1,
        duration=120,
        id_="Cargo_1",
    ),
    model.MoveActivity(
        env=my_env,
        name="sailing filled",
        registry=registry,
        mover=transporter01,
        destination=to_site,
    ),
    model.ShiftAmountActivity(
        env=my_env,
        name="transfer Cargo_1",
        registry=registry,
        processor=installer01,
        origin=transporter01,
        destination=installer01,
        amount=1,
        duration=120,
        id_="Cargo_1",
        start_event=[{"type": "activity", "name": "preparing for delivery", "state": "done",}],
    ),
]

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

# create a while activity that executes the 'sequential activity' while the stop condition is not triggered 
transport_activity = model.WhileActivity(
    env=my_env,
    name="Transporter01 move process",
    registry=registry,
    sub_processes=[sequential_activity],
    condition_event=[{"type": "container", "concept": from_site, "state": "empty", "id_": "Cargo_1"}],
)

3.3.2 Create installer activity (first move, then install)#

# create a list of the sub processes: in field installation
sub_processes =[
    model.BasicActivity(
        env=my_env,
        name="preparing for delivery",
        registry=registry,
        duration=30,
        additional_logs=[installer01],
    ),
    model.BasicActivity(
        env=my_env,
        name="preparing for unloading",
        registry=registry,
        duration=60,
        additional_logs=[installer01],
        start_event=[
            {"type": "activity", "name": "sequential_activity_transport_subcycle", "state": "done"}
        ],
    ),
    model.ShiftAmountActivity(
        env=my_env,
        name="unload Cargo_1",
        registry=registry,
        processor=installer01,
        origin=installer01,
        destination=to_site,
        amount=1,
        duration=120,
        id_="Cargo_1",
    ),
]

# create a 'sequential activity' that is made up of the 'sub_processes'
installer_shift_sequential_activity = model.SequentialActivity(
    env=my_env,
    name="Installer01 installation process",
    registry=registry,
    sub_processes=sub_processes,
)
# create a list of the sub processes: in field installation
sub_processes = [
    model.MoveActivity(
        env=my_env,
        name="sailing to site",
        registry=registry,
        mover=installer01,
        destination=to_site,
    ),
    model.WhileActivity(
        env=my_env,
        name="installer run while",
        registry=registry,
        sub_processes=[installer_shift_sequential_activity],
        condition_event=[
            {"type": "container", "concept": to_site, "state": "full", "id_": "Cargo_1"}
        ],
    ),
]

installer_move_sequential_activity = model.SequentialActivity(
    env=my_env,
    name="Installer01 move process",
    registry=registry,
    sub_processes=sub_processes,
)

4. Register processes and run simpy#

model.register_processes([transport_activity, installer_move_sequential_activity])
my_env.run()

5. Inspect results#

5.1 Inspect logs#

plot.get_log_dataframe(transporter01, [transport_activity])
Activity Timestamp ActivityState container level geometry
0 sailing empty 1970-01-01 00:00:00.000000 START {'Cargo_1': 0, 'Cargo_2': 0} POINT (4.18055556 52.18664444)
1 sailing empty 1970-01-01 00:00:00.000000 STOP {'Cargo_1': 0, 'Cargo_2': 0} POINT (4.18055556 52.18664444)
2 loading Cargo_1 1970-01-01 00:00:00.000000 START {'Cargo_1': 0, 'Cargo_2': 0} POINT (4.18055556 52.18664444)
3 loading Cargo_1 1970-01-01 00:02:00.000000 STOP {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.18055556 52.18664444)
4 sailing filled 1970-01-01 00:02:00.000000 START {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.18055556 52.18664444)
5 sailing filled 1970-01-01 00:17:42.824591 STOP {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.25222222 52.11428333)
6 transfer Cargo_1 1970-01-01 00:17:42.824591 START {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.25222222 52.11428333)
7 transfer Cargo_1 1970-01-01 00:19:42.824591 STOP {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.25222222 52.11428333)
8 sailing empty 1970-01-01 00:19:42.824591 START {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.25222222 52.11428333)
9 sailing empty 1970-01-01 00:35:25.649183 STOP {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.18055556 52.18664444)
10 loading Cargo_1 1970-01-01 00:35:25.649183 START {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.18055556 52.18664444)
11 loading Cargo_1 1970-01-01 00:37:25.649183 STOP {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.18055556 52.18664444)
12 sailing filled 1970-01-01 00:37:25.649183 START {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.18055556 52.18664444)
13 sailing filled 1970-01-01 00:53:08.473774 STOP {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.25222222 52.11428333)
14 transfer Cargo_1 1970-01-01 00:53:08.473774 START {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.25222222 52.11428333)
15 transfer Cargo_1 1970-01-01 00:55:08.473774 STOP {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.25222222 52.11428333)
16 sailing empty 1970-01-01 00:55:08.473774 START {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.25222222 52.11428333)
17 sailing empty 1970-01-01 01:10:51.298365 STOP {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.18055556 52.18664444)
18 loading Cargo_1 1970-01-01 01:10:51.298365 START {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.18055556 52.18664444)
19 loading Cargo_1 1970-01-01 01:12:51.298365 STOP {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.18055556 52.18664444)
20 sailing filled 1970-01-01 01:12:51.298365 START {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.18055556 52.18664444)
21 sailing filled 1970-01-01 01:28:34.122956 STOP {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.25222222 52.11428333)
22 transfer Cargo_1 1970-01-01 01:28:34.122956 START {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.25222222 52.11428333)
23 transfer Cargo_1 1970-01-01 01:30:34.122956 STOP {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.25222222 52.11428333)
24 sailing empty 1970-01-01 01:30:34.122956 START {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.25222222 52.11428333)
25 sailing empty 1970-01-01 01:46:16.947548 STOP {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.18055556 52.18664444)
26 loading Cargo_1 1970-01-01 01:46:16.947548 START {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.18055556 52.18664444)
27 loading Cargo_1 1970-01-01 01:48:16.947548 STOP {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.18055556 52.18664444)
28 sailing filled 1970-01-01 01:48:16.947548 START {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.18055556 52.18664444)
29 sailing filled 1970-01-01 02:03:59.772139 STOP {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.25222222 52.11428333)
30 transfer Cargo_1 1970-01-01 02:03:59.772139 START {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.25222222 52.11428333)
31 transfer Cargo_1 1970-01-01 02:05:59.772139 STOP {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.25222222 52.11428333)
32 sailing empty 1970-01-01 02:05:59.772139 START {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.25222222 52.11428333)
33 sailing empty 1970-01-01 02:21:42.596730 STOP {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.18055556 52.18664444)
34 loading Cargo_1 1970-01-01 02:21:42.596730 START {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.18055556 52.18664444)
35 loading Cargo_1 1970-01-01 02:23:42.596730 STOP {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.18055556 52.18664444)
36 sailing filled 1970-01-01 02:23:42.596730 START {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.18055556 52.18664444)
37 sailing filled 1970-01-01 02:39:25.421321 STOP {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.25222222 52.11428333)
38 transfer Cargo_1 1970-01-01 02:39:25.421321 START {'Cargo_2': 0, 'Cargo_1': 1} POINT (4.25222222 52.11428333)
39 transfer Cargo_1 1970-01-01 02:41:25.421321 STOP {'Cargo_2': 0, 'Cargo_1': 0} POINT (4.25222222 52.11428333)

5.2 Visualise gantt charts#

plot.get_gantt_chart([transport_activity, installer_move_sequential_activity])
plot.get_gantt_chart([transporter01, installer01, from_site, to_site],id_map=[transport_activity, installer_move_sequential_activity])

5.3 Visualise container volume developments#

fig = plot.get_step_chart([from_site, to_site])
../_images/6f73e9fe844ceddd3ba56b5f28454738d6c5f409fbb8159b7e95491f5d1bb413.png
fig = plot.get_step_chart([transporter01, installer01])
../_images/0469bf5708e327cbf9feb21e4c7682b6a0a35a017fc2752f181210a7d2fd2dc7.png