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,26 +2,17 @@ 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
|
|
10
9
|
class SimpleHeatExchanger(Component):
|
|
11
10
|
r"""
|
|
12
|
-
Class for exergy analysis of simple heat exchangers.
|
|
11
|
+
Class for exergy and exergoeconomic analysis of simple heat exchangers.
|
|
13
12
|
|
|
14
|
-
This class performs exergy analysis calculations for
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
ambient temperature.
|
|
18
|
-
|
|
19
|
-
Parameters
|
|
20
|
-
----------
|
|
21
|
-
**kwargs : dict
|
|
22
|
-
Arbitrary keyword arguments passed to parent class.
|
|
23
|
-
Optional parameter 'dissipative' (bool) to indicate if the component
|
|
24
|
-
is considered fully dissipative.
|
|
13
|
+
This class performs exergy and exergoeconomic analysis calculations for heat exchanger components,
|
|
14
|
+
accounting for one inlet and one outlet stream across various temperature regimes, including
|
|
15
|
+
above and below ambient temperature, and optional dissipative behavior.
|
|
25
16
|
|
|
26
17
|
Attributes
|
|
27
18
|
----------
|
|
@@ -34,119 +25,263 @@ class SimpleHeatExchanger(Component):
|
|
|
34
25
|
epsilon : float
|
|
35
26
|
Exergetic efficiency of the component :math:`\varepsilon` in :math:`-`.
|
|
36
27
|
inl : dict
|
|
37
|
-
Dictionary containing inlet stream data with
|
|
38
|
-
enthalpies, and specific exergies.
|
|
28
|
+
Dictionary containing inlet stream data with mass flows and specific exergies.
|
|
39
29
|
outl : dict
|
|
40
|
-
Dictionary containing outlet stream data with
|
|
41
|
-
|
|
30
|
+
Dictionary containing outlet stream data with mass flows and specific exergies.
|
|
31
|
+
Z_costs : float
|
|
32
|
+
Investment cost rate of the component in currency/h.
|
|
33
|
+
C_P : float
|
|
34
|
+
Cost of product stream :math:`\dot{C}_P` in currency/h.
|
|
35
|
+
C_F : float
|
|
36
|
+
Cost of fuel stream :math:`\dot{C}_F` in currency/h.
|
|
37
|
+
C_D : float
|
|
38
|
+
Cost of exergy destruction :math:`\dot{C}_D` in currency/h.
|
|
39
|
+
c_P : float
|
|
40
|
+
Specific cost of product stream (currency per unit exergy).
|
|
41
|
+
c_F : float
|
|
42
|
+
Specific cost of fuel stream (currency per unit exergy).
|
|
43
|
+
r : float
|
|
44
|
+
Relative cost difference, :math:`(c_P - c_F)/c_F`.
|
|
45
|
+
f : float
|
|
46
|
+
Exergoeconomic factor, :math:`\dot{Z}/(\dot{Z} + \dot{C}_D)`.
|
|
47
|
+
Ex_C_col : dict
|
|
48
|
+
Custom cost coefficients collection passed via `kwargs`.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
def __init__(self, **kwargs):
|
|
52
|
+
r"""
|
|
53
|
+
Initialize the heat exchanger component.
|
|
54
|
+
|
|
55
|
+
Parameters
|
|
56
|
+
----------
|
|
57
|
+
**kwargs : dict
|
|
58
|
+
Arbitrary keyword arguments. Recognized keys:
|
|
59
|
+
- dissipative (bool): whether component has dissipative behavior, default False
|
|
60
|
+
- Ex_C_col (dict): custom cost coefficients, default {}
|
|
61
|
+
- Z_costs (float): investment cost rate in currency/h, default 0.0
|
|
62
|
+
"""
|
|
63
|
+
super().__init__(**kwargs)
|
|
42
64
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
and temperatures relative to ambient temperature :math:`T_0`:
|
|
65
|
+
def calc_exergy_balance(self, T0: float, p0: float, split_physical_exergy) -> None:
|
|
66
|
+
r"""
|
|
67
|
+
Compute the exergy balance of the simple heat exchanger.
|
|
47
68
|
|
|
48
|
-
|
|
69
|
+
**Heat release** :math:\dot{Q}<0
|
|
49
70
|
|
|
50
|
-
|
|
71
|
+
Case 1: Both streams above ambient temperature
|
|
51
72
|
|
|
52
|
-
|
|
53
|
-
\dot{E}_\mathrm{P} &= \dot{m} \cdot (e^\mathrm{T}_\mathrm{in} -
|
|
54
|
-
e^\mathrm{T}_\mathrm{out})\\
|
|
55
|
-
\dot{E}_\mathrm{F} &= \dot{m} \cdot (e^\mathrm{PH}_\mathrm{in} -
|
|
56
|
-
e^\mathrm{PH}_\mathrm{out})
|
|
73
|
+
If split_physical_exergy=True:
|
|
57
74
|
|
|
58
|
-
|
|
75
|
+
.. math::
|
|
59
76
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
\dot{m}_\mathrm{out} \cdot e^\mathrm{T}_\mathrm{out} +
|
|
64
|
-
(\dot{m}_\mathrm{in} \cdot e^\mathrm{M}_\mathrm{in} -
|
|
65
|
-
\dot{m}_\mathrm{out} \cdot e^\mathrm{M}_\mathrm{out})
|
|
77
|
+
\dot{E}_{\mathrm{P}}
|
|
78
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
79
|
+
- \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
66
80
|
|
|
67
|
-
|
|
81
|
+
.. math::
|
|
68
82
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
\dot{E}_\mathrm{F} &= \dot{E}_\mathrm{P} + \dot{m}_\mathrm{in} \cdot
|
|
73
|
-
(e^\mathrm{M}_\mathrm{in} - e^\mathrm{M}_\mathrm{out})
|
|
83
|
+
\dot{E}_{\mathrm{F}}
|
|
84
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
85
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
74
86
|
|
|
75
|
-
|
|
87
|
+
Else:
|
|
76
88
|
|
|
77
|
-
|
|
89
|
+
.. math::
|
|
78
90
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
\dot{E}_\mathrm{F} &= \dot{m}_\mathrm{out} \cdot
|
|
83
|
-
(e^\mathrm{T}_\mathrm{out} - e^\mathrm{T}_\mathrm{in})
|
|
91
|
+
\dot{E}_{\mathrm{P}}
|
|
92
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
93
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
84
94
|
|
|
85
|
-
|
|
95
|
+
.. math::
|
|
86
96
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
\dot{E}_\mathrm{F} &= \dot{m}_\mathrm{in} \cdot e^\mathrm{T}_\mathrm{in} +
|
|
91
|
-
(\dot{m}_\mathrm{in} \cdot e^\mathrm{M}_\mathrm{in} -
|
|
92
|
-
\dot{m}_\mathrm{out} \cdot e^\mathrm{M}_\mathrm{out})
|
|
97
|
+
\dot{E}_{\mathrm{F}}
|
|
98
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
99
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
93
100
|
|
|
94
|
-
|
|
101
|
+
Case 2: Inlet above and outlet below ambient temperature
|
|
95
102
|
|
|
96
|
-
|
|
97
|
-
\dot{E}_\mathrm{P} &= \dot{m}_\mathrm{in} \cdot
|
|
98
|
-
(e^\mathrm{T}_\mathrm{in} - e^\mathrm{T}_\mathrm{out}) +
|
|
99
|
-
(\dot{m}_\mathrm{out} \cdot e^\mathrm{M}_\mathrm{out} -
|
|
100
|
-
\dot{m}_\mathrm{in} \cdot e^\mathrm{M}_\mathrm{in})\\
|
|
101
|
-
\dot{E}_\mathrm{F} &= \dot{m}_\mathrm{in} \cdot
|
|
102
|
-
(e^\mathrm{T}_\mathrm{in} - e^\mathrm{T}_\mathrm{out})
|
|
103
|
+
If split_physical_exergy=True:
|
|
103
104
|
|
|
104
|
-
|
|
105
|
+
.. math::
|
|
105
106
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
\dot{E}_\mathrm{F} &= \dot{m}_\mathrm{in} \cdot
|
|
109
|
-
(e^\mathrm{PH}_\mathrm{in} - e^\mathrm{PH}_\mathrm{out})
|
|
107
|
+
\dot{E}_{\mathrm{P}}
|
|
108
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
110
109
|
|
|
111
|
-
|
|
110
|
+
.. math::
|
|
112
111
|
|
|
113
|
-
|
|
114
|
-
|
|
112
|
+
\dot{E}_{\mathrm{F}}
|
|
113
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
114
|
+
+ \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
115
|
+
+ \bigl(\dot{E}^{\mathrm{M}}_{\mathrm{in}}
|
|
116
|
+
- \dot{E}^{\mathrm{M}}_{\mathrm{out}}\bigr)
|
|
115
117
|
|
|
116
|
-
|
|
117
|
-
- :math:`e^\mathrm{T}`: Thermal exergy
|
|
118
|
-
- :math:`e^\mathrm{PH}`: Physical exergy
|
|
119
|
-
- :math:`e^\mathrm{M}`: Mechanical exergy
|
|
120
|
-
"""
|
|
118
|
+
Else:
|
|
121
119
|
|
|
122
|
-
|
|
123
|
-
r"""Initialize simple heat exchanger component with given parameters."""
|
|
124
|
-
super().__init__(**kwargs)
|
|
120
|
+
.. math::
|
|
125
121
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
122
|
+
\dot{E}_{\mathrm{P}}
|
|
123
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
124
|
+
|
|
125
|
+
.. math::
|
|
126
|
+
|
|
127
|
+
\dot{E}_{\mathrm{F}}
|
|
128
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
129
|
+
|
|
130
|
+
Case 3: Both streams below ambient temperature
|
|
131
|
+
|
|
132
|
+
If split_physical_exergy=True:
|
|
133
|
+
|
|
134
|
+
.. math::
|
|
135
|
+
|
|
136
|
+
\dot{E}_{\mathrm{P}}
|
|
137
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
138
|
+
- \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
139
|
+
|
|
140
|
+
.. math::
|
|
141
|
+
|
|
142
|
+
\dot{E}_{\mathrm{F}}
|
|
143
|
+
= \bigl(\dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
144
|
+
- \dot{E}^{\mathrm{T}}_{\mathrm{in}}\bigr)
|
|
145
|
+
+ \bigl(\dot{E}^{\mathrm{M}}_{\mathrm{in}}
|
|
146
|
+
- \dot{E}^{\mathrm{M}}_{\mathrm{out}}\bigr)
|
|
147
|
+
|
|
148
|
+
Else:
|
|
149
|
+
|
|
150
|
+
.. math::
|
|
151
|
+
|
|
152
|
+
\dot{E}_{\mathrm{P}}
|
|
153
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
154
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
155
|
+
|
|
156
|
+
.. math::
|
|
157
|
+
|
|
158
|
+
\dot{E}_{\mathrm{F}}
|
|
159
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
160
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
161
|
+
|
|
162
|
+
**Heat injection** :math:\dot{Q}>0
|
|
163
|
+
|
|
164
|
+
Case 1: Both streams above ambient temperature
|
|
165
|
+
|
|
166
|
+
If split_physical_exergy=True:
|
|
167
|
+
|
|
168
|
+
.. math::
|
|
169
|
+
|
|
170
|
+
\dot{E}_{\mathrm{P}}
|
|
171
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
172
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
173
|
+
|
|
174
|
+
.. math::
|
|
175
|
+
|
|
176
|
+
\dot{E}_{\mathrm{F}}
|
|
177
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
178
|
+
- \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
179
|
+
|
|
180
|
+
Else:
|
|
129
181
|
|
|
130
|
-
|
|
131
|
-
|
|
182
|
+
.. math::
|
|
183
|
+
|
|
184
|
+
\dot{E}_{\mathrm{P}}
|
|
185
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
186
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
187
|
+
|
|
188
|
+
.. math::
|
|
189
|
+
|
|
190
|
+
\dot{E}_{\mathrm{F}}
|
|
191
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
192
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
193
|
+
|
|
194
|
+
Case 2: Inlet below and outlet above ambient temperature
|
|
195
|
+
|
|
196
|
+
If split_physical_exergy=True:
|
|
197
|
+
|
|
198
|
+
.. math::
|
|
199
|
+
|
|
200
|
+
\dot{E}_{\mathrm{P}}
|
|
201
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
202
|
+
+ \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
203
|
+
|
|
204
|
+
.. math::
|
|
205
|
+
|
|
206
|
+
\dot{E}_{\mathrm{F}}
|
|
207
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
208
|
+
+ \bigl(\dot{E}^{\mathrm{M}}_{\mathrm{in}}
|
|
209
|
+
- \dot{E}^{\mathrm{M}}_{\mathrm{out}}\bigr)
|
|
210
|
+
|
|
211
|
+
Else:
|
|
212
|
+
|
|
213
|
+
.. math::
|
|
214
|
+
|
|
215
|
+
\dot{E}_{\mathrm{P}}
|
|
216
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
217
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
218
|
+
|
|
219
|
+
.. math::
|
|
220
|
+
|
|
221
|
+
\dot{E}_{\mathrm{F}}
|
|
222
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
223
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
224
|
+
|
|
225
|
+
Case 3: Both streams below ambient temperature
|
|
226
|
+
|
|
227
|
+
If split_physical_exergy=True:
|
|
228
|
+
|
|
229
|
+
.. math::
|
|
230
|
+
|
|
231
|
+
\dot{E}_{\mathrm{P}}
|
|
232
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
233
|
+
- \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
234
|
+
+ \bigl(\dot{E}^{\mathrm{M}}_{\mathrm{out}}
|
|
235
|
+
- \dot{E}^{\mathrm{M}}_{\mathrm{in}}\bigr)
|
|
236
|
+
|
|
237
|
+
.. math::
|
|
238
|
+
|
|
239
|
+
\dot{E}_{\mathrm{F}}
|
|
240
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
241
|
+
- \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
242
|
+
|
|
243
|
+
Else:
|
|
244
|
+
|
|
245
|
+
.. math::
|
|
246
|
+
|
|
247
|
+
\dot{E}_{\mathrm{P}}
|
|
248
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
249
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
250
|
+
|
|
251
|
+
.. math::
|
|
252
|
+
|
|
253
|
+
\dot{E}_{\mathrm{F}}
|
|
254
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
255
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
256
|
+
|
|
257
|
+
Fully dissipative or :math:\dot{Q}=0
|
|
258
|
+
|
|
259
|
+
.. math::
|
|
260
|
+
|
|
261
|
+
\dot{E}_{\mathrm{P}} = \mathrm{NaN}
|
|
262
|
+
|
|
263
|
+
.. math::
|
|
264
|
+
|
|
265
|
+
\dot{E}_{\mathrm{F}}
|
|
266
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
267
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
132
268
|
|
|
133
269
|
Parameters
|
|
134
270
|
----------
|
|
135
271
|
T0 : float
|
|
136
|
-
Ambient temperature
|
|
272
|
+
Ambient temperature (K).
|
|
137
273
|
p0 : float
|
|
138
|
-
Ambient pressure
|
|
274
|
+
Ambient pressure (Pa).
|
|
139
275
|
split_physical_exergy : bool
|
|
140
|
-
|
|
276
|
+
Whether to split thermal and mechanical exergy.
|
|
141
277
|
|
|
142
278
|
Raises
|
|
143
279
|
------
|
|
144
280
|
ValueError
|
|
145
|
-
If
|
|
146
|
-
|
|
147
|
-
"""
|
|
281
|
+
If required inlet or outlet are missing.
|
|
282
|
+
"""
|
|
148
283
|
# Validate the number of inlets and outlets
|
|
149
|
-
if not hasattr(self,
|
|
284
|
+
if not hasattr(self, "inl") or not hasattr(self, "outl") or len(self.inl) < 1 or len(self.outl) < 1:
|
|
150
285
|
msg = "SimpleHeatExchanger requires at least one inlet and one outlet as well as one heat flow."
|
|
151
286
|
logging.error(msg)
|
|
152
287
|
raise ValueError(msg)
|
|
@@ -160,7 +295,7 @@ class SimpleHeatExchanger(Component):
|
|
|
160
295
|
outlet = self.outl[0]
|
|
161
296
|
|
|
162
297
|
# Calculate heat transfer Q
|
|
163
|
-
Q = outlet[
|
|
298
|
+
Q = outlet["m"] * outlet["h"] - inlet["m"] * inlet["h"]
|
|
164
299
|
|
|
165
300
|
# Initialize E_P and E_F
|
|
166
301
|
self.E_P = 0.0
|
|
@@ -168,78 +303,87 @@ class SimpleHeatExchanger(Component):
|
|
|
168
303
|
|
|
169
304
|
# Case 1: Heat is released (Q < 0)
|
|
170
305
|
if Q < 0:
|
|
171
|
-
if inlet[
|
|
306
|
+
if inlet["T"] >= T0 and outlet["T"] >= T0:
|
|
172
307
|
if split_physical_exergy:
|
|
173
|
-
self.E_P =
|
|
308
|
+
self.E_P = (
|
|
309
|
+
np.nan if getattr(self, "dissipative", False) else inlet["m"] * (inlet["e_T"] - outlet["e_T"])
|
|
310
|
+
)
|
|
174
311
|
else:
|
|
175
|
-
self.E_P =
|
|
176
|
-
|
|
312
|
+
self.E_P = (
|
|
313
|
+
np.nan if getattr(self, "dissipative", False) else inlet["m"] * (inlet["e_PH"] - outlet["e_PH"])
|
|
314
|
+
)
|
|
315
|
+
self.E_F = inlet["m"] * (inlet["e_PH"] - outlet["e_PH"])
|
|
177
316
|
|
|
178
|
-
elif inlet[
|
|
317
|
+
elif inlet["T"] >= T0 and outlet["T"] < T0:
|
|
179
318
|
if split_physical_exergy:
|
|
180
|
-
self.E_P = outlet[
|
|
181
|
-
self.E_F = (
|
|
182
|
-
|
|
319
|
+
self.E_P = outlet["m"] * outlet["e_T"]
|
|
320
|
+
self.E_F = (
|
|
321
|
+
inlet["m"] * inlet["e_T"]
|
|
322
|
+
+ outlet["m"] * outlet["e_T"]
|
|
323
|
+
+ (inlet["m"] * inlet["e_M"] - outlet["m"] * outlet["e_M"])
|
|
324
|
+
)
|
|
183
325
|
else:
|
|
184
|
-
self.E_P = outlet[
|
|
185
|
-
self.E_F = inlet[
|
|
326
|
+
self.E_P = outlet["m"] * outlet["e_PH"]
|
|
327
|
+
self.E_F = inlet["m"] * inlet["e_PH"]
|
|
186
328
|
|
|
187
|
-
elif inlet[
|
|
329
|
+
elif inlet["T"] <= T0 and outlet["T"] < T0:
|
|
188
330
|
if split_physical_exergy:
|
|
189
|
-
self.E_P = outlet[
|
|
190
|
-
self.E_F = self.E_P + inlet[
|
|
331
|
+
self.E_P = outlet["m"] * (outlet["e_T"] - inlet["e_T"])
|
|
332
|
+
self.E_F = self.E_P + inlet["m"] * (inlet["e_M"] - outlet["m"] * outlet["e_M"])
|
|
191
333
|
else:
|
|
192
|
-
self.E_P =
|
|
193
|
-
|
|
194
|
-
|
|
334
|
+
self.E_P = (
|
|
335
|
+
np.nan
|
|
336
|
+
if getattr(self, "dissipative", False)
|
|
337
|
+
else outlet["m"] * (outlet["e_PH"] - inlet["e_PH"])
|
|
338
|
+
)
|
|
339
|
+
self.E_F = outlet["m"] * (outlet["e_PH"] - inlet["e_PH"])
|
|
195
340
|
|
|
196
341
|
else:
|
|
197
342
|
# Unimplemented corner case
|
|
198
|
-
logging.warning(
|
|
199
|
-
"SimpleHeatExchanger: unimplemented case (Q < 0, T_in < T0 < T_out?)."
|
|
200
|
-
)
|
|
343
|
+
logging.warning("SimpleHeatExchanger: unimplemented case (Q < 0, T_in < T0 < T_out?).")
|
|
201
344
|
self.E_P = np.nan
|
|
202
345
|
self.E_F = np.nan
|
|
203
346
|
|
|
204
347
|
# Case 2: Heat is added (Q > 0)
|
|
205
348
|
elif Q > 0:
|
|
206
|
-
if inlet[
|
|
349
|
+
if inlet["T"] >= T0 and outlet["T"] >= T0:
|
|
207
350
|
if split_physical_exergy:
|
|
208
|
-
self.E_P = outlet[
|
|
209
|
-
self.E_F = outlet[
|
|
351
|
+
self.E_P = outlet["m"] * (outlet["e_PH"] - inlet["e_PH"])
|
|
352
|
+
self.E_F = outlet["m"] * (outlet["e_T"] - inlet["e_T"])
|
|
210
353
|
else:
|
|
211
|
-
self.E_P = outlet[
|
|
212
|
-
self.E_F = outlet[
|
|
213
|
-
elif inlet[
|
|
354
|
+
self.E_P = outlet["m"] * (outlet["e_PH"] - inlet["e_PH"])
|
|
355
|
+
self.E_F = outlet["m"] * (outlet["e_PH"] - inlet["e_PH"])
|
|
356
|
+
elif inlet["T"] < T0 and outlet["T"] >= T0:
|
|
214
357
|
if split_physical_exergy:
|
|
215
|
-
self.E_P = outlet[
|
|
216
|
-
self.E_F =
|
|
217
|
-
(inlet['m'] * inlet['e_M'] - outlet['m'] * outlet['e_M']))
|
|
358
|
+
self.E_P = outlet["m"] * (outlet["e_T"] + inlet["e_T"])
|
|
359
|
+
self.E_F = inlet["m"] * inlet["e_T"] + (inlet["m"] * inlet["e_M"] - outlet["m"] * outlet["e_M"])
|
|
218
360
|
else:
|
|
219
|
-
self.E_P = outlet[
|
|
220
|
-
self.E_F = outlet[
|
|
361
|
+
self.E_P = outlet["m"] * (outlet["e_PH"] - inlet["e_PH"])
|
|
362
|
+
self.E_F = outlet["m"] * (outlet["e_PH"] - inlet["e_PH"])
|
|
221
363
|
|
|
222
|
-
elif inlet[
|
|
364
|
+
elif inlet["T"] < T0 and outlet["T"] <= T0:
|
|
223
365
|
if split_physical_exergy:
|
|
224
|
-
self.E_P =
|
|
225
|
-
|
|
226
|
-
(
|
|
227
|
-
|
|
366
|
+
self.E_P = (
|
|
367
|
+
np.nan
|
|
368
|
+
if getattr(self, "dissipative", False)
|
|
369
|
+
else inlet["m"] * (inlet["e_T"] - outlet["e_T"])
|
|
370
|
+
+ (outlet["m"] * outlet["e_M"] - inlet["m"] * inlet["e_M"])
|
|
371
|
+
)
|
|
372
|
+
self.E_F = inlet["m"] * (inlet["e_T"] - outlet["e_T"])
|
|
228
373
|
else:
|
|
229
|
-
self.E_P =
|
|
230
|
-
inlet[
|
|
231
|
-
|
|
374
|
+
self.E_P = (
|
|
375
|
+
np.nan if getattr(self, "dissipative", False) else inlet["m"] * (inlet["e_PH"] - outlet["e_PH"])
|
|
376
|
+
)
|
|
377
|
+
self.E_F = inlet["m"] * (inlet["e_PH"] - outlet["e_PH"])
|
|
232
378
|
else:
|
|
233
|
-
logging.warning(
|
|
234
|
-
"SimpleHeatExchanger: unimplemented case (Q > 0, T_in > T0 > T_out?)."
|
|
235
|
-
)
|
|
379
|
+
logging.warning("SimpleHeatExchanger: unimplemented case (Q > 0, T_in > T0 > T_out?).")
|
|
236
380
|
self.E_P = np.nan
|
|
237
381
|
self.E_F = np.nan
|
|
238
382
|
|
|
239
383
|
# Case 3: Fully dissipative or Q == 0
|
|
240
384
|
else:
|
|
241
385
|
self.E_P = np.nan
|
|
242
|
-
self.E_F = inlet[
|
|
386
|
+
self.E_F = inlet["m"] * (inlet["e_PH"] - outlet["e_PH"])
|
|
243
387
|
|
|
244
388
|
# Calculate exergy destruction
|
|
245
389
|
if np.isnan(self.E_P):
|
|
@@ -252,107 +396,313 @@ class SimpleHeatExchanger(Component):
|
|
|
252
396
|
|
|
253
397
|
# Log the results
|
|
254
398
|
logging.info(
|
|
255
|
-
f"SimpleHeatExchanger
|
|
399
|
+
f"Exergy balance of SimpleHeatExchanger {self.name} calculated: "
|
|
256
400
|
f"E_P={self.E_P:.2f}, E_F={self.E_F:.2f}, E_D={self.E_D:.2f}, "
|
|
257
401
|
f"Efficiency={self.epsilon:.2%}"
|
|
258
402
|
)
|
|
259
403
|
|
|
260
|
-
|
|
261
404
|
def aux_eqs(self, A, b, counter, T0, equations, chemical_exergy_enabled):
|
|
405
|
+
r"""
|
|
406
|
+
This function must be implemented in the future.
|
|
407
|
+
|
|
408
|
+
The exergoeconomic analysis of SimpleHeatExchanger is not implemented yet.
|
|
262
409
|
"""
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
410
|
+
|
|
411
|
+
# Extract inlet and outlet
|
|
412
|
+
inlet = self.inl[0]
|
|
413
|
+
outlet = self.outl[0]
|
|
414
|
+
|
|
415
|
+
# Calculate heat transfer Q
|
|
416
|
+
Q = outlet["m"] * outlet["h"] - inlet["m"] * inlet["h"]
|
|
417
|
+
|
|
418
|
+
# Extract temperatures
|
|
419
|
+
T_in = inlet["T"]
|
|
420
|
+
T_out = outlet["T"]
|
|
421
|
+
|
|
422
|
+
# Equality equation for mechanical exergy costs (c_M,in = c_M,out)
|
|
423
|
+
A[counter, inlet["CostVar_index"]["M"]] = 1 / inlet["E_M"] if inlet["e_M"] != 0 else 1
|
|
424
|
+
A[counter, outlet["CostVar_index"]["M"]] = -1 / outlet["E_M"] if outlet["e_M"] != 0 else -1
|
|
425
|
+
equations[counter] = {
|
|
426
|
+
"kind": "aux_equality",
|
|
427
|
+
"objects": [self.name, inlet["name"], outlet["name"]],
|
|
428
|
+
"property": "c_M",
|
|
429
|
+
}
|
|
430
|
+
b[counter] = 0
|
|
431
|
+
counter += 1
|
|
432
|
+
|
|
433
|
+
# Equality equation for chemical exergy costs (c_CH,in = c_CH,out)
|
|
434
|
+
if chemical_exergy_enabled:
|
|
435
|
+
A[counter, inlet["CostVar_index"]["CH"]] = 1 / inlet["E_CH"] if inlet["e_CH"] != 0 else 1
|
|
436
|
+
A[counter, outlet["CostVar_index"]["CH"]] = -1 / outlet["E_CH"] if outlet["e_CH"] != 0 else -1
|
|
437
|
+
equations[counter] = {
|
|
438
|
+
"kind": "aux_equality",
|
|
439
|
+
"objects": [self.name, inlet["name"], outlet["name"]],
|
|
440
|
+
"property": "c_CH",
|
|
441
|
+
}
|
|
442
|
+
b[counter] = 0
|
|
443
|
+
counter += 1
|
|
444
|
+
|
|
445
|
+
# Thermal exergy cost equations
|
|
446
|
+
|
|
447
|
+
# Case 1: Heat is released (Q < 0)
|
|
448
|
+
if Q < 0:
|
|
449
|
+
# Case 1.1: Both streams above ambient temperature
|
|
450
|
+
if T_in >= T0 and T_out >= T0:
|
|
451
|
+
# Apply F-rule to thermal exergy (c_T,in = c_T,out)
|
|
452
|
+
A[counter, inlet["CostVar_index"]["T"]] = 1 / inlet["E_T"] if inlet["e_T"] != 0 else 1
|
|
453
|
+
A[counter, outlet["CostVar_index"]["T"]] = -1 / outlet["E_T"] if outlet["e_T"] != 0 else -1
|
|
454
|
+
equations[counter] = {
|
|
455
|
+
"kind": "aux_f_rule",
|
|
456
|
+
"objects": [self.name, inlet["name"], outlet["name"]],
|
|
457
|
+
"property": "c_T",
|
|
458
|
+
}
|
|
459
|
+
b[counter] = 0
|
|
460
|
+
counter += 1
|
|
461
|
+
|
|
462
|
+
elif T_in >= T0 and T_out < T0:
|
|
463
|
+
# Tricky case: inlet above T0, outlet below T0
|
|
464
|
+
logging.warning(
|
|
465
|
+
f"SimpleHeatExchanger '{self.name}': Stream crossing ambient temperature "
|
|
466
|
+
f"during heat release not implemented in exergoeconomics yet!"
|
|
467
|
+
)
|
|
468
|
+
|
|
469
|
+
else:
|
|
470
|
+
# Tricky case: both streams below T0 while heat is released
|
|
471
|
+
logging.warning(
|
|
472
|
+
f"SimpleHeatExchanger '{self.name}': Both streams below T0 during heat release "
|
|
473
|
+
f"not implemented in exergoeconomics yet!"
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
# Case 2: Heat is added (Q > 0)
|
|
477
|
+
elif Q > 0:
|
|
478
|
+
# Case 2.1: Both streams below ambient temperature
|
|
479
|
+
if T_in < T0 and T_out < T0:
|
|
480
|
+
# No auxiliary equation needed for thermal exergy
|
|
481
|
+
# The cost balance will determine c_T,out based on c_T,in and c_heat
|
|
482
|
+
pass
|
|
483
|
+
|
|
484
|
+
elif T_in < T0 and T_out >= T0:
|
|
485
|
+
# Tricky case: inlet below T0, outlet above T0
|
|
486
|
+
logging.warning(
|
|
487
|
+
f"SimpleHeatExchanger '{self.name}': Stream crossing ambient temperature "
|
|
488
|
+
f"during heat absorption not implemented in exergoeconomics yet!"
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
# Case 2.2: Both streams above ambient temperature
|
|
492
|
+
elif T_in >= T0 and T_out >= T0:
|
|
493
|
+
# No auxiliary equation needed for thermal exergy
|
|
494
|
+
# The cost balance will determine c_T,out based on c_T,in and c_heat
|
|
495
|
+
pass
|
|
496
|
+
|
|
497
|
+
return A, b, counter, equations
|
|
498
|
+
|
|
499
|
+
def exergoeconomic_balance(self, T0, chemical_exergy_enabled=False):
|
|
500
|
+
r"""
|
|
501
|
+
Perform exergoeconomic cost balance for the simple heat exchanger.
|
|
502
|
+
|
|
503
|
+
The general exergoeconomic balance equation is:
|
|
504
|
+
|
|
505
|
+
.. math::
|
|
506
|
+
\dot{C}^{\mathrm{T}}_{\mathrm{in}}
|
|
507
|
+
+ \dot{C}^{\mathrm{M}}_{\mathrm{in}}
|
|
508
|
+
- \dot{C}^{\mathrm{T}}_{\mathrm{out}}
|
|
509
|
+
- \dot{C}^{\mathrm{M}}_{\mathrm{out}}
|
|
510
|
+
+ \dot{Z}
|
|
511
|
+
= 0
|
|
512
|
+
|
|
513
|
+
In case the chemical exergy of the streams is known:
|
|
514
|
+
|
|
515
|
+
.. math::
|
|
516
|
+
\dot{C}^{\mathrm{CH}}_{\mathrm{in}} =
|
|
517
|
+
\dot{C}^{\mathrm{CH}}_{\mathrm{out}}
|
|
518
|
+
|
|
519
|
+
This method computes cost rates for product and fuel, and derives
|
|
520
|
+
exergoeconomic indicators based on the operating conditions.
|
|
521
|
+
|
|
522
|
+
**Heat release** (:math:`\dot{Q} < 0`)
|
|
523
|
+
|
|
524
|
+
Case 1: Both streams above ambient temperature
|
|
525
|
+
|
|
526
|
+
.. math::
|
|
527
|
+
\dot{E}_{\mathrm{P}}
|
|
528
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
529
|
+
- \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
530
|
+
|
|
531
|
+
.. math::
|
|
532
|
+
\dot{E}_{\mathrm{F}}
|
|
533
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
534
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
535
|
+
|
|
536
|
+
Case 2: Inlet above and outlet below ambient temperature
|
|
537
|
+
|
|
538
|
+
.. math::
|
|
539
|
+
\dot{E}_{\mathrm{P}}
|
|
540
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
541
|
+
|
|
542
|
+
.. math::
|
|
543
|
+
\dot{E}_{\mathrm{F}}
|
|
544
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
545
|
+
+ \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
546
|
+
+ \bigl(\dot{E}^{\mathrm{M}}_{\mathrm{in}}
|
|
547
|
+
- \dot{E}^{\mathrm{M}}_{\mathrm{out}}\bigr)
|
|
548
|
+
|
|
549
|
+
Case 3: Both streams below ambient temperature
|
|
550
|
+
|
|
551
|
+
.. math::
|
|
552
|
+
\dot{E}_{\mathrm{P}}
|
|
553
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
554
|
+
- \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
555
|
+
|
|
556
|
+
.. math::
|
|
557
|
+
\dot{E}_{\mathrm{F}}
|
|
558
|
+
= \bigl(\dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
559
|
+
- \dot{E}^{\mathrm{T}}_{\mathrm{in}}\bigr)
|
|
560
|
+
+ \bigl(\dot{E}^{\mathrm{M}}_{\mathrm{in}}
|
|
561
|
+
- \dot{E}^{\mathrm{M}}_{\mathrm{out}}\bigr)
|
|
562
|
+
|
|
563
|
+
**Heat injection** (:math:`\dot{Q} > 0`)
|
|
564
|
+
|
|
565
|
+
Case 1: Both streams above ambient temperature
|
|
566
|
+
|
|
567
|
+
.. math::
|
|
568
|
+
\dot{E}_{\mathrm{P}}
|
|
569
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
570
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
571
|
+
|
|
572
|
+
.. math::
|
|
573
|
+
\dot{E}_{\mathrm{F}}
|
|
574
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
575
|
+
- \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
576
|
+
|
|
577
|
+
Case 2: Inlet below and outlet above ambient temperature
|
|
578
|
+
|
|
579
|
+
.. math::
|
|
580
|
+
\dot{E}_{\mathrm{P}}
|
|
581
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
582
|
+
+ \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
583
|
+
|
|
584
|
+
.. math::
|
|
585
|
+
\dot{E}_{\mathrm{F}}
|
|
586
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
587
|
+
+ \bigl(\dot{E}^{\mathrm{M}}_{\mathrm{in}}
|
|
588
|
+
- \dot{E}^{\mathrm{M}}_{\mathrm{out}}\bigr)
|
|
589
|
+
|
|
590
|
+
Case 3: Both streams below ambient temperature
|
|
591
|
+
|
|
592
|
+
.. math::
|
|
593
|
+
\dot{E}_{\mathrm{P}}
|
|
594
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
595
|
+
- \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
596
|
+
+ \bigl(\dot{E}^{\mathrm{M}}_{\mathrm{out}}
|
|
597
|
+
- \dot{E}^{\mathrm{M}}_{\mathrm{in}}\bigr)
|
|
598
|
+
|
|
599
|
+
.. math::
|
|
600
|
+
\dot{E}_{\mathrm{F}}
|
|
601
|
+
= \dot{E}^{\mathrm{T}}_{\mathrm{in}}
|
|
602
|
+
- \dot{E}^{\mathrm{T}}_{\mathrm{out}}
|
|
603
|
+
|
|
604
|
+
**Fully dissipative or** :math:`\dot{Q} = 0`
|
|
605
|
+
|
|
606
|
+
.. math::
|
|
607
|
+
\dot{E}_{\mathrm{P}} = \mathrm{NaN}
|
|
608
|
+
|
|
609
|
+
.. math::
|
|
610
|
+
\dot{E}_{\mathrm{F}}
|
|
611
|
+
= \dot{E}^{\mathrm{PH}}_{\mathrm{in}}
|
|
612
|
+
- \dot{E}^{\mathrm{PH}}_{\mathrm{out}}
|
|
613
|
+
|
|
614
|
+
**Calculated exergoeconomic indicators:**
|
|
615
|
+
|
|
616
|
+
.. math::
|
|
617
|
+
c_{\mathrm{F}} = \frac{\dot{C}_{\mathrm{F}}}{\dot{E}_{\mathrm{F}}}
|
|
618
|
+
|
|
619
|
+
.. math::
|
|
620
|
+
c_{\mathrm{P}} = \frac{\dot{C}_{\mathrm{P}}}{\dot{E}_{\mathrm{P}}}
|
|
621
|
+
|
|
622
|
+
.. math::
|
|
623
|
+
\dot{C}_{\mathrm{D}} = c_{\mathrm{F}} \cdot \dot{E}_{\mathrm{D}}
|
|
624
|
+
|
|
625
|
+
.. math::
|
|
626
|
+
r = \frac{c_{\mathrm{P}} - c_{\mathrm{F}}}{c_{\mathrm{F}}}
|
|
627
|
+
|
|
628
|
+
.. math::
|
|
629
|
+
f = \frac{\dot{Z}}{\dot{Z} + \dot{C}_{\mathrm{D}}}
|
|
630
|
+
|
|
282
631
|
Parameters
|
|
283
632
|
----------
|
|
284
|
-
A : numpy.ndarray
|
|
285
|
-
The current cost matrix.
|
|
286
|
-
b : numpy.ndarray
|
|
287
|
-
The current right-hand-side vector.
|
|
288
|
-
counter : int
|
|
289
|
-
The current row index in the matrix.
|
|
290
633
|
T0 : float
|
|
291
|
-
Ambient temperature.
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
634
|
+
Ambient temperature (K).
|
|
635
|
+
chemical_exergy_enabled : bool, optional
|
|
636
|
+
If True, chemical exergy is considered in the calculations.
|
|
637
|
+
Default is False.
|
|
638
|
+
|
|
639
|
+
Attributes Set
|
|
640
|
+
--------------
|
|
641
|
+
C_P : float
|
|
642
|
+
Cost rate of product (currency/time).
|
|
643
|
+
C_F : float
|
|
644
|
+
Cost rate of fuel (currency/time).
|
|
645
|
+
c_P : float
|
|
646
|
+
Specific cost of product (currency/energy).
|
|
647
|
+
c_F : float
|
|
648
|
+
Specific cost of fuel (currency/energy).
|
|
649
|
+
C_D : float
|
|
650
|
+
Cost rate of exergy destruction (currency/time).
|
|
651
|
+
r : float
|
|
652
|
+
Relative cost difference (dimensionless).
|
|
653
|
+
f : float
|
|
654
|
+
Exergoeconomic factor (dimensionless).
|
|
307
655
|
"""
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
logging.warning("SimpleHeatExchanger: dET or dEM is zero; case not implemented.")
|
|
329
|
-
equations[counter] = "aux_unimpl_HEX"
|
|
656
|
+
inlet = self.inl[0]
|
|
657
|
+
outlet = self.outl[0]
|
|
658
|
+
|
|
659
|
+
# Determine heat transfer direction
|
|
660
|
+
Q = outlet["m"] * outlet["h"] - inlet["m"] * inlet["h"]
|
|
661
|
+
|
|
662
|
+
# Case 1: Heat is released (Q < 0)
|
|
663
|
+
if Q < 0:
|
|
664
|
+
if inlet["T"] >= T0 and outlet["T"] >= T0:
|
|
665
|
+
# Both streams above ambient
|
|
666
|
+
self.C_P = outlet["C_T"] - inlet["C_T"]
|
|
667
|
+
self.C_F = inlet["C_PH"] - outlet["C_PH"]
|
|
668
|
+
elif inlet["T"] >= T0 and outlet["T"] < T0:
|
|
669
|
+
# Inlet above, outlet below ambient
|
|
670
|
+
self.C_P = outlet["C_T"]
|
|
671
|
+
self.C_F = inlet["C_T"] + outlet["C_T"] + (inlet["C_M"] - outlet["C_M"])
|
|
672
|
+
elif inlet["T"] <= T0 and outlet["T"] < T0:
|
|
673
|
+
# Both streams below ambient
|
|
674
|
+
self.C_P = outlet["C_T"] - inlet["C_T"]
|
|
675
|
+
self.C_F = self.C_P + (inlet["C_M"] - outlet["C_M"])
|
|
330
676
|
else:
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
else:
|
|
334
|
-
logging.warning("SimpleHeatExchanger: Cases with T_in or T_out below T0 are not implemented.")
|
|
335
|
-
equations[counter] = "aux_unimpl_HEX"
|
|
336
|
-
b[counter] = 0
|
|
677
|
+
self.C_P = np.nan
|
|
678
|
+
self.C_F = np.nan
|
|
337
679
|
|
|
338
|
-
#
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
680
|
+
# Case 2: Heat is added (Q > 0)
|
|
681
|
+
elif Q > 0:
|
|
682
|
+
if inlet["T"] >= T0 and outlet["T"] >= T0:
|
|
683
|
+
# Both streams above ambient
|
|
684
|
+
self.C_P = outlet["C_PH"] - inlet["C_PH"]
|
|
685
|
+
self.C_F = outlet["C_T"] - inlet["C_T"]
|
|
686
|
+
elif inlet["T"] < T0 and outlet["T"] >= T0:
|
|
687
|
+
# Inlet below, outlet above ambient
|
|
688
|
+
self.C_P = outlet["C_T"] + inlet["C_T"]
|
|
689
|
+
self.C_F = inlet["C_T"] + (inlet["C_M"] - outlet["C_M"])
|
|
690
|
+
elif inlet["T"] < T0 and outlet["T"] <= T0:
|
|
691
|
+
# Both streams below ambient
|
|
692
|
+
self.C_P = inlet["C_T"] - outlet["C_T"] + (outlet["C_M"] - inlet["C_M"])
|
|
693
|
+
self.C_F = inlet["C_T"] - outlet["C_T"]
|
|
694
|
+
else:
|
|
695
|
+
self.C_P = np.nan
|
|
696
|
+
self.C_F = np.nan
|
|
345
697
|
|
|
346
|
-
#
|
|
347
|
-
if chemical_exergy_enabled:
|
|
348
|
-
A[counter+2, self.inl[0]["CostVar_index"]["CH"]] = (1 / self.inl[0]["e_CH"]
|
|
349
|
-
if self.inl[0]["e_CH"] != 0 else 1)
|
|
350
|
-
A[counter+2, self.outl[0]["CostVar_index"]["CH"]] = (-1 / self.outl[0]["e_CH"]
|
|
351
|
-
if self.outl[0]["e_CH"] != 0 else 1)
|
|
352
|
-
equations[counter+2] = f"aux_equality_chem_{self.outl[0]['name']}"
|
|
353
|
-
b[counter+2] = 0
|
|
354
|
-
counter += 3
|
|
698
|
+
# Case 3: Fully dissipative or Q == 0
|
|
355
699
|
else:
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
700
|
+
self.C_P = np.nan
|
|
701
|
+
self.C_F = inlet["C_PH"] - outlet["C_PH"]
|
|
702
|
+
|
|
703
|
+
# Calculate specific costs and exergoeconomic indicators
|
|
704
|
+
self.c_F = self.C_F / self.E_F if self.E_F else np.nan
|
|
705
|
+
self.c_P = self.C_P / self.E_P if self.E_P else np.nan
|
|
706
|
+
self.C_D = self.c_F * self.E_D if self.E_D else np.nan
|
|
707
|
+
self.r = (self.c_P - self.c_F) / self.c_F if self.c_F else np.nan
|
|
708
|
+
self.f = self.Z_costs / (self.Z_costs + self.C_D) if self.C_D else np.nan
|