simulation_classes.train
This module defines the Train class, which simulates the loading and unloading of cargo at a terminal. The train processes cargo in batches, either importing or exporting based on the flags provided.
1""" 2This module defines the Train class, which simulates the loading and unloading of cargo at a terminal. 3The train processes cargo in batches, either importing or exporting based on the flags provided. 4""" 5 6from simulation_classes.port import Container 7 8class Train(object): 9 """Train class to simulate the loading and unloading of cargo at a terminal. 10 Args: 11 env (simpy.Environment): Simulation environment. 12 train_id (str): Unique identifier for the train. 13 terminal_id (str): Unique identifier for the terminal. 14 car_amount (int): Number of cars in the train. 15 cargo_transfer_rate (float): Rate at which cargo is transferred (e.g., pounds per hour). 16 racks (simpy.Resource): Resource representing the unloading racks. 17 cargo_yard (simpy.Container): Container representing the cargo yard. 18 train_events (dict): Dictionary to log events related to the train. 19 transfer_amount (float): Total amount of cargo to be transferred per car. 20 import_bool (bool): Flag indicating if the train is importing cargo. 21 export_bool (bool): Flag indicating if the train is exporting cargo. 22 cargo_type (str): Type of cargo being handled ("Container" or "Bulk"). 23 """ 24 def __init__(self, env, train_id, terminal_id, car_amount, cargo_transfer_rate, racks, cargo_yard, train_events, transfer_amount, import_bool, export_bool, cargo_type): 25 self.env = env 26 self.train_id = train_id 27 self.terminal_id = terminal_id 28 self.car_amount = car_amount 29 self.cargo_transfer_rate = cargo_transfer_rate 30 self.racks = racks # simpy.Resource object for unloading 31 self.cargo_yard = cargo_yard 32 self.train_events = train_events 33 self.transfer_amount_per_car = transfer_amount / car_amount 34 self.import_bool = import_bool 35 self.export_bool = export_bool 36 self.cargo_type = cargo_type 37 self.env.process(self.process()) 38 39 def process(self): 40 """ 41 Process to handle the train's loading and unloading operations. 42 This method initializes the train's event log, waits for the train to arrive, 43 and then either imports or exports cargo based on the flags provided. 44 It also logs the time taken for each operation and the start/end times of each car. 45 """ 46 # Initialize train event log 47 self.train_events[self.train_id] = {} 48 self.train_events[self.train_id]["Batch size"] = self.racks.capacity 49 self.train_events[self.train_id]["Cargo type"] = self.cargo_type 50 self.train_events[self.train_id]["Cargo transfer rate"] = self.cargo_transfer_rate 51 self.train_events[self.train_id]["Transfer amount per car"] = self.transfer_amount_per_car 52 self.train_events[self.train_id]["Import/Export"] = "Import" if self.import_bool else "Export" 53 self.train_events[self.train_id]["Train ID"] = self.train_id 54 self.train_events[self.train_id]["Terminal ID"] = self.terminal_id 55 self.train_events[self.train_id]["Car amount"] = self.car_amount 56 self.train_events[self.train_id]["Car start/end times"] = [] 57 self.train_events[self.train_id]["Time to get racks"] = [] 58 self.train_events[self.train_id]["Train Arrival"] = self.env.now 59 60 if self.import_bool: # Import Process 61 yield self.env.process(self.import_cargo(self.car_amount)) 62 if self.export_bool: # Export Process 63 yield self.env.process(self.export_cargo(self.car_amount)) 64 65 self.train_events[self.train_id]["Train Departure"] = self.env.now 66 self.train_events[self.train_id]["Train Duration"] = self.train_events[self.train_id]["Train Departure"] - self.train_events[self.train_id]["Train Arrival"] 67 68 def import_cargo(self, empty_cars): 69 """ 70 Import cargo into the train's cars. 71 This method processes the loading of cargo into the train's cars in batches. 72 Args: 73 empty_cars (int): Number of empty cars to be loaded with cargo. 74 Yields: 75 simpy.Timeout: Waits for all cars in the batch to be loaded before proceeding. 76 Returns: 77 None 78 """ 79 cars_remaining = empty_cars 80 while cars_remaining > 0: 81 batch_size = min(cars_remaining, self.racks.capacity) 82 tasks = [self.env.process(self.load_car()) for _ in range(batch_size)] 83 yield self.env.all_of(tasks) # Wait for all cars in the batch to be loaded 84 cars_remaining -= batch_size 85 86 def export_cargo(self, full_cars): 87 """ 88 Export cargo from the train's cars. 89 This method processes the unloading of cargo from the train's cars in batches. 90 Args: 91 full_cars (int): Number of full cars to be unloaded. 92 Yields: 93 simpy.Timeout: Waits for all cars in the batch to be unloaded before proceeding. 94 Returns: 95 None 96 """ 97 cars_remaining = full_cars 98 while cars_remaining > 0: 99 batch_size = min(cars_remaining, self.racks.capacity) 100 tasks = [self.env.process(self.unload_car()) for _ in range(batch_size)] 101 yield self.env.all_of(tasks) # Wait for all cars in the batch to be unloaded 102 cars_remaining -= batch_size 103 104 def load_car(self): 105 """ 106 Load cargo into a single car of the train. 107 This method handles the loading of cargo into a car, including waiting for the racks 108 and calculating the time taken for loading. 109 Yields: 110 simpy.Timeout: Waits for the loading process to complete. 111 Returns: 112 None 113 """ 114 car_start_time = self.env.now 115 with self.racks.request() as req: 116 yield req 117 self.train_events[self.train_id]["Time to get racks"].append(self.env.now - car_start_time) 118 load_time = self.transfer_amount_per_car / self.cargo_transfer_rate # ex: (50 lbs / car) / (20 lbs/hr) = 2.5 hr / car 119 yield self.env.timeout(load_time) 120 if self.cargo_type == "Container": 121 num_containers = int(self.transfer_amount_per_car) 122 for i in range(num_containers): 123 yield self.cargo_yard.get() 124 else: 125 yield self.cargo_yard.get(self.transfer_amount_per_car) 126 car_end_time = self.env.now 127 self.train_events[self.train_id]["Car start/end times"].append((car_start_time, car_end_time)) 128 129 130 def unload_car(self): 131 """ 132 Unload cargo from a single car of the train. 133 This method handles the unloading of cargo from a car, including waiting for the racks 134 and calculating the time taken for unloading. 135 Yields: 136 simpy.Timeout: Waits for the unloading process to complete. 137 Returns: 138 None 139 """ 140 car_start_time = self.env.now 141 with self.racks.request() as req: 142 yield req 143 self.train_events[self.train_id]["Time to get racks"].append(self.env.now - car_start_time) 144 unload_time = self.transfer_amount_per_car / self.cargo_transfer_rate # ex: (50 lbs / car) / (20 lbs/hr) = 2.5 hr / car 145 yield self.env.timeout(unload_time) 146 if self.cargo_type == "Container": 147 num_containers = int(self.transfer_amount_per_car) 148 for i in range(num_containers): 149 ctr = Container(id=f"{self.train_id}_unload_{i}", width=100000) 150 yield self.cargo_yard.put(ctr) 151 else: 152 self.cargo_yard.put(self.transfer_amount_per_car) 153 car_end_time = self.env.now 154 self.train_events[self.train_id]["Car start/end times"].append((car_start_time, car_end_time)) 155 156 157 158 159 160 161 162 163 164 165 166 167 168
9class Train(object): 10 """Train class to simulate the loading and unloading of cargo at a terminal. 11 Args: 12 env (simpy.Environment): Simulation environment. 13 train_id (str): Unique identifier for the train. 14 terminal_id (str): Unique identifier for the terminal. 15 car_amount (int): Number of cars in the train. 16 cargo_transfer_rate (float): Rate at which cargo is transferred (e.g., pounds per hour). 17 racks (simpy.Resource): Resource representing the unloading racks. 18 cargo_yard (simpy.Container): Container representing the cargo yard. 19 train_events (dict): Dictionary to log events related to the train. 20 transfer_amount (float): Total amount of cargo to be transferred per car. 21 import_bool (bool): Flag indicating if the train is importing cargo. 22 export_bool (bool): Flag indicating if the train is exporting cargo. 23 cargo_type (str): Type of cargo being handled ("Container" or "Bulk"). 24 """ 25 def __init__(self, env, train_id, terminal_id, car_amount, cargo_transfer_rate, racks, cargo_yard, train_events, transfer_amount, import_bool, export_bool, cargo_type): 26 self.env = env 27 self.train_id = train_id 28 self.terminal_id = terminal_id 29 self.car_amount = car_amount 30 self.cargo_transfer_rate = cargo_transfer_rate 31 self.racks = racks # simpy.Resource object for unloading 32 self.cargo_yard = cargo_yard 33 self.train_events = train_events 34 self.transfer_amount_per_car = transfer_amount / car_amount 35 self.import_bool = import_bool 36 self.export_bool = export_bool 37 self.cargo_type = cargo_type 38 self.env.process(self.process()) 39 40 def process(self): 41 """ 42 Process to handle the train's loading and unloading operations. 43 This method initializes the train's event log, waits for the train to arrive, 44 and then either imports or exports cargo based on the flags provided. 45 It also logs the time taken for each operation and the start/end times of each car. 46 """ 47 # Initialize train event log 48 self.train_events[self.train_id] = {} 49 self.train_events[self.train_id]["Batch size"] = self.racks.capacity 50 self.train_events[self.train_id]["Cargo type"] = self.cargo_type 51 self.train_events[self.train_id]["Cargo transfer rate"] = self.cargo_transfer_rate 52 self.train_events[self.train_id]["Transfer amount per car"] = self.transfer_amount_per_car 53 self.train_events[self.train_id]["Import/Export"] = "Import" if self.import_bool else "Export" 54 self.train_events[self.train_id]["Train ID"] = self.train_id 55 self.train_events[self.train_id]["Terminal ID"] = self.terminal_id 56 self.train_events[self.train_id]["Car amount"] = self.car_amount 57 self.train_events[self.train_id]["Car start/end times"] = [] 58 self.train_events[self.train_id]["Time to get racks"] = [] 59 self.train_events[self.train_id]["Train Arrival"] = self.env.now 60 61 if self.import_bool: # Import Process 62 yield self.env.process(self.import_cargo(self.car_amount)) 63 if self.export_bool: # Export Process 64 yield self.env.process(self.export_cargo(self.car_amount)) 65 66 self.train_events[self.train_id]["Train Departure"] = self.env.now 67 self.train_events[self.train_id]["Train Duration"] = self.train_events[self.train_id]["Train Departure"] - self.train_events[self.train_id]["Train Arrival"] 68 69 def import_cargo(self, empty_cars): 70 """ 71 Import cargo into the train's cars. 72 This method processes the loading of cargo into the train's cars in batches. 73 Args: 74 empty_cars (int): Number of empty cars to be loaded with cargo. 75 Yields: 76 simpy.Timeout: Waits for all cars in the batch to be loaded before proceeding. 77 Returns: 78 None 79 """ 80 cars_remaining = empty_cars 81 while cars_remaining > 0: 82 batch_size = min(cars_remaining, self.racks.capacity) 83 tasks = [self.env.process(self.load_car()) for _ in range(batch_size)] 84 yield self.env.all_of(tasks) # Wait for all cars in the batch to be loaded 85 cars_remaining -= batch_size 86 87 def export_cargo(self, full_cars): 88 """ 89 Export cargo from the train's cars. 90 This method processes the unloading of cargo from the train's cars in batches. 91 Args: 92 full_cars (int): Number of full cars to be unloaded. 93 Yields: 94 simpy.Timeout: Waits for all cars in the batch to be unloaded before proceeding. 95 Returns: 96 None 97 """ 98 cars_remaining = full_cars 99 while cars_remaining > 0: 100 batch_size = min(cars_remaining, self.racks.capacity) 101 tasks = [self.env.process(self.unload_car()) for _ in range(batch_size)] 102 yield self.env.all_of(tasks) # Wait for all cars in the batch to be unloaded 103 cars_remaining -= batch_size 104 105 def load_car(self): 106 """ 107 Load cargo into a single car of the train. 108 This method handles the loading of cargo into a car, including waiting for the racks 109 and calculating the time taken for loading. 110 Yields: 111 simpy.Timeout: Waits for the loading process to complete. 112 Returns: 113 None 114 """ 115 car_start_time = self.env.now 116 with self.racks.request() as req: 117 yield req 118 self.train_events[self.train_id]["Time to get racks"].append(self.env.now - car_start_time) 119 load_time = self.transfer_amount_per_car / self.cargo_transfer_rate # ex: (50 lbs / car) / (20 lbs/hr) = 2.5 hr / car 120 yield self.env.timeout(load_time) 121 if self.cargo_type == "Container": 122 num_containers = int(self.transfer_amount_per_car) 123 for i in range(num_containers): 124 yield self.cargo_yard.get() 125 else: 126 yield self.cargo_yard.get(self.transfer_amount_per_car) 127 car_end_time = self.env.now 128 self.train_events[self.train_id]["Car start/end times"].append((car_start_time, car_end_time)) 129 130 131 def unload_car(self): 132 """ 133 Unload cargo from a single car of the train. 134 This method handles the unloading of cargo from a car, including waiting for the racks 135 and calculating the time taken for unloading. 136 Yields: 137 simpy.Timeout: Waits for the unloading process to complete. 138 Returns: 139 None 140 """ 141 car_start_time = self.env.now 142 with self.racks.request() as req: 143 yield req 144 self.train_events[self.train_id]["Time to get racks"].append(self.env.now - car_start_time) 145 unload_time = self.transfer_amount_per_car / self.cargo_transfer_rate # ex: (50 lbs / car) / (20 lbs/hr) = 2.5 hr / car 146 yield self.env.timeout(unload_time) 147 if self.cargo_type == "Container": 148 num_containers = int(self.transfer_amount_per_car) 149 for i in range(num_containers): 150 ctr = Container(id=f"{self.train_id}_unload_{i}", width=100000) 151 yield self.cargo_yard.put(ctr) 152 else: 153 self.cargo_yard.put(self.transfer_amount_per_car) 154 car_end_time = self.env.now 155 self.train_events[self.train_id]["Car start/end times"].append((car_start_time, car_end_time))
Train class to simulate the loading and unloading of cargo at a terminal.
Arguments:
- env (simpy.Environment): Simulation environment.
- train_id (str): Unique identifier for the train.
- terminal_id (str): Unique identifier for the terminal.
- car_amount (int): Number of cars in the train.
- cargo_transfer_rate (float): Rate at which cargo is transferred (e.g., pounds per hour).
- racks (simpy.Resource): Resource representing the unloading racks.
- cargo_yard (simpy.Container): Container representing the cargo yard.
- train_events (dict): Dictionary to log events related to the train.
- transfer_amount (float): Total amount of cargo to be transferred per car.
- import_bool (bool): Flag indicating if the train is importing cargo.
- export_bool (bool): Flag indicating if the train is exporting cargo.
- cargo_type (str): Type of cargo being handled ("Container" or "Bulk").
40 def process(self): 41 """ 42 Process to handle the train's loading and unloading operations. 43 This method initializes the train's event log, waits for the train to arrive, 44 and then either imports or exports cargo based on the flags provided. 45 It also logs the time taken for each operation and the start/end times of each car. 46 """ 47 # Initialize train event log 48 self.train_events[self.train_id] = {} 49 self.train_events[self.train_id]["Batch size"] = self.racks.capacity 50 self.train_events[self.train_id]["Cargo type"] = self.cargo_type 51 self.train_events[self.train_id]["Cargo transfer rate"] = self.cargo_transfer_rate 52 self.train_events[self.train_id]["Transfer amount per car"] = self.transfer_amount_per_car 53 self.train_events[self.train_id]["Import/Export"] = "Import" if self.import_bool else "Export" 54 self.train_events[self.train_id]["Train ID"] = self.train_id 55 self.train_events[self.train_id]["Terminal ID"] = self.terminal_id 56 self.train_events[self.train_id]["Car amount"] = self.car_amount 57 self.train_events[self.train_id]["Car start/end times"] = [] 58 self.train_events[self.train_id]["Time to get racks"] = [] 59 self.train_events[self.train_id]["Train Arrival"] = self.env.now 60 61 if self.import_bool: # Import Process 62 yield self.env.process(self.import_cargo(self.car_amount)) 63 if self.export_bool: # Export Process 64 yield self.env.process(self.export_cargo(self.car_amount)) 65 66 self.train_events[self.train_id]["Train Departure"] = self.env.now 67 self.train_events[self.train_id]["Train Duration"] = self.train_events[self.train_id]["Train Departure"] - self.train_events[self.train_id]["Train Arrival"]
Process to handle the train's loading and unloading operations. This method initializes the train's event log, waits for the train to arrive, and then either imports or exports cargo based on the flags provided. It also logs the time taken for each operation and the start/end times of each car.
69 def import_cargo(self, empty_cars): 70 """ 71 Import cargo into the train's cars. 72 This method processes the loading of cargo into the train's cars in batches. 73 Args: 74 empty_cars (int): Number of empty cars to be loaded with cargo. 75 Yields: 76 simpy.Timeout: Waits for all cars in the batch to be loaded before proceeding. 77 Returns: 78 None 79 """ 80 cars_remaining = empty_cars 81 while cars_remaining > 0: 82 batch_size = min(cars_remaining, self.racks.capacity) 83 tasks = [self.env.process(self.load_car()) for _ in range(batch_size)] 84 yield self.env.all_of(tasks) # Wait for all cars in the batch to be loaded 85 cars_remaining -= batch_size
Import cargo into the train's cars. This method processes the loading of cargo into the train's cars in batches.
Arguments:
- empty_cars (int): Number of empty cars to be loaded with cargo.
Yields:
simpy.Timeout: Waits for all cars in the batch to be loaded before proceeding.
Returns:
None
87 def export_cargo(self, full_cars): 88 """ 89 Export cargo from the train's cars. 90 This method processes the unloading of cargo from the train's cars in batches. 91 Args: 92 full_cars (int): Number of full cars to be unloaded. 93 Yields: 94 simpy.Timeout: Waits for all cars in the batch to be unloaded before proceeding. 95 Returns: 96 None 97 """ 98 cars_remaining = full_cars 99 while cars_remaining > 0: 100 batch_size = min(cars_remaining, self.racks.capacity) 101 tasks = [self.env.process(self.unload_car()) for _ in range(batch_size)] 102 yield self.env.all_of(tasks) # Wait for all cars in the batch to be unloaded 103 cars_remaining -= batch_size
Export cargo from the train's cars. This method processes the unloading of cargo from the train's cars in batches.
Arguments:
- full_cars (int): Number of full cars to be unloaded.
Yields:
simpy.Timeout: Waits for all cars in the batch to be unloaded before proceeding.
Returns:
None
105 def load_car(self): 106 """ 107 Load cargo into a single car of the train. 108 This method handles the loading of cargo into a car, including waiting for the racks 109 and calculating the time taken for loading. 110 Yields: 111 simpy.Timeout: Waits for the loading process to complete. 112 Returns: 113 None 114 """ 115 car_start_time = self.env.now 116 with self.racks.request() as req: 117 yield req 118 self.train_events[self.train_id]["Time to get racks"].append(self.env.now - car_start_time) 119 load_time = self.transfer_amount_per_car / self.cargo_transfer_rate # ex: (50 lbs / car) / (20 lbs/hr) = 2.5 hr / car 120 yield self.env.timeout(load_time) 121 if self.cargo_type == "Container": 122 num_containers = int(self.transfer_amount_per_car) 123 for i in range(num_containers): 124 yield self.cargo_yard.get() 125 else: 126 yield self.cargo_yard.get(self.transfer_amount_per_car) 127 car_end_time = self.env.now 128 self.train_events[self.train_id]["Car start/end times"].append((car_start_time, car_end_time))
Load cargo into a single car of the train. This method handles the loading of cargo into a car, including waiting for the racks and calculating the time taken for loading.
Yields:
simpy.Timeout: Waits for the loading process to complete.
Returns:
None
131 def unload_car(self): 132 """ 133 Unload cargo from a single car of the train. 134 This method handles the unloading of cargo from a car, including waiting for the racks 135 and calculating the time taken for unloading. 136 Yields: 137 simpy.Timeout: Waits for the unloading process to complete. 138 Returns: 139 None 140 """ 141 car_start_time = self.env.now 142 with self.racks.request() as req: 143 yield req 144 self.train_events[self.train_id]["Time to get racks"].append(self.env.now - car_start_time) 145 unload_time = self.transfer_amount_per_car / self.cargo_transfer_rate # ex: (50 lbs / car) / (20 lbs/hr) = 2.5 hr / car 146 yield self.env.timeout(unload_time) 147 if self.cargo_type == "Container": 148 num_containers = int(self.transfer_amount_per_car) 149 for i in range(num_containers): 150 ctr = Container(id=f"{self.train_id}_unload_{i}", width=100000) 151 yield self.cargo_yard.put(ctr) 152 else: 153 self.cargo_yard.put(self.transfer_amount_per_car) 154 car_end_time = self.env.now 155 self.train_events[self.train_id]["Car start/end times"].append((car_start_time, car_end_time))
Unload cargo from a single car of the train. This method handles the unloading of cargo from a car, including waiting for the racks and calculating the time taken for unloading.
Yields:
simpy.Timeout: Waits for the unloading process to complete.
Returns:
None