flixopt 2.1.7__py3-none-any.whl → 2.1.9__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.
- docs/user-guide/Mathematical Notation/Effects, Penalty & Objective.md +8 -8
- docs/user-guide/Mathematical Notation/Flow.md +3 -3
- docs/user-guide/Mathematical Notation/InvestParameters.md +3 -0
- docs/user-guide/Mathematical Notation/LinearConverter.md +3 -3
- docs/user-guide/Mathematical Notation/OnOffParameters.md +3 -0
- docs/user-guide/Mathematical Notation/Storage.md +1 -1
- flixopt/aggregation.py +33 -32
- flixopt/calculation.py +158 -58
- flixopt/components.py +673 -150
- flixopt/config.py +17 -8
- flixopt/core.py +59 -54
- flixopt/effects.py +144 -63
- flixopt/elements.py +292 -107
- flixopt/features.py +61 -58
- flixopt/flow_system.py +69 -48
- flixopt/interface.py +952 -113
- flixopt/io.py +15 -10
- flixopt/linear_converters.py +373 -81
- flixopt/network_app.py +73 -39
- flixopt/plotting.py +215 -87
- flixopt/results.py +382 -209
- flixopt/solvers.py +25 -21
- flixopt/structure.py +41 -37
- flixopt/utils.py +10 -7
- {flixopt-2.1.7.dist-info → flixopt-2.1.9.dist-info}/METADATA +46 -42
- {flixopt-2.1.7.dist-info → flixopt-2.1.9.dist-info}/RECORD +30 -28
- scripts/gen_ref_pages.py +1 -1
- {flixopt-2.1.7.dist-info → flixopt-2.1.9.dist-info}/WHEEL +0 -0
- {flixopt-2.1.7.dist-info → flixopt-2.1.9.dist-info}/licenses/LICENSE +0 -0
- {flixopt-2.1.7.dist-info → flixopt-2.1.9.dist-info}/top_level.txt +0 -0
flixopt/elements.py
CHANGED
|
@@ -2,21 +2,24 @@
|
|
|
2
2
|
This module contains the basic elements of the flixopt framework.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
5
7
|
import logging
|
|
6
8
|
import warnings
|
|
7
|
-
from typing import TYPE_CHECKING
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
8
10
|
|
|
9
|
-
import linopy
|
|
10
11
|
import numpy as np
|
|
11
12
|
|
|
12
13
|
from .config import CONFIG
|
|
13
|
-
from .core import NumericData, NumericDataTS, PlausibilityError, Scalar
|
|
14
|
-
from .effects import EffectValuesUser
|
|
14
|
+
from .core import NumericData, NumericDataTS, PlausibilityError, Scalar
|
|
15
15
|
from .features import InvestmentModel, OnOffModel, PreventSimultaneousUsageModel
|
|
16
16
|
from .interface import InvestParameters, OnOffParameters
|
|
17
17
|
from .structure import Element, ElementModel, SystemModel, register_class_for_io
|
|
18
18
|
|
|
19
19
|
if TYPE_CHECKING:
|
|
20
|
+
import linopy
|
|
21
|
+
|
|
22
|
+
from .effects import EffectValuesUser
|
|
20
23
|
from .flow_system import FlowSystem
|
|
21
24
|
|
|
22
25
|
logger = logging.getLogger('flixopt')
|
|
@@ -25,54 +28,78 @@ logger = logging.getLogger('flixopt')
|
|
|
25
28
|
@register_class_for_io
|
|
26
29
|
class Component(Element):
|
|
27
30
|
"""
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
Base class for all system components that transform, convert, or process flows.
|
|
32
|
+
|
|
33
|
+
Components are the active elements in energy systems that define how input and output
|
|
34
|
+
Flows interact with each other. They represent equipment, processes, or logical
|
|
35
|
+
operations that transform energy or materials between different states, carriers,
|
|
36
|
+
or locations.
|
|
37
|
+
|
|
38
|
+
Components serve as connection points between Buses through their associated Flows,
|
|
39
|
+
enabling the modeling of complex energy system topologies and operational constraints.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
label: The label of the Element. Used to identify it in the FlowSystem.
|
|
43
|
+
inputs: list of input Flows feeding into the component. These represent
|
|
44
|
+
energy/material consumption by the component.
|
|
45
|
+
outputs: list of output Flows leaving the component. These represent
|
|
46
|
+
energy/material production by the component.
|
|
47
|
+
on_off_parameters: Defines binary operation constraints and costs when the
|
|
48
|
+
component has discrete on/off states. Creates binary variables for all
|
|
49
|
+
connected Flows. For better performance, prefer defining OnOffParameters
|
|
50
|
+
on individual Flows when possible.
|
|
51
|
+
prevent_simultaneous_flows: list of Flows that cannot be active simultaneously.
|
|
52
|
+
Creates binary variables to enforce mutual exclusivity. Use sparingly as
|
|
53
|
+
it increases computational complexity.
|
|
54
|
+
meta_data: Used to store additional information. Not used internally but saved
|
|
55
|
+
in results. Only use Python native types.
|
|
56
|
+
|
|
57
|
+
Note:
|
|
58
|
+
Component operational state is determined by its connected Flows:
|
|
59
|
+
- Component is "on" if ANY of its Flows is active (flow_rate > 0)
|
|
60
|
+
- Component is "off" only when ALL Flows are inactive (flow_rate = 0)
|
|
61
|
+
|
|
62
|
+
Binary variables and constraints:
|
|
63
|
+
- on_off_parameters creates binary variables for ALL connected Flows
|
|
64
|
+
- prevent_simultaneous_flows creates binary variables for specified Flows
|
|
65
|
+
- For better computational performance, prefer Flow-level OnOffParameters
|
|
66
|
+
|
|
67
|
+
Component is an abstract base class. In practice, use specialized subclasses:
|
|
68
|
+
- LinearConverter: Linear input/output relationships
|
|
69
|
+
- Storage: Temporal energy/material storage
|
|
70
|
+
- Transmission: Transport between locations
|
|
71
|
+
- Source/Sink: System boundaries
|
|
72
|
+
|
|
33
73
|
"""
|
|
34
74
|
|
|
35
75
|
def __init__(
|
|
36
76
|
self,
|
|
37
77
|
label: str,
|
|
38
|
-
inputs:
|
|
39
|
-
outputs:
|
|
40
|
-
on_off_parameters:
|
|
41
|
-
prevent_simultaneous_flows:
|
|
42
|
-
meta_data:
|
|
78
|
+
inputs: list[Flow] | None = None,
|
|
79
|
+
outputs: list[Flow] | None = None,
|
|
80
|
+
on_off_parameters: OnOffParameters | None = None,
|
|
81
|
+
prevent_simultaneous_flows: list[Flow] | None = None,
|
|
82
|
+
meta_data: dict | None = None,
|
|
43
83
|
):
|
|
44
|
-
"""
|
|
45
|
-
Args:
|
|
46
|
-
label: The label of the Element. Used to identify it in the FlowSystem
|
|
47
|
-
inputs: input flows.
|
|
48
|
-
outputs: output flows.
|
|
49
|
-
on_off_parameters: Information about on and off state of Component.
|
|
50
|
-
Component is On/Off, if all connected Flows are On/Off. This induces an On-Variable (binary) in all Flows!
|
|
51
|
-
If possible, use OnOffParameters in a single Flow instead to keep the number of binary variables low.
|
|
52
|
-
See class OnOffParameters.
|
|
53
|
-
prevent_simultaneous_flows: Define a Group of Flows. Only one them can be on at a time.
|
|
54
|
-
Induces On-Variable in all Flows! If possible, use OnOffParameters in a single Flow instead.
|
|
55
|
-
meta_data: used to store more information about the Element. Is not used internally, but saved in the results. Only use python native types.
|
|
56
|
-
"""
|
|
57
84
|
super().__init__(label, meta_data=meta_data)
|
|
58
|
-
self.inputs:
|
|
59
|
-
self.outputs:
|
|
85
|
+
self.inputs: list[Flow] = inputs or []
|
|
86
|
+
self.outputs: list[Flow] = outputs or []
|
|
60
87
|
self._check_unique_flow_labels()
|
|
61
88
|
self.on_off_parameters = on_off_parameters
|
|
62
|
-
self.prevent_simultaneous_flows:
|
|
89
|
+
self.prevent_simultaneous_flows: list[Flow] = prevent_simultaneous_flows or []
|
|
63
90
|
|
|
64
|
-
self.flows:
|
|
91
|
+
self.flows: dict[str, Flow] = {flow.label: flow for flow in self.inputs + self.outputs}
|
|
65
92
|
|
|
66
|
-
def create_model(self, model: SystemModel) ->
|
|
93
|
+
def create_model(self, model: SystemModel) -> ComponentModel:
|
|
67
94
|
self._plausibility_checks()
|
|
68
95
|
self.model = ComponentModel(model, self)
|
|
69
96
|
return self.model
|
|
70
97
|
|
|
71
|
-
def transform_data(self, flow_system:
|
|
98
|
+
def transform_data(self, flow_system: FlowSystem) -> None:
|
|
72
99
|
if self.on_off_parameters is not None:
|
|
73
100
|
self.on_off_parameters.transform_data(flow_system, self.label_full)
|
|
74
101
|
|
|
75
|
-
def infos(self, use_numpy=True, use_element_label: bool = False) ->
|
|
102
|
+
def infos(self, use_numpy=True, use_element_label: bool = False) -> dict:
|
|
76
103
|
infos = super().infos(use_numpy, use_element_label)
|
|
77
104
|
infos['inputs'] = [flow.infos(use_numpy, use_element_label) for flow in self.inputs]
|
|
78
105
|
infos['outputs'] = [flow.infos(use_numpy, use_element_label) for flow in self.outputs]
|
|
@@ -92,38 +119,89 @@ class Component(Element):
|
|
|
92
119
|
@register_class_for_io
|
|
93
120
|
class Bus(Element):
|
|
94
121
|
"""
|
|
95
|
-
|
|
122
|
+
Buses represent nodal balances between flow rates, serving as connection points.
|
|
123
|
+
|
|
124
|
+
A Bus enforces energy or material balance constraints where the sum of all incoming
|
|
125
|
+
flows must equal the sum of all outgoing flows at each time step. Buses represent
|
|
126
|
+
physical or logical connection points for energy carriers (electricity, heat, gas)
|
|
127
|
+
or material flows between different Components.
|
|
128
|
+
|
|
129
|
+
Args:
|
|
130
|
+
label: The label of the Element. Used to identify it in the FlowSystem.
|
|
131
|
+
excess_penalty_per_flow_hour: Penalty costs for bus balance violations.
|
|
132
|
+
When None, no excess/deficit is allowed (hard constraint). When set to a
|
|
133
|
+
value > 0, allows bus imbalances at penalty cost. Default is 1e5 (high penalty).
|
|
134
|
+
meta_data: Used to store additional information. Not used internally but saved
|
|
135
|
+
in results. Only use Python native types.
|
|
136
|
+
|
|
137
|
+
Examples:
|
|
138
|
+
Electrical bus with strict balance:
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
electricity_bus = Bus(
|
|
142
|
+
label='main_electrical_bus',
|
|
143
|
+
excess_penalty_per_flow_hour=None, # No imbalance allowed
|
|
144
|
+
)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Heat network with penalty for imbalances:
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
heat_network = Bus(
|
|
151
|
+
label='district_heating_network',
|
|
152
|
+
excess_penalty_per_flow_hour=1000, # €1000/MWh penalty for imbalance
|
|
153
|
+
)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Material flow with time-varying penalties:
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
material_hub = Bus(
|
|
160
|
+
label='material_processing_hub',
|
|
161
|
+
excess_penalty_per_flow_hour=waste_disposal_costs, # Time series
|
|
162
|
+
)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Note:
|
|
166
|
+
The bus balance equation enforced is: Σ(inflows) = Σ(outflows) + excess - deficit
|
|
167
|
+
|
|
168
|
+
When excess_penalty_per_flow_hour is None, excess and deficit are forced to zero.
|
|
169
|
+
When a penalty cost is specified, the optimization can choose to violate the
|
|
170
|
+
balance if economically beneficial, paying the penalty.
|
|
171
|
+
The penalty is added to the objective directly.
|
|
172
|
+
|
|
173
|
+
Empty `inputs` and `outputs` lists are initialized and populated automatically
|
|
174
|
+
by the FlowSystem during system setup.
|
|
96
175
|
"""
|
|
97
176
|
|
|
98
177
|
def __init__(
|
|
99
|
-
self,
|
|
178
|
+
self,
|
|
179
|
+
label: str,
|
|
180
|
+
excess_penalty_per_flow_hour: NumericData | NumericDataTS | None = 1e5,
|
|
181
|
+
meta_data: dict | None = None,
|
|
100
182
|
):
|
|
101
|
-
"""
|
|
102
|
-
Args:
|
|
103
|
-
label: The label of the Element. Used to identify it in the FlowSystem
|
|
104
|
-
excess_penalty_per_flow_hour: excess costs / penalty costs (bus balance compensation)
|
|
105
|
-
(none/ 0 -> no penalty). The default is 1e5.
|
|
106
|
-
(Take care: if you use a timeseries (no scalar), timeseries is aggregated if calculation_type = aggregated!)
|
|
107
|
-
meta_data: used to store more information about the Element. Is not used internally, but saved in the results. Only use python native types.
|
|
108
|
-
"""
|
|
109
183
|
super().__init__(label, meta_data=meta_data)
|
|
110
184
|
self.excess_penalty_per_flow_hour = excess_penalty_per_flow_hour
|
|
111
|
-
self.inputs:
|
|
112
|
-
self.outputs:
|
|
185
|
+
self.inputs: list[Flow] = []
|
|
186
|
+
self.outputs: list[Flow] = []
|
|
113
187
|
|
|
114
|
-
def create_model(self, model: SystemModel) ->
|
|
188
|
+
def create_model(self, model: SystemModel) -> BusModel:
|
|
115
189
|
self._plausibility_checks()
|
|
116
190
|
self.model = BusModel(model, self)
|
|
117
191
|
return self.model
|
|
118
192
|
|
|
119
|
-
def transform_data(self, flow_system:
|
|
193
|
+
def transform_data(self, flow_system: FlowSystem):
|
|
120
194
|
self.excess_penalty_per_flow_hour = flow_system.create_time_series(
|
|
121
195
|
f'{self.label_full}|excess_penalty_per_flow_hour', self.excess_penalty_per_flow_hour
|
|
122
196
|
)
|
|
123
197
|
|
|
124
198
|
def _plausibility_checks(self) -> None:
|
|
125
|
-
if self.excess_penalty_per_flow_hour is not None
|
|
126
|
-
|
|
199
|
+
if self.excess_penalty_per_flow_hour is not None:
|
|
200
|
+
zero_penalty = np.all(np.equal(self.excess_penalty_per_flow_hour, 0))
|
|
201
|
+
if zero_penalty:
|
|
202
|
+
logger.warning(
|
|
203
|
+
f'In Bus {self.label}, the excess_penalty_per_flow_hour is 0. Use "None" or a value > 0.'
|
|
204
|
+
)
|
|
127
205
|
|
|
128
206
|
@property
|
|
129
207
|
def with_excess(self) -> bool:
|
|
@@ -145,60 +223,167 @@ class Connection:
|
|
|
145
223
|
|
|
146
224
|
@register_class_for_io
|
|
147
225
|
class Flow(Element):
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
226
|
+
"""Define a directed flow of energy or material between bus and component.
|
|
227
|
+
|
|
228
|
+
A Flow represents the transfer of energy (electricity, heat, fuel) or material
|
|
229
|
+
between a Bus and a Component in a specific direction. The flow rate is the
|
|
230
|
+
primary optimization variable, with constraints and costs defined through
|
|
231
|
+
various parameters. Flows can have fixed or variable sizes, operational
|
|
232
|
+
constraints, and complex on/off behavior.
|
|
233
|
+
|
|
234
|
+
Key Concepts:
|
|
235
|
+
**Flow Rate**: The instantaneous rate of energy/material transfer (optimization variable) [kW, m³/h, kg/h]
|
|
236
|
+
**Flow Hours**: Amount of energy/material transferred per timestep. [kWh, m³, kg]
|
|
237
|
+
**Flow Size**: The maximum capacity or nominal rating of the flow [kW, m³/h, kg/h]
|
|
238
|
+
**Relative Bounds**: Flow rate limits expressed as fractions of flow size
|
|
239
|
+
|
|
240
|
+
Integration with Parameter Classes:
|
|
241
|
+
- **InvestParameters**: Used for `size` when flow Size is an investment decision
|
|
242
|
+
- **OnOffParameters**: Used for `on_off_parameters` when flow has discrete states
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
label: Unique identifier for the flow within its component.
|
|
246
|
+
The full label combines component and flow labels.
|
|
247
|
+
bus: Label of the bus this flow connects to. Must match a bus in the FlowSystem.
|
|
248
|
+
size: Flow capacity or nominal rating. Can be:
|
|
249
|
+
- Scalar value for fixed capacity
|
|
250
|
+
- InvestParameters for investment-based sizing decisions
|
|
251
|
+
- None to use large default value (CONFIG.modeling.BIG)
|
|
252
|
+
relative_minimum: Minimum flow rate as fraction of size.
|
|
253
|
+
Example: 0.2 means flow cannot go below 20% of rated capacity.
|
|
254
|
+
relative_maximum: Maximum flow rate as fraction of size (typically 1.0).
|
|
255
|
+
Values >1.0 allow temporary overload operation.
|
|
256
|
+
load_factor_min: Minimum average utilization over the time horizon (0-1).
|
|
257
|
+
Calculated as total flow hours divided by (size × total time).
|
|
258
|
+
load_factor_max: Maximum average utilization over the time horizon (0-1).
|
|
259
|
+
Useful for equipment duty cycle limits or maintenance scheduling.
|
|
260
|
+
effects_per_flow_hour: Operational costs and impacts per unit of flow-time.
|
|
261
|
+
Dictionary mapping effect names to unit costs (e.g., fuel costs, emissions).
|
|
262
|
+
on_off_parameters: Binary operation constraints using OnOffParameters.
|
|
263
|
+
Enables modeling of startup costs, minimum run times, cycling limits.
|
|
264
|
+
Only relevant when relative_minimum > 0 or discrete operation is required.
|
|
265
|
+
flow_hours_total_max: Maximum cumulative flow-hours over time horizon.
|
|
266
|
+
Alternative to load_factor_max for absolute energy/material limits.
|
|
267
|
+
flow_hours_total_min: Minimum cumulative flow-hours over time horizon.
|
|
268
|
+
Alternative to load_factor_min for contractual or operational requirements.
|
|
269
|
+
fixed_relative_profile: Predetermined flow pattern as fraction of size.
|
|
270
|
+
When specified, flow rate becomes: size × fixed_relative_profile(t).
|
|
271
|
+
Used for: demand profiles, renewable generation, fixed schedules.
|
|
272
|
+
previous_flow_rate: Initial flow state for startup/shutdown dynamics.
|
|
273
|
+
Used with on_off_parameters to determine initial on/off status.
|
|
274
|
+
If None, assumes flow was off in previous time period.
|
|
275
|
+
meta_data: Additional information stored with results but not used in optimization.
|
|
276
|
+
Must contain only Python native types (dict, list, str, int, float, bool).
|
|
277
|
+
|
|
278
|
+
Examples:
|
|
279
|
+
Basic power flow with fixed capacity:
|
|
280
|
+
|
|
281
|
+
```python
|
|
282
|
+
generator_output = Flow(
|
|
283
|
+
label='electricity_out',
|
|
284
|
+
bus='electricity_grid',
|
|
285
|
+
size=100, # 100 MW capacity
|
|
286
|
+
relative_minimum=0.4, # Cannot operate below 40 MW
|
|
287
|
+
effects_per_flow_hour={'fuel_cost': 45, 'co2_emissions': 0.8},
|
|
288
|
+
)
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Investment decision for battery capacity:
|
|
292
|
+
|
|
293
|
+
```python
|
|
294
|
+
battery_flow = Flow(
|
|
295
|
+
label='electricity_storage',
|
|
296
|
+
bus='electricity_grid',
|
|
297
|
+
size=InvestParameters(
|
|
298
|
+
minimum_size=10, # Minimum 10 MWh
|
|
299
|
+
maximum_size=100, # Maximum 100 MWh
|
|
300
|
+
specific_effects={'cost': 150_000}, # €150k/MWh annualized
|
|
301
|
+
),
|
|
302
|
+
)
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Heat pump with startup costs and minimum run times:
|
|
306
|
+
|
|
307
|
+
```python
|
|
308
|
+
heat_pump = Flow(
|
|
309
|
+
label='heat_output',
|
|
310
|
+
bus='heating_network',
|
|
311
|
+
size=50, # 50 kW thermal
|
|
312
|
+
relative_minimum=0.3, # Minimum 15 kW output when on
|
|
313
|
+
effects_per_flow_hour={'electricity_cost': 25, 'maintenance': 2},
|
|
314
|
+
on_off_parameters=OnOffParameters(
|
|
315
|
+
effects_per_switch_on={'startup_cost': 100, 'wear': 0.1},
|
|
316
|
+
consecutive_on_hours_min=2, # Must run at least 2 hours
|
|
317
|
+
consecutive_off_hours_min=1, # Must stay off at least 1 hour
|
|
318
|
+
switch_on_total_max=200, # Maximum 200 starts per year
|
|
319
|
+
),
|
|
320
|
+
)
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
Fixed renewable generation profile:
|
|
324
|
+
|
|
325
|
+
```python
|
|
326
|
+
solar_generation = Flow(
|
|
327
|
+
label='solar_power',
|
|
328
|
+
bus='electricity_grid',
|
|
329
|
+
size=25, # 25 MW installed capacity
|
|
330
|
+
fixed_relative_profile=np.array([0, 0.1, 0.4, 0.8, 0.9, 0.7, 0.3, 0.1, 0]),
|
|
331
|
+
effects_per_flow_hour={'maintenance_costs': 5}, # €5/MWh maintenance
|
|
332
|
+
)
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Industrial process with annual utilization limits:
|
|
336
|
+
|
|
337
|
+
```python
|
|
338
|
+
production_line = Flow(
|
|
339
|
+
label='product_output',
|
|
340
|
+
bus='product_market',
|
|
341
|
+
size=1000, # 1000 units/hour capacity
|
|
342
|
+
load_factor_min=0.6, # Must achieve 60% annual utilization
|
|
343
|
+
load_factor_max=0.85, # Cannot exceed 85% for maintenance
|
|
344
|
+
effects_per_flow_hour={'variable_cost': 12, 'quality_control': 0.5},
|
|
345
|
+
)
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Design Considerations:
|
|
349
|
+
**Size vs Load Factors**: Use `flow_hours_total_min/max` for absolute limits,
|
|
350
|
+
`load_factor_min/max` for utilization-based constraints.
|
|
351
|
+
|
|
352
|
+
**Relative Bounds**: Set `relative_minimum > 0` only when equipment cannot
|
|
353
|
+
operate below that level. Use `on_off_parameters` for discrete on/off behavior.
|
|
354
|
+
|
|
355
|
+
**Fixed Profiles**: Use `fixed_relative_profile` for known exact patterns,
|
|
356
|
+
`relative_maximum` for upper bounds on optimization variables.
|
|
357
|
+
|
|
358
|
+
Notes:
|
|
359
|
+
- Default size (CONFIG.modeling.BIG) is used when size=None
|
|
360
|
+
- list inputs for previous_flow_rate are converted to NumPy arrays
|
|
361
|
+
- Flow direction is determined by component input/output designation
|
|
362
|
+
|
|
363
|
+
Deprecated:
|
|
364
|
+
Passing Bus objects to `bus` parameter. Use bus label strings instead.
|
|
365
|
+
|
|
151
366
|
"""
|
|
152
367
|
|
|
153
368
|
def __init__(
|
|
154
369
|
self,
|
|
155
370
|
label: str,
|
|
156
371
|
bus: str,
|
|
157
|
-
size:
|
|
158
|
-
fixed_relative_profile:
|
|
372
|
+
size: Scalar | InvestParameters | None = None,
|
|
373
|
+
fixed_relative_profile: NumericDataTS | None = None,
|
|
159
374
|
relative_minimum: NumericDataTS = 0,
|
|
160
375
|
relative_maximum: NumericDataTS = 1,
|
|
161
|
-
effects_per_flow_hour:
|
|
162
|
-
on_off_parameters:
|
|
163
|
-
flow_hours_total_max:
|
|
164
|
-
flow_hours_total_min:
|
|
165
|
-
load_factor_min:
|
|
166
|
-
load_factor_max:
|
|
167
|
-
previous_flow_rate:
|
|
168
|
-
meta_data:
|
|
376
|
+
effects_per_flow_hour: EffectValuesUser | None = None,
|
|
377
|
+
on_off_parameters: OnOffParameters | None = None,
|
|
378
|
+
flow_hours_total_max: Scalar | None = None,
|
|
379
|
+
flow_hours_total_min: Scalar | None = None,
|
|
380
|
+
load_factor_min: Scalar | None = None,
|
|
381
|
+
load_factor_max: Scalar | None = None,
|
|
382
|
+
previous_flow_rate: NumericData | None = None,
|
|
383
|
+
meta_data: dict | None = None,
|
|
169
384
|
):
|
|
170
|
-
r"""
|
|
171
|
-
Args:
|
|
172
|
-
label: The label of the FLow. Used to identify it in the FlowSystem. Its `full_label` consists of the label of the Component and the label of the Flow.
|
|
173
|
-
bus: blabel of the bus the flow is connected to.
|
|
174
|
-
size: size of the flow. If InvestmentParameters is used, size is optimized.
|
|
175
|
-
If size is None, a default value is used.
|
|
176
|
-
relative_minimum: min value is relative_minimum multiplied by size
|
|
177
|
-
relative_maximum: max value is relative_maximum multiplied by size. If size = max then relative_maximum=1
|
|
178
|
-
load_factor_min: minimal load factor general: avg Flow per nominalVal/investSize
|
|
179
|
-
(e.g. boiler, kW/kWh=h; solarthermal: kW/m²;
|
|
180
|
-
def: :math:`load\_factor:= sumFlowHours/ (nominal\_val \cdot \Delta t_{tot})`
|
|
181
|
-
load_factor_max: maximal load factor (see minimal load factor)
|
|
182
|
-
effects_per_flow_hour: operational costs, costs per flow-"work"
|
|
183
|
-
on_off_parameters: If present, flow can be "off", i.e. be zero (only relevant if relative_minimum > 0)
|
|
184
|
-
Therefore a binary var "on" is used. Further, several other restrictions and effects can be modeled
|
|
185
|
-
through this On/Off State (See OnOffParameters)
|
|
186
|
-
flow_hours_total_max: maximum flow-hours ("flow-work")
|
|
187
|
-
(if size is not const, maybe load_factor_max is the better choice!)
|
|
188
|
-
flow_hours_total_min: minimum flow-hours ("flow-work")
|
|
189
|
-
(if size is not predefined, maybe load_factor_min is the better choice!)
|
|
190
|
-
fixed_relative_profile: fixed relative values for flow (if given).
|
|
191
|
-
flow_rate(t) := fixed_relative_profile(t) * size(t)
|
|
192
|
-
With this value, the flow_rate is no optimization-variable anymore.
|
|
193
|
-
(relative_minimum and relative_maximum are ignored)
|
|
194
|
-
used for fixed load or supply profiles, i.g. heat demand, wind-power, solarthermal
|
|
195
|
-
If the load-profile is just an upper limit, use relative_maximum instead.
|
|
196
|
-
previous_flow_rate: previous flow rate of the flow. Used to determine if and how long the
|
|
197
|
-
flow is already on / off. If None, the flow is considered to be off for one timestep.
|
|
198
|
-
meta_data: used to store more information about the Element. Is not used internally, but saved in the results. Only use python native types.
|
|
199
|
-
"""
|
|
200
385
|
super().__init__(label, meta_data=meta_data)
|
|
201
|
-
self.size =
|
|
386
|
+
self.size = CONFIG.modeling.BIG if size is None else size
|
|
202
387
|
self.relative_minimum = relative_minimum
|
|
203
388
|
self.relative_maximum = relative_maximum
|
|
204
389
|
self.fixed_relative_profile = fixed_relative_profile
|
|
@@ -216,7 +401,7 @@ class Flow(Element):
|
|
|
216
401
|
)
|
|
217
402
|
|
|
218
403
|
self.component: str = 'UnknownComponent'
|
|
219
|
-
self.is_input_in_component:
|
|
404
|
+
self.is_input_in_component: bool | None = None
|
|
220
405
|
if isinstance(bus, Bus):
|
|
221
406
|
self.bus = bus.label_full
|
|
222
407
|
warnings.warn(
|
|
@@ -230,12 +415,12 @@ class Flow(Element):
|
|
|
230
415
|
self.bus = bus
|
|
231
416
|
self._bus_object = None
|
|
232
417
|
|
|
233
|
-
def create_model(self, model: SystemModel) ->
|
|
418
|
+
def create_model(self, model: SystemModel) -> FlowModel:
|
|
234
419
|
self._plausibility_checks()
|
|
235
420
|
self.model = FlowModel(model, self)
|
|
236
421
|
return self.model
|
|
237
422
|
|
|
238
|
-
def transform_data(self, flow_system:
|
|
423
|
+
def transform_data(self, flow_system: FlowSystem):
|
|
239
424
|
self.relative_minimum = flow_system.create_time_series(
|
|
240
425
|
f'{self.label_full}|relative_minimum', self.relative_minimum
|
|
241
426
|
)
|
|
@@ -253,12 +438,12 @@ class Flow(Element):
|
|
|
253
438
|
if isinstance(self.size, InvestParameters):
|
|
254
439
|
self.size.transform_data(flow_system)
|
|
255
440
|
|
|
256
|
-
def infos(self, use_numpy: bool = True, use_element_label: bool = False) ->
|
|
441
|
+
def infos(self, use_numpy: bool = True, use_element_label: bool = False) -> dict:
|
|
257
442
|
infos = super().infos(use_numpy, use_element_label)
|
|
258
443
|
infos['is_input_in_component'] = self.is_input_in_component
|
|
259
444
|
return infos
|
|
260
445
|
|
|
261
|
-
def to_dict(self) ->
|
|
446
|
+
def to_dict(self) -> dict:
|
|
262
447
|
data = super().to_dict()
|
|
263
448
|
if isinstance(data.get('previous_flow_rate'), np.ndarray):
|
|
264
449
|
data['previous_flow_rate'] = data['previous_flow_rate'].tolist()
|
|
@@ -311,11 +496,11 @@ class FlowModel(ElementModel):
|
|
|
311
496
|
def __init__(self, model: SystemModel, element: Flow):
|
|
312
497
|
super().__init__(model, element)
|
|
313
498
|
self.element: Flow = element
|
|
314
|
-
self.flow_rate:
|
|
315
|
-
self.total_flow_hours:
|
|
499
|
+
self.flow_rate: linopy.Variable | None = None
|
|
500
|
+
self.total_flow_hours: linopy.Variable | None = None
|
|
316
501
|
|
|
317
|
-
self.on_off:
|
|
318
|
-
self._investment:
|
|
502
|
+
self.on_off: OnOffModel | None = None
|
|
503
|
+
self._investment: InvestmentModel | None = None
|
|
319
504
|
|
|
320
505
|
def do_modeling(self):
|
|
321
506
|
# eq relative_minimum(t) * size <= flow_rate(t) <= relative_maximum(t) * size
|
|
@@ -430,7 +615,7 @@ class FlowModel(ElementModel):
|
|
|
430
615
|
)
|
|
431
616
|
|
|
432
617
|
@property
|
|
433
|
-
def flow_rate_bounds_on(self) ->
|
|
618
|
+
def flow_rate_bounds_on(self) -> tuple[NumericData, NumericData]:
|
|
434
619
|
"""Returns absolute flow rate bounds. Important for OnOffModel"""
|
|
435
620
|
relative_minimum, relative_maximum = self.flow_rate_lower_bound_relative, self.flow_rate_upper_bound_relative
|
|
436
621
|
size = self.element.size
|
|
@@ -485,8 +670,8 @@ class BusModel(ElementModel):
|
|
|
485
670
|
def __init__(self, model: SystemModel, element: Bus):
|
|
486
671
|
super().__init__(model, element)
|
|
487
672
|
self.element: Bus = element
|
|
488
|
-
self.excess_input:
|
|
489
|
-
self.excess_output:
|
|
673
|
+
self.excess_input: linopy.Variable | None = None
|
|
674
|
+
self.excess_output: linopy.Variable | None = None
|
|
490
675
|
|
|
491
676
|
def do_modeling(self) -> None:
|
|
492
677
|
# inputs == outputs
|
|
@@ -528,7 +713,7 @@ class ComponentModel(ElementModel):
|
|
|
528
713
|
def __init__(self, model: SystemModel, element: Component):
|
|
529
714
|
super().__init__(model, element)
|
|
530
715
|
self.element: Component = element
|
|
531
|
-
self.on_off:
|
|
716
|
+
self.on_off: OnOffModel | None = None
|
|
532
717
|
|
|
533
718
|
def do_modeling(self):
|
|
534
719
|
"""Initiates all FlowModels"""
|