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
|
@@ -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
|
|
@@ -11,9 +10,9 @@ class Deaerator(Component):
|
|
|
11
10
|
r"""
|
|
12
11
|
Class for exergy analysis of deaerators.
|
|
13
12
|
|
|
14
|
-
This class performs exergy analysis calculations for deaerators with multiple
|
|
15
|
-
inlet streams and one outlet stream. The exergy product and fuel definitions
|
|
16
|
-
vary based on the temperature relationships between inlet streams, outlet
|
|
13
|
+
This class performs exergy analysis calculations for deaerators with multiple
|
|
14
|
+
inlet streams and one outlet stream. The exergy product and fuel definitions
|
|
15
|
+
vary based on the temperature relationships between inlet streams, outlet
|
|
17
16
|
stream, and ambient conditions.
|
|
18
17
|
|
|
19
18
|
Parameters
|
|
@@ -44,53 +43,52 @@ class Deaerator(Component):
|
|
|
44
43
|
product and fuel are defined based on temperature relationships:
|
|
45
44
|
|
|
46
45
|
.. math::
|
|
47
|
-
|
|
48
|
-
\dot{
|
|
49
|
-
\begin{cases}
|
|
46
|
+
\displaystyle
|
|
47
|
+
\dot E_{P} =
|
|
50
48
|
\begin{cases}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
\end{cases} & T_\mathrm{out} < T_0\\
|
|
49
|
+
\displaystyle
|
|
50
|
+
\sum_{i}\dot m_{i}\,\bigl(e_{\mathrm{out}}^{\mathrm{PH}}
|
|
51
|
+
-e_{\mathrm{in},i}^{\mathrm{PH}}\bigr),
|
|
52
|
+
\quad \text{if }T_{\mathrm{in},i}<T_{\mathrm{out}}\text{ and }T_{\mathrm{in},i}\ge T_{0},\\[8pt]
|
|
53
|
+
\displaystyle
|
|
54
|
+
\sum_{i}\dot m_{i}\,e_{\mathrm{out}}^{\mathrm{PH}},
|
|
55
|
+
\quad \text{if }T_{\mathrm{in},i}<T_{\mathrm{out}}\text{ and }T_{\mathrm{in},i}<T_{0},\\[8pt]
|
|
56
|
+
\displaystyle
|
|
57
|
+
\text{not defined (nan)},
|
|
58
|
+
\quad \text{if }T_{\mathrm{out}}=T_{0},\\[8pt]
|
|
59
|
+
\displaystyle
|
|
60
|
+
\sum_{i}\dot m_{i}\,e_{\mathrm{out}}^{\mathrm{PH}},
|
|
61
|
+
\quad \text{if }T_{\mathrm{in},i}>T_{\mathrm{out}}\text{ and }T_{\mathrm{in},i}\ge T_{0},\\[8pt]
|
|
62
|
+
\displaystyle
|
|
63
|
+
\sum_{i}\dot m_{i}\,\bigl(e_{\mathrm{out}}^{\mathrm{PH}}
|
|
64
|
+
-e_{\mathrm{in},i}^{\mathrm{PH}}\bigr),
|
|
65
|
+
\quad \text{if }T_{\mathrm{in},i}>T_{\mathrm{out}}\text{ and }T_{\mathrm{in},i}<T_{0}.
|
|
69
66
|
\end{cases}
|
|
70
67
|
|
|
71
|
-
|
|
72
|
-
\
|
|
73
|
-
\
|
|
74
|
-
\sum_i \dot{m}_i \cdot (e_{\mathrm{in,}i}^\mathrm{PH} -
|
|
75
|
-
e_\mathrm{out}^\mathrm{PH})
|
|
76
|
-
& T_{\mathrm{in,}i} > T_\mathrm{out} \\
|
|
77
|
-
\sum_i \dot{m}_i \cdot e_{\mathrm{in,}i}^\mathrm{PH}
|
|
78
|
-
& T_{\mathrm{in,}i} < T_\mathrm{out} \mathrm{ & }
|
|
79
|
-
T_{\mathrm{in,}i} < T_0 \\
|
|
80
|
-
\end{cases} & T_\mathrm{out} > T_0\\
|
|
81
|
-
\sum_i \dot{m}_i \cdot e_{\mathrm{in,}i}^\mathrm{PH}
|
|
82
|
-
& T_\mathrm{out} = T_0\\
|
|
68
|
+
.. math::
|
|
69
|
+
\displaystyle
|
|
70
|
+
\dot E_{F} =
|
|
83
71
|
\begin{cases}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
72
|
+
\displaystyle
|
|
73
|
+
\sum_{i}\dot m_{i}\,\bigl(e_{\mathrm{in},i}^{\mathrm{PH}}
|
|
74
|
+
-e_{\mathrm{out}}^{\mathrm{PH}}\bigr),
|
|
75
|
+
\quad \text{if }T_{\mathrm{out}}>T_{0}\text{ and }T_{\mathrm{in},i}>T_{\mathrm{out}},\\[8pt]
|
|
76
|
+
\displaystyle
|
|
77
|
+
\sum_{i}\dot m_{i}\,e_{\mathrm{in},i}^{\mathrm{PH}},
|
|
78
|
+
\quad \text{if }T_{\mathrm{out}}>T_{0}\text{ and }T_{\mathrm{in},i}<T_{\mathrm{out}}
|
|
79
|
+
\text{ and }T_{\mathrm{in},i}<T_{0},\\[8pt]
|
|
80
|
+
\displaystyle
|
|
81
|
+
\sum_{i}\dot m_{i}\,e_{\mathrm{in},i}^{\mathrm{PH}},
|
|
82
|
+
\quad \text{if }T_{\mathrm{out}}=T_{0},\\[8pt]
|
|
83
|
+
\displaystyle
|
|
84
|
+
\sum_{i}\dot m_{i}\,e_{\mathrm{in},i}^{\mathrm{PH}},
|
|
85
|
+
\quad \text{if }T_{\mathrm{out}}<T_{0}\text{ and }T_{\mathrm{in},i}>T_{\mathrm{out}},\\[8pt]
|
|
86
|
+
\displaystyle
|
|
87
|
+
\sum_{i}\dot m_{i}\,\bigl(e_{\mathrm{in},i}^{\mathrm{PH}}
|
|
88
|
+
-e_{\mathrm{out}}^{\mathrm{PH}}\bigr),
|
|
89
|
+
\quad \text{if }T_{\mathrm{out}}<T_{0}\text{ and }T_{\mathrm{in},i}<T_{\mathrm{out}}.
|
|
91
90
|
\end{cases}
|
|
92
91
|
|
|
93
|
-
\forall i \in \mathrm{deaerator inlets}
|
|
94
92
|
"""
|
|
95
93
|
|
|
96
94
|
def __init__(self, **kwargs):
|
|
@@ -117,7 +115,7 @@ class Deaerator(Component):
|
|
|
117
115
|
------
|
|
118
116
|
ValueError
|
|
119
117
|
If the required inlet and outlet streams are not properly defined.
|
|
120
|
-
"""
|
|
118
|
+
"""
|
|
121
119
|
# Ensure that the component has both inlet and outlet streams
|
|
122
120
|
if len(self.inl) < 2 or len(self.outl) < 1:
|
|
123
121
|
raise ValueError("Deaerator requires at least two inlets and one outlet.")
|
|
@@ -126,34 +124,34 @@ class Deaerator(Component):
|
|
|
126
124
|
self.E_F = 0
|
|
127
125
|
|
|
128
126
|
# Case 1: Outlet temperature is greater than T0
|
|
129
|
-
if self.outl[0][
|
|
127
|
+
if self.outl[0]["T"] > T0:
|
|
130
128
|
for _, inlet in self.inl.items():
|
|
131
|
-
if inlet[
|
|
132
|
-
if inlet[
|
|
133
|
-
self.E_P += inlet[
|
|
129
|
+
if inlet["T"] < self.outl[0]["T"]: # Tin < Tout
|
|
130
|
+
if inlet["T"] >= T0: # and Tin >= T0
|
|
131
|
+
self.E_P += inlet["m"] * (self.outl[0]["e_PH"] - inlet["e_PH"])
|
|
134
132
|
else: # and Tin < T0
|
|
135
|
-
self.E_P += inlet[
|
|
136
|
-
self.E_F += inlet[
|
|
133
|
+
self.E_P += inlet["m"] * self.outl[0]["e_PH"]
|
|
134
|
+
self.E_F += inlet["m"] * inlet["e_PH"]
|
|
137
135
|
else: # Tin > Tout
|
|
138
|
-
self.E_F += inlet[
|
|
136
|
+
self.E_F += inlet["m"] * (inlet["e_PH"] - self.outl[0]["e_PH"])
|
|
139
137
|
|
|
140
138
|
# Case 2: Outlet temperature is equal to T0
|
|
141
|
-
elif self.outl[0][
|
|
139
|
+
elif self.outl[0]["T"] == T0:
|
|
142
140
|
self.E_P = np.nan
|
|
143
141
|
for _, inlet in self.inl.items():
|
|
144
|
-
self.E_F += inlet[
|
|
142
|
+
self.E_F += inlet["m"] * inlet["e_PH"]
|
|
145
143
|
|
|
146
144
|
# Case 3: Outlet temperature is less than T0
|
|
147
145
|
else:
|
|
148
146
|
for _, inlet in self.inl.items():
|
|
149
|
-
if inlet[
|
|
150
|
-
if inlet[
|
|
151
|
-
self.E_P += inlet[
|
|
152
|
-
self.E_F += inlet[
|
|
147
|
+
if inlet["T"] > self.outl[0]["T"]: # Tin > Tout
|
|
148
|
+
if inlet["T"] >= T0: # and Tin >= T0
|
|
149
|
+
self.E_P += inlet["m"] * self.outl[0]["e_PH"]
|
|
150
|
+
self.E_F += inlet["m"] * inlet["e_PH"]
|
|
153
151
|
else: # and Tin < T0
|
|
154
|
-
self.E_P += inlet[
|
|
152
|
+
self.E_P += inlet["m"] * (self.outl[0]["e_PH"] - inlet["e_PH"])
|
|
155
153
|
else: # Tin < Tout
|
|
156
|
-
self.E_F += inlet[
|
|
154
|
+
self.E_F += inlet["m"] * (inlet["e_PH"] - self.outl[0]["e_PH"])
|
|
157
155
|
|
|
158
156
|
# Calculate exergy destruction and efficiency
|
|
159
157
|
if np.isnan(self.E_P):
|
|
@@ -164,7 +162,7 @@ class Deaerator(Component):
|
|
|
164
162
|
|
|
165
163
|
# Log the results
|
|
166
164
|
logging.info(
|
|
167
|
-
f"Deaerator
|
|
165
|
+
f"Exergy balance of Deaerator {self.name} calculated: "
|
|
168
166
|
f"E_P={self.E_P:.2f}, E_F={self.E_F:.2f}, E_D={self.E_D:.2f}, "
|
|
169
167
|
f"Efficiency={self.epsilon:.2%}"
|
|
170
168
|
)
|
|
@@ -172,23 +170,25 @@ class Deaerator(Component):
|
|
|
172
170
|
def aux_eqs(self, A, b, counter, T0, equations, chemical_exergy_enabled):
|
|
173
171
|
"""
|
|
174
172
|
Auxiliary equations for the deaerator.
|
|
175
|
-
|
|
173
|
+
|
|
176
174
|
This function adds rows to the cost matrix A and the right-hand-side vector b to enforce
|
|
177
175
|
the following auxiliary cost relations:
|
|
178
|
-
|
|
176
|
+
|
|
179
177
|
(1) Mixing equation for chemical exergy costs (if enabled):
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
178
|
+
|
|
179
|
+
- The outlet's specific chemical exergy cost is calculated as a mass-weighted average of the inlet streams' specific chemical exergy costs
|
|
180
|
+
|
|
181
|
+
- This enforces proper chemical exergy cost distribution through the deaerator
|
|
182
|
+
|
|
184
183
|
(2) Mixing equation for mechanical exergy costs:
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
184
|
+
|
|
185
|
+
- The outlet's specific mechanical exergy cost is calculated as a mass-weighted average of the inlet streams' specific mechanical exergy costs
|
|
186
|
+
|
|
187
|
+
- This ensures mechanical exergy costs are properly conserved in the mixing process
|
|
188
|
+
|
|
189
189
|
Both equations implement the proportionality rule for mixing processes where
|
|
190
190
|
the outlet's specific costs should reflect the contribution of each inlet stream.
|
|
191
|
-
|
|
191
|
+
|
|
192
192
|
Parameters
|
|
193
193
|
----------
|
|
194
194
|
A : numpy.ndarray
|
|
@@ -203,7 +203,7 @@ class Deaerator(Component):
|
|
|
203
203
|
Dictionary for storing equation labels.
|
|
204
204
|
chemical_exergy_enabled : bool
|
|
205
205
|
Flag indicating whether chemical exergy auxiliary equations should be added.
|
|
206
|
-
|
|
206
|
+
|
|
207
207
|
Returns
|
|
208
208
|
-------
|
|
209
209
|
A : numpy.ndarray
|
|
@@ -229,13 +229,16 @@ class Deaerator(Component):
|
|
|
229
229
|
# Outlet chemical exergy is zero: assign fallback for all inlets.
|
|
230
230
|
for inlet in self.inl.values():
|
|
231
231
|
A[counter, inlet["CostVar_index"]["CH"]] = 1
|
|
232
|
-
equations[counter] =
|
|
232
|
+
equations[counter] = {
|
|
233
|
+
"kind": "aux_mixing",
|
|
234
|
+
"objects": [self.name, self.inl[0]["name"], self.inl[1]["name"], self.outl[0]["name"]],
|
|
235
|
+
"property": "c_CH",
|
|
236
|
+
}
|
|
233
237
|
chem_row = 1 # One row added for chemical equation.
|
|
234
238
|
else:
|
|
235
239
|
chem_row = 0 # No row added.
|
|
236
240
|
|
|
237
241
|
# --- Mechanical cost auxiliary equation ---
|
|
238
|
-
mech_row = 0 # This row will always be added.
|
|
239
242
|
if self.outl[0]["e_M"] != 0:
|
|
240
243
|
A[counter + chem_row, self.outl[0]["CostVar_index"]["M"]] = -1 / self.outl[0]["E_M"]
|
|
241
244
|
# Iterate over inlet streams for mechanical mixing.
|
|
@@ -247,7 +250,11 @@ class Deaerator(Component):
|
|
|
247
250
|
else:
|
|
248
251
|
for inlet in self.inl.values():
|
|
249
252
|
A[counter + chem_row, inlet["CostVar_index"]["M"]] = 1
|
|
250
|
-
equations[counter + chem_row] =
|
|
253
|
+
equations[counter + chem_row] = {
|
|
254
|
+
"kind": "aux_mixing",
|
|
255
|
+
"objects": [self.name, self.inl[0]["name"], self.inl[1]["name"], self.outl[0]["name"]],
|
|
256
|
+
"property": "c_M",
|
|
257
|
+
}
|
|
251
258
|
|
|
252
259
|
# Set the right-hand side entries to zero for the added rows.
|
|
253
260
|
if chemical_exergy_enabled:
|
|
@@ -260,26 +267,141 @@ class Deaerator(Component):
|
|
|
260
267
|
|
|
261
268
|
return A, b, counter, equations
|
|
262
269
|
|
|
263
|
-
def exergoeconomic_balance(self, T0):
|
|
264
|
-
"""
|
|
265
|
-
Perform exergoeconomic balance
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
270
|
+
def exergoeconomic_balance(self, T0, chemical_exergy_enabled=False):
|
|
271
|
+
r"""
|
|
272
|
+
Perform exergoeconomic cost balance for the deaerator (mixing component).
|
|
273
|
+
|
|
274
|
+
The deaerator is a mixing component where multiple streams combine. The general
|
|
275
|
+
exergoeconomic balance equation is:
|
|
276
|
+
|
|
277
|
+
.. math::
|
|
278
|
+
\sum_{\mathrm{in}} \left(\dot{C}^{\mathrm{T}}_{\mathrm{in}}
|
|
279
|
+
+ \dot{C}^{\mathrm{M}}_{\mathrm{in}}
|
|
280
|
+
+ \dot{C}^{\mathrm{CH}}_{\mathrm{in}}\right)
|
|
281
|
+
- \sum_{\mathrm{out}} \left(\dot{C}^{\mathrm{T}}_{\mathrm{out}}
|
|
282
|
+
+ \dot{C}^{\mathrm{M}}_{\mathrm{out}}
|
|
283
|
+
+ \dot{C}^{\mathrm{CH}}_{\mathrm{out}}\right)
|
|
284
|
+
+ \dot{Z}
|
|
285
|
+
= 0
|
|
286
|
+
|
|
287
|
+
The product is defined as the outlet stream. The fuel consists of all inlet
|
|
288
|
+
streams, with specific treatment depending on temperature levels. The cost
|
|
289
|
+
balance is closed using:
|
|
290
|
+
|
|
291
|
+
.. math::
|
|
292
|
+
\dot{C}_{\mathrm{P}} = \dot{C}_{\mathrm{F}} + \dot{Z}
|
|
293
|
+
|
|
294
|
+
**Case 1: Outlet above ambient temperature**
|
|
295
|
+
|
|
296
|
+
When :math:`T_{\mathrm{out}} > T_0`:
|
|
297
|
+
|
|
298
|
+
For cold inlets (:math:`T_{\mathrm{in}} < T_{\mathrm{out}}`):
|
|
299
|
+
|
|
300
|
+
.. math::
|
|
301
|
+
\dot{C}_{\mathrm{F,cold}} = \dot{C}^{\mathrm{M}}_{\mathrm{in}}
|
|
302
|
+
+ \dot{C}^{\mathrm{CH}}_{\mathrm{in}}
|
|
303
|
+
|
|
304
|
+
For hot inlets (:math:`T_{\mathrm{in}} \geq T_{\mathrm{out}}`):
|
|
305
|
+
|
|
306
|
+
.. math::
|
|
307
|
+
\dot{C}_{\mathrm{F,hot}} = -\dot{m}_{\mathrm{in}} \cdot c^{\mathrm{T}}_{\mathrm{in}}
|
|
308
|
+
\cdot e^{\mathrm{T}}_{\mathrm{in}}
|
|
309
|
+
+ \left(\dot{C}^{\mathrm{T}}_{\mathrm{in}}
|
|
310
|
+
+ \dot{C}^{\mathrm{M}}_{\mathrm{in}}
|
|
311
|
+
+ \dot{C}^{\mathrm{CH}}_{\mathrm{in}}\right)
|
|
312
|
+
|
|
313
|
+
Total fuel cost:
|
|
314
|
+
|
|
315
|
+
.. math::
|
|
316
|
+
\dot{C}_{\mathrm{F}} = \sum \dot{C}_{\mathrm{F,cold}}
|
|
317
|
+
+ \sum \dot{C}_{\mathrm{F,hot}}
|
|
318
|
+
- \dot{C}^{\mathrm{M}}_{\mathrm{out}}
|
|
319
|
+
- \dot{C}^{\mathrm{CH}}_{\mathrm{out}}
|
|
320
|
+
|
|
321
|
+
**Case 2: Outlet at ambient temperature (dissipative)**
|
|
322
|
+
|
|
323
|
+
When :math:`|T_{\mathrm{out}} - T_0| < 10^{-6}`:
|
|
324
|
+
|
|
325
|
+
.. math::
|
|
326
|
+
\dot{C}_{\mathrm{F}} = \sum_{\mathrm{in}} \dot{C}^{\mathrm{TOT}}_{\mathrm{in}}
|
|
327
|
+
|
|
328
|
+
**Case 3: Outlet below ambient temperature**
|
|
329
|
+
|
|
330
|
+
When :math:`T_{\mathrm{out}} < T_0`:
|
|
331
|
+
|
|
332
|
+
For hot inlets (:math:`T_{\mathrm{in}} > T_{\mathrm{out}}`):
|
|
333
|
+
|
|
334
|
+
.. math::
|
|
335
|
+
\dot{C}_{\mathrm{F,hot}} = \dot{C}^{\mathrm{M}}_{\mathrm{in}}
|
|
336
|
+
+ \dot{C}^{\mathrm{CH}}_{\mathrm{in}}
|
|
337
|
+
|
|
338
|
+
For cold inlets (:math:`T_{\mathrm{in}} \leq T_{\mathrm{out}}`):
|
|
339
|
+
|
|
340
|
+
.. math::
|
|
341
|
+
\dot{C}_{\mathrm{F,cold}} = -\dot{m}_{\mathrm{in}} \cdot c^{\mathrm{T}}_{\mathrm{in}}
|
|
342
|
+
\cdot e^{\mathrm{T}}_{\mathrm{in}}
|
|
343
|
+
+ \left(\dot{C}^{\mathrm{T}}_{\mathrm{in}}
|
|
344
|
+
+ \dot{C}^{\mathrm{M}}_{\mathrm{in}}
|
|
345
|
+
+ \dot{C}^{\mathrm{CH}}_{\mathrm{in}}\right)
|
|
346
|
+
|
|
347
|
+
Total fuel cost:
|
|
348
|
+
|
|
349
|
+
.. math::
|
|
350
|
+
\dot{C}_{\mathrm{F}} = \sum \dot{C}_{\mathrm{F,hot}}
|
|
351
|
+
+ \sum \dot{C}_{\mathrm{F,cold}}
|
|
352
|
+
- \dot{C}^{\mathrm{M}}_{\mathrm{out}}
|
|
353
|
+
- \dot{C}^{\mathrm{CH}}_{\mathrm{out}}
|
|
354
|
+
|
|
355
|
+
**Calculated exergoeconomic indicators:**
|
|
356
|
+
|
|
357
|
+
.. math::
|
|
358
|
+
c_{\mathrm{F}} = \frac{\dot{C}_{\mathrm{F}}}{\dot{E}_{\mathrm{F}}}
|
|
359
|
+
|
|
360
|
+
.. math::
|
|
361
|
+
c_{\mathrm{P}} = \frac{\dot{C}_{\mathrm{P}}}{\dot{E}_{\mathrm{P}}}
|
|
362
|
+
|
|
363
|
+
.. math::
|
|
364
|
+
\dot{C}_{\mathrm{D}} = c_{\mathrm{F}} \cdot \dot{E}_{\mathrm{D}}
|
|
365
|
+
|
|
366
|
+
.. math::
|
|
367
|
+
r = \frac{c_{\mathrm{P}} - c_{\mathrm{F}}}{c_{\mathrm{F}}}
|
|
368
|
+
|
|
369
|
+
.. math::
|
|
370
|
+
f = \frac{\dot{Z}}{\dot{Z} + \dot{C}_{\mathrm{D}}}
|
|
371
|
+
|
|
274
372
|
Parameters
|
|
275
373
|
----------
|
|
276
374
|
T0 : float
|
|
277
|
-
Ambient temperature
|
|
278
|
-
|
|
375
|
+
Ambient temperature (K).
|
|
376
|
+
chemical_exergy_enabled : bool, optional
|
|
377
|
+
If True, chemical exergy is considered in the calculations.
|
|
378
|
+
Default is False.
|
|
379
|
+
|
|
380
|
+
Attributes Set
|
|
381
|
+
--------------
|
|
382
|
+
C_P : float
|
|
383
|
+
Cost rate of product (currency/time).
|
|
384
|
+
C_F : float
|
|
385
|
+
Cost rate of fuel (currency/time).
|
|
386
|
+
c_P : float
|
|
387
|
+
Specific cost of product (currency/energy).
|
|
388
|
+
c_F : float
|
|
389
|
+
Specific cost of fuel (currency/energy).
|
|
390
|
+
C_D : float
|
|
391
|
+
Cost rate of exergy destruction (currency/time).
|
|
392
|
+
r : float
|
|
393
|
+
Relative cost difference (dimensionless).
|
|
394
|
+
f : float
|
|
395
|
+
Exergoeconomic factor (dimensionless).
|
|
396
|
+
|
|
279
397
|
Notes
|
|
280
398
|
-----
|
|
281
|
-
The
|
|
282
|
-
|
|
399
|
+
The deaerator treats thermal, mechanical, and chemical exergy components
|
|
400
|
+
differently depending on whether inlets are "hot" or "cold" relative to
|
|
401
|
+
the outlet temperature. The distinction ensures proper cost allocation
|
|
402
|
+
for streams that provide heating versus those being heated.
|
|
403
|
+
|
|
404
|
+
Future development may include merging profits from dissipative components.
|
|
283
405
|
"""
|
|
284
406
|
self.C_P = 0
|
|
285
407
|
self.C_F = 0
|
|
@@ -290,9 +412,8 @@ class Deaerator(Component):
|
|
|
290
412
|
self.C_F += i["C_M"] + i["C_CH"]
|
|
291
413
|
else:
|
|
292
414
|
# hot inlets
|
|
293
|
-
self.C_F += -
|
|
294
|
-
|
|
295
|
-
self.C_F += (-self.outl[0]["C_M"] - self.outl[0]["C_CH"])
|
|
415
|
+
self.C_F += -i["M"] * i["C_T"] * i["e_T"] + (i["C_T"] + i["C_M"] + i["C_CH"])
|
|
416
|
+
self.C_F += -self.outl[0]["C_M"] - self.outl[0]["C_CH"]
|
|
296
417
|
elif self.outl[0]["T"] - 1e-6 < T0 and self.outl[0]["T"] + 1e-6 > T0:
|
|
297
418
|
# dissipative
|
|
298
419
|
for i in self.inl:
|
|
@@ -304,15 +425,13 @@ class Deaerator(Component):
|
|
|
304
425
|
self.C_F += i["C_M"] + i["C_CH"]
|
|
305
426
|
else:
|
|
306
427
|
# cold inlets
|
|
307
|
-
self.C_F += -
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
self.C_P = self.C_F + self.Z_costs # +1/num_serving_comps * C_diff
|
|
428
|
+
self.C_F += -i["M"] * i["C_T"] * i["e_T"] + (i["C_T"] + i["C_M"] + i["C_CH"])
|
|
429
|
+
self.C_F += -self.outl[0]["C_M"] - self.outl[0]["C_CH"]
|
|
430
|
+
self.C_P = self.C_F + self.Z_costs # +1/num_serving_comps * C_diff
|
|
311
431
|
# ToDo: add case that merge profits from dissipative component(s)
|
|
312
432
|
|
|
313
|
-
|
|
314
433
|
self.c_F = self.C_F / self.E_F
|
|
315
434
|
self.c_P = self.C_P / self.E_P
|
|
316
435
|
self.C_D = self.c_F * self.E_D
|
|
317
436
|
self.r = (self.c_P - self.c_F) / self.c_F
|
|
318
|
-
self.f = self.Z_costs / (self.Z_costs + self.C_D)
|
|
437
|
+
self.f = self.Z_costs / (self.Z_costs + self.C_D)
|
exerpy/components/nodes/drum.py
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
from exerpy.components.component import Component
|
|
6
|
-
from exerpy.components.component import component_registry
|
|
3
|
+
from exerpy.components.component import Component, component_registry
|
|
7
4
|
|
|
8
5
|
|
|
9
6
|
@component_registry
|
|
@@ -30,14 +27,8 @@ class Drum(Component):
|
|
|
30
27
|
\dot{E}_\mathrm{P} = \sum \dot{E}_{\mathrm{out,}j}^\mathrm{PH}\\
|
|
31
28
|
\dot{E}_\mathrm{F} = \sum \dot{E}_{\mathrm{in,}i}^\mathrm{PH}
|
|
32
29
|
"""
|
|
33
|
-
self.E_P =
|
|
34
|
-
|
|
35
|
-
+ self.outl[1]['e_PH'] * self.outl[1]['m']
|
|
36
|
-
)
|
|
37
|
-
self.E_F = (
|
|
38
|
-
self.inl[0]['e_PH'] * self.inl[0]['m']
|
|
39
|
-
+ self.inl[1]['e_PH'] * self.inl[1]['m']
|
|
40
|
-
)
|
|
30
|
+
self.E_P = self.outl[0]["e_PH"] * self.outl[0]["m"] + self.outl[1]["e_PH"] * self.outl[1]["m"]
|
|
31
|
+
self.E_F = self.inl[0]["e_PH"] * self.inl[0]["m"] + self.inl[1]["e_PH"] * self.inl[1]["m"]
|
|
41
32
|
|
|
42
33
|
# Calculate exergy destruction and efficiency
|
|
43
34
|
self.E_D = self.E_F - self.E_P
|
|
@@ -45,7 +36,7 @@ class Drum(Component):
|
|
|
45
36
|
|
|
46
37
|
# Log the results
|
|
47
38
|
logging.info(
|
|
48
|
-
f"Drum
|
|
39
|
+
f"Exergy balance of Drum {self.name} calculated: "
|
|
49
40
|
f"E_P={self.E_P:.2f}, E_F={self.E_F:.2f}, E_D={self.E_D:.2f}, "
|
|
50
41
|
f"Efficiency={self.epsilon:.2%}"
|
|
51
42
|
)
|
|
@@ -102,18 +93,26 @@ class Drum(Component):
|
|
|
102
93
|
A[counter, self.outl[0]["CostVar_index"]["CH"]] = -1 / self.outl[0]["E_CH"]
|
|
103
94
|
else:
|
|
104
95
|
A[counter, self.outl[0]["CostVar_index"]["CH"]] = -1
|
|
105
|
-
equations[counter] =
|
|
106
|
-
|
|
96
|
+
equations[counter] = {
|
|
97
|
+
"kind": "aux_equality",
|
|
98
|
+
"objects": [self.name, self.inl[0]["name"], self.outl[0]["name"]],
|
|
99
|
+
"property": "c_CH",
|
|
100
|
+
}
|
|
101
|
+
|
|
107
102
|
# Equation 2: Balance between inlet 0 and outlet 1 for chemical exergy
|
|
108
103
|
if self.inl[0]["e_CH"] != 0:
|
|
109
|
-
A[counter+1, self.inl[0]["CostVar_index"]["CH"]] = 1 / self.inl[0]["E_CH"]
|
|
104
|
+
A[counter + 1, self.inl[0]["CostVar_index"]["CH"]] = 1 / self.inl[0]["E_CH"]
|
|
110
105
|
else:
|
|
111
|
-
A[counter+1, self.inl[0]["CostVar_index"]["CH"]] = 1
|
|
106
|
+
A[counter + 1, self.inl[0]["CostVar_index"]["CH"]] = 1
|
|
112
107
|
if self.outl[1]["e_CH"] != 0:
|
|
113
|
-
A[counter+1, self.outl[1]["CostVar_index"]["CH"]] = -1 / self.outl[1]["E_CH"]
|
|
108
|
+
A[counter + 1, self.outl[1]["CostVar_index"]["CH"]] = -1 / self.outl[1]["E_CH"]
|
|
114
109
|
else:
|
|
115
|
-
A[counter+1, self.outl[1]["CostVar_index"]["CH"]] = -1
|
|
116
|
-
equations[counter+1] =
|
|
110
|
+
A[counter + 1, self.outl[1]["CostVar_index"]["CH"]] = -1
|
|
111
|
+
equations[counter + 1] = {
|
|
112
|
+
"kind": "aux_equality",
|
|
113
|
+
"objects": [self.name, self.inl[1]["name"], self.outl[1]["name"]],
|
|
114
|
+
"property": "c_CH",
|
|
115
|
+
}
|
|
117
116
|
chem_rows = 2
|
|
118
117
|
else:
|
|
119
118
|
chem_rows = 0
|
|
@@ -121,41 +120,53 @@ class Drum(Component):
|
|
|
121
120
|
# --- Thermal cost auxiliary equation ---
|
|
122
121
|
# For thermal exergy, we balance the two outlets.
|
|
123
122
|
if (self.outl[0]["e_T"] != 0) and (self.outl[1]["e_T"] != 0):
|
|
124
|
-
A[counter+chem_rows, self.outl[0]["CostVar_index"]["T"]] = 1 / self.outl[0]["E_T"]
|
|
125
|
-
A[counter+chem_rows, self.outl[1]["CostVar_index"]["T"]] = -1 / self.outl[1]["E_T"]
|
|
123
|
+
A[counter + chem_rows, self.outl[0]["CostVar_index"]["T"]] = 1 / self.outl[0]["E_T"]
|
|
124
|
+
A[counter + chem_rows, self.outl[1]["CostVar_index"]["T"]] = -1 / self.outl[1]["E_T"]
|
|
126
125
|
elif self.outl[0]["e_T"] == 0 and self.outl[1]["e_T"] != 0:
|
|
127
|
-
A[counter+chem_rows, self.outl[0]["CostVar_index"]["T"]] = 1
|
|
126
|
+
A[counter + chem_rows, self.outl[0]["CostVar_index"]["T"]] = 1
|
|
128
127
|
elif self.outl[0]["e_T"] != 0 and self.outl[1]["e_T"] == 0:
|
|
129
|
-
A[counter+chem_rows, self.outl[1]["CostVar_index"]["T"]] = -1
|
|
128
|
+
A[counter + chem_rows, self.outl[1]["CostVar_index"]["T"]] = -1
|
|
130
129
|
else:
|
|
131
|
-
A[counter+chem_rows, self.outl[0]["CostVar_index"]["T"]] = 1
|
|
132
|
-
A[counter+chem_rows, self.outl[1]["CostVar_index"]["T"]] = -1
|
|
133
|
-
equations[counter+chem_rows] =
|
|
130
|
+
A[counter + chem_rows, self.outl[0]["CostVar_index"]["T"]] = 1
|
|
131
|
+
A[counter + chem_rows, self.outl[1]["CostVar_index"]["T"]] = -1
|
|
132
|
+
equations[counter + chem_rows] = {
|
|
133
|
+
"kind": "aux_p_rule",
|
|
134
|
+
"objects": [self.name, self.outl[0]["name"], self.outl[1]["name"]],
|
|
135
|
+
"property": "c_T",
|
|
136
|
+
}
|
|
134
137
|
|
|
135
138
|
# --- Mechanical cost auxiliary equation ---
|
|
136
139
|
if self.outl[0]["e_M"] != 0:
|
|
137
|
-
A[counter+chem_rows+1, self.outl[0]["CostVar_index"]["M"]] = 1 / self.outl[0]["E_M"]
|
|
140
|
+
A[counter + chem_rows + 1, self.outl[0]["CostVar_index"]["M"]] = 1 / self.outl[0]["E_M"]
|
|
138
141
|
else:
|
|
139
|
-
A[counter+chem_rows+1, self.outl[0]["CostVar_index"]["M"]] = 1
|
|
142
|
+
A[counter + chem_rows + 1, self.outl[0]["CostVar_index"]["M"]] = 1
|
|
140
143
|
if self.outl[1]["e_M"] != 0:
|
|
141
|
-
A[counter+chem_rows+1, self.outl[1]["CostVar_index"]["M"]] = -1 / self.outl[1]["E_M"]
|
|
144
|
+
A[counter + chem_rows + 1, self.outl[1]["CostVar_index"]["M"]] = -1 / self.outl[1]["E_M"]
|
|
142
145
|
else:
|
|
143
|
-
A[counter+chem_rows+1, self.outl[1]["CostVar_index"]["M"]] = -1
|
|
144
|
-
equations[counter+chem_rows+1] =
|
|
146
|
+
A[counter + chem_rows + 1, self.outl[1]["CostVar_index"]["M"]] = -1
|
|
147
|
+
equations[counter + chem_rows + 1] = {
|
|
148
|
+
"kind": "aux_p_rule",
|
|
149
|
+
"objects": [self.name, self.outl[0]["name"], self.outl[1]["name"]],
|
|
150
|
+
"property": "c_M",
|
|
151
|
+
}
|
|
145
152
|
|
|
146
153
|
# --- Thermal-Mechanical coupling equation for outlet 0 ---
|
|
147
154
|
# This enforces that the thermal and mechanical cost components at outlet 0 are consistent.
|
|
148
155
|
if (self.outl[0]["e_T"] != 0) and (self.outl[0]["e_M"] != 0):
|
|
149
|
-
A[counter+chem_rows+2, self.outl[0]["CostVar_index"]["T"]] = 1 / self.outl[0]["E_T"]
|
|
150
|
-
A[counter+chem_rows+2, self.outl[0]["CostVar_index"]["M"]] = -1 / self.outl[0]["E_M"]
|
|
156
|
+
A[counter + chem_rows + 2, self.outl[0]["CostVar_index"]["T"]] = 1 / self.outl[0]["E_T"]
|
|
157
|
+
A[counter + chem_rows + 2, self.outl[0]["CostVar_index"]["M"]] = -1 / self.outl[0]["E_M"]
|
|
151
158
|
elif (self.outl[0]["e_T"] == 0) and (self.outl[0]["e_M"] == 0):
|
|
152
|
-
A[counter+chem_rows+2, self.outl[0]["CostVar_index"]["T"]] = 1
|
|
153
|
-
A[counter+chem_rows+2, self.outl[0]["CostVar_index"]["M"]] = -1
|
|
159
|
+
A[counter + chem_rows + 2, self.outl[0]["CostVar_index"]["T"]] = 1
|
|
160
|
+
A[counter + chem_rows + 2, self.outl[0]["CostVar_index"]["M"]] = -1
|
|
154
161
|
elif self.outl[0]["e_T"] == 0:
|
|
155
|
-
A[counter+chem_rows+2, self.outl[0]["CostVar_index"]["T"]] = 1
|
|
162
|
+
A[counter + chem_rows + 2, self.outl[0]["CostVar_index"]["T"]] = 1
|
|
156
163
|
else:
|
|
157
|
-
A[counter+chem_rows+2, self.outl[0]["CostVar_index"]["M"]] = -1
|
|
158
|
-
equations[counter+chem_rows+2] =
|
|
164
|
+
A[counter + chem_rows + 2, self.outl[0]["CostVar_index"]["M"]] = -1
|
|
165
|
+
equations[counter + chem_rows + 2] = {
|
|
166
|
+
"kind": "aux_equality",
|
|
167
|
+
"objects": [self.name, self.outl[0]["name"]],
|
|
168
|
+
"property": "c_T, c_M",
|
|
169
|
+
}
|
|
159
170
|
|
|
160
171
|
# Set the right-hand side entries to zero for all added rows.
|
|
161
172
|
for i in range(chem_rows + 3):
|