exerpy 0.0.1__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 +157 -114
- exerpy/components/component.py +8 -8
- exerpy/components/heat_exchanger/base.py +593 -256
- exerpy/components/heat_exchanger/condenser.py +353 -166
- exerpy/components/heat_exchanger/simple.py +575 -225
- exerpy/components/heat_exchanger/steam_generator.py +153 -123
- exerpy/components/helpers/cycle_closer.py +61 -34
- exerpy/components/helpers/power_bus.py +117 -0
- exerpy/components/nodes/deaerator.py +221 -102
- exerpy/components/nodes/drum.py +50 -39
- exerpy/components/nodes/flash_tank.py +218 -43
- exerpy/components/nodes/mixer.py +296 -115
- exerpy/components/nodes/splitter.py +173 -0
- exerpy/components/nodes/storage.py +130 -0
- exerpy/components/piping/valve.py +351 -139
- 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 +329 -227
- 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.1.dist-info → exerpy-0.0.3.dist-info}/METADATA +45 -4
- exerpy-0.0.3.dist-info/RECORD +48 -0
- exerpy-0.0.1.dist-info/RECORD +0 -44
- {exerpy-0.0.1.dist-info → exerpy-0.0.3.dist-info}/WHEEL +0 -0
- {exerpy-0.0.1.dist-info → exerpy-0.0.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,169 +1,223 @@
|
|
|
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
|
|
8
9
|
class Condenser(Component):
|
|
9
|
-
"""
|
|
10
|
-
|
|
10
|
+
r"""
|
|
11
|
+
Class for exergy and exergoeconomic analysis of condensers (only dissipative).
|
|
11
12
|
|
|
12
|
-
This class
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
This class performs exergy and exergoeconomic analysis calculations for condenser components,
|
|
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
|
|
16
|
+
`HeatExchanger` class.
|
|
16
17
|
|
|
17
18
|
Attributes
|
|
18
19
|
----------
|
|
19
|
-
|
|
20
|
-
Exergy
|
|
21
|
-
between specific outlet and inlet streams).
|
|
20
|
+
E_F : float
|
|
21
|
+
Exergy fuel of the component :math:`\dot{E}_\mathrm{F}` in :math:`\mathrm{W}`.
|
|
22
22
|
E_D : float
|
|
23
|
-
Exergy destruction
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
23
|
+
Exergy destruction of the component :math:`\dot{E}_\mathrm{D}` in :math:`\mathrm{W}`.
|
|
24
|
+
E_L : float
|
|
25
|
+
Exergy loss of the component :math:`\dot{E}_\mathrm{L}` in :math:`\mathrm{W}`.
|
|
26
|
+
inl : dict
|
|
27
|
+
Dictionary containing inlet stream data with mass flows and specific exergies.
|
|
28
|
+
outl : dict
|
|
29
|
+
Dictionary containing outlet stream data with mass flows and specific exergies.
|
|
30
|
+
Z_costs : float
|
|
31
|
+
Investment cost rate of the component in currency/h.
|
|
32
|
+
C_F : float
|
|
33
|
+
Cost of fuel stream :math:`\dot{C}_F` in currency/h.
|
|
34
|
+
C_D : float
|
|
35
|
+
Cost of exergy destruction :math:`\dot{C}_D` in currency/h.
|
|
36
|
+
c_F : float
|
|
37
|
+
Specific cost of fuel stream (currency per unit exergy).
|
|
38
|
+
f : float
|
|
39
|
+
Exergoeconomic factor, :math:`\dot{Z}/(\dot{Z} + \dot{C}_D)`.
|
|
40
|
+
Ex_C_col : dict
|
|
41
|
+
Custom cost coefficients collection passed via `kwargs`.
|
|
42
42
|
"""
|
|
43
43
|
|
|
44
44
|
def __init__(self, **kwargs):
|
|
45
|
-
"""
|
|
46
|
-
Initialize the
|
|
45
|
+
r"""
|
|
46
|
+
Initialize the condenser component.
|
|
47
47
|
|
|
48
48
|
Parameters
|
|
49
49
|
----------
|
|
50
50
|
**kwargs : dict
|
|
51
|
-
Arbitrary keyword arguments
|
|
51
|
+
Arbitrary keyword arguments. Recognized keys:
|
|
52
|
+
- Ex_C_col (dict): custom cost coefficients, default {}
|
|
53
|
+
- Z_costs (float): investment cost rate in currency/h, default 0.0
|
|
52
54
|
"""
|
|
53
55
|
super().__init__(**kwargs)
|
|
54
|
-
|
|
56
|
+
|
|
55
57
|
def calc_exergy_balance(self, T0: float, p0: float, split_physical_exergy) -> None:
|
|
56
|
-
"""
|
|
57
|
-
|
|
58
|
+
r"""
|
|
59
|
+
Compute the exergy balance of the condenser.
|
|
60
|
+
|
|
61
|
+
In order to distinguish between the exergetic destruction because of heat transfer
|
|
62
|
+
and the exergetic loss (coldf stream leaving the system) the exergetic losses and
|
|
63
|
+
destruction are calculated as follows:
|
|
64
|
+
|
|
65
|
+
.. math::
|
|
66
|
+
|
|
67
|
+
\dot{E}_{\mathrm{L}}
|
|
68
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{out},2}
|
|
69
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{in},2}
|
|
58
70
|
|
|
59
|
-
|
|
60
|
-
|
|
71
|
+
.. math::
|
|
72
|
+
|
|
73
|
+
\dot{E}_{\mathrm{D}}
|
|
74
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{in},1}
|
|
75
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{out},1}
|
|
76
|
+
- \dot{E}_{\mathrm{L}}
|
|
77
|
+
|
|
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
|
|
80
|
+
the condenser is counted as the exergy loss and the exergetic destruction due to heat transfer.
|
|
61
81
|
|
|
62
82
|
Parameters
|
|
63
83
|
----------
|
|
64
84
|
T0 : float
|
|
65
|
-
|
|
85
|
+
Ambient temperature (K).
|
|
66
86
|
p0 : float
|
|
67
|
-
|
|
87
|
+
Ambient pressure (Pa).
|
|
68
88
|
split_physical_exergy : bool
|
|
69
|
-
|
|
89
|
+
Whether to split thermal and mechanical exergy.
|
|
70
90
|
|
|
71
91
|
Raises
|
|
72
92
|
------
|
|
73
93
|
ValueError
|
|
74
|
-
If
|
|
75
|
-
|
|
76
|
-
Calculation Details
|
|
77
|
-
-------------------
|
|
78
|
-
The exergy balance is determined based on exergy transfer due to heat loss (`E_L`)
|
|
79
|
-
and the exergy destruction within the system:
|
|
80
|
-
|
|
81
|
-
- **Exergy Loss (E_L)**:
|
|
82
|
-
\[
|
|
83
|
-
E_L = \dot{m}_{\mathrm{out,1}} \cdot (e_{\mathrm{PH,out,1}} - e_{\mathrm{PH,in,1}})
|
|
84
|
-
\]
|
|
85
|
-
Represents the exergy loss due to heat transfer from the process.
|
|
86
|
-
|
|
87
|
-
- **Exergy Destruction (E_D)**:
|
|
88
|
-
\[
|
|
89
|
-
E_D = \dot{m}_{\mathrm{out,0}} \cdot (e_{\mathrm{PH,in,0}} - e_{\mathrm{PH,out,0}}) - E_L
|
|
90
|
-
\]
|
|
91
|
-
Accounts for the irreversibilities and losses in the condenser.
|
|
92
|
-
|
|
93
|
-
Note
|
|
94
|
-
----
|
|
95
|
-
Exergy product (E_P) and exergy fuel (E_F) are generally undefined in a
|
|
96
|
-
condenser due to the focus on exergy loss rather than productive exergy usage.
|
|
94
|
+
If required inlets or outlets are missing.
|
|
97
95
|
"""
|
|
98
96
|
# Ensure that the component has both inlet and outlet streams
|
|
99
97
|
if len(self.inl) < 2 or len(self.outl) < 2:
|
|
100
98
|
raise ValueError("Condenser requires two inlets and two outlets.")
|
|
101
|
-
|
|
99
|
+
|
|
102
100
|
# Calculate exergy loss (E_L) for the heat transfer process
|
|
103
|
-
self.E_L = self.outl[1][
|
|
101
|
+
self.E_L = self.outl[1]["m"] * (self.outl[1]["e_PH"] - self.inl[1]["e_PH"])
|
|
104
102
|
|
|
105
103
|
# Calculate exergy destruction (E_D)
|
|
106
|
-
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
|
|
107
105
|
|
|
108
106
|
# Exergy fuel and product are not typically defined for a condenser
|
|
109
|
-
self.E_F =
|
|
110
|
-
self.E_P =
|
|
111
|
-
self.epsilon =
|
|
112
|
-
|
|
113
|
-
# Log the exergy balance results
|
|
114
|
-
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
|
|
115
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
|
+
)
|
|
116
117
|
|
|
117
118
|
def aux_eqs(self, A, b, counter, T0, equations, chemical_exergy_enabled):
|
|
118
|
-
"""
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
This
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
119
|
+
r"""
|
|
120
|
+
Add auxiliary cost equations for the condenser.
|
|
121
|
+
|
|
122
|
+
This method appends rows to the cost matrix to enforce:
|
|
123
|
+
|
|
124
|
+
Case 1: All streams above ambient temperature
|
|
125
|
+
|
|
126
|
+
F rule for thermal exergy of the hot stream:
|
|
127
|
+
|
|
128
|
+
.. math::
|
|
129
|
+
-\frac{1}{\dot{E}^{\mathrm{T}}_{\mathrm{out},1}}\,\dot{C}^{\mathrm{T}}_{\mathrm{out},1}
|
|
130
|
+
+ \frac{1}{\dot{E}^{\mathrm{T}}_{\mathrm{in},1}}\,\dot{C}^{\mathrm{T}}_{\mathrm{in},1}
|
|
131
|
+
= 0
|
|
132
|
+
|
|
133
|
+
Case 2: All streams below or equal to ambient temperature
|
|
134
|
+
|
|
135
|
+
F rule for thermal exergy of the cold stream:
|
|
136
|
+
|
|
137
|
+
.. math::
|
|
138
|
+
-\frac{1}{\dot{E}^{\mathrm{T}}_{\mathrm{out},2}}\,\dot{C}^{\mathrm{T}}_{\mathrm{out},2}
|
|
139
|
+
+ \frac{1}{\dot{E}^{\mathrm{T}}_{\mathrm{in},2}}\,\dot{C}^{\mathrm{T}}_{\mathrm{in},2}
|
|
140
|
+
= 0
|
|
141
|
+
|
|
142
|
+
Case 3: Both stream crossing ambient temperature
|
|
143
|
+
|
|
144
|
+
P rule for thermal exergy of both outlets:
|
|
145
|
+
|
|
146
|
+
.. math::
|
|
147
|
+
-\frac{1}{\dot{E}^{\mathrm{T}}_{\mathrm{out},1}}\,\dot{C}^{\mathrm{T}}_{\mathrm{out},1}
|
|
148
|
+
+ \frac{1}{\dot{E}^{\mathrm{T}}_{\mathrm{out},2}}\,\dot{C}^{\mathrm{T}}_{\mathrm{out},2}
|
|
149
|
+
= 0
|
|
150
|
+
|
|
151
|
+
Case 4: Only the hot inlet above ambient temperature
|
|
152
|
+
|
|
153
|
+
F rule for thermal exergy of the cold stream:
|
|
154
|
+
|
|
155
|
+
.. math::
|
|
156
|
+
-\frac{1}{\dot{E}^{\mathrm{T}}_{\mathrm{out},2}}\,\dot{C}^{\mathrm{T}}_{\mathrm{out},2}
|
|
157
|
+
+ \frac{1}{\dot{E}^{\mathrm{T}}_{\mathrm{in},2}}\,\dot{C}^{\mathrm{T}}_{\mathrm{in},2}
|
|
158
|
+
= 0
|
|
159
|
+
|
|
160
|
+
Case 5: Only the cold inlet below ambient temperature
|
|
161
|
+
|
|
162
|
+
F rule for thermal exergy of the hot stream:
|
|
163
|
+
|
|
164
|
+
.. math::
|
|
165
|
+
-\frac{1}{\dot{E}^{\mathrm{T}}_{\mathrm{out},1}}\,\dot{C}^{\mathrm{T}}_{\mathrm{out},1}
|
|
166
|
+
+ \frac{1}{\dot{E}^{\mathrm{T}}_{\mathrm{in},1}}\,\dot{C}^{\mathrm{T}}_{\mathrm{in},1}
|
|
167
|
+
= 0
|
|
168
|
+
|
|
169
|
+
Case 6: Hot stream always above and cold stream always below ambiente temperature (dissipative case):
|
|
170
|
+
|
|
171
|
+
The dissipative is not handeld here!
|
|
172
|
+
|
|
173
|
+
For all cases, the mechanical and chemical exergy costs are handled as follows:
|
|
174
|
+
|
|
175
|
+
F rule for mechanical exergy of the hot stream:
|
|
176
|
+
|
|
177
|
+
.. math::
|
|
178
|
+
-\frac{1}{\dot{E}^{\mathrm{M}}_{\mathrm{out},i}}\,\dot{C}^{\mathrm{M}}_{\mathrm{out},i}
|
|
179
|
+
+ \frac{1}{\dot{E}^{\mathrm{M}}_{\mathrm{in},i}}\,\dot{C}^{\mathrm{M}}_{\mathrm{in},i}
|
|
180
|
+
= 0
|
|
181
|
+
|
|
182
|
+
F rule for chemical exergy on hot branch:
|
|
183
|
+
|
|
184
|
+
.. math::
|
|
185
|
+
-\frac{1}{\dot{E}^{\mathrm{CH}}_{\mathrm{out},i}}\,\dot{C}^{\mathrm{CH}}_{\mathrm{out},i}
|
|
186
|
+
+ \frac{1}{\dot{E}^{\mathrm{CH}}_{\mathrm{in},i}}\,\dot{C}^{\mathrm{CH}}_{\mathrm{in},i}
|
|
187
|
+
= 0
|
|
188
|
+
|
|
141
189
|
Parameters
|
|
142
190
|
----------
|
|
143
191
|
A : numpy.ndarray
|
|
144
|
-
|
|
192
|
+
Current cost matrix.
|
|
145
193
|
b : numpy.ndarray
|
|
146
|
-
|
|
194
|
+
Current RHS vector.
|
|
147
195
|
counter : int
|
|
148
|
-
|
|
196
|
+
Starting row index for auxiliary equations.
|
|
149
197
|
T0 : float
|
|
150
|
-
Ambient temperature.
|
|
151
|
-
equations : dict
|
|
152
|
-
|
|
198
|
+
Ambient temperature (K).
|
|
199
|
+
equations : dict or list
|
|
200
|
+
Structure for equation labels.
|
|
153
201
|
chemical_exergy_enabled : bool
|
|
154
|
-
|
|
155
|
-
|
|
202
|
+
Must be True to include chemical exergy mixing.
|
|
203
|
+
|
|
156
204
|
Returns
|
|
157
205
|
-------
|
|
158
206
|
A : numpy.ndarray
|
|
159
|
-
|
|
207
|
+
Updated cost matrix.
|
|
160
208
|
b : numpy.ndarray
|
|
161
|
-
|
|
209
|
+
Updated RHS vector.
|
|
162
210
|
counter : int
|
|
163
|
-
|
|
164
|
-
equations : dict
|
|
165
|
-
Updated
|
|
211
|
+
Updated row index after adding equations.
|
|
212
|
+
equations : dict or list
|
|
213
|
+
Updated labels.
|
|
214
|
+
|
|
215
|
+
Raises
|
|
216
|
+
------
|
|
217
|
+
ValueError
|
|
218
|
+
If required cost variable indices are missing.
|
|
166
219
|
"""
|
|
220
|
+
|
|
167
221
|
# Equality equation for mechanical and chemical exergy costs.
|
|
168
222
|
def set_equal(A, row, in_item, out_item, var):
|
|
169
223
|
if in_item["e_" + var] != 0 and out_item["e_" + var] != 0:
|
|
@@ -220,48 +274,101 @@ class Condenser(Component):
|
|
|
220
274
|
# Case 1: All temperatures > T0.
|
|
221
275
|
if all([c["T"] > T0 for c in list(self.inl.values()) + list(self.outl.values())]):
|
|
222
276
|
set_thermal_f_hot(A, counter + 0)
|
|
223
|
-
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
|
+
}
|
|
224
282
|
# Case 2: All temperatures <= T0.
|
|
225
|
-
elif all([c["T"] <= T0 for c in self.inl + self.outl]):
|
|
283
|
+
elif all([c["T"] <= T0 for c in list(self.inl.values()) + list(self.outl.values())]):
|
|
226
284
|
set_thermal_f_cold(A, counter + 0)
|
|
227
|
-
equations[counter] =
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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
|
+
}
|
|
290
|
+
logging.warning(
|
|
291
|
+
f"All temperatures in {self.name} are below ambient temperature. "
|
|
292
|
+
"This is not a typical case for a dissipative condenser."
|
|
293
|
+
)
|
|
294
|
+
# Case 3: Both stream crossing T0 (hot inlet and cold outlet > T0, hot outlet and cold inlet <= 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:
|
|
231
296
|
set_thermal_p_rule(A, counter + 0)
|
|
232
|
-
equations[counter] =
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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
|
+
}
|
|
302
|
+
logging.warning(
|
|
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."
|
|
305
|
+
"The exergoeconomic analysis is counting the outlets as products."
|
|
306
|
+
)
|
|
307
|
+
# Case 4: Only hot inlet > 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:
|
|
236
309
|
set_thermal_f_cold(A, counter + 0)
|
|
237
|
-
equations[counter] =
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
+
}
|
|
315
|
+
logging.warning(
|
|
316
|
+
f"Cold inlet in {self.name} is below ambient temperature. "
|
|
317
|
+
"This is not a typical case for a dissipative condenser."
|
|
318
|
+
)
|
|
319
|
+
# Case 5: Only cold inlet <= 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:
|
|
241
321
|
set_thermal_f_hot(A, counter + 0)
|
|
242
|
-
equations[counter] =
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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
|
+
}
|
|
327
|
+
logging.warning(
|
|
328
|
+
f"Cold inlet in {self.name} is below ambient temperature. "
|
|
329
|
+
"This is not a typical case for a dissipative condenser."
|
|
330
|
+
)
|
|
331
|
+
# Case 6: hot stream always above T0, cold stream always below 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:
|
|
246
333
|
print("you shouldn't see this")
|
|
247
334
|
return
|
|
248
335
|
# Case 7: Default case.
|
|
249
336
|
else:
|
|
250
337
|
set_thermal_f_hot(A, counter + 0)
|
|
251
|
-
equations[counter] =
|
|
252
|
-
|
|
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
|
+
|
|
253
344
|
# Mechanical equations (always added)
|
|
254
345
|
set_equal(A, counter + 1, self.inl[0], self.outl[0], "M")
|
|
255
346
|
set_equal(A, counter + 2, self.inl[1], self.outl[1], "M")
|
|
256
|
-
equations[counter + 1] =
|
|
257
|
-
|
|
258
|
-
|
|
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
|
+
|
|
259
358
|
# Only add chemical auxiliary equations if chemical exergy is enabled.
|
|
260
359
|
if chemical_exergy_enabled:
|
|
261
360
|
set_equal(A, counter + 3, self.inl[0], self.outl[0], "CH")
|
|
262
361
|
set_equal(A, counter + 4, self.inl[1], self.outl[1], "CH")
|
|
263
|
-
equations[counter + 3] =
|
|
264
|
-
|
|
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
|
+
}
|
|
265
372
|
num_aux_eqs = 5
|
|
266
373
|
else:
|
|
267
374
|
# Skip chemical auxiliary equations.
|
|
@@ -271,50 +378,130 @@ class Condenser(Component):
|
|
|
271
378
|
b[counter + i] = 0
|
|
272
379
|
|
|
273
380
|
return A, b, counter + num_aux_eqs, equations
|
|
274
|
-
|
|
275
|
-
def exergoeconomic_balance(self, T0):
|
|
276
|
-
"""
|
|
277
|
-
Perform exergoeconomic balance
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
381
|
+
|
|
382
|
+
def exergoeconomic_balance(self, T0, chemical_exergy_enabled=False):
|
|
383
|
+
r"""
|
|
384
|
+
Perform exergoeconomic cost balance for the condenser.
|
|
385
|
+
|
|
386
|
+
Even though this class should only consider dissipative condensers, the exergoeconomic balance is
|
|
387
|
+
still performed to ensure consistency. Please note that same of the following cases cases are not
|
|
388
|
+
typical for dissipative condensers. This may change in a future version of ExerPy.
|
|
389
|
+
|
|
390
|
+
.. math::
|
|
391
|
+
\dot{C}^{\mathrm{T}}_{\mathrm{in},1}
|
|
392
|
+
+ \dot{C}^{\mathrm{M}}_{\mathrm{in},1}
|
|
393
|
+
+ \dot{C}^{\mathrm{T}}_{\mathrm{in},2}
|
|
394
|
+
+ \dot{C}^{\mathrm{M}}_{\mathrm{in},2}
|
|
395
|
+
- \dot{C}^{\mathrm{T}}_{\mathrm{out},1}
|
|
396
|
+
- \dot{C}^{\mathrm{M}}_{\mathrm{out},1}
|
|
397
|
+
- \dot{C}^{\mathrm{T}}_{\mathrm{out},2}
|
|
398
|
+
- \dot{C}^{\mathrm{M}}_{\mathrm{out},2}
|
|
399
|
+
+ \dot{Z}
|
|
400
|
+
= 0
|
|
401
|
+
|
|
402
|
+
In case the chemical exergy of the streams is know:
|
|
403
|
+
|
|
404
|
+
.. math::
|
|
405
|
+
\dot{C}^{\mathrm{CH}}_{\mathrm{in},1} =
|
|
406
|
+
\dot{C}^{\mathrm{CH}}_{\mathrm{out},1}
|
|
407
|
+
|
|
408
|
+
.. math::
|
|
409
|
+
\dot{C}^{\mathrm{CH}}_{\mathrm{in},2} =
|
|
410
|
+
\dot{C}^{\mathrm{CH}}_{\mathrm{out},2}
|
|
411
|
+
|
|
412
|
+
This method computes cost coefficients and ratios:
|
|
413
|
+
|
|
414
|
+
Case 1: All streams above ambient temperature
|
|
415
|
+
|
|
416
|
+
.. math::
|
|
417
|
+
\dot{C}_P = \dot{C}^{\mathrm{T}}_{\mathrm{out},2}
|
|
418
|
+
- \dot{C}^{\mathrm{T}}_{\mathrm{in},2}
|
|
419
|
+
|
|
420
|
+
.. math::
|
|
421
|
+
\dot{C}_F = \dot{C}^{\mathrm{PH}}_{\mathrm{in},1}
|
|
422
|
+
- \dot{C}^{\mathrm{PH}}_{\mathrm{out},1}
|
|
423
|
+
+ \bigl(\dot{C}^{\mathrm{M}}_{\mathrm{in},2}
|
|
424
|
+
- \dot{C}^{\mathrm{M}}_{\mathrm{out},2}\bigr)
|
|
425
|
+
|
|
426
|
+
Case 2: All streams below or equal to ambient temperature
|
|
427
|
+
|
|
428
|
+
.. math::
|
|
429
|
+
\dot{C}_P = \dot{C}^{\mathrm{T}}_{\mathrm{out},1}
|
|
430
|
+
- \dot{C}^{\mathrm{T}}_{\mathrm{in},1}
|
|
431
|
+
|
|
432
|
+
.. math::
|
|
433
|
+
\dot{C}_F = \dot{C}^{\mathrm{PH}}_{\mathrm{in},2}
|
|
434
|
+
- \dot{C}^{\mathrm{PH}}_{\mathrm{out},2}
|
|
435
|
+
+ \bigl(\dot{C}^{\mathrm{M}}_{\mathrm{in},1}
|
|
436
|
+
- \dot{C}^{\mathrm{M}}_{\mathrm{out},1}\bigr)
|
|
437
|
+
|
|
438
|
+
Case 3: Both stream crossing ambient temperature
|
|
439
|
+
|
|
440
|
+
.. math::
|
|
441
|
+
\dot{C}_P = \dot{C}^{\mathrm{T}}_{\mathrm{out},1}
|
|
442
|
+
+ \dot{C}^{\mathrm{T}}_{\mathrm{out},2}
|
|
443
|
+
|
|
444
|
+
.. math::
|
|
445
|
+
\dot{C}_F = \dot{C}^{\mathrm{PH}}_{\mathrm{in},1}
|
|
446
|
+
+ \dot{C}^{\mathrm{PH}}_{\mathrm{in},2}
|
|
447
|
+
- \bigl(\dot{C}^{\mathrm{M}}_{\mathrm{out},1}
|
|
448
|
+
+ \dot{C}^{\mathrm{M}}_{\mathrm{out},2}\bigr)
|
|
449
|
+
|
|
450
|
+
Case 4: Only the hot inlet above ambient temperature
|
|
451
|
+
|
|
452
|
+
.. math::
|
|
453
|
+
\dot{C}_P = \dot{C}^{\mathrm{T}}_{\mathrm{out},1}
|
|
454
|
+
|
|
455
|
+
.. math::
|
|
456
|
+
\dot{C}_F = \bigl(\dot{C}^{\mathrm{PH}}_{\mathrm{in},1}
|
|
457
|
+
+ \dot{C}^{\mathrm{PH}}_{\mathrm{in},2}\bigr)
|
|
458
|
+
- \bigl(\dot{C}^{\mathrm{PH}}_{\mathrm{out},2}
|
|
459
|
+
+ \dot{C}^{\mathrm{M}}_{\mathrm{out},1}\bigr)
|
|
460
|
+
|
|
461
|
+
Case 5: Only the cold inlet below ambient temperature
|
|
462
|
+
|
|
463
|
+
.. math::
|
|
464
|
+
\dot{C}_P = \dot{C}^{\mathrm{T}}_{\mathrm{out},2}
|
|
465
|
+
|
|
466
|
+
.. math::
|
|
467
|
+
\dot{C}_F = \dot{C}^{\mathrm{PH}}_{\mathrm{in},1}
|
|
468
|
+
- \dot{C}^{\mathrm{PH}}_{\mathrm{out},1}
|
|
469
|
+
+ \bigl(\dot{C}^{\mathrm{PH}}_{\mathrm{in},2}
|
|
470
|
+
- \dot{C}^{\mathrm{M}}_{\mathrm{out},2}\bigr)
|
|
471
|
+
|
|
472
|
+
Case 6: Hot stream always above and cold stream always below ambient temperature (dissipative case):
|
|
473
|
+
|
|
474
|
+
.. math::
|
|
475
|
+
\dot{C}_P = \mathrm{NaN}
|
|
476
|
+
|
|
477
|
+
.. math::
|
|
478
|
+
\dot{C}_F = \bigl(\dot{C}^{\mathrm{PH}}_{\mathrm{in},1}
|
|
479
|
+
- \dot{C}^{\mathrm{PH}}_{\mathrm{out},1}\bigr)
|
|
480
|
+
- \dot{C}^{\mathrm{PH}}_{\mathrm{out},2}
|
|
481
|
+
+ \dot{C}^{\mathrm{PH}}_{\mathrm{in},2}
|
|
482
|
+
|
|
286
483
|
Parameters
|
|
287
484
|
----------
|
|
288
485
|
T0 : float
|
|
289
|
-
Ambient temperature
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
-----
|
|
293
|
-
The exergoeconomic balance considers thermal (T), chemical (CH),
|
|
294
|
-
and mechanical (M) exergy components for the inlet and outlet streams.
|
|
486
|
+
Ambient temperature (K).
|
|
487
|
+
chemical_exergy_enabled : bool, optional
|
|
488
|
+
If True, chemical exergy is considered in the calculations.
|
|
295
489
|
"""
|
|
296
490
|
if all([c["T"] > T0 for c in list(self.inl.values()) + list(self.outl.values())]):
|
|
297
491
|
self.C_P = self.outl[1]["C_T"] - self.inl[1]["C_T"]
|
|
298
|
-
self.C_F = self.inl[0]["C_PH"] - self.outl[0]["C_PH"] + (
|
|
299
|
-
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"])
|
|
300
493
|
elif all([c["T"] <= T0 for c in list(self.inl.values()) + list(self.outl.values())]):
|
|
301
494
|
self.C_P = self.outl[0]["C_T"] - self.inl[0]["C_T"]
|
|
302
|
-
self.C_F = self.inl[1]["C_PH"] - self.outl[1]["C_PH"] + (
|
|
303
|
-
|
|
304
|
-
elif (self.inl[0]["T"] > T0 and self.outl[1]["T"] > T0 and
|
|
305
|
-
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:
|
|
306
497
|
self.C_P = self.outl[0]["C_T"] + self.outl[1]["C_T"]
|
|
307
|
-
self.C_F = self.inl[0]["C_PH"] + self.inl[1]["C_PH"] - (
|
|
308
|
-
|
|
309
|
-
elif (self.inl[0]["T"] > T0 and self.inl[1]["T"] <= T0 and
|
|
310
|
-
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:
|
|
311
500
|
self.C_P = self.outl[0]["C_T"]
|
|
312
|
-
self.C_F = self.inl[0]["C_PH"] + self.inl[1]["C_PH"] - (
|
|
313
|
-
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"])
|
|
314
502
|
else:
|
|
315
503
|
self.C_P = self.outl[1]["C_T"]
|
|
316
|
-
self.C_F = self.inl[0]["C_PH"] - self.outl[0]["C_PH"] + (
|
|
317
|
-
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"])
|
|
318
505
|
|
|
319
506
|
self.c_F = self.C_F / self.E_F
|
|
320
507
|
self.c_P = self.C_P / self.E_P
|