eflips-depot 4.9.1__py3-none-any.whl → 4.10.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- eflips/depot/api/__init__.py +147 -10
- eflips/depot/api/private/depot.py +2 -1
- {eflips_depot-4.9.1.dist-info → eflips_depot-4.10.0.dist-info}/METADATA +1 -1
- {eflips_depot-4.9.1.dist-info → eflips_depot-4.10.0.dist-info}/RECORD +6 -6
- {eflips_depot-4.9.1.dist-info → eflips_depot-4.10.0.dist-info}/LICENSE.md +0 -0
- {eflips_depot-4.9.1.dist-info → eflips_depot-4.10.0.dist-info}/WHEEL +0 -0
eflips/depot/api/__init__.py
CHANGED
|
@@ -49,6 +49,8 @@ from eflips.model import (
|
|
|
49
49
|
AreaType,
|
|
50
50
|
ChargeType,
|
|
51
51
|
Route,
|
|
52
|
+
ConsistencyWarning,
|
|
53
|
+
Station,
|
|
52
54
|
)
|
|
53
55
|
from sqlalchemy.orm import Session
|
|
54
56
|
|
|
@@ -67,6 +69,7 @@ from eflips.depot.api.private.depot import (
|
|
|
67
69
|
depot_to_template,
|
|
68
70
|
group_rotations_by_start_end_stop,
|
|
69
71
|
generate_depot,
|
|
72
|
+
depot_smallest_possible_size,
|
|
70
73
|
)
|
|
71
74
|
from eflips.depot.api.private.results_to_database import (
|
|
72
75
|
get_finished_schedules_per_vehicle,
|
|
@@ -492,19 +495,14 @@ def generate_depot_layout(
|
|
|
492
495
|
|
|
493
496
|
# Create one direct slot for each rotation (it's way too much, but should work)
|
|
494
497
|
vt_capacity_dict: Dict[VehicleType, Dict[AreaType, None | int]] = {}
|
|
498
|
+
rotation_count_depot = 0
|
|
495
499
|
for vehicle_type, rotations in vehicle_type_dict.items():
|
|
496
|
-
rotation_count = len(rotations)
|
|
497
500
|
vt_capacity_dict[vehicle_type] = {
|
|
498
501
|
AreaType.LINE: None,
|
|
499
|
-
AreaType.DIRECT_ONESIDE:
|
|
502
|
+
AreaType.DIRECT_ONESIDE: len(rotations),
|
|
500
503
|
AreaType.DIRECT_TWOSIDE: None,
|
|
501
504
|
}
|
|
502
|
-
|
|
503
|
-
total_rotation_count = (
|
|
504
|
-
session.query(Rotation)
|
|
505
|
-
.filter(Rotation.scenario_id == scenario.id)
|
|
506
|
-
.count()
|
|
507
|
-
)
|
|
505
|
+
rotation_count_depot += len(rotations)
|
|
508
506
|
|
|
509
507
|
generate_depot(
|
|
510
508
|
vt_capacity_dict,
|
|
@@ -512,8 +510,8 @@ def generate_depot_layout(
|
|
|
512
510
|
scenario,
|
|
513
511
|
session,
|
|
514
512
|
charging_power=charging_power,
|
|
515
|
-
num_shunting_slots=max(
|
|
516
|
-
num_cleaning_slots=max(
|
|
513
|
+
num_shunting_slots=max(rotation_count_depot // 10, 1),
|
|
514
|
+
num_cleaning_slots=max(rotation_count_depot // 10, 1),
|
|
517
515
|
)
|
|
518
516
|
|
|
519
517
|
|
|
@@ -1097,3 +1095,142 @@ def add_evaluation_to_database(
|
|
|
1097
1095
|
# Postprocessing of events
|
|
1098
1096
|
update_vehicle_in_rotation(session, scenario, list_of_assigned_schedules)
|
|
1099
1097
|
update_waiting_events(session, scenario, waiting_area_id)
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
def generate_depot_optimal_size(
|
|
1101
|
+
scenario: Scenario,
|
|
1102
|
+
standard_block_length: int = 6,
|
|
1103
|
+
charging_power: float = 90,
|
|
1104
|
+
database_url: Optional[str] = None,
|
|
1105
|
+
delete_existing_depot: bool = False,
|
|
1106
|
+
) -> None:
|
|
1107
|
+
"""
|
|
1108
|
+
Generates an optimal depot layout with the smallest possible size for each depot in the scenario. Line charging areas
|
|
1109
|
+
with given block length area preferred. The existing depot will be deleted if `delete_existing_depot` is set to True.
|
|
1110
|
+
|
|
1111
|
+
:param scenario: A :class:`eflips.model.Scenario` object containing the input data for the simulation.
|
|
1112
|
+
:param standard_block_length: The standard block length for the depot layout in meters. Default is 6.
|
|
1113
|
+
:param charging_power: The charging power of the charging area in kW. Default is 90.
|
|
1114
|
+
:param database_url: An optional database URL. Used if no database url is given by the environment variable.
|
|
1115
|
+
:param delete_existing_depot: If there is already a depot existing in this scenario, set True to delete this
|
|
1116
|
+
existing depot. Set to False and a ValueError will be raised if there is a depot in this scenario.
|
|
1117
|
+
|
|
1118
|
+
:return: None. The depot layout will be added to the database.
|
|
1119
|
+
|
|
1120
|
+
"""
|
|
1121
|
+
|
|
1122
|
+
logger = logging.getLogger(__name__)
|
|
1123
|
+
|
|
1124
|
+
with create_session(scenario, database_url) as (session, scenario):
|
|
1125
|
+
# Delete all vehicles and events, also disconnect the vehicles from the rotations
|
|
1126
|
+
rotation_q = session.query(Rotation).filter(Rotation.scenario_id == scenario.id)
|
|
1127
|
+
rotation_q.update({"vehicle_id": None})
|
|
1128
|
+
session.query(Event).filter(Event.scenario_id == scenario.id).delete()
|
|
1129
|
+
session.query(Vehicle).filter(Vehicle.scenario_id == scenario.id).delete()
|
|
1130
|
+
|
|
1131
|
+
# Handles existing depot
|
|
1132
|
+
if session.query(Depot).filter(Depot.scenario_id == scenario.id).count() != 0:
|
|
1133
|
+
if delete_existing_depot is False:
|
|
1134
|
+
raise ValueError("Depot already exists.")
|
|
1135
|
+
|
|
1136
|
+
delete_depots(scenario, session)
|
|
1137
|
+
|
|
1138
|
+
# Temporary workaround to set vehicle energy consumption manually
|
|
1139
|
+
# TODO: Replace by "use DS consumption if LUT"
|
|
1140
|
+
for vehicle_type in (
|
|
1141
|
+
session.query(VehicleType)
|
|
1142
|
+
.filter(VehicleType.scenario_id == scenario.id)
|
|
1143
|
+
.all()
|
|
1144
|
+
):
|
|
1145
|
+
vehicle_type.consumption = 2.0
|
|
1146
|
+
vehicle_type.vehicle_classes = []
|
|
1147
|
+
|
|
1148
|
+
##### Step 0: Consumption Simulation #####
|
|
1149
|
+
# Run the consumption simulation for all depots
|
|
1150
|
+
simple_consumption_simulation(scenario, initialize_vehicles=True)
|
|
1151
|
+
|
|
1152
|
+
##### Step 1: Find all potential depots #####
|
|
1153
|
+
# These are all the spots where a rotation starts and end
|
|
1154
|
+
warnings.simplefilter("ignore", category=ConsistencyWarning)
|
|
1155
|
+
warnings.simplefilter("ignore", category=UserWarning)
|
|
1156
|
+
|
|
1157
|
+
depot_capacities_for_scenario: Dict[
|
|
1158
|
+
Station, Dict[VehicleType, Dict[AreaType, int]]
|
|
1159
|
+
] = {}
|
|
1160
|
+
|
|
1161
|
+
num_rotations_for_scenario: Dict[Station, int] = {}
|
|
1162
|
+
|
|
1163
|
+
for (
|
|
1164
|
+
first_last_stop_tup,
|
|
1165
|
+
vehicle_type_dict,
|
|
1166
|
+
) in group_rotations_by_start_end_stop(scenario.id, session).items():
|
|
1167
|
+
first_stop, last_stop = first_last_stop_tup
|
|
1168
|
+
if first_stop != last_stop:
|
|
1169
|
+
raise ValueError("First and last stop of a rotation are not the same.")
|
|
1170
|
+
|
|
1171
|
+
station = first_stop
|
|
1172
|
+
rotation_count_depot = sum(
|
|
1173
|
+
len(rotations) for vehicle_type, rotations in vehicle_type_dict.items()
|
|
1174
|
+
)
|
|
1175
|
+
|
|
1176
|
+
savepoint = session.begin_nested()
|
|
1177
|
+
try:
|
|
1178
|
+
# (Temporarily) Delete all rotations not starting or ending at the station
|
|
1179
|
+
logger.debug(
|
|
1180
|
+
f"Deleting all rotations not starting or ending at {station.name}"
|
|
1181
|
+
)
|
|
1182
|
+
all_rot_for_scenario = (
|
|
1183
|
+
session.query(Rotation)
|
|
1184
|
+
.filter(Rotation.scenario_id == scenario.id)
|
|
1185
|
+
.all()
|
|
1186
|
+
)
|
|
1187
|
+
to_delete = []
|
|
1188
|
+
for rot in all_rot_for_scenario:
|
|
1189
|
+
first_stop = rot.trips[0].route.departure_station
|
|
1190
|
+
if first_stop != station:
|
|
1191
|
+
for trip in rot.trips:
|
|
1192
|
+
for stop_time in trip.stop_times:
|
|
1193
|
+
to_delete.append(stop_time)
|
|
1194
|
+
for event in trip.events:
|
|
1195
|
+
to_delete.append(event)
|
|
1196
|
+
to_delete.append(trip)
|
|
1197
|
+
to_delete.append(rot)
|
|
1198
|
+
for obj in to_delete:
|
|
1199
|
+
session.flush()
|
|
1200
|
+
session.delete(obj)
|
|
1201
|
+
session.flush()
|
|
1202
|
+
|
|
1203
|
+
logger.info(f"Generating depot layout for station {station.name}")
|
|
1204
|
+
vt_capacities_for_station = depot_smallest_possible_size(
|
|
1205
|
+
station,
|
|
1206
|
+
scenario,
|
|
1207
|
+
session,
|
|
1208
|
+
standard_block_length,
|
|
1209
|
+
charging_power,
|
|
1210
|
+
)
|
|
1211
|
+
|
|
1212
|
+
depot_capacities_for_scenario[station] = vt_capacities_for_station
|
|
1213
|
+
num_rotations_for_scenario[station] = rotation_count_depot
|
|
1214
|
+
finally:
|
|
1215
|
+
savepoint.rollback()
|
|
1216
|
+
|
|
1217
|
+
# create depot with the calculated area sizes
|
|
1218
|
+
|
|
1219
|
+
for depot_station, capacities in depot_capacities_for_scenario.items():
|
|
1220
|
+
generate_depot(
|
|
1221
|
+
capacities,
|
|
1222
|
+
depot_station,
|
|
1223
|
+
scenario,
|
|
1224
|
+
session,
|
|
1225
|
+
standard_block_length=standard_block_length,
|
|
1226
|
+
charging_power=charging_power,
|
|
1227
|
+
num_shunting_slots=num_rotations_for_scenario[depot_station] // 10,
|
|
1228
|
+
num_cleaning_slots=num_rotations_for_scenario[depot_station] // 10,
|
|
1229
|
+
)
|
|
1230
|
+
|
|
1231
|
+
# Delete all vehicles and events again. Only depot layout is kept
|
|
1232
|
+
|
|
1233
|
+
rotation_q = session.query(Rotation).filter(Rotation.scenario_id == scenario.id)
|
|
1234
|
+
rotation_q.update({"vehicle_id": None})
|
|
1235
|
+
session.query(Event).filter(Event.scenario_id == scenario.id).delete()
|
|
1236
|
+
session.query(Vehicle).filter(Vehicle.scenario_id == scenario.id).delete()
|
|
@@ -1070,7 +1070,8 @@ def depot_smallest_possible_size(
|
|
|
1070
1070
|
logger.debug(
|
|
1071
1071
|
f"Vehicle count for {vt.name} in {amount_of_line_areas} line areas configuration: {vehicle_count_q}. This is > than the all-direct configuration ({vehicle_counts_all_direct[vt]})."
|
|
1072
1072
|
)
|
|
1073
|
-
except
|
|
1073
|
+
except Exception as e:
|
|
1074
|
+
# This change is made after Unstable exception and delay exceptions are introduced
|
|
1074
1075
|
if (
|
|
1075
1076
|
"which suggests the fleet or the infrastructure might not be enough for the full electrification. Please add charging interfaces or increase charging power ."
|
|
1076
1077
|
in repr(e)
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
eflips/depot/__init__.py,sha256=06GUem0JIEunIyJ0_P_MLAGfibGEnNqcPPY0OBpO2NQ,1662
|
|
2
|
-
eflips/depot/api/__init__.py,sha256
|
|
2
|
+
eflips/depot/api/__init__.py,sha256=5GnYLIHVowzdEqSd8GSehwtzxgnESXYaIt4exDhV06g,54135
|
|
3
3
|
eflips/depot/api/defaults/default_settings.json,sha256=0eUDTw_rtLQFvthP8oJL93iRXlmAOravAg-4qqGMQAY,5375
|
|
4
4
|
eflips/depot/api/private/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
5
|
eflips/depot/api/private/consumption.py,sha256=FTF_E-DsbvJNWZJKQy_CPoHQpLz--pWY-inJYg8lsjM,16453
|
|
6
|
-
eflips/depot/api/private/depot.py,sha256
|
|
6
|
+
eflips/depot/api/private/depot.py,sha256=-LpLeEi3ctjsLzWbBGDBTic_aKrb6S35ii5wt-7QTmI,43359
|
|
7
7
|
eflips/depot/api/private/results_to_database.py,sha256=rSwBAjwiThE8_B8e0rrIGFhrEjo8kPiHM5NPwAEGdEI,25514
|
|
8
8
|
eflips/depot/api/private/util.py,sha256=YcvjKikgdquYXx61pbDiB3Naa1FTEvEfiEcWbnFGNH8,16841
|
|
9
9
|
eflips/depot/configuration.py,sha256=Op3hlir-dEN7yHr0kTqbYANoCBKFWK6uKOv3NJl8w_w,35678
|
|
@@ -36,7 +36,7 @@ eflips/depot/simulation.py,sha256=ee0qTzOzG-8ybN36ie_NJallXfC7jUaS9JZvaYFziLs,10
|
|
|
36
36
|
eflips/depot/smart_charging.py,sha256=C3BYqzn2-OYY4ipXm0ETtavbAM9QXZMYULBpVoChf0E,54311
|
|
37
37
|
eflips/depot/standalone.py,sha256=8O01zEXghFG9zZBu0fUD0sXvbHQ-AXw6RB5M750a_sM,22419
|
|
38
38
|
eflips/depot/validation.py,sha256=TIuY7cQtEJI4H2VVMSuY5IIVkacEEZ67weeMuY3NSAM,7097
|
|
39
|
-
eflips_depot-4.
|
|
40
|
-
eflips_depot-4.
|
|
41
|
-
eflips_depot-4.
|
|
42
|
-
eflips_depot-4.
|
|
39
|
+
eflips_depot-4.10.0.dist-info/LICENSE.md,sha256=KB4XTk1fPHjtZCYDyPyreu6h1LVJVZXYg-5vePcWZAc,34143
|
|
40
|
+
eflips_depot-4.10.0.dist-info/METADATA,sha256=j2GXtPn_Qm349L5BATf6OMThhcl98MWxO-yra-fn4tQ,5985
|
|
41
|
+
eflips_depot-4.10.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
42
|
+
eflips_depot-4.10.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|