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
@@ -1,58 +1,67 @@
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
10
7
  class FlashTank(Component):
11
8
  r"""
12
- Class for exergy analysis of flash tanks.
13
-
14
- This class performs exergy analysis calculations for flash tanks where a feed
15
- stream is partially flashed into two different outlet streams (e.g., vapor and liquid).
16
- The exergy fuel is calculated using the physical/thermal exergy of the inlet streams,
17
- while the exergy product is computed as the sum of the physical exergy of the outlet streams.
18
- Exergy destruction is the difference between the fuel and product, and the efficiency is defined
19
- as ε = E_P / E_F.
9
+ Class for exergy and exergoeconomic analysis of flash tank.
20
10
 
21
- Parameters
22
- ----------
23
- **kwargs : dict
24
- Arbitrary keyword arguments passed to the parent class.
11
+ This class performs exergy and exergoeconomic analysis calculations for flash tank components,
12
+ accounting for two inlet and two outlet streams.
25
13
 
26
14
  Attributes
27
15
  ----------
28
16
  E_F : float
29
- Exergy fuel of the component (W), computed from the inlet streams.
17
+ Exergy fuel of the component :math:`\dot{E}_\mathrm{F}` in :math:`\mathrm{W}`.
30
18
  E_P : float
31
- Exergy product of the component (W), computed from the outlet streams.
19
+ Exergy product of the component :math:`\dot{E}_\mathrm{P}` in :math:`\mathrm{W}`.
32
20
  E_D : float
33
- Exergy destruction (W).
21
+ Exergy destruction of the component :math:`\dot{E}_\mathrm{D}` in :math:`\mathrm{W}`.
34
22
  epsilon : float
35
- Exergetic efficiency, defined as E_P/E_F.
23
+ Exergetic efficiency of the component :math:`\varepsilon` in :math:`-`.
36
24
  inl : dict
37
- Dictionary containing inlet streams data (e.g., temperature, mass flow, specific exergy).
25
+ Dictionary containing inlet stream data with mass flows and specific exergies.
38
26
  outl : dict
39
- Dictionary containing outlet streams data (e.g., temperature, mass flow, specific exergy).
27
+ Dictionary containing outlet stream data with mass flows and specific exergies.
28
+ Z_costs : float
29
+ Investment cost rate of the component in currency/h.
30
+ C_P : float
31
+ Cost of product stream :math:`\dot{C}_P` in currency/h.
32
+ C_F : float
33
+ Cost of fuel stream :math:`\dot{C}_F` in currency/h.
34
+ C_D : float
35
+ Cost of exergy destruction :math:`\dot{C}_D` in currency/h.
36
+ c_P : float
37
+ Specific cost of product stream (currency per unit exergy).
38
+ c_F : float
39
+ Specific cost of fuel stream (currency per unit exergy).
40
+ r : float
41
+ Relative cost difference, :math:`(c_P - c_F)/c_F`.
42
+ f : float
43
+ Exergoeconomic factor, :math:`\dot{Z}/(\dot{Z} + \dot{C}_D)`.
44
+ Ex_C_col : dict
45
+ Custom cost coefficients collection passed via `kwargs`.
40
46
  """
41
47
 
42
48
  def __init__(self, **kwargs):
43
- r"""Initialize flash tank component with given parameters."""
49
+ r"""
50
+ Initialize the flash tank component.
51
+
52
+ Parameters
53
+ ----------
54
+ **kwargs : dict
55
+ Arbitrary keyword arguments. Recognized keys:
56
+ - Ex_C_col (dict): custom cost coefficients, default {}
57
+ - Z_costs (float): investment cost rate in currency/h, default 0.0
58
+ """
59
+ self.dissipative = False
44
60
  super().__init__(**kwargs)
45
61
 
46
- def calc_exergy_balance(self, T0: float, p0: float, split_physical_exergy: bool) -> None:
62
+ def calc_exergy_balance(self, T0: float, p0: float, split_physical_exergy) -> None:
47
63
  r"""
48
- Calculate the exergy balance of the flash tank.
49
-
50
- The exergy fuel (E_F) is computed as the sum of the inlet streams' exergy.
51
- If split_physical_exergy is True, the thermal exergy (e_T) is used;
52
- otherwise, the physical exergy (e_PH) is used.
53
- The exergy product (E_P) is calculated as the sum of the physical exergy of the
54
- outlet streams. Exergy destruction (E_D) is the difference E_F - E_P, and
55
- exergetic efficiency is ε = E_P / E_F.
64
+ Compute the exergy balance of the flash tank.
56
65
 
57
66
  Parameters
58
67
  ----------
@@ -62,20 +71,36 @@ class FlashTank(Component):
62
71
  Ambient pressure in Pascal.
63
72
  split_physical_exergy : bool
64
73
  Flag indicating whether physical exergy is split into thermal and mechanical components.
74
+
75
+ Raises
76
+ ------
77
+ ValueError
78
+ If the number of inlet or outlet streams is less than two.
79
+
80
+ Notes
81
+ -----
82
+ The definition of exergy fuel and product for this component has not been validated yet. For now, the
83
+ exergy fuel is defined as the inlet streams exergy, and the exergy product is defined as the
84
+ sum of the outlet streams' exergies (i). The exergy destruction is calculated as the difference between the exergy fuel and product.
85
+ .. math::
86
+
87
+ \dot{E}_\mathrm{F} = \dot{E}_{in}^\mathrm{PH}
88
+
89
+ .. math::
90
+
91
+ \dot{E}_\mathrm{P} = \sum_{i=1}^{m} \dot{E}_i^\mathrm{PH}
92
+
65
93
  """
66
- # Ensure that at least two inlet streams and two outlet streams are provided.
67
- if len(self.inl) < 2 or len(self.outl) < 2:
68
- raise ValueError("FlashTank requires at least two inlets and two outlets.")
69
-
70
- if split_physical_exergy:
71
- exergy_type = 'e_T'
72
- else:
73
- exergy_type = 'e_PH'
94
+ # Ensure that the component has at least two outlets and one inlet.
95
+ if len(self.inl) < 1 or len(self.outl) < 2:
96
+ raise ValueError("Flash tank requires one inlet and two outlets.")
97
+
98
+ exergy_type = "e_T" if split_physical_exergy else "e_PH"
74
99
 
75
100
  # Calculate exergy fuel (E_F) from inlet streams.
76
- self.E_F = sum(inlet['m'] * inlet[exergy_type] for inlet in self.inl.values())
101
+ self.E_F = sum(inlet["m"] * inlet[exergy_type] for inlet in self.inl.values())
77
102
  # Calculate exergy product (E_P) from outlet streams.
78
- self.E_P = sum(outlet['m'] * outlet[exergy_type] for outlet in self.outl.values())
103
+ self.E_P = sum(outlet["m"] * outlet[exergy_type] for outlet in self.outl.values())
79
104
 
80
105
  # Exergy destruction and efficiency.
81
106
  self.E_D = self.E_F - self.E_P
@@ -83,7 +108,157 @@ class FlashTank(Component):
83
108
 
84
109
  # Log the results.
85
110
  logging.info(
86
- f"FlashTank exergy balance calculated: "
111
+ f"Exergy balance of FlashTank {self.name} calculated: "
87
112
  f"E_F = {self.E_F:.2f} W, E_P = {self.E_P:.2f} W, E_D = {self.E_D:.2f} W, "
88
113
  f"Efficiency = {self.epsilon:.2%}"
89
114
  )
115
+
116
+ def aux_eqs(self, A, b, counter, T0, equations, chemical_exergy_enabled):
117
+ """
118
+ Auxiliary equations for the flash tank.
119
+
120
+ This function adds rows to the cost matrix A and the right-hand-side vector b to enforce
121
+ equality of specific exergy costs between the single inlet stream and each outlet stream.
122
+ Thermal and mechanical costs are always equated; chemical costs are equated only if enabled.
123
+
124
+ Parameters
125
+ ----------
126
+ A : numpy.ndarray
127
+ The current cost matrix.
128
+ b : numpy.ndarray
129
+ The current right-hand-side vector.
130
+ counter : int
131
+ The current row index in the matrix.
132
+ T0 : float
133
+ Ambient temperature (not used).
134
+ equations : list or dict
135
+ Data structure for storing equation labels.
136
+ chemical_exergy_enabled : bool
137
+ Flag indicating whether chemical exergy auxiliary equations should be added.
138
+
139
+ Returns
140
+ -------
141
+ A : numpy.ndarray
142
+ The updated cost matrix.
143
+ b : numpy.ndarray
144
+ The updated right-hand-side vector.
145
+ counter : int
146
+ The updated row index after adding equations.
147
+ equations : list or dict
148
+ Updated structure with equation labels.
149
+ """
150
+ # single inlet
151
+ inlet = self.inl[0]
152
+ # two outlets (assumed indices 0 and 1)
153
+ out0 = self.outl[0]
154
+ out1 = self.outl[1]
155
+
156
+ # --- Thermal product‐rule: c_T,out0 = c_T,out1 ---
157
+ # 1/e_T,out0 · C_T,out0 − 1/e_T,out1 · C_T,out1 = 0
158
+ if out0["e_T"] != 0 and out1["e_T"] != 0:
159
+ A[counter, out0["CostVar_index"]["T"]] = 1.0 / out0["e_T"]
160
+ A[counter, out1["CostVar_index"]["T"]] = -1.0 / out1["e_T"]
161
+ elif out0["e_T"] == 0 and out1["e_T"] != 0:
162
+ A[counter, out0["CostVar_index"]["T"]] = 1.0
163
+ elif out0["e_T"] != 0 and out1["e_T"] == 0:
164
+ A[counter, out1["CostVar_index"]["T"]] = 1.0
165
+ else:
166
+ A[counter, out0["CostVar_index"]["T"]] = 1.0
167
+ A[counter, out1["CostVar_index"]["T"]] = -1.0
168
+
169
+ equations[counter] = {
170
+ "kind": "aux_p_rule",
171
+ "objects": [self.name, out0["name"], out1["name"]],
172
+ "property": "c_T",
173
+ }
174
+ b[counter] = 0.0
175
+ counter += 1
176
+
177
+ # --- Mechanical equality: c_M,inlet = c_M,outlet_i for each outlet ---
178
+ for out in (out0, out1):
179
+ if inlet["e_M"] != 0 and out["e_M"] != 0:
180
+ A[counter, inlet["CostVar_index"]["M"]] = 1.0 / inlet["e_M"]
181
+ A[counter, out["CostVar_index"]["M"]] = -1.0 / out["e_M"]
182
+ elif inlet["e_M"] == 0 and out["e_M"] != 0:
183
+ A[counter, inlet["CostVar_index"]["M"]] = 1.0
184
+ elif inlet["e_M"] != 0 and out["e_M"] == 0:
185
+ A[counter, out["CostVar_index"]["M"]] = 1.0
186
+ else:
187
+ A[counter, inlet["CostVar_index"]["M"]] = 1.0
188
+ A[counter, out["CostVar_index"]["M"]] = -1.0
189
+
190
+ equations[counter] = {
191
+ "kind": "aux_equality",
192
+ "objects": [self.name, inlet["name"], out["name"]],
193
+ "property": "c_M",
194
+ }
195
+ b[counter] = 0.0
196
+ counter += 1
197
+
198
+ # --- Chemical equality, if enabled: c_CH,inlet = c_CH,outlet_i ---
199
+ if chemical_exergy_enabled:
200
+ for out in (out0, out1):
201
+ if inlet["e_CH"] != 0 and out["e_CH"] != 0:
202
+ A[counter, inlet["CostVar_index"]["CH"]] = 1.0 / inlet["e_CH"]
203
+ A[counter, out["CostVar_index"]["CH"]] = -1.0 / out["e_CH"]
204
+ elif inlet["e_CH"] == 0 and out["e_CH"] != 0:
205
+ A[counter, inlet["CostVar_index"]["CH"]] = 1.0
206
+ elif inlet["e_CH"] != 0 and out["e_CH"] == 0:
207
+ A[counter, out["CostVar_index"]["CH"]] = 1.0
208
+ else:
209
+ A[counter, inlet["CostVar_index"]["CH"]] = 1.0
210
+ A[counter, out["CostVar_index"]["CH"]] = -1.0
211
+
212
+ equations[counter] = {
213
+ "kind": "aux_equality",
214
+ "objects": [self.name, inlet["name"], out["name"]],
215
+ "property": "c_CH",
216
+ }
217
+ b[counter] = 0.0
218
+ counter += 1
219
+
220
+ return A, b, counter, equations
221
+
222
+ def exergoeconomic_balance(self, T0, chemical_exergy_enabled=False):
223
+ r"""
224
+ Perform exergoeconomic cost balance for the flash tank.
225
+
226
+ The general cost balance is:
227
+
228
+ .. math::
229
+ \dot{C}^{\mathrm{T}}_{\mathrm{in}}
230
+ + \dot{C}^{\mathrm{M}}_{\mathrm{in}}
231
+ - \sum_{i=1}^{n} \dot{C}^{\mathrm{T}}_{\mathrm{out},i}
232
+ - \sum_{i=1}^{n} \dot{C}^{\mathrm{M}}_{\mathrm{out},i}
233
+ + \dot{Z}
234
+ = 0
235
+
236
+ Parameters
237
+ ----------
238
+ T0 : float
239
+ Ambient temperature
240
+ chemical_exergy_enabled : bool, optional
241
+ If True, chemical exergy is considered in the calculations.
242
+ """
243
+
244
+ # Calculate total cost of inlet streams (thermal + mechanical [+ chemical if enabled])
245
+ C_F = 0.0
246
+ for inlet in self.inl.values():
247
+ C_F += inlet["m"] * (inlet["c_T"] + inlet["c_M"])
248
+ if chemical_exergy_enabled:
249
+ C_F += inlet["m"] * inlet["c_CH"]
250
+ self.C_F = C_F
251
+
252
+ # Calculate total cost of outlet streams (thermal + mechanical [+ chemical if enabled])
253
+ C_P = 0.0
254
+ for outlet in self.outl.values():
255
+ C_P += outlet["m"] * (outlet["c_T"] + outlet["c_M"])
256
+ if chemical_exergy_enabled:
257
+ C_P += outlet["m"] * outlet["c_CH"]
258
+ self.C_P = C_P
259
+
260
+ self.c_F = self.C_F / self.E_F
261
+ self.c_P = self.C_P / self.E_P
262
+ self.C_D = self.c_F * self.E_D
263
+ self.r = (self.c_P - self.c_F) / self.c_F
264
+ self.f = self.Z_costs / (self.Z_costs + self.C_D)