exerpy 0.0.2__py3-none-any.whl → 0.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- exerpy/__init__.py +2 -4
- exerpy/analyses.py +849 -304
- exerpy/components/__init__.py +3 -0
- exerpy/components/combustion/base.py +53 -35
- exerpy/components/component.py +8 -8
- exerpy/components/heat_exchanger/base.py +188 -121
- exerpy/components/heat_exchanger/condenser.py +98 -62
- exerpy/components/heat_exchanger/simple.py +237 -137
- exerpy/components/heat_exchanger/steam_generator.py +46 -41
- exerpy/components/helpers/cycle_closer.py +61 -34
- exerpy/components/helpers/power_bus.py +117 -0
- exerpy/components/nodes/deaerator.py +176 -58
- exerpy/components/nodes/drum.py +50 -39
- exerpy/components/nodes/flash_tank.py +218 -43
- exerpy/components/nodes/mixer.py +249 -69
- exerpy/components/nodes/splitter.py +173 -0
- exerpy/components/nodes/storage.py +130 -0
- exerpy/components/piping/valve.py +311 -115
- exerpy/components/power_machines/generator.py +105 -38
- exerpy/components/power_machines/motor.py +111 -39
- exerpy/components/turbomachinery/compressor.py +214 -68
- exerpy/components/turbomachinery/pump.py +215 -68
- exerpy/components/turbomachinery/turbine.py +182 -74
- exerpy/cost_estimation/__init__.py +65 -0
- exerpy/cost_estimation/turton.py +1260 -0
- exerpy/data/cost_correlations/cepci_index.json +135 -0
- exerpy/data/cost_correlations/component_mapping.json +450 -0
- exerpy/data/cost_correlations/material_factors.json +428 -0
- exerpy/data/cost_correlations/pressure_factors.json +206 -0
- exerpy/data/cost_correlations/turton2008.json +726 -0
- exerpy/data/cost_correlations/turton2008_design_analysis_synthesis_components_tables.pdf +0 -0
- exerpy/data/cost_correlations/turton2008_design_analysis_synthesis_components_theory.pdf +0 -0
- exerpy/functions.py +389 -264
- exerpy/parser/from_aspen/aspen_config.py +57 -48
- exerpy/parser/from_aspen/aspen_parser.py +373 -280
- exerpy/parser/from_ebsilon/__init__.py +2 -2
- exerpy/parser/from_ebsilon/check_ebs_path.py +15 -19
- exerpy/parser/from_ebsilon/ebsilon_config.py +328 -226
- exerpy/parser/from_ebsilon/ebsilon_functions.py +205 -38
- exerpy/parser/from_ebsilon/ebsilon_parser.py +392 -255
- exerpy/parser/from_ebsilon/utils.py +16 -11
- exerpy/parser/from_tespy/tespy_config.py +33 -1
- exerpy/parser/from_tespy/tespy_parser.py +151 -0
- {exerpy-0.0.2.dist-info → exerpy-0.0.4.dist-info}/METADATA +43 -2
- exerpy-0.0.4.dist-info/RECORD +57 -0
- exerpy-0.0.2.dist-info/RECORD +0 -44
- {exerpy-0.0.2.dist-info → exerpy-0.0.4.dist-info}/WHEEL +0 -0
- {exerpy-0.0.2.dist-info → exerpy-0.0.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
|
-
from exerpy.components.component import Component
|
|
4
|
-
from exerpy.components.component import component_registry
|
|
3
|
+
from exerpy.components.component import Component, component_registry
|
|
5
4
|
|
|
6
5
|
|
|
7
6
|
@component_registry
|
|
@@ -76,14 +75,14 @@ class SteamGenerator(Component):
|
|
|
76
75
|
Arbitrary keyword arguments. Recognized keys:
|
|
77
76
|
- Ex_C_col (dict): custom cost coefficients, default {}
|
|
78
77
|
- Z_costs (float): investment cost rate in currency/h, default 0.0
|
|
79
|
-
"""
|
|
78
|
+
"""
|
|
80
79
|
super().__init__(**kwargs)
|
|
81
80
|
|
|
82
81
|
def calc_exergy_balance(self, T0: float, p0: float, split_physical_exergy) -> None:
|
|
83
82
|
r"""
|
|
84
83
|
Compute the exergy balance of the steam generator.
|
|
85
84
|
|
|
86
|
-
The exergy fuel is defined as follows.
|
|
85
|
+
The exergy fuel is defined as follows.
|
|
87
86
|
|
|
88
87
|
If `split_physical_exergy` is `True`:
|
|
89
88
|
|
|
@@ -141,28 +140,35 @@ class SteamGenerator(Component):
|
|
|
141
140
|
if idx not in self.outl:
|
|
142
141
|
raise ValueError(f"Missing outlet stream with index {idx}.")
|
|
143
142
|
|
|
144
|
-
if split_physical_exergy
|
|
145
|
-
exergy_type = 'e_T'
|
|
146
|
-
else:
|
|
147
|
-
exergy_type = 'e_PH'
|
|
143
|
+
exergy_type = "e_T" if split_physical_exergy else "e_PH"
|
|
148
144
|
|
|
149
145
|
# Calculate exergy fuel
|
|
150
146
|
# High pressure part: Superheated steam outlet (HP) minus Feed water inlet (HP)
|
|
151
|
-
E_F_HP = self.outl[0][
|
|
147
|
+
E_F_HP = self.outl[0]["m"] * self.outl[0][exergy_type] - self.inl[0]["m"] * self.inl[0][exergy_type]
|
|
152
148
|
# Intermediate pressure part: Superheated steam outlet (IP) minus Steam inlet (IP)
|
|
153
|
-
E_F_IP = self.outl.get(1, {}).get(
|
|
149
|
+
E_F_IP = self.outl.get(1, {}).get("m", 0) * self.outl.get(1, {}).get(exergy_type, 0) - self.inl.get(1, {}).get(
|
|
150
|
+
"m", 0
|
|
151
|
+
) * self.inl.get(1, {}).get(exergy_type, 0)
|
|
154
152
|
# Water injection contributions (assumed to be negative)
|
|
155
|
-
E_F_w_inj = self.inl.get(2, {}).get(
|
|
153
|
+
E_F_w_inj = self.inl.get(2, {}).get("m", 0) * self.inl.get(2, {}).get(exergy_type, 0) + self.inl.get(3, {}).get(
|
|
154
|
+
"m", 0
|
|
155
|
+
) * self.inl.get(3, {}).get(exergy_type, 0)
|
|
156
156
|
self.E_F = E_F_HP + E_F_IP - E_F_w_inj
|
|
157
|
-
logging.warning(
|
|
158
|
-
|
|
157
|
+
logging.warning(
|
|
158
|
+
"Since the temperature level of the heat source of the steam generator is unknown, "
|
|
159
|
+
"the exergy fuel of this component is calculated based on the thermal exergy value of the water streams."
|
|
160
|
+
)
|
|
159
161
|
# Calculate exergy product
|
|
160
162
|
# High pressure part: Superheated steam outlet (HP) minus Feed water inlet (HP)
|
|
161
|
-
E_P_HP = self.outl[0][
|
|
163
|
+
E_P_HP = self.outl[0]["m"] * self.outl[0]["e_PH"] - self.inl[0]["m"] * self.inl[0]["e_PH"]
|
|
162
164
|
# Intermediate pressure part: Superheated steam outlet (IP) minus Steam inlet (IP)
|
|
163
|
-
E_P_IP = self.outl.get(1, {}).get(
|
|
165
|
+
E_P_IP = self.outl.get(1, {}).get("m", 0) * self.outl.get(1, {}).get("e_PH", 0) - self.inl.get(1, {}).get(
|
|
166
|
+
"m", 0
|
|
167
|
+
) * self.inl.get(1, {}).get("e_PH", 0)
|
|
164
168
|
# Water injection contributions (assumed to be negative)
|
|
165
|
-
E_P_w_inj = self.inl.get(2, {}).get(
|
|
169
|
+
E_P_w_inj = self.inl.get(2, {}).get("m", 0) * self.inl.get(2, {}).get("e_PH", 0) + self.inl.get(3, {}).get(
|
|
170
|
+
"m", 0
|
|
171
|
+
) * self.inl.get(3, {}).get("e_PH", 0)
|
|
166
172
|
self.E_P = E_P_HP + E_P_IP - E_P_w_inj
|
|
167
173
|
|
|
168
174
|
# Calculate exergy destruction and efficiency
|
|
@@ -171,12 +177,11 @@ class SteamGenerator(Component):
|
|
|
171
177
|
|
|
172
178
|
# Log the results
|
|
173
179
|
logging.info(
|
|
174
|
-
f"SteamGenerator
|
|
180
|
+
f"Exergy balance of SteamGenerator {self.name} calculated: "
|
|
175
181
|
f"E_P = {self.E_P:.2f} W, E_F = {self.E_F:.2f} W, "
|
|
176
182
|
f"E_D = {self.E_D:.2f} W, Efficiency = {self.epsilon:.2%}"
|
|
177
183
|
)
|
|
178
184
|
|
|
179
|
-
|
|
180
185
|
def aux_eqs(self, A, b, counter, T0, equations, chemical_exergy_enabled):
|
|
181
186
|
r"""
|
|
182
187
|
This function must be implemented in the future.
|
|
@@ -189,22 +194,22 @@ class SteamGenerator(Component):
|
|
|
189
194
|
)
|
|
190
195
|
"""
|
|
191
196
|
Auxiliary equations for the steam generator.
|
|
192
|
-
|
|
197
|
+
|
|
193
198
|
This function adds rows to the cost matrix A and the right-hand-side vector b to enforce
|
|
194
199
|
the following auxiliary cost relations:
|
|
195
|
-
|
|
200
|
+
|
|
196
201
|
(1) c_T(heat_source)/E_F = c_T(HP_outlet)/E_T(HP) + c_T(IP_outlet)/E_T(IP)
|
|
197
202
|
- P-principle: thermal exergy costs from heat source are distributed to steam outlets
|
|
198
|
-
|
|
203
|
+
|
|
199
204
|
(2) 1/E_M_in(HP) * C_M_in(HP) - 1/E_M_out(HP) * C_M_out(HP) = 0
|
|
200
205
|
- F-principle: specific mechanical exergy costs equalized between HP inlet/outlet
|
|
201
|
-
|
|
206
|
+
|
|
202
207
|
(3) 1/E_M_in(IP) * C_M_in(IP) - 1/E_M_out(IP) * C_M_out(IP) = 0
|
|
203
208
|
- F-principle: specific mechanical exergy costs equalized between IP inlet/outlet
|
|
204
|
-
|
|
209
|
+
|
|
205
210
|
(4-5) Chemical exergy cost equations (if enabled) for HP and IP streams
|
|
206
211
|
- F-principle: specific chemical exergy costs equalized between inlets/outlets
|
|
207
|
-
|
|
212
|
+
|
|
208
213
|
Parameters
|
|
209
214
|
----------
|
|
210
215
|
A : numpy.ndarray
|
|
@@ -219,7 +224,7 @@ class SteamGenerator(Component):
|
|
|
219
224
|
Dictionary for storing equation labels.
|
|
220
225
|
chemical_exergy_enabled : bool
|
|
221
226
|
Flag indicating whether chemical exergy auxiliary equations should be added.
|
|
222
|
-
|
|
227
|
+
|
|
223
228
|
Returns
|
|
224
229
|
-------
|
|
225
230
|
A : numpy.ndarray
|
|
@@ -232,58 +237,58 @@ class SteamGenerator(Component):
|
|
|
232
237
|
Updated dictionary with equation labels.
|
|
233
238
|
"""
|
|
234
239
|
|
|
235
|
-
def exergoeconomic_balance(self, T0):
|
|
240
|
+
def exergoeconomic_balance(self, T0, chemical_exergy_enabled=False):
|
|
236
241
|
r"""
|
|
237
242
|
This function must be implemented in the future.
|
|
238
243
|
|
|
239
244
|
The exergoeconomic analysis of SteamGenerator is not implemented yet.
|
|
240
245
|
"""
|
|
241
|
-
|
|
246
|
+
|
|
242
247
|
logging.error(
|
|
243
248
|
"The exergoeconomic analysis of SteamGenerator is not implemented yet. "
|
|
244
249
|
"This method will be implemented in a future release."
|
|
245
250
|
)
|
|
246
251
|
"""
|
|
247
252
|
Perform exergoeconomic balance calculations for the steam generator.
|
|
248
|
-
|
|
253
|
+
|
|
249
254
|
This method calculates various exergoeconomic parameters including:
|
|
250
255
|
- Cost rates of product (C_P) and fuel (C_F)
|
|
251
256
|
- Specific cost of product (c_P) and fuel (c_F)
|
|
252
257
|
- Cost rate of exergy destruction (C_D)
|
|
253
258
|
- Relative cost difference (r)
|
|
254
259
|
- Exergoeconomic factor (f)
|
|
255
|
-
|
|
260
|
+
|
|
256
261
|
Parameters
|
|
257
262
|
----------
|
|
258
263
|
T0 : float
|
|
259
264
|
Ambient temperature
|
|
260
|
-
|
|
265
|
+
chemical_exergy_enabled : bool, optional
|
|
266
|
+
If True, chemical exergy is considered in the calculations.
|
|
267
|
+
|
|
261
268
|
Notes
|
|
262
269
|
-----
|
|
263
270
|
The exergoeconomic balance considers thermal (T), chemical (CH),
|
|
264
271
|
and mechanical (M) exergy components for the inlet and outlet streams.
|
|
265
272
|
"""
|
|
266
273
|
# 1) Product cost rate: HP and IP steam net physical exergy costs, minus injection
|
|
267
|
-
C_P_hp =
|
|
268
|
-
- self.inl[0]['m'] * self.inl[0]['C_PH'])
|
|
274
|
+
C_P_hp = self.outl[0]["m"] * self.outl[0]["C_PH"] - self.inl[0]["m"] * self.inl[0]["C_PH"]
|
|
269
275
|
C_P_ip = 0.0
|
|
270
276
|
if 1 in self.outl and 1 in self.inl:
|
|
271
|
-
C_P_ip =
|
|
272
|
-
- self.inl[1]['m'] * self.inl[1]['C_PH'])
|
|
277
|
+
C_P_ip = self.outl[1]["m"] * self.outl[1]["C_PH"] - self.inl[1]["m"] * self.inl[1]["C_PH"]
|
|
273
278
|
# Subtract water injection costs
|
|
274
279
|
C_P_w = 0.0
|
|
275
280
|
if 3 in self.inl:
|
|
276
|
-
C_P_w += self.inl[3][
|
|
281
|
+
C_P_w += self.inl[3]["m"] * self.inl[3]["C_PH"]
|
|
277
282
|
if 4 in self.inl:
|
|
278
|
-
C_P_w += self.inl[4][
|
|
283
|
+
C_P_w += self.inl[4]["m"] * self.inl[4]["C_PH"]
|
|
279
284
|
self.C_P = C_P_hp + C_P_ip - C_P_w
|
|
280
285
|
|
|
281
286
|
# 2) Fuel cost rate: cost of heat exergy stream
|
|
282
|
-
self.C_F = self.inl[2][
|
|
287
|
+
self.C_F = self.inl[2]["C_T"]
|
|
283
288
|
|
|
284
289
|
# 3) Specific costs and destruction cost
|
|
285
|
-
self.c_F = self.C_F / self.E_F if self.E_F != 0 else float(
|
|
286
|
-
self.c_P = self.C_P / self.E_P if self.E_P != 0 else float(
|
|
290
|
+
self.c_F = self.C_F / self.E_F if self.E_F != 0 else float("nan")
|
|
291
|
+
self.c_P = self.C_P / self.E_P if self.E_P != 0 else float("nan")
|
|
287
292
|
self.C_D = self.C_F - self.C_P
|
|
288
|
-
self.r = (self.c_P - self.c_F) / self.c_F if self.c_F != 0 else float(
|
|
289
|
-
self.f = self.Z_costs / (self.Z_costs + self.C_D) if (self.Z_costs + self.C_D) != 0 else float(
|
|
293
|
+
self.r = (self.c_P - self.c_F) / self.c_F if self.c_F != 0 else float("nan")
|
|
294
|
+
self.f = self.Z_costs / (self.Z_costs + self.C_D) if (self.Z_costs + self.C_D) != 0 else float("nan")
|
|
@@ -2,15 +2,15 @@ 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 CycleCloser(Component):
|
|
11
10
|
r"""
|
|
12
|
-
Component for closing cycles. This component is not
|
|
11
|
+
Component for closing cycles. This component is not considered in exergy analysis, but it is used in exergoeconomic analysis.
|
|
13
12
|
"""
|
|
13
|
+
|
|
14
14
|
def __init__(self, **kwargs):
|
|
15
15
|
r"""Initialize CycleCloser component with given parameters."""
|
|
16
16
|
super().__init__(**kwargs)
|
|
@@ -18,7 +18,7 @@ class CycleCloser(Component):
|
|
|
18
18
|
def calc_exergy_balance(self, T0: float, p0: float, split_physical_exergy) -> None:
|
|
19
19
|
r"""
|
|
20
20
|
The CycleCloser component does not have an exergy balance calculation.
|
|
21
|
-
"""
|
|
21
|
+
"""
|
|
22
22
|
self.E_D = np.nan
|
|
23
23
|
self.E_F = np.nan
|
|
24
24
|
self.E_P = np.nan
|
|
@@ -26,24 +26,21 @@ class CycleCloser(Component):
|
|
|
26
26
|
self.epsilon = np.nan
|
|
27
27
|
|
|
28
28
|
# Log the results
|
|
29
|
-
logging.info(
|
|
30
|
-
f"The exergy balance of a CycleCloser component is skipped."
|
|
31
|
-
)
|
|
29
|
+
logging.info(f"The exergy balance of a CycleCloser {self.name} is skipped.")
|
|
32
30
|
|
|
33
|
-
|
|
34
31
|
def aux_eqs(self, A, b, counter, T0, equations, chemical_exergy_enabled):
|
|
35
32
|
"""
|
|
36
33
|
Auxiliary equations for the cycle closer.
|
|
37
|
-
|
|
38
|
-
This function adds two rows to the cost matrix A and the right-hand side vector b to enforce
|
|
34
|
+
|
|
35
|
+
This function adds two rows to the cost matrix A and the right-hand side vector b to enforce
|
|
39
36
|
the following auxiliary cost relations:
|
|
40
|
-
|
|
37
|
+
|
|
41
38
|
(1) 1/E_M_in * C_M_in - 1/E_M_out * C_M_out = 0
|
|
42
39
|
(2) 1/E_T_in * C_T_in - 1/E_T_out * C_T_out = 0
|
|
43
|
-
|
|
44
|
-
These equations ensure that the specific mechanical and thermal costs are equalized between
|
|
40
|
+
|
|
41
|
+
These equations ensure that the specific mechanical and thermal costs are equalized between
|
|
45
42
|
the inlet and outlet of the cycle closer. Chemical exergy is not considered for the cycle closer.
|
|
46
|
-
|
|
43
|
+
|
|
47
44
|
Parameters
|
|
48
45
|
----------
|
|
49
46
|
A : numpy.ndarray
|
|
@@ -59,7 +56,7 @@ class CycleCloser(Component):
|
|
|
59
56
|
chemical_exergy_enabled : bool
|
|
60
57
|
Flag indicating whether chemical exergy auxiliary equations should be added.
|
|
61
58
|
This flag is ignored for CycleCloser.
|
|
62
|
-
|
|
59
|
+
|
|
63
60
|
Returns
|
|
64
61
|
-------
|
|
65
62
|
A : numpy.ndarray
|
|
@@ -74,31 +71,61 @@ class CycleCloser(Component):
|
|
|
74
71
|
# Mechanical cost equality equation:
|
|
75
72
|
A[counter, self.inl[0]["CostVar_index"]["M"]] = (1 / self.inl[0]["e_M"]) if self.inl[0]["e_M"] != 0 else 1
|
|
76
73
|
A[counter, self.outl[0]["CostVar_index"]["M"]] = (-1 / self.outl[0]["e_M"]) if self.outl[0]["e_M"] != 0 else -1
|
|
77
|
-
equations[counter] =
|
|
74
|
+
equations[counter] = {
|
|
75
|
+
"kind": "aux_equality",
|
|
76
|
+
"objects": [self.name, self.inl[0]["name"], self.outl[0]["name"]],
|
|
77
|
+
"property": "c_M",
|
|
78
|
+
}
|
|
78
79
|
b[counter] = 0
|
|
79
80
|
|
|
80
81
|
# Thermal cost equality equation:
|
|
81
|
-
A[counter+1, self.inl[0]["CostVar_index"]["T"]] = (1 / self.inl[0]["e_T"]) if self.inl[0]["e_T"] != 0 else 1
|
|
82
|
-
A[counter+1, self.outl[0]["CostVar_index"]["T"]] = (
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
A[counter + 1, self.inl[0]["CostVar_index"]["T"]] = (1 / self.inl[0]["e_T"]) if self.inl[0]["e_T"] != 0 else 1
|
|
83
|
+
A[counter + 1, self.outl[0]["CostVar_index"]["T"]] = (
|
|
84
|
+
(-1 / self.outl[0]["e_T"]) if self.outl[0]["e_T"] != 0 else -1
|
|
85
|
+
)
|
|
86
|
+
equations[counter + 1] = {
|
|
87
|
+
"kind": "aux_equality",
|
|
88
|
+
"objects": [self.name, self.inl[0]["name"], self.outl[0]["name"]],
|
|
89
|
+
"property": "c_T",
|
|
90
|
+
}
|
|
91
|
+
b[counter + 1] = 0
|
|
85
92
|
|
|
86
93
|
counter += 2
|
|
94
|
+
|
|
95
|
+
if chemical_exergy_enabled:
|
|
96
|
+
# Chemical cost equality equation:
|
|
97
|
+
A[counter, self.inl[0]["CostVar_index"]["CH"]] = (1 / self.inl[0]["e_C"]) if self.inl[0]["e_CH"] != 0 else 1
|
|
98
|
+
A[counter, self.outl[0]["CostVar_index"]["CH"]] = (
|
|
99
|
+
(-1 / self.outl[0]["e_C"]) if self.outl[0]["e_CH"] != 0 else -1
|
|
100
|
+
)
|
|
101
|
+
equations[counter] = {
|
|
102
|
+
"kind": "aux_equality",
|
|
103
|
+
"objects": [self.name, self.inl[0]["name"], self.outl[0]["name"]],
|
|
104
|
+
"property": "c_CH",
|
|
105
|
+
}
|
|
106
|
+
b[counter] = 0
|
|
107
|
+
|
|
108
|
+
counter += 1
|
|
109
|
+
|
|
87
110
|
return A, b, counter, equations
|
|
88
|
-
|
|
89
|
-
def exergoeconomic_balance(self, T0):
|
|
90
|
-
"""
|
|
91
|
-
Placeholder for exergoeconomic balance calculations.
|
|
92
|
-
|
|
93
|
-
The CycleCloser component is not considered in exergoeconomic analysis
|
|
94
|
-
and all calculations are skipped. NaN values are assigned to all
|
|
95
|
-
exergoeconomic parameters.
|
|
111
|
+
|
|
112
|
+
def exergoeconomic_balance(self, T0, chemical_exergy_enabled=False) -> None:
|
|
96
113
|
"""
|
|
114
|
+
Exergoeconomic balance for the CycleCloser is not defined.
|
|
115
|
+
|
|
116
|
+
This component does not generate or consume exergy, so all cost terms are undefined.
|
|
97
117
|
|
|
118
|
+
Parameters
|
|
119
|
+
----------
|
|
120
|
+
T0 : float
|
|
121
|
+
Ambient temperature (unused).
|
|
122
|
+
chemical_exergy_enabled : bool, optional
|
|
123
|
+
If True, chemical exergy is considered in the calculations.
|
|
124
|
+
"""
|
|
125
|
+
self.C_F = np.nan
|
|
98
126
|
self.C_P = np.nan
|
|
99
|
-
self.
|
|
100
|
-
self.
|
|
101
|
-
self.
|
|
102
|
-
self.
|
|
103
|
-
self.
|
|
104
|
-
self.f = np.nan
|
|
127
|
+
self.C_D = np.nan
|
|
128
|
+
self.c_TOT = np.nan
|
|
129
|
+
self.C_TOT = np.nan
|
|
130
|
+
self.r = np.nan
|
|
131
|
+
self.f = np.nan
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from exerpy.components.component import Component, component_registry
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@component_registry
|
|
9
|
+
class PowerBus(Component):
|
|
10
|
+
r"""
|
|
11
|
+
Component for power busses. This component is not considered in exergy analysis, but it is used in exergoeconomic analysis.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(self, **kwargs):
|
|
15
|
+
r"""Initialize CycleCloser component with given parameters."""
|
|
16
|
+
super().__init__(**kwargs)
|
|
17
|
+
|
|
18
|
+
def calc_exergy_balance(self, T0: float, p0: float, split_physical_exergy) -> None:
|
|
19
|
+
r"""
|
|
20
|
+
The PowerBus component does not have an exergy balance calculation.
|
|
21
|
+
"""
|
|
22
|
+
self.E_D = np.nan
|
|
23
|
+
self.E_F = np.nan
|
|
24
|
+
self.E_P = np.nan
|
|
25
|
+
self.E_L = np.nan
|
|
26
|
+
self.epsilon = np.nan
|
|
27
|
+
|
|
28
|
+
# Log the results
|
|
29
|
+
logging.info(f"The exergy balance of a PowerBus {self.name} is skipped.")
|
|
30
|
+
|
|
31
|
+
def aux_eqs(self, A, b, counter, T0, equations, chemical_exergy_enabled):
|
|
32
|
+
"""
|
|
33
|
+
Auxiliary equations for the cycle closer.
|
|
34
|
+
|
|
35
|
+
This function adds two rows to the cost matrix A and the right-hand side vector b to enforce
|
|
36
|
+
the following auxiliary cost relations:
|
|
37
|
+
|
|
38
|
+
(1) 1/E_M_in * C_M_in - 1/E_M_out * C_M_out = 0
|
|
39
|
+
(2) 1/E_T_in * C_T_in - 1/E_T_out * C_T_out = 0
|
|
40
|
+
|
|
41
|
+
These equations ensure that the specific mechanical and thermal costs are equalized between
|
|
42
|
+
the inlet and outlet of the cycle closer. Chemical exergy is not considered for the cycle closer.
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
A : numpy.ndarray
|
|
47
|
+
The current cost matrix.
|
|
48
|
+
b : numpy.ndarray
|
|
49
|
+
The current right-hand-side vector.
|
|
50
|
+
counter : int
|
|
51
|
+
The current row index in the matrix.
|
|
52
|
+
T0 : float
|
|
53
|
+
Ambient temperature (not used in this component).
|
|
54
|
+
equations : list or dict
|
|
55
|
+
Data structure for storing equation labels.
|
|
56
|
+
chemical_exergy_enabled : bool
|
|
57
|
+
Flag indicating whether chemical exergy auxiliary equations should be added.
|
|
58
|
+
This flag is ignored for CycleCloser.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
A : numpy.ndarray
|
|
63
|
+
The updated cost matrix.
|
|
64
|
+
b : numpy.ndarray
|
|
65
|
+
The updated right-hand-side vector.
|
|
66
|
+
counter : int
|
|
67
|
+
The updated row index (increased by 2).
|
|
68
|
+
equations : list or dict
|
|
69
|
+
Updated structure with equation labels.
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
# Splitter case
|
|
73
|
+
if len(self.inl) >= 1 and len(self.outl) <= 1:
|
|
74
|
+
logging.info(f"PowerBus {self.name} has only one output, no auxiliary equations added.")
|
|
75
|
+
|
|
76
|
+
# Mixer case
|
|
77
|
+
elif len(self.inl) == 1 and len(self.outl) > 1:
|
|
78
|
+
logging.info(f"PowerBus {self.name} has multiple outputs, auxiliary equations will be added.")
|
|
79
|
+
for out in list(self.outl.values())[:]:
|
|
80
|
+
A[counter, self.inl[0]["CostVar_index"]["exergy"]] = (
|
|
81
|
+
(1 / self.inl[0]["E"]) if self.inl[0]["E"] != 0 else 1
|
|
82
|
+
)
|
|
83
|
+
A[counter, out["CostVar_index"]["exergy"]] = (-1 / out["E"]) if out["E"] != 0 else -1
|
|
84
|
+
equations[counter] = {
|
|
85
|
+
"kind": "aux_power_eq",
|
|
86
|
+
"objects": [self.name, self.inl[0]["name"], out["name"]],
|
|
87
|
+
"property": "c_TOT",
|
|
88
|
+
}
|
|
89
|
+
b[counter] = 0
|
|
90
|
+
counter += 1
|
|
91
|
+
|
|
92
|
+
# Mixer case with multiple inputs and outputs
|
|
93
|
+
else:
|
|
94
|
+
logging.error(f"PowerBus {self.name} has multiple inputs and outputs, which has not been implemented yet.")
|
|
95
|
+
|
|
96
|
+
return A, b, counter, equations
|
|
97
|
+
|
|
98
|
+
def exergoeconomic_balance(self, T0, chemical_exergy_enabled=False) -> None:
|
|
99
|
+
"""
|
|
100
|
+
Exergoeconomic balance for the PowerBus is not defined.
|
|
101
|
+
|
|
102
|
+
This component does not convert or destroy exergy, so all cost terms are undefined.
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
T0 : float
|
|
107
|
+
Ambient temperature (unused).
|
|
108
|
+
chemical_exergy_enabled : bool, optional
|
|
109
|
+
If True, chemical exergy is considered in the calculations.
|
|
110
|
+
"""
|
|
111
|
+
self.C_F = np.nan
|
|
112
|
+
self.C_P = np.nan
|
|
113
|
+
self.C_D = np.nan
|
|
114
|
+
self.c_TOT = np.nan
|
|
115
|
+
self.C_TOT = np.nan
|
|
116
|
+
self.r = np.nan
|
|
117
|
+
self.f = np.nan
|