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
@@ -12,8 +11,8 @@ class Mixer(Component):
12
11
  Class for exergy analysis of mixers.
13
12
 
14
13
  This class performs exergy analysis calculations for mixers with multiple
15
- inlet streams and generally one outlet stream (multiple outlets are possible).
16
- The exergy product and fuel definitions vary based on the temperature
14
+ inlet streams and generally one outlet stream (multiple outlets are possible).
15
+ The exergy product and fuel definitions vary based on the temperature
17
16
  relationships between inlet streams, outlet streams, and ambient conditions.
18
17
 
19
18
  Parameters
@@ -44,53 +43,52 @@ class Mixer(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}
50
- \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\\
46
+ \displaystyle
47
+ \dot E_{P} =
60
48
  \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{mixer inlets}
94
92
  """
95
93
 
96
94
  def __init__(self, **kwargs):
@@ -121,22 +119,22 @@ class Mixer(Component):
121
119
  # Ensure that the component has at least two inlets and one outlet.
122
120
  if len(self.inl) < 2 or len(self.outl) < 1:
123
121
  raise ValueError("Mixer requires at least two inlets and one outlet.")
124
-
122
+
125
123
  # Compute effective outlet state by aggregating all outlet streams.
126
124
  # Assume that all outlets share the same thermodynamic state.
127
125
  outlet_list = list(self.outl.values())
128
126
  first_outlet = outlet_list[0]
129
- T_out = first_outlet['T']
130
- e_out_PH = first_outlet['e_PH']
127
+ T_out = first_outlet["T"]
128
+ e_out_PH = first_outlet["e_PH"]
131
129
  # Verify that all outlets have the same thermodynamic state.
132
130
  for outlet in outlet_list:
133
- if outlet['T'] != T_out or outlet['e_PH'] != e_out_PH:
131
+ if outlet["T"] != T_out or outlet["e_PH"] != e_out_PH:
134
132
  msg = "All outlets in Mixer must have the same thermodynamic state."
135
133
  logging.error(msg)
136
134
  raise ValueError(msg)
137
135
  # Sum the mass of all outlet streams (if needed for further analysis)
138
- m_out_total = sum(outlet.get('m', 0) for outlet in outlet_list)
139
-
136
+ sum(outlet.get("m", 0) for outlet in outlet_list)
137
+
140
138
  # Initialize exergy product and fuel.
141
139
  self.E_P = 0
142
140
  self.E_F = 0
@@ -145,64 +143,64 @@ class Mixer(Component):
145
143
  if T_out > T0:
146
144
  for _, inlet in self.inl.items():
147
145
  # Case when inlet temperature is lower than outlet temperature.
148
- if inlet['T'] < T_out:
149
- if inlet['T'] >= T0:
146
+ if inlet["T"] < T_out:
147
+ if inlet["T"] >= T0:
150
148
  # Contribution to exergy product from inlets above ambient.
151
- self.E_P += inlet['m'] * (e_out_PH - inlet['e_PH'])
149
+ self.E_P += inlet["m"] * (e_out_PH - inlet["e_PH"])
152
150
  else: # inlet['T'] < T0
153
- self.E_P += inlet['m'] * e_out_PH
154
- self.E_F += inlet['m'] * inlet['e_PH']
151
+ self.E_P += inlet["m"] * e_out_PH
152
+ self.E_F += inlet["m"] * inlet["e_PH"]
155
153
  else: # inlet['T'] > T_out
156
- self.E_F += inlet['m'] * (inlet['e_PH'] - e_out_PH)
157
-
154
+ self.E_F += inlet["m"] * (inlet["e_PH"] - e_out_PH)
155
+
158
156
  # Case 2: Outlet temperature equals ambient.
159
157
  elif T_out == T0:
160
158
  self.E_P = np.nan
161
159
  for _, inlet in self.inl.items():
162
- self.E_F += inlet['m'] * inlet['e_PH']
163
-
160
+ self.E_F += inlet["m"] * inlet["e_PH"]
161
+
164
162
  # Case 3: Outlet temperature is less than ambient.
165
163
  else: # T_out < T0
166
164
  for _, inlet in self.inl.items():
167
- if inlet['T'] > T_out:
168
- if inlet['T'] >= T0:
169
- self.E_P += inlet['m'] * e_out_PH
170
- self.E_F += inlet['m'] * inlet['e_PH']
165
+ if inlet["T"] > T_out:
166
+ if inlet["T"] >= T0:
167
+ self.E_P += inlet["m"] * e_out_PH
168
+ self.E_F += inlet["m"] * inlet["e_PH"]
171
169
  else: # inlet['T'] < T0
172
- self.E_P += inlet['m'] * (e_out_PH - inlet['e_PH'])
170
+ self.E_P += inlet["m"] * (e_out_PH - inlet["e_PH"])
173
171
  else: # inlet['T'] <= T_out
174
- self.E_F += inlet['m'] * (inlet['e_PH'] - e_out_PH)
175
-
172
+ self.E_F += inlet["m"] * (inlet["e_PH"] - e_out_PH)
173
+
176
174
  # Calculate exergy destruction and efficiency.
177
175
  self.E_D = self.E_F - self.E_P
178
176
  self.epsilon = self.calc_epsilon()
179
-
177
+
180
178
  # Log the results.
181
179
  logging.info(
182
- f"Mixer exergy balance calculated: "
180
+ f"Exergy balance of Mixer {self.name} calculated: "
183
181
  f"E_P={self.E_P:.2f}, E_F={self.E_F:.2f}, E_D={self.E_D:.2f}, "
184
182
  f"Efficiency={self.epsilon:.2%}"
185
- )
186
-
187
-
183
+ )
188
184
 
189
185
  def aux_eqs(self, A, b, counter, T0, equations, chemical_exergy_enabled):
190
186
  """
191
187
  Auxiliary equations for the mixer.
192
-
188
+
193
189
  This function adds rows to the cost matrix A and the right-hand-side vector b to enforce
194
190
  the following auxiliary cost relations:
195
-
196
- (1) Chemical exergy cost equation (if enabled):
197
- - F-principle: The specific chemical exergy cost of the outlet stream is calculated as
198
- the weighted average of the specific chemical exergy costs of the inlet streams.
199
- - For inlets with zero chemical exergy, their specific costs are directly transferred.
200
-
201
- (2) Mechanical exergy cost equation:
202
- - F-principle: The specific mechanical exergy cost of the outlet stream is calculated as
203
- the weighted average of the specific mechanical exergy costs of the inlet streams.
204
- - For inlets with zero mechanical exergy, their specific costs are directly transferred.
205
-
191
+
192
+ (1) Mixing equation for chemical exergy costs (if enabled):
193
+
194
+ - The outlet's specific chemical exergy cost is calculated as a mass-weighted average of the inlet streams' specific chemical exergy costs
195
+
196
+ - This enforces proper chemical exergy cost distribution through the deaerator
197
+
198
+ (2) Mixing equation for mechanical exergy costs:
199
+
200
+ - The outlet's specific mechanical exergy cost is calculated as a mass-weighted average of the inlet streams' specific mechanical exergy costs
201
+
202
+ - This ensures mechanical exergy costs are properly conserved in the mixing process
203
+
206
204
  Parameters
207
205
  ----------
208
206
  A : numpy.ndarray
@@ -243,13 +241,16 @@ class Mixer(Component):
243
241
  # Outlet chemical exergy is zero: assign fallback for all inlets.
244
242
  for inlet in self.inl.values():
245
243
  A[counter, inlet["CostVar_index"]["CH"]] = 1
246
- equations[counter] = f"aux_mixing_chem_{self.outl[0]['name']}"
244
+ equations[counter] = {
245
+ "kind": "aux_mixing",
246
+ "objects": [self.name, self.inl[0]["name"], self.inl[1]["name"], self.outl[0]["name"]],
247
+ "property": "c_CH",
248
+ }
247
249
  chem_row = 1 # One row added for chemical equation.
248
250
  else:
249
251
  chem_row = 0 # No row added.
250
252
 
251
253
  # --- Mechanical cost auxiliary equation ---
252
- mech_row = 0 # This row will always be added.
253
254
  if self.outl[0]["e_M"] != 0:
254
255
  A[counter + chem_row, self.outl[0]["CostVar_index"]["M"]] = -1 / self.outl[0]["E_M"]
255
256
  # Iterate over inlet streams for mechanical mixing.
@@ -261,7 +262,15 @@ class Mixer(Component):
261
262
  else:
262
263
  for inlet in self.inl.values():
263
264
  A[counter + chem_row, inlet["CostVar_index"]["M"]] = 1
264
- equations[counter + chem_row] = f"aux_mixing_mech_{self.outl[0]['name']}"
265
+
266
+ # Dynamically build the list of inlet names
267
+ inlet_names = [inlet["name"] for inlet in self.inl.values()]
268
+
269
+ equations[counter + chem_row] = {
270
+ "kind": "aux_mixing",
271
+ "objects": [self.name] + inlet_names + [self.outl[0]["name"]],
272
+ "property": "c_M",
273
+ }
265
274
 
266
275
  # Set the right-hand side entries to zero for the added rows.
267
276
  if chemical_exergy_enabled:
@@ -273,40 +282,208 @@ class Mixer(Component):
273
282
  counter += 1 # Only one row was added.
274
283
 
275
284
  return A, b, counter, equations
276
-
277
- def exergoeconomic_balance(self, T0):
278
- """
279
- Perform exergoeconomic balance calculations for the mixer.
280
-
281
- This method calculates various exergoeconomic parameters including:
282
- - Cost rates of product (C_P) and fuel (C_F)
283
- - Specific cost of product (c_P) and fuel (c_F)
284
- - Cost rate of exergy destruction (C_D)
285
- - Relative cost difference (r)
286
- - Exergoeconomic factor (f)
287
-
285
+
286
+ def exergoeconomic_balance(self, T0, chemical_exergy_enabled=False):
287
+ r"""
288
+ Perform exergoeconomic cost balance for the mixer.
289
+
290
+ The mixer is a component where multiple streams combine. The general
291
+ exergoeconomic balance equation is:
292
+
293
+ .. math::
294
+ \sum_{\mathrm{in}} \left(\dot{C}^{\mathrm{T}}_{\mathrm{in}}
295
+ + \dot{C}^{\mathrm{M}}_{\mathrm{in}}
296
+ + \dot{C}^{\mathrm{CH}}_{\mathrm{in}}\right)
297
+ - \sum_{\mathrm{out}} \left(\dot{C}^{\mathrm{T}}_{\mathrm{out}}
298
+ + \dot{C}^{\mathrm{M}}_{\mathrm{out}}
299
+ + \dot{C}^{\mathrm{CH}}_{\mathrm{out}}\right)
300
+ + \dot{Z}
301
+ = 0
302
+
303
+ The product is defined as the outlet stream. The fuel consists of all inlet
304
+ streams, with treatment depending on temperature levels and whether chemical
305
+ exergy is enabled. The cost balance is closed using:
306
+
307
+ .. math::
308
+ \dot{C}_{\mathrm{P}} = \dot{C}_{\mathrm{F}} + \dot{Z}
309
+
310
+ **Case 1: Outlet above ambient temperature**
311
+
312
+ When :math:`T_{\mathrm{out}} > T_0`:
313
+
314
+ For cold inlets (:math:`T_{\mathrm{in}} < T_{\mathrm{out}}`):
315
+
316
+ Without chemical exergy:
317
+
318
+ .. math::
319
+ \dot{C}_{\mathrm{F,cold}} = \dot{C}^{\mathrm{M}}_{\mathrm{in}}
320
+
321
+ With chemical exergy enabled:
322
+
323
+ .. math::
324
+ \dot{C}_{\mathrm{F,cold}} = \dot{C}^{\mathrm{M}}_{\mathrm{in}}
325
+ + \dot{C}^{\mathrm{CH}}_{\mathrm{in}}
326
+
327
+ For hot inlets (:math:`T_{\mathrm{in}} \geq T_{\mathrm{out}}`):
328
+
329
+ Without chemical exergy:
330
+
331
+ .. math::
332
+ \dot{C}_{\mathrm{F,hot}} = -\dot{m}_{\mathrm{in}} \cdot c^{\mathrm{T}}_{\mathrm{in}}
333
+ \cdot e^{\mathrm{T}}_{\mathrm{in}}
334
+ + \left(\dot{C}^{\mathrm{T}}_{\mathrm{in}}
335
+ + \dot{C}^{\mathrm{M}}_{\mathrm{in}}\right)
336
+
337
+ With chemical exergy enabled:
338
+
339
+ .. math::
340
+ \dot{C}_{\mathrm{F,hot}} = -\dot{m}_{\mathrm{in}} \cdot c^{\mathrm{T}}_{\mathrm{in}}
341
+ \cdot e^{\mathrm{T}}_{\mathrm{in}}
342
+ + \left(\dot{C}^{\mathrm{T}}_{\mathrm{in}}
343
+ + \dot{C}^{\mathrm{M}}_{\mathrm{in}}
344
+ + \dot{C}^{\mathrm{CH}}_{\mathrm{in}}\right)
345
+
346
+ Total fuel cost (without chemical exergy):
347
+
348
+ .. math::
349
+ \dot{C}_{\mathrm{F}} = \sum \dot{C}_{\mathrm{F,cold}}
350
+ + \sum \dot{C}_{\mathrm{F,hot}}
351
+ - \dot{C}^{\mathrm{M}}_{\mathrm{out}}
352
+
353
+ Total fuel cost (with chemical exergy):
354
+
355
+ .. math::
356
+ \dot{C}_{\mathrm{F}} = \sum \dot{C}_{\mathrm{F,cold}}
357
+ + \sum \dot{C}_{\mathrm{F,hot}}
358
+ - \dot{C}^{\mathrm{M}}_{\mathrm{out}}
359
+ - \dot{C}^{\mathrm{CH}}_{\mathrm{out}}
360
+
361
+ **Case 2: Outlet at ambient temperature (dissipative)**
362
+
363
+ When :math:`|T_{\mathrm{out}} - T_0| < 10^{-6}`:
364
+
365
+ .. math::
366
+ \dot{C}_{\mathrm{F}} = \sum_{\mathrm{in}} \dot{C}^{\mathrm{TOT}}_{\mathrm{in}}
367
+
368
+ **Case 3: Outlet below ambient temperature**
369
+
370
+ When :math:`T_{\mathrm{out}} < T_0`:
371
+
372
+ For hot inlets (:math:`T_{\mathrm{in}} > T_{\mathrm{out}}`):
373
+
374
+ Without chemical exergy:
375
+
376
+ .. math::
377
+ \dot{C}_{\mathrm{F,hot}} = \dot{C}^{\mathrm{M}}_{\mathrm{in}}
378
+
379
+ With chemical exergy enabled:
380
+
381
+ .. math::
382
+ \dot{C}_{\mathrm{F,hot}} = \dot{C}^{\mathrm{M}}_{\mathrm{in}}
383
+ + \dot{C}^{\mathrm{CH}}_{\mathrm{in}}
384
+
385
+ For cold inlets (:math:`T_{\mathrm{in}} \leq T_{\mathrm{out}}`):
386
+
387
+ Without chemical exergy:
388
+
389
+ .. math::
390
+ \dot{C}_{\mathrm{F,cold}} = -\dot{m}_{\mathrm{in}} \cdot c^{\mathrm{T}}_{\mathrm{in}}
391
+ \cdot e^{\mathrm{T}}_{\mathrm{in}}
392
+ + \left(\dot{C}^{\mathrm{T}}_{\mathrm{in}}
393
+ + \dot{C}^{\mathrm{M}}_{\mathrm{in}}\right)
394
+
395
+ With chemical exergy enabled:
396
+
397
+ .. math::
398
+ \dot{C}_{\mathrm{F,cold}} = -\dot{m}_{\mathrm{in}} \cdot c^{\mathrm{T}}_{\mathrm{in}}
399
+ \cdot e^{\mathrm{T}}_{\mathrm{in}}
400
+ + \left(\dot{C}^{\mathrm{T}}_{\mathrm{in}}
401
+ + \dot{C}^{\mathrm{M}}_{\mathrm{in}}
402
+ + \dot{C}^{\mathrm{CH}}_{\mathrm{in}}\right)
403
+
404
+ Total fuel cost (without chemical exergy):
405
+
406
+ .. math::
407
+ \dot{C}_{\mathrm{F}} = \sum \dot{C}_{\mathrm{F,hot}}
408
+ + \sum \dot{C}_{\mathrm{F,cold}}
409
+ - \dot{C}^{\mathrm{M}}_{\mathrm{out}}
410
+
411
+ Total fuel cost (with chemical exergy):
412
+
413
+ .. math::
414
+ \dot{C}_{\mathrm{F}} = \sum \dot{C}_{\mathrm{F,hot}}
415
+ + \sum \dot{C}_{\mathrm{F,cold}}
416
+ - \dot{C}^{\mathrm{M}}_{\mathrm{out}}
417
+ - \dot{C}^{\mathrm{CH}}_{\mathrm{out}}
418
+
419
+ **Calculated exergoeconomic indicators:**
420
+
421
+ .. math::
422
+ c_{\mathrm{F}} = \frac{\dot{C}_{\mathrm{F}}}{\dot{E}_{\mathrm{F}}}
423
+
424
+ .. math::
425
+ c_{\mathrm{P}} = \frac{\dot{C}_{\mathrm{P}}}{\dot{E}_{\mathrm{P}}}
426
+
427
+ .. math::
428
+ \dot{C}_{\mathrm{D}} = c_{\mathrm{F}} \cdot \dot{E}_{\mathrm{D}}
429
+
430
+ .. math::
431
+ r = \frac{c_{\mathrm{P}} - c_{\mathrm{F}}}{c_{\mathrm{F}}}
432
+
433
+ .. math::
434
+ f = \frac{\dot{Z}}{\dot{Z} + \dot{C}_{\mathrm{D}}}
435
+
288
436
  Parameters
289
437
  ----------
290
438
  T0 : float
291
- Ambient temperature
292
-
439
+ Ambient temperature (K).
440
+ chemical_exergy_enabled : bool, optional
441
+ If True, chemical exergy is considered in the calculations.
442
+ Default is False.
443
+
444
+ Attributes Set
445
+ --------------
446
+ C_P : float
447
+ Cost rate of product (currency/time).
448
+ C_F : float
449
+ Cost rate of fuel (currency/time).
450
+ c_P : float
451
+ Specific cost of product (currency/energy).
452
+ c_F : float
453
+ Specific cost of fuel (currency/energy).
454
+ C_D : float
455
+ Cost rate of exergy destruction (currency/time).
456
+ r : float
457
+ Relative cost difference (dimensionless).
458
+ f : float
459
+ Exergoeconomic factor (dimensionless).
460
+
293
461
  Notes
294
462
  -----
295
- The exergoeconomic balance considers thermal (T), chemical (CH),
296
- and mechanical (M) exergy components for the inlet and outlet streams.
463
+ The mixer treats thermal, mechanical, and chemical exergy components
464
+ differently depending on whether inlets are "hot" or "cold" relative to
465
+ the outlet temperature. The distinction ensures proper cost allocation
466
+ for streams that provide heating versus those being heated.
467
+
468
+ Future development may include merging profits from dissipative components.
297
469
  """
298
470
  self.C_P = 0
299
471
  self.C_F = 0
300
472
  if self.outl[0]["T"] > T0:
301
- for i in self.inl:
473
+ for i in self.inl.values():
302
474
  if i["T"] < self.outl[0]["T"]:
303
475
  # cold inlets
304
- self.C_F += i["C_M"] + i["C_CH"]
476
+ self.C_F += i["C_M"]
477
+ if chemical_exergy_enabled:
478
+ self.C_F += i["C_CH"]
305
479
  else:
306
480
  # hot 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"])
481
+ self.C_F += -i["m"] * i["c_T"] * i["e_T"] + (i["C_T"] + i["C_M"])
482
+ if chemical_exergy_enabled:
483
+ self.C_F += i["C_CH"]
484
+ self.C_F += -self.outl[0]["C_M"]
485
+ if chemical_exergy_enabled:
486
+ self.C_F += -self.outl[0]["C_CH"]
310
487
  elif self.outl[0]["T"] - 1e-6 < T0 and self.outl[0]["T"] + 1e-6 > T0:
311
488
  # dissipative
312
489
  for i in self.inl:
@@ -315,18 +492,22 @@ class Mixer(Component):
315
492
  for i in self.inl:
316
493
  if i["T"] > self.outl[0]["T"]:
317
494
  # hot inlets
318
- self.C_F += i["C_M"] + i["C_CH"]
495
+ self.C_F += i["C_M"]
496
+ if chemical_exergy_enabled:
497
+ self.C_F += i["C_M"] + i["C_CH"]
319
498
  else:
320
499
  # cold inlets
321
- self.C_F += - i["M"] * i["C_T"] * i["e_T"] + (
322
- i["C_T"] + i["C_M"] + i["C_CH"])
323
- self.C_F += (-self.outl[0]["C_M"] - self.outl[0]["C_CH"])
324
- self.C_P = self.C_F + self.Z_costs # +1/num_serving_comps * C_diff
500
+ self.C_F += -i["m"] * i["c_T"] * i["e_T"] + (i["C_T"] + i["C_M"])
501
+ if chemical_exergy_enabled:
502
+ self.C_F += i["C_CH"]
503
+ self.C_F += -self.outl[0]["C_M"]
504
+ if chemical_exergy_enabled:
505
+ self.C_F += -self.outl[0]["C_CH"]
506
+ self.C_P = self.C_F + self.Z_costs # +1/num_serving_comps * C_diff
325
507
  # ToDo: add case that merge profits from dissipative component(s)
326
508
 
327
-
328
509
  self.c_F = self.C_F / self.E_F
329
510
  self.c_P = self.C_P / self.E_P
330
511
  self.C_D = self.c_F * self.E_D
331
512
  self.r = (self.c_P - self.c_F) / self.c_F
332
- self.f = self.Z_costs / (self.Z_costs + self.C_D)
513
+ self.f = self.Z_costs / (self.Z_costs + self.C_D)