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.
Files changed (39) hide show
  1. exerpy/__init__.py +2 -4
  2. exerpy/analyses.py +597 -297
  3. exerpy/components/__init__.py +3 -0
  4. exerpy/components/combustion/base.py +157 -114
  5. exerpy/components/component.py +8 -8
  6. exerpy/components/heat_exchanger/base.py +593 -256
  7. exerpy/components/heat_exchanger/condenser.py +353 -166
  8. exerpy/components/heat_exchanger/simple.py +575 -225
  9. exerpy/components/heat_exchanger/steam_generator.py +153 -123
  10. exerpy/components/helpers/cycle_closer.py +61 -34
  11. exerpy/components/helpers/power_bus.py +117 -0
  12. exerpy/components/nodes/deaerator.py +221 -102
  13. exerpy/components/nodes/drum.py +50 -39
  14. exerpy/components/nodes/flash_tank.py +218 -43
  15. exerpy/components/nodes/mixer.py +296 -115
  16. exerpy/components/nodes/splitter.py +173 -0
  17. exerpy/components/nodes/storage.py +130 -0
  18. exerpy/components/piping/valve.py +351 -139
  19. exerpy/components/power_machines/generator.py +105 -38
  20. exerpy/components/power_machines/motor.py +111 -39
  21. exerpy/components/turbomachinery/compressor.py +181 -63
  22. exerpy/components/turbomachinery/pump.py +182 -63
  23. exerpy/components/turbomachinery/turbine.py +182 -74
  24. exerpy/functions.py +388 -263
  25. exerpy/parser/from_aspen/aspen_config.py +57 -48
  26. exerpy/parser/from_aspen/aspen_parser.py +373 -280
  27. exerpy/parser/from_ebsilon/__init__.py +2 -2
  28. exerpy/parser/from_ebsilon/check_ebs_path.py +15 -19
  29. exerpy/parser/from_ebsilon/ebsilon_config.py +329 -227
  30. exerpy/parser/from_ebsilon/ebsilon_functions.py +205 -38
  31. exerpy/parser/from_ebsilon/ebsilon_parser.py +392 -255
  32. exerpy/parser/from_ebsilon/utils.py +16 -11
  33. exerpy/parser/from_tespy/tespy_config.py +32 -1
  34. exerpy/parser/from_tespy/tespy_parser.py +151 -0
  35. {exerpy-0.0.1.dist-info → exerpy-0.0.3.dist-info}/METADATA +45 -4
  36. exerpy-0.0.3.dist-info/RECORD +48 -0
  37. exerpy-0.0.1.dist-info/RECORD +0 -44
  38. {exerpy-0.0.1.dist-info → exerpy-0.0.3.dist-info}/WHEEL +0 -0
  39. {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 simple heat exchangers with
15
- one primary flow stream and heat transfer. The exergy product and fuel definitions
16
- vary based on the direction of heat transfer and temperature levels relative to
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 temperature, mass flows,
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 temperature, mass flows,
41
- enthalpies, and specific exergies.
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
- Notes
44
- -----
45
- The exergy analysis considers three main cases based on heat transfer direction
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
- Case 1 - **Heat Release** (:math:`\dot{Q} < 0`):
69
+ **Heat release** :math:\dot{Q}<0
49
70
 
50
- a) Both temperatures above ambient:
71
+ Case 1: Both streams above ambient temperature
51
72
 
52
- .. math::
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
- b) Inlet above, outlet below ambient:
75
+ .. math::
59
76
 
60
- .. math::
61
- \dot{E}_\mathrm{P} &= \dot{m}_\mathrm{out} \cdot e^\mathrm{T}_\mathrm{out}\\
62
- \dot{E}_\mathrm{F} &= \dot{m}_\mathrm{in} \cdot e^\mathrm{T}_\mathrm{in} +
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
- c) Both temperatures below ambient:
81
+ .. math::
68
82
 
69
- .. math::
70
- \dot{E}_\mathrm{P} &= \dot{m}_\mathrm{out} \cdot
71
- (e^\mathrm{T}_\mathrm{out} - e^\mathrm{T}_\mathrm{in})\\
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
- Case 2 - **Heat Addition** (:math:`\dot{Q} > 0`):
87
+ Else:
76
88
 
77
- a) Both temperatures above ambient:
89
+ .. math::
78
90
 
79
- .. math::
80
- \dot{E}_\mathrm{P} &= \dot{m}_\mathrm{out} \cdot
81
- (e^\mathrm{PH}_\mathrm{out} - e^\mathrm{PH}_\mathrm{in})\\
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
- b) Inlet below, outlet above ambient:
95
+ .. math::
86
96
 
87
- .. math::
88
- \dot{E}_\mathrm{P} &= \dot{m}_\mathrm{out} \cdot
89
- (e^\mathrm{T}_\mathrm{out} + e^\mathrm{T}_\mathrm{in})\\
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
- c) Both temperatures below ambient:
101
+ Case 2: Inlet above and outlet below ambient temperature
95
102
 
96
- .. math::
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
- Case 3 - **Dissipative** (it is not possible to specify the exergy product :math:`\dot{E}_\mathrm{P}` for this component):
105
+ .. math::
105
106
 
106
- .. math::
107
- \dot{E}_\mathrm{P} &= \mathrm{NaN}\\
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
- For all cases, the exergy destruction is calculated as:
110
+ .. math::
112
111
 
113
- .. math::
114
- \dot{E}_\mathrm{D} = \dot{E}_\mathrm{F} - \dot{E}_\mathrm{P}
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
- Where:
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
- def __init__(self, **kwargs):
123
- r"""Initialize simple heat exchanger component with given parameters."""
124
- super().__init__(**kwargs)
120
+ .. math::
125
121
 
126
- def calc_exergy_balance(self, T0: float, p0: float, split_physical_exergy) -> None:
127
- r"""
128
- Calculate the exergy balance of the simple heat exchanger.
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
- Performs exergy balance calculations considering both heat transfer direction
131
- and temperature levels relative to ambient temperature.
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 in :math:`\mathrm{K}`.
272
+ Ambient temperature (K).
137
273
  p0 : float
138
- Ambient pressure in :math:`\mathrm{Pa}`.
274
+ Ambient pressure (Pa).
139
275
  split_physical_exergy : bool
140
- Flag indicating whether physical exergy is split into thermal and mechanical components.
276
+ Whether to split thermal and mechanical exergy.
141
277
 
142
278
  Raises
143
279
  ------
144
280
  ValueError
145
- If the required inlet and outlet streams are not properly defined or
146
- exceed the maximum allowed number.
147
- """
281
+ If required inlet or outlet are missing.
282
+ """
148
283
  # Validate the number of inlets and outlets
149
- if not hasattr(self, 'inl') or not hasattr(self, 'outl') or len(self.inl) < 1 or len(self.outl) < 1:
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['m'] * outlet['h'] - inlet['m'] * inlet['h']
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['T'] >= T0 and outlet['T'] >= T0:
306
+ if inlet["T"] >= T0 and outlet["T"] >= T0:
172
307
  if split_physical_exergy:
173
- self.E_P = np.nan if getattr(self, 'dissipative', False) else inlet['m'] * (inlet['e_T'] - outlet['e_T'])
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 = np.nan if getattr(self, 'dissipative', False) else inlet['m'] * (inlet['e_PH'] - outlet['e_PH'])
176
- self.E_F = inlet['m'] * (inlet['e_PH'] - outlet['e_PH'])
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['T'] >= T0 and outlet['T'] < T0:
317
+ elif inlet["T"] >= T0 and outlet["T"] < T0:
179
318
  if split_physical_exergy:
180
- self.E_P = outlet['m'] * outlet['e_T']
181
- self.E_F = (inlet['m'] * inlet['e_T'] + outlet['m'] * outlet['e_T'] +
182
- (inlet['m'] * inlet['e_M'] - outlet['m'] * outlet['e_M']))
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['m'] * outlet['e_PH']
185
- self.E_F = inlet['m'] * inlet['e_PH']
326
+ self.E_P = outlet["m"] * outlet["e_PH"]
327
+ self.E_F = inlet["m"] * inlet["e_PH"]
186
328
 
187
- elif inlet['T'] <= T0 and outlet['T'] <= T0:
329
+ elif inlet["T"] <= T0 and outlet["T"] < T0:
188
330
  if split_physical_exergy:
189
- self.E_P = outlet['m'] * (outlet['e_T'] - inlet['e_T'])
190
- self.E_F = self.E_P + inlet['m'] * (inlet['e_M'] - outlet['m'] * outlet['e_M'])
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 = np.nan if getattr(self, 'dissipative', False) else \
193
- outlet['m'] * (outlet['e_PH'] - inlet['e_PH'])
194
- self.E_F = outlet['m'] * (outlet['e_PH'] - inlet['e_PH'])
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['T'] >= T0 and outlet['T'] >= T0:
349
+ if inlet["T"] >= T0 and outlet["T"] >= T0:
207
350
  if split_physical_exergy:
208
- self.E_P = outlet['m'] * (outlet['e_PH'] - inlet['e_PH'])
209
- self.E_F = outlet['m'] * (outlet['e_T'] - inlet['e_T'])
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['m'] * (outlet['e_PH'] - inlet['e_PH'])
212
- self.E_F = outlet['m'] * (outlet['e_PH'] - inlet['e_PH'])
213
- elif inlet['T'] < T0 and outlet['T'] > T0:
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['m'] * (outlet['e_T'] + inlet['e_T'])
216
- self.E_F = (inlet['m'] * inlet['e_T'] +
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['m'] * (outlet['e_PH'] - inlet['e_PH'])
220
- self.E_F = outlet['m'] * (outlet['e_PH'] - inlet['e_PH'])
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['T'] < T0 and outlet['T'] < T0:
364
+ elif inlet["T"] < T0 and outlet["T"] <= T0:
223
365
  if split_physical_exergy:
224
- self.E_P = np.nan if getattr(self, 'dissipative', False) else \
225
- inlet['m'] * (inlet['e_T'] - outlet['e_T']) + \
226
- (outlet['m'] * outlet['e_M'] - inlet['m'] * inlet['e_M'])
227
- self.E_F = inlet['m'] * (inlet['e_T'] - outlet['e_T'])
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 = np.nan if getattr(self, 'dissipative', False) else \
230
- inlet['m'] * (inlet['e_PH'] - outlet['e_PH'])
231
- self.E_F = inlet['m'] * (inlet['e_PH'] - outlet['e_PH'])
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['m'] * (inlet['e_PH'] - outlet['e_PH'])
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 exergy balance calculated: "
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
- Auxiliary equations for the simple heat exchanger.
264
-
265
- This function adds rows to the cost matrix A and the right-hand-side vector b to enforce
266
- the following auxiliary cost relations:
267
-
268
- (1) Thermal exergy cost equation:
269
- - For heat release (T_in > T_out > T0): F-principle is applied
270
- 1/E_T_in * C_T_in - 1/E_T_out * C_T_out = 0
271
- - For heat addition (T_in < T_out > T0): P-principle is applied
272
- 1/ΔE_T * (C_T_out - C_T_in) = 1/ΔE_M * (C_M_out - C_M_in)
273
-
274
- (2) Mechanical exergy cost equation:
275
- 1/E_M_in * C_M_in - 1/E_M_out * C_M_out = 0
276
- - F-principle: specific mechanical exergy costs equalized between inlet/outlet
277
-
278
- (3) Chemical exergy cost equation (if enabled):
279
- 1/E_CH_in * C_CH_in - 1/E_CH_out * C_CH_out = 0
280
- - F-principle: specific chemical exergy costs equalized between inlet/outlet
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
- equations : dict
293
- Dictionary for storing equation labels.
294
- chemical_exergy_enabled : bool
295
- Flag indicating whether chemical exergy auxiliary equations should be added.
296
-
297
- Returns
298
- -------
299
- A : numpy.ndarray
300
- The updated cost matrix.
301
- b : numpy.ndarray
302
- The updated right-hand-side vector.
303
- counter : int
304
- The updated row index.
305
- equations : dict
306
- Updated dictionary with equation labels.
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
- # --- Thermal cost equation (row counter) ---
309
- if self.inl[0]["T"] > T0 and self.outl[0]["T"] > T0:
310
- if self.inl[0]["T"] > self.outl[0]["T"]:
311
- # Heat is released (turbine-like behavior, f‑rule).
312
- A[counter, self.inl[0]["CostVar_index"]["T"]] = (1 / self.inl[0]["e_T"]
313
- if self.inl[0]["e_T"] != 0 else 1)
314
- A[counter, self.outl[0]["CostVar_index"]["T"]] = (-1 / self.outl[0]["e_T"]
315
- if self.outl[0]["e_T"] != 0 else -1)
316
- equations[counter] = f"aux_f_rule_{self.name}"
317
- elif self.inl[0]["T"] < self.outl[0]["T"]:
318
- # Heat is injected (compressor-like behavior, p‑rule):
319
- dET = self.outl[0]["e_T"] - self.inl[0]["e_T"]
320
- dEM = self.outl[0]["e_M"] - self.inl[0]["e_M"]
321
- if dET != 0 and dEM != 0:
322
- A[counter, self.inl[0]["CostVar_index"]["T"]] = -1 / dET
323
- A[counter, self.outl[0]["CostVar_index"]["T"]] = 1 / dET
324
- A[counter, self.inl[0]["CostVar_index"]["M"]] = 1 / dEM
325
- A[counter, self.outl[0]["CostVar_index"]["M"]] = -1 / dEM
326
- equations[counter] = f"aux_p_rule_{self.name}"
327
- else:
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
- logging.warning("SimpleHeatExchanger: Inlet and outlet temperatures are equal; case not implemented.")
332
- equations[counter] = "aux_unimpl_HEX"
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
- # --- Mechanical cost equality (row counter+1) ---
339
- A[counter+1, self.inl[0]["CostVar_index"]["M"]] = (1 / self.inl[0]["e_M"]
340
- if self.inl[0]["e_M"] != 0 else 1)
341
- A[counter+1, self.outl[0]["CostVar_index"]["M"]] = (-1 / self.outl[0]["e_M"]
342
- if self.outl[0]["e_M"] != 0 else 1)
343
- equations[counter+1] = f"aux_equality_mech_{self.outl[0]['name']}"
344
- b[counter+1] = 0
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
- # --- Chemical cost equality (conditionally added) ---
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
- counter += 2
357
-
358
- return A, b, counter, equations
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