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.

Files changed (41) hide show
  1. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/PKG-INFO +1 -1
  2. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/api/__init__.py +26 -17
  3. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/api/private/smart_charging.py +91 -28
  4. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/pyproject.toml +1 -1
  5. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/LICENSE.md +0 -0
  6. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/README.md +0 -0
  7. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/__init__.py +0 -0
  8. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/api/defaults/default_settings.json +0 -0
  9. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/api/private/__init__.py +0 -0
  10. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/api/private/depot.py +0 -0
  11. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/api/private/util.py +0 -0
  12. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/configuration.py +0 -0
  13. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/depot.py +0 -0
  14. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/evaluation.py +0 -0
  15. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/filters.py +0 -0
  16. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/input_epex_power_price.py +0 -0
  17. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/__init__.py +0 -0
  18. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/doc/__init__.py +0 -0
  19. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/doc/direct_details.pdf +0 -0
  20. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/evaluation.py +0 -0
  21. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/opt_tools/__init__.py +0 -0
  22. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/opt_tools/crossover.py +0 -0
  23. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/opt_tools/fitness_c_urfd.py +0 -0
  24. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/opt_tools/fitness_util.py +0 -0
  25. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/opt_tools/init.py +0 -0
  26. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/opt_tools/mutation.py +0 -0
  27. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/optimize_c_urfd.py +0 -0
  28. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/packing.py +0 -0
  29. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/settings.py +0 -0
  30. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/template_creation.py +0 -0
  31. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/layout_opt/util.py +0 -0
  32. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/plots.py +0 -0
  33. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/processes.py +0 -0
  34. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/rating.py +0 -0
  35. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/resources.py +0 -0
  36. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/settings_config.py +0 -0
  37. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/simple_vehicle.py +0 -0
  38. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/simulation.py +0 -0
  39. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/smart_charging.py +0 -0
  40. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/standalone.py +0 -0
  41. {eflips_depot-3.2.3 → eflips_depot-3.2.5}/eflips/depot/validation.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: eflips-depot
3
- Version: 3.2.3
3
+ Version: 3.2.5
4
4
  Summary: Depot Simulation for eFLIPS
5
5
  Home-page: https://github.com/mpm-tu-berlin/eflips-depot
6
6
  License: AGPL-3.0-or-later
@@ -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, auto
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 SmartChargingStragegy(Enum):
71
+ class SmartChargingStrategy(Enum):
72
72
  """Enum class for different smart charging strategies."""
73
73
 
74
- NONE = auto
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 = auto
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 = auto
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
- assert next_event is not None
426
- assert next_event.event_type == EventType.STANDBY_DEPARTURE
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: SmartChargingStragegy = SmartChargingStragegy.EVEN,
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
- match smart_charging_strategy:
501
- case SmartChargingStragegy.NONE:
502
- pass
503
- case SmartChargingStragegy.EVEN:
504
- apply_even_smart_charging(scenario, database_url)
505
- case SmartChargingStragegy.MIN_PRICE:
506
- raise NotImplementedError("MIN_PRICE strategy is not implemented yet.")
507
- case _:
508
- raise NotImplementedError()
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 = (mean_occupancy / (total_occupancy)) * params_for_event[
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
- optimized_power = (
124
- params_for_event["charging_allowed"] * mean_power * charging_factor
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
- assert post_opt_energy >= params_for_event["transferred_energy"]
153
- # Make it fit exactly
154
- optimized_power = optimized_power * (
155
- params_for_event["transferred_energy"] / post_opt_energy
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.subplot(3, 1, 1)
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
- plt.plot(total_time, total_power, label="Original power draw")
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
- plt.plot(total_time, optimized_power, label="Optimized power draw")
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
- plt.plot(total_time, optimized_power2, label="Mean power draw")
185
- plt.xlabel("Time")
186
- plt.ylabel("Total power draw (kW)")
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
- plt.axhline(
253
+ axs[0].axhline(
189
254
  y=max(total_power), color="blue", linestyle="--", label="Max power draw"
190
255
  )
191
- plt.axhline(
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
- plt.axhline(
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
- plt.plot(total_time, total_energy, label="Original energy transferred")
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
- plt.plot(total_time, optimized_energy, label="Optimized energy transferred")
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
- plt.plot(total_time, optimized_energy2, label="Mean energy transferred")
216
- plt.xlabel("Time")
217
- plt.ylabel("Total energy transferred (kWh)")
218
-
219
- plt.subplot(3, 1, 3)
220
- plt.plot(total_time, total_occupancy)
221
- plt.xlabel("Time")
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
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "eflips-depot"
3
- version = "3.2.3"
3
+ version = "3.2.5"
4
4
  description = "Depot Simulation for eFLIPS"
5
5
  authors = ["Enrico Lauth <enrico.lauth@tu-berlin.de>",
6
6
  "Ludger Heide <ludger.heide@tu-berlin.de",
File without changes
File without changes