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.
Files changed (58) hide show
  1. flixopt/__init__.py +33 -4
  2. flixopt/aggregation.py +60 -80
  3. flixopt/calculation.py +403 -182
  4. flixopt/commons.py +1 -10
  5. flixopt/components.py +939 -448
  6. flixopt/config.py +553 -191
  7. flixopt/core.py +513 -846
  8. flixopt/effects.py +644 -178
  9. flixopt/elements.py +610 -355
  10. flixopt/features.py +394 -966
  11. flixopt/flow_system.py +736 -219
  12. flixopt/interface.py +1104 -302
  13. flixopt/io.py +103 -79
  14. flixopt/linear_converters.py +387 -95
  15. flixopt/modeling.py +757 -0
  16. flixopt/network_app.py +73 -39
  17. flixopt/plotting.py +294 -138
  18. flixopt/results.py +1254 -300
  19. flixopt/solvers.py +25 -21
  20. flixopt/structure.py +938 -396
  21. flixopt/utils.py +36 -12
  22. flixopt-3.0.1.dist-info/METADATA +209 -0
  23. flixopt-3.0.1.dist-info/RECORD +26 -0
  24. flixopt-3.0.1.dist-info/top_level.txt +1 -0
  25. docs/examples/00-Minimal Example.md +0 -5
  26. docs/examples/01-Basic Example.md +0 -5
  27. docs/examples/02-Complex Example.md +0 -10
  28. docs/examples/03-Calculation Modes.md +0 -5
  29. docs/examples/index.md +0 -5
  30. docs/faq/contribute.md +0 -61
  31. docs/faq/index.md +0 -3
  32. docs/images/architecture_flixOpt-pre2.0.0.png +0 -0
  33. docs/images/architecture_flixOpt.png +0 -0
  34. docs/images/flixopt-icon.svg +0 -1
  35. docs/javascripts/mathjax.js +0 -18
  36. docs/user-guide/Mathematical Notation/Bus.md +0 -33
  37. docs/user-guide/Mathematical Notation/Effects, Penalty & Objective.md +0 -132
  38. docs/user-guide/Mathematical Notation/Flow.md +0 -26
  39. docs/user-guide/Mathematical Notation/LinearConverter.md +0 -21
  40. docs/user-guide/Mathematical Notation/Piecewise.md +0 -49
  41. docs/user-guide/Mathematical Notation/Storage.md +0 -44
  42. docs/user-guide/Mathematical Notation/index.md +0 -22
  43. docs/user-guide/Mathematical Notation/others.md +0 -3
  44. docs/user-guide/index.md +0 -124
  45. flixopt/config.yaml +0 -10
  46. flixopt-2.2.0rc2.dist-info/METADATA +0 -167
  47. flixopt-2.2.0rc2.dist-info/RECORD +0 -54
  48. flixopt-2.2.0rc2.dist-info/top_level.txt +0 -5
  49. pics/architecture_flixOpt-pre2.0.0.png +0 -0
  50. pics/architecture_flixOpt.png +0 -0
  51. pics/flixOpt_plotting.jpg +0 -0
  52. pics/flixopt-icon.svg +0 -1
  53. pics/pics.pptx +0 -0
  54. scripts/extract_release_notes.py +0 -45
  55. scripts/gen_ref_pages.py +0 -54
  56. tests/ressources/Zeitreihen2020.csv +0 -35137
  57. {flixopt-2.2.0rc2.dist-info → flixopt-3.0.1.dist-info}/WHEEL +0 -0
  58. {flixopt-2.2.0rc2.dist-info → flixopt-3.0.1.dist-info}/licenses/LICENSE +0 -0
@@ -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 Dict, Optional
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 NumericDataTS, TimeSeriesData
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: NumericDataTS,
79
+ eta: TemporalDataUser,
25
80
  Q_fu: Flow,
26
81
  Q_th: Flow,
27
- on_off_parameters: OnOffParameters = None,
28
- meta_data: Optional[Dict] = None,
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: NumericDataTS,
166
+ eta: TemporalDataUser,
66
167
  P_el: Flow,
67
168
  Q_th: Flow,
68
- on_off_parameters: OnOffParameters = None,
69
- meta_data: Optional[Dict] = None,
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: NumericDataTS,
253
+ COP: TemporalDataUser,
108
254
  P_el: Flow,
109
255
  Q_th: Flow,
110
- on_off_parameters: OnOffParameters = None,
111
- meta_data: Optional[Dict] = None,
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: NumericDataTS,
342
+ specific_electricity_demand: TemporalDataUser,
150
343
  P_el: Flow,
151
344
  Q_th: Flow,
152
- on_off_parameters: OnOffParameters = None,
153
- meta_data: Optional[Dict] = None,
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: -specific_electricity_demand}],
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 -self.conversion_factors[0][self.Q_th.label]
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] = -value
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: NumericDataTS,
194
- eta_el: NumericDataTS,
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: Optional[Dict] = None,
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: NumericDataTS,
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: Optional[Dict] = None,
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=[electricity, heat_source],
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.Q_th.label]
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
- self.conversion_factors[0][self.Q_th.label] = value
296
- self.conversion_factors[1][self.Q_th.label] = value / (value - 1)
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: NumericDataTS,
592
+ value: TemporalDataUser,
301
593
  parameter_label: str,
302
594
  element_label: str,
303
- lower_bound: NumericDataTS,
304
- upper_bound: NumericDataTS,
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.