eflips-depot 4.6.6__py3-none-any.whl → 4.6.8__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/__init__.py +4 -1
- eflips/depot/api/__init__.py +19 -2
- eflips/depot/api/private/results_to_database.py +67 -58
- {eflips_depot-4.6.6.dist-info → eflips_depot-4.6.8.dist-info}/METADATA +1 -1
- {eflips_depot-4.6.6.dist-info → eflips_depot-4.6.8.dist-info}/RECORD +7 -7
- {eflips_depot-4.6.6.dist-info → eflips_depot-4.6.8.dist-info}/WHEEL +1 -1
- {eflips_depot-4.6.6.dist-info → eflips_depot-4.6.8.dist-info}/LICENSE.md +0 -0
eflips/depot/__init__.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# 1st: Namespaced Package Compat., see https://packaging.python.org/en/latest/guides/packaging-namespace-packages/
|
|
2
2
|
__path__ = __import__("pkgutil").extend_path(__path__, __name__)
|
|
3
3
|
|
|
4
|
-
|
|
5
4
|
# 2nd: Importing of the eflips modules -> TODO Cleanups here to avoid all those imports
|
|
6
5
|
|
|
7
6
|
|
|
@@ -57,3 +56,7 @@ from eflips.depot.validation import Validator
|
|
|
57
56
|
|
|
58
57
|
class UnstableSimulationException(Exception):
|
|
59
58
|
pass
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class DelayedTripException(Exception):
|
|
62
|
+
pass
|
eflips/depot/api/__init__.py
CHANGED
|
@@ -500,14 +500,21 @@ def generate_depot_layout(
|
|
|
500
500
|
AreaType.DIRECT_ONESIDE: rotation_count,
|
|
501
501
|
AreaType.DIRECT_TWOSIDE: None,
|
|
502
502
|
}
|
|
503
|
+
|
|
504
|
+
total_rotation_count = (
|
|
505
|
+
session.query(Rotation)
|
|
506
|
+
.filter(Rotation.scenario_id == scenario.id)
|
|
507
|
+
.count()
|
|
508
|
+
)
|
|
509
|
+
|
|
503
510
|
generate_depot(
|
|
504
511
|
vt_capacity_dict,
|
|
505
512
|
first_stop,
|
|
506
513
|
scenario,
|
|
507
514
|
session,
|
|
508
515
|
charging_power=charging_power,
|
|
509
|
-
num_shunting_slots=max(
|
|
510
|
-
num_cleaning_slots=max(
|
|
516
|
+
num_shunting_slots=max(total_rotation_count // 10, 1),
|
|
517
|
+
num_cleaning_slots=max(total_rotation_count // 10, 1),
|
|
511
518
|
)
|
|
512
519
|
|
|
513
520
|
|
|
@@ -604,6 +611,7 @@ def simulate_scenario(
|
|
|
604
611
|
database_url: Optional[str] = None,
|
|
605
612
|
smart_charging_strategy: SmartChargingStrategy = SmartChargingStrategy.EVEN,
|
|
606
613
|
ignore_unstable_simulation: bool = False,
|
|
614
|
+
ignore_delayed_trips: bool = False,
|
|
607
615
|
) -> None:
|
|
608
616
|
"""
|
|
609
617
|
This method simulates a scenario and adds the results to the database.
|
|
@@ -637,11 +645,13 @@ def simulate_scenario(
|
|
|
637
645
|
- SmartChargingStrategy.MIN_PRICE: Not implemented yet.
|
|
638
646
|
|
|
639
647
|
:param ignore_unstable_simulation: If True, the simulation will not raise an exception if it becomes unstable.
|
|
648
|
+
:param ignore_delayed_trips: If True, the simulation will not raise an exception if there are delayed trips.
|
|
640
649
|
|
|
641
650
|
:return: Nothing. The results are added to the database.
|
|
642
651
|
|
|
643
652
|
:raises UnstableSimulationException: If the simulation becomes numerically unstable or if
|
|
644
653
|
the parameters cause the solver to diverge.
|
|
654
|
+
:raises DelayedTripException: If there are delayed trips in the simulation.
|
|
645
655
|
"""
|
|
646
656
|
logger = logging.getLogger(__name__)
|
|
647
657
|
|
|
@@ -659,6 +669,11 @@ def simulate_scenario(
|
|
|
659
669
|
logger.warning("Simulation is unstable. Continuing.")
|
|
660
670
|
else:
|
|
661
671
|
raise e
|
|
672
|
+
except eflips.depot.DelayedTripException as e:
|
|
673
|
+
if ignore_delayed_trips:
|
|
674
|
+
logger.warning("Simulation has delayed trips. Continuing.")
|
|
675
|
+
else:
|
|
676
|
+
raise e
|
|
662
677
|
|
|
663
678
|
match smart_charging_strategy:
|
|
664
679
|
case SmartChargingStrategy.NONE:
|
|
@@ -1007,6 +1022,8 @@ def add_evaluation_to_database(
|
|
|
1007
1022
|
|
|
1008
1023
|
:raises UnstableSimulationException: If the simulation becomes numerically unstable or if
|
|
1009
1024
|
the parameters cause the solver to diverge.
|
|
1025
|
+
:raises DelayedTripException: If there are delayed trips in the simulation.
|
|
1026
|
+
|
|
1010
1027
|
"""
|
|
1011
1028
|
|
|
1012
1029
|
# Read simulation start time
|
|
@@ -4,10 +4,12 @@ import logging
|
|
|
4
4
|
from datetime import timedelta
|
|
5
5
|
from typing import List, Dict
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
import numpy as np
|
|
8
|
+
from eflips.model import Event, EventType, Rotation, Vehicle, Area, AreaType
|
|
8
9
|
from sqlalchemy import select
|
|
9
10
|
|
|
10
11
|
from eflips.depot import SimpleVehicle, ProcessStatus
|
|
12
|
+
from eflips.depot import UnstableSimulationException, DelayedTripException
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
def get_finished_schedules_per_vehicle(
|
|
@@ -47,10 +49,13 @@ def get_finished_schedules_per_vehicle(
|
|
|
47
49
|
latest_time = None
|
|
48
50
|
|
|
49
51
|
for i in range(len(list_of_finished_trips)):
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
try:
|
|
53
|
+
assert list_of_finished_trips[i].atd == list_of_finished_trips[i].std
|
|
54
|
+
except AssertionError:
|
|
55
|
+
raise DelayedTripException(
|
|
56
|
+
f"The trip {list_of_finished_trips[i].ID} is delayed. The simulation doesn't "
|
|
57
|
+
"support delayed trips for now."
|
|
58
|
+
)
|
|
54
59
|
|
|
55
60
|
if list_of_finished_trips[i].is_copy is False:
|
|
56
61
|
current_trip = list_of_finished_trips[i]
|
|
@@ -61,7 +66,7 @@ def get_finished_schedules_per_vehicle(
|
|
|
61
66
|
"id": int(current_trip.ID),
|
|
62
67
|
}
|
|
63
68
|
if i == 0:
|
|
64
|
-
raise
|
|
69
|
+
raise UnstableSimulationException(
|
|
65
70
|
f"New Vehicle required for the trip {current_trip.ID}, which suggests the fleet or the "
|
|
66
71
|
f"infrastructure might not be enough for the full electrification. Please add charging "
|
|
67
72
|
f"interfaces or increase charging power ."
|
|
@@ -164,8 +169,7 @@ def generate_vehicle_events(
|
|
|
164
169
|
"dwd.active_processes_copy"
|
|
165
170
|
].items():
|
|
166
171
|
if earliest_time <= time_stamp <= latest_time:
|
|
167
|
-
|
|
168
|
-
if num_process == 0:
|
|
172
|
+
if len(process_log) == 0:
|
|
169
173
|
# A departure happens and this trip should already be stored in the dictionary
|
|
170
174
|
pass
|
|
171
175
|
else:
|
|
@@ -202,35 +206,50 @@ def generate_vehicle_events(
|
|
|
202
206
|
f"A process with no duration could only "
|
|
203
207
|
f"happen in the last area before dispatched"
|
|
204
208
|
)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
+
start_this_event = None
|
|
210
|
+
if time_stamp in dict_of_events.keys():
|
|
211
|
+
assert "end" in dict_of_events[time_stamp].keys(), (
|
|
212
|
+
f"The former event of {process} "
|
|
213
|
+
f"should have an end time."
|
|
214
|
+
)
|
|
209
215
|
start_this_event = dict_of_events[time_stamp]["end"]
|
|
210
|
-
|
|
216
|
+
else:
|
|
217
|
+
for other_process in process_log:
|
|
211
218
|
if (
|
|
212
|
-
|
|
213
|
-
|
|
219
|
+
other_process.ID != process.ID
|
|
220
|
+
and other_process.dur > 0
|
|
214
221
|
):
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
222
|
+
start_this_event = other_process.ends[0]
|
|
223
|
+
break
|
|
224
|
+
|
|
225
|
+
assert (
|
|
226
|
+
start_this_event is not None
|
|
227
|
+
), f"Current process {process} should have a start time by now"
|
|
228
|
+
|
|
229
|
+
if start_this_event in dict_of_events.keys():
|
|
230
|
+
if (
|
|
231
|
+
dict_of_events[start_this_event]["type"]
|
|
232
|
+
== "Trip"
|
|
233
|
+
):
|
|
234
|
+
logger.info(
|
|
235
|
+
f"Vehicle {current_vehicle.ID} must depart immediately after charged. "
|
|
236
|
+
f"Thus there will be no STANDBY_DEPARTURE event."
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
else:
|
|
240
|
+
raise ValueError(
|
|
241
|
+
f"There is already an event "
|
|
242
|
+
f"{dict_of_events[start_this_event]} at {start_this_event}."
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
continue
|
|
246
|
+
|
|
247
|
+
dict_of_events[start_this_event] = {
|
|
248
|
+
"type": type(process).__name__,
|
|
249
|
+
"area": current_area.ID,
|
|
250
|
+
"slot": current_slot,
|
|
251
|
+
"id": process.ID,
|
|
252
|
+
}
|
|
234
253
|
|
|
235
254
|
case ProcessStatus.IN_PROGRESS:
|
|
236
255
|
assert (
|
|
@@ -317,35 +336,25 @@ def add_soc_to_events(dict_of_events, battery_log) -> None:
|
|
|
317
336
|
battery_log_list.append((log.t, log.energy / log.energy_real))
|
|
318
337
|
|
|
319
338
|
time_keys = sorted(dict_of_events.keys())
|
|
339
|
+
|
|
340
|
+
battery_log_times = [log[0] for log in battery_log_list]
|
|
341
|
+
battery_log_socs = [log[1] for log in battery_log_list]
|
|
342
|
+
|
|
320
343
|
for i in range(len(time_keys)):
|
|
321
344
|
# Get soc
|
|
322
|
-
|
|
323
|
-
soc_end = None
|
|
345
|
+
|
|
324
346
|
start_time = time_keys[i]
|
|
325
347
|
process_dict = dict_of_events[time_keys[i]]
|
|
326
|
-
for j in range(len(battery_log_list)):
|
|
327
|
-
# Access the correct battery log according to time since there is only one battery log for each time
|
|
328
|
-
log = battery_log_list[j]
|
|
329
|
-
|
|
330
|
-
if process_dict["type"] != "Trip":
|
|
331
|
-
if log[0] == start_time:
|
|
332
|
-
soc_start = log[1]
|
|
333
|
-
if log[0] == process_dict["end"]:
|
|
334
|
-
soc_end = log[1]
|
|
335
|
-
if log[0] < start_time < battery_log_list[j + 1][0]:
|
|
336
|
-
soc_start = log[1]
|
|
337
|
-
if log[0] < process_dict["end"] < battery_log_list[j + 1][0]:
|
|
338
|
-
soc_end = log[1]
|
|
339
|
-
|
|
340
|
-
if soc_start is not None:
|
|
341
|
-
soc_start = min(soc_start, 1) # so
|
|
342
|
-
process_dict["soc_start"] = soc_start
|
|
343
|
-
if soc_end is not None:
|
|
344
|
-
soc_end = min(soc_end, 1) # soc should not exceed 1
|
|
345
|
-
process_dict["soc_end"] = soc_end
|
|
346
348
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
+
if process_dict["type"] != "Trip":
|
|
350
|
+
soc_start = np.interp(start_time, battery_log_times, battery_log_socs)
|
|
351
|
+
process_dict["soc_start"] = min(float(soc_start), 1.0)
|
|
352
|
+
soc_end = np.interp(
|
|
353
|
+
process_dict["end"], battery_log_times, battery_log_socs
|
|
354
|
+
)
|
|
355
|
+
process_dict["soc_end"] = min(float(soc_end), 1.0)
|
|
356
|
+
else:
|
|
357
|
+
continue
|
|
349
358
|
|
|
350
359
|
|
|
351
360
|
def add_events_into_database(
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
eflips/depot/__init__.py,sha256=
|
|
2
|
-
eflips/depot/api/__init__.py,sha256=
|
|
1
|
+
eflips/depot/__init__.py,sha256=06GUem0JIEunIyJ0_P_MLAGfibGEnNqcPPY0OBpO2NQ,1662
|
|
2
|
+
eflips/depot/api/__init__.py,sha256=GgFmHnpawNDdhc8ki4DwXzpMDrRjl1r0TYNXKdRUehk,49718
|
|
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
6
|
eflips/depot/api/private/depot.py,sha256=WcCcib3NSbvoL3G06I2ajT8U5L7AkDK5qe969PHq-fg,41014
|
|
7
|
-
eflips/depot/api/private/results_to_database.py,sha256=
|
|
7
|
+
eflips/depot/api/private/results_to_database.py,sha256=R3wwGuaEsof2sW_fFv5Y9K0cl2K8W0JKe5VoN2elXTQ,25037
|
|
8
8
|
eflips/depot/api/private/smart_charging.py,sha256=MQ9fXdKByHAz6RSKXYcpJXDBccdJKZ2qGReCHagVCyo,13033
|
|
9
9
|
eflips/depot/api/private/util.py,sha256=gk5TJZrcvtkyrqnjR3Cq-hPRGRCovhzKz3LrBDIvN0E,16799
|
|
10
10
|
eflips/depot/configuration.py,sha256=Op3hlir-dEN7yHr0kTqbYANoCBKFWK6uKOv3NJl8w_w,35678
|
|
@@ -37,7 +37,7 @@ eflips/depot/simulation.py,sha256=ee0qTzOzG-8ybN36ie_NJallXfC7jUaS9JZvaYFziLs,10
|
|
|
37
37
|
eflips/depot/smart_charging.py,sha256=C3BYqzn2-OYY4ipXm0ETtavbAM9QXZMYULBpVoChf0E,54311
|
|
38
38
|
eflips/depot/standalone.py,sha256=VxcTzBaB67fNJUMmjPRwKXjhqTy6oQ41Coote2LvAmk,22338
|
|
39
39
|
eflips/depot/validation.py,sha256=TIuY7cQtEJI4H2VVMSuY5IIVkacEEZ67weeMuY3NSAM,7097
|
|
40
|
-
eflips_depot-4.6.
|
|
41
|
-
eflips_depot-4.6.
|
|
42
|
-
eflips_depot-4.6.
|
|
43
|
-
eflips_depot-4.6.
|
|
40
|
+
eflips_depot-4.6.8.dist-info/LICENSE.md,sha256=KB4XTk1fPHjtZCYDyPyreu6h1LVJVZXYg-5vePcWZAc,34143
|
|
41
|
+
eflips_depot-4.6.8.dist-info/METADATA,sha256=YeJBI-UcgIp0m_fqql6ef1a8eMmNZRG-kMm4R9pkTqo,5940
|
|
42
|
+
eflips_depot-4.6.8.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
|
43
|
+
eflips_depot-4.6.8.dist-info/RECORD,,
|
|
File without changes
|