simulation_classes.port

This module defines the port resources and their initialization for a port simulation. It includes classes for containers, cranes, berths, pipelines, conveyors, and their respective initialization methods. This module is part of a larger port simulation system that models the operations of a port, including handling of containers, liquid bulk, and dry bulk cargo.

  1"""
  2This module defines the port resources and their initialization for a port simulation.
  3It includes classes for containers, cranes, berths, pipelines, conveyors, and their respective initialization methods.
  4This module is part of a larger port simulation system that models the operations of a port, including handling of containers, liquid bulk, and dry bulk cargo.
  5"""
  6import simpy
  7import random
  8import pandas as pd
  9import constants
 10
 11from simulation_handler.helpers import get_value_by_terminal, get_values_by_terminal_random_sample, normal_random_with_limit, get_value_from_terminal_tuple
 12
 13# initial terminal storage levels set as 50%
 14prefill_yard_per = 0.5
 15prefill_tank_per = 0.5
 16prefill_silo_per = 0.5
 17NUM_PILOTS_DAY = constants.NUM_PILOTS_DAY
 18NUM_PILOTS_NIGHT = constants.NUM_PILOTS_NIGHT
 19NUM_TUGBOATS = constants.NUM_TUGBOATS
 20
 21
 22class Container:
 23    """Class representing a container in the port yard.
 24    Args:
 25        id (str): Unique identifier for the container.
 26        width (int): Width of the container.
 27    """
 28
 29    def __init__(self, id, width):
 30        self.id = id
 31        self.width = width
 32
 33
 34class Crane:
 35    """Class representing a crane in a container berth.
 36    Args:
 37        id (str): Unique identifier for the crane.
 38        width (int): Width of the crane.
 39        crane_transfer_rate (float): Rate at which the crane can transfer containers.
 40    """
 41
 42    def __init__(self, id, width, crane_transfer_rate):
 43        self.id = id
 44        self.width = width
 45        self.crane_transfer_rate = crane_transfer_rate
 46
 47
 48class Berth_Ctr:
 49    """Class representing a container berth with multiple cranes.
 50    Args:
 51        env (simpy.Environment): The simulation environment.
 52        id (str): Unique identifier for the berth.
 53        cranes_per_berth (int): Number of cranes in the berth.
 54        crane_transfer_rate (float): Rate at which each crane can transfer containers.
 55    """
 56
 57    def __init__(self, env, id, cranes_per_berth, crane_transfer_rate):
 58        self.id = id
 59        self.cranes = simpy.Store(env, capacity=cranes_per_berth)
 60        self.crane_transfer_rate = crane_transfer_rate
 61        for i in range(cranes_per_berth):
 62            self.cranes.put(
 63                Crane(id=f"{id}.{i}", width="width", crane_transfer_rate=crane_transfer_rate))
 64
 65
 66class Pipeline:
 67    """Class representing a pipeline in a liquid berth.
 68    Args:
 69        env (simpy.Environment): The simulation environment.
 70        id (str): Unique identifier for the pipeline.
 71        pump_rate_per_pipeline (float): Rate at which the pipeline can pump liquid.
 72    """
 73
 74    def __init__(self, env, id, pump_rate_per_pipeline):
 75        self.env = env
 76        self.id = id
 77        self.pump_rate_per_pipeline = pump_rate_per_pipeline
 78
 79
 80class Berth_Liq:
 81    """Class representing a liquid berth with multiple pipelines.
 82    Args:
 83        env (simpy.Environment): The simulation environment.
 84        id (str): Unique identifier for the berth.
 85        piplines_per_berth (int): Number of pipelines in the berth.
 86        pump_rate_per_pipeline (float): Rate at which each pipeline can pump liquid.
 87    """
 88
 89    def __init__(self, env, id, piplines_per_berth, pump_rate_per_pipeline):
 90        self.id = id
 91        self.pipelines = simpy.Store(env, capacity=piplines_per_berth)
 92        for i in range(piplines_per_berth):
 93            self.pipelines.put(Pipeline(
 94                env=env, id=f"{id}.{i}", pump_rate_per_pipeline=pump_rate_per_pipeline))
 95
 96
 97class Conveyor:
 98    """
 99    Class representing a conveyor in a dry bulk berth.
100     Args:
101        env (simpy.Environment): The simulation environment.
102        id (str): Unique identifier for the conveyor.
103        conveyor_rate_per_conveyor (float): Rate at which the conveyor can transfer dry bulk.
104    """
105
106    def __init__(self, env, id, conveyor_rate_per_conveyor):
107        self.env = env
108        self.id = id
109        self.conveyor_rate_per_conveyor = conveyor_rate_per_conveyor
110
111
112class Berth_DryBulk:
113    """Class representing a dry bulk berth with multiple conveyors.
114    Args:
115        env (simpy.Environment): The simulation environment.
116        id (str): Unique identifier for the berth.
117        conveyors_per_berth (int): Number of conveyors in the berth.
118        conveyor_rate_per_conveyor (float): Rate at which each conveyor can transfer dry bulk.
119    """
120
121    def __init__(self, env, id, conveyors_per_berth, conveyor_rate_per_conveyor):
122        self.id = id
123        self.conveyors = simpy.Store(env, capacity=conveyors_per_berth)
124        for i in range(conveyors_per_berth):
125            self.conveyors.put(Conveyor(
126                env=env, id=f"{id}.{i}", conveyor_rate_per_conveyor=conveyor_rate_per_conveyor))
127
128
129def create_resources(terminal_data, run_id, terminal_data_df, num_terminals, env, seed):
130    """
131    Create and initialize resources for the port simulation based on terminal data.
132    This function sets up yards, berths, tanks, silos, loading bays, truck gates, train loading racks,
133    and pilot/tugboat resources for each terminal type (Container, Liquid, DryBulk).
134    Args:
135        terminal_data (dict): Dictionary containing terminal data.
136        run_id (str): Unique identifier for the simulation run.
137        terminal_data_df (pd.DataFrame): DataFrame containing terminal data.
138        num_terminals (tuple): Tuple containing the number of terminals for each cargo type (Container, Liquid, DryBulk).
139        env (simpy.Environment): The simulation environment.
140        seed (int): Random seed for reproducibility.
141    Returns:
142        terminal_resouces (list): List of resources created for each terminal type. This includes yards, berths, tanks, silos, loading bays, truck gates, train loading racks, pilots, tugboats, and channel scheduler.
143    """
144    num_container_terminals, num_liquid_terminals, num_drybulk_terminals = num_terminals
145
146    #############################
147    # Container terminal resources
148    #############################
149
150    random.seed(seed)
151    # Yard
152    port_yard_container_terminals = [
153        simpy.Store(env, capacity=get_value_by_terminal(
154            terminal_data, 'Container', idx + 1, 'storage volume'))
155        for idx in range(num_container_terminals)
156    ]
157    for idx in range(num_container_terminals):
158        initial_capacity = int(prefill_yard_per * get_value_by_terminal(
159            terminal_data, 'Container', idx + 1, 'storage volume'))
160        for i in range(initial_capacity):
161            port_yard_container_terminals[idx].put(
162                Container(id=f"initial_{i}", width=0))
163
164    port_chassis_container_terminals = [
165        simpy.Store(env, capacity=get_value_by_terminal(terminal_data, 'Container', idx +
166                    1, 'truck bays/chassis'))  # Setting capacity to infinity or a large value
167        for _ in range(num_container_terminals)
168    ]
169
170    # Initialize each store with the desired number of items
171    for idx, store in enumerate(port_chassis_container_terminals):
172        init_items = get_value_by_terminal(
173            terminal_data, 'Container', idx + 1, 'truck bays/chassis')
174        for _ in range(init_items):
175            store.put(1)
176
177    # Berths
178    port_berths_container_terminals = [
179        simpy.Store(env, capacity=get_value_by_terminal(
180            terminal_data, 'Container', idx + 1, 'Berths'))
181        for idx in range(num_container_terminals)
182    ]
183
184    # Add cranes to the container berths
185    for idx, terminal in enumerate(port_berths_container_terminals):
186        num_cranes_list = get_values_by_terminal_random_sample(
187            terminal_data_df, 'Container', idx+1, 'transfer units per berth', num_samples=get_value_by_terminal(terminal_data, 'Container', idx + 1, 'Berths'), seed=seed)
188
189        for i in range(get_value_by_terminal(terminal_data, 'Container', idx + 1, 'Berths')):
190            terminal.put(Berth_Ctr(env=env, id=i, cranes_per_berth=num_cranes_list[i], crane_transfer_rate=get_value_by_terminal(
191                terminal_data, 'Container', idx + 1, 'transfer rate per unit')))
192            # print(f"Container Terminal {idx+1} Berth {i} has {num_cranes_list[i]} cranes")
193
194    #############################
195    # Liquid bulk terminal resources
196    #############################
197
198    # Tanks
199    tank_capacity = [get_value_by_terminal(
200        terminal_data, 'Liquid', idx + 1, 'storage volume') for idx in range(num_liquid_terminals)]
201    port_tanks_liquid_terminals = [simpy.Container(env, capacity=capacity, init=int(
202        prefill_tank_per*capacity)) for capacity in tank_capacity]
203
204    #  Loading bays
205    port_loading_bays_liquid_terminals = [simpy.Resource(env, capacity=get_value_by_terminal(
206        terminal_data, 'Liquid', idx + 1, 'truck bays/chassis')) for idx in range(num_liquid_terminals)]
207
208    # Berths
209    port_berth_liquid_terminals = [
210        simpy.Store(env, capacity=get_value_by_terminal(
211            terminal_data, 'Liquid', idx + 1, 'Berths'))
212        for idx in range(num_liquid_terminals)
213    ]
214
215    #  Add pipelines to the liquid berths
216    for idx, terminal in enumerate(port_berth_liquid_terminals):
217        num_pipelines_list = get_values_by_terminal_random_sample(
218            terminal_data_df, 'Liquid', idx+1, 'transfer units per berth', num_samples=get_value_by_terminal(terminal_data, 'Liquid', idx + 1, 'Berths'), seed=seed)
219        for i in range(get_value_by_terminal(terminal_data, 'Liquid', idx + 1, 'Berths')):
220            terminal.put(Berth_Liq(env=env, id=i, piplines_per_berth=num_pipelines_list[i], pump_rate_per_pipeline=get_value_by_terminal(
221                terminal_data, 'Liquid', idx + 1, 'transfer rate per unit')))
222            # print(f"Liquid Terminal {idx+1} Berth {i} has {num_pipelines_list[i]} pipelines")
223
224    #############################
225    # Dry bulk terminal resources
226    #############################
227
228    # Silos
229    silo_capacity = [get_value_by_terminal(
230        terminal_data, 'DryBulk', idx + 1, 'storage volume') for idx in range(num_drybulk_terminals)]
231    port_silos_drybulk_terminals = [simpy.Container(env, capacity=capacity, init=int(
232        prefill_silo_per*capacity)) for capacity in silo_capacity]
233
234    # Drybulk bays
235    port_drybulk_bays_drybulk_terminals = [simpy.Resource(env, capacity=get_value_by_terminal(
236        terminal_data, 'DryBulk', idx + 1, 'truck bays/chassis')) for idx in range(num_drybulk_terminals)]
237
238    # Berths
239    port_berth_drybulk_terminals = [
240        simpy.Store(env, capacity=get_value_by_terminal(
241            terminal_data, 'DryBulk', idx + 1, 'Berths'))
242        for idx in range(num_drybulk_terminals)
243    ]
244
245    # Conveyors
246    for idx, terminal in enumerate(port_berth_drybulk_terminals):
247        num_conveyors_list = get_values_by_terminal_random_sample(
248            terminal_data_df, 'DryBulk', idx+1, 'transfer units per berth', num_samples=get_value_by_terminal(terminal_data, 'DryBulk', idx + 1, 'Berths'), seed=seed)
249        for i in range(get_value_by_terminal(terminal_data, 'DryBulk', idx + 1, 'Berths')):
250            terminal.put(Berth_DryBulk(env=env, id=i, conveyors_per_berth=num_conveyors_list[i], conveyor_rate_per_conveyor=get_value_by_terminal(
251                terminal_data, 'DryBulk', idx + 1, 'transfer rate per unit')))
252            # print(f"Drybulk Terminal {idx+1} Berth {i} has {num_conveyors_list[i]} conveyors")
253
254    #############################
255    # Truck gates
256    #############################
257
258    truck_gates_ctr = [simpy.Resource(env, capacity=get_value_by_terminal(
259        terminal_data, 'Container', idx + 1, 'truck gates')) for idx in range(num_container_terminals)]
260    truck_gates_liquid = [simpy.Resource(env, capacity=get_value_by_terminal(
261        terminal_data, 'Liquid', idx + 1, 'truck gates')) for idx in range(num_liquid_terminals)]
262    truck_gates_dk = [simpy.Resource(env, capacity=get_value_by_terminal(
263        terminal_data, 'DryBulk', idx + 1, 'truck gates')) for idx in range(num_drybulk_terminals)]
264
265    #############################
266    # Train resources
267    #############################
268
269    # Loading racks (for loading operations)
270    train_loading_racks_ctr = [
271        simpy.Resource(env, capacity=get_value_by_terminal(
272            terminal_data, 'Container', idx + 1, 'train car loading bays'))
273        for idx in range(num_container_terminals)
274    ]
275    train_loading_racks_liquid = [
276        simpy.Resource(env, capacity=get_value_by_terminal(
277            terminal_data, 'Liquid', idx + 1, 'train car loading bays'))
278        for idx in range(num_liquid_terminals)
279    ]
280    train_loading_racks_dk = [
281        simpy.Resource(env, capacity=get_value_by_terminal(
282            terminal_data, 'DryBulk', idx + 1, 'train car loading bays'))
283        for idx in range(num_drybulk_terminals)
284    ]
285
286    #############################
287    # Pilot and tugboat resources
288    #############################
289
290    num_pilots_day = int(normal_random_with_limit(
291        NUM_PILOTS_DAY[0], NUM_PILOTS_DAY[1], seed))
292    num_pilots_night = int(normal_random_with_limit(
293        NUM_PILOTS_NIGHT[0], NUM_PILOTS_NIGHT[1], seed))
294    num_tugboats = int(normal_random_with_limit(
295        NUM_TUGBOATS[0], NUM_TUGBOATS[1], seed))
296
297    report_path = f".{run_id}/logs/final_report.txt"
298    with open(report_path, 'a') as f:
299        f.write(f"Num pilots in day shift: {num_pilots_day}\n")
300        f.write(f"Num pilots in night shift: {num_pilots_night}\n")
301        f.write(f"Num tugboats: {num_tugboats}\n\n")
302
303    day_pilots = simpy.Container(
304        env, init=num_pilots_day, capacity=num_pilots_day)
305    night_pilots = simpy.Container(
306        env, init=num_pilots_night, capacity=num_pilots_night)
307    tugboats = simpy.Container(env, init=num_tugboats, capacity=num_tugboats)
308
309    #############################
310    # Channel scheduler
311    #############################
312
313    # Only one ship can be scheduled at a time
314    channel_scheduer = simpy.Resource(env, capacity=1)
315
316    #############################
317    # Combines and returns all terminal resources for all cargo types
318    #############################
319
320    terminal_resouces = [port_berths_container_terminals, port_yard_container_terminals, port_berth_liquid_terminals,
321                         port_tanks_liquid_terminals, port_berth_drybulk_terminals, port_silos_drybulk_terminals,
322                         port_loading_bays_liquid_terminals, port_drybulk_bays_drybulk_terminals, port_chassis_container_terminals,
323                         truck_gates_ctr, truck_gates_liquid, truck_gates_dk, train_loading_racks_ctr, train_loading_racks_liquid,
324                         train_loading_racks_dk, day_pilots, night_pilots, tugboats, channel_scheduer]
325    return terminal_resouces
class Container:
23class Container:
24    """Class representing a container in the port yard.
25    Args:
26        id (str): Unique identifier for the container.
27        width (int): Width of the container.
28    """
29
30    def __init__(self, id, width):
31        self.id = id
32        self.width = width

Class representing a container in the port yard.

Arguments:
  • id (str): Unique identifier for the container.
  • width (int): Width of the container.
class Crane:
35class Crane:
36    """Class representing a crane in a container berth.
37    Args:
38        id (str): Unique identifier for the crane.
39        width (int): Width of the crane.
40        crane_transfer_rate (float): Rate at which the crane can transfer containers.
41    """
42
43    def __init__(self, id, width, crane_transfer_rate):
44        self.id = id
45        self.width = width
46        self.crane_transfer_rate = crane_transfer_rate

Class representing a crane in a container berth.

Arguments:
  • id (str): Unique identifier for the crane.
  • width (int): Width of the crane.
  • crane_transfer_rate (float): Rate at which the crane can transfer containers.
class Berth_Ctr:
49class Berth_Ctr:
50    """Class representing a container berth with multiple cranes.
51    Args:
52        env (simpy.Environment): The simulation environment.
53        id (str): Unique identifier for the berth.
54        cranes_per_berth (int): Number of cranes in the berth.
55        crane_transfer_rate (float): Rate at which each crane can transfer containers.
56    """
57
58    def __init__(self, env, id, cranes_per_berth, crane_transfer_rate):
59        self.id = id
60        self.cranes = simpy.Store(env, capacity=cranes_per_berth)
61        self.crane_transfer_rate = crane_transfer_rate
62        for i in range(cranes_per_berth):
63            self.cranes.put(
64                Crane(id=f"{id}.{i}", width="width", crane_transfer_rate=crane_transfer_rate))

Class representing a container berth with multiple cranes.

Arguments:
  • env (simpy.Environment): The simulation environment.
  • id (str): Unique identifier for the berth.
  • cranes_per_berth (int): Number of cranes in the berth.
  • crane_transfer_rate (float): Rate at which each crane can transfer containers.
class Pipeline:
67class Pipeline:
68    """Class representing a pipeline in a liquid berth.
69    Args:
70        env (simpy.Environment): The simulation environment.
71        id (str): Unique identifier for the pipeline.
72        pump_rate_per_pipeline (float): Rate at which the pipeline can pump liquid.
73    """
74
75    def __init__(self, env, id, pump_rate_per_pipeline):
76        self.env = env
77        self.id = id
78        self.pump_rate_per_pipeline = pump_rate_per_pipeline

Class representing a pipeline in a liquid berth.

Arguments:
  • env (simpy.Environment): The simulation environment.
  • id (str): Unique identifier for the pipeline.
  • pump_rate_per_pipeline (float): Rate at which the pipeline can pump liquid.
class Berth_Liq:
81class Berth_Liq:
82    """Class representing a liquid berth with multiple pipelines.
83    Args:
84        env (simpy.Environment): The simulation environment.
85        id (str): Unique identifier for the berth.
86        piplines_per_berth (int): Number of pipelines in the berth.
87        pump_rate_per_pipeline (float): Rate at which each pipeline can pump liquid.
88    """
89
90    def __init__(self, env, id, piplines_per_berth, pump_rate_per_pipeline):
91        self.id = id
92        self.pipelines = simpy.Store(env, capacity=piplines_per_berth)
93        for i in range(piplines_per_berth):
94            self.pipelines.put(Pipeline(
95                env=env, id=f"{id}.{i}", pump_rate_per_pipeline=pump_rate_per_pipeline))

Class representing a liquid berth with multiple pipelines.

Arguments:
  • env (simpy.Environment): The simulation environment.
  • id (str): Unique identifier for the berth.
  • piplines_per_berth (int): Number of pipelines in the berth.
  • pump_rate_per_pipeline (float): Rate at which each pipeline can pump liquid.
class Conveyor:
 98class Conveyor:
 99    """
100    Class representing a conveyor in a dry bulk berth.
101     Args:
102        env (simpy.Environment): The simulation environment.
103        id (str): Unique identifier for the conveyor.
104        conveyor_rate_per_conveyor (float): Rate at which the conveyor can transfer dry bulk.
105    """
106
107    def __init__(self, env, id, conveyor_rate_per_conveyor):
108        self.env = env
109        self.id = id
110        self.conveyor_rate_per_conveyor = conveyor_rate_per_conveyor

Class representing a conveyor in a dry bulk berth. Args: env (simpy.Environment): The simulation environment. id (str): Unique identifier for the conveyor. conveyor_rate_per_conveyor (float): Rate at which the conveyor can transfer dry bulk.

class Berth_DryBulk:
113class Berth_DryBulk:
114    """Class representing a dry bulk berth with multiple conveyors.
115    Args:
116        env (simpy.Environment): The simulation environment.
117        id (str): Unique identifier for the berth.
118        conveyors_per_berth (int): Number of conveyors in the berth.
119        conveyor_rate_per_conveyor (float): Rate at which each conveyor can transfer dry bulk.
120    """
121
122    def __init__(self, env, id, conveyors_per_berth, conveyor_rate_per_conveyor):
123        self.id = id
124        self.conveyors = simpy.Store(env, capacity=conveyors_per_berth)
125        for i in range(conveyors_per_berth):
126            self.conveyors.put(Conveyor(
127                env=env, id=f"{id}.{i}", conveyor_rate_per_conveyor=conveyor_rate_per_conveyor))

Class representing a dry bulk berth with multiple conveyors.

Arguments:
  • env (simpy.Environment): The simulation environment.
  • id (str): Unique identifier for the berth.
  • conveyors_per_berth (int): Number of conveyors in the berth.
  • conveyor_rate_per_conveyor (float): Rate at which each conveyor can transfer dry bulk.
def create_resources(terminal_data, run_id, terminal_data_df, num_terminals, env, seed):
130def create_resources(terminal_data, run_id, terminal_data_df, num_terminals, env, seed):
131    """
132    Create and initialize resources for the port simulation based on terminal data.
133    This function sets up yards, berths, tanks, silos, loading bays, truck gates, train loading racks,
134    and pilot/tugboat resources for each terminal type (Container, Liquid, DryBulk).
135    Args:
136        terminal_data (dict): Dictionary containing terminal data.
137        run_id (str): Unique identifier for the simulation run.
138        terminal_data_df (pd.DataFrame): DataFrame containing terminal data.
139        num_terminals (tuple): Tuple containing the number of terminals for each cargo type (Container, Liquid, DryBulk).
140        env (simpy.Environment): The simulation environment.
141        seed (int): Random seed for reproducibility.
142    Returns:
143        terminal_resouces (list): List of resources created for each terminal type. This includes yards, berths, tanks, silos, loading bays, truck gates, train loading racks, pilots, tugboats, and channel scheduler.
144    """
145    num_container_terminals, num_liquid_terminals, num_drybulk_terminals = num_terminals
146
147    #############################
148    # Container terminal resources
149    #############################
150
151    random.seed(seed)
152    # Yard
153    port_yard_container_terminals = [
154        simpy.Store(env, capacity=get_value_by_terminal(
155            terminal_data, 'Container', idx + 1, 'storage volume'))
156        for idx in range(num_container_terminals)
157    ]
158    for idx in range(num_container_terminals):
159        initial_capacity = int(prefill_yard_per * get_value_by_terminal(
160            terminal_data, 'Container', idx + 1, 'storage volume'))
161        for i in range(initial_capacity):
162            port_yard_container_terminals[idx].put(
163                Container(id=f"initial_{i}", width=0))
164
165    port_chassis_container_terminals = [
166        simpy.Store(env, capacity=get_value_by_terminal(terminal_data, 'Container', idx +
167                    1, 'truck bays/chassis'))  # Setting capacity to infinity or a large value
168        for _ in range(num_container_terminals)
169    ]
170
171    # Initialize each store with the desired number of items
172    for idx, store in enumerate(port_chassis_container_terminals):
173        init_items = get_value_by_terminal(
174            terminal_data, 'Container', idx + 1, 'truck bays/chassis')
175        for _ in range(init_items):
176            store.put(1)
177
178    # Berths
179    port_berths_container_terminals = [
180        simpy.Store(env, capacity=get_value_by_terminal(
181            terminal_data, 'Container', idx + 1, 'Berths'))
182        for idx in range(num_container_terminals)
183    ]
184
185    # Add cranes to the container berths
186    for idx, terminal in enumerate(port_berths_container_terminals):
187        num_cranes_list = get_values_by_terminal_random_sample(
188            terminal_data_df, 'Container', idx+1, 'transfer units per berth', num_samples=get_value_by_terminal(terminal_data, 'Container', idx + 1, 'Berths'), seed=seed)
189
190        for i in range(get_value_by_terminal(terminal_data, 'Container', idx + 1, 'Berths')):
191            terminal.put(Berth_Ctr(env=env, id=i, cranes_per_berth=num_cranes_list[i], crane_transfer_rate=get_value_by_terminal(
192                terminal_data, 'Container', idx + 1, 'transfer rate per unit')))
193            # print(f"Container Terminal {idx+1} Berth {i} has {num_cranes_list[i]} cranes")
194
195    #############################
196    # Liquid bulk terminal resources
197    #############################
198
199    # Tanks
200    tank_capacity = [get_value_by_terminal(
201        terminal_data, 'Liquid', idx + 1, 'storage volume') for idx in range(num_liquid_terminals)]
202    port_tanks_liquid_terminals = [simpy.Container(env, capacity=capacity, init=int(
203        prefill_tank_per*capacity)) for capacity in tank_capacity]
204
205    #  Loading bays
206    port_loading_bays_liquid_terminals = [simpy.Resource(env, capacity=get_value_by_terminal(
207        terminal_data, 'Liquid', idx + 1, 'truck bays/chassis')) for idx in range(num_liquid_terminals)]
208
209    # Berths
210    port_berth_liquid_terminals = [
211        simpy.Store(env, capacity=get_value_by_terminal(
212            terminal_data, 'Liquid', idx + 1, 'Berths'))
213        for idx in range(num_liquid_terminals)
214    ]
215
216    #  Add pipelines to the liquid berths
217    for idx, terminal in enumerate(port_berth_liquid_terminals):
218        num_pipelines_list = get_values_by_terminal_random_sample(
219            terminal_data_df, 'Liquid', idx+1, 'transfer units per berth', num_samples=get_value_by_terminal(terminal_data, 'Liquid', idx + 1, 'Berths'), seed=seed)
220        for i in range(get_value_by_terminal(terminal_data, 'Liquid', idx + 1, 'Berths')):
221            terminal.put(Berth_Liq(env=env, id=i, piplines_per_berth=num_pipelines_list[i], pump_rate_per_pipeline=get_value_by_terminal(
222                terminal_data, 'Liquid', idx + 1, 'transfer rate per unit')))
223            # print(f"Liquid Terminal {idx+1} Berth {i} has {num_pipelines_list[i]} pipelines")
224
225    #############################
226    # Dry bulk terminal resources
227    #############################
228
229    # Silos
230    silo_capacity = [get_value_by_terminal(
231        terminal_data, 'DryBulk', idx + 1, 'storage volume') for idx in range(num_drybulk_terminals)]
232    port_silos_drybulk_terminals = [simpy.Container(env, capacity=capacity, init=int(
233        prefill_silo_per*capacity)) for capacity in silo_capacity]
234
235    # Drybulk bays
236    port_drybulk_bays_drybulk_terminals = [simpy.Resource(env, capacity=get_value_by_terminal(
237        terminal_data, 'DryBulk', idx + 1, 'truck bays/chassis')) for idx in range(num_drybulk_terminals)]
238
239    # Berths
240    port_berth_drybulk_terminals = [
241        simpy.Store(env, capacity=get_value_by_terminal(
242            terminal_data, 'DryBulk', idx + 1, 'Berths'))
243        for idx in range(num_drybulk_terminals)
244    ]
245
246    # Conveyors
247    for idx, terminal in enumerate(port_berth_drybulk_terminals):
248        num_conveyors_list = get_values_by_terminal_random_sample(
249            terminal_data_df, 'DryBulk', idx+1, 'transfer units per berth', num_samples=get_value_by_terminal(terminal_data, 'DryBulk', idx + 1, 'Berths'), seed=seed)
250        for i in range(get_value_by_terminal(terminal_data, 'DryBulk', idx + 1, 'Berths')):
251            terminal.put(Berth_DryBulk(env=env, id=i, conveyors_per_berth=num_conveyors_list[i], conveyor_rate_per_conveyor=get_value_by_terminal(
252                terminal_data, 'DryBulk', idx + 1, 'transfer rate per unit')))
253            # print(f"Drybulk Terminal {idx+1} Berth {i} has {num_conveyors_list[i]} conveyors")
254
255    #############################
256    # Truck gates
257    #############################
258
259    truck_gates_ctr = [simpy.Resource(env, capacity=get_value_by_terminal(
260        terminal_data, 'Container', idx + 1, 'truck gates')) for idx in range(num_container_terminals)]
261    truck_gates_liquid = [simpy.Resource(env, capacity=get_value_by_terminal(
262        terminal_data, 'Liquid', idx + 1, 'truck gates')) for idx in range(num_liquid_terminals)]
263    truck_gates_dk = [simpy.Resource(env, capacity=get_value_by_terminal(
264        terminal_data, 'DryBulk', idx + 1, 'truck gates')) for idx in range(num_drybulk_terminals)]
265
266    #############################
267    # Train resources
268    #############################
269
270    # Loading racks (for loading operations)
271    train_loading_racks_ctr = [
272        simpy.Resource(env, capacity=get_value_by_terminal(
273            terminal_data, 'Container', idx + 1, 'train car loading bays'))
274        for idx in range(num_container_terminals)
275    ]
276    train_loading_racks_liquid = [
277        simpy.Resource(env, capacity=get_value_by_terminal(
278            terminal_data, 'Liquid', idx + 1, 'train car loading bays'))
279        for idx in range(num_liquid_terminals)
280    ]
281    train_loading_racks_dk = [
282        simpy.Resource(env, capacity=get_value_by_terminal(
283            terminal_data, 'DryBulk', idx + 1, 'train car loading bays'))
284        for idx in range(num_drybulk_terminals)
285    ]
286
287    #############################
288    # Pilot and tugboat resources
289    #############################
290
291    num_pilots_day = int(normal_random_with_limit(
292        NUM_PILOTS_DAY[0], NUM_PILOTS_DAY[1], seed))
293    num_pilots_night = int(normal_random_with_limit(
294        NUM_PILOTS_NIGHT[0], NUM_PILOTS_NIGHT[1], seed))
295    num_tugboats = int(normal_random_with_limit(
296        NUM_TUGBOATS[0], NUM_TUGBOATS[1], seed))
297
298    report_path = f".{run_id}/logs/final_report.txt"
299    with open(report_path, 'a') as f:
300        f.write(f"Num pilots in day shift: {num_pilots_day}\n")
301        f.write(f"Num pilots in night shift: {num_pilots_night}\n")
302        f.write(f"Num tugboats: {num_tugboats}\n\n")
303
304    day_pilots = simpy.Container(
305        env, init=num_pilots_day, capacity=num_pilots_day)
306    night_pilots = simpy.Container(
307        env, init=num_pilots_night, capacity=num_pilots_night)
308    tugboats = simpy.Container(env, init=num_tugboats, capacity=num_tugboats)
309
310    #############################
311    # Channel scheduler
312    #############################
313
314    # Only one ship can be scheduled at a time
315    channel_scheduer = simpy.Resource(env, capacity=1)
316
317    #############################
318    # Combines and returns all terminal resources for all cargo types
319    #############################
320
321    terminal_resouces = [port_berths_container_terminals, port_yard_container_terminals, port_berth_liquid_terminals,
322                         port_tanks_liquid_terminals, port_berth_drybulk_terminals, port_silos_drybulk_terminals,
323                         port_loading_bays_liquid_terminals, port_drybulk_bays_drybulk_terminals, port_chassis_container_terminals,
324                         truck_gates_ctr, truck_gates_liquid, truck_gates_dk, train_loading_racks_ctr, train_loading_racks_liquid,
325                         train_loading_racks_dk, day_pilots, night_pilots, tugboats, channel_scheduer]
326    return terminal_resouces

Create and initialize resources for the port simulation based on terminal data. This function sets up yards, berths, tanks, silos, loading bays, truck gates, train loading racks, and pilot/tugboat resources for each terminal type (Container, Liquid, DryBulk).

Arguments:
  • terminal_data (dict): Dictionary containing terminal data.
  • run_id (str): Unique identifier for the simulation run.
  • terminal_data_df (pd.DataFrame): DataFrame containing terminal data.
  • num_terminals (tuple): Tuple containing the number of terminals for each cargo type (Container, Liquid, DryBulk).
  • env (simpy.Environment): The simulation environment.
  • seed (int): Random seed for reproducibility.
Returns:

terminal_resouces (list): List of resources created for each terminal type. This includes yards, berths, tanks, silos, loading bays, truck gates, train loading racks, pilots, tugboats, and channel scheduler.