Skip to content

Commit

Permalink
Add modification of the algorithm for an improved ramp-up and ramp-do…
Browse files Browse the repository at this point in the history
…wn phases (#209)

* Add flow_direction as a container property

* Modify how the onward transport assignment algorithm treats transshipment containers

* Save ConFlowGen version in SQLITE table

* Add happy path with ramp-up and ramp-down

* drop unnecessary save statements

* Modify CTA script and add 10 days of ramp-up and ramp-down

* Change API of PortCallManager and adjust demo scripts to new API

* Create VehicleCapacityManager and VehicleContainerVolumeCalculator to decrease the complexity of the LargeScheduledVehicleRepository - that one was just dealing with too many aspects at the same time!

* Keep internal files in .tools subfolder

* Fix TKinter issue in CI

* PIANC Yearbook 2023 is now published - use updated citation

* Update URL of DESTATIS

* Renamed logging to logger

---------

Co-authored-by: Shubhangi Gupta <[email protected]>
Co-authored-by: Marvin Kastner <[email protected]>
  • Loading branch information
3 people authored Aug 20, 2024
1 parent 97447c9 commit 147c40e
Show file tree
Hide file tree
Showing 109 changed files with 2,493 additions and 716 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,4 @@ examples/Python_Script/databases/
# Ignore local changes as they happen with every execution. If something changes, the commit must be forced.
conflowgen/data/tools/
docs/notebooks/data/prepared_dbs/
.tools/
File renamed without changes.
13 changes: 8 additions & 5 deletions conflowgen/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@
InboundAndOutboundVehicleCapacityAnalysis
from conflowgen.analyses.inbound_and_outbound_vehicle_capacity_analysis_report import \
InboundAndOutboundVehicleCapacityAnalysisReport
from conflowgen.analyses.inbound_to_outbound_vehicle_capacity_utilization_analysis import \
InboundToOutboundVehicleCapacityUtilizationAnalysis
from conflowgen.analyses.inbound_to_outbound_vehicle_capacity_utilization_analysis_report import \
InboundToOutboundVehicleCapacityUtilizationAnalysisReport
from conflowgen.analyses.outbound_to_inbound_vehicle_capacity_utilization_analysis import \
OutboundToInboundVehicleCapacityUtilizationAnalysis
from conflowgen.analyses.outbound_to_inbound_vehicle_capacity_utilization_analysis_report import \
OutboundToInboundVehicleCapacityUtilizationAnalysisReport
from conflowgen.analyses.container_flow_by_vehicle_type_analysis import ContainerFlowByVehicleTypeAnalysis
from conflowgen.analyses.container_flow_by_vehicle_type_analysis_report import \
ContainerFlowByVehicleTypeAnalysisReport
Expand All @@ -64,6 +64,9 @@
ContainerFlowVehicleTypeAdjustmentPerVehicleAnalysis
from conflowgen.analyses.container_flow_vehicle_type_adjustment_per_vehicle_analysis_report import \
ContainerFlowVehicleTypeAdjustmentPerVehicleAnalysisReport
from conflowgen.analyses.container_flow_by_vehicle_instance_analysis import ContainerFlowByVehicleInstanceAnalysis
from conflowgen.analyses.container_flow_by_vehicle_instance_analysis_report import (
ContainerFlowByVehicleInstanceAnalysisReport)

# Cache for analyses and previews
from conflowgen.data_summaries.data_summaries_cache import DataSummariesCache
Expand All @@ -83,7 +86,7 @@
from conflowgen.domain_models.data_types.storage_requirement import StorageRequirement

# List of functions
from conflowgen.logging.logging import setup_logger
from conflowgen.logger.logger import setup_logger
from conflowgen.analyses import run_all_analyses
from conflowgen.previews import run_all_previews

Expand Down
8 changes: 5 additions & 3 deletions conflowgen/analyses/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
ContainerFlowAdjustmentByVehicleTypeAnalysisReport
from .container_flow_adjustment_by_vehicle_type_analysis_summary_report import \
ContainerFlowAdjustmentByVehicleTypeAnalysisSummaryReport
from .container_flow_by_vehicle_instance_analysis_report import ContainerFlowByVehicleInstanceAnalysisReport
from .container_flow_by_vehicle_type_analysis_report import ContainerFlowByVehicleTypeAnalysisReport
from .container_flow_vehicle_type_adjustment_per_vehicle_analysis_report import \
ContainerFlowVehicleTypeAdjustmentPerVehicleAnalysisReport
from .inbound_and_outbound_vehicle_capacity_analysis_report import InboundAndOutboundVehicleCapacityAnalysisReport
from .inbound_to_outbound_vehicle_capacity_utilization_analysis_report import \
InboundToOutboundVehicleCapacityUtilizationAnalysisReport
from .outbound_to_inbound_vehicle_capacity_utilization_analysis_report import \
OutboundToInboundVehicleCapacityUtilizationAnalysisReport
from .modal_split_analysis_report import ModalSplitAnalysisReport
from .quay_side_throughput_analysis_report import QuaySideThroughputAnalysisReport
from .truck_gate_throughput_analysis_report import TruckGateThroughputAnalysisReport
Expand All @@ -26,6 +27,7 @@
reports: typing.Iterable[typing.Type[AbstractReport]] = [
InboundAndOutboundVehicleCapacityAnalysisReport,
ContainerFlowByVehicleTypeAnalysisReport,
ContainerFlowByVehicleInstanceAnalysisReport,
ContainerFlowAdjustmentByVehicleTypeAnalysisReport,
ContainerFlowAdjustmentByVehicleTypeAnalysisSummaryReport,
ContainerFlowVehicleTypeAdjustmentPerVehicleAnalysisReport,
Expand All @@ -34,7 +36,7 @@
QuaySideThroughputAnalysisReport,
TruckGateThroughputAnalysisReport,
YardCapacityAnalysisReport,
InboundToOutboundVehicleCapacityUtilizationAnalysisReport
OutboundToInboundVehicleCapacityUtilizationAnalysisReport
]


Expand Down
14 changes: 9 additions & 5 deletions conflowgen/analyses/abstract_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,35 +98,39 @@ def _restrict_storage_requirement(selected_containers: ModelSelect, storage_requ
@staticmethod
def _restrict_container_delivered_by_vehicle_type(
selected_containers: ModelSelect, container_delivered_by_vehicle_type: typing.Any
) -> ModelSelect:
) -> (ModelSelect, list[ModeOfTransport]):
if hashable(container_delivered_by_vehicle_type) \
and container_delivered_by_vehicle_type in set(ModeOfTransport):
selected_containers = selected_containers.where(
Container.delivered_by == container_delivered_by_vehicle_type
)
list_of_vehicle_types = [container_delivered_by_vehicle_type]
else: # assume it is some kind of collection (list, set, ...)
selected_containers = selected_containers.where(
Container.delivered_by << container_delivered_by_vehicle_type
)
return selected_containers
list_of_vehicle_types = list(container_delivered_by_vehicle_type)
return selected_containers, list_of_vehicle_types

@staticmethod
def _restrict_container_picked_up_by_vehicle_type(
selected_containers: ModelSelect, container_picked_up_by_vehicle_type: typing.Any
) -> ModelSelect:
) -> (ModelSelect, list[ModeOfTransport]):
if container_picked_up_by_vehicle_type == "scheduled vehicles":
container_picked_up_by_vehicle_type = ModeOfTransport.get_scheduled_vehicles()

list_of_vehicle_types = container_picked_up_by_vehicle_type
if hashable(container_picked_up_by_vehicle_type) \
and container_picked_up_by_vehicle_type in set(ModeOfTransport):
selected_containers = selected_containers.where(
Container.picked_up_by == container_picked_up_by_vehicle_type
)
list_of_vehicle_types = [container_picked_up_by_vehicle_type]
else: # assume it is some kind of collection (list, set, ...)
selected_containers = selected_containers.where(
Container.picked_up_by << container_picked_up_by_vehicle_type
)
return selected_containers
list_of_vehicle_types = list(container_picked_up_by_vehicle_type)
return selected_containers, list_of_vehicle_types

@staticmethod
def _restrict_container_picked_up_by_initial_vehicle_type(
Expand Down
4 changes: 2 additions & 2 deletions conflowgen/analyses/container_dwell_time_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ def get_container_dwell_times(
)

if container_delivered_by_vehicle_type != "all":
selected_containers = self._restrict_container_delivered_by_vehicle_type(
selected_containers, vehicle_types = self._restrict_container_delivered_by_vehicle_type(
selected_containers, container_delivered_by_vehicle_type
)

if container_picked_up_by_vehicle_type != "all":
selected_containers = self._restrict_container_picked_up_by_vehicle_type(
selected_containers, vehicle_types = self._restrict_container_picked_up_by_vehicle_type(
selected_containers, container_picked_up_by_vehicle_type
)

Expand Down
3 changes: 2 additions & 1 deletion conflowgen/analyses/container_dwell_time_analysis_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import statistics
import typing # noqa, pylint: disable=unused-import # lgtm [py/unused-import] # used in the docstring

import matplotlib.axis
import pandas as pd
import matplotlib.axis


from conflowgen.analyses.container_dwell_time_analysis import ContainerDwellTimeAnalysis
from conflowgen.reporting import AbstractReportWithMatplotlib
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import typing # noqa, pylint: disable=unused-import # lgtm [py/unused-import] # used in the docstring

import matplotlib.axis
import numpy as np
import pandas as pd
import numpy as np
import matplotlib.axis

from conflowgen.analyses.container_flow_adjustment_by_vehicle_type_analysis_summary import \
ContainerFlowAdjustmentByVehicleTypeAnalysisSummary, ContainerFlowAdjustedToVehicleType
Expand Down
125 changes: 125 additions & 0 deletions conflowgen/analyses/container_flow_by_vehicle_instance_analysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
from __future__ import annotations

import datetime
import typing

from peewee import ModelSelect

from conflowgen.data_summaries.data_summaries_cache import DataSummariesCache
from conflowgen.domain_models.container import Container
from conflowgen.domain_models.data_types.mode_of_transport import ModeOfTransport
from conflowgen.analyses.abstract_analysis import AbstractAnalysis
from conflowgen.descriptive_datatypes import VehicleIdentifier, FlowDirection


class ContainerFlowByVehicleInstanceAnalysis(AbstractAnalysis):
"""
This analysis can be run after the synthetic data has been generated.
The analysis returns a data structure that can be used for generating reports (e.g., in text or as a figure)
as it is the case with :class:`.ContainerFlowByVehicleInstanceAnalysisReport`.
"""

@DataSummariesCache.cache_result
def get_container_flow_by_vehicle(
self,
vehicle_types: typing.Collection[ModeOfTransport] = (
ModeOfTransport.train,
ModeOfTransport.feeder,
ModeOfTransport.deep_sea_vessel,
ModeOfTransport.barge
),
start_date: typing.Optional[datetime.datetime] = None,
end_date: typing.Optional[datetime.datetime] = None,
) -> [
ModeOfTransport, typing.Dict[VehicleIdentifier, typing.Dict[FlowDirection, (int, int)]]
]:
"""
Args:
vehicle_types: A collection of vehicle types, e.g., passed as a :class:`list` or :class:`set`.
Only the vehicles that correspond to the provided vehicle type(s) are considered in the analysis.
start_date:
The earliest arriving container that is included. Consider all containers if :obj:`None`.
end_date:
The latest departing container that is included. Consider all containers if :obj:`None`.
Returns:
Grouped by vehicle type and vehicle instance, how many import, export, and transshipment containers are
unloaded and loaded (measured in TEU).
"""

container_flow_by_vehicle: typing.Dict[
ModeOfTransport, typing.Dict[VehicleIdentifier,
typing.Dict[FlowDirection, typing.Dict[str, int]]]] = {
vehicle_type: {}
for vehicle_type in ModeOfTransport
}

vehicle_identifier_cache = {}

selected_containers: ModelSelect = Container.select().where(
(Container.delivered_by.in_(vehicle_types) | Container.picked_up_by.in_(vehicle_types))
)

container: Container
for container in selected_containers:
if start_date and container.get_arrival_time() < start_date:
continue
if end_date and container.get_departure_time() > end_date:
continue

if container.delivered_by_large_scheduled_vehicle is not None: # if not transported by truck

if container.delivered_by_large_scheduled_vehicle not in vehicle_identifier_cache:
vehicle_id_inbound = VehicleIdentifier(
id=container.delivered_by_large_scheduled_vehicle.id,
mode_of_transport=container.delivered_by,
service_name=container.delivered_by_large_scheduled_vehicle.schedule.service_name,
vehicle_name=container.delivered_by_large_scheduled_vehicle.vehicle_name,
vehicle_arrival_time=container.get_arrival_time(),
)
vehicle_identifier_cache[container.delivered_by_large_scheduled_vehicle] = vehicle_id_inbound

vehicle_id_inbound = vehicle_identifier_cache[container.delivered_by_large_scheduled_vehicle]

if vehicle_id_inbound not in container_flow_by_vehicle[container.delivered_by]:
container_flow_by_vehicle[container.delivered_by][vehicle_id_inbound] = {
flow_direction: {
"inbound": 0,
"outbound": 0,
}
for flow_direction in FlowDirection
}
container_flow_by_vehicle[
container.delivered_by
][vehicle_id_inbound][container.flow_direction]["inbound"] += container.occupied_teu

if container.picked_up_by_large_scheduled_vehicle is not None: # if not transported by truck

if container.picked_up_by_large_scheduled_vehicle not in vehicle_identifier_cache:
vehicle_id_outbound = VehicleIdentifier(
id=container.picked_up_by_large_scheduled_vehicle.id,
mode_of_transport=container.picked_up_by,
service_name=container.picked_up_by_large_scheduled_vehicle.schedule.service_name,
vehicle_name=container.picked_up_by_large_scheduled_vehicle.vehicle_name,
vehicle_arrival_time=container.get_departure_time(),
)
vehicle_identifier_cache[container.picked_up_by_large_scheduled_vehicle] = vehicle_id_outbound

vehicle_id_outbound = vehicle_identifier_cache[container.picked_up_by_large_scheduled_vehicle]

if vehicle_id_outbound not in container_flow_by_vehicle[container.picked_up_by]:
container_flow_by_vehicle[container.picked_up_by][vehicle_id_outbound] = {
flow_direction: {
"inbound": 0,
"outbound": 0,
}
for flow_direction in FlowDirection
}
container_flow_by_vehicle[
container.picked_up_by][vehicle_id_outbound][container.flow_direction]["outbound"] += 1

for skipped_vehicle_type in set(ModeOfTransport) - set(vehicle_types):
assert len(container_flow_by_vehicle[skipped_vehicle_type]) == 0
del container_flow_by_vehicle[skipped_vehicle_type]

return container_flow_by_vehicle
Loading

0 comments on commit 147c40e

Please sign in to comment.