simulation_classes.truck

Creates class object for Trucks.

  1"""
  2Creates class object for Trucks.
  3"""
  4import constants
  5import random
  6from simulation_handler.helpers import get_value_by_terminal, log_line
  7from simulation_classes.pipeline import Pipeline
  8
  9# Initialize the constants from the constants file
 10TRUCK_WAITING_TIME_MIN, TRUCK_WAITING_TIME_MAX = constants.TRUCK_WAITING_TIME
 11actions = {
 12    (1, 1): "both",
 13    (1, 0): "load",
 14    (0, 1): "unload",
 15    (0, 0): None
 16}
 17
 18
 19class Truck(object):
 20    """
 21    Truck class to simulate the loading and unloading of trucks at different terminals.
 22    Args:
 23        env (simpy.Environment): Simulation environment.
 24        liq_terminals_with_pipeline_source (list): List of liquid terminals with pipeline source.
 25        liq_terminals_with_pipeline_sink (list): List of liquid terminals with pipeline sink.       
 26        chassis_bays_utilization (dict): Dictionary to track chassis bays utilization.
 27        truck_id (int): Unique identifier for the truck.
 28        run_id (int): Unique identifier for the simulation run.
 29        terminal_type (str): Type of the terminal (e.g., "Container", "Liquid", "DryBulk").
 30        terminal_id (int): Unique identifier for the terminal, starts from 1.
 31        container_amount (tuple): Amount of containers to load and unload.
 32        liquid_amount (int): Amount of liquid to load or unload.
 33        drybulk_amount (int): Amount of dry bulk to load or unload.
 34        loading_bays (simpy.Resource): Resource representing the loading bays.
 35        port_tanks (simpy.Container): Container representing the liquid storage tanks at the port.
 36        truck_chassis (simpy.Resource): Resource representing the truck chassis.
 37        port_yard (simpy.Store): Store representing the container yard at the port.
 38        port_silos (simpy.Container): Container representing the dry bulk storage silos at the port.
 39        drybulk_bays (simpy.Resource): Resource representing the dry bulk loading bays.
 40        events (list): List to store events for logging.
 41        seed (int): Random seed for reproducibility.
 42    """
 43
 44    def __init__(self, env, liq_terminals_with_pipeline_source, liq_terminals_with_pipeline_sink, chassis_bays_utilization, truck_id, run_id, terminal_type, terminal_id, container_amount, liquid_amount, drybulk_amount, loading_bays, port_tanks, truck_chassis, port_yard, port_silos, drybulk_bays, events, seed, terminal_data):
 45
 46        self.env = env
 47        self.events = events
 48        self.truck_id = truck_id
 49        self.terminal_type = terminal_type
 50        self.terminal_id = terminal_id  # starts from 1
 51        self.terminal_data = terminal_data
 52        self.run_id = run_id
 53        self.chassis_bays_utilization = chassis_bays_utilization
 54
 55        self.container_amount = container_amount
 56        self.liquid_amount = liquid_amount
 57        self.drybulk_amount = drybulk_amount
 58
 59        self.transfer_rate = get_value_by_terminal(
 60            self.terminal_data, terminal_type, terminal_id, 'truck loading/unloading rate')
 61
 62        self.loading_bays = loading_bays
 63        # port_tanks_liquid_terminals[terminal_id]
 64        self.port_tanks = port_tanks
 65
 66        self.truck_chassis = truck_chassis
 67        # port_yard_container_terminals[terminal_id]
 68        self.port_yard = port_yard
 69
 70        # port_silos_drybulk_terminals[terminal_id]
 71        self.port_silos = port_silos
 72        self.drybulk_bays = drybulk_bays
 73
 74        self.liq_terminals_with_pipeline_source = liq_terminals_with_pipeline_source
 75        self.liq_terminals_with_pipeline_sink = liq_terminals_with_pipeline_sink
 76
 77        self.env.process(self.process(seed, self.run_id))
 78
 79    def process(self, seed, run_id):
 80        """
 81        Process to handle the truck loading and unloading at the terminal.
 82        Args:
 83            seed (int): Random seed for reproducibility.
 84            run_id (int): Unique identifier for the simulation run.
 85        Yields:
 86            simpy.Process: The truck loading and unloading process.
 87        Returns:
 88            None
 89        """
 90        import_terminal = get_value_by_terminal(
 91            self.terminal_data, self.terminal_type, self.terminal_id, 'import')
 92        export_terminal = get_value_by_terminal(
 93            self.terminal_data, self.terminal_type, self.terminal_id, 'export')
 94        action = actions.get((import_terminal, export_terminal))
 95
 96        start_time = self.env.now
 97
 98        if self.terminal_type == "Container":
 99            yield self.env.process(self.container_truck(run_id=run_id, truck_id=f"C.{self.terminal_id}:{self.truck_id}", load_amount=self.container_amount[0], unload_amount=self.container_amount[1], terminal_id=1, action=action, seed=seed))
100        elif self.terminal_type == "Liquid":
101            # if action == "both":
102            #     action = random.choice(["load", "unload"]) # new
103            yield self.env.process(self.tanker_truck(truck_id=f"L.{self.terminal_id}:{self.truck_id}", amount=self.liquid_amount, terminal_id=1, action=action, seed=seed))
104        elif self.terminal_type == "DryBulk":
105            # if action == "both":
106            #     action = random.choice(["load", "unload"]) # new
107            yield self.env.process(self.drybulk_truck(truck_id=f"D.{self.terminal_id}:{self.truck_id}", amount=self.drybulk_amount, terminal_id=1, action=action, seed=seed))
108
109        dwell_time = self.env.now - start_time
110
111        # log the truck id, start time, dwell time, terminal id, terminal type
112        log_line(self.run_id, "truck_data.txt", f'truck_id: {self.truck_id}, start_time: {start_time}, dwell_time: {dwell_time}, terminal_id: {self.terminal_id}, terminal_type: {self.terminal_type}')
113
114
115    def tanker_truck(self, truck_id, amount, terminal_id, action, seed):
116        """
117        Process to handle the tanker truck loading and unloading at the liquid terminal.
118        Args:
119            truck_id (str): Unique identifier for the truck.
120            amount (int): Amount of liquid to load or unload.
121            terminal_id (int): Unique identifier for the terminal.
122            action (str): Action to perform, either "load" or "unload".
123            seed (int): Random seed for reproducibility.
124        Yields:
125            simpy.Process: The tanker truck loading and unloading process.
126        Returns:
127            None
128        """
129        random.seed(seed)
130        self.chassis_bays_utilization["Liquid"][self.terminal_id].append(
131            (self.env.now, self.loading_bays.count / self.loading_bays.capacity))
132        with self.loading_bays.request() as req:
133            yield req
134            TRUCK_WAITING_TIME = random.uniform(
135                TRUCK_WAITING_TIME_MIN, TRUCK_WAITING_TIME_MAX)
136            yield self.env.timeout(TRUCK_WAITING_TIME)
137            TRUCK_PUMP_RATE = self.transfer_rate
138
139            if action == "load":
140                yield self.port_tanks.get(amount)
141                load_time = amount / TRUCK_PUMP_RATE
142                yield self.env.timeout(load_time)
143            elif action == "unload":
144                yield self.port_tanks.put(amount)
145                unload_time = amount / TRUCK_PUMP_RATE
146                yield self.env.timeout(unload_time)
147
148        if self.port_tanks.level + amount >= 0.9 * self.port_tanks.capacity:
149            if terminal_id in self.liq_terminals_with_pipeline_sink:
150                Pipeline(self.run_id, self.env, self.port_tanks,
151                         mode='sink', rate=constants.PIPELINE_RATE)
152                with open(f'.{self.run_id}/logs/force_action.txt', 'a') as f:
153                    f.write(
154                        f"Pipeline from source sink activated {self.env.now}")
155                    f.write('\n')
156
157        if self.port_tanks.level - amount <= 0.1 * self.port_tanks.capacity:
158            if terminal_id in self.liq_terminals_with_pipeline_source:
159                Pipeline(self.run_id, self.env, self.port_tanks,
160                         mode='source', rate=constants.PIPELINE_RATE)
161                with open(f'.{self.run_id}/logs/force_action.txt', 'a') as f:
162                    f.write(
163                        f"Pipeline from source source activated {self.env.now}")
164                    f.write('\n')
165
166    def drybulk_truck(self, truck_id, amount, terminal_id, action, seed):
167        """
168        Process to handle the dry bulk truck loading and unloading at the dry bulk terminal.    
169        Args:
170            truck_id (str): Unique identifier for the truck.
171            amount (int): Amount of dry bulk to load or unload.
172            terminal_id (int): Unique identifier for the terminal.
173            action (str): Action to perform, either "load" or "unload".
174            seed (int): Random seed for reproducibility.
175        Yields:
176            simpy.Process: The dry bulk truck loading and unloading process.
177        Returns:
178            None
179        """
180        random.seed(seed)
181        self.chassis_bays_utilization["DryBulk"][self.terminal_id].append(
182            (self.env.now, self.drybulk_bays.count / self.drybulk_bays.capacity))
183        start_time = self.env.now
184        with self.drybulk_bays.request() as req:
185            yield req
186            TRUCK_WAITING_TIME = random.uniform(
187                TRUCK_WAITING_TIME_MIN, TRUCK_WAITING_TIME_MAX)
188            yield self.env.timeout(TRUCK_WAITING_TIME)
189            TRUCK_TRANSFER_RATE = self.transfer_rate
190
191            if action == "load":
192                yield self.port_silos.get(amount)
193                load_time = amount / TRUCK_TRANSFER_RATE
194                yield self.env.timeout(load_time)
195            elif action == "unload":
196                yield self.port_silos.put(amount)
197                unload_time = amount / TRUCK_TRANSFER_RATE
198                yield self.env.timeout(unload_time)
199
200    def container_truck(self, run_id, truck_id, load_amount, unload_amount, terminal_id, action, seed):
201        """
202        Process to handle the container truck loading and unloading at the container terminal.
203        Args:
204            run_id (int): Unique identifier for the simulation run.
205            truck_id (str): Unique identifier for the truck.
206            load_amount (int): Amount of containers to load.
207            unload_amount (int): Amount of containers to unload.
208            terminal_id (int): Unique identifier for the terminal.
209            action (str): Action to perform, either "load", "unload", or "both".
210            seed (int): Random seed for reproducibility.
211        Yields:
212            simpy.Process: The container truck loading and unloading process.
213        Returns:
214            None
215        """
216        random.seed(seed)
217        start_time = self.env.now
218        self.chassis_bays_utilization["Container"][self.terminal_id].append(
219            (self.env.now, len(self.truck_chassis.items) / self.truck_chassis.capacity))
220        TRUCK_WAITING_TIME = random.uniform(
221            TRUCK_WAITING_TIME_MIN, TRUCK_WAITING_TIME_MAX)
222        yield self.env.timeout(TRUCK_WAITING_TIME)
223
224        force = False
225        if constants.CTR_TRUCK_OVERRIDE:
226            if len(self.port_yard.items) <= 0.05 * self.port_yard.capacity:
227                action = "unload"
228                force = True
229                with open(f'.{run_id}/logs/force_action.txt', 'a') as f:
230                    f.write(
231                        f"Container truck force unloading at {self.env.now}")
232                    f.write('\n')
233            elif len(self.port_yard.items) >= 0.95 * self.port_yard.capacity:
234                action = "load"
235                force = True
236                with open(f'.{run_id}/logs/force_action.txt', 'a') as f:
237                    f.write(f"Container truck force loading at {self.env.now}")
238                    f.write('\n')
239        if action == "both":
240            force = False
241            action = random.choice(["load", "unload"])
242
243        if action == "load":
244            if not force:
245                yield self.truck_chassis.get()
246            for _ in range(load_amount):
247                yield self.port_yard.get()
248                load_time = 1 / self.transfer_rate
249                yield self.env.timeout(load_time)
250        if action == "unload":
251            for _ in range(unload_amount):
252                yield self.port_yard.put(1)
253                unload_time = 1 / self.transfer_rate
254                yield self.env.timeout(unload_time)
255            if not force:
256                yield self.truck_chassis.put(1)
class Truck:
 20class Truck(object):
 21    """
 22    Truck class to simulate the loading and unloading of trucks at different terminals.
 23    Args:
 24        env (simpy.Environment): Simulation environment.
 25        liq_terminals_with_pipeline_source (list): List of liquid terminals with pipeline source.
 26        liq_terminals_with_pipeline_sink (list): List of liquid terminals with pipeline sink.       
 27        chassis_bays_utilization (dict): Dictionary to track chassis bays utilization.
 28        truck_id (int): Unique identifier for the truck.
 29        run_id (int): Unique identifier for the simulation run.
 30        terminal_type (str): Type of the terminal (e.g., "Container", "Liquid", "DryBulk").
 31        terminal_id (int): Unique identifier for the terminal, starts from 1.
 32        container_amount (tuple): Amount of containers to load and unload.
 33        liquid_amount (int): Amount of liquid to load or unload.
 34        drybulk_amount (int): Amount of dry bulk to load or unload.
 35        loading_bays (simpy.Resource): Resource representing the loading bays.
 36        port_tanks (simpy.Container): Container representing the liquid storage tanks at the port.
 37        truck_chassis (simpy.Resource): Resource representing the truck chassis.
 38        port_yard (simpy.Store): Store representing the container yard at the port.
 39        port_silos (simpy.Container): Container representing the dry bulk storage silos at the port.
 40        drybulk_bays (simpy.Resource): Resource representing the dry bulk loading bays.
 41        events (list): List to store events for logging.
 42        seed (int): Random seed for reproducibility.
 43    """
 44
 45    def __init__(self, env, liq_terminals_with_pipeline_source, liq_terminals_with_pipeline_sink, chassis_bays_utilization, truck_id, run_id, terminal_type, terminal_id, container_amount, liquid_amount, drybulk_amount, loading_bays, port_tanks, truck_chassis, port_yard, port_silos, drybulk_bays, events, seed, terminal_data):
 46
 47        self.env = env
 48        self.events = events
 49        self.truck_id = truck_id
 50        self.terminal_type = terminal_type
 51        self.terminal_id = terminal_id  # starts from 1
 52        self.terminal_data = terminal_data
 53        self.run_id = run_id
 54        self.chassis_bays_utilization = chassis_bays_utilization
 55
 56        self.container_amount = container_amount
 57        self.liquid_amount = liquid_amount
 58        self.drybulk_amount = drybulk_amount
 59
 60        self.transfer_rate = get_value_by_terminal(
 61            self.terminal_data, terminal_type, terminal_id, 'truck loading/unloading rate')
 62
 63        self.loading_bays = loading_bays
 64        # port_tanks_liquid_terminals[terminal_id]
 65        self.port_tanks = port_tanks
 66
 67        self.truck_chassis = truck_chassis
 68        # port_yard_container_terminals[terminal_id]
 69        self.port_yard = port_yard
 70
 71        # port_silos_drybulk_terminals[terminal_id]
 72        self.port_silos = port_silos
 73        self.drybulk_bays = drybulk_bays
 74
 75        self.liq_terminals_with_pipeline_source = liq_terminals_with_pipeline_source
 76        self.liq_terminals_with_pipeline_sink = liq_terminals_with_pipeline_sink
 77
 78        self.env.process(self.process(seed, self.run_id))
 79
 80    def process(self, seed, run_id):
 81        """
 82        Process to handle the truck loading and unloading at the terminal.
 83        Args:
 84            seed (int): Random seed for reproducibility.
 85            run_id (int): Unique identifier for the simulation run.
 86        Yields:
 87            simpy.Process: The truck loading and unloading process.
 88        Returns:
 89            None
 90        """
 91        import_terminal = get_value_by_terminal(
 92            self.terminal_data, self.terminal_type, self.terminal_id, 'import')
 93        export_terminal = get_value_by_terminal(
 94            self.terminal_data, self.terminal_type, self.terminal_id, 'export')
 95        action = actions.get((import_terminal, export_terminal))
 96
 97        start_time = self.env.now
 98
 99        if self.terminal_type == "Container":
100            yield self.env.process(self.container_truck(run_id=run_id, truck_id=f"C.{self.terminal_id}:{self.truck_id}", load_amount=self.container_amount[0], unload_amount=self.container_amount[1], terminal_id=1, action=action, seed=seed))
101        elif self.terminal_type == "Liquid":
102            # if action == "both":
103            #     action = random.choice(["load", "unload"]) # new
104            yield self.env.process(self.tanker_truck(truck_id=f"L.{self.terminal_id}:{self.truck_id}", amount=self.liquid_amount, terminal_id=1, action=action, seed=seed))
105        elif self.terminal_type == "DryBulk":
106            # if action == "both":
107            #     action = random.choice(["load", "unload"]) # new
108            yield self.env.process(self.drybulk_truck(truck_id=f"D.{self.terminal_id}:{self.truck_id}", amount=self.drybulk_amount, terminal_id=1, action=action, seed=seed))
109
110        dwell_time = self.env.now - start_time
111
112        # log the truck id, start time, dwell time, terminal id, terminal type
113        log_line(self.run_id, "truck_data.txt", f'truck_id: {self.truck_id}, start_time: {start_time}, dwell_time: {dwell_time}, terminal_id: {self.terminal_id}, terminal_type: {self.terminal_type}')
114
115
116    def tanker_truck(self, truck_id, amount, terminal_id, action, seed):
117        """
118        Process to handle the tanker truck loading and unloading at the liquid terminal.
119        Args:
120            truck_id (str): Unique identifier for the truck.
121            amount (int): Amount of liquid to load or unload.
122            terminal_id (int): Unique identifier for the terminal.
123            action (str): Action to perform, either "load" or "unload".
124            seed (int): Random seed for reproducibility.
125        Yields:
126            simpy.Process: The tanker truck loading and unloading process.
127        Returns:
128            None
129        """
130        random.seed(seed)
131        self.chassis_bays_utilization["Liquid"][self.terminal_id].append(
132            (self.env.now, self.loading_bays.count / self.loading_bays.capacity))
133        with self.loading_bays.request() as req:
134            yield req
135            TRUCK_WAITING_TIME = random.uniform(
136                TRUCK_WAITING_TIME_MIN, TRUCK_WAITING_TIME_MAX)
137            yield self.env.timeout(TRUCK_WAITING_TIME)
138            TRUCK_PUMP_RATE = self.transfer_rate
139
140            if action == "load":
141                yield self.port_tanks.get(amount)
142                load_time = amount / TRUCK_PUMP_RATE
143                yield self.env.timeout(load_time)
144            elif action == "unload":
145                yield self.port_tanks.put(amount)
146                unload_time = amount / TRUCK_PUMP_RATE
147                yield self.env.timeout(unload_time)
148
149        if self.port_tanks.level + amount >= 0.9 * self.port_tanks.capacity:
150            if terminal_id in self.liq_terminals_with_pipeline_sink:
151                Pipeline(self.run_id, self.env, self.port_tanks,
152                         mode='sink', rate=constants.PIPELINE_RATE)
153                with open(f'.{self.run_id}/logs/force_action.txt', 'a') as f:
154                    f.write(
155                        f"Pipeline from source sink activated {self.env.now}")
156                    f.write('\n')
157
158        if self.port_tanks.level - amount <= 0.1 * self.port_tanks.capacity:
159            if terminal_id in self.liq_terminals_with_pipeline_source:
160                Pipeline(self.run_id, self.env, self.port_tanks,
161                         mode='source', rate=constants.PIPELINE_RATE)
162                with open(f'.{self.run_id}/logs/force_action.txt', 'a') as f:
163                    f.write(
164                        f"Pipeline from source source activated {self.env.now}")
165                    f.write('\n')
166
167    def drybulk_truck(self, truck_id, amount, terminal_id, action, seed):
168        """
169        Process to handle the dry bulk truck loading and unloading at the dry bulk terminal.    
170        Args:
171            truck_id (str): Unique identifier for the truck.
172            amount (int): Amount of dry bulk to load or unload.
173            terminal_id (int): Unique identifier for the terminal.
174            action (str): Action to perform, either "load" or "unload".
175            seed (int): Random seed for reproducibility.
176        Yields:
177            simpy.Process: The dry bulk truck loading and unloading process.
178        Returns:
179            None
180        """
181        random.seed(seed)
182        self.chassis_bays_utilization["DryBulk"][self.terminal_id].append(
183            (self.env.now, self.drybulk_bays.count / self.drybulk_bays.capacity))
184        start_time = self.env.now
185        with self.drybulk_bays.request() as req:
186            yield req
187            TRUCK_WAITING_TIME = random.uniform(
188                TRUCK_WAITING_TIME_MIN, TRUCK_WAITING_TIME_MAX)
189            yield self.env.timeout(TRUCK_WAITING_TIME)
190            TRUCK_TRANSFER_RATE = self.transfer_rate
191
192            if action == "load":
193                yield self.port_silos.get(amount)
194                load_time = amount / TRUCK_TRANSFER_RATE
195                yield self.env.timeout(load_time)
196            elif action == "unload":
197                yield self.port_silos.put(amount)
198                unload_time = amount / TRUCK_TRANSFER_RATE
199                yield self.env.timeout(unload_time)
200
201    def container_truck(self, run_id, truck_id, load_amount, unload_amount, terminal_id, action, seed):
202        """
203        Process to handle the container truck loading and unloading at the container terminal.
204        Args:
205            run_id (int): Unique identifier for the simulation run.
206            truck_id (str): Unique identifier for the truck.
207            load_amount (int): Amount of containers to load.
208            unload_amount (int): Amount of containers to unload.
209            terminal_id (int): Unique identifier for the terminal.
210            action (str): Action to perform, either "load", "unload", or "both".
211            seed (int): Random seed for reproducibility.
212        Yields:
213            simpy.Process: The container truck loading and unloading process.
214        Returns:
215            None
216        """
217        random.seed(seed)
218        start_time = self.env.now
219        self.chassis_bays_utilization["Container"][self.terminal_id].append(
220            (self.env.now, len(self.truck_chassis.items) / self.truck_chassis.capacity))
221        TRUCK_WAITING_TIME = random.uniform(
222            TRUCK_WAITING_TIME_MIN, TRUCK_WAITING_TIME_MAX)
223        yield self.env.timeout(TRUCK_WAITING_TIME)
224
225        force = False
226        if constants.CTR_TRUCK_OVERRIDE:
227            if len(self.port_yard.items) <= 0.05 * self.port_yard.capacity:
228                action = "unload"
229                force = True
230                with open(f'.{run_id}/logs/force_action.txt', 'a') as f:
231                    f.write(
232                        f"Container truck force unloading at {self.env.now}")
233                    f.write('\n')
234            elif len(self.port_yard.items) >= 0.95 * self.port_yard.capacity:
235                action = "load"
236                force = True
237                with open(f'.{run_id}/logs/force_action.txt', 'a') as f:
238                    f.write(f"Container truck force loading at {self.env.now}")
239                    f.write('\n')
240        if action == "both":
241            force = False
242            action = random.choice(["load", "unload"])
243
244        if action == "load":
245            if not force:
246                yield self.truck_chassis.get()
247            for _ in range(load_amount):
248                yield self.port_yard.get()
249                load_time = 1 / self.transfer_rate
250                yield self.env.timeout(load_time)
251        if action == "unload":
252            for _ in range(unload_amount):
253                yield self.port_yard.put(1)
254                unload_time = 1 / self.transfer_rate
255                yield self.env.timeout(unload_time)
256            if not force:
257                yield self.truck_chassis.put(1)

Truck class to simulate the loading and unloading of trucks at different terminals.

Arguments:
  • env (simpy.Environment): Simulation environment.
  • liq_terminals_with_pipeline_source (list): List of liquid terminals with pipeline source.
  • liq_terminals_with_pipeline_sink (list): List of liquid terminals with pipeline sink.
  • chassis_bays_utilization (dict): Dictionary to track chassis bays utilization.
  • truck_id (int): Unique identifier for the truck.
  • run_id (int): Unique identifier for the simulation run.
  • terminal_type (str): Type of the terminal (e.g., "Container", "Liquid", "DryBulk").
  • terminal_id (int): Unique identifier for the terminal, starts from 1.
  • container_amount (tuple): Amount of containers to load and unload.
  • liquid_amount (int): Amount of liquid to load or unload.
  • drybulk_amount (int): Amount of dry bulk to load or unload.
  • loading_bays (simpy.Resource): Resource representing the loading bays.
  • port_tanks (simpy.Container): Container representing the liquid storage tanks at the port.
  • truck_chassis (simpy.Resource): Resource representing the truck chassis.
  • port_yard (simpy.Store): Store representing the container yard at the port.
  • port_silos (simpy.Container): Container representing the dry bulk storage silos at the port.
  • drybulk_bays (simpy.Resource): Resource representing the dry bulk loading bays.
  • events (list): List to store events for logging.
  • seed (int): Random seed for reproducibility.
def process(self, seed, run_id):
 80    def process(self, seed, run_id):
 81        """
 82        Process to handle the truck loading and unloading at the terminal.
 83        Args:
 84            seed (int): Random seed for reproducibility.
 85            run_id (int): Unique identifier for the simulation run.
 86        Yields:
 87            simpy.Process: The truck loading and unloading process.
 88        Returns:
 89            None
 90        """
 91        import_terminal = get_value_by_terminal(
 92            self.terminal_data, self.terminal_type, self.terminal_id, 'import')
 93        export_terminal = get_value_by_terminal(
 94            self.terminal_data, self.terminal_type, self.terminal_id, 'export')
 95        action = actions.get((import_terminal, export_terminal))
 96
 97        start_time = self.env.now
 98
 99        if self.terminal_type == "Container":
100            yield self.env.process(self.container_truck(run_id=run_id, truck_id=f"C.{self.terminal_id}:{self.truck_id}", load_amount=self.container_amount[0], unload_amount=self.container_amount[1], terminal_id=1, action=action, seed=seed))
101        elif self.terminal_type == "Liquid":
102            # if action == "both":
103            #     action = random.choice(["load", "unload"]) # new
104            yield self.env.process(self.tanker_truck(truck_id=f"L.{self.terminal_id}:{self.truck_id}", amount=self.liquid_amount, terminal_id=1, action=action, seed=seed))
105        elif self.terminal_type == "DryBulk":
106            # if action == "both":
107            #     action = random.choice(["load", "unload"]) # new
108            yield self.env.process(self.drybulk_truck(truck_id=f"D.{self.terminal_id}:{self.truck_id}", amount=self.drybulk_amount, terminal_id=1, action=action, seed=seed))
109
110        dwell_time = self.env.now - start_time
111
112        # log the truck id, start time, dwell time, terminal id, terminal type
113        log_line(self.run_id, "truck_data.txt", f'truck_id: {self.truck_id}, start_time: {start_time}, dwell_time: {dwell_time}, terminal_id: {self.terminal_id}, terminal_type: {self.terminal_type}')

Process to handle the truck loading and unloading at the terminal.

Arguments:
  • seed (int): Random seed for reproducibility.
  • run_id (int): Unique identifier for the simulation run.
Yields:

simpy.Process: The truck loading and unloading process.

Returns:

None

def tanker_truck(self, truck_id, amount, terminal_id, action, seed):
116    def tanker_truck(self, truck_id, amount, terminal_id, action, seed):
117        """
118        Process to handle the tanker truck loading and unloading at the liquid terminal.
119        Args:
120            truck_id (str): Unique identifier for the truck.
121            amount (int): Amount of liquid to load or unload.
122            terminal_id (int): Unique identifier for the terminal.
123            action (str): Action to perform, either "load" or "unload".
124            seed (int): Random seed for reproducibility.
125        Yields:
126            simpy.Process: The tanker truck loading and unloading process.
127        Returns:
128            None
129        """
130        random.seed(seed)
131        self.chassis_bays_utilization["Liquid"][self.terminal_id].append(
132            (self.env.now, self.loading_bays.count / self.loading_bays.capacity))
133        with self.loading_bays.request() as req:
134            yield req
135            TRUCK_WAITING_TIME = random.uniform(
136                TRUCK_WAITING_TIME_MIN, TRUCK_WAITING_TIME_MAX)
137            yield self.env.timeout(TRUCK_WAITING_TIME)
138            TRUCK_PUMP_RATE = self.transfer_rate
139
140            if action == "load":
141                yield self.port_tanks.get(amount)
142                load_time = amount / TRUCK_PUMP_RATE
143                yield self.env.timeout(load_time)
144            elif action == "unload":
145                yield self.port_tanks.put(amount)
146                unload_time = amount / TRUCK_PUMP_RATE
147                yield self.env.timeout(unload_time)
148
149        if self.port_tanks.level + amount >= 0.9 * self.port_tanks.capacity:
150            if terminal_id in self.liq_terminals_with_pipeline_sink:
151                Pipeline(self.run_id, self.env, self.port_tanks,
152                         mode='sink', rate=constants.PIPELINE_RATE)
153                with open(f'.{self.run_id}/logs/force_action.txt', 'a') as f:
154                    f.write(
155                        f"Pipeline from source sink activated {self.env.now}")
156                    f.write('\n')
157
158        if self.port_tanks.level - amount <= 0.1 * self.port_tanks.capacity:
159            if terminal_id in self.liq_terminals_with_pipeline_source:
160                Pipeline(self.run_id, self.env, self.port_tanks,
161                         mode='source', rate=constants.PIPELINE_RATE)
162                with open(f'.{self.run_id}/logs/force_action.txt', 'a') as f:
163                    f.write(
164                        f"Pipeline from source source activated {self.env.now}")
165                    f.write('\n')

Process to handle the tanker truck loading and unloading at the liquid terminal.

Arguments:
  • truck_id (str): Unique identifier for the truck.
  • amount (int): Amount of liquid to load or unload.
  • terminal_id (int): Unique identifier for the terminal.
  • action (str): Action to perform, either "load" or "unload".
  • seed (int): Random seed for reproducibility.
Yields:

simpy.Process: The tanker truck loading and unloading process.

Returns:

None

def drybulk_truck(self, truck_id, amount, terminal_id, action, seed):
167    def drybulk_truck(self, truck_id, amount, terminal_id, action, seed):
168        """
169        Process to handle the dry bulk truck loading and unloading at the dry bulk terminal.    
170        Args:
171            truck_id (str): Unique identifier for the truck.
172            amount (int): Amount of dry bulk to load or unload.
173            terminal_id (int): Unique identifier for the terminal.
174            action (str): Action to perform, either "load" or "unload".
175            seed (int): Random seed for reproducibility.
176        Yields:
177            simpy.Process: The dry bulk truck loading and unloading process.
178        Returns:
179            None
180        """
181        random.seed(seed)
182        self.chassis_bays_utilization["DryBulk"][self.terminal_id].append(
183            (self.env.now, self.drybulk_bays.count / self.drybulk_bays.capacity))
184        start_time = self.env.now
185        with self.drybulk_bays.request() as req:
186            yield req
187            TRUCK_WAITING_TIME = random.uniform(
188                TRUCK_WAITING_TIME_MIN, TRUCK_WAITING_TIME_MAX)
189            yield self.env.timeout(TRUCK_WAITING_TIME)
190            TRUCK_TRANSFER_RATE = self.transfer_rate
191
192            if action == "load":
193                yield self.port_silos.get(amount)
194                load_time = amount / TRUCK_TRANSFER_RATE
195                yield self.env.timeout(load_time)
196            elif action == "unload":
197                yield self.port_silos.put(amount)
198                unload_time = amount / TRUCK_TRANSFER_RATE
199                yield self.env.timeout(unload_time)

Process to handle the dry bulk truck loading and unloading at the dry bulk terminal.

Arguments:
  • truck_id (str): Unique identifier for the truck.
  • amount (int): Amount of dry bulk to load or unload.
  • terminal_id (int): Unique identifier for the terminal.
  • action (str): Action to perform, either "load" or "unload".
  • seed (int): Random seed for reproducibility.
Yields:

simpy.Process: The dry bulk truck loading and unloading process.

Returns:

None

def container_truck( self, run_id, truck_id, load_amount, unload_amount, terminal_id, action, seed):
201    def container_truck(self, run_id, truck_id, load_amount, unload_amount, terminal_id, action, seed):
202        """
203        Process to handle the container truck loading and unloading at the container terminal.
204        Args:
205            run_id (int): Unique identifier for the simulation run.
206            truck_id (str): Unique identifier for the truck.
207            load_amount (int): Amount of containers to load.
208            unload_amount (int): Amount of containers to unload.
209            terminal_id (int): Unique identifier for the terminal.
210            action (str): Action to perform, either "load", "unload", or "both".
211            seed (int): Random seed for reproducibility.
212        Yields:
213            simpy.Process: The container truck loading and unloading process.
214        Returns:
215            None
216        """
217        random.seed(seed)
218        start_time = self.env.now
219        self.chassis_bays_utilization["Container"][self.terminal_id].append(
220            (self.env.now, len(self.truck_chassis.items) / self.truck_chassis.capacity))
221        TRUCK_WAITING_TIME = random.uniform(
222            TRUCK_WAITING_TIME_MIN, TRUCK_WAITING_TIME_MAX)
223        yield self.env.timeout(TRUCK_WAITING_TIME)
224
225        force = False
226        if constants.CTR_TRUCK_OVERRIDE:
227            if len(self.port_yard.items) <= 0.05 * self.port_yard.capacity:
228                action = "unload"
229                force = True
230                with open(f'.{run_id}/logs/force_action.txt', 'a') as f:
231                    f.write(
232                        f"Container truck force unloading at {self.env.now}")
233                    f.write('\n')
234            elif len(self.port_yard.items) >= 0.95 * self.port_yard.capacity:
235                action = "load"
236                force = True
237                with open(f'.{run_id}/logs/force_action.txt', 'a') as f:
238                    f.write(f"Container truck force loading at {self.env.now}")
239                    f.write('\n')
240        if action == "both":
241            force = False
242            action = random.choice(["load", "unload"])
243
244        if action == "load":
245            if not force:
246                yield self.truck_chassis.get()
247            for _ in range(load_amount):
248                yield self.port_yard.get()
249                load_time = 1 / self.transfer_rate
250                yield self.env.timeout(load_time)
251        if action == "unload":
252            for _ in range(unload_amount):
253                yield self.port_yard.put(1)
254                unload_time = 1 / self.transfer_rate
255                yield self.env.timeout(unload_time)
256            if not force:
257                yield self.truck_chassis.put(1)

Process to handle the container truck loading and unloading at the container terminal.

Arguments:
  • run_id (int): Unique identifier for the simulation run.
  • truck_id (str): Unique identifier for the truck.
  • load_amount (int): Amount of containers to load.
  • unload_amount (int): Amount of containers to unload.
  • terminal_id (int): Unique identifier for the terminal.
  • action (str): Action to perform, either "load", "unload", or "both".
  • seed (int): Random seed for reproducibility.
Yields:

simpy.Process: The container truck loading and unloading process.

Returns:

None