exerpy 0.0.2__py3-none-any.whl → 0.0.3__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.
- exerpy/__init__.py +2 -4
- exerpy/analyses.py +597 -297
- exerpy/components/__init__.py +3 -0
- exerpy/components/combustion/base.py +53 -35
- exerpy/components/component.py +8 -8
- exerpy/components/heat_exchanger/base.py +186 -119
- exerpy/components/heat_exchanger/condenser.py +96 -60
- exerpy/components/heat_exchanger/simple.py +237 -137
- exerpy/components/heat_exchanger/steam_generator.py +46 -41
- exerpy/components/helpers/cycle_closer.py +61 -34
- exerpy/components/helpers/power_bus.py +117 -0
- exerpy/components/nodes/deaerator.py +176 -58
- exerpy/components/nodes/drum.py +50 -39
- exerpy/components/nodes/flash_tank.py +218 -43
- exerpy/components/nodes/mixer.py +249 -69
- exerpy/components/nodes/splitter.py +173 -0
- exerpy/components/nodes/storage.py +130 -0
- exerpy/components/piping/valve.py +311 -115
- exerpy/components/power_machines/generator.py +105 -38
- exerpy/components/power_machines/motor.py +111 -39
- exerpy/components/turbomachinery/compressor.py +181 -63
- exerpy/components/turbomachinery/pump.py +182 -63
- exerpy/components/turbomachinery/turbine.py +182 -74
- exerpy/functions.py +388 -263
- exerpy/parser/from_aspen/aspen_config.py +57 -48
- exerpy/parser/from_aspen/aspen_parser.py +373 -280
- exerpy/parser/from_ebsilon/__init__.py +2 -2
- exerpy/parser/from_ebsilon/check_ebs_path.py +15 -19
- exerpy/parser/from_ebsilon/ebsilon_config.py +328 -226
- exerpy/parser/from_ebsilon/ebsilon_functions.py +205 -38
- exerpy/parser/from_ebsilon/ebsilon_parser.py +392 -255
- exerpy/parser/from_ebsilon/utils.py +16 -11
- exerpy/parser/from_tespy/tespy_config.py +32 -1
- exerpy/parser/from_tespy/tespy_parser.py +151 -0
- {exerpy-0.0.2.dist-info → exerpy-0.0.3.dist-info}/METADATA +43 -2
- exerpy-0.0.3.dist-info/RECORD +48 -0
- exerpy-0.0.2.dist-info/RECORD +0 -44
- {exerpy-0.0.2.dist-info → exerpy-0.0.3.dist-info}/WHEEL +0 -0
- {exerpy-0.0.2.dist-info → exerpy-0.0.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,8 +2,7 @@ import logging
|
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
|
|
5
|
-
from exerpy.components.component import Component
|
|
6
|
-
from exerpy.components.component import component_registry
|
|
5
|
+
from exerpy.components.component import Component, component_registry
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
@component_registry
|
|
@@ -187,7 +186,7 @@ class HeatExchanger(Component):
|
|
|
187
186
|
Case 5: Only the cold inlet below ambient temperature
|
|
188
187
|
|
|
189
188
|
If `split_physical_exergy=True`:
|
|
190
|
-
|
|
189
|
+
|
|
191
190
|
.. math::
|
|
192
191
|
\dot{E}_{\mathrm{P}}
|
|
193
192
|
= \dot{E}^{\mathrm{T}}_{\mathrm{out},2}
|
|
@@ -198,7 +197,7 @@ class HeatExchanger(Component):
|
|
|
198
197
|
- \dot{E}^{\mathrm{PH}}_{\mathrm{out},1}\bigr)
|
|
199
198
|
+ \bigl(\dot{E}^{\mathrm{PH}}_{\mathrm{in},2}
|
|
200
199
|
- \dot{E}^{\mathrm{M}}_{\mathrm{out},2}\bigr)
|
|
201
|
-
|
|
200
|
+
|
|
202
201
|
Else:
|
|
203
202
|
|
|
204
203
|
.. math::
|
|
@@ -211,7 +210,7 @@ class HeatExchanger(Component):
|
|
|
211
210
|
- \dot{E}^{\mathrm{PH}}_{\mathrm{out},1}\bigr)
|
|
212
211
|
+ \dot{E}^{\mathrm{PH}}_{\mathrm{in},2}
|
|
213
212
|
|
|
214
|
-
Case 6: Hot stream always above and cold stream always below ambiente temperature (dissipative case):
|
|
213
|
+
Case 6: Hot stream always above and cold stream always below ambiente temperature (dissipative case):
|
|
215
214
|
|
|
216
215
|
.. math::
|
|
217
216
|
\dot{E}_{\mathrm{P}} = \mathrm{NaN}
|
|
@@ -258,89 +257,125 @@ class HeatExchanger(Component):
|
|
|
258
257
|
|
|
259
258
|
if not self.dissipative:
|
|
260
259
|
# Case 1: All streams are above the ambient temperature
|
|
261
|
-
if all([stream[
|
|
260
|
+
if all([stream["T"] >= T0 for stream in all_streams]):
|
|
262
261
|
if split_physical_exergy:
|
|
263
|
-
self.E_P = self.outl[1][
|
|
264
|
-
self.E_F =
|
|
265
|
-
self.inl[
|
|
262
|
+
self.E_P = self.outl[1]["m"] * self.outl[1]["e_T"] - self.inl[1]["m"] * self.inl[1]["e_T"]
|
|
263
|
+
self.E_F = (
|
|
264
|
+
self.inl[0]["m"] * self.inl[0]["e_PH"]
|
|
265
|
+
- self.outl[0]["m"] * self.outl[0]["e_PH"]
|
|
266
|
+
+ (self.inl[1]["m"] * self.inl[1]["e_M"] - self.outl[1]["m"] * self.outl[1]["e_M"])
|
|
267
|
+
)
|
|
266
268
|
else:
|
|
267
|
-
self.E_P = self.outl[1][
|
|
268
|
-
self.E_F = self.inl[0][
|
|
269
|
+
self.E_P = self.outl[1]["m"] * self.outl[1]["e_PH"] - self.inl[1]["m"] * self.inl[1]["e_PH"]
|
|
270
|
+
self.E_F = self.inl[0]["m"] * self.inl[0]["e_PH"] - self.outl[0]["m"] * self.outl[0]["e_PH"]
|
|
269
271
|
|
|
270
272
|
# Case 2: All streams are below or equal to the ambient temperature
|
|
271
|
-
elif all([stream[
|
|
273
|
+
elif all([stream["T"] <= T0 for stream in all_streams]):
|
|
272
274
|
if split_physical_exergy:
|
|
273
|
-
self.E_P = self.outl[0][
|
|
274
|
-
self.E_F =
|
|
275
|
-
self.inl[
|
|
275
|
+
self.E_P = self.outl[0]["m"] * self.outl[0]["e_T"] - self.inl[0]["m"] * self.inl[0]["e_T"]
|
|
276
|
+
self.E_F = (
|
|
277
|
+
self.inl[1]["m"] * self.inl[1]["e_PH"]
|
|
278
|
+
- self.outl[1]["m"] * self.outl[1]["e_PH"]
|
|
279
|
+
+ (self.inl[0]["m"] * self.inl[0]["e_M"] - self.outl[0]["m"] * self.outl[0]["e_M"])
|
|
280
|
+
)
|
|
276
281
|
else:
|
|
277
|
-
logging.warning(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
282
|
+
logging.warning(
|
|
283
|
+
"While dealing with heat exchnager below ambient temperautre, "
|
|
284
|
+
"physical exergy should be split into thermal and mechanical components!"
|
|
285
|
+
)
|
|
286
|
+
self.E_P = self.outl[0]["m"] * self.outl[0]["e_PH"] - self.inl[0]["m"] * self.inl[0]["e_PH"]
|
|
287
|
+
self.E_F = self.inl[1]["m"] * self.inl[1]["e_PH"] - self.outl[1]["m"] * self.outl[1]["e_PH"]
|
|
281
288
|
|
|
282
289
|
# Case 3: Both stream crossing T0 (hot inlet and cold outlet > T0, hot outlet and cold inlet <= T0)
|
|
283
|
-
elif (
|
|
284
|
-
self.outl[0][
|
|
290
|
+
elif (
|
|
291
|
+
self.inl[0]["T"] > T0 and self.outl[1]["T"] > T0 and self.outl[0]["T"] <= T0 and self.inl[1]["T"] <= T0
|
|
292
|
+
):
|
|
285
293
|
if split_physical_exergy:
|
|
286
|
-
self.E_P = self.outl[0][
|
|
287
|
-
self.E_F =
|
|
288
|
-
self.
|
|
294
|
+
self.E_P = self.outl[0]["m"] * self.outl[0]["e_T"] + self.outl[1]["m"] * self.outl[1]["e_T"]
|
|
295
|
+
self.E_F = (
|
|
296
|
+
self.inl[0]["m"] * self.inl[0]["e_PH"]
|
|
297
|
+
+ self.inl[1]["m"] * self.inl[1]["e_PH"]
|
|
298
|
+
- (self.outl[0]["m"] * self.outl[0]["e_M"] + self.outl[1]["m"] * self.outl[1]["e_M"])
|
|
299
|
+
)
|
|
289
300
|
else:
|
|
290
|
-
logging.warning(
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
301
|
+
logging.warning(
|
|
302
|
+
"While dealing with heat exchnager below ambient temperautre, "
|
|
303
|
+
"physical exergy should be split into thermal and mechanical components!"
|
|
304
|
+
)
|
|
305
|
+
self.E_P = self.outl[0]["m"] * self.outl[0]["e_PH"] + self.outl[1]["m"] * self.outl[1]["e_PH"]
|
|
306
|
+
self.E_F = self.inl[0]["m"] * self.inl[0]["e_PH"] + self.inl[1]["m"] * self.inl[1]["e_PH"]
|
|
294
307
|
|
|
295
308
|
# Case 4: Only hot inlet > T0
|
|
296
|
-
elif (
|
|
297
|
-
self.outl[0][
|
|
309
|
+
elif (
|
|
310
|
+
self.inl[0]["T"] > T0 and self.inl[1]["T"] <= T0 and self.outl[0]["T"] <= T0 and self.outl[1]["T"] <= T0
|
|
311
|
+
):
|
|
298
312
|
if split_physical_exergy:
|
|
299
|
-
self.E_P = self.outl[0][
|
|
300
|
-
self.E_F =
|
|
301
|
-
self.
|
|
313
|
+
self.E_P = self.outl[0]["m"] * self.outl[0]["e_T"]
|
|
314
|
+
self.E_F = (
|
|
315
|
+
self.inl[0]["m"] * self.inl[0]["e_PH"]
|
|
316
|
+
+ self.inl[1]["m"] * self.inl[1]["e_PH"]
|
|
317
|
+
- (self.outl[1]["m"] * self.outl[1]["e_PH"] + self.outl[0]["m"] * self.outl[0]["e_M"])
|
|
318
|
+
)
|
|
302
319
|
else:
|
|
303
|
-
logging.warning(
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
320
|
+
logging.warning(
|
|
321
|
+
"While dealing with heat exchnager below ambient temperautre, "
|
|
322
|
+
"physical exergy should be split into thermal and mechanical components!"
|
|
323
|
+
)
|
|
324
|
+
self.E_P = self.outl[0]["m"] * self.outl[0]["e_PH"]
|
|
325
|
+
self.E_F = self.inl[0]["m"] * self.inl[0]["e_PH"] + (
|
|
326
|
+
self.inl[1]["m"] * self.inl[1]["e_PH"] - self.outl[1]["m"] * self.outl[1]["e_PH"]
|
|
327
|
+
)
|
|
308
328
|
|
|
309
329
|
# Case 5: Only cold inlet <= T0
|
|
310
|
-
elif
|
|
311
|
-
self.outl[0]["T"] > T0 and self.outl[1]["T"] > T0):
|
|
330
|
+
elif self.inl[0]["T"] > T0 and self.inl[1]["T"] <= T0 and self.outl[0]["T"] > T0 and self.outl[1]["T"] > T0:
|
|
312
331
|
if split_physical_exergy:
|
|
313
|
-
self.E_P = self.outl[1][
|
|
314
|
-
self.E_F =
|
|
315
|
-
self.inl[
|
|
332
|
+
self.E_P = self.outl[1]["m"] * self.outl[1]["e_T"]
|
|
333
|
+
self.E_F = (
|
|
334
|
+
self.inl[0]["m"] * self.inl[0]["e_PH"]
|
|
335
|
+
- self.outl[0]["m"] * self.outl[0]["e_PH"]
|
|
336
|
+
+ (self.inl[1]["m"] * self.inl[1]["e_PH"] - self.outl[1]["m"] * self.outl[1]["e_M"])
|
|
337
|
+
)
|
|
316
338
|
else:
|
|
317
|
-
logging.warning(
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
339
|
+
logging.warning(
|
|
340
|
+
"While dealing with heat exchnager below ambient temperautre, "
|
|
341
|
+
"physical exergy should be split into thermal and mechanical components!"
|
|
342
|
+
)
|
|
343
|
+
self.E_P = self.outl[1]["m"] * self.outl[1]["e_PH"]
|
|
344
|
+
self.E_F = (
|
|
345
|
+
self.inl[0]["m"] * self.inl[0]["e_PH"]
|
|
346
|
+
- self.outl[0]["m"] * self.outl[0]["e_PH"]
|
|
347
|
+
+ (self.inl[1]["m"] * self.inl[1]["e_PH"])
|
|
348
|
+
)
|
|
349
|
+
|
|
323
350
|
# Case 6: hot stream always above T0, cold stream always below T0 (dissipative case)
|
|
324
|
-
elif (
|
|
325
|
-
self.outl[0]["T"] > T0 and self.outl[1]["T"] <= T0
|
|
351
|
+
elif (
|
|
352
|
+
self.inl[0]["T"] > T0 and self.inl[1]["T"] <= T0 and self.outl[0]["T"] > T0 and self.outl[1]["T"] <= T0
|
|
353
|
+
):
|
|
326
354
|
self.E_P = np.nan
|
|
327
|
-
self.E_F =
|
|
328
|
-
self.inl[
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
355
|
+
self.E_F = (
|
|
356
|
+
self.inl[0]["m"] * self.inl[0]["e_PH"]
|
|
357
|
+
- self.outl[0]["m"] * self.outl[0]["e_PH"]
|
|
358
|
+
+ (self.inl[1]["m"] * self.inl[1]["e_PH"] - self.outl[1]["m"] * self.outl[1]["e_PH"])
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
logging.warning(
|
|
362
|
+
f"Component {self.name} is dissipative. This component should be "
|
|
363
|
+
"handled with the `dissipative` flag set to True."
|
|
364
|
+
)
|
|
365
|
+
|
|
333
366
|
# Case 7: Not implemented case
|
|
334
|
-
else:
|
|
335
|
-
logging.error(
|
|
336
|
-
|
|
367
|
+
else:
|
|
368
|
+
logging.error(
|
|
369
|
+
f"The heat exchanger {self.name} has an unexpected temperature configuration. "
|
|
370
|
+
"Please check the inlet and outlet temperatures."
|
|
371
|
+
)
|
|
337
372
|
|
|
338
373
|
else:
|
|
339
374
|
self.E_F = (
|
|
340
|
-
self.inl[0][
|
|
341
|
-
- self.outl[0][
|
|
342
|
-
- self.outl[1][
|
|
343
|
-
+ self.inl[1][
|
|
375
|
+
self.inl[0]["m"] * self.inl[0]["e_PH"]
|
|
376
|
+
- self.outl[0]["m"] * self.outl[0]["e_PH"]
|
|
377
|
+
- self.outl[1]["m"] * self.outl[1]["e_PH"]
|
|
378
|
+
+ self.inl[1]["m"] * self.inl[1]["e_PH"]
|
|
344
379
|
)
|
|
345
380
|
self.E_P = np.nan
|
|
346
381
|
# Calculate exergy destruction and efficiency
|
|
@@ -352,12 +387,11 @@ class HeatExchanger(Component):
|
|
|
352
387
|
|
|
353
388
|
# Log the results
|
|
354
389
|
logging.info(
|
|
355
|
-
f"HeatExchanger
|
|
390
|
+
f"Exergy balance of HeatExchanger {self.name} calculated: "
|
|
356
391
|
f"E_P={self.E_P:.2f}, E_F={self.E_F:.2f}, E_D={self.E_D:.2f}, "
|
|
357
392
|
f"Efficiency={self.epsilon:.2%}"
|
|
358
393
|
)
|
|
359
394
|
|
|
360
|
-
|
|
361
395
|
def aux_eqs(self, A, b, counter, T0, equations, chemical_exergy_enabled):
|
|
362
396
|
r"""
|
|
363
397
|
Add auxiliary cost equations for the heat exchanger.
|
|
@@ -409,7 +443,7 @@ class HeatExchanger(Component):
|
|
|
409
443
|
+ \frac{1}{\dot{E}^{\mathrm{T}}_{\mathrm{in},1}}\,\dot{C}^{\mathrm{T}}_{\mathrm{in},1}
|
|
410
444
|
= 0
|
|
411
445
|
|
|
412
|
-
Case 6: Hot stream always above and cold stream always below ambiente temperature (dissipative case):
|
|
446
|
+
Case 6: Hot stream always above and cold stream always below ambiente temperature (dissipative case):
|
|
413
447
|
|
|
414
448
|
The dissipative is not handeld here!
|
|
415
449
|
|
|
@@ -460,6 +494,7 @@ class HeatExchanger(Component):
|
|
|
460
494
|
ValueError
|
|
461
495
|
If required cost variable indices are missing.
|
|
462
496
|
"""
|
|
497
|
+
|
|
463
498
|
# Equality equation for mechanical and chemical exergy costs.
|
|
464
499
|
def set_equal(A, row, in_item, out_item, var):
|
|
465
500
|
if in_item["e_" + var] != 0 and out_item["e_" + var] != 0:
|
|
@@ -516,49 +551,85 @@ class HeatExchanger(Component):
|
|
|
516
551
|
# Case 1: All temperatures > T0.
|
|
517
552
|
if all([c["T"] > T0 for c in list(self.inl.values()) + list(self.outl.values())]):
|
|
518
553
|
set_thermal_f_hot(A, counter + 0)
|
|
519
|
-
equations[counter] =
|
|
554
|
+
equations[counter] = {
|
|
555
|
+
"kind": "aux_f_rule_hot",
|
|
556
|
+
"objects": [self.name, self.inl[0]["name"], self.outl[0]["name"]],
|
|
557
|
+
"property": "c_T",
|
|
558
|
+
}
|
|
520
559
|
# Case 2: All temperatures <= T0.
|
|
521
560
|
elif all([c["T"] <= T0 for c in list(self.inl.values()) + list(self.outl.values())]):
|
|
522
561
|
set_thermal_f_cold(A, counter + 0)
|
|
523
|
-
equations[counter] =
|
|
562
|
+
equations[counter] = {
|
|
563
|
+
"kind": "aux_f_rule_cold",
|
|
564
|
+
"objects": [self.name, self.inl[1]["name"], self.outl[1]["name"]],
|
|
565
|
+
"property": "c_T",
|
|
566
|
+
}
|
|
524
567
|
# Case 3: Both stream crossing T0 (hot inlet and cold outlet > T0, hot outlet and cold inlet <= T0)
|
|
525
|
-
elif
|
|
526
|
-
self.outl[0]["T"] <= T0 and self.inl[1]["T"] <= T0):
|
|
568
|
+
elif self.inl[0]["T"] > T0 and self.outl[1]["T"] > T0 and self.outl[0]["T"] <= T0 and self.inl[1]["T"] <= T0:
|
|
527
569
|
set_thermal_p_rule(A, counter + 0)
|
|
528
|
-
equations[counter] =
|
|
570
|
+
equations[counter] = {
|
|
571
|
+
"kind": "aux_p_rule",
|
|
572
|
+
"objects": [self.name, self.outl[0]["name"], self.outl[1]["name"]],
|
|
573
|
+
"property": "c_T",
|
|
574
|
+
}
|
|
529
575
|
# Case 4: Only hot inlet > T0
|
|
530
|
-
elif
|
|
531
|
-
self.outl[0]["T"] <= T0 and self.outl[1]["T"] <= T0):
|
|
576
|
+
elif self.inl[0]["T"] > T0 and self.inl[1]["T"] <= T0 and self.outl[0]["T"] <= T0 and self.outl[1]["T"] <= T0:
|
|
532
577
|
set_thermal_f_cold(A, counter + 0)
|
|
533
|
-
equations[counter] =
|
|
578
|
+
equations[counter] = {
|
|
579
|
+
"kind": "aux_f_rule_cold",
|
|
580
|
+
"objects": [self.name, self.inl[1]["name"], self.outl[1]["name"]],
|
|
581
|
+
"property": "c_T",
|
|
582
|
+
}
|
|
534
583
|
# Case 5: Only cold inlet <= T0
|
|
535
|
-
elif
|
|
536
|
-
self.outl[0]["T"] > T0 and self.outl[1]["T"] > T0):
|
|
584
|
+
elif self.inl[0]["T"] > T0 and self.inl[1]["T"] <= T0 and self.outl[0]["T"] > T0 and self.outl[1]["T"] > T0:
|
|
537
585
|
set_thermal_f_hot(A, counter + 0)
|
|
538
|
-
equations[counter] =
|
|
586
|
+
equations[counter] = {
|
|
587
|
+
"kind": "aux_f_rule_hot",
|
|
588
|
+
"objects": [self.name, self.inl[0]["name"], self.outl[0]["name"]],
|
|
589
|
+
"property": "c_T",
|
|
590
|
+
}
|
|
539
591
|
# Case 6: hot stream always above T0, cold stream always below T0 (dissipative case)
|
|
540
|
-
elif
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
592
|
+
elif self.inl[0]["T"] > T0 and self.inl[1]["T"] <= T0 and self.outl[0]["T"] > T0 and self.outl[1]["T"] <= T0:
|
|
593
|
+
logging.warning(
|
|
594
|
+
f"Component {self.name} is dissipative. This component should be "
|
|
595
|
+
"handled with the `dissipative` flag set to True."
|
|
596
|
+
)
|
|
544
597
|
return
|
|
545
598
|
# Case 7: Not implemented case
|
|
546
|
-
else:
|
|
547
|
-
logging.error(
|
|
548
|
-
|
|
549
|
-
|
|
599
|
+
else:
|
|
600
|
+
logging.error(
|
|
601
|
+
f"The heat exchanger {self.name} has an unexpected temperature configuration. "
|
|
602
|
+
"Please check the inlet and outlet temperatures."
|
|
603
|
+
)
|
|
604
|
+
|
|
550
605
|
# Mechanical equations (always added)
|
|
551
606
|
set_equal(A, counter + 1, self.inl[0], self.outl[0], "M")
|
|
552
607
|
set_equal(A, counter + 2, self.inl[1], self.outl[1], "M")
|
|
553
|
-
equations[counter + 1] =
|
|
554
|
-
|
|
555
|
-
|
|
608
|
+
equations[counter + 1] = {
|
|
609
|
+
"kind": "aux_equality",
|
|
610
|
+
"objects": [self.name, self.inl[0]["name"], self.outl[0]["name"]],
|
|
611
|
+
"property": "c_M",
|
|
612
|
+
}
|
|
613
|
+
equations[counter + 2] = {
|
|
614
|
+
"kind": "aux_equality",
|
|
615
|
+
"objects": [self.name, self.inl[1]["name"], self.outl[1]["name"]],
|
|
616
|
+
"property": "c_M",
|
|
617
|
+
}
|
|
618
|
+
|
|
556
619
|
# Only add chemical auxiliary equations if chemical exergy is enabled.
|
|
557
620
|
if chemical_exergy_enabled:
|
|
558
621
|
set_equal(A, counter + 3, self.inl[0], self.outl[0], "CH")
|
|
559
622
|
set_equal(A, counter + 4, self.inl[1], self.outl[1], "CH")
|
|
560
|
-
equations[counter + 3] =
|
|
561
|
-
|
|
623
|
+
equations[counter + 3] = {
|
|
624
|
+
"kind": "aux_equality",
|
|
625
|
+
"objects": [self.name, self.inl[0]["name"], self.outl[0]["name"]],
|
|
626
|
+
"property": "c_CH",
|
|
627
|
+
}
|
|
628
|
+
equations[counter + 4] = {
|
|
629
|
+
"kind": "aux_equality",
|
|
630
|
+
"objects": [self.name, self.inl[1]["name"], self.outl[1]["name"]],
|
|
631
|
+
"property": "c_M",
|
|
632
|
+
}
|
|
562
633
|
num_aux_eqs = 5
|
|
563
634
|
else:
|
|
564
635
|
# Skip chemical auxiliary equations.
|
|
@@ -569,7 +640,7 @@ class HeatExchanger(Component):
|
|
|
569
640
|
|
|
570
641
|
return A, b, counter + num_aux_eqs, equations
|
|
571
642
|
|
|
572
|
-
def exergoeconomic_balance(self, T0):
|
|
643
|
+
def exergoeconomic_balance(self, T0, chemical_exergy_enabled=False):
|
|
573
644
|
r"""
|
|
574
645
|
Perform exergoeconomic cost balance for the heat exchanger.
|
|
575
646
|
|
|
@@ -665,55 +736,51 @@ class HeatExchanger(Component):
|
|
|
665
736
|
- \dot{C}^{\mathrm{PH}}_{\mathrm{out},1}\bigr)
|
|
666
737
|
- \dot{C}^{\mathrm{PH}}_{\mathrm{out},2}
|
|
667
738
|
+ \dot{C}^{\mathrm{PH}}_{\mathrm{in},2}
|
|
668
|
-
|
|
739
|
+
|
|
669
740
|
Parameters
|
|
670
741
|
----------
|
|
671
742
|
T0 : float
|
|
672
743
|
Ambient temperature (K).
|
|
744
|
+
chemical_exergy_enabled : bool, optional
|
|
745
|
+
If True, chemical exergy is considered in the calculations.
|
|
673
746
|
"""
|
|
674
747
|
# Case 1: All streams are above the ambient temperature
|
|
675
748
|
if all([c["T"] > T0 for c in list(self.inl.values()) + list(self.outl.values())]):
|
|
676
749
|
self.C_P = self.outl[1]["C_T"] - self.inl[1]["C_T"]
|
|
677
|
-
self.C_F = self.inl[0]["C_PH"] - self.outl[0]["C_PH"] + (
|
|
678
|
-
self.inl[1]["C_M"] - self.outl[1]["C_M"])
|
|
750
|
+
self.C_F = self.inl[0]["C_PH"] - self.outl[0]["C_PH"] + (self.inl[1]["C_M"] - self.outl[1]["C_M"])
|
|
679
751
|
# Case 2: All streams are below or equal to the ambient temperature
|
|
680
752
|
elif all([c["T"] <= T0 for c in list(self.inl.values()) + list(self.outl.values())]):
|
|
681
753
|
self.C_P = self.outl[0]["C_T"] - self.inl[0]["C_T"]
|
|
682
|
-
self.C_F = self.inl[1]["C_PH"] - self.outl[1]["C_PH"] + (
|
|
683
|
-
self.inl[0]["C_M"] - self.outl[0]["C_M"])
|
|
754
|
+
self.C_F = self.inl[1]["C_PH"] - self.outl[1]["C_PH"] + (self.inl[0]["C_M"] - self.outl[0]["C_M"])
|
|
684
755
|
# Case 3: Both stream crossing T0 (hot inlet and cold outlet > T0, hot outlet and cold inlet <= T0)
|
|
685
|
-
elif
|
|
686
|
-
self.outl[0]["T"] <= T0 and self.inl[1]["T"] <= T0):
|
|
756
|
+
elif self.inl[0]["T"] > T0 and self.outl[1]["T"] > T0 and self.outl[0]["T"] <= T0 and self.inl[1]["T"] <= T0:
|
|
687
757
|
self.C_P = self.outl[0]["C_T"] + self.outl[1]["C_T"]
|
|
688
|
-
self.C_F = self.inl[0]["C_PH"] + self.inl[1]["C_PH"] - (
|
|
689
|
-
self.outl[0]["C_M"] + self.outl[1]["C_M"])
|
|
758
|
+
self.C_F = self.inl[0]["C_PH"] + self.inl[1]["C_PH"] - (self.outl[0]["C_M"] + self.outl[1]["C_M"])
|
|
690
759
|
# Case 4: Only hot inlet > T0
|
|
691
|
-
elif
|
|
692
|
-
self.outl[0]["T"] <= T0 and self.outl[1]["T"] <= T0):
|
|
760
|
+
elif self.inl[0]["T"] > T0 and self.inl[1]["T"] <= T0 and self.outl[0]["T"] <= T0 and self.outl[1]["T"] <= T0:
|
|
693
761
|
self.C_P = self.outl[0]["C_T"]
|
|
694
|
-
self.C_F = self.inl[0]["C_PH"] + self.inl[1]["C_PH"] - (
|
|
695
|
-
self.outl[1]["C_PH"] + self.outl[0]["C_M"])
|
|
762
|
+
self.C_F = self.inl[0]["C_PH"] + self.inl[1]["C_PH"] - (self.outl[1]["C_PH"] + self.outl[0]["C_M"])
|
|
696
763
|
# Case 5: Only cold inlet <= T0
|
|
697
|
-
elif
|
|
698
|
-
self.outl[0]["T"] > T0 and self.outl[1]["T"] > T0):
|
|
764
|
+
elif self.inl[0]["T"] > T0 and self.inl[1]["T"] <= T0 and self.outl[0]["T"] > T0 and self.outl[1]["T"] > T0:
|
|
699
765
|
self.C_P = self.outl[1]["C_T"]
|
|
700
|
-
self.C_F = self.inl[0]["C_PH"] - self.outl[0]["C_PH"] + (
|
|
701
|
-
self.inl[1]["C_PH"] - self.outl[1]["C_M"])
|
|
766
|
+
self.C_F = self.inl[0]["C_PH"] - self.outl[0]["C_PH"] + (self.inl[1]["C_PH"] - self.outl[1]["C_M"])
|
|
702
767
|
# Case 6: hot stream always above T0, cold stream always below T0 (dissipative case)
|
|
703
|
-
elif
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
768
|
+
elif self.inl[0]["T"] > T0 and self.inl[1]["T"] <= T0 and self.outl[0]["T"] > T0 and self.outl[1]["T"] <= T0:
|
|
769
|
+
logging.warning(
|
|
770
|
+
f"Component {self.name} is dissipative. This component should be "
|
|
771
|
+
"handled with the `dissipative` flag set to True."
|
|
772
|
+
)
|
|
707
773
|
self.C_P = np.nan
|
|
708
|
-
self.C_F = self.inl[0]["C_PH"] - self.outl[0]["C_PH"] + (
|
|
709
|
-
self.inl[1]["C_PH"] - self.outl[1]["C_PH"])
|
|
774
|
+
self.C_F = self.inl[0]["C_PH"] - self.outl[0]["C_PH"] + (self.inl[1]["C_PH"] - self.outl[1]["C_PH"])
|
|
710
775
|
# Case 7: Not implemented case
|
|
711
|
-
else:
|
|
712
|
-
logging.error(
|
|
713
|
-
|
|
776
|
+
else:
|
|
777
|
+
logging.error(
|
|
778
|
+
f"The heat exchanger {self.name} has an unexpected temperature configuration. "
|
|
779
|
+
"Please check the inlet and outlet temperatures."
|
|
780
|
+
)
|
|
714
781
|
|
|
715
782
|
self.c_F = self.C_F / self.E_F
|
|
716
783
|
self.c_P = self.C_P / self.E_P
|
|
717
784
|
self.C_D = self.c_F * self.E_D
|
|
718
785
|
self.r = (self.c_P - self.c_F) / self.c_F
|
|
719
|
-
self.f = self.Z_costs / (self.Z_costs + self.C_D)
|
|
786
|
+
self.f = self.Z_costs / (self.Z_costs + self.C_D)
|