diff --git a/conflowgen/domain_models/data_types/container_length.py b/conflowgen/domain_models/data_types/container_length.py index 54106894..a90bbc94 100644 --- a/conflowgen/domain_models/data_types/container_length.py +++ b/conflowgen/domain_models/data_types/container_length.py @@ -20,7 +20,7 @@ class ContainerLength(enum.Enum): other = -1 # doc: Any other length usually does not fit into the standardized slots and handling processes. @classmethod - def get_factor(cls, container_length: ContainerLength) -> float: + def get_teu_factor(cls, container_length: ContainerLength) -> float: """ Each container occupies a certain amount of space when stored. This required space is measured in TEU. @@ -36,6 +36,10 @@ def get_factor(cls, container_length: ContainerLength) -> float: """ return CONTAINER_LENGTH_TO_OCCUPIED_TEU[container_length] + @classmethod + def get_maximum_teu_factor(cls) -> float: + return MAXIMUM_OCCUPIED_TEU + def __str__(self) -> str: """ The textual representation is, e.g., '20 feet' instead of '' so it is easier to @@ -79,3 +83,5 @@ def cast_element_type(cls, text: str) -> ContainerLength | None: The TEU factor for the value 'other' is chosen to be rather large because it is assumed to be difficult to find a proper storage position. """ + +MAXIMUM_OCCUPIED_TEU = max(list(CONTAINER_LENGTH_TO_OCCUPIED_TEU.values())) diff --git a/conflowgen/domain_models/distribution_repositories/container_length_distribution_repository.py b/conflowgen/domain_models/distribution_repositories/container_length_distribution_repository.py index b70d26ec..3bcd1f9f 100644 --- a/conflowgen/domain_models/distribution_repositories/container_length_distribution_repository.py +++ b/conflowgen/domain_models/distribution_repositories/container_length_distribution_repository.py @@ -63,5 +63,6 @@ def get_teu_factor(cls) -> float: container_length_weighted_average = 0.0 container_length_distribution = cls.get_distribution() for container_length, fraction in container_length_distribution.items(): - container_length_weighted_average += ContainerLength.get_factor(container_length) * fraction + container_length_weighted_average += ContainerLength.get_teu_factor(container_length) * fraction + assert 0 < container_length_weighted_average < ContainerLength.get_maximum_teu_factor() return container_length_weighted_average diff --git a/conflowgen/domain_models/factories/container_factory.py b/conflowgen/domain_models/factories/container_factory.py index 8e01e954..4b35cff2 100644 --- a/conflowgen/domain_models/factories/container_factory.py +++ b/conflowgen/domain_models/factories/container_factory.py @@ -26,7 +26,7 @@ class ContainerFactory: Creates containers according to the distributions which are either hard-coded or stored in the database. """ - ignored_capacity = ContainerLength.get_factor(ContainerLength.other) + ignored_capacity = ContainerLength.get_teu_factor(ContainerLength.other) random_seed = 1 diff --git a/conflowgen/domain_models/repositories/large_scheduled_vehicle_repository.py b/conflowgen/domain_models/repositories/large_scheduled_vehicle_repository.py index 933c1fec..05563689 100644 --- a/conflowgen/domain_models/repositories/large_scheduled_vehicle_repository.py +++ b/conflowgen/domain_models/repositories/large_scheduled_vehicle_repository.py @@ -9,7 +9,7 @@ class LargeScheduledVehicleRepository: - ignored_capacity = ContainerLength.get_factor(ContainerLength.other) + ignored_capacity = ContainerLength.get_teu_factor(ContainerLength.other) def __init__(self): self.transportation_buffer = None @@ -44,7 +44,7 @@ def block_capacity_for_inbound_journey( # calculate new free capacity free_capacity_in_teu = self.free_capacity_for_inbound_journey_buffer[vehicle] - used_capacity_in_teu = ContainerLength.get_factor(container_length=container.length) + used_capacity_in_teu = ContainerLength.get_teu_factor(container_length=container.length) new_free_capacity_in_teu = free_capacity_in_teu - used_capacity_in_teu assert new_free_capacity_in_teu >= 0, f"vehicle {vehicle} is overloaded, " \ f"free_capacity_in_teu: {free_capacity_in_teu}, " \ @@ -65,7 +65,7 @@ def block_capacity_for_outbound_journey( # calculate new free capacity free_capacity_in_teu = self.free_capacity_for_outbound_journey_buffer[vehicle] - used_capacity_in_teu = ContainerLength.get_factor(container_length=container.length) + used_capacity_in_teu = ContainerLength.get_teu_factor(container_length=container.length) new_free_capacity_in_teu = free_capacity_in_teu - used_capacity_in_teu assert new_free_capacity_in_teu >= 0, f"vehicle {vehicle} is overloaded, " \ f"free_capacity_in_teu: {free_capacity_in_teu}, " \ @@ -133,10 +133,10 @@ def _get_free_capacity_in_teu( loaded_other_containers = container_counter(vehicle, ContainerLength.other) free_capacity_in_teu = ( maximum_capacity - - loaded_20_foot_containers * ContainerLength.get_factor(ContainerLength.twenty_feet) - - loaded_40_foot_containers * ContainerLength.get_factor(ContainerLength.forty_feet) - - loaded_45_foot_containers * ContainerLength.get_factor(ContainerLength.forty_five_feet) - - loaded_other_containers * ContainerLength.get_factor(ContainerLength.other) + - loaded_20_foot_containers * ContainerLength.get_teu_factor(ContainerLength.twenty_feet) + - loaded_40_foot_containers * ContainerLength.get_teu_factor(ContainerLength.forty_feet) + - loaded_45_foot_containers * ContainerLength.get_teu_factor(ContainerLength.forty_five_feet) + - loaded_other_containers * ContainerLength.get_teu_factor(ContainerLength.other) ) vehicle_name = vehicle.large_scheduled_vehicle.vehicle_name assert free_capacity_in_teu >= 0, f"vehicle {vehicle} of type {vehicle.get_mode_of_transport()} with the " \ diff --git a/conflowgen/domain_models/repositories/schedule_repository.py b/conflowgen/domain_models/repositories/schedule_repository.py index 53b93b4e..b45382a3 100644 --- a/conflowgen/domain_models/repositories/schedule_repository.py +++ b/conflowgen/domain_models/repositories/schedule_repository.py @@ -41,7 +41,7 @@ def get_departing_vehicles( ) # Check for each of the vehicles how much it has already loaded - required_capacity_in_teu = ContainerLength.get_factor(required_capacity) + required_capacity_in_teu = ContainerLength.get_teu_factor(required_capacity) vehicles_with_sufficient_capacity = [] vehicle: Type[AbstractLargeScheduledVehicle] for vehicle in vehicles: diff --git a/conflowgen/flow_generator/allocate_space_for_containers_delivered_by_truck_service.py b/conflowgen/flow_generator/allocate_space_for_containers_delivered_by_truck_service.py index 8c4b064d..322e4dc7 100644 --- a/conflowgen/flow_generator/allocate_space_for_containers_delivered_by_truck_service.py +++ b/conflowgen/flow_generator/allocate_space_for_containers_delivered_by_truck_service.py @@ -15,7 +15,7 @@ class AllocateSpaceForContainersDeliveredByTruckService: - ignored_capacity = ContainerLength.get_factor(ContainerLength.other) + ignored_capacity = ContainerLength.get_teu_factor(ContainerLength.other) def __init__(self): self.logger = logging.getLogger("conflowgen") @@ -131,7 +131,7 @@ def allocate(self) -> None: continue # try again (possibly new vehicle type, definitely not same vehicle again) container = self.container_factory.create_container_for_delivering_truck(vehicle) - teu_total += ContainerLength.get_factor(container.length) + teu_total += ContainerLength.get_teu_factor(container.length) self.large_scheduled_vehicle_repository.block_capacity_for_outbound_journey(vehicle, container) successful_assignment += 1 break # success, no further looping to search for a suitable vehicle diff --git a/conflowgen/flow_generator/large_scheduled_vehicle_for_onward_transportation_manager.py b/conflowgen/flow_generator/large_scheduled_vehicle_for_onward_transportation_manager.py index 8a5e6888..b18b995c 100644 --- a/conflowgen/flow_generator/large_scheduled_vehicle_for_onward_transportation_manager.py +++ b/conflowgen/flow_generator/large_scheduled_vehicle_for_onward_transportation_manager.py @@ -195,7 +195,7 @@ def _draw_vehicle( vehicles_and_their_respective_free_capacity = {} for vehicle in available_vehicles: free_capacity = self.large_scheduled_vehicle_repository.get_free_capacity_for_outbound_journey(vehicle) - if free_capacity >= ContainerLength.get_factor(ContainerLength.other): + if free_capacity >= ContainerLength.get_teu_factor(ContainerLength.other): vehicles_and_their_respective_free_capacity[vehicle] = free_capacity if len(available_vehicles) == 0: diff --git a/conflowgen/flow_generator/truck_for_export_containers_manager.py b/conflowgen/flow_generator/truck_for_export_containers_manager.py index dc4d10cc..2d89aab6 100644 --- a/conflowgen/flow_generator/truck_for_export_containers_manager.py +++ b/conflowgen/flow_generator/truck_for_export_containers_manager.py @@ -144,6 +144,6 @@ def generate_trucks_for_delivering(self) -> None: ) container.delivered_by_truck = truck container.save() - teu_total += ContainerLength.get_factor(container.length) + teu_total += ContainerLength.get_teu_factor(container.length) self.logger.info(f"All {number_containers} trucks that deliver a container are created now, moving " f"{teu_total} TEU.") diff --git a/conflowgen/flow_generator/truck_for_import_containers_manager.py b/conflowgen/flow_generator/truck_for_import_containers_manager.py index ad1db089..94d2b0ca 100644 --- a/conflowgen/flow_generator/truck_for_import_containers_manager.py +++ b/conflowgen/flow_generator/truck_for_import_containers_manager.py @@ -122,6 +122,6 @@ def generate_trucks_for_picking_up(self): ) container.picked_up_by_truck = truck container.save() - teu_total += ContainerLength.get_factor(container.length) + teu_total += ContainerLength.get_teu_factor(container.length) self.logger.info(f"All {number_containers} trucks that pick up a container have been generated, moving " f"{teu_total} TEU.") diff --git a/conflowgen/tests/flow_generator/test_large_scheduled_vehicle_for_onward_transportation_manager.py b/conflowgen/tests/flow_generator/test_large_scheduled_vehicle_for_onward_transportation_manager.py index dd02630a..05bdadb4 100644 --- a/conflowgen/tests/flow_generator/test_large_scheduled_vehicle_for_onward_transportation_manager.py +++ b/conflowgen/tests/flow_generator/test_large_scheduled_vehicle_for_onward_transportation_manager.py @@ -171,7 +171,7 @@ def test_do_not_overload_feeder_with_truck_traffic(self): feeder.large_scheduled_vehicle.moved_capacity = 10 # in TEU containers = [self._create_container_for_truck(truck) for _ in range(10)] self.assertEqual(Container.select().count(), 10) - teu_generated = sum((ContainerLength.get_factor(container.length) for container in containers)) + teu_generated = sum((ContainerLength.get_teu_factor(container.length) for container in containers)) self.assertGreaterEqual(teu_generated, 10, "Generating 10 containers with each at least 1 TEU must result in a " "total TEU of more than 10 TEU") @@ -185,7 +185,7 @@ def test_do_not_overload_feeder_with_truck_traffic(self): teu_loaded = 0 for container in containers_reloaded: # pylint: disable=E1133 self.assertEqual(container.picked_up_by_large_scheduled_vehicle, feeder.large_scheduled_vehicle) - teu_loaded += ContainerLength.get_factor(container.length) + teu_loaded += ContainerLength.get_teu_factor(container.length) self.assertLessEqual(teu_loaded, 10, "Feeder must not be loaded with more than 10 TEU") def test_do_not_overload_feeder_with_train_traffic(self): @@ -200,7 +200,7 @@ def test_do_not_overload_feeder_with_train_traffic(self): feeder.save() self.assertEqual(Container.select().count(), 90) - teu_generated = sum((ContainerLength.get_factor(container.length) for container in containers)) + teu_generated = sum((ContainerLength.get_teu_factor(container.length) for container in containers)) self.assertEqual(teu_generated, 90) self.manager.choose_departing_vehicle_for_containers() @@ -213,7 +213,7 @@ def test_do_not_overload_feeder_with_train_traffic(self): teu_loaded = 0 for container in containers_reloaded: # pylint: disable=not-an-iterable self.assertEqual(container.picked_up_by_large_scheduled_vehicle, feeder.large_scheduled_vehicle) - teu_loaded += ContainerLength.get_factor(container.length) + teu_loaded += ContainerLength.get_teu_factor(container.length) self.assertLessEqual(teu_loaded, 80, "Feeder must not be loaded with more than what it can carry") def test_do_not_load_if_the_time_span_is_too_long(self): @@ -228,7 +228,7 @@ def test_do_not_load_if_the_time_span_is_too_long(self): feeder.save() self.assertEqual(Container.select().count(), 90) - teu_generated = sum((ContainerLength.get_factor(container.length) for container in containers)) + teu_generated = sum((ContainerLength.get_teu_factor(container.length) for container in containers)) self.assertEqual(teu_generated, 90) self.manager.choose_departing_vehicle_for_containers() @@ -256,7 +256,7 @@ def test_do_not_overload_feeder_with_train_traffic_of_two_vehicles(self): feeder.save() self.assertEqual(Container.select().count(), 180) - teu_generated = sum((ContainerLength.get_factor(container.length) for container in containers)) + teu_generated = sum((ContainerLength.get_teu_factor(container.length) for container in containers)) self.assertEqual(teu_generated, 180) self.manager.choose_departing_vehicle_for_containers() @@ -269,7 +269,7 @@ def test_do_not_overload_feeder_with_train_traffic_of_two_vehicles(self): teu_loaded = 0 for container in containers_reloaded: # pylint: disable=not-an-iterable self.assertEqual(container.picked_up_by_large_scheduled_vehicle, feeder.large_scheduled_vehicle) - teu_loaded += ContainerLength.get_factor(container.length) + teu_loaded += ContainerLength.get_teu_factor(container.length) self.assertLessEqual(teu_loaded, 80, "Feeder must not be loaded with more than what it can carry") def test_do_not_overload_feeder_with_train_traffic_of_two_vehicles_and_changing_container_lengths(self): @@ -293,7 +293,7 @@ def test_do_not_overload_feeder_with_train_traffic_of_two_vehicles_and_changing_ feeder.save() self.assertEqual(Container.select().count(), 180) - teu_generated = sum((ContainerLength.get_factor(container.length) for container in containers)) + teu_generated = sum((ContainerLength.get_teu_factor(container.length) for container in containers)) self.assertEqual(teu_generated, 270) self.manager.choose_departing_vehicle_for_containers() @@ -306,7 +306,7 @@ def test_do_not_overload_feeder_with_train_traffic_of_two_vehicles_and_changing_ teu_loaded = 0 for container in containers_reloaded: # pylint: disable=not-an-iterable self.assertEqual(container.picked_up_by_large_scheduled_vehicle, feeder.large_scheduled_vehicle) - teu_loaded += ContainerLength.get_factor(container.length) + teu_loaded += ContainerLength.get_teu_factor(container.length) self.assertLessEqual(teu_loaded, 80, "Feeder must not be loaded with more than what it can carry") def test_nothing_to_do(self):