eflips-depot 4.6.3__py3-none-any.whl → 4.6.5__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.
@@ -48,6 +48,7 @@ from eflips.model import (
48
48
  VehicleType,
49
49
  AreaType,
50
50
  ChargeType,
51
+ Route,
51
52
  )
52
53
  from sqlalchemy.orm import Session
53
54
 
@@ -246,7 +247,11 @@ def simple_consumption_simulation(
246
247
  session.query(Rotation)
247
248
  .filter(Rotation.scenario_id == scenario.id)
248
249
  .order_by(Rotation.id)
249
- .options(sqlalchemy.orm.joinedload(Rotation.trips).joinedload(Trip.route))
250
+ .options(
251
+ sqlalchemy.orm.joinedload(Rotation.trips)
252
+ .joinedload(Trip.route)
253
+ .joinedload(Route.arrival_station)
254
+ )
250
255
  .options(sqlalchemy.orm.joinedload(Rotation.vehicle_type))
251
256
  .options(sqlalchemy.orm.joinedload(Rotation.vehicle))
252
257
  )
@@ -789,6 +794,10 @@ def init_simulation(
789
794
  if "None" in vehicle_types_for_depot:
790
795
  vehicle_types_for_depot.remove("None")
791
796
 
797
+ # In this case, all types are allowed
798
+ if len(vehicle_types_for_depot) == 0:
799
+ vehicle_types_for_depot = set([str(vt.id) for vt in scenario.vehicle_types])
800
+
792
801
  # If we have a vehicle count dictionary, we validate and use ir
793
802
  if vehicle_count_dict is not None and depot_id in vehicle_count_dict.keys():
794
803
  if set(vehicle_count_dict[depot_id].keys()) < vehicle_types_for_depot:
@@ -804,8 +813,11 @@ def init_simulation(
804
813
  for vehicle_type in vehicle_types_for_depot:
805
814
  vehicle_count = 0
806
815
  for area in depot.areas:
807
- if area.vehicle_type_id == int(vehicle_type):
808
- # TODO potential edit if we make vehicle type of an area a list
816
+ if (
817
+ area.vehicle_type_id == int(vehicle_type)
818
+ or area.vehicle_type_id is None
819
+ ):
820
+ # The areas allow either one type, or all vehicle types
809
821
  for p in area.processes:
810
822
  if p.electric_power is not None and p.duration is None:
811
823
  vehicle_count += area.capacity
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ import warnings
2
3
  from datetime import timedelta, datetime
3
4
  from math import ceil
4
5
  from typing import Tuple
@@ -7,7 +8,6 @@ from zoneinfo import ZoneInfo
7
8
  import numpy as np
8
9
  import sqlalchemy.orm
9
10
  from eflips.model import (
10
- Area,
11
11
  Event,
12
12
  EventType,
13
13
  Rotation,
@@ -15,6 +15,7 @@ from eflips.model import (
15
15
  Trip,
16
16
  Station,
17
17
  ChargeType,
18
+ ConsistencyWarning,
18
19
  )
19
20
 
20
21
 
@@ -51,7 +52,7 @@ def initialize_vehicle(rotation: Rotation, session: sqlalchemy.orm.session.Sessi
51
52
 
52
53
  def add_initial_standby_event(
53
54
  vehicle: Vehicle, session: sqlalchemy.orm.session.Session
54
- ):
55
+ ) -> None:
55
56
  """
56
57
  Create and add a standby event immediately before the earliest trip of the given vehicle.
57
58
 
@@ -76,25 +77,20 @@ def add_initial_standby_event(
76
77
  ``None``. A new event is added to the session for the earliest trip,
77
78
  but changes are not yet committed.
78
79
  """
79
- logger = logging.getLogger(__name__)
80
-
81
- rotation_per_vehicle = sorted(
82
- vehicle.rotations, key=lambda r: r.trips[0].departure_time
83
- )
84
-
85
- # Only keep the rotations that contain trips
86
- rotation_per_vehicle = [r for r in rotation_per_vehicle if len(r.trips) > 0]
87
- if len(rotation_per_vehicle) == 0:
88
- logger.warning(f"No trips found for vehicle {vehicle.id}.")
89
- return
90
80
 
91
- earliest_trip = rotation_per_vehicle[0].trips[0]
92
- area = (
93
- session.query(Area)
94
- .filter(Area.scenario_id == vehicle.scenario_id)
95
- .filter(Area.vehicle_type_id == vehicle.vehicle_type_id)
81
+ earliest_trip = (
82
+ session.query(Trip)
83
+ .join(Rotation)
84
+ .filter(Rotation.vehicle == vehicle)
85
+ .order_by(Trip.departure_time)
96
86
  .first()
97
87
  )
88
+ if earliest_trip is None:
89
+ warnings.warn(
90
+ f"No trips found for vehicle {vehicle.id}. Cannot add initial standby event.",
91
+ ConsistencyWarning,
92
+ )
93
+ return
98
94
 
99
95
  standby_start = earliest_trip.departure_time - timedelta(seconds=1)
100
96
  standby_event = Event(
@@ -148,15 +144,11 @@ def find_charger_occupancy(
148
144
  (shape: ``(n,)``), indicating how many charging events are active.
149
145
  """
150
146
  # Load all charging events that could be relevant
151
- charging_events = (
152
- session.query(Event)
153
- .filter(
154
- Event.event_type == EventType.CHARGING_OPPORTUNITY,
155
- Event.station_id == station.id,
156
- Event.time_start < time_end,
157
- Event.time_end > time_start,
158
- )
159
- .all()
147
+ charging_events_q = session.query(Event).filter(
148
+ Event.event_type == EventType.CHARGING_OPPORTUNITY,
149
+ Event.station_id == station.id,
150
+ Event.time_start < time_end,
151
+ Event.time_end > time_start,
160
152
  )
161
153
 
162
154
  # We need to change the times to numpy datetime64 with implicit UTC timezone
@@ -166,7 +158,7 @@ def find_charger_occupancy(
166
158
 
167
159
  times = np.arange(time_start, time_end, resolution)
168
160
  occupancy = np.zeros_like(times, dtype=int)
169
- for event in charging_events:
161
+ for event in charging_events_q:
170
162
  event_start = np.datetime64(
171
163
  event.time_start.astimezone(tz).replace(tzinfo=None)
172
164
  )
@@ -272,9 +264,11 @@ def attempt_opportunity_charging_event(
272
264
 
273
265
  # Sanity checks
274
266
  if previous_trip.route.arrival_station_id != next_trip.route.departure_station_id:
275
- raise ValueError(
276
- f"Trips {previous_trip.id} and {next_trip.id} are not consecutive."
267
+ warnings.warn(
268
+ f"Trips {previous_trip.id} and {next_trip.id} are not consecutive.",
269
+ ConsistencyWarning,
277
270
  )
271
+ return charge_start_soc
278
272
  if previous_trip.rotation_id != next_trip.rotation_id:
279
273
  raise ValueError(
280
274
  f"Trips {previous_trip.id} and {next_trip.id} are not in the same rotation."
@@ -111,7 +111,13 @@ def depot_to_template(depot: Depot) -> Dict[str, str | Dict[str, str | int]]:
111
111
  }
112
112
  else:
113
113
  # If the vehicle type id is not set, the area is for all vehicle types
114
- template["areas"][area_name]["entry_filter"] = dict()
114
+ scenario = depot.scenario
115
+ all_vehicle_type_ids = [str(vt.id) for vt in scenario.vehicle_types]
116
+
117
+ template["areas"][area_name]["entry_filter"] = {
118
+ "filter_names": ["vehicle_type"],
119
+ "vehicle_types": all_vehicle_type_ids,
120
+ }
115
121
 
116
122
  for process in area.processes:
117
123
  # Add process into process list
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: eflips-depot
3
- Version: 4.6.3
3
+ Version: 4.6.5
4
4
  Summary: Depot Simulation for eFLIPS
5
5
  License: AGPL-3.0-or-later
6
6
  Author: Enrico Lauth
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Classifier: Programming Language :: Python :: 3.13
15
15
  Requires-Dist: eflips (>=0.1.3,<0.2.0)
16
- Requires-Dist: eflips-model (>=6.0.4,<7.0.0)
16
+ Requires-Dist: eflips-model (>=6.0.6,<7.0.0)
17
17
  Requires-Dist: pandas (>=2.2.0,<3.0.0)
18
18
  Requires-Dist: scipy (>=1.14.0,<2.0.0)
19
19
  Requires-Dist: simpy (>=4.0.1,<5.0.0)
@@ -1,9 +1,9 @@
1
1
  eflips/depot/__init__.py,sha256=RQ_UKNrGWA6q17TZFu86ai8pC7qCpcbmAgVKh7aImwo,1613
2
- eflips/depot/api/__init__.py,sha256=Sxsqj5qIcSK-dqtE2UqaHVWEWnycU65N-pDnLuTJfeU,48244
2
+ eflips/depot/api/__init__.py,sha256=0ifYtEwSs2LbpPINxdDsGNxdywKRicCQBETB7BpBh9Y,48631
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=k-YYeBTvlKBAE-YSoPSiJofsz6VmazRn__Qe238mE2w,16616
6
- eflips/depot/api/private/depot.py,sha256=v5Edb0sQP2QNIyBLvccVzAK9_kxCszar0cOu5ciFyrw,40780
5
+ eflips/depot/api/private/consumption.py,sha256=vDPCogd3NPx2duCUhg_CcW9rMQWgrppfqsS4E7W9T1Y,16400
6
+ eflips/depot/api/private/depot.py,sha256=WcCcib3NSbvoL3G06I2ajT8U5L7AkDK5qe969PHq-fg,41014
7
7
  eflips/depot/api/private/results_to_database.py,sha256=Sh2VJ3k60QJ5RGkc8sw-7XbljiMe65EHeoagKIpYlHM,24585
8
8
  eflips/depot/api/private/smart_charging.py,sha256=MQ9fXdKByHAz6RSKXYcpJXDBccdJKZ2qGReCHagVCyo,13033
9
9
  eflips/depot/api/private/util.py,sha256=gk5TJZrcvtkyrqnjR3Cq-hPRGRCovhzKz3LrBDIvN0E,16799
@@ -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.3.dist-info/LICENSE.md,sha256=KB4XTk1fPHjtZCYDyPyreu6h1LVJVZXYg-5vePcWZAc,34143
41
- eflips_depot-4.6.3.dist-info/METADATA,sha256=8mi6aRYWW1DOT4QkR5UytrBAoOK6OKHj6G3N1Ykiw00,5940
42
- eflips_depot-4.6.3.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
43
- eflips_depot-4.6.3.dist-info/RECORD,,
40
+ eflips_depot-4.6.5.dist-info/LICENSE.md,sha256=KB4XTk1fPHjtZCYDyPyreu6h1LVJVZXYg-5vePcWZAc,34143
41
+ eflips_depot-4.6.5.dist-info/METADATA,sha256=aPK2OCraATDQr-H1kBZGqyZkj1fC0ZUBecES6EFCyoU,5940
42
+ eflips_depot-4.6.5.dist-info/WHEEL,sha256=IYZQI976HJqqOpQU6PHkJ8fb3tMNBFjg-Cn-pwAbaFM,88
43
+ eflips_depot-4.6.5.dist-info/RECORD,,