simulation_classes.terminal_container
Uses container terminal class objects to create container terminal processes. Vessel arrivals, berth and crane allocation, container unloading, container loading, vessel waiting, and vessel departure are simulated.
1""" 2Uses container terminal class objects to create container terminal processes. 3Vessel arrivals, berth and crane allocation, container unloading, container loading, vessel waiting, and vessel departure are simulated. 4""" 5import constants 6from simulation_analysis.results import update_ship_logs 7from simulation_handler.helpers import get_value_by_terminal, is_daytime 8 9TIME_COMMON_CHANNEL = constants.TIME_COMMON_CHANNEL 10TIME_FOR_TUG_STEER = constants.TIME_FOR_TUG_STEER 11TIME_FOR_UTURN = constants.TIME_FOR_UTURN 12CONTAINER_TERMINAL_EFFICIENCY = constants.CTR_TERMINAL_EFFICIENCY 13 14nan = float('nan') 15 16 17class ContainerTerminal: 18 """ 19 Class to simulate the container terminal and the processes of arriving ships. 20 This class handles the docking, unloading, loading, waiting, and departure of container ships. 21 It also manages the allocation of berths and cranes, and the interaction with the channel for ship movements. 22 The processes include the following steps: 23 1. Ship arrival at the port. 24 2. Anchorage waiting. 25 3. Berth allocation. 26 4. Channel process (inbound). 27 5. Docking the ship to a berth. 28 6. Unloading containers from the ship. 29 7. Loading containers onto the ship. 30 8. Waiting at the port after unloading and loading operations. 31 9. Detaching from the berth and departing from the port. 32 10. Channel process (outbound). 33 11. Ship departure from the port. 34 The class also logs events and ship activities throughout the process. 35 36 Args: 37 env (simpy.Environment): The simulation environment 38 chassis_bays_utilization (float): Utilization of chassis bays 39 run_id (int): Unique identifier for the simulation run 40 channel (Channel): The channel object for managing ship movements 41 day_pilots (simpy.Container): Simpy container for day pilots available 42 night_pilots (simpy.Container) : Simpy container for night pilots available 43 tugboats (simpy.Container): Simpy container for tugboats available 44 ship_info (dict): Information about the ships 45 last_section (str): The last section of the channel 46 selected_terminal (str): The terminal selected for the ship 47 id (int): Unique identifier for the ship 48 ship_type (str): Type of the ship (e.g., Container, Liquid, DryBulk) 49 draft (float): Draft of the ship 50 width (float): Width of the ship 51 unload_time_per_container (float): Time taken to unload a container 52 load_time_per_container (float): Time taken to load a container 53 containers_to_unload (list): List of containers to be unloaded 54 containers_to_load (list): List of containers to be loaded 55 events (list): List to store events during the simulation 56 ship_logs (list): List to store logs of the ship's activities 57 port_berths (simpy.Resource): Resource representing the berths at the port 58 port_yard (simpy.Store): Store representing the port's yard for containers 59 SHIPS_IN_CHANNEL (int): Number of ships allowed in the channel 60 SHIPS_IN_ANCHORAGE (int): Number of ships allowed in the anchorage 61 terminal_data (dict): Data about the terminals, including transfer units per berth and import/export capabilities 62 """ 63 def __init__(self, env, chassis_bays_utilization, run_id, channel, day_pilots, night_pilots, tugboats, ship_info, last_section, selected_terminal, id, ship_type, draft, width, unload_time_per_container, load_time_per_container, containers_to_unload, containers_to_load, events, ship_logs, port_berths, port_yard, SHIPS_IN_CHANNEL, SHIPS_IN_ANCHORAGE, terminal_data): 64 # Initialize the environment 65 self.env = env 66 self.SHIPS_IN_CHANNEL = SHIPS_IN_CHANNEL 67 self.SHIPS_IN_ANCHORAGE = SHIPS_IN_ANCHORAGE 68 self.run_id = run_id 69 self.terminal_data = terminal_data 70 self.chassis_bays_utilization = chassis_bays_utilization 71 72 # Initialize the channel 73 self.channel = channel 74 self.ship_info = ship_info 75 self.last_section = last_section 76 77 # day_pilots, night_pilots and tugboats 78 self.day_pilots, self.night_pilots = day_pilots, night_pilots 79 self.tugboats = tugboats 80 81 # Attributes of ship 82 self.id = id 83 self.selected_terminal = selected_terminal 84 self.ship_type = ship_type 85 self.num_cranes = get_value_by_terminal( 86 self.terminal_data, 'Container', selected_terminal, 'transfer units per berth') 87 self.containers_to_unload = containers_to_unload 88 self.containers_to_load = containers_to_load 89 self.draft = draft 90 self.width = width 91 self.day = None 92 93 # Attributes of container terminal 94 self.unload_time = unload_time_per_container 95 self.load_time = load_time_per_container 96 self.time_for_uturn_min, self.time_for_uturn_max = TIME_FOR_UTURN 97 98 # proxy for wait time 99 self.cargo_wait_time = 0 100 101 # The allocation of cranes and berth will be done during the process 102 self.current_berth = None 103 self.allocated_cranes = [] 104 105 # Get the ship logs and events 106 self.events = events 107 self.ship_logs = ship_logs 108 109 # Allocate berth and cranes (note that cranes are part of berths) 110 self.port_berths = port_berths 111 self.port_yard = port_yard 112 113 # Start the process 114 self.env.process(self.process()) 115 116 def process(self): 117 """ 118 Process for the container terminal, simulating the arrival, unloading, loading, waiting, and departure of ships. 119 """ 120 121 self.ship_logs = update_ship_logs(self.ship_logs, "C", self.id, self.selected_terminal, ship_start_time=nan, time_to_get_berth=nan, time_for_restriction_in=nan, time_to_get_pilot_in=nan, 122 time_to_get_tugs_in=nan, time_to_common_channel_in=nan, time_to_travel_channel_in=nan, time_to_tug_steer_in=nan, unloading_time=nan, loading_time=nan, waiting_time=nan, 123 departure_time=nan, time_to_get_pilot_out=nan, time_to_get_tugs_out=nan, time_to_tug_steer_out=nan, time_for_uturn=nan, 124 time_to_travel_channel_out=nan, time_to_common_channel_out=nan, ship_end_time=nan) 125 126 # ship arrival 127 ship_start_time = self.env.now 128 update_ship_logs(self.ship_logs, "C", self.id, 129 self.selected_terminal, ship_start_time=ship_start_time) 130 self.events.append((f"Ship_{self.id}", "Container", f"L.{self.selected_terminal}", 131 "arrive", self.env.now, f"Ship {self.id} arrived at the port")) 132 133 # Anchorage waiting 134 yield self.env.timeout(constants.ANCHORAGE_WAITING_CONTAINER) 135 136 # Berth allocation 137 start_time = self.env.now 138 yield self.env.process(self.dock()) 139 time_to_get_berth = self.env.now - ship_start_time 140 update_ship_logs(self.ship_logs, "C", self.id, 141 self.selected_terminal, time_to_get_berth=time_to_get_berth) 142 143 # check day or night 144 self.day = is_daytime(self.env.now, 7, 19) 145 146 # Channel process (in) 147 yield self.env.process(self.channel.channel_process(self.ship_info, self.day, self.last_section, self.id, self.selected_terminal, "C", self.run_id)) 148 149 # Terminal process 150 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", "dock", self.env.now, 151 f"Ship {self.id} docked to berth {self.current_berth.id} with waiting time {'N/A'}")) 152 153 start_time = self.env.now 154 yield self.env.process(self.unload()) 155 unloading_time = self.env.now - start_time 156 update_ship_logs(self.ship_logs, "C", self.id, 157 self.selected_terminal, unloading_time=unloading_time) 158 159 start_time = self.env.now 160 yield self.env.process(self.load()) 161 loading_time = self.env.now - start_time 162 update_ship_logs(self.ship_logs, "C", self.id, 163 self.selected_terminal, loading_time=loading_time) 164 165 start_time = self.env.now 166 yield self.env.process(self.wait()) 167 waiting_time = self.env.now - start_time 168 update_ship_logs(self.ship_logs, "C", self.id, 169 self.selected_terminal, waiting_time=waiting_time) 170 171 start_time = self.env.now 172 yield self.env.process(self.detach_and_depart()) 173 departure_time = self.env.now - start_time 174 update_ship_logs(self.ship_logs, "C", self.id, 175 self.selected_terminal, departure_time=departure_time) 176 177 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", "undock", self.env.now, 178 f"Ship {self.id} undocked to berth {self.current_berth.id} with waiting time {'N/A'}")) 179 180 # Channel process (out) 181 self.day = is_daytime(self.env.now, 7, 19) 182 yield self.env.process(self.channel.channel_process(self.ship_info, self.day, self.last_section, self.id, self.selected_terminal, "C", self.run_id)) 183 184 ship_end_time = self.env.now 185 update_ship_logs(self.ship_logs, "C", self.id, 186 self.selected_terminal, ship_end_time=ship_end_time) 187 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", "depart", self.env.now, 188 f"Ship {self.id} departed from berth {self.current_berth.id} with waiting time {'N/A'}")) 189 190 def dock(self): 191 """ 192 Represents the process of docking the ship to a berth and allocating cranes. 193 This includes waiting for a berth to become available and then getting the cranes allocated. 194 """ 195 self.current_berth = yield self.port_berths.get() 196 197 def unload(self): 198 """ 199 Represents the unloading of containers from the vessel at the input crane movement rate. 200 This includes requesting cranes, unloading containers, and storing them in the port yard. 201 """ 202 import_terminal = get_value_by_terminal( 203 self.terminal_data, 'Container', self.selected_terminal, 'import') 204 if import_terminal: 205 # Request for the required number of cranes 206 for _ in range(self.num_cranes): 207 crane = yield self.current_berth.cranes.get() 208 self.allocated_cranes.append(crane) 209 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 210 "all_cranes_attached", self.env.now, f"Ship {self.id} cranes allocated")) 211 # Unload containers 212 for container in self.containers_to_unload: 213 unload_time_per_container = self.unload_time 214 self.cargo_wait_time += unload_time_per_container / self.num_cranes 215 yield self.env.timeout(unload_time_per_container / self.num_cranes) 216 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 217 "all_container_unloaded", self.env.now, f"Ship {self.id} unloaded all containers")) 218 # Put containers in yard 219 for container in self.containers_to_unload: 220 yield self.port_yard.put(container) 221 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 222 "all_container_stored", self.env.now, f"Ship {self.id} unloaded all containers")) 223 else: 224 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 225 "all_cranes_attached", self.env.now, f"Ship {self.id} cranes allocated")) 226 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 227 "all_container_unloaded", self.env.now, f"Ship {self.id} unloaded all containers")) 228 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 229 "all_container_stored", self.env.now, f"Ship {self.id} unloaded all containers")) 230 231 def load(self): 232 """ 233 Represents the loading of containers onto the vessel at the input crane movement rate. 234 This includes checking if the terminal can export containers, loading them onto the vessel, and removing them from the yard. 235 """ 236 export_terminal = get_value_by_terminal( 237 self.terminal_data, 'Container', self.selected_terminal, 'export') 238 # Load containers 239 if export_terminal: 240 for container in self.containers_to_load: 241 # Remove the container from the yard 242 yield self.port_yard.get() 243 # Load the containers onto the vessel 244 load_time_per_container = self.load_time 245 self.cargo_wait_time += load_time_per_container / self.num_cranes 246 yield self.env.timeout(load_time_per_container / self.num_cranes) 247 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 248 "all_container_loaded", self.env.now, f"Ship {self.id} loaded all containers")) 249 else: 250 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 251 "all_container_loaded", self.env.now, f"Ship {self.id} loaded all containers")) 252 253 def wait(self): 254 """ 255 Represents the waiting time at the port after unloading and loading operations. 256 This includes calculating the waiting time based on the terminal efficiency and cargo wait time. 257 """ 258 # Calculate the waiting time based on the terminal efficiency and cargo wait time 259 port_waiting_time = (1 / CONTAINER_TERMINAL_EFFICIENCY) * \ 260 self.cargo_wait_time - self.cargo_wait_time 261 yield self.env.timeout(port_waiting_time) 262 263 def detach_and_depart(self): 264 """ 265 Represents the process of detaching from the berth and departing from the port. 266 This includes returning the cranes to the berth and releasing the berth for other ships. 267 """ 268 # Return the cranes to the berth 269 for crane in self.allocated_cranes: 270 yield self.current_berth.cranes.put(crane) 271 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 272 "all_cranes_returned", self.env.now, f"Ship {self.id} returned all cranes")) 273 274 # Depart from the berth 275 yield self.port_berths.put(self.current_berth)
18class ContainerTerminal: 19 """ 20 Class to simulate the container terminal and the processes of arriving ships. 21 This class handles the docking, unloading, loading, waiting, and departure of container ships. 22 It also manages the allocation of berths and cranes, and the interaction with the channel for ship movements. 23 The processes include the following steps: 24 1. Ship arrival at the port. 25 2. Anchorage waiting. 26 3. Berth allocation. 27 4. Channel process (inbound). 28 5. Docking the ship to a berth. 29 6. Unloading containers from the ship. 30 7. Loading containers onto the ship. 31 8. Waiting at the port after unloading and loading operations. 32 9. Detaching from the berth and departing from the port. 33 10. Channel process (outbound). 34 11. Ship departure from the port. 35 The class also logs events and ship activities throughout the process. 36 37 Args: 38 env (simpy.Environment): The simulation environment 39 chassis_bays_utilization (float): Utilization of chassis bays 40 run_id (int): Unique identifier for the simulation run 41 channel (Channel): The channel object for managing ship movements 42 day_pilots (simpy.Container): Simpy container for day pilots available 43 night_pilots (simpy.Container) : Simpy container for night pilots available 44 tugboats (simpy.Container): Simpy container for tugboats available 45 ship_info (dict): Information about the ships 46 last_section (str): The last section of the channel 47 selected_terminal (str): The terminal selected for the ship 48 id (int): Unique identifier for the ship 49 ship_type (str): Type of the ship (e.g., Container, Liquid, DryBulk) 50 draft (float): Draft of the ship 51 width (float): Width of the ship 52 unload_time_per_container (float): Time taken to unload a container 53 load_time_per_container (float): Time taken to load a container 54 containers_to_unload (list): List of containers to be unloaded 55 containers_to_load (list): List of containers to be loaded 56 events (list): List to store events during the simulation 57 ship_logs (list): List to store logs of the ship's activities 58 port_berths (simpy.Resource): Resource representing the berths at the port 59 port_yard (simpy.Store): Store representing the port's yard for containers 60 SHIPS_IN_CHANNEL (int): Number of ships allowed in the channel 61 SHIPS_IN_ANCHORAGE (int): Number of ships allowed in the anchorage 62 terminal_data (dict): Data about the terminals, including transfer units per berth and import/export capabilities 63 """ 64 def __init__(self, env, chassis_bays_utilization, run_id, channel, day_pilots, night_pilots, tugboats, ship_info, last_section, selected_terminal, id, ship_type, draft, width, unload_time_per_container, load_time_per_container, containers_to_unload, containers_to_load, events, ship_logs, port_berths, port_yard, SHIPS_IN_CHANNEL, SHIPS_IN_ANCHORAGE, terminal_data): 65 # Initialize the environment 66 self.env = env 67 self.SHIPS_IN_CHANNEL = SHIPS_IN_CHANNEL 68 self.SHIPS_IN_ANCHORAGE = SHIPS_IN_ANCHORAGE 69 self.run_id = run_id 70 self.terminal_data = terminal_data 71 self.chassis_bays_utilization = chassis_bays_utilization 72 73 # Initialize the channel 74 self.channel = channel 75 self.ship_info = ship_info 76 self.last_section = last_section 77 78 # day_pilots, night_pilots and tugboats 79 self.day_pilots, self.night_pilots = day_pilots, night_pilots 80 self.tugboats = tugboats 81 82 # Attributes of ship 83 self.id = id 84 self.selected_terminal = selected_terminal 85 self.ship_type = ship_type 86 self.num_cranes = get_value_by_terminal( 87 self.terminal_data, 'Container', selected_terminal, 'transfer units per berth') 88 self.containers_to_unload = containers_to_unload 89 self.containers_to_load = containers_to_load 90 self.draft = draft 91 self.width = width 92 self.day = None 93 94 # Attributes of container terminal 95 self.unload_time = unload_time_per_container 96 self.load_time = load_time_per_container 97 self.time_for_uturn_min, self.time_for_uturn_max = TIME_FOR_UTURN 98 99 # proxy for wait time 100 self.cargo_wait_time = 0 101 102 # The allocation of cranes and berth will be done during the process 103 self.current_berth = None 104 self.allocated_cranes = [] 105 106 # Get the ship logs and events 107 self.events = events 108 self.ship_logs = ship_logs 109 110 # Allocate berth and cranes (note that cranes are part of berths) 111 self.port_berths = port_berths 112 self.port_yard = port_yard 113 114 # Start the process 115 self.env.process(self.process()) 116 117 def process(self): 118 """ 119 Process for the container terminal, simulating the arrival, unloading, loading, waiting, and departure of ships. 120 """ 121 122 self.ship_logs = update_ship_logs(self.ship_logs, "C", self.id, self.selected_terminal, ship_start_time=nan, time_to_get_berth=nan, time_for_restriction_in=nan, time_to_get_pilot_in=nan, 123 time_to_get_tugs_in=nan, time_to_common_channel_in=nan, time_to_travel_channel_in=nan, time_to_tug_steer_in=nan, unloading_time=nan, loading_time=nan, waiting_time=nan, 124 departure_time=nan, time_to_get_pilot_out=nan, time_to_get_tugs_out=nan, time_to_tug_steer_out=nan, time_for_uturn=nan, 125 time_to_travel_channel_out=nan, time_to_common_channel_out=nan, ship_end_time=nan) 126 127 # ship arrival 128 ship_start_time = self.env.now 129 update_ship_logs(self.ship_logs, "C", self.id, 130 self.selected_terminal, ship_start_time=ship_start_time) 131 self.events.append((f"Ship_{self.id}", "Container", f"L.{self.selected_terminal}", 132 "arrive", self.env.now, f"Ship {self.id} arrived at the port")) 133 134 # Anchorage waiting 135 yield self.env.timeout(constants.ANCHORAGE_WAITING_CONTAINER) 136 137 # Berth allocation 138 start_time = self.env.now 139 yield self.env.process(self.dock()) 140 time_to_get_berth = self.env.now - ship_start_time 141 update_ship_logs(self.ship_logs, "C", self.id, 142 self.selected_terminal, time_to_get_berth=time_to_get_berth) 143 144 # check day or night 145 self.day = is_daytime(self.env.now, 7, 19) 146 147 # Channel process (in) 148 yield self.env.process(self.channel.channel_process(self.ship_info, self.day, self.last_section, self.id, self.selected_terminal, "C", self.run_id)) 149 150 # Terminal process 151 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", "dock", self.env.now, 152 f"Ship {self.id} docked to berth {self.current_berth.id} with waiting time {'N/A'}")) 153 154 start_time = self.env.now 155 yield self.env.process(self.unload()) 156 unloading_time = self.env.now - start_time 157 update_ship_logs(self.ship_logs, "C", self.id, 158 self.selected_terminal, unloading_time=unloading_time) 159 160 start_time = self.env.now 161 yield self.env.process(self.load()) 162 loading_time = self.env.now - start_time 163 update_ship_logs(self.ship_logs, "C", self.id, 164 self.selected_terminal, loading_time=loading_time) 165 166 start_time = self.env.now 167 yield self.env.process(self.wait()) 168 waiting_time = self.env.now - start_time 169 update_ship_logs(self.ship_logs, "C", self.id, 170 self.selected_terminal, waiting_time=waiting_time) 171 172 start_time = self.env.now 173 yield self.env.process(self.detach_and_depart()) 174 departure_time = self.env.now - start_time 175 update_ship_logs(self.ship_logs, "C", self.id, 176 self.selected_terminal, departure_time=departure_time) 177 178 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", "undock", self.env.now, 179 f"Ship {self.id} undocked to berth {self.current_berth.id} with waiting time {'N/A'}")) 180 181 # Channel process (out) 182 self.day = is_daytime(self.env.now, 7, 19) 183 yield self.env.process(self.channel.channel_process(self.ship_info, self.day, self.last_section, self.id, self.selected_terminal, "C", self.run_id)) 184 185 ship_end_time = self.env.now 186 update_ship_logs(self.ship_logs, "C", self.id, 187 self.selected_terminal, ship_end_time=ship_end_time) 188 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", "depart", self.env.now, 189 f"Ship {self.id} departed from berth {self.current_berth.id} with waiting time {'N/A'}")) 190 191 def dock(self): 192 """ 193 Represents the process of docking the ship to a berth and allocating cranes. 194 This includes waiting for a berth to become available and then getting the cranes allocated. 195 """ 196 self.current_berth = yield self.port_berths.get() 197 198 def unload(self): 199 """ 200 Represents the unloading of containers from the vessel at the input crane movement rate. 201 This includes requesting cranes, unloading containers, and storing them in the port yard. 202 """ 203 import_terminal = get_value_by_terminal( 204 self.terminal_data, 'Container', self.selected_terminal, 'import') 205 if import_terminal: 206 # Request for the required number of cranes 207 for _ in range(self.num_cranes): 208 crane = yield self.current_berth.cranes.get() 209 self.allocated_cranes.append(crane) 210 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 211 "all_cranes_attached", self.env.now, f"Ship {self.id} cranes allocated")) 212 # Unload containers 213 for container in self.containers_to_unload: 214 unload_time_per_container = self.unload_time 215 self.cargo_wait_time += unload_time_per_container / self.num_cranes 216 yield self.env.timeout(unload_time_per_container / self.num_cranes) 217 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 218 "all_container_unloaded", self.env.now, f"Ship {self.id} unloaded all containers")) 219 # Put containers in yard 220 for container in self.containers_to_unload: 221 yield self.port_yard.put(container) 222 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 223 "all_container_stored", self.env.now, f"Ship {self.id} unloaded all containers")) 224 else: 225 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 226 "all_cranes_attached", self.env.now, f"Ship {self.id} cranes allocated")) 227 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 228 "all_container_unloaded", self.env.now, f"Ship {self.id} unloaded all containers")) 229 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 230 "all_container_stored", self.env.now, f"Ship {self.id} unloaded all containers")) 231 232 def load(self): 233 """ 234 Represents the loading of containers onto the vessel at the input crane movement rate. 235 This includes checking if the terminal can export containers, loading them onto the vessel, and removing them from the yard. 236 """ 237 export_terminal = get_value_by_terminal( 238 self.terminal_data, 'Container', self.selected_terminal, 'export') 239 # Load containers 240 if export_terminal: 241 for container in self.containers_to_load: 242 # Remove the container from the yard 243 yield self.port_yard.get() 244 # Load the containers onto the vessel 245 load_time_per_container = self.load_time 246 self.cargo_wait_time += load_time_per_container / self.num_cranes 247 yield self.env.timeout(load_time_per_container / self.num_cranes) 248 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 249 "all_container_loaded", self.env.now, f"Ship {self.id} loaded all containers")) 250 else: 251 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 252 "all_container_loaded", self.env.now, f"Ship {self.id} loaded all containers")) 253 254 def wait(self): 255 """ 256 Represents the waiting time at the port after unloading and loading operations. 257 This includes calculating the waiting time based on the terminal efficiency and cargo wait time. 258 """ 259 # Calculate the waiting time based on the terminal efficiency and cargo wait time 260 port_waiting_time = (1 / CONTAINER_TERMINAL_EFFICIENCY) * \ 261 self.cargo_wait_time - self.cargo_wait_time 262 yield self.env.timeout(port_waiting_time) 263 264 def detach_and_depart(self): 265 """ 266 Represents the process of detaching from the berth and departing from the port. 267 This includes returning the cranes to the berth and releasing the berth for other ships. 268 """ 269 # Return the cranes to the berth 270 for crane in self.allocated_cranes: 271 yield self.current_berth.cranes.put(crane) 272 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 273 "all_cranes_returned", self.env.now, f"Ship {self.id} returned all cranes")) 274 275 # Depart from the berth 276 yield self.port_berths.put(self.current_berth)
Class to simulate the container terminal and the processes of arriving ships.
This class handles the docking, unloading, loading, waiting, and departure of container ships.
It also manages the allocation of berths and cranes, and the interaction with the channel for ship movements.
The processes include the following steps:
- Ship arrival at the port.
- Anchorage waiting.
- Berth allocation.
- Channel process (inbound).
- Docking the ship to a berth.
- Unloading containers from the ship.
- Loading containers onto the ship.
- Waiting at the port after unloading and loading operations.
- Detaching from the berth and departing from the port.
- Channel process (outbound).
- Ship departure from the port. The class also logs events and ship activities throughout the process.
Arguments:
- env (simpy.Environment): The simulation environment
- chassis_bays_utilization (float): Utilization of chassis bays
- run_id (int): Unique identifier for the simulation run
- channel (Channel): The channel object for managing ship movements
- day_pilots (simpy.Container): Simpy container for day pilots available
- night_pilots (simpy.Container) : Simpy container for night pilots available
- tugboats (simpy.Container): Simpy container for tugboats available
- ship_info (dict): Information about the ships
- last_section (str): The last section of the channel
- selected_terminal (str): The terminal selected for the ship
- id (int): Unique identifier for the ship
- ship_type (str): Type of the ship (e.g., Container, Liquid, DryBulk)
- draft (float): Draft of the ship
- width (float): Width of the ship
- unload_time_per_container (float): Time taken to unload a container
- load_time_per_container (float): Time taken to load a container
- containers_to_unload (list): List of containers to be unloaded
- containers_to_load (list): List of containers to be loaded
- events (list): List to store events during the simulation
- ship_logs (list): List to store logs of the ship's activities
- port_berths (simpy.Resource): Resource representing the berths at the port
- port_yard (simpy.Store): Store representing the port's yard for containers
- SHIPS_IN_CHANNEL (int): Number of ships allowed in the channel
- SHIPS_IN_ANCHORAGE (int): Number of ships allowed in the anchorage
- terminal_data (dict): Data about the terminals, including transfer units per berth and import/export capabilities
117 def process(self): 118 """ 119 Process for the container terminal, simulating the arrival, unloading, loading, waiting, and departure of ships. 120 """ 121 122 self.ship_logs = update_ship_logs(self.ship_logs, "C", self.id, self.selected_terminal, ship_start_time=nan, time_to_get_berth=nan, time_for_restriction_in=nan, time_to_get_pilot_in=nan, 123 time_to_get_tugs_in=nan, time_to_common_channel_in=nan, time_to_travel_channel_in=nan, time_to_tug_steer_in=nan, unloading_time=nan, loading_time=nan, waiting_time=nan, 124 departure_time=nan, time_to_get_pilot_out=nan, time_to_get_tugs_out=nan, time_to_tug_steer_out=nan, time_for_uturn=nan, 125 time_to_travel_channel_out=nan, time_to_common_channel_out=nan, ship_end_time=nan) 126 127 # ship arrival 128 ship_start_time = self.env.now 129 update_ship_logs(self.ship_logs, "C", self.id, 130 self.selected_terminal, ship_start_time=ship_start_time) 131 self.events.append((f"Ship_{self.id}", "Container", f"L.{self.selected_terminal}", 132 "arrive", self.env.now, f"Ship {self.id} arrived at the port")) 133 134 # Anchorage waiting 135 yield self.env.timeout(constants.ANCHORAGE_WAITING_CONTAINER) 136 137 # Berth allocation 138 start_time = self.env.now 139 yield self.env.process(self.dock()) 140 time_to_get_berth = self.env.now - ship_start_time 141 update_ship_logs(self.ship_logs, "C", self.id, 142 self.selected_terminal, time_to_get_berth=time_to_get_berth) 143 144 # check day or night 145 self.day = is_daytime(self.env.now, 7, 19) 146 147 # Channel process (in) 148 yield self.env.process(self.channel.channel_process(self.ship_info, self.day, self.last_section, self.id, self.selected_terminal, "C", self.run_id)) 149 150 # Terminal process 151 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", "dock", self.env.now, 152 f"Ship {self.id} docked to berth {self.current_berth.id} with waiting time {'N/A'}")) 153 154 start_time = self.env.now 155 yield self.env.process(self.unload()) 156 unloading_time = self.env.now - start_time 157 update_ship_logs(self.ship_logs, "C", self.id, 158 self.selected_terminal, unloading_time=unloading_time) 159 160 start_time = self.env.now 161 yield self.env.process(self.load()) 162 loading_time = self.env.now - start_time 163 update_ship_logs(self.ship_logs, "C", self.id, 164 self.selected_terminal, loading_time=loading_time) 165 166 start_time = self.env.now 167 yield self.env.process(self.wait()) 168 waiting_time = self.env.now - start_time 169 update_ship_logs(self.ship_logs, "C", self.id, 170 self.selected_terminal, waiting_time=waiting_time) 171 172 start_time = self.env.now 173 yield self.env.process(self.detach_and_depart()) 174 departure_time = self.env.now - start_time 175 update_ship_logs(self.ship_logs, "C", self.id, 176 self.selected_terminal, departure_time=departure_time) 177 178 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", "undock", self.env.now, 179 f"Ship {self.id} undocked to berth {self.current_berth.id} with waiting time {'N/A'}")) 180 181 # Channel process (out) 182 self.day = is_daytime(self.env.now, 7, 19) 183 yield self.env.process(self.channel.channel_process(self.ship_info, self.day, self.last_section, self.id, self.selected_terminal, "C", self.run_id)) 184 185 ship_end_time = self.env.now 186 update_ship_logs(self.ship_logs, "C", self.id, 187 self.selected_terminal, ship_end_time=ship_end_time) 188 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", "depart", self.env.now, 189 f"Ship {self.id} departed from berth {self.current_berth.id} with waiting time {'N/A'}"))
Process for the container terminal, simulating the arrival, unloading, loading, waiting, and departure of ships.
191 def dock(self): 192 """ 193 Represents the process of docking the ship to a berth and allocating cranes. 194 This includes waiting for a berth to become available and then getting the cranes allocated. 195 """ 196 self.current_berth = yield self.port_berths.get()
Represents the process of docking the ship to a berth and allocating cranes. This includes waiting for a berth to become available and then getting the cranes allocated.
198 def unload(self): 199 """ 200 Represents the unloading of containers from the vessel at the input crane movement rate. 201 This includes requesting cranes, unloading containers, and storing them in the port yard. 202 """ 203 import_terminal = get_value_by_terminal( 204 self.terminal_data, 'Container', self.selected_terminal, 'import') 205 if import_terminal: 206 # Request for the required number of cranes 207 for _ in range(self.num_cranes): 208 crane = yield self.current_berth.cranes.get() 209 self.allocated_cranes.append(crane) 210 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 211 "all_cranes_attached", self.env.now, f"Ship {self.id} cranes allocated")) 212 # Unload containers 213 for container in self.containers_to_unload: 214 unload_time_per_container = self.unload_time 215 self.cargo_wait_time += unload_time_per_container / self.num_cranes 216 yield self.env.timeout(unload_time_per_container / self.num_cranes) 217 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 218 "all_container_unloaded", self.env.now, f"Ship {self.id} unloaded all containers")) 219 # Put containers in yard 220 for container in self.containers_to_unload: 221 yield self.port_yard.put(container) 222 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 223 "all_container_stored", self.env.now, f"Ship {self.id} unloaded all containers")) 224 else: 225 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 226 "all_cranes_attached", self.env.now, f"Ship {self.id} cranes allocated")) 227 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 228 "all_container_unloaded", self.env.now, f"Ship {self.id} unloaded all containers")) 229 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 230 "all_container_stored", self.env.now, f"Ship {self.id} unloaded all containers"))
Represents the unloading of containers from the vessel at the input crane movement rate. This includes requesting cranes, unloading containers, and storing them in the port yard.
232 def load(self): 233 """ 234 Represents the loading of containers onto the vessel at the input crane movement rate. 235 This includes checking if the terminal can export containers, loading them onto the vessel, and removing them from the yard. 236 """ 237 export_terminal = get_value_by_terminal( 238 self.terminal_data, 'Container', self.selected_terminal, 'export') 239 # Load containers 240 if export_terminal: 241 for container in self.containers_to_load: 242 # Remove the container from the yard 243 yield self.port_yard.get() 244 # Load the containers onto the vessel 245 load_time_per_container = self.load_time 246 self.cargo_wait_time += load_time_per_container / self.num_cranes 247 yield self.env.timeout(load_time_per_container / self.num_cranes) 248 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 249 "all_container_loaded", self.env.now, f"Ship {self.id} loaded all containers")) 250 else: 251 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 252 "all_container_loaded", self.env.now, f"Ship {self.id} loaded all containers"))
Represents the loading of containers onto the vessel at the input crane movement rate. This includes checking if the terminal can export containers, loading them onto the vessel, and removing them from the yard.
254 def wait(self): 255 """ 256 Represents the waiting time at the port after unloading and loading operations. 257 This includes calculating the waiting time based on the terminal efficiency and cargo wait time. 258 """ 259 # Calculate the waiting time based on the terminal efficiency and cargo wait time 260 port_waiting_time = (1 / CONTAINER_TERMINAL_EFFICIENCY) * \ 261 self.cargo_wait_time - self.cargo_wait_time 262 yield self.env.timeout(port_waiting_time)
Represents the waiting time at the port after unloading and loading operations. This includes calculating the waiting time based on the terminal efficiency and cargo wait time.
264 def detach_and_depart(self): 265 """ 266 Represents the process of detaching from the berth and departing from the port. 267 This includes returning the cranes to the berth and releasing the berth for other ships. 268 """ 269 # Return the cranes to the berth 270 for crane in self.allocated_cranes: 271 yield self.current_berth.cranes.put(crane) 272 self.events.append((f"Ship_{self.id}", "Container", f"C.{self.selected_terminal}", 273 "all_cranes_returned", self.env.now, f"Ship {self.id} returned all cranes")) 274 275 # Depart from the berth 276 yield self.port_berths.put(self.current_berth)
Represents the process of detaching from the berth and departing from the port. This includes returning the cranes to the berth and releasing the berth for other ships.