flixopt 2.2.0rc2__py3-none-any.whl → 3.0.1__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.
- flixopt/__init__.py +33 -4
- flixopt/aggregation.py +60 -80
- flixopt/calculation.py +403 -182
- flixopt/commons.py +1 -10
- flixopt/components.py +939 -448
- flixopt/config.py +553 -191
- flixopt/core.py +513 -846
- flixopt/effects.py +644 -178
- flixopt/elements.py +610 -355
- flixopt/features.py +394 -966
- flixopt/flow_system.py +736 -219
- flixopt/interface.py +1104 -302
- flixopt/io.py +103 -79
- flixopt/linear_converters.py +387 -95
- flixopt/modeling.py +757 -0
- flixopt/network_app.py +73 -39
- flixopt/plotting.py +294 -138
- flixopt/results.py +1254 -300
- flixopt/solvers.py +25 -21
- flixopt/structure.py +938 -396
- flixopt/utils.py +36 -12
- flixopt-3.0.1.dist-info/METADATA +209 -0
- flixopt-3.0.1.dist-info/RECORD +26 -0
- flixopt-3.0.1.dist-info/top_level.txt +1 -0
- docs/examples/00-Minimal Example.md +0 -5
- docs/examples/01-Basic Example.md +0 -5
- docs/examples/02-Complex Example.md +0 -10
- docs/examples/03-Calculation Modes.md +0 -5
- docs/examples/index.md +0 -5
- docs/faq/contribute.md +0 -61
- docs/faq/index.md +0 -3
- docs/images/architecture_flixOpt-pre2.0.0.png +0 -0
- docs/images/architecture_flixOpt.png +0 -0
- docs/images/flixopt-icon.svg +0 -1
- docs/javascripts/mathjax.js +0 -18
- docs/user-guide/Mathematical Notation/Bus.md +0 -33
- docs/user-guide/Mathematical Notation/Effects, Penalty & Objective.md +0 -132
- docs/user-guide/Mathematical Notation/Flow.md +0 -26
- docs/user-guide/Mathematical Notation/LinearConverter.md +0 -21
- docs/user-guide/Mathematical Notation/Piecewise.md +0 -49
- docs/user-guide/Mathematical Notation/Storage.md +0 -44
- docs/user-guide/Mathematical Notation/index.md +0 -22
- docs/user-guide/Mathematical Notation/others.md +0 -3
- docs/user-guide/index.md +0 -124
- flixopt/config.yaml +0 -10
- flixopt-2.2.0rc2.dist-info/METADATA +0 -167
- flixopt-2.2.0rc2.dist-info/RECORD +0 -54
- flixopt-2.2.0rc2.dist-info/top_level.txt +0 -5
- pics/architecture_flixOpt-pre2.0.0.png +0 -0
- pics/architecture_flixOpt.png +0 -0
- pics/flixOpt_plotting.jpg +0 -0
- pics/flixopt-icon.svg +0 -1
- pics/pics.pptx +0 -0
- scripts/extract_release_notes.py +0 -45
- scripts/gen_ref_pages.py +0 -54
- tests/ressources/Zeitreihen2020.csv +0 -35137
- {flixopt-2.2.0rc2.dist-info → flixopt-3.0.1.dist-info}/WHEEL +0 -0
- {flixopt-2.2.0rc2.dist-info → flixopt-3.0.1.dist-info}/licenses/LICENSE +0 -0
flixopt/linear_converters.py
CHANGED
|
@@ -2,40 +2,86 @@
|
|
|
2
2
|
This Module contains high-level classes to easily model a FlowSystem.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
5
7
|
import logging
|
|
6
|
-
from typing import
|
|
8
|
+
from typing import TYPE_CHECKING
|
|
7
9
|
|
|
8
10
|
import numpy as np
|
|
9
11
|
|
|
10
12
|
from .components import LinearConverter
|
|
11
|
-
from .core import
|
|
12
|
-
from .elements import Flow
|
|
13
|
-
from .interface import OnOffParameters
|
|
13
|
+
from .core import TemporalDataUser, TimeSeriesData
|
|
14
14
|
from .structure import register_class_for_io
|
|
15
15
|
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from .elements import Flow
|
|
18
|
+
from .interface import OnOffParameters
|
|
19
|
+
|
|
16
20
|
logger = logging.getLogger('flixopt')
|
|
17
21
|
|
|
18
22
|
|
|
19
23
|
@register_class_for_io
|
|
20
24
|
class Boiler(LinearConverter):
|
|
25
|
+
"""
|
|
26
|
+
A specialized LinearConverter representing a fuel-fired boiler for thermal energy generation.
|
|
27
|
+
|
|
28
|
+
Boilers convert fuel input into thermal energy with a specified efficiency factor.
|
|
29
|
+
This is a simplified wrapper around LinearConverter with predefined conversion
|
|
30
|
+
relationships for thermal generation applications.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
label: The label of the Element. Used to identify it in the FlowSystem.
|
|
34
|
+
eta: Thermal efficiency factor (0-1 range). Defines the ratio of thermal
|
|
35
|
+
output to fuel input energy content.
|
|
36
|
+
Q_fu: Fuel input-flow representing fuel consumption.
|
|
37
|
+
Q_th: Thermal output-flow representing heat generation.
|
|
38
|
+
on_off_parameters: Parameters defining binary operation constraints and costs.
|
|
39
|
+
meta_data: Used to store additional information. Not used internally but
|
|
40
|
+
saved in results. Only use Python native types.
|
|
41
|
+
|
|
42
|
+
Examples:
|
|
43
|
+
Natural gas boiler:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
gas_boiler = Boiler(
|
|
47
|
+
label='natural_gas_boiler',
|
|
48
|
+
eta=0.85, # 85% thermal efficiency
|
|
49
|
+
Q_fu=natural_gas_flow,
|
|
50
|
+
Q_th=hot_water_flow,
|
|
51
|
+
)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Biomass boiler with seasonal efficiency variation:
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
biomass_boiler = Boiler(
|
|
58
|
+
label='wood_chip_boiler',
|
|
59
|
+
eta=seasonal_efficiency_profile, # Time-varying efficiency
|
|
60
|
+
Q_fu=biomass_flow,
|
|
61
|
+
Q_th=district_heat_flow,
|
|
62
|
+
on_off_parameters=OnOffParameters(
|
|
63
|
+
consecutive_on_hours_min=4, # Minimum 4-hour operation
|
|
64
|
+
effects_per_switch_on={'startup_fuel': 50}, # Startup fuel penalty
|
|
65
|
+
),
|
|
66
|
+
)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Note:
|
|
70
|
+
The conversion relationship is: Q_th = Q_fu × eta
|
|
71
|
+
|
|
72
|
+
Efficiency should be between 0 and 1, where 1 represents perfect conversion
|
|
73
|
+
(100% of fuel energy converted to useful thermal output).
|
|
74
|
+
"""
|
|
75
|
+
|
|
21
76
|
def __init__(
|
|
22
77
|
self,
|
|
23
78
|
label: str,
|
|
24
|
-
eta:
|
|
79
|
+
eta: TemporalDataUser,
|
|
25
80
|
Q_fu: Flow,
|
|
26
81
|
Q_th: Flow,
|
|
27
|
-
on_off_parameters: OnOffParameters = None,
|
|
28
|
-
meta_data:
|
|
82
|
+
on_off_parameters: OnOffParameters | None = None,
|
|
83
|
+
meta_data: dict | None = None,
|
|
29
84
|
):
|
|
30
|
-
"""
|
|
31
|
-
Args:
|
|
32
|
-
label: The label of the Element. Used to identify it in the FlowSystem
|
|
33
|
-
eta: thermal efficiency.
|
|
34
|
-
Q_fu: fuel input-flow
|
|
35
|
-
Q_th: thermal output-flow.
|
|
36
|
-
on_off_parameters: Parameters defining the on/off behavior of the component.
|
|
37
|
-
meta_data: used to store more information about the Element. Is not used internally, but saved in the results. Only use python native types.
|
|
38
|
-
"""
|
|
39
85
|
super().__init__(
|
|
40
86
|
label,
|
|
41
87
|
inputs=[Q_fu],
|
|
@@ -59,24 +105,70 @@ class Boiler(LinearConverter):
|
|
|
59
105
|
|
|
60
106
|
@register_class_for_io
|
|
61
107
|
class Power2Heat(LinearConverter):
|
|
108
|
+
"""
|
|
109
|
+
A specialized LinearConverter representing electric resistance heating or power-to-heat conversion.
|
|
110
|
+
|
|
111
|
+
Power2Heat components convert electrical energy directly into thermal energy through
|
|
112
|
+
resistance heating elements, electrode boilers, or other direct electric heating
|
|
113
|
+
technologies. This is a simplified wrapper around LinearConverter with predefined
|
|
114
|
+
conversion relationships for electric heating applications.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
label: The label of the Element. Used to identify it in the FlowSystem.
|
|
118
|
+
eta: Thermal efficiency factor (0-1 range). For resistance heating this is
|
|
119
|
+
typically close to 1.0 (nearly 100% efficiency), but may be lower for
|
|
120
|
+
electrode boilers or systems with distribution losses.
|
|
121
|
+
P_el: Electrical input-flow representing electricity consumption.
|
|
122
|
+
Q_th: Thermal output-flow representing heat generation.
|
|
123
|
+
on_off_parameters: Parameters defining binary operation constraints and costs.
|
|
124
|
+
meta_data: Used to store additional information. Not used internally but
|
|
125
|
+
saved in results. Only use Python native types.
|
|
126
|
+
|
|
127
|
+
Examples:
|
|
128
|
+
Electric resistance heater:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
electric_heater = Power2Heat(
|
|
132
|
+
label='resistance_heater',
|
|
133
|
+
eta=0.98, # 98% efficiency (small losses)
|
|
134
|
+
P_el=electricity_flow,
|
|
135
|
+
Q_th=space_heating_flow,
|
|
136
|
+
)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Electrode boiler for industrial steam:
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
electrode_boiler = Power2Heat(
|
|
143
|
+
label='electrode_steam_boiler',
|
|
144
|
+
eta=0.95, # 95% efficiency including boiler losses
|
|
145
|
+
P_el=industrial_electricity,
|
|
146
|
+
Q_th=process_steam_flow,
|
|
147
|
+
on_off_parameters=OnOffParameters(
|
|
148
|
+
consecutive_on_hours_min=1, # Minimum 1-hour operation
|
|
149
|
+
effects_per_switch_on={'startup_cost': 100},
|
|
150
|
+
),
|
|
151
|
+
)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Note:
|
|
155
|
+
The conversion relationship is: Q_th = P_el × eta
|
|
156
|
+
|
|
157
|
+
Unlike heat pumps, Power2Heat systems cannot exceed 100% efficiency (eta ≤ 1.0)
|
|
158
|
+
as they only convert electrical energy without extracting additional energy
|
|
159
|
+
from the environment. However, they provide fast response times and precise
|
|
160
|
+
temperature control.
|
|
161
|
+
"""
|
|
162
|
+
|
|
62
163
|
def __init__(
|
|
63
164
|
self,
|
|
64
165
|
label: str,
|
|
65
|
-
eta:
|
|
166
|
+
eta: TemporalDataUser,
|
|
66
167
|
P_el: Flow,
|
|
67
168
|
Q_th: Flow,
|
|
68
|
-
on_off_parameters: OnOffParameters = None,
|
|
69
|
-
meta_data:
|
|
169
|
+
on_off_parameters: OnOffParameters | None = None,
|
|
170
|
+
meta_data: dict | None = None,
|
|
70
171
|
):
|
|
71
|
-
"""
|
|
72
|
-
Args:
|
|
73
|
-
label: The label of the Element. Used to identify it in the FlowSystem
|
|
74
|
-
eta: thermal efficiency.
|
|
75
|
-
P_el: electric input-flow
|
|
76
|
-
Q_th: thermal output-flow.
|
|
77
|
-
on_off_parameters: Parameters defining the on/off behavior of the component.
|
|
78
|
-
meta_data: used to store more information about the Element. Is not used internally, but saved in the results. Only use python native types.
|
|
79
|
-
"""
|
|
80
172
|
super().__init__(
|
|
81
173
|
label,
|
|
82
174
|
inputs=[P_el],
|
|
@@ -101,24 +193,69 @@ class Power2Heat(LinearConverter):
|
|
|
101
193
|
|
|
102
194
|
@register_class_for_io
|
|
103
195
|
class HeatPump(LinearConverter):
|
|
196
|
+
"""
|
|
197
|
+
A specialized LinearConverter representing an electric heat pump for thermal energy generation.
|
|
198
|
+
|
|
199
|
+
Heat pumps convert electrical energy into thermal energy with a Coefficient of
|
|
200
|
+
Performance (COP) greater than 1, making them more efficient than direct electric
|
|
201
|
+
heating. This is a simplified wrapper around LinearConverter with predefined
|
|
202
|
+
conversion relationships for heat pump applications.
|
|
203
|
+
|
|
204
|
+
Args:
|
|
205
|
+
label: The label of the Element. Used to identify it in the FlowSystem.
|
|
206
|
+
COP: Coefficient of Performance (typically 1-20 range). Defines the ratio of
|
|
207
|
+
thermal output to electrical input. COP > 1 indicates the heat pump extracts
|
|
208
|
+
additional energy from the environment.
|
|
209
|
+
P_el: Electrical input-flow representing electricity consumption.
|
|
210
|
+
Q_th: Thermal output-flow representing heat generation.
|
|
211
|
+
on_off_parameters: Parameters defining binary operation constraints and costs.
|
|
212
|
+
meta_data: Used to store additional information. Not used internally but
|
|
213
|
+
saved in results. Only use Python native types.
|
|
214
|
+
|
|
215
|
+
Examples:
|
|
216
|
+
Air-source heat pump with constant COP:
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
air_hp = HeatPump(
|
|
220
|
+
label='air_source_heat_pump',
|
|
221
|
+
COP=3.5, # COP of 3.5 (350% efficiency)
|
|
222
|
+
P_el=electricity_flow,
|
|
223
|
+
Q_th=heating_flow,
|
|
224
|
+
)
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Ground-source heat pump with temperature-dependent COP:
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
ground_hp = HeatPump(
|
|
231
|
+
label='geothermal_heat_pump',
|
|
232
|
+
COP=temperature_dependent_cop, # Time-varying COP based on ground temp
|
|
233
|
+
P_el=electricity_flow,
|
|
234
|
+
Q_th=radiant_heating_flow,
|
|
235
|
+
on_off_parameters=OnOffParameters(
|
|
236
|
+
consecutive_on_hours_min=2, # Avoid frequent cycling
|
|
237
|
+
effects_per_running_hour={'maintenance': 0.5},
|
|
238
|
+
),
|
|
239
|
+
)
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Note:
|
|
243
|
+
The conversion relationship is: Q_th = P_el × COP
|
|
244
|
+
|
|
245
|
+
COP should be greater than 1 for realistic heat pump operation, with typical
|
|
246
|
+
values ranging from 2-6 depending on technology and operating conditions.
|
|
247
|
+
Higher COP values indicate more efficient heat extraction from the environment.
|
|
248
|
+
"""
|
|
249
|
+
|
|
104
250
|
def __init__(
|
|
105
251
|
self,
|
|
106
252
|
label: str,
|
|
107
|
-
COP:
|
|
253
|
+
COP: TemporalDataUser,
|
|
108
254
|
P_el: Flow,
|
|
109
255
|
Q_th: Flow,
|
|
110
|
-
on_off_parameters: OnOffParameters = None,
|
|
111
|
-
meta_data:
|
|
256
|
+
on_off_parameters: OnOffParameters | None = None,
|
|
257
|
+
meta_data: dict | None = None,
|
|
112
258
|
):
|
|
113
|
-
"""
|
|
114
|
-
Args:
|
|
115
|
-
label: The label of the Element. Used to identify it in the FlowSystem
|
|
116
|
-
COP: Coefficient of performance.
|
|
117
|
-
P_el: electricity input-flow.
|
|
118
|
-
Q_th: thermal output-flow.
|
|
119
|
-
on_off_parameters: Parameters defining the on/off behavior of the component.
|
|
120
|
-
meta_data: used to store more information about the Element. Is not used internally, but saved in the results. Only use python native types.
|
|
121
|
-
"""
|
|
122
259
|
super().__init__(
|
|
123
260
|
label,
|
|
124
261
|
inputs=[P_el],
|
|
@@ -143,29 +280,76 @@ class HeatPump(LinearConverter):
|
|
|
143
280
|
|
|
144
281
|
@register_class_for_io
|
|
145
282
|
class CoolingTower(LinearConverter):
|
|
283
|
+
"""
|
|
284
|
+
A specialized LinearConverter representing a cooling tower for waste heat rejection.
|
|
285
|
+
|
|
286
|
+
Cooling towers consume electrical energy (for fans, pumps) to reject thermal energy
|
|
287
|
+
to the environment through evaporation and heat transfer. The electricity demand
|
|
288
|
+
is typically a small fraction of the thermal load being rejected. This component
|
|
289
|
+
has no thermal outputs as the heat is rejected to the environment.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
label: The label of the Element. Used to identify it in the FlowSystem.
|
|
293
|
+
specific_electricity_demand: Auxiliary electricity demand per unit of cooling
|
|
294
|
+
power (dimensionless, typically 0.01-0.05 range). Represents the fraction
|
|
295
|
+
of thermal power that must be supplied as electricity for fans and pumps.
|
|
296
|
+
P_el: Electrical input-flow representing electricity consumption for fans/pumps.
|
|
297
|
+
Q_th: Thermal input-flow representing waste heat to be rejected to environment.
|
|
298
|
+
on_off_parameters: Parameters defining binary operation constraints and costs.
|
|
299
|
+
meta_data: Used to store additional information. Not used internally but
|
|
300
|
+
saved in results. Only use Python native types.
|
|
301
|
+
|
|
302
|
+
Examples:
|
|
303
|
+
Industrial cooling tower:
|
|
304
|
+
|
|
305
|
+
```python
|
|
306
|
+
cooling_tower = CoolingTower(
|
|
307
|
+
label='process_cooling_tower',
|
|
308
|
+
specific_electricity_demand=0.025, # 2.5% auxiliary power
|
|
309
|
+
P_el=cooling_electricity,
|
|
310
|
+
Q_th=waste_heat_flow,
|
|
311
|
+
)
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Power plant condenser cooling:
|
|
315
|
+
|
|
316
|
+
```python
|
|
317
|
+
condenser_cooling = CoolingTower(
|
|
318
|
+
label='power_plant_cooling',
|
|
319
|
+
specific_electricity_demand=0.015, # 1.5% auxiliary power
|
|
320
|
+
P_el=auxiliary_electricity,
|
|
321
|
+
Q_th=condenser_waste_heat,
|
|
322
|
+
on_off_parameters=OnOffParameters(
|
|
323
|
+
consecutive_on_hours_min=4, # Minimum operation time
|
|
324
|
+
effects_per_running_hour={'water_consumption': 2.5}, # m³/h
|
|
325
|
+
),
|
|
326
|
+
)
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Note:
|
|
330
|
+
The conversion relationship is: P_el = Q_th × specific_electricity_demand
|
|
331
|
+
|
|
332
|
+
The cooling tower consumes electrical power proportional to the thermal load.
|
|
333
|
+
No thermal energy is produced - all thermal input is rejected to the environment.
|
|
334
|
+
|
|
335
|
+
Typical specific electricity demands range from 1-5% of the thermal cooling load,
|
|
336
|
+
depending on tower design, climate conditions, and operational requirements.
|
|
337
|
+
"""
|
|
338
|
+
|
|
146
339
|
def __init__(
|
|
147
340
|
self,
|
|
148
341
|
label: str,
|
|
149
|
-
specific_electricity_demand:
|
|
342
|
+
specific_electricity_demand: TemporalDataUser,
|
|
150
343
|
P_el: Flow,
|
|
151
344
|
Q_th: Flow,
|
|
152
|
-
on_off_parameters: OnOffParameters = None,
|
|
153
|
-
meta_data:
|
|
345
|
+
on_off_parameters: OnOffParameters | None = None,
|
|
346
|
+
meta_data: dict | None = None,
|
|
154
347
|
):
|
|
155
|
-
"""
|
|
156
|
-
Args:
|
|
157
|
-
label: The label of the Element. Used to identify it in the FlowSystem
|
|
158
|
-
specific_electricity_demand: auxiliary electricty demand per cooling power, i.g. 0.02 (2 %).
|
|
159
|
-
P_el: electricity input-flow.
|
|
160
|
-
Q_th: thermal input-flow.
|
|
161
|
-
on_off_parameters: Parameters defining the on/off behavior of the component.
|
|
162
|
-
meta_data: used to store more information about the Element. Is not used internally, but saved in the results. Only use python native types.
|
|
163
|
-
"""
|
|
164
348
|
super().__init__(
|
|
165
349
|
label,
|
|
166
350
|
inputs=[P_el, Q_th],
|
|
167
351
|
outputs=[],
|
|
168
|
-
conversion_factors=[{P_el.label: 1, Q_th.label:
|
|
352
|
+
conversion_factors=[{P_el.label: -1, Q_th.label: specific_electricity_demand}],
|
|
169
353
|
on_off_parameters=on_off_parameters,
|
|
170
354
|
meta_data=meta_data,
|
|
171
355
|
)
|
|
@@ -177,38 +361,90 @@ class CoolingTower(LinearConverter):
|
|
|
177
361
|
|
|
178
362
|
@property
|
|
179
363
|
def specific_electricity_demand(self):
|
|
180
|
-
return
|
|
364
|
+
return self.conversion_factors[0][self.Q_th.label]
|
|
181
365
|
|
|
182
366
|
@specific_electricity_demand.setter
|
|
183
367
|
def specific_electricity_demand(self, value):
|
|
184
368
|
check_bounds(value, 'specific_electricity_demand', self.label_full, 0, 1)
|
|
185
|
-
self.conversion_factors[0][self.Q_th.label] =
|
|
369
|
+
self.conversion_factors[0][self.Q_th.label] = value
|
|
186
370
|
|
|
187
371
|
|
|
188
372
|
@register_class_for_io
|
|
189
373
|
class CHP(LinearConverter):
|
|
374
|
+
"""
|
|
375
|
+
A specialized LinearConverter representing a Combined Heat and Power (CHP) unit.
|
|
376
|
+
|
|
377
|
+
CHP units simultaneously generate both electrical and thermal energy from a single
|
|
378
|
+
fuel input, providing higher overall efficiency than separate generation. This is
|
|
379
|
+
a wrapper around LinearConverter with predefined conversion relationships for
|
|
380
|
+
cogeneration applications.
|
|
381
|
+
|
|
382
|
+
Args:
|
|
383
|
+
label: The label of the Element. Used to identify it in the FlowSystem.
|
|
384
|
+
eta_th: Thermal efficiency factor (0-1 range). Defines the fraction of fuel
|
|
385
|
+
energy converted to useful thermal output.
|
|
386
|
+
eta_el: Electrical efficiency factor (0-1 range). Defines the fraction of fuel
|
|
387
|
+
energy converted to electrical output.
|
|
388
|
+
Q_fu: Fuel input-flow representing fuel consumption.
|
|
389
|
+
P_el: Electrical output-flow representing electricity generation.
|
|
390
|
+
Q_th: Thermal output-flow representing heat generation.
|
|
391
|
+
on_off_parameters: Parameters defining binary operation constraints and costs.
|
|
392
|
+
meta_data: Used to store additional information. Not used internally but
|
|
393
|
+
saved in results. Only use Python native types.
|
|
394
|
+
|
|
395
|
+
Examples:
|
|
396
|
+
Natural gas CHP unit:
|
|
397
|
+
|
|
398
|
+
```python
|
|
399
|
+
gas_chp = CHP(
|
|
400
|
+
label='natural_gas_chp',
|
|
401
|
+
eta_th=0.45, # 45% thermal efficiency
|
|
402
|
+
eta_el=0.35, # 35% electrical efficiency (80% total)
|
|
403
|
+
Q_fu=natural_gas_flow,
|
|
404
|
+
P_el=electricity_flow,
|
|
405
|
+
Q_th=district_heat_flow,
|
|
406
|
+
)
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Industrial CHP with operational constraints:
|
|
410
|
+
|
|
411
|
+
```python
|
|
412
|
+
industrial_chp = CHP(
|
|
413
|
+
label='industrial_chp',
|
|
414
|
+
eta_th=0.40,
|
|
415
|
+
eta_el=0.38,
|
|
416
|
+
Q_fu=fuel_gas_flow,
|
|
417
|
+
P_el=plant_electricity,
|
|
418
|
+
Q_th=process_steam,
|
|
419
|
+
on_off_parameters=OnOffParameters(
|
|
420
|
+
consecutive_on_hours_min=8, # Minimum 8-hour operation
|
|
421
|
+
effects_per_switch_on={'startup_cost': 5000},
|
|
422
|
+
on_hours_total_max=6000, # Annual operating limit
|
|
423
|
+
),
|
|
424
|
+
)
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Note:
|
|
428
|
+
The conversion relationships are:
|
|
429
|
+
- Q_th = Q_fu × eta_th (thermal output)
|
|
430
|
+
- P_el = Q_fu × eta_el (electrical output)
|
|
431
|
+
|
|
432
|
+
Total efficiency (eta_th + eta_el) should be ≤ 1.0, with typical combined
|
|
433
|
+
efficiencies of 80-90% for modern CHP units. This provides significant
|
|
434
|
+
efficiency gains compared to separate heat and power generation.
|
|
435
|
+
"""
|
|
436
|
+
|
|
190
437
|
def __init__(
|
|
191
438
|
self,
|
|
192
439
|
label: str,
|
|
193
|
-
eta_th:
|
|
194
|
-
eta_el:
|
|
440
|
+
eta_th: TemporalDataUser,
|
|
441
|
+
eta_el: TemporalDataUser,
|
|
195
442
|
Q_fu: Flow,
|
|
196
443
|
P_el: Flow,
|
|
197
444
|
Q_th: Flow,
|
|
198
|
-
on_off_parameters: OnOffParameters = None,
|
|
199
|
-
meta_data:
|
|
445
|
+
on_off_parameters: OnOffParameters | None = None,
|
|
446
|
+
meta_data: dict | None = None,
|
|
200
447
|
):
|
|
201
|
-
"""
|
|
202
|
-
Args:
|
|
203
|
-
label: The label of the Element. Used to identify it in the FlowSystem
|
|
204
|
-
eta_th: thermal efficiency.
|
|
205
|
-
eta_el: electrical efficiency.
|
|
206
|
-
Q_fu: fuel input-flow.
|
|
207
|
-
P_el: electricity output-flow.
|
|
208
|
-
Q_th: heat output-flow.
|
|
209
|
-
on_off_parameters: Parameters defining the on/off behavior of the component.
|
|
210
|
-
meta_data: used to store more information about the Element. Is not used internally, but saved in the results. Only use python native types.
|
|
211
|
-
"""
|
|
212
448
|
heat = {Q_fu.label: eta_th, Q_th.label: 1}
|
|
213
449
|
electricity = {Q_fu.label: eta_el, P_el.label: 1}
|
|
214
450
|
|
|
@@ -248,36 +484,85 @@ class CHP(LinearConverter):
|
|
|
248
484
|
|
|
249
485
|
@register_class_for_io
|
|
250
486
|
class HeatPumpWithSource(LinearConverter):
|
|
487
|
+
"""
|
|
488
|
+
A specialized LinearConverter representing a heat pump with explicit heat source modeling.
|
|
489
|
+
|
|
490
|
+
This component models a heat pump that extracts thermal energy from a heat source
|
|
491
|
+
(ground, air, water) and upgrades it using electrical energy to provide higher-grade
|
|
492
|
+
thermal output. Unlike the simple HeatPump class, this explicitly models both the
|
|
493
|
+
heat source extraction and electrical consumption with their interdependent relationships.
|
|
494
|
+
|
|
495
|
+
Args:
|
|
496
|
+
label: The label of the Element. Used to identify it in the FlowSystem.
|
|
497
|
+
COP: Coefficient of Performance (typically 1-20 range). Defines the ratio of
|
|
498
|
+
thermal output to electrical input. The heat source extraction is automatically
|
|
499
|
+
calculated as Q_ab = Q_th × (COP-1)/COP.
|
|
500
|
+
P_el: Electrical input-flow representing electricity consumption for compressor.
|
|
501
|
+
Q_ab: Heat source input-flow representing thermal energy extracted from environment
|
|
502
|
+
(ground, air, water source).
|
|
503
|
+
Q_th: Thermal output-flow representing useful heat delivered to the application.
|
|
504
|
+
on_off_parameters: Parameters defining binary operation constraints and costs.
|
|
505
|
+
meta_data: Used to store additional information. Not used internally but
|
|
506
|
+
saved in results. Only use Python native types.
|
|
507
|
+
|
|
508
|
+
Examples:
|
|
509
|
+
Ground-source heat pump with explicit ground coupling:
|
|
510
|
+
|
|
511
|
+
```python
|
|
512
|
+
ground_source_hp = HeatPumpWithSource(
|
|
513
|
+
label='geothermal_heat_pump',
|
|
514
|
+
COP=4.5, # High COP due to stable ground temperature
|
|
515
|
+
P_el=electricity_flow,
|
|
516
|
+
Q_ab=ground_heat_extraction, # Heat extracted from ground loop
|
|
517
|
+
Q_th=building_heating_flow,
|
|
518
|
+
)
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
Air-source heat pump with temperature-dependent performance:
|
|
522
|
+
|
|
523
|
+
```python
|
|
524
|
+
waste_heat_pump = HeatPumpWithSource(
|
|
525
|
+
label='waste_heat_pump',
|
|
526
|
+
COP=temperature_dependent_cop, # Varies with temperature of heat source
|
|
527
|
+
P_el=electricity_consumption,
|
|
528
|
+
Q_ab=industrial_heat_extraction, # Heat extracted from a industrial process or waste water
|
|
529
|
+
Q_th=heat_supply,
|
|
530
|
+
on_off_parameters=OnOffParameters(
|
|
531
|
+
consecutive_on_hours_min=0.5, # 30-minute minimum runtime
|
|
532
|
+
effects_per_switch_on={'costs': 1000},
|
|
533
|
+
),
|
|
534
|
+
)
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
Note:
|
|
538
|
+
The conversion relationships are:
|
|
539
|
+
- Q_th = P_el × COP (thermal output from electrical input)
|
|
540
|
+
- Q_ab = Q_th × (COP-1)/COP (heat source extraction)
|
|
541
|
+
- Energy balance: Q_th = P_el + Q_ab
|
|
542
|
+
|
|
543
|
+
This formulation explicitly tracks the heat source, which is
|
|
544
|
+
important for systems where the source capacity or temperature is limited,
|
|
545
|
+
or where the impact of heat extraction must be considered.
|
|
546
|
+
|
|
547
|
+
COP should be > 1 for thermodynamically valid operation, with typical
|
|
548
|
+
values of 2-6 depending on source and sink temperatures.
|
|
549
|
+
"""
|
|
550
|
+
|
|
251
551
|
def __init__(
|
|
252
552
|
self,
|
|
253
553
|
label: str,
|
|
254
|
-
COP:
|
|
554
|
+
COP: TemporalDataUser,
|
|
255
555
|
P_el: Flow,
|
|
256
556
|
Q_ab: Flow,
|
|
257
557
|
Q_th: Flow,
|
|
258
|
-
on_off_parameters: OnOffParameters = None,
|
|
259
|
-
meta_data:
|
|
558
|
+
on_off_parameters: OnOffParameters | None = None,
|
|
559
|
+
meta_data: dict | None = None,
|
|
260
560
|
):
|
|
261
|
-
"""
|
|
262
|
-
Args:
|
|
263
|
-
label: The label of the Element. Used to identify it in the FlowSystem
|
|
264
|
-
COP: Coefficient of performance.
|
|
265
|
-
Q_ab: Heatsource input-flow.
|
|
266
|
-
P_el: electricity input-flow.
|
|
267
|
-
Q_th: thermal output-flow.
|
|
268
|
-
on_off_parameters: Parameters defining the on/off behavior of the component.
|
|
269
|
-
meta_data: used to store more information about the Element. Is not used internally, but saved in the results. Only use python native types.
|
|
270
|
-
"""
|
|
271
|
-
|
|
272
|
-
# super:
|
|
273
|
-
electricity = {P_el.label: COP, Q_th.label: 1}
|
|
274
|
-
heat_source = {Q_ab.label: COP / (COP - 1), Q_th.label: 1}
|
|
275
|
-
|
|
276
561
|
super().__init__(
|
|
277
562
|
label,
|
|
278
563
|
inputs=[P_el, Q_ab],
|
|
279
564
|
outputs=[Q_th],
|
|
280
|
-
conversion_factors=[
|
|
565
|
+
conversion_factors=[{P_el.label: COP, Q_th.label: 1}, {Q_ab.label: COP / (COP - 1), Q_th.label: 1}],
|
|
281
566
|
on_off_parameters=on_off_parameters,
|
|
282
567
|
meta_data=meta_data,
|
|
283
568
|
)
|
|
@@ -285,23 +570,30 @@ class HeatPumpWithSource(LinearConverter):
|
|
|
285
570
|
self.Q_ab = Q_ab
|
|
286
571
|
self.Q_th = Q_th
|
|
287
572
|
|
|
573
|
+
if np.any(np.asarray(self.COP) <= 1):
|
|
574
|
+
raise ValueError(f'{self.label_full}.COP must be strictly > 1 for HeatPumpWithSource.')
|
|
575
|
+
|
|
288
576
|
@property
|
|
289
577
|
def COP(self): # noqa: N802
|
|
290
|
-
return self.conversion_factors[0][self.
|
|
578
|
+
return self.conversion_factors[0][self.P_el.label]
|
|
291
579
|
|
|
292
580
|
@COP.setter
|
|
293
581
|
def COP(self, value): # noqa: N802
|
|
294
582
|
check_bounds(value, 'COP', self.label_full, 1, 20)
|
|
295
|
-
|
|
296
|
-
|
|
583
|
+
if np.any(np.asarray(value) <= 1):
|
|
584
|
+
raise ValueError(f'{self.label_full}.COP must be strictly > 1 for HeatPumpWithSource.')
|
|
585
|
+
self.conversion_factors = [
|
|
586
|
+
{self.P_el.label: value, self.Q_th.label: 1},
|
|
587
|
+
{self.Q_ab.label: value / (value - 1), self.Q_th.label: 1},
|
|
588
|
+
]
|
|
297
589
|
|
|
298
590
|
|
|
299
591
|
def check_bounds(
|
|
300
|
-
value:
|
|
592
|
+
value: TemporalDataUser,
|
|
301
593
|
parameter_label: str,
|
|
302
594
|
element_label: str,
|
|
303
|
-
lower_bound:
|
|
304
|
-
upper_bound:
|
|
595
|
+
lower_bound: TemporalDataUser,
|
|
596
|
+
upper_bound: TemporalDataUser,
|
|
305
597
|
) -> None:
|
|
306
598
|
"""
|
|
307
599
|
Check if the value is within the bounds. The bounds are exclusive.
|