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.
Files changed (48) hide show
  1. exerpy/__init__.py +2 -4
  2. exerpy/analyses.py +849 -304
  3. exerpy/components/__init__.py +3 -0
  4. exerpy/components/combustion/base.py +53 -35
  5. exerpy/components/component.py +8 -8
  6. exerpy/components/heat_exchanger/base.py +188 -121
  7. exerpy/components/heat_exchanger/condenser.py +98 -62
  8. exerpy/components/heat_exchanger/simple.py +237 -137
  9. exerpy/components/heat_exchanger/steam_generator.py +46 -41
  10. exerpy/components/helpers/cycle_closer.py +61 -34
  11. exerpy/components/helpers/power_bus.py +117 -0
  12. exerpy/components/nodes/deaerator.py +176 -58
  13. exerpy/components/nodes/drum.py +50 -39
  14. exerpy/components/nodes/flash_tank.py +218 -43
  15. exerpy/components/nodes/mixer.py +249 -69
  16. exerpy/components/nodes/splitter.py +173 -0
  17. exerpy/components/nodes/storage.py +130 -0
  18. exerpy/components/piping/valve.py +311 -115
  19. exerpy/components/power_machines/generator.py +105 -38
  20. exerpy/components/power_machines/motor.py +111 -39
  21. exerpy/components/turbomachinery/compressor.py +214 -68
  22. exerpy/components/turbomachinery/pump.py +215 -68
  23. exerpy/components/turbomachinery/turbine.py +182 -74
  24. exerpy/cost_estimation/__init__.py +65 -0
  25. exerpy/cost_estimation/turton.py +1260 -0
  26. exerpy/data/cost_correlations/cepci_index.json +135 -0
  27. exerpy/data/cost_correlations/component_mapping.json +450 -0
  28. exerpy/data/cost_correlations/material_factors.json +428 -0
  29. exerpy/data/cost_correlations/pressure_factors.json +206 -0
  30. exerpy/data/cost_correlations/turton2008.json +726 -0
  31. exerpy/data/cost_correlations/turton2008_design_analysis_synthesis_components_tables.pdf +0 -0
  32. exerpy/data/cost_correlations/turton2008_design_analysis_synthesis_components_theory.pdf +0 -0
  33. exerpy/functions.py +389 -264
  34. exerpy/parser/from_aspen/aspen_config.py +57 -48
  35. exerpy/parser/from_aspen/aspen_parser.py +373 -280
  36. exerpy/parser/from_ebsilon/__init__.py +2 -2
  37. exerpy/parser/from_ebsilon/check_ebs_path.py +15 -19
  38. exerpy/parser/from_ebsilon/ebsilon_config.py +328 -226
  39. exerpy/parser/from_ebsilon/ebsilon_functions.py +205 -38
  40. exerpy/parser/from_ebsilon/ebsilon_parser.py +392 -255
  41. exerpy/parser/from_ebsilon/utils.py +16 -11
  42. exerpy/parser/from_tespy/tespy_config.py +33 -1
  43. exerpy/parser/from_tespy/tespy_parser.py +151 -0
  44. {exerpy-0.0.2.dist-info → exerpy-0.0.4.dist-info}/METADATA +43 -2
  45. exerpy-0.0.4.dist-info/RECORD +57 -0
  46. exerpy-0.0.2.dist-info/RECORD +0 -44
  47. {exerpy-0.0.2.dist-info → exerpy-0.0.4.dist-info}/WHEEL +0 -0
  48. {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]['m'] * self.outl[0][exergy_type] - self.inl[0]['m'] * self.inl[0][exergy_type]
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('m', 0) * self.outl.get(1, {}).get(exergy_type, 0) - self.inl.get(1, {}).get('m', 0) * self.inl.get(1, {}).get(exergy_type, 0)
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('m', 0) * self.inl.get(2, {}).get(exergy_type, 0) + self.inl.get(3, {}).get('m', 0) * self.inl.get(3, {}).get(exergy_type, 0)
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(f"Since the temperature level of the heat source of the steam generator is unknown, "
158
- "the exergy fuel of this component is calculated based on the thermal exergy value of the water streams.")
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]['m'] * self.outl[0]['e_PH'] - self.inl[0]['m'] * self.inl[0]['e_PH']
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('m', 0) * self.outl.get(1, {}).get('e_PH', 0) - self.inl.get(1, {}).get('m', 0) * self.inl.get(1, {}).get('e_PH', 0)
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('m', 0) * self.inl.get(2, {}).get('e_PH', 0) + self.inl.get(3, {}).get('m', 0) * self.inl.get(3, {}).get('e_PH', 0)
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 exergy balance calculated: "
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 = (self.outl[0]['m'] * self.outl[0]['C_PH']
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 = (self.outl[1]['m'] * self.outl[1]['C_PH']
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]['m'] * self.inl[3]['C_PH']
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]['m'] * self.inl[4]['C_PH']
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]['C_T']
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('nan')
286
- self.c_P = self.C_P / self.E_P if self.E_P != 0 else float('nan')
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('nan')
289
- self.f = self.Z_costs / (self.Z_costs + self.C_D) if (self.Z_costs + self.C_D) != 0 else float('nan')
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 analyzed in exergy analysis.
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] = f"aux_cyclecloser_mech"
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"]] = (-1 / self.outl[0]["e_T"]) if self.outl[0]["e_T"] != 0 else -1
83
- equations[counter+1] = f"aux_cyclecloser_thermal"
84
- b[counter+1] = 0
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.C_F = np.nan
100
- self.c_F = np.nan
101
- self.c_P = np.nan
102
- self.C_D = np.nan
103
- self.r = np.nan
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