eflips-depot 4.6.5__py3-none-any.whl → 4.6.7__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.
Potentially problematic release.
This version of eflips-depot might be problematic. Click here for more details.
- eflips/depot/__init__.py +4 -1
- eflips/depot/api/__init__.py +21 -1
- eflips/depot/api/private/consumption.py +3 -2
- eflips/depot/api/private/results_to_database.py +67 -58
- {eflips_depot-4.6.5.dist-info → eflips_depot-4.6.7.dist-info}/METADATA +1 -1
- {eflips_depot-4.6.5.dist-info → eflips_depot-4.6.7.dist-info}/RECORD +8 -8
- {eflips_depot-4.6.5.dist-info → eflips_depot-4.6.7.dist-info}/WHEEL +1 -1
- {eflips_depot-4.6.5.dist-info → eflips_depot-4.6.7.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
|
@@ -266,8 +266,18 @@ def simple_consumption_simulation(
|
|
|
266
266
|
vehicles = (
|
|
267
267
|
session.query(Vehicle).filter(Vehicle.scenario_id == scenario.id).all()
|
|
268
268
|
)
|
|
269
|
+
|
|
270
|
+
# Get the event count for each vbehicle in a single query using a groub_py clause
|
|
271
|
+
vehicle_event_count_q = (
|
|
272
|
+
session.query(Event.vehicle_id, sqlalchemy.func.count(Event.id))
|
|
273
|
+
.join(Vehicle)
|
|
274
|
+
.filter(Vehicle.scenario_id == scenario.id)
|
|
275
|
+
.group_by(Event.vehicle_id)
|
|
276
|
+
)
|
|
277
|
+
vehicle_event_count = dict(vehicle_event_count_q.all())
|
|
278
|
+
|
|
269
279
|
for vehicle in vehicles:
|
|
270
|
-
if
|
|
280
|
+
if vehicle.id not in vehicle_event_count.keys():
|
|
271
281
|
add_initial_standby_event(vehicle, session)
|
|
272
282
|
|
|
273
283
|
# Since we are doing no_autoflush blocks later, we need to flush the session once here so that unflushed stuff
|
|
@@ -594,6 +604,7 @@ def simulate_scenario(
|
|
|
594
604
|
database_url: Optional[str] = None,
|
|
595
605
|
smart_charging_strategy: SmartChargingStrategy = SmartChargingStrategy.EVEN,
|
|
596
606
|
ignore_unstable_simulation: bool = False,
|
|
607
|
+
ignore_delayed_trips: bool = False,
|
|
597
608
|
) -> None:
|
|
598
609
|
"""
|
|
599
610
|
This method simulates a scenario and adds the results to the database.
|
|
@@ -627,11 +638,13 @@ def simulate_scenario(
|
|
|
627
638
|
- SmartChargingStrategy.MIN_PRICE: Not implemented yet.
|
|
628
639
|
|
|
629
640
|
:param ignore_unstable_simulation: If True, the simulation will not raise an exception if it becomes unstable.
|
|
641
|
+
:param ignore_delayed_trips: If True, the simulation will not raise an exception if there are delayed trips.
|
|
630
642
|
|
|
631
643
|
:return: Nothing. The results are added to the database.
|
|
632
644
|
|
|
633
645
|
:raises UnstableSimulationException: If the simulation becomes numerically unstable or if
|
|
634
646
|
the parameters cause the solver to diverge.
|
|
647
|
+
:raises DelayedTripException: If there are delayed trips in the simulation.
|
|
635
648
|
"""
|
|
636
649
|
logger = logging.getLogger(__name__)
|
|
637
650
|
|
|
@@ -649,6 +662,11 @@ def simulate_scenario(
|
|
|
649
662
|
logger.warning("Simulation is unstable. Continuing.")
|
|
650
663
|
else:
|
|
651
664
|
raise e
|
|
665
|
+
except eflips.depot.DelayedTripException as e:
|
|
666
|
+
if ignore_delayed_trips:
|
|
667
|
+
logger.warning("Simulation has delayed trips. Continuing.")
|
|
668
|
+
else:
|
|
669
|
+
raise e
|
|
652
670
|
|
|
653
671
|
match smart_charging_strategy:
|
|
654
672
|
case SmartChargingStrategy.NONE:
|
|
@@ -997,6 +1015,8 @@ def add_evaluation_to_database(
|
|
|
997
1015
|
|
|
998
1016
|
:raises UnstableSimulationException: If the simulation becomes numerically unstable or if
|
|
999
1017
|
the parameters cause the solver to diverge.
|
|
1018
|
+
:raises DelayedTripException: If there are delayed trips in the simulation.
|
|
1019
|
+
|
|
1000
1020
|
"""
|
|
1001
1021
|
|
|
1002
1022
|
# Read simulation start time
|
|
@@ -78,13 +78,14 @@ def add_initial_standby_event(
|
|
|
78
78
|
but changes are not yet committed.
|
|
79
79
|
"""
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
earliest_trip_q = (
|
|
82
82
|
session.query(Trip)
|
|
83
83
|
.join(Rotation)
|
|
84
84
|
.filter(Rotation.vehicle == vehicle)
|
|
85
85
|
.order_by(Trip.departure_time)
|
|
86
|
-
.
|
|
86
|
+
.limit(1)
|
|
87
87
|
)
|
|
88
|
+
earliest_trip = earliest_trip_q.one_or_none()
|
|
88
89
|
if earliest_trip is None:
|
|
89
90
|
warnings.warn(
|
|
90
91
|
f"No trips found for vehicle {vehicle.id}. Cannot add initial standby event.",
|
|
@@ -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=2isjSF0bef8Nq_lHMC2MGgfAFBgj4OWeezouzeSisss,49527
|
|
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
|
-
eflips/depot/api/private/consumption.py,sha256=
|
|
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.7.dist-info/LICENSE.md,sha256=KB4XTk1fPHjtZCYDyPyreu6h1LVJVZXYg-5vePcWZAc,34143
|
|
41
|
+
eflips_depot-4.6.7.dist-info/METADATA,sha256=8ZhFsc9DzScN-igSjjhMmKbUnErElAu9FRWZn8rI1w8,5940
|
|
42
|
+
eflips_depot-4.6.7.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
|
43
|
+
eflips_depot-4.6.7.dist-info/RECORD,,
|
|
File without changes
|