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,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{E}_\mathrm{P} =
49
- \begin{cases}
46
+ \displaystyle
47
+ \dot E_{P} =
50
48
  \begin{cases}
51
- \sum_i \dot{m}_i \cdot (e_\mathrm{out}^\mathrm{PH} -
52
- e_{\mathrm{in,}i}^\mathrm{PH})
53
- & T_{\mathrm{in,}i} < T_\mathrm{out} \mathrm{ & }
54
- T_{\mathrm{in,}i} \geq T_0 \\
55
- \sum_i \dot{m}_i \cdot e_\mathrm{out}^\mathrm{PH}
56
- & T_{\mathrm{in,}i} < T_\mathrm{out} \mathrm{ & }
57
- T_{\mathrm{in,}i} < T_0 \\
58
- \end{cases} & T_\mathrm{out} > T_0\\
59
- \mathrm{not defined (nan)} & T_\mathrm{out} = T_0\\
60
- \begin{cases}
61
- \sum_i \dot{m}_i \cdot e_\mathrm{out}^\mathrm{PH}
62
- & T_{\mathrm{in,}i} > T_\mathrm{out} \mathrm{ & }
63
- T_{\mathrm{in,}i} \geq T_0 \\
64
- \sum_i \dot{m}_i \cdot (e_\mathrm{out}^\mathrm{PH} -
65
- e_{\mathrm{in,}i}^\mathrm{PH})
66
- & T_{\mathrm{in,}i} > T_\mathrm{out} \mathrm{ & }
67
- T_{\mathrm{in,}i} < T_0 \\
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
- \dot{E}_\mathrm{F} =
72
- \begin{cases}
73
- \begin{cases}
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
- \sum_i \dot{m}_i \cdot e_{\mathrm{in,}i}^\mathrm{PH}
85
- & T_{\mathrm{in,}i} > T_\mathrm{out} \mathrm{ & }
86
- T_{\mathrm{in,}i} \geq T_0 \\
87
- \sum_i \dot{m}_i \cdot (e_{\mathrm{in,}i}^\mathrm{PH} -
88
- e_\mathrm{out}^\mathrm{PH})
89
- & T_{\mathrm{in,}i} < T_\mathrm{out} \\
90
- \end{cases} & T_\mathrm{out} < T_0\\
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]['T'] > T0:
127
+ if self.outl[0]["T"] > T0:
130
128
  for _, inlet in self.inl.items():
131
- if inlet['T'] < self.outl[0]['T']: # Tin < Tout
132
- if inlet['T'] >= T0: # and Tin >= T0
133
- self.E_P += inlet['m'] * (self.outl[0]['e_PH'] - inlet['e_PH'])
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['m'] * self.outl[0]['e_PH']
136
- self.E_F += inlet['m'] * inlet['e_PH']
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['m'] * (inlet['e_PH'] - self.outl[0]['e_PH'])
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]['T'] == T0:
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['m'] * inlet['e_PH']
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['T'] > self.outl[0]['T']: # Tin > Tout
150
- if inlet['T'] >= T0: # and Tin >= T0
151
- self.E_P += inlet['m'] * self.outl[0]['e_PH']
152
- self.E_F += inlet['m'] * inlet['e_PH']
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['m'] * (self.outl[0]['e_PH'] - inlet['e_PH'])
152
+ self.E_P += inlet["m"] * (self.outl[0]["e_PH"] - inlet["e_PH"])
155
153
  else: # Tin < Tout
156
- self.E_F += inlet['m'] * (inlet['e_PH'] - self.outl[0]['e_PH'])
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 exergy balance calculated: "
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
- - The outlet's specific chemical exergy cost is calculated as a mass-weighted
181
- average of the inlet streams' specific chemical exergy costs
182
- - This enforces proper chemical exergy cost distribution through the deaerator
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
- - The outlet's specific mechanical exergy cost is calculated as a mass-weighted
186
- average of the inlet streams' specific mechanical exergy costs
187
- - This ensures mechanical exergy costs are properly conserved in the mixing process
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] = f"aux_mixing_chem_{self.outl[0]['name']}"
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] = f"aux_mixing_mech_{self.outl[0]['name']}"
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 calculations for the deaerator.
266
-
267
- This method calculates various exergoeconomic parameters including:
268
- - Cost rates of product (C_P) and fuel (C_F)
269
- - Specific cost of product (c_P) and fuel (c_F)
270
- - Cost rate of exergy destruction (C_D)
271
- - Relative cost difference (r)
272
- - Exergoeconomic factor (f)
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 exergoeconomic balance considers thermal (T), chemical (CH),
282
- and mechanical (M) exergy components for the inlet and outlet streams.
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 += - i["M"] * i["C_T"] * i["e_T"] + (
294
- i["C_T"] + i["C_M"] + i["C_CH"])
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 += - i["M"] * i["C_T"] * i["e_T"] + (
308
- i["C_T"] + i["C_M"] + i["C_CH"])
309
- self.C_F += (-self.outl[0]["C_M"] - self.outl[0]["C_CH"])
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)
@@ -1,9 +1,6 @@
1
1
  import logging
2
2
 
3
- import numpy as np
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
- self.outl[0]['e_PH'] * self.outl[0]['m']
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 exergy balance calculated: "
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] = f"aux_drum_chem1_{self.outl[0]['name']}"
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] = f"aux_drum_chem2_{self.outl[1]['name']}"
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] = f"aux_drum_therm_{self.outl[0]['name']}_{self.outl[1]['name']}"
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] = f"aux_drum_mech_{self.outl[0]['name']}_{self.outl[1]['name']}"
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] = f"aux_drum_therm_mech_{self.outl[0]['name']}"
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):