exerpy 0.0.2__py3-none-any.whl → 0.0.4__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 +849 -304
- 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 +188 -121
- exerpy/components/heat_exchanger/condenser.py +98 -62
- 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 +214 -68
- exerpy/components/turbomachinery/pump.py +215 -68
- exerpy/components/turbomachinery/turbine.py +182 -74
- exerpy/cost_estimation/__init__.py +65 -0
- exerpy/cost_estimation/turton.py +1260 -0
- exerpy/data/cost_correlations/cepci_index.json +135 -0
- exerpy/data/cost_correlations/component_mapping.json +450 -0
- exerpy/data/cost_correlations/material_factors.json +428 -0
- exerpy/data/cost_correlations/pressure_factors.json +206 -0
- exerpy/data/cost_correlations/turton2008.json +726 -0
- exerpy/data/cost_correlations/turton2008_design_analysis_synthesis_components_tables.pdf +0 -0
- exerpy/data/cost_correlations/turton2008_design_analysis_synthesis_components_theory.pdf +0 -0
- exerpy/functions.py +389 -264
- 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 +33 -1
- exerpy/parser/from_tespy/tespy_parser.py +151 -0
- {exerpy-0.0.2.dist-info → exerpy-0.0.4.dist-info}/METADATA +43 -2
- exerpy-0.0.4.dist-info/RECORD +57 -0
- exerpy-0.0.2.dist-info/RECORD +0 -44
- {exerpy-0.0.2.dist-info → exerpy-0.0.4.dist-info}/WHEEL +0 -0
- {exerpy-0.0.2.dist-info → exerpy-0.0.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from exerpy.components.component import Component, component_registry
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
@component_registry
|
|
@@ -10,8 +11,8 @@ class Condenser(Component):
|
|
|
10
11
|
Class for exergy and exergoeconomic analysis of condensers (only dissipative).
|
|
11
12
|
|
|
12
13
|
This class performs exergy and exergoeconomic analysis calculations for condenser components,
|
|
13
|
-
accounting for two inlet and two outlet streams. This class should be used only for dissipative
|
|
14
|
-
condensers. For non-dissipative condensers, use components that are modeled in ExerPy using the
|
|
14
|
+
accounting for two inlet and two outlet streams. This class should be used only for dissipative
|
|
15
|
+
condensers. For non-dissipative condensers, use components that are modeled in ExerPy using the
|
|
15
16
|
`HeatExchanger` class.
|
|
16
17
|
|
|
17
18
|
Attributes
|
|
@@ -52,7 +53,7 @@ class Condenser(Component):
|
|
|
52
53
|
- Z_costs (float): investment cost rate in currency/h, default 0.0
|
|
53
54
|
"""
|
|
54
55
|
super().__init__(**kwargs)
|
|
55
|
-
|
|
56
|
+
|
|
56
57
|
def calc_exergy_balance(self, T0: float, p0: float, split_physical_exergy) -> None:
|
|
57
58
|
r"""
|
|
58
59
|
Compute the exergy balance of the condenser.
|
|
@@ -74,8 +75,8 @@ class Condenser(Component):
|
|
|
74
75
|
- \dot{E}^{\mathrm{PH}}_{\mathrm{out},1}
|
|
75
76
|
- \dot{E}_{\mathrm{L}}
|
|
76
77
|
|
|
77
|
-
However, these value can only be accessed via the attributes `E_L` and `E_D` of the component.
|
|
78
|
-
In the table of final results of the exergy analysis of the system, the exergy destruction of
|
|
78
|
+
However, these value can only be accessed via the attributes `E_L` and `E_D` of the component.
|
|
79
|
+
In the table of final results of the exergy analysis of the system, the exergy destruction of
|
|
79
80
|
the condenser is counted as the exergy loss and the exergetic destruction due to heat transfer.
|
|
80
81
|
|
|
81
82
|
Parameters
|
|
@@ -95,21 +96,24 @@ class Condenser(Component):
|
|
|
95
96
|
# Ensure that the component has both inlet and outlet streams
|
|
96
97
|
if len(self.inl) < 2 or len(self.outl) < 2:
|
|
97
98
|
raise ValueError("Condenser requires two inlets and two outlets.")
|
|
98
|
-
|
|
99
|
+
|
|
99
100
|
# Calculate exergy loss (E_L) for the heat transfer process
|
|
100
|
-
self.E_L = self.outl[1][
|
|
101
|
+
self.E_L = self.outl[1]["m"] * (self.outl[1]["e_PH"] - self.inl[1]["e_PH"])
|
|
101
102
|
|
|
102
103
|
# Calculate exergy destruction (E_D)
|
|
103
|
-
self.E_D = self.outl[0][
|
|
104
|
+
self.E_D = self.outl[0]["m"] * (self.inl[0]["e_PH"] - self.outl[0]["e_PH"]) - self.E_L
|
|
104
105
|
|
|
105
106
|
# Exergy fuel and product are not typically defined for a condenser
|
|
106
|
-
self.E_F =
|
|
107
|
-
self.E_P =
|
|
108
|
-
self.epsilon =
|
|
109
|
-
|
|
110
|
-
# Log the exergy balance results
|
|
111
|
-
logging.info(f"Condenser exergy balance calculated: E_D={self.E_D}, E_L={self.E_L}")
|
|
107
|
+
self.E_F = np.nan
|
|
108
|
+
self.E_P = np.nan
|
|
109
|
+
self.epsilon = np.nan
|
|
112
110
|
|
|
111
|
+
# Log the results
|
|
112
|
+
logging.info(
|
|
113
|
+
f"Exergy balance of Condenser {self.name} calculated: "
|
|
114
|
+
f"E_P={self.E_P:.2f}, E_F={self.E_F:.2f}, E_D={self.E_D:.2f}, "
|
|
115
|
+
f"Efficiency={self.epsilon:.2%}"
|
|
116
|
+
)
|
|
113
117
|
|
|
114
118
|
def aux_eqs(self, A, b, counter, T0, equations, chemical_exergy_enabled):
|
|
115
119
|
r"""
|
|
@@ -162,7 +166,7 @@ class Condenser(Component):
|
|
|
162
166
|
+ \frac{1}{\dot{E}^{\mathrm{T}}_{\mathrm{in},1}}\,\dot{C}^{\mathrm{T}}_{\mathrm{in},1}
|
|
163
167
|
= 0
|
|
164
168
|
|
|
165
|
-
Case 6: Hot stream always above and cold stream always below ambiente temperature (dissipative case):
|
|
169
|
+
Case 6: Hot stream always above and cold stream always below ambiente temperature (dissipative case):
|
|
166
170
|
|
|
167
171
|
The dissipative is not handeld here!
|
|
168
172
|
|
|
@@ -213,11 +217,12 @@ class Condenser(Component):
|
|
|
213
217
|
ValueError
|
|
214
218
|
If required cost variable indices are missing.
|
|
215
219
|
"""
|
|
220
|
+
|
|
216
221
|
# Equality equation for mechanical and chemical exergy costs.
|
|
217
222
|
def set_equal(A, row, in_item, out_item, var):
|
|
218
223
|
if in_item["e_" + var] != 0 and out_item["e_" + var] != 0:
|
|
219
|
-
A[row, in_item["CostVar_index"][var]] = 1 / in_item["
|
|
220
|
-
A[row, out_item["CostVar_index"][var]] = -1 / out_item["
|
|
224
|
+
A[row, in_item["CostVar_index"][var]] = 1 / in_item["E_" + var]
|
|
225
|
+
A[row, out_item["CostVar_index"][var]] = -1 / out_item["E_" + var]
|
|
221
226
|
elif in_item["e_" + var] == 0 and out_item["e_" + var] != 0:
|
|
222
227
|
A[row, in_item["CostVar_index"][var]] = 1
|
|
223
228
|
elif in_item["e_" + var] != 0 and out_item["e_" + var] == 0:
|
|
@@ -269,65 +274,101 @@ class Condenser(Component):
|
|
|
269
274
|
# Case 1: All temperatures > T0.
|
|
270
275
|
if all([c["T"] > T0 for c in list(self.inl.values()) + list(self.outl.values())]):
|
|
271
276
|
set_thermal_f_hot(A, counter + 0)
|
|
272
|
-
equations[counter] =
|
|
277
|
+
self.equations[counter] = {
|
|
278
|
+
"kind": "aux_f_rule_hot",
|
|
279
|
+
"objects": [self.name, self.inl[0]["name"], self.outl[0]["name"]],
|
|
280
|
+
"property": "c_T",
|
|
281
|
+
}
|
|
273
282
|
# Case 2: All temperatures <= T0.
|
|
274
283
|
elif all([c["T"] <= T0 for c in list(self.inl.values()) + list(self.outl.values())]):
|
|
275
284
|
set_thermal_f_cold(A, counter + 0)
|
|
276
|
-
equations[counter] =
|
|
285
|
+
self.equations[counter] = {
|
|
286
|
+
"kind": "aux_f_rule_cold",
|
|
287
|
+
"objects": [self.name, self.inl[1]["name"], self.outl[1]["name"]],
|
|
288
|
+
"property": "c_T",
|
|
289
|
+
}
|
|
277
290
|
logging.warning(
|
|
278
|
-
f"All temperatures in {self.name} are below ambient temperature. "
|
|
291
|
+
f"All temperatures in {self.name} are below ambient temperature. "
|
|
279
292
|
"This is not a typical case for a dissipative condenser."
|
|
280
293
|
)
|
|
281
294
|
# Case 3: Both stream crossing T0 (hot inlet and cold outlet > T0, hot outlet and cold inlet <= T0)
|
|
282
|
-
elif
|
|
283
|
-
self.outl[0]["T"] <= T0 and self.inl[1]["T"] <= T0):
|
|
295
|
+
elif self.inl[0]["T"] > T0 and self.outl[1]["T"] > T0 and self.outl[0]["T"] <= T0 and self.inl[1]["T"] <= T0:
|
|
284
296
|
set_thermal_p_rule(A, counter + 0)
|
|
285
|
-
equations[counter] =
|
|
297
|
+
equations[counter] = {
|
|
298
|
+
"kind": "aux_p_rule",
|
|
299
|
+
"objects": [self.name, self.outl[0]["name"], self.outl[1]["name"]],
|
|
300
|
+
"property": "c_T",
|
|
301
|
+
}
|
|
286
302
|
logging.warning(
|
|
287
|
-
f"Hot inlet and cold outlet in {self.name} are above ambient temperature, "
|
|
288
|
-
"while hot outlet and cold inlet are below. This is not a typical case for a dissipative condenser."
|
|
303
|
+
f"Hot inlet and cold outlet in {self.name} are above ambient temperature, "
|
|
304
|
+
"while hot outlet and cold inlet are below. This is not a typical case for a dissipative condenser."
|
|
289
305
|
"The exergoeconomic analysis is counting the outlets as products."
|
|
290
306
|
)
|
|
291
307
|
# Case 4: Only hot inlet > T0
|
|
292
|
-
elif
|
|
293
|
-
self.outl[0]["T"] <= T0 and self.outl[1]["T"] <= T0):
|
|
308
|
+
elif self.inl[0]["T"] > T0 and self.inl[1]["T"] <= T0 and self.outl[0]["T"] <= T0 and self.outl[1]["T"] <= T0:
|
|
294
309
|
set_thermal_f_cold(A, counter + 0)
|
|
295
|
-
equations[counter] =
|
|
310
|
+
equations[counter] = {
|
|
311
|
+
"kind": "aux_f_rule_cold",
|
|
312
|
+
"objects": [self.name, self.inl[1]["name"], self.outl[1]["name"]],
|
|
313
|
+
"property": "c_T",
|
|
314
|
+
}
|
|
296
315
|
logging.warning(
|
|
297
|
-
f"Cold inlet in {self.name} is below ambient temperature. "
|
|
316
|
+
f"Cold inlet in {self.name} is below ambient temperature. "
|
|
298
317
|
"This is not a typical case for a dissipative condenser."
|
|
299
318
|
)
|
|
300
319
|
# Case 5: Only cold inlet <= T0
|
|
301
|
-
elif
|
|
302
|
-
self.outl[0]["T"] > T0 and self.outl[1]["T"] > T0):
|
|
320
|
+
elif self.inl[0]["T"] > T0 and self.inl[1]["T"] <= T0 and self.outl[0]["T"] > T0 and self.outl[1]["T"] > T0:
|
|
303
321
|
set_thermal_f_hot(A, counter + 0)
|
|
304
|
-
equations[counter] =
|
|
322
|
+
equations[counter] = {
|
|
323
|
+
"kind": "aux_f_rule_hot",
|
|
324
|
+
"objects": [self.name, self.inl[0]["name"], self.outl[0]["name"]],
|
|
325
|
+
"property": "c_T",
|
|
326
|
+
}
|
|
305
327
|
logging.warning(
|
|
306
|
-
f"Cold inlet in {self.name} is below ambient temperature. "
|
|
328
|
+
f"Cold inlet in {self.name} is below ambient temperature. "
|
|
307
329
|
"This is not a typical case for a dissipative condenser."
|
|
308
330
|
)
|
|
309
331
|
# Case 6: hot stream always above T0, cold stream always below T0
|
|
310
|
-
elif
|
|
311
|
-
self.outl[0]["T"] > T0 and self.outl[1]["T"] <= T0):
|
|
332
|
+
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
333
|
print("you shouldn't see this")
|
|
313
334
|
return
|
|
314
335
|
# Case 7: Default case.
|
|
315
336
|
else:
|
|
316
337
|
set_thermal_f_hot(A, counter + 0)
|
|
317
|
-
equations[counter] =
|
|
318
|
-
|
|
338
|
+
equations[counter] = {
|
|
339
|
+
"kind": "aux_f_rule_hot",
|
|
340
|
+
"objects": [self.name, self.inl[0]["name"], self.outl[0]["name"]],
|
|
341
|
+
"property": "c_T",
|
|
342
|
+
}
|
|
343
|
+
|
|
319
344
|
# Mechanical equations (always added)
|
|
320
345
|
set_equal(A, counter + 1, self.inl[0], self.outl[0], "M")
|
|
321
346
|
set_equal(A, counter + 2, self.inl[1], self.outl[1], "M")
|
|
322
|
-
equations[counter + 1] =
|
|
323
|
-
|
|
324
|
-
|
|
347
|
+
equations[counter + 1] = {
|
|
348
|
+
"kind": "aux_equality",
|
|
349
|
+
"objects": [self.name, self.inl[0]["name"], self.outl[0]["name"]],
|
|
350
|
+
"property": "c_M",
|
|
351
|
+
}
|
|
352
|
+
equations[counter + 2] = {
|
|
353
|
+
"kind": "aux_equality",
|
|
354
|
+
"objects": [self.name, self.inl[1]["name"], self.outl[1]["name"]],
|
|
355
|
+
"property": "c_M",
|
|
356
|
+
}
|
|
357
|
+
|
|
325
358
|
# Only add chemical auxiliary equations if chemical exergy is enabled.
|
|
326
359
|
if chemical_exergy_enabled:
|
|
327
360
|
set_equal(A, counter + 3, self.inl[0], self.outl[0], "CH")
|
|
328
361
|
set_equal(A, counter + 4, self.inl[1], self.outl[1], "CH")
|
|
329
|
-
equations[counter + 3] =
|
|
330
|
-
|
|
362
|
+
equations[counter + 3] = {
|
|
363
|
+
"kind": "aux_equality",
|
|
364
|
+
"objects": [self.name, self.inl[0]["name"], self.outl[0]["name"]],
|
|
365
|
+
"property": "c_CH",
|
|
366
|
+
}
|
|
367
|
+
equations[counter + 4] = {
|
|
368
|
+
"kind": "aux_equality",
|
|
369
|
+
"objects": [self.name, self.inl[1]["name"], self.outl[1]["name"]],
|
|
370
|
+
"property": "c_M",
|
|
371
|
+
}
|
|
331
372
|
num_aux_eqs = 5
|
|
332
373
|
else:
|
|
333
374
|
# Skip chemical auxiliary equations.
|
|
@@ -337,13 +378,13 @@ class Condenser(Component):
|
|
|
337
378
|
b[counter + i] = 0
|
|
338
379
|
|
|
339
380
|
return A, b, counter + num_aux_eqs, equations
|
|
340
|
-
|
|
341
|
-
def exergoeconomic_balance(self, T0):
|
|
381
|
+
|
|
382
|
+
def exergoeconomic_balance(self, T0, chemical_exergy_enabled=False):
|
|
342
383
|
r"""
|
|
343
384
|
Perform exergoeconomic cost balance for the condenser.
|
|
344
385
|
|
|
345
386
|
Even though this class should only consider dissipative condensers, the exergoeconomic balance is
|
|
346
|
-
still performed to ensure consistency. Please note that same of the following cases cases are not
|
|
387
|
+
still performed to ensure consistency. Please note that same of the following cases cases are not
|
|
347
388
|
typical for dissipative condensers. This may change in a future version of ExerPy.
|
|
348
389
|
|
|
349
390
|
.. math::
|
|
@@ -438,34 +479,29 @@ class Condenser(Component):
|
|
|
438
479
|
- \dot{C}^{\mathrm{PH}}_{\mathrm{out},1}\bigr)
|
|
439
480
|
- \dot{C}^{\mathrm{PH}}_{\mathrm{out},2}
|
|
440
481
|
+ \dot{C}^{\mathrm{PH}}_{\mathrm{in},2}
|
|
441
|
-
|
|
482
|
+
|
|
442
483
|
Parameters
|
|
443
484
|
----------
|
|
444
485
|
T0 : float
|
|
445
486
|
Ambient temperature (K).
|
|
487
|
+
chemical_exergy_enabled : bool, optional
|
|
488
|
+
If True, chemical exergy is considered in the calculations.
|
|
446
489
|
"""
|
|
447
490
|
if all([c["T"] > T0 for c in list(self.inl.values()) + list(self.outl.values())]):
|
|
448
491
|
self.C_P = self.outl[1]["C_T"] - self.inl[1]["C_T"]
|
|
449
|
-
self.C_F = self.inl[0]["C_PH"] - self.outl[0]["C_PH"] + (
|
|
450
|
-
self.inl[1]["C_M"] - self.outl[1]["C_M"])
|
|
492
|
+
self.C_F = self.inl[0]["C_PH"] - self.outl[0]["C_PH"] + (self.inl[1]["C_M"] - self.outl[1]["C_M"])
|
|
451
493
|
elif all([c["T"] <= T0 for c in list(self.inl.values()) + list(self.outl.values())]):
|
|
452
494
|
self.C_P = self.outl[0]["C_T"] - self.inl[0]["C_T"]
|
|
453
|
-
self.C_F = self.inl[1]["C_PH"] - self.outl[1]["C_PH"] + (
|
|
454
|
-
|
|
455
|
-
elif (self.inl[0]["T"] > T0 and self.outl[1]["T"] > T0 and
|
|
456
|
-
self.outl[0]["T"] <= T0 and self.inl[1]["T"] <= T0):
|
|
495
|
+
self.C_F = self.inl[1]["C_PH"] - self.outl[1]["C_PH"] + (self.inl[0]["C_M"] - self.outl[0]["C_M"])
|
|
496
|
+
elif self.inl[0]["T"] > T0 and self.outl[1]["T"] > T0 and self.outl[0]["T"] <= T0 and self.inl[1]["T"] <= T0:
|
|
457
497
|
self.C_P = self.outl[0]["C_T"] + self.outl[1]["C_T"]
|
|
458
|
-
self.C_F = self.inl[0]["C_PH"] + self.inl[1]["C_PH"] - (
|
|
459
|
-
|
|
460
|
-
elif (self.inl[0]["T"] > T0 and self.inl[1]["T"] <= T0 and
|
|
461
|
-
self.outl[0]["T"] <= T0 and self.outl[1]["T"] <= T0):
|
|
498
|
+
self.C_F = self.inl[0]["C_PH"] + self.inl[1]["C_PH"] - (self.outl[0]["C_M"] + self.outl[1]["C_M"])
|
|
499
|
+
elif self.inl[0]["T"] > T0 and self.inl[1]["T"] <= T0 and self.outl[0]["T"] <= T0 and self.outl[1]["T"] <= T0:
|
|
462
500
|
self.C_P = self.outl[0]["C_T"]
|
|
463
|
-
self.C_F = self.inl[0]["C_PH"] + self.inl[1]["C_PH"] - (
|
|
464
|
-
self.outl[1]["C_PH"] + self.outl[0]["C_M"])
|
|
501
|
+
self.C_F = self.inl[0]["C_PH"] + self.inl[1]["C_PH"] - (self.outl[1]["C_PH"] + self.outl[0]["C_M"])
|
|
465
502
|
else:
|
|
466
503
|
self.C_P = self.outl[1]["C_T"]
|
|
467
|
-
self.C_F = self.inl[0]["C_PH"] - self.outl[0]["C_PH"] + (
|
|
468
|
-
self.inl[1]["C_PH"] - self.outl[1]["C_M"])
|
|
504
|
+
self.C_F = self.inl[0]["C_PH"] - self.outl[0]["C_PH"] + (self.inl[1]["C_PH"] - self.outl[1]["C_M"])
|
|
469
505
|
|
|
470
506
|
self.c_F = self.C_F / self.E_F
|
|
471
507
|
self.c_P = self.C_P / self.E_P
|