feeder concept + MultiContainer#

This notebook shows how to implement a basic feeder concept with two types of cargo

0. Import libraries#

import datetime, time
import simpy

import numpy as np
import pandas as pd
import shapely.geometry

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

1. Initialise simpy environment#

NR_BARGES = 3
TOTAL_AMOUNT = 100
BARGE_CAPACITY=10

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

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.Identifiable,
        core.Log,
    ),
    {"key": "MultiStoreHopper"},
)

3. Create objects#

3.1. Create site object(s)#

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,
                  "nr_resources": 1,
                  "initials": [
                    {
                        "id": "Cargo type 1",
                        "level": TOTAL_AMOUNT,
                        "capacity": TOTAL_AMOUNT
                    },
                  ],
                 }
from_site = Site(**data_from_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,
                "nr_resources": 1,
                "initials": [
                    {
                        "id": "Cargo type 1",
                        "level": 0,
                        "capacity": TOTAL_AMOUNT
                    },
                ],
                 }
to_site = Site(**data_to_site)

3.2. Create vessel object(s)#

vessels = {}
for i in range(NR_BARGES):
    vessels[f"barge {i}"] = TransportProcessingResource(
        env=my_env,
        name=f"barge{i}",
        geometry=location_from_site, 
        store_capacity=4,
        nr_resources=1,
        compute_v=lambda x: 10,
        initials=[
            {
                "id": "Cargo type 1",
                "level": 0,
                "capacity": BARGE_CAPACITY
            },
         ],
    )
    


# prepare input data for installer01
data_installer01 = {"env": my_env,
                 "name": "installer01",
                 "geometry": location_to_site, 
                 "store_capacity": 4,
                 "nr_resources": 1,
                 "compute_v": lambda x: 10,
                 "initials": [
                    {
                        "id": "Cargo type 1",
                        "level": 0,
                        "capacity": NR_BARGES, # Bug we need a watchtower for this
                    },
                 ],
                 }
# instantiate vessel_02 
installer01 = TransportProcessingResource(**data_installer01)

3.3 Create activity/activities#

processes = []
for i in range(NR_BARGES):
    vessel = vessels[f"barge {i}"]
    requested_resources={}
    
    processes.append(
        model.WhileActivity(
            env=my_env,
            name=f"while {vessel.name}",
            registry=registry,
            sub_processes=[
                model.SequentialActivity(
                    env=my_env,
                    name=f"sequence {vessel.name}",
                    registry=registry,
                    sub_processes=[
                        model.MoveActivity(
                            env=my_env,
                            name=f"sailing empty {vessel.name}",
                            registry=registry,
                            mover=vessel,
                            destination=from_site,
                            duration=10,
                        ),
                        model.ShiftAmountActivity(
                            env=my_env,
                            name=f"load cargo type 1 {vessel.name}",
                            registry=registry,
                            processor=vessel,
                            origin=from_site,
                            destination=vessel,
                            amount=BARGE_CAPACITY,
                            duration=10,
                            id_="Cargo type 1",
                            requested_resources=requested_resources,
                        ),
                        model.MoveActivity(
                            env=my_env,
                            name=f"sailing filled {vessel.name}",
                            registry=registry,
                            mover=vessel,
                            destination=to_site,
                            duration=10,
                        ),
                        model.WhileActivity(
                            env=my_env,
                            name=f"unload cycle {vessel.name}",
                            registry=registry,
                            condition_event={
                                "type": "container", 
                                "concept": vessel, 
                                "state": "empty",
                                "id_":"Cargo type 1"
                            },
                            sub_processes=[
                                model.ShiftAmountActivity(
                                    env=my_env,
                                    name=f"unload cargo type 1 {vessel.name}",
                                    registry=registry,
                                    processor=installer01,
                                    origin=vessel,
                                    destination=installer01,
                                    amount=1,
                                    duration=10,
                                    id_="Cargo type 1",
                                    requested_resources=requested_resources,
                                    start_event={
                                        "type": "container", 
                                        "concept": installer01, 
                                        "state": "lt", 
                                        "level":1,
                                        "id_":"Cargo type 1"
                                    }
                                ),
                            ]
                        )
                    ],
                )
            ],
            condition_event={
                "type": "container", 
                "concept": from_site, 
                "state": "empty",
                "id_":"Cargo type 1_reservations"
            },
        )
    )
install_process = model.WhileActivity(
    env=my_env,
    name=f"While installer",
    registry=registry,
    condition_event={
        "type": "container", 
        "concept": to_site, 
        "state": "full",
        "id_":"Cargo type 1"
    },
    sub_processes=[
        model.ShiftAmountActivity(
            env=my_env,
            name=f"Install Cargo type 1",
            registry=registry,
            processor=installer01,
            origin=installer01,
            destination=to_site,
            amount=1,
            duration=2,
            id_="Cargo type 1",
            start_event={
                "type": "container", 
                "concept": installer01, 
                "state": "ge", 
                "level":1,
                "id_":"Cargo type 1"
            }
        )
    ],
)

4. Register processes and run simpy#

model.register_processes([install_process, *processes])
my_env.run()
# this should be made generic and added to openclsim.plot
def extend_id_map(activity, id_map):
    if hasattr(activity, "sub_processes"):
        for sub_process in activity.sub_processes:
            id_map = extend_id_map(sub_process, id_map)
    
    return {**id_map, activity.id: activity }

activity_map = {}
for activity in [*processes, install_process]:
    activity_map = extend_id_map(activity, activity_map)

5. Inspect results#

5.1 Inspect logs#

plot.get_log_dataframe(installer01, list(activity_map.values())).head()
Activity Timestamp ActivityState container level geometry
0 unload cargo type 1 barge0 1970-01-01 00:00:30 START {'Cargo type 1': 0} POINT (4.25222222 52.11428333)
1 unload cargo type 1 barge0 1970-01-01 00:00:40 STOP {'Cargo type 1': 1} POINT (4.25222222 52.11428333)
2 unload cargo type 1 barge1 1970-01-01 00:00:40 START {'Cargo type 1': 1} POINT (4.25222222 52.11428333)
3 unload cargo type 1 barge1 1970-01-01 00:00:50 STOP {'Cargo type 1': 2} POINT (4.25222222 52.11428333)
4 Install Cargo type 1 1970-01-01 00:00:50 START {'Cargo type 1': 2} POINT (4.25222222 52.11428333)

5.2 Visualise gantt charts#

acts = []
for proc in processes:
    acts.extend(proc.sub_processes[0].sub_processes)
    
plot.get_gantt_chart([*install_process.sub_processes, *acts])
plot.get_gantt_chart(
    [installer01, *[vessels[v] for v in vessels]], 
    id_map=[install_process,*processes]
)
[installer01.name, *[vessels[v].name for v in vessels]]
['installer01', 'barge0', 'barge1', 'barge2']

5.3 Visualise step charts#

fig = plot.get_step_chart([installer01])
../_images/103f80c505731c7b06dbc2ee4e97337ce79c83bdd795c0a8a8d2fb66944e2b42.png
fig = plot.get_step_chart([from_site, *vessels.values(), installer01, to_site])
../_images/d038f931009060d536f3e6b1009323a5f21726520cd447ccbf5f65c5afa896b8.png