-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add get_average_container_dwell_time method (#187)
* Add get_average_container_dwell_time method * Add InboundAndOutboundVehicleCapacityCalculatorService * Add AverageContainerDwellTimeCalculatorService * Remove link to http://www.instances.de/dfg/ --------- Co-authored-by: Luc Edes <[email protected]>
- Loading branch information
Showing
18 changed files
with
621 additions
and
136 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
conflowgen/application/services/average_container_dwell_time_calculator_service.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import datetime | ||
|
||
from conflowgen.api.container_length_distribution_manager import ContainerLengthDistributionManager | ||
from conflowgen.api.mode_of_transport_distribution_manager import ModeOfTransportDistributionManager | ||
from conflowgen.api.storage_requirement_distribution_manager import StorageRequirementDistributionManager | ||
from conflowgen.application.services.inbound_and_outbound_vehicle_capacity_calculator_service import \ | ||
InboundAndOutboundVehicleCapacityCalculatorService | ||
from conflowgen.domain_models.data_types.container_length import ContainerLength | ||
from conflowgen.domain_models.data_types.mode_of_transport import ModeOfTransport | ||
from conflowgen.domain_models.data_types.storage_requirement import StorageRequirement | ||
from conflowgen.domain_models.distribution_repositories.container_dwell_time_distribution_repository import \ | ||
ContainerDwellTimeDistributionRepository | ||
|
||
|
||
class AverageContainerDwellTimeCalculatorService: | ||
|
||
def get_average_container_dwell_time(self, start_date: datetime.date, end_date: datetime.date) -> float: | ||
inbound_vehicle_capacity = InboundAndOutboundVehicleCapacityCalculatorService.get_inbound_capacity_of_vehicles( | ||
start_date=start_date, | ||
end_date=end_date | ||
) | ||
mode_of_transport_distribution = ModeOfTransportDistributionManager().get_mode_of_transport_distribution() | ||
container_length_distribution = ContainerLengthDistributionManager().get_container_length_distribution() | ||
container_storage_requirement_distribution = \ | ||
StorageRequirementDistributionManager().get_storage_requirement_distribution() | ||
container_dwell_time_distribution = ContainerDwellTimeDistributionRepository(). \ | ||
get_distributions() | ||
average_container_dwell_time = 0 | ||
total_containers = 0 | ||
for delivering_vehicle_type in ModeOfTransport: | ||
for picking_up_vehicle_type in ModeOfTransport: | ||
for container_length in ContainerLength: | ||
for storage_requirement in StorageRequirement: | ||
num_containers = inbound_vehicle_capacity.containers[delivering_vehicle_type] * \ | ||
mode_of_transport_distribution[delivering_vehicle_type][ | ||
picking_up_vehicle_type] * \ | ||
container_length_distribution[container_length] * \ | ||
container_storage_requirement_distribution[container_length][ | ||
storage_requirement] | ||
total_containers += num_containers | ||
average_container_dwell_time += \ | ||
container_dwell_time_distribution[delivering_vehicle_type][picking_up_vehicle_type][ | ||
storage_requirement].average * num_containers | ||
|
||
average_container_dwell_time /= total_containers | ||
return average_container_dwell_time |
166 changes: 166 additions & 0 deletions
166
conflowgen/application/services/inbound_and_outbound_vehicle_capacity_calculator_service.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
from typing import Dict | ||
|
||
import numpy as np | ||
|
||
from conflowgen.data_summaries.data_summaries_cache import DataSummariesCache | ||
from conflowgen.descriptive_datatypes import ContainerVolumeByVehicleType | ||
from conflowgen.domain_models.data_types.mode_of_transport import ModeOfTransport | ||
from conflowgen.descriptive_datatypes import OutboundUsedAndMaximumCapacity | ||
from conflowgen.domain_models.distribution_repositories.container_length_distribution_repository import \ | ||
ContainerLengthDistributionRepository | ||
from conflowgen.domain_models.distribution_repositories.mode_of_transport_distribution_repository import \ | ||
ModeOfTransportDistributionRepository | ||
from conflowgen.domain_models.factories.fleet_factory import create_arrivals_within_time_range | ||
from conflowgen.domain_models.large_vehicle_schedule import Schedule | ||
|
||
|
||
class InboundAndOutboundVehicleCapacityCalculatorService: | ||
|
||
@staticmethod | ||
@DataSummariesCache.cache_result | ||
def get_truck_capacity_for_export_containers( | ||
inbound_capacity_of_vehicles: Dict[ModeOfTransport, float] | ||
) -> float: | ||
""" | ||
Get the capacity in TEU which is transported by truck. Currently, during the generation process each import | ||
container is picked up by one truck and for each import container, in the next step one export container is | ||
created. | ||
Thus, this method accounts for both import and export. | ||
""" | ||
truck_capacity = 0 | ||
for vehicle_type in ModeOfTransport.get_scheduled_vehicles(): | ||
number_of_containers_delivered_to_terminal_by_vehicle_type = inbound_capacity_of_vehicles[vehicle_type] | ||
mode_of_transport_distribution_of_vehicle_type = \ | ||
ModeOfTransportDistributionRepository().get_distribution()[vehicle_type] | ||
vehicle_to_truck_fraction = mode_of_transport_distribution_of_vehicle_type[ModeOfTransport.truck] | ||
number_of_containers_to_pick_up_by_truck_from_vehicle_type = \ | ||
number_of_containers_delivered_to_terminal_by_vehicle_type * vehicle_to_truck_fraction | ||
truck_capacity += number_of_containers_to_pick_up_by_truck_from_vehicle_type | ||
return truck_capacity | ||
|
||
@staticmethod | ||
@DataSummariesCache.cache_result | ||
def get_inbound_capacity_of_vehicles(start_date, end_date) -> ContainerVolumeByVehicleType: | ||
""" | ||
For the inbound capacity, first vehicles that adhere to a schedule are considered. Trucks, which are created | ||
depending on the outbound distribution, are created based on the assumptions of the further container flow | ||
generation process. | ||
""" | ||
containers: Dict[ModeOfTransport, float] = { | ||
vehicle_type: 0 | ||
for vehicle_type in ModeOfTransport | ||
} | ||
inbound_capacity_in_teu: Dict[ModeOfTransport, float] = { | ||
vehicle_type: 0 | ||
for vehicle_type in ModeOfTransport | ||
} | ||
|
||
for schedule in Schedule.select(): | ||
arrivals = create_arrivals_within_time_range( | ||
start_date, | ||
schedule.vehicle_arrives_at, | ||
end_date, | ||
schedule.vehicle_arrives_every_k_days, | ||
schedule.vehicle_arrives_at_time | ||
) | ||
total_capacity_moved_by_vessel = (len(arrivals) # number of vehicles that are planned | ||
* schedule.average_moved_capacity) # TEU capacity of each vehicle | ||
containers[schedule.vehicle_type] += total_capacity_moved_by_vessel / \ | ||
(ContainerLengthDistributionRepository.get_teu_factor() * 20) | ||
inbound_capacity_in_teu[schedule.vehicle_type] += total_capacity_moved_by_vessel | ||
|
||
inbound_capacity_in_teu[ModeOfTransport.truck] = \ | ||
InboundAndOutboundVehicleCapacityCalculatorService.get_truck_capacity_for_export_containers( | ||
inbound_capacity_in_teu | ||
) | ||
containers[ModeOfTransport.truck] = \ | ||
inbound_capacity_in_teu[ModeOfTransport.truck] / \ | ||
(ContainerLengthDistributionRepository.get_teu_factor() * 20) | ||
|
||
return ContainerVolumeByVehicleType( | ||
containers=containers, | ||
teu=inbound_capacity_in_teu | ||
) | ||
|
||
@staticmethod | ||
@DataSummariesCache.cache_result | ||
def get_outbound_capacity_of_vehicles(start_date, end_date, transportation_buffer) \ | ||
-> OutboundUsedAndMaximumCapacity: | ||
""" | ||
For the outbound capacity, both the used outbound capacity (estimated) and the maximum outbound capacity is | ||
reported. If a vehicle type reaches the maximum outbound capacity, this means that containers need to be | ||
redistributed to other vehicle types due to a lack of capacity. The capacities are only calculated in TEU, not | ||
in containers. | ||
""" | ||
outbound_used_containers: Dict[ModeOfTransport, float] = { | ||
vehicle_type: 0 | ||
for vehicle_type in ModeOfTransport | ||
} | ||
outbound_maximum_containers: Dict[ModeOfTransport, float] = { | ||
vehicle_type: 0 | ||
for vehicle_type in ModeOfTransport | ||
} | ||
outbound_used_capacity_in_teu: Dict[ModeOfTransport, float] = { | ||
vehicle_type: 0 | ||
for vehicle_type in ModeOfTransport | ||
} | ||
outbound_maximum_capacity_in_teu: Dict[ModeOfTransport, float] = { | ||
vehicle_type: 0 | ||
for vehicle_type in ModeOfTransport | ||
} | ||
|
||
schedule: Schedule | ||
for schedule in Schedule.select(): | ||
assert schedule.average_moved_capacity <= schedule.average_vehicle_capacity, \ | ||
"A vehicle cannot move a larger amount of containers (in TEU) than its capacity, " \ | ||
f"the input data is malformed. Schedule '{schedule.service_name}' of vehicle type " \ | ||
f"{schedule.vehicle_type} has an average moved capacity of {schedule.average_moved_capacity} but an " \ | ||
f"averaged vehicle capacity of {schedule.average_vehicle_capacity}." | ||
|
||
arrivals = create_arrivals_within_time_range( | ||
start_date, | ||
schedule.vehicle_arrives_at, | ||
end_date, | ||
schedule.vehicle_arrives_every_k_days, | ||
schedule.vehicle_arrives_at_time | ||
) | ||
|
||
# If all container flows are balanced, only the average moved capacity is required | ||
total_average_capacity_moved_by_vessel_in_teu = len(arrivals) * schedule.average_moved_capacity | ||
outbound_used_capacity_in_teu[schedule.vehicle_type] += total_average_capacity_moved_by_vessel_in_teu | ||
outbound_used_containers[schedule.vehicle_type] += total_average_capacity_moved_by_vessel_in_teu / \ | ||
(ContainerLengthDistributionRepository.get_teu_factor() * 20) | ||
|
||
# If there are unbalanced container flows, a vehicle departs with more containers than it delivered | ||
maximum_capacity_of_vehicle_in_teu = min( | ||
schedule.average_moved_capacity * (1 + transportation_buffer), | ||
schedule.average_vehicle_capacity | ||
) | ||
total_maximum_capacity_moved_by_vessel = len(arrivals) * maximum_capacity_of_vehicle_in_teu | ||
outbound_maximum_capacity_in_teu[schedule.vehicle_type] += total_maximum_capacity_moved_by_vessel | ||
outbound_maximum_containers[schedule.vehicle_type] += total_maximum_capacity_moved_by_vessel / \ | ||
(ContainerLengthDistributionRepository.get_teu_factor() * 20) | ||
|
||
inbound_capacity = InboundAndOutboundVehicleCapacityCalculatorService.\ | ||
get_inbound_capacity_of_vehicles(start_date, end_date) | ||
outbound_used_capacity_in_teu[ModeOfTransport.truck] = \ | ||
InboundAndOutboundVehicleCapacityCalculatorService.get_truck_capacity_for_export_containers( | ||
inbound_capacity.teu | ||
) | ||
outbound_used_containers[ModeOfTransport.truck] = \ | ||
outbound_used_capacity_in_teu[ModeOfTransport.truck] / \ | ||
(ContainerLengthDistributionRepository.get_teu_factor() * 20) | ||
|
||
outbound_maximum_capacity_in_teu[ModeOfTransport.truck] = np.nan # Trucks can always be added as required | ||
outbound_maximum_containers[ModeOfTransport.truck] = np.nan | ||
|
||
return OutboundUsedAndMaximumCapacity( | ||
used=ContainerVolumeByVehicleType( | ||
containers=outbound_used_containers, | ||
teu=outbound_used_capacity_in_teu | ||
), | ||
maximum=ContainerVolumeByVehicleType( | ||
containers=outbound_maximum_containers, | ||
teu=outbound_maximum_capacity_in_teu | ||
) | ||
) |
Oops, something went wrong.