eflips-depot 4.15.1__py3-none-any.whl → 4.15.6__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.
@@ -685,7 +685,9 @@ def simulate_scenario(
685
685
  case SmartChargingStrategy.NONE:
686
686
  pass
687
687
  case SmartChargingStrategy.EVEN:
688
- apply_even_smart_charging(scenario, database_url)
688
+ apply_even_smart_charging(
689
+ scenario, database_url, delete_existing_charging_timeseries=True
690
+ )
689
691
  case SmartChargingStrategy.MIN_PRICE:
690
692
  raise NotImplementedError("MIN_PRICE strategy is not implemented yet.")
691
693
  case _:
@@ -126,20 +126,27 @@ class DepotConfigurationWish:
126
126
  self.areas = areas
127
127
 
128
128
  if self.auto_generate is True:
129
- if self.default_power is None or self.standard_block_length is None:
130
- raise ValueError(
131
- "If auto_generate is True, default_power, standard_block_length, cleaning_slots, cleaning_duration and shunting_slots must be provided."
132
- )
133
- if (
134
- self.cleaning_slots is not None
135
- or self.cleaning_duration is not None
136
- or self.shunting_slots is not None
137
- or self.shunting_duration is not None
138
- ):
139
- raise ValueError(
140
- "If auto_generate is True, default_power, standard_block_length, cleaning_slots, cleaning_duration and shunting_slots cannot be provided."
141
- )
142
- # do some simple validation here
129
+ assert (
130
+ self.default_power is not None
131
+ ), "default_power must be provided if auto_generate is True"
132
+ assert (
133
+ self.standard_block_length is not None
134
+ ), "standard_block_length must be provided if auto_generate is True"
135
+
136
+ assert (
137
+ self.cleaning_slots is None
138
+ ), "cleaning_slots cannot be provided if auto_generate is True"
139
+ assert (
140
+ self.cleaning_duration is None
141
+ ), "cleaning_duration cannot be provided if auto_generate is True"
142
+ assert (
143
+ self.shunting_slots is None
144
+ ), "shunting_slots cannot be provided if auto_generate is True"
145
+ assert (
146
+ self.shunting_duration is None
147
+ ), "shunting_duration cannot be provided if auto_generate is True"
148
+
149
+ assert areas is None, "areas cannot be provided if auto_generate is True"
143
150
 
144
151
 
145
152
  def delete_depots(scenario: Scenario, session: Session) -> None:
@@ -230,7 +237,7 @@ def depot_to_template(depot: Depot) -> Dict[str, str | Dict[str, str | int]]:
230
237
  if process_type(processes_in_area) == ProcessType.CHARGING:
231
238
  # Add the charging process for this vehicle type
232
239
  template["areas"][area_name]["available_processes"].append(
233
- str(processes_in_area.id) + str(area.vehicle_type_id)
240
+ str(processes_in_area.id) + "vt" + str(area.vehicle_type_id)
234
241
  )
235
242
  # Delete the original charging process
236
243
  template["areas"][area_name]["available_processes"].remove(
@@ -253,7 +260,7 @@ def depot_to_template(depot: Depot) -> Dict[str, str | Dict[str, str | int]]:
253
260
  # Add the charging process for this vehicle type
254
261
  for vt in scenario.vehicle_types:
255
262
  template["areas"][area_name]["available_processes"].append(
256
- str(processes_in_area.id) + str(vt.id)
263
+ str(processes_in_area.id) + "vt" + str(vt.id)
257
264
  )
258
265
  # Delete the original charging process
259
266
  template["areas"][area_name]["available_processes"].remove(
@@ -386,30 +393,31 @@ def depot_to_template(depot: Depot) -> Dict[str, str | Dict[str, str | int]]:
386
393
 
387
394
  for vt in all_vehicle_types:
388
395
  charging_curve = vt.charging_curve
389
- template["processes"][process_name + str(vt.id)] = template[
396
+
397
+ charging_process_name = process_name + "vt" + str(vt.id)
398
+ template["processes"][charging_process_name] = template[
390
399
  "processes"
391
400
  ][process_name].copy()
392
- template["processes"][process_name + str(vt.id)][
401
+ template["processes"][charging_process_name][
393
402
  "typename"
394
403
  ] = "ChargeEquationSteps"
395
- template["processes"][process_name + str(vt.id)][
396
- "vehicle_filter"
397
- ] = {
404
+ template["processes"][charging_process_name]["vehicle_filter"] = {
398
405
  "filter_names": ["vehicle_type"],
399
406
  "vehicle_types": [str(vt.id)],
400
407
  }
401
408
 
402
- template["processes"][process_name + str(vt.id)][
409
+ template["processes"][charging_process_name][
403
410
  "peq_name"
404
411
  ] = "charging_curve_power"
405
- template["processes"][process_name + str(vt.id)]["peq_params"] = {
412
+ template["processes"][charging_process_name]["peq_params"] = {
406
413
  "soc": [soc_power_pair[0] for soc_power_pair in charging_curve],
407
414
  "power": [
408
415
  soc_power_pair[1] for soc_power_pair in charging_curve
409
416
  ],
417
+ "precision": 0.01,
410
418
  }
411
419
 
412
- del template["processes"][process_name + str(vt.id)]["dur"]
420
+ del template["processes"][charging_process_name]["dur"]
413
421
 
414
422
  # delete the original process
415
423
  del template["processes"][process_name]
@@ -1195,7 +1203,9 @@ def depot_smallest_possible_size(
1195
1203
 
1196
1204
  # Simulate the depot
1197
1205
  simulate_scenario(
1198
- scenario, smart_charging_strategy=SmartChargingStrategy.NONE
1206
+ scenario,
1207
+ smart_charging_strategy=SmartChargingStrategy.NONE,
1208
+ ignore_unstable_simulation=True,
1199
1209
  )
1200
1210
 
1201
1211
  # Find the peak usage of the depot
@@ -1259,12 +1269,6 @@ def depot_smallest_possible_size(
1259
1269
 
1260
1270
  except MissingVehicleDimensionError as e:
1261
1271
  raise e
1262
- except UnstableSimulationException as e:
1263
- # This change is made after Unstable exception and delay exceptions are introduced
1264
- logger.debug(
1265
- f"Results are unstable, suggesting depot is too small."
1266
- )
1267
- continue
1268
1272
  except DelayedTripException as e:
1269
1273
  logger.debug(f"Trips are delayed, suggesting depot is too small.")
1270
1274
  continue
@@ -1274,6 +1278,10 @@ def depot_smallest_possible_size(
1274
1278
  # Identify the best configuration for each vehicle type
1275
1279
  ret_val: Dict[VehicleType, Dict[AreaType, int]] = dict()
1276
1280
  for vt in vts_and_rotations.keys():
1281
+ assert area_needed[vt] != {}, (
1282
+ f"No valid configurations found for {vt.name}, "
1283
+ f"please check if there are any delays after simulating scenario."
1284
+ )
1277
1285
  best_config = min(area_needed[vt].keys(), key=lambda x: area_needed[vt][x])
1278
1286
  ret_val[vt] = {
1279
1287
  AreaType.LINE: best_config * standard_block_length,
@@ -1,6 +1,7 @@
1
1
  import datetime
2
2
  import itertools
3
3
  import logging
4
+ import math
4
5
  import warnings
5
6
  from datetime import timedelta
6
7
  from typing import List, Dict
@@ -398,6 +399,10 @@ def add_soc_to_events(dict_of_events, battery_log) -> None:
398
399
  """
399
400
  battery_log_list = []
400
401
  for log in battery_log:
402
+ # TODO this is a bypass of update events having lower energy_real than the event before. It happens in processes L 1304
403
+ if log.event_name == "update":
404
+ continue
405
+
401
406
  battery_log_list.append((log.t, round(log.energy / log.energy_real, 4)))
402
407
 
403
408
  time_keys = sorted(dict_of_events.keys())
@@ -522,7 +527,7 @@ def add_events_into_database(
522
527
  if "timeseries" in process_dict.keys():
523
528
  # Convert "time" in timeseries to timedelta
524
529
  timeseries["time"] = [
525
- (timedelta(seconds=t) + simulation_start_time).isoformat()
530
+ (timedelta(seconds=math.ceil(t)) + simulation_start_time).isoformat()
526
531
  for t in process_dict["timeseries"]["time"]
527
532
  ]
528
533
  timeseries["soc"] = process_dict["timeseries"]["soc"]
@@ -540,8 +545,9 @@ def add_events_into_database(
540
545
  area_id=area_id,
541
546
  subloc_no=process_dict["slot"] if "slot" in process_dict.keys() else 00,
542
547
  trip_id=None,
543
- time_start=timedelta(seconds=start_time) + simulation_start_time,
544
- time_end=timedelta(seconds=process_dict["end"]) + simulation_start_time,
548
+ time_start=timedelta(seconds=math.ceil(start_time)) + simulation_start_time,
549
+ time_end=timedelta(seconds=math.ceil(process_dict["end"]))
550
+ + simulation_start_time,
545
551
  soc_start=process_dict["soc_start"]
546
552
  if process_dict["soc_start"] is not None
547
553
  else process_dict["soc_end"],
@@ -102,6 +102,7 @@ def vehicle_type_to_global_constants_dict(vt: VehicleType) -> Dict[str, float]:
102
102
  "soc_max": 1.0,
103
103
  "soc_init": 1.0,
104
104
  "soh": 1.0,
105
+ "charging_efficiency": vt.charging_efficiency,
105
106
  }
106
107
  return the_dict
107
108
 
eflips/depot/processes.py CHANGED
@@ -840,6 +840,7 @@ class Charge(ChargeAbstract):
840
840
 
841
841
  @property
842
842
  def power(self):
843
+ # TODO this doesn't consider vehicle charging power
843
844
  return self.charging_interface.max_power
844
845
 
845
846
  def _action(self, *args, **kwargs):
@@ -1240,6 +1241,8 @@ class ChargeEquationSteps(ChargeAbstract):
1240
1241
  self.precision = precision
1241
1242
  Charge.check_soc_target(soc_target, vehicle_filter)
1242
1243
  self.soc_target = soc_target
1244
+ if "precision" in self.peq_params:
1245
+ self.precision = self.peq_params["precision"]
1243
1246
 
1244
1247
  @property
1245
1248
  def power(self):
@@ -1271,8 +1274,12 @@ class ChargeEquationSteps(ChargeAbstract):
1271
1274
  )
1272
1275
  soc_target_step = self.vehicle.battery.soc + soc_interval
1273
1276
  amount = self.vehicle.battery.energy_real * soc_interval
1274
- effective_power = self.power * self.efficiency
1275
- self.dur = int(amount / effective_power * 3600)
1277
+ effective_power = (
1278
+ self.power
1279
+ * self.efficiency
1280
+ * self.vehicle.vehicle_type.charging_efficiency
1281
+ )
1282
+ self.dur = round(amount / effective_power * 3600, 12)
1276
1283
 
1277
1284
  if self.dur == 0:
1278
1285
  # amount is so small that dur is <1s. Reduce the precision
@@ -1295,6 +1302,7 @@ class ChargeEquationSteps(ChargeAbstract):
1295
1302
  yield self.env.timeout(self.dur)
1296
1303
 
1297
1304
  if soc_target_step < self.soc_target:
1305
+ # TODO why here we have energy higher than the step_soc_target?
1298
1306
  # recalculate amount because update_battery may have been
1299
1307
  # called in the meantime
1300
1308
  amount_step = (
@@ -1438,13 +1446,21 @@ def charging_curve_power(vehicle, charging_interface, peq_params):
1438
1446
  :return: charging power in float for given SimpleVehicle
1439
1447
  """
1440
1448
 
1449
+ precision = peq_params.get("precision", 0.01)
1441
1450
  current_soc = vehicle.battery.soc
1442
1451
  p_max = charging_interface.max_power
1452
+ target_step_soc = min(vehicle.battery.soc + precision, vehicle.battery.soc_max)
1443
1453
 
1444
- current_power = min(
1454
+ power_current_soc = min(
1445
1455
  p_max, np.interp(current_soc, peq_params["soc"], peq_params["power"])
1446
1456
  )
1447
1457
 
1458
+ power_target_soc = min(
1459
+ p_max, np.interp(target_step_soc, peq_params["soc"], peq_params["power"])
1460
+ )
1461
+
1462
+ current_power = min(power_current_soc, power_target_soc)
1463
+
1448
1464
  return float(current_power)
1449
1465
 
1450
1466
 
eflips/depot/rating.py CHANGED
@@ -422,7 +422,7 @@ class RfdDiffDispatch:
422
422
  diffs = []
423
423
  for vehicle in area.vehicles:
424
424
  etc = vehicle.dwd.etc_processes
425
- if isinstance(etc, int):
425
+ if isinstance(etc, int) or isinstance(etc, float):
426
426
  diff = etc - slot[0].env.now
427
427
  diffs.append(diff)
428
428
  # Convert EstimateValue to numerical rfddiff
@@ -36,7 +36,17 @@ class VehicleType:
36
36
 
37
37
  """
38
38
 
39
- def __init__(self, ID, battery_capacity, soc_min, soc_max, soc_init, soh, CR=None):
39
+ def __init__(
40
+ self,
41
+ ID,
42
+ battery_capacity,
43
+ soc_min,
44
+ soc_max,
45
+ soc_init,
46
+ soh,
47
+ charging_efficiency=1.0,
48
+ CR=None,
49
+ ):
40
50
  self.ID = ID
41
51
  self.battery_capacity = battery_capacity
42
52
  self.soc_min = soc_min
@@ -45,6 +55,7 @@ class VehicleType:
45
55
  self.soh = soh
46
56
  self.CR = CR
47
57
  self.group = None
58
+ self.charging_efficiency = charging_efficiency
48
59
 
49
60
  self.count = {}
50
61
  self.share = {}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: eflips-depot
3
- Version: 4.15.1
3
+ Version: 4.15.6
4
4
  Summary: Depot Simulation for eFLIPS
5
5
  License: AGPL-3.0-or-later
6
6
  License-File: LICENSE.md
@@ -1,11 +1,11 @@
1
1
  eflips/depot/__init__.py,sha256=FCVnYU7aSfR4BNCo722I1V3uU5336qr1tTt-zT6X4UI,1555
2
- eflips/depot/api/__init__.py,sha256=nq5aHGTOIpDmvDfcGMlCH_jd97E0VZ28KVcT3XTwpbE,67539
2
+ eflips/depot/api/__init__.py,sha256=HvPtHi55hXwGgxD_DcYZxUnws1KRkKnezxI3Bao9TTg,67619
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=494u6FelymWfI-Yt3ybJpLHUL-6zEqBOT2qSrPhRmMo,30038
6
- eflips/depot/api/private/depot.py,sha256=Vx6mC5YynyQ5hEw9QeXAi84VSaYc3qVJAqE2dSfHGJI,59655
7
- eflips/depot/api/private/results_to_database.py,sha256=-8qXk8lRsMElm9pke6MWzCNUQKtrd59n4Ye2X8Ojw-M,29814
8
- eflips/depot/api/private/util.py,sha256=rZzyfEYYhF55f6QkiXjwMvJkg98KeHx8XN4Z1OwtSU8,18287
6
+ eflips/depot/api/private/depot.py,sha256=5w2g8Ki6HqR5LRfCgU2sF72jG6EDixqIOTHq2NpWZBY,59864
7
+ eflips/depot/api/private/results_to_database.py,sha256=7gQMPPQpOrArFE3R_8Fni6jK8IZsd5SoNdUh2Zt6pJA,30060
8
+ eflips/depot/api/private/util.py,sha256=e7T_-1AUXoCV9c11zaED2-za7p0TDhYG4Dg0lBZnrZI,18342
9
9
  eflips/depot/configuration.py,sha256=Op3hlir-dEN7yHr0kTqbYANoCBKFWK6uKOv3NJl8w_w,35678
10
10
  eflips/depot/depot.py,sha256=5NBw5bvOP2cplkRGZbKbG3SOA23F2Kw-UsabHubocPU,107555
11
11
  eflips/depot/evaluation.py,sha256=qqXyP4jA1zFcKuWhliQ6n25ZlGl9mJV-vtXf0yu8WN8,140842
@@ -27,16 +27,16 @@ eflips/depot/layout_opt/settings.py,sha256=EUGCp4dAX22j2uF8sKqbi9a5iP8hb6QpP7t2N
27
27
  eflips/depot/layout_opt/template_creation.py,sha256=H4LoFjQfbPjTt9rGvapH2tEUWcQ56kPwDucq7t6YahU,9736
28
28
  eflips/depot/layout_opt/util.py,sha256=EYh7IN58ZjysmCFdSieQqIQ9goe1a_ZwARRHxOgjEQo,3780
29
29
  eflips/depot/plots.py,sha256=85xInZWfJIOVm03onvppgP5yLTgQeMn-1t5aoNdavyY,2509
30
- eflips/depot/processes.py,sha256=n4p_TDvtCDdkagLyX8eJbFFxext3fpVTTfbrGsCO52o,59321
31
- eflips/depot/rating.py,sha256=audUASHExeWg5ugytPLlcy5QGiTiFucnZ6-v3REoO2g,16427
30
+ eflips/depot/processes.py,sha256=2ovkJuyBCHT3L4JudePVGVqdk_KKnGQXorndqdEFqsQ,60017
31
+ eflips/depot/rating.py,sha256=WjySy_cT3CtKLFaCCCVZB1f7qCYRyNFxAnM6IgJW7Ro,16453
32
32
  eflips/depot/resources.py,sha256=0SuzN8qgMmCqa7oUEXVC_XE6pCUtxTsqOfCsaM9Oh3o,13568
33
33
  eflips/depot/settings_config.py,sha256=z7CqPdjd8QRlgZj0Zis-H13cL7LOiheRT4ctYCYGguc,2527
34
- eflips/depot/simple_vehicle.py,sha256=Wl3IqYxMrs6J0U0iCrG3Qq8ONuDGoZ00r7h7svVyEik,9375
34
+ eflips/depot/simple_vehicle.py,sha256=-fqHhuyC1KXhl53zCZh8x8NUQnuz4EpZ6oLtaTaRqFw,9534
35
35
  eflips/depot/simulation.py,sha256=ee0qTzOzG-8ybN36ie_NJallXfC7jUaS9JZvaYFziLs,10676
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.15.1.dist-info/METADATA,sha256=K-X0YzOgpwV6fXCxQxDZP9h_uKiOVMZMKdPz2uu2c_k,5961
40
- eflips_depot-4.15.1.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
41
- eflips_depot-4.15.1.dist-info/licenses/LICENSE.md,sha256=KB4XTk1fPHjtZCYDyPyreu6h1LVJVZXYg-5vePcWZAc,34143
42
- eflips_depot-4.15.1.dist-info/RECORD,,
39
+ eflips_depot-4.15.6.dist-info/METADATA,sha256=9nnGlmtfW4-SdK24I21ZAoYZBKlnhTntfcpj_5nJ8w0,5961
40
+ eflips_depot-4.15.6.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
41
+ eflips_depot-4.15.6.dist-info/licenses/LICENSE.md,sha256=KB4XTk1fPHjtZCYDyPyreu6h1LVJVZXYg-5vePcWZAc,34143
42
+ eflips_depot-4.15.6.dist-info/RECORD,,