eflips-depot 3.2.3__tar.gz → 3.2.5__tar.gz
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-3.2.3 → eflips_depot-3.2.5}/PKG-INFO +1 -1
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/api/__init__.py +26 -17
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/api/private/smart_charging.py +91 -28
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/pyproject.toml +1 -1
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/LICENSE.md +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/README.md +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/__init__.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/api/defaults/default_settings.json +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/api/private/__init__.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/api/private/depot.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/api/private/util.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/configuration.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/depot.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/evaluation.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/filters.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/input_epex_power_price.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/__init__.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/doc/__init__.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/doc/direct_details.pdf +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/evaluation.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/opt_tools/__init__.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/opt_tools/crossover.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/opt_tools/fitness_c_urfd.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/opt_tools/fitness_util.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/opt_tools/init.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/opt_tools/mutation.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/optimize_c_urfd.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/packing.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/settings.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/template_creation.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/util.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/plots.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/processes.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/rating.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/resources.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/settings_config.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/simple_vehicle.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/simulation.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/smart_charging.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/standalone.py +0 -0
- {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/validation.py +0 -0
|
@@ -28,7 +28,7 @@ import copy
|
|
|
28
28
|
import os
|
|
29
29
|
import warnings
|
|
30
30
|
from datetime import timedelta
|
|
31
|
-
from enum import Enum
|
|
31
|
+
from enum import Enum
|
|
32
32
|
from math import ceil
|
|
33
33
|
from typing import Any, Dict, Optional, Union
|
|
34
34
|
|
|
@@ -68,24 +68,24 @@ from eflips.depot.api.private.util import (
|
|
|
68
68
|
)
|
|
69
69
|
|
|
70
70
|
|
|
71
|
-
class
|
|
71
|
+
class SmartChargingStrategy(Enum):
|
|
72
72
|
"""Enum class for different smart charging strategies."""
|
|
73
73
|
|
|
74
|
-
NONE =
|
|
74
|
+
NONE = 0
|
|
75
75
|
"""
|
|
76
76
|
Do not use smart charging.
|
|
77
77
|
|
|
78
78
|
Buses are charged with the maximum power available, from the time they arrive at the depot
|
|
79
79
|
until they are full (or leave the depot).
|
|
80
80
|
"""
|
|
81
|
-
EVEN =
|
|
81
|
+
EVEN = 1
|
|
82
82
|
"""
|
|
83
83
|
Use smart charging with an even distribution of charging power over the time the bus is at the depot.
|
|
84
84
|
|
|
85
85
|
This aims to
|
|
86
86
|
minimize the peak power demand.
|
|
87
87
|
"""
|
|
88
|
-
MIN_PRICE =
|
|
88
|
+
MIN_PRICE = 2
|
|
89
89
|
"""
|
|
90
90
|
Use smart charging in order to minimize the cost of charging.
|
|
91
91
|
|
|
@@ -422,8 +422,17 @@ def apply_even_smart_charging(
|
|
|
422
422
|
.order_by(Event.time_start)
|
|
423
423
|
.first()
|
|
424
424
|
)
|
|
425
|
-
|
|
426
|
-
|
|
425
|
+
|
|
426
|
+
if (
|
|
427
|
+
next_event is None
|
|
428
|
+
or next_event.event_type != EventType.STANDBY_DEPARTURE
|
|
429
|
+
):
|
|
430
|
+
warnings.warn(
|
|
431
|
+
f"Event {charging_event.id} has no STANDBY_DEPARTURE event after a CHARGING_DEPOT "
|
|
432
|
+
f"event. No room for smart charging."
|
|
433
|
+
)
|
|
434
|
+
continue
|
|
435
|
+
|
|
427
436
|
assert next_event.time_start == charging_event.time_end
|
|
428
437
|
|
|
429
438
|
if (
|
|
@@ -457,7 +466,7 @@ def simulate_scenario(
|
|
|
457
466
|
scenario: Union[Scenario, int, Any],
|
|
458
467
|
repetition_period: Optional[timedelta] = None,
|
|
459
468
|
database_url: Optional[str] = None,
|
|
460
|
-
smart_charging_strategy:
|
|
469
|
+
smart_charging_strategy: SmartChargingStrategy = SmartChargingStrategy.EVEN,
|
|
461
470
|
) -> None:
|
|
462
471
|
"""
|
|
463
472
|
This method simulates a scenario and adds the results to the database.
|
|
@@ -497,15 +506,15 @@ def simulate_scenario(
|
|
|
497
506
|
ev = run_simulation(simulation_host)
|
|
498
507
|
add_evaluation_to_database(scenario, ev, session)
|
|
499
508
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
+
match smart_charging_strategy:
|
|
510
|
+
case SmartChargingStrategy.NONE:
|
|
511
|
+
pass
|
|
512
|
+
case SmartChargingStrategy.EVEN:
|
|
513
|
+
apply_even_smart_charging(scenario, database_url)
|
|
514
|
+
case SmartChargingStrategy.MIN_PRICE:
|
|
515
|
+
raise NotImplementedError("MIN_PRICE strategy is not implemented yet.")
|
|
516
|
+
case _:
|
|
517
|
+
raise NotImplementedError()
|
|
509
518
|
|
|
510
519
|
|
|
511
520
|
def _init_simulation(
|
|
@@ -113,15 +113,20 @@ def optimize_charging_events_even(charging_events: List[Event]) -> None:
|
|
|
113
113
|
|
|
114
114
|
# for each timestep optimize the power draw. We want to charge less when there are more vehicles at the depot
|
|
115
115
|
# The power draw is varies with the amount of vehicles present at the depot relative to the mean amount
|
|
116
|
-
charging_factor = (
|
|
116
|
+
charging_factor = (total_occupancy / mean_occupancy) * params_for_event[
|
|
117
117
|
"charging_allowed"
|
|
118
118
|
]
|
|
119
119
|
|
|
120
120
|
# Make sure the charging factor is not infinite or NaN
|
|
121
121
|
charging_factor[np.isnan(charging_factor)] = 1
|
|
122
122
|
charging_factor[np.isinf(charging_factor)] = 1
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
power_scaling_vector = (
|
|
124
|
+
(mean_power * charging_factor) - mean_power
|
|
125
|
+
) * -1 # How much to shift the power draw
|
|
126
|
+
if min(power_scaling_vector) < -mean_power:
|
|
127
|
+
power_scaling_vector /= min(power_scaling_vector) / -mean_power
|
|
128
|
+
optimized_power = params_for_event["charging_allowed"] * (
|
|
129
|
+
power_scaling_vector + mean_power
|
|
125
130
|
)
|
|
126
131
|
|
|
127
132
|
# Cap it at the peak power
|
|
@@ -149,11 +154,71 @@ def optimize_charging_events_even(charging_events: List[Event]) -> None:
|
|
|
149
154
|
post_opt_energy = (
|
|
150
155
|
scipy.integrate.trapz(optimized_power, total_time) / 3600
|
|
151
156
|
) # kWh
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
+
|
|
158
|
+
if False:
|
|
159
|
+
# Some plots for only this charging event
|
|
160
|
+
from matplotlib import pyplot as plt
|
|
161
|
+
|
|
162
|
+
valid_charging_indices = np.where(
|
|
163
|
+
params_for_event["charging_allowed"] == 1
|
|
164
|
+
)[0]
|
|
165
|
+
|
|
166
|
+
fig, axs = plt.subplots(3, 1, sharex=True)
|
|
167
|
+
axs[0].axhline(mean_power, color="red", linestyle="--", label="Mean power")
|
|
168
|
+
axs[0].plot(
|
|
169
|
+
total_time[valid_charging_indices],
|
|
170
|
+
params_for_event["power_draw"][valid_charging_indices],
|
|
171
|
+
label="Original power draw",
|
|
172
|
+
)
|
|
173
|
+
axs[0].plot(
|
|
174
|
+
total_time[valid_charging_indices],
|
|
175
|
+
optimized_power[valid_charging_indices],
|
|
176
|
+
label="Optimized power draw",
|
|
177
|
+
)
|
|
178
|
+
axs[0].plot(
|
|
179
|
+
total_time[valid_charging_indices],
|
|
180
|
+
optimized_power_capped[valid_charging_indices],
|
|
181
|
+
label="Optimized power draw capped",
|
|
182
|
+
)
|
|
183
|
+
axs[0].set_xlabel("Time")
|
|
184
|
+
axs[0].legend()
|
|
185
|
+
|
|
186
|
+
axs[1].plot(
|
|
187
|
+
total_time[valid_charging_indices],
|
|
188
|
+
np.cumsum(params_for_event["power_draw"][valid_charging_indices])
|
|
189
|
+
/ 3600,
|
|
190
|
+
label="Original energy transferred",
|
|
191
|
+
)
|
|
192
|
+
axs[1].plot(
|
|
193
|
+
total_time[valid_charging_indices],
|
|
194
|
+
np.cumsum(optimized_power[valid_charging_indices]) / 3600,
|
|
195
|
+
label="Optimized energy transferred",
|
|
196
|
+
)
|
|
197
|
+
axs[1].set_xlabel("Time")
|
|
198
|
+
|
|
199
|
+
axs[2].axhline(
|
|
200
|
+
mean_occupancy, color="red", linestyle="--", label="Mean occupancy"
|
|
201
|
+
)
|
|
202
|
+
axs[2].plot(
|
|
203
|
+
total_time[valid_charging_indices],
|
|
204
|
+
total_occupancy[valid_charging_indices],
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
mean_arr = np.ones_like(total_occupancy) * mean_occupancy
|
|
208
|
+
mean_cumsum = np.cumsum(mean_arr[valid_charging_indices])
|
|
209
|
+
total_cumsum = np.cumsum(total_occupancy[valid_charging_indices])
|
|
210
|
+
assert np.isclose(mean_cumsum[-1], total_cumsum[-1], atol=0.01)
|
|
211
|
+
|
|
212
|
+
axs[2].set_xlabel("Time")
|
|
213
|
+
plt.show()
|
|
214
|
+
|
|
215
|
+
if not np.isclose(
|
|
216
|
+
post_opt_energy, params_for_event["transferred_energy"], rtol=0.001
|
|
217
|
+
):
|
|
218
|
+
# Scale the power draw to match the transferred energy
|
|
219
|
+
optimized_power = optimized_power * (
|
|
220
|
+
params_for_event["transferred_energy"] / post_opt_energy
|
|
221
|
+
)
|
|
157
222
|
|
|
158
223
|
optimized_power2 = (
|
|
159
224
|
params_for_event["charging_allowed"] * mean_power
|
|
@@ -169,57 +234,55 @@ def optimize_charging_events_even(charging_events: List[Event]) -> None:
|
|
|
169
234
|
if False:
|
|
170
235
|
from matplotlib import pyplot as plt
|
|
171
236
|
|
|
172
|
-
plt.
|
|
237
|
+
fig, axs = plt.subplots(3, 1, sharex=True)
|
|
173
238
|
total_power = np.sum(
|
|
174
239
|
[event["power_draw"] for event in params_for_events], axis=0
|
|
175
240
|
)
|
|
176
|
-
|
|
241
|
+
axs[0].plot(total_time, total_power, label="Original power draw")
|
|
177
242
|
optimized_power = np.sum(
|
|
178
243
|
[event["optimized_power"] for event in params_for_events], axis=0
|
|
179
244
|
)
|
|
180
|
-
|
|
245
|
+
axs[0].plot(total_time, optimized_power, label="Optimized power draw")
|
|
181
246
|
optimized_power2 = np.sum(
|
|
182
247
|
[event["optimized_power2"] for event in params_for_events], axis=0
|
|
183
248
|
)
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
249
|
+
axs[0].plot(total_time, optimized_power2, label="Mean power draw")
|
|
250
|
+
axs[0].set_xlabel("Time")
|
|
251
|
+
axs[0].set_ylabel("Total power draw (kW)")
|
|
187
252
|
|
|
188
|
-
|
|
253
|
+
axs[0].axhline(
|
|
189
254
|
y=max(total_power), color="blue", linestyle="--", label="Max power draw"
|
|
190
255
|
)
|
|
191
|
-
|
|
256
|
+
axs[0].axhline(
|
|
192
257
|
y=max(optimized_power),
|
|
193
258
|
color="orange",
|
|
194
259
|
linestyle="--",
|
|
195
260
|
label="Max optimized power draw",
|
|
196
261
|
)
|
|
197
|
-
|
|
262
|
+
axs[0].axhline(
|
|
198
263
|
y=max(optimized_power2),
|
|
199
264
|
color="green",
|
|
200
265
|
linestyle="--",
|
|
201
266
|
label="Max mean power draw",
|
|
202
267
|
)
|
|
203
268
|
|
|
204
|
-
plt.subplot(3, 1, 2)
|
|
205
269
|
# Energy transferred
|
|
206
270
|
total_energy = scipy.integrate.cumtrapz(total_power, total_time, initial=0)
|
|
207
|
-
|
|
271
|
+
axs[1].plot(total_time, total_energy, label="Original energy transferred")
|
|
208
272
|
optimized_energy = scipy.integrate.cumtrapz(
|
|
209
273
|
optimized_power, total_time, initial=0
|
|
210
274
|
)
|
|
211
|
-
|
|
275
|
+
axs[1].plot(total_time, optimized_energy, label="Optimized energy transferred")
|
|
212
276
|
optimized_energy2 = scipy.integrate.cumtrapz(
|
|
213
277
|
optimized_power2, total_time, initial=0
|
|
214
278
|
)
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
plt.ylabel("Vehicle count")
|
|
279
|
+
axs[1].plot(total_time, optimized_energy2, label="Mean energy transferred")
|
|
280
|
+
axs[1].set_xlabel("Time")
|
|
281
|
+
axs[1].set_ylabel("Total energy transferred (kWh)")
|
|
282
|
+
|
|
283
|
+
axs[2].plot(total_time, total_occupancy)
|
|
284
|
+
axs[2].set_xlabel("Time")
|
|
285
|
+
axs[2].set_ylabel("Vehicle count")
|
|
223
286
|
plt.show()
|
|
224
287
|
|
|
225
288
|
# Finally, update the events in the database
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/opt_tools/fitness_c_urfd.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|