flixopt 2.1.7__py3-none-any.whl → 2.1.8__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 flixopt might be problematic. Click here for more details.

flixopt/features.py CHANGED
@@ -3,18 +3,21 @@ This module contains the features of the flixopt framework.
3
3
  Features extend the functionality of Elements.
4
4
  """
5
5
 
6
+ from __future__ import annotations
7
+
6
8
  import logging
7
- from typing import Dict, List, Optional, Tuple, Union
9
+ from typing import TYPE_CHECKING
8
10
 
9
11
  import linopy
10
12
  import numpy as np
11
13
 
12
- from . import utils
13
14
  from .config import CONFIG
14
15
  from .core import NumericData, Scalar, TimeSeries
15
- from .interface import InvestParameters, OnOffParameters, Piecewise
16
16
  from .structure import Model, SystemModel
17
17
 
18
+ if TYPE_CHECKING:
19
+ from .interface import InvestParameters, OnOffParameters, Piecewise
20
+
18
21
  logger = logging.getLogger('flixopt')
19
22
 
20
23
 
@@ -26,16 +29,16 @@ class InvestmentModel(Model):
26
29
  model: SystemModel,
27
30
  label_of_element: str,
28
31
  parameters: InvestParameters,
29
- defining_variable: [linopy.Variable],
30
- relative_bounds_of_defining_variable: Tuple[NumericData, NumericData],
31
- label: Optional[str] = None,
32
- on_variable: Optional[linopy.Variable] = None,
32
+ defining_variable: linopy.Variable,
33
+ relative_bounds_of_defining_variable: tuple[NumericData, NumericData],
34
+ label: str | None = None,
35
+ on_variable: linopy.Variable | None = None,
33
36
  ):
34
37
  super().__init__(model, label_of_element, label)
35
- self.size: Optional[Union[Scalar, linopy.Variable]] = None
36
- self.is_invested: Optional[linopy.Variable] = None
38
+ self.size: Scalar | linopy.Variable | None = None
39
+ self.is_invested: linopy.Variable | None = None
37
40
 
38
- self.piecewise_effects: Optional[PiecewiseEffectsModel] = None
41
+ self.piecewise_effects: PiecewiseEffectsModel | None = None
39
42
 
40
43
  self._on_variable = on_variable
41
44
  self._defining_variable = defining_variable
@@ -205,14 +208,14 @@ class StateModel(Model):
205
208
  self,
206
209
  model: SystemModel,
207
210
  label_of_element: str,
208
- defining_variables: List[linopy.Variable],
209
- defining_bounds: List[Tuple[NumericData, NumericData]],
210
- previous_values: List[Optional[NumericData]] = None,
211
+ defining_variables: list[linopy.Variable],
212
+ defining_bounds: list[tuple[NumericData, NumericData]],
213
+ previous_values: list[NumericData | None] | None = None,
211
214
  use_off: bool = True,
212
- on_hours_total_min: Optional[NumericData] = 0,
213
- on_hours_total_max: Optional[NumericData] = None,
214
- effects_per_running_hour: Dict[str, NumericData] = None,
215
- label: Optional[str] = None,
215
+ on_hours_total_min: NumericData | None = 0,
216
+ on_hours_total_max: NumericData | None = None,
217
+ effects_per_running_hour: dict[str, NumericData] | None = None,
218
+ label: str | None = None,
216
219
  ):
217
220
  """
218
221
  Models binary state variables based on a continous variable.
@@ -240,7 +243,7 @@ class StateModel(Model):
240
243
  self._effects_per_running_hour = effects_per_running_hour or {}
241
244
 
242
245
  self.on = None
243
- self.total_on_hours: Optional[linopy.Variable] = None
246
+ self.total_on_hours: linopy.Variable | None = None
244
247
  self.off = None
245
248
 
246
249
  def do_modeling(self):
@@ -345,7 +348,7 @@ class StateModel(Model):
345
348
  return 1 - self.previous_states
346
349
 
347
350
  @staticmethod
348
- def compute_previous_states(previous_values: List[NumericData], epsilon: float = 1e-5) -> np.ndarray:
351
+ def compute_previous_states(previous_values: list[NumericData | None] | None, epsilon: float = 1e-5) -> np.ndarray:
349
352
  """Computes the previous states {0, 1} of defining variables as a binary array from their previous values."""
350
353
  if not previous_values or all([val is None for val in previous_values]):
351
354
  return np.array([0])
@@ -369,8 +372,8 @@ class SwitchStateModel(Model):
369
372
  label_of_element: str,
370
373
  state_variable: linopy.Variable,
371
374
  previous_state=0,
372
- switch_on_max: Optional[Scalar] = None,
373
- label: Optional[str] = None,
375
+ switch_on_max: Scalar | None = None,
376
+ label: str | None = None,
374
377
  ):
375
378
  super().__init__(model, label_of_element, label)
376
379
  self._state_variable = state_variable
@@ -454,10 +457,10 @@ class ConsecutiveStateModel(Model):
454
457
  model: SystemModel,
455
458
  label_of_element: str,
456
459
  state_variable: linopy.Variable,
457
- minimum_duration: Optional[NumericData] = None,
458
- maximum_duration: Optional[NumericData] = None,
459
- previous_states: Optional[NumericData] = None,
460
- label: Optional[str] = None,
460
+ minimum_duration: NumericData | None = None,
461
+ maximum_duration: NumericData | None = None,
462
+ previous_states: NumericData | None = None,
463
+ label: str | None = None,
461
464
  ):
462
465
  """
463
466
  Model and constraint the consecutive duration of a state variable.
@@ -576,7 +579,7 @@ class ConsecutiveStateModel(Model):
576
579
 
577
580
  @staticmethod
578
581
  def compute_consecutive_hours_in_state(
579
- binary_values: NumericData, hours_per_timestep: Union[int, float, np.ndarray]
582
+ binary_values: NumericData, hours_per_timestep: int | float | np.ndarray
580
583
  ) -> Scalar:
581
584
  """
582
585
  Computes the final consecutive duration in state 'on' (=1) in hours, from a binary array.
@@ -616,7 +619,7 @@ class ConsecutiveStateModel(Model):
616
619
  if len(hours_per_timestep) < nr_of_indexes_with_consecutive_ones:
617
620
  raise ValueError(
618
621
  f'When trying to calculate the consecutive duration, the length of the last duration '
619
- f'({len(nr_of_indexes_with_consecutive_ones)}) is longer than the provided hours_per_timestep ({len(hours_per_timestep)}), '
622
+ f'({nr_of_indexes_with_consecutive_ones}) is longer than the provided hours_per_timestep ({len(hours_per_timestep)}), '
620
623
  f'as {binary_values=}'
621
624
  )
622
625
 
@@ -637,10 +640,10 @@ class OnOffModel(Model):
637
640
  model: SystemModel,
638
641
  on_off_parameters: OnOffParameters,
639
642
  label_of_element: str,
640
- defining_variables: List[linopy.Variable],
641
- defining_bounds: List[Tuple[NumericData, NumericData]],
642
- previous_values: List[Optional[NumericData]],
643
- label: Optional[str] = None,
643
+ defining_variables: list[linopy.Variable],
644
+ defining_bounds: list[tuple[NumericData, NumericData]],
645
+ previous_values: list[NumericData | None],
646
+ label: str | None = None,
644
647
  ):
645
648
  """
646
649
  Constructor for OnOffModel
@@ -786,9 +789,9 @@ class PieceModel(Model):
786
789
  as_time_series: bool = True,
787
790
  ):
788
791
  super().__init__(model, label_of_element, label)
789
- self.inside_piece: Optional[linopy.Variable] = None
790
- self.lambda0: Optional[linopy.Variable] = None
791
- self.lambda1: Optional[linopy.Variable] = None
792
+ self.inside_piece: linopy.Variable | None = None
793
+ self.lambda0: linopy.Variable | None = None
794
+ self.lambda1: linopy.Variable | None = None
792
795
  self._as_time_series = as_time_series
793
796
 
794
797
  def do_modeling(self):
@@ -835,8 +838,8 @@ class PiecewiseModel(Model):
835
838
  self,
836
839
  model: SystemModel,
837
840
  label_of_element: str,
838
- piecewise_variables: Dict[str, Piecewise],
839
- zero_point: Optional[Union[bool, linopy.Variable]],
841
+ piecewise_variables: dict[str, Piecewise],
842
+ zero_point: bool | linopy.Variable | None,
840
843
  as_time_series: bool,
841
844
  label: str = '',
842
845
  ):
@@ -858,8 +861,8 @@ class PiecewiseModel(Model):
858
861
  self._zero_point = zero_point
859
862
  self._as_time_series = as_time_series
860
863
 
861
- self.pieces: List[PieceModel] = []
862
- self.zero_point: Optional[linopy.Variable] = None
864
+ self.pieces: list[PieceModel] = []
865
+ self.zero_point: linopy.Variable | None = None
863
866
 
864
867
  def do_modeling(self):
865
868
  for i in range(len(list(self._piecewise_variables.values())[0])):
@@ -922,30 +925,30 @@ class ShareAllocationModel(Model):
922
925
  self,
923
926
  model: SystemModel,
924
927
  shares_are_time_series: bool,
925
- label_of_element: Optional[str] = None,
926
- label: Optional[str] = None,
927
- label_full: Optional[str] = None,
928
- total_max: Optional[Scalar] = None,
929
- total_min: Optional[Scalar] = None,
930
- max_per_hour: Optional[NumericData] = None,
931
- min_per_hour: Optional[NumericData] = None,
928
+ label_of_element: str | None = None,
929
+ label: str | None = None,
930
+ label_full: str | None = None,
931
+ total_max: Scalar | None = None,
932
+ total_min: Scalar | None = None,
933
+ max_per_hour: NumericData | None = None,
934
+ min_per_hour: NumericData | None = None,
932
935
  ):
933
936
  super().__init__(model, label_of_element=label_of_element, label=label, label_full=label_full)
934
937
  if not shares_are_time_series: # If the condition is True
935
938
  assert max_per_hour is None and min_per_hour is None, (
936
939
  'Both max_per_hour and min_per_hour cannot be used when shares_are_time_series is False'
937
940
  )
938
- self.total_per_timestep: Optional[linopy.Variable] = None
939
- self.total: Optional[linopy.Variable] = None
940
- self.shares: Dict[str, linopy.Variable] = {}
941
- self.share_constraints: Dict[str, linopy.Constraint] = {}
941
+ self.total_per_timestep: linopy.Variable | None = None
942
+ self.total: linopy.Variable | None = None
943
+ self.shares: dict[str, linopy.Variable] = {}
944
+ self.share_constraints: dict[str, linopy.Constraint] = {}
942
945
 
943
- self._eq_total_per_timestep: Optional[linopy.Constraint] = None
944
- self._eq_total: Optional[linopy.Constraint] = None
946
+ self._eq_total_per_timestep: linopy.Constraint | None = None
947
+ self._eq_total: linopy.Constraint | None = None
945
948
 
946
949
  # Parameters
947
950
  self._shares_are_time_series = shares_are_time_series
948
- self._total_max = total_max if total_min is not None else np.inf
951
+ self._total_max = total_max if total_max is not None else np.inf
949
952
  self._total_min = total_min if total_min is not None else -np.inf
950
953
  self._max_per_hour = max_per_hour if max_per_hour is not None else np.inf
951
954
  self._min_per_hour = min_per_hour if min_per_hour is not None else -np.inf
@@ -1028,9 +1031,9 @@ class PiecewiseEffectsModel(Model):
1028
1031
  self,
1029
1032
  model: SystemModel,
1030
1033
  label_of_element: str,
1031
- piecewise_origin: Tuple[str, Piecewise],
1032
- piecewise_shares: Dict[str, Piecewise],
1033
- zero_point: Optional[Union[bool, linopy.Variable]],
1034
+ piecewise_origin: tuple[str, Piecewise],
1035
+ piecewise_shares: dict[str, Piecewise],
1036
+ zero_point: bool | linopy.Variable | None,
1034
1037
  label: str = 'PiecewiseEffects',
1035
1038
  ):
1036
1039
  super().__init__(model, label_of_element, label)
@@ -1040,9 +1043,9 @@ class PiecewiseEffectsModel(Model):
1040
1043
  self._zero_point = zero_point
1041
1044
  self._piecewise_origin = piecewise_origin
1042
1045
  self._piecewise_shares = piecewise_shares
1043
- self.shares: Dict[str, linopy.Variable] = {}
1046
+ self.shares: dict[str, linopy.Variable] = {}
1044
1047
 
1045
- self.piecewise_model: Optional[PiecewiseModel] = None
1048
+ self.piecewise_model: PiecewiseModel | None = None
1046
1049
 
1047
1050
  def do_modeling(self):
1048
1051
  self.shares = {
@@ -1100,7 +1103,7 @@ class PreventSimultaneousUsageModel(Model):
1100
1103
  def __init__(
1101
1104
  self,
1102
1105
  model: SystemModel,
1103
- variables: List[linopy.Variable],
1106
+ variables: list[linopy.Variable],
1104
1107
  label_of_element: str,
1105
1108
  label: str = 'PreventSimultaneousUsage',
1106
1109
  ):
flixopt/flow_system.py CHANGED
@@ -2,50 +2,71 @@
2
2
  This module contains the FlowSystem class, which is used to collect instances of many other classes by the end User.
3
3
  """
4
4
 
5
+ from __future__ import annotations
6
+
5
7
  import json
6
8
  import logging
7
- import pathlib
8
9
  import warnings
9
10
  from io import StringIO
10
- from typing import TYPE_CHECKING, Dict, List, Literal, Optional, Tuple, Union
11
+ from typing import TYPE_CHECKING, Literal
11
12
 
12
- import numpy as np
13
13
  import pandas as pd
14
- import xarray as xr
15
14
  from rich.console import Console
16
15
  from rich.pretty import Pretty
17
16
 
18
17
  from . import io as fx_io
19
- from .core import NumericData, NumericDataTS, TimeSeries, TimeSeriesCollection, TimeSeriesData
18
+ from .core import NumericData, TimeSeries, TimeSeriesCollection, TimeSeriesData
20
19
  from .effects import Effect, EffectCollection, EffectTimeSeries, EffectValuesDict, EffectValuesUser
21
20
  from .elements import Bus, Component, Flow
22
- from .structure import CLASS_REGISTRY, Element, SystemModel, get_compact_representation, get_str_representation
21
+ from .structure import CLASS_REGISTRY, Element, SystemModel
23
22
 
24
23
  if TYPE_CHECKING:
24
+ import pathlib
25
+
26
+ import numpy as np
25
27
  import pyvis
28
+ import xarray as xr
26
29
 
27
30
  logger = logging.getLogger('flixopt')
28
31
 
29
32
 
30
33
  class FlowSystem:
31
34
  """
32
- A FlowSystem organizes the high level Elements (Components & Effects).
35
+ A FlowSystem organizes the high level Elements (Components, Buses & Effects).
36
+
37
+ This is the main container class that users work with to build and manage their System.
38
+
39
+ Args:
40
+ timesteps: The timesteps of the model.
41
+ hours_of_last_timestep: The duration of the last time step. Uses the last time interval if not specified
42
+ hours_of_previous_timesteps: The duration of previous timesteps.
43
+ If None, the first time increment of time_series is used.
44
+ This is needed to calculate previous durations (for example consecutive_on_hours).
45
+ If you use an array, take care that its long enough to cover all previous values!
46
+
47
+ Notes:
48
+ - Creates an empty registry for components and buses, an empty EffectCollection, and a placeholder for a SystemModel.
49
+ - The instance starts disconnected (self._connected == False) and will be connected automatically when trying to solve a calculation.
33
50
  """
34
51
 
35
52
  def __init__(
36
53
  self,
37
54
  timesteps: pd.DatetimeIndex,
38
- hours_of_last_timestep: Optional[float] = None,
39
- hours_of_previous_timesteps: Optional[Union[int, float, np.ndarray]] = None,
55
+ hours_of_last_timestep: float | None = None,
56
+ hours_of_previous_timesteps: int | float | np.ndarray | None = None,
40
57
  ):
41
58
  """
42
- Args:
43
- timesteps: The timesteps of the model.
44
- hours_of_last_timestep: The duration of the last time step. Uses the last time interval if not specified
45
- hours_of_previous_timesteps: The duration of previous timesteps.
46
- If None, the first time increment of time_series is used.
47
- This is needed to calculate previous durations (for example consecutive_on_hours).
48
- If you use an array, take care that its long enough to cover all previous values!
59
+ Initialize a FlowSystem that manages components, buses, effects, and their time-series.
60
+
61
+ Parameters:
62
+ timesteps: DatetimeIndex defining the primary timesteps for the system's TimeSeriesCollection.
63
+ hours_of_last_timestep: Duration (in hours) of the final timestep; if None, inferred from timesteps or defaults in TimeSeriesCollection.
64
+ hours_of_previous_timesteps: Scalar or array-like durations (in hours) for the preceding timesteps; used to configure non-uniform timestep lengths.
65
+
66
+ Notes:
67
+ Creates an empty registry for components and buses, an empty EffectCollection, and a placeholder for a SystemModel.
68
+ The instance starts disconnected (self._connected == False) and with no active network visualization app.
69
+ This can also be triggered manually with `_connect_network()`.
49
70
  """
50
71
  self.time_series_collection = TimeSeriesCollection(
51
72
  timesteps=timesteps,
@@ -54,10 +75,10 @@ class FlowSystem:
54
75
  )
55
76
 
56
77
  # defaults:
57
- self.components: Dict[str, Component] = {}
58
- self.buses: Dict[str, Bus] = {}
78
+ self.components: dict[str, Component] = {}
79
+ self.buses: dict[str, Bus] = {}
59
80
  self.effects: EffectCollection = EffectCollection()
60
- self.model: Optional[SystemModel] = None
81
+ self.model: SystemModel | None = None
61
82
 
62
83
  self._connected = False
63
84
 
@@ -83,7 +104,7 @@ class FlowSystem:
83
104
  return flow_system
84
105
 
85
106
  @classmethod
86
- def from_dict(cls, data: Dict) -> 'FlowSystem':
107
+ def from_dict(cls, data: dict) -> FlowSystem:
87
108
  """
88
109
  Load a FlowSystem from a dictionary.
89
110
 
@@ -112,7 +133,7 @@ class FlowSystem:
112
133
  return flow_system
113
134
 
114
135
  @classmethod
115
- def from_netcdf(cls, path: Union[str, pathlib.Path]):
136
+ def from_netcdf(cls, path: str | pathlib.Path):
116
137
  """
117
138
  Load a FlowSystem from a netcdf file
118
139
  """
@@ -144,7 +165,7 @@ class FlowSystem:
144
165
  f'Tried to add incompatible object to FlowSystem: {type(new_element)=}: {new_element=} '
145
166
  )
146
167
 
147
- def to_json(self, path: Union[str, pathlib.Path]):
168
+ def to_json(self, path: str | pathlib.Path):
148
169
  """
149
170
  Saves the flow system to a json file.
150
171
  This not meant to be reloaded and recreate the object,
@@ -156,7 +177,7 @@ class FlowSystem:
156
177
  with open(path, 'w', encoding='utf-8') as f:
157
178
  json.dump(self.as_dict('stats'), f, indent=4, ensure_ascii=False)
158
179
 
159
- def as_dict(self, data_mode: Literal['data', 'name', 'stats'] = 'data') -> Dict:
180
+ def as_dict(self, data_mode: Literal['data', 'name', 'stats'] = 'data') -> dict:
160
181
  """Convert the object to a dictionary representation."""
161
182
  data = {
162
183
  'components': {
@@ -190,7 +211,7 @@ class FlowSystem:
190
211
  ds.attrs = self.as_dict(data_mode='name')
191
212
  return ds
192
213
 
193
- def to_netcdf(self, path: Union[str, pathlib.Path], compression: int = 0, constants_in_dataset: bool = True):
214
+ def to_netcdf(self, path: str | pathlib.Path, compression: int = 0, constants_in_dataset: bool = True):
194
215
  """
195
216
  Saves the FlowSystem to a netCDF file.
196
217
  Args:
@@ -204,15 +225,13 @@ class FlowSystem:
204
225
 
205
226
  def plot_network(
206
227
  self,
207
- path: Union[bool, str, pathlib.Path] = 'flow_system.html',
208
- controls: Union[
209
- bool,
210
- List[
211
- Literal['nodes', 'edges', 'layout', 'interaction', 'manipulation', 'physics', 'selection', 'renderer']
212
- ],
228
+ path: bool | str | pathlib.Path = 'flow_system.html',
229
+ controls: bool
230
+ | list[
231
+ Literal['nodes', 'edges', 'layout', 'interaction', 'manipulation', 'physics', 'selection', 'renderer']
213
232
  ] = True,
214
233
  show: bool = False,
215
- ) -> Optional['pyvis.network.Network']:
234
+ ) -> pyvis.network.Network | None:
216
235
  """
217
236
  Visualizes the network structure of a FlowSystem using PyVis, saving it as an interactive HTML file.
218
237
 
@@ -227,7 +246,7 @@ class FlowSystem:
227
246
  show: Whether to open the visualization in the web browser.
228
247
 
229
248
  Returns:
230
- - Optional[pyvis.network.Network]: The `Network` instance representing the visualization, or `None` if `pyvis` is not installed.
249
+ - 'pyvis.network.Network' | None: The `Network` instance representing the visualization, or `None` if `pyvis` is not installed.
231
250
 
232
251
  Examples:
233
252
  >>> flow_system.plot_network()
@@ -245,7 +264,7 @@ class FlowSystem:
245
264
 
246
265
  def start_network_app(self):
247
266
  """Visualizes the network structure of a FlowSystem using Dash, Cytoscape, and networkx.
248
- Requires optional dependencies: dash, dash-cytoscape, networkx, werkzeug.
267
+ Requires optional dependencies: dash, dash-cytoscape, dash-daq, networkx, flask, werkzeug.
249
268
  """
250
269
  from .network_app import DASH_CYTOSCAPE_AVAILABLE, VISUALIZATION_ERROR, flow_graph, shownetwork
251
270
 
@@ -258,7 +277,8 @@ class FlowSystem:
258
277
  if not DASH_CYTOSCAPE_AVAILABLE:
259
278
  raise ImportError(
260
279
  f'Network visualization requires optional dependencies. '
261
- f'Install with: pip install flixopt[viz], flixopt[full] or pip install dash dash_cytoscape networkx werkzeug. '
280
+ f'Install with: `pip install flixopt[network_viz]`, `pip install flixopt[full]` '
281
+ f'or: `pip install dash dash-cytoscape dash-daq networkx werkzeug`. '
262
282
  f'Original error: {VISUALIZATION_ERROR}'
263
283
  )
264
284
 
@@ -278,7 +298,8 @@ class FlowSystem:
278
298
  if not DASH_CYTOSCAPE_AVAILABLE:
279
299
  raise ImportError(
280
300
  f'Network visualization requires optional dependencies. '
281
- f'Install with: pip install flixopt[viz]. '
301
+ f'Install with: `pip install flixopt[network_viz]`, `pip install flixopt[full]` '
302
+ f'or: `pip install dash dash-cytoscape dash-daq networkx werkzeug`. '
282
303
  f'Original error: {VISUALIZATION_ERROR}'
283
304
  )
284
305
 
@@ -295,7 +316,7 @@ class FlowSystem:
295
316
  finally:
296
317
  self._network_app = None
297
318
 
298
- def network_infos(self) -> Tuple[Dict[str, Dict[str, str]], Dict[str, Dict[str, str]]]:
319
+ def network_infos(self) -> tuple[dict[str, dict[str, str]], dict[str, dict[str, str]]]:
299
320
  if not self._connected:
300
321
  self._connect_network()
301
322
  nodes = {
@@ -328,9 +349,9 @@ class FlowSystem:
328
349
  def create_time_series(
329
350
  self,
330
351
  name: str,
331
- data: Optional[Union[NumericData, TimeSeriesData, TimeSeries]],
352
+ data: NumericData | TimeSeriesData | TimeSeries | None,
332
353
  needs_extra_timestep: bool = False,
333
- ) -> Optional[TimeSeries]:
354
+ ) -> TimeSeries | None:
334
355
  """
335
356
  Tries to create a TimeSeries from NumericData Data and adds it to the time_series_collection
336
357
  If the data already is a TimeSeries, nothing happens and the TimeSeries gets reset and returned
@@ -353,10 +374,10 @@ class FlowSystem:
353
374
 
354
375
  def create_effect_time_series(
355
376
  self,
356
- label_prefix: Optional[str],
377
+ label_prefix: str | None,
357
378
  effect_values: EffectValuesUser,
358
- label_suffix: Optional[str] = None,
359
- ) -> Optional[EffectTimeSeries]:
379
+ label_suffix: str | None = None,
380
+ ) -> EffectTimeSeries | None:
360
381
  """
361
382
  Transform EffectValues to EffectTimeSeries.
362
383
  Creates a TimeSeries for each key in the nested_values dictionary, using the value as the data.
@@ -365,13 +386,13 @@ class FlowSystem:
365
386
  followed by the label of the Effect in the nested_values and the label_suffix.
366
387
  If the key in the EffectValues is None, the alias 'Standard_Effect' is used
367
388
  """
368
- effect_values: Optional[EffectValuesDict] = self.effects.create_effect_values_dict(effect_values)
369
- if effect_values is None:
389
+ effect_values_dict: EffectValuesDict | None = self.effects.create_effect_values_dict(effect_values)
390
+ if effect_values_dict is None:
370
391
  return None
371
392
 
372
393
  return {
373
394
  effect: self.create_time_series('|'.join(filter(None, [label_prefix, effect, label_suffix])), value)
374
- for effect, value in effect_values.items()
395
+ for effect, value in effect_values_dict.items()
375
396
  }
376
397
 
377
398
  def create_model(self) -> SystemModel:
@@ -417,14 +438,14 @@ class FlowSystem:
417
438
 
418
439
  # Add Bus if not already added (deprecated)
419
440
  if flow._bus_object is not None and flow._bus_object not in self.buses.values():
420
- self._add_buses(flow._bus_object)
421
441
  warnings.warn(
422
442
  f'The Bus {flow._bus_object.label} was added to the FlowSystem from {flow.label_full}.'
423
443
  f'This is deprecated and will be removed in the future. '
424
444
  f'Please pass the Bus.label to the Flow and the Bus to the FlowSystem instead.',
425
- UserWarning,
445
+ DeprecationWarning,
426
446
  stacklevel=1,
427
447
  )
448
+ self._add_buses(flow._bus_object)
428
449
 
429
450
  # Connect Buses
430
451
  bus = self.buses.get(flow.bus)
@@ -454,10 +475,10 @@ class FlowSystem:
454
475
  return value
455
476
 
456
477
  @property
457
- def flows(self) -> Dict[str, Flow]:
478
+ def flows(self) -> dict[str, Flow]:
458
479
  set_of_flows = {flow for comp in self.components.values() for flow in comp.inputs + comp.outputs}
459
480
  return {flow.label_full: flow for flow in set_of_flows}
460
481
 
461
482
  @property
462
- def all_elements(self) -> Dict[str, Element]:
483
+ def all_elements(self) -> dict[str, Element]:
463
484
  return {**self.components, **self.effects.effects, **self.flows, **self.buses}