exerpy 0.0.1__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 (44) hide show
  1. exerpy/__init__.py +12 -0
  2. exerpy/analyses.py +1711 -0
  3. exerpy/components/__init__.py +16 -0
  4. exerpy/components/combustion/__init__.py +0 -0
  5. exerpy/components/combustion/base.py +248 -0
  6. exerpy/components/component.py +126 -0
  7. exerpy/components/heat_exchanger/__init__.py +0 -0
  8. exerpy/components/heat_exchanger/base.py +449 -0
  9. exerpy/components/heat_exchanger/condenser.py +323 -0
  10. exerpy/components/heat_exchanger/simple.py +358 -0
  11. exerpy/components/heat_exchanger/steam_generator.py +264 -0
  12. exerpy/components/helpers/__init__.py +0 -0
  13. exerpy/components/helpers/cycle_closer.py +104 -0
  14. exerpy/components/nodes/__init__.py +0 -0
  15. exerpy/components/nodes/deaerator.py +318 -0
  16. exerpy/components/nodes/drum.py +164 -0
  17. exerpy/components/nodes/flash_tank.py +89 -0
  18. exerpy/components/nodes/mixer.py +332 -0
  19. exerpy/components/piping/__init__.py +0 -0
  20. exerpy/components/piping/valve.py +394 -0
  21. exerpy/components/power_machines/__init__.py +0 -0
  22. exerpy/components/power_machines/generator.py +168 -0
  23. exerpy/components/power_machines/motor.py +173 -0
  24. exerpy/components/turbomachinery/__init__.py +0 -0
  25. exerpy/components/turbomachinery/compressor.py +318 -0
  26. exerpy/components/turbomachinery/pump.py +310 -0
  27. exerpy/components/turbomachinery/turbine.py +351 -0
  28. exerpy/data/Ahrendts.json +90 -0
  29. exerpy/functions.py +637 -0
  30. exerpy/parser/__init__.py +0 -0
  31. exerpy/parser/from_aspen/__init__.py +0 -0
  32. exerpy/parser/from_aspen/aspen_config.py +61 -0
  33. exerpy/parser/from_aspen/aspen_parser.py +721 -0
  34. exerpy/parser/from_ebsilon/__init__.py +38 -0
  35. exerpy/parser/from_ebsilon/check_ebs_path.py +74 -0
  36. exerpy/parser/from_ebsilon/ebsilon_config.py +1055 -0
  37. exerpy/parser/from_ebsilon/ebsilon_functions.py +181 -0
  38. exerpy/parser/from_ebsilon/ebsilon_parser.py +660 -0
  39. exerpy/parser/from_ebsilon/utils.py +79 -0
  40. exerpy/parser/from_tespy/tespy_config.py +23 -0
  41. exerpy-0.0.1.dist-info/METADATA +158 -0
  42. exerpy-0.0.1.dist-info/RECORD +44 -0
  43. exerpy-0.0.1.dist-info/WHEEL +4 -0
  44. exerpy-0.0.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,16 @@
1
+ from .combustion.base import CombustionChamber
2
+ from .heat_exchanger.base import HeatExchanger
3
+ from .heat_exchanger.condenser import Condenser
4
+ from .heat_exchanger.simple import SimpleHeatExchanger
5
+ from .heat_exchanger.steam_generator import SteamGenerator
6
+ from .helpers.cycle_closer import CycleCloser
7
+ from .nodes.deaerator import Deaerator
8
+ from .nodes.drum import Drum
9
+ from .nodes.flash_tank import FlashTank
10
+ from .nodes.mixer import Mixer
11
+ from .piping.valve import Valve
12
+ from .power_machines.generator import Generator
13
+ from .power_machines.motor import Motor
14
+ from .turbomachinery.compressor import Compressor
15
+ from .turbomachinery.pump import Pump
16
+ from .turbomachinery.turbine import Turbine
File without changes
@@ -0,0 +1,248 @@
1
+ import logging
2
+
3
+ import numpy as np
4
+
5
+ from exerpy.components.component import Component
6
+ from exerpy.components.component import component_registry
7
+
8
+
9
+ @component_registry
10
+ class CombustionChamber(Component):
11
+ r"""
12
+ Class for exergy and exergoeconomic analysis of combustion chambers.
13
+
14
+ This class performs exergy and exergoeconomic analysis calculations for combustion chambers,
15
+ considering both thermal and mechanical exergy flows, as well as chemical exergy flows.
16
+ The exergy product is defined based on thermal and mechanical exergy differences,
17
+ while the exergy fuel is based on chemical exergy differences.
18
+
19
+ Parameters
20
+ ----------
21
+ **kwargs : dict
22
+ Arbitrary keyword arguments passed to parent class.
23
+ Optional parameter 'Z_costs' (float): Investment cost rate of the component in currency/h.
24
+
25
+ Attributes
26
+ ----------
27
+ E_F : float
28
+ Exergy fuel of the component :math:`\dot{E}_\mathrm{F}` in :math:`\mathrm{W}`.
29
+ E_P : float
30
+ Exergy product of the component :math:`\dot{E}_\mathrm{P}` in :math:`\mathrm{W}`.
31
+ E_D : float
32
+ Exergy destruction of the component :math:`\dot{E}_\mathrm{D}` in :math:`\mathrm{W}`.
33
+ epsilon : float
34
+ Exergetic efficiency of the component :math:`\varepsilon` in :math:`-`.
35
+ inl : dict
36
+ Dictionary containing inlet stream data with mass flows and specific exergies.
37
+ outl : dict
38
+ Dictionary containing outlet stream data with mass flows and specific exergies.
39
+ Z_costs : float
40
+ Investment cost rate of the component in currency/h.
41
+
42
+ Notes
43
+ -----
44
+ The exergy analysis considers the following definitions:
45
+
46
+ .. math::
47
+ \dot{E}_\mathrm{P} &= \sum_{out} \dot{m}_{out} \cdot e^\mathrm{T}_{out}
48
+ + \sum_{out} \dot{m}_{out} \cdot e^\mathrm{M}_{out}
49
+ - \sum_{in} \dot{m}_{in} \cdot e^\mathrm{T}_{in}
50
+ - \sum_{in} \dot{m}_{in} \cdot e^\mathrm{M}_{in}
51
+
52
+ .. math::
53
+ \dot{E}_\mathrm{F} &= \sum_{in} \dot{m}_{in} \cdot e^\mathrm{CH}_{in}
54
+ - \sum_{out} \dot{m}_{out} \cdot e^\mathrm{CH}_{out}
55
+
56
+ The exergetic efficiency is calculated as:
57
+
58
+ .. math::
59
+ \varepsilon = \frac{\dot{E}_\mathrm{P}}{\dot{E}_\mathrm{F}}
60
+
61
+ The exergy destruction follows from the exergy balance:
62
+
63
+ .. math::
64
+ \dot{E}_\mathrm{D} = \dot{E}_\mathrm{F} - \dot{E}_\mathrm{P}
65
+ """
66
+
67
+ def __init__(self, **kwargs):
68
+ r"""Initialize combustion chamber component with given parameters."""
69
+ super().__init__(**kwargs)
70
+ # Initialize additional attributes if necessary
71
+ self.Ex_C_col = kwargs.get('Ex_C_col', {})
72
+ self.Z_costs = kwargs.get('Z_costs', 0.0) # Cost rate in currency/h
73
+
74
+ def calc_exergy_balance(self, T0: float, p0: float, split_physical_exergy) -> None:
75
+ r"""
76
+ Calculate the exergy balance of the combustion chamber.
77
+
78
+ Performs exergy balance calculations considering both physical and chemical
79
+ exergy flows. The exergy product is based on physical exergy differences,
80
+ while the exergy fuel is based on chemical exergy differences.
81
+
82
+ Parameters
83
+ ----------
84
+ T0 : float
85
+ Ambient temperature in :math:`\mathrm{K}`.
86
+ p0 : float
87
+ Ambient pressure in :math:`\mathrm{Pa}`.
88
+
89
+ Raises
90
+ ------
91
+ ValueError
92
+ If the required inlet and outlet streams are not properly defined.
93
+ """
94
+ # Check for necessary inlet and outlet data
95
+ if not hasattr(self, 'inl') or not hasattr(self, 'outl') or len(self.inl) < 2 or len(self.outl) < 1:
96
+ msg = "CombustionChamber requires at least two inlets (air and fuel) and one outlet (exhaust)."
97
+ logging.error(msg)
98
+ raise ValueError(msg)
99
+
100
+ # Calculate total physical exergy of outlets
101
+ total_E_P_out = sum(outlet['m'] * outlet['e_PH'] for outlet in self.outl.values())
102
+
103
+ # Calculate total physical exergy of inlets
104
+ total_E_P_in = sum(inlet['m'] * inlet['e_PH'] for inlet in self.inl.values())
105
+
106
+ # Exergy Product (E_P)
107
+ self.E_P = total_E_P_out - total_E_P_in
108
+
109
+ # Calculate total chemical exergy of inlets
110
+ total_E_F_in = sum(inlet['m'] * inlet['e_CH'] for inlet in self.inl.values())
111
+
112
+ # Calculate total chemical exergy of outlets
113
+ total_E_F_out = sum(outlet['m'] * outlet['e_CH'] for outlet in self.outl.values())
114
+
115
+ # Exergy Fuel (E_F)
116
+ self.E_F = total_E_F_in - total_E_F_out
117
+
118
+ # Exergy destruction (difference between exergy fuel and exergy product)
119
+ self.E_D = self.E_F - self.E_P
120
+
121
+ # Exergetic efficiency (epsilon)
122
+ self.epsilon = self.calc_epsilon()
123
+
124
+ # Log the results
125
+ logging.info(
126
+ f"CombustionChamber exergy balance calculated: "
127
+ f"E_P={self.E_P:.2f}, E_F={self.E_F:.2f}, E_D={self.E_D:.2f}, "
128
+ f"Efficiency={self.epsilon:.2%}"
129
+ )
130
+
131
+
132
+ def aux_eqs(self, A, b, counter, T0, equations, chemical_exergy_enabled):
133
+ """
134
+ Auxiliary equations for the combustion chamber.
135
+
136
+ This function adds rows to the cost matrix A and the right-hand-side vector b to enforce
137
+ the following auxiliary cost relations:
138
+
139
+ (1) For mechanical exergy:
140
+ - When all streams have non-zero mechanical exergy:
141
+ c_M(outlet)/E_M(outlet) = weighted average of inlet specific mechanical exergy costs
142
+ - When pressure can only decrease: c_M(outlet) is directly set
143
+
144
+ (2) For chemical exergy:
145
+ - When all streams have non-zero chemical exergy:
146
+ c_CH(outlet)/E_CH(outlet) = weighted average of inlet specific chemical exergy costs
147
+ - When an inlet has zero chemical exergy: its specific cost is directly set
148
+
149
+ Parameters
150
+ ----------
151
+ A : numpy.ndarray
152
+ The current cost matrix.
153
+ b : numpy.ndarray
154
+ The current right-hand-side vector.
155
+ counter : int
156
+ The current row index in the matrix.
157
+ T0 : float
158
+ Ambient temperature.
159
+ equations : dict or list
160
+ Data structure for storing equation labels.
161
+ chemical_exergy_enabled : bool
162
+ Flag indicating whether chemical exergy is enabled.
163
+
164
+ Returns
165
+ -------
166
+ A : numpy.ndarray
167
+ The updated cost matrix.
168
+ b : numpy.ndarray
169
+ The updated right-hand-side vector.
170
+ counter : int
171
+ The updated row index (counter + 2).
172
+ equations : dict or list
173
+ Updated structure with equation labels.
174
+
175
+ Raises
176
+ ------
177
+ ValueError
178
+ If chemical exergy is not enabled, which is mandatory for combustion chambers.
179
+ """
180
+ # For the combustion chamber, chemical exergy is mandatory.
181
+ if not chemical_exergy_enabled:
182
+ raise ValueError("Chemical exergy is mandatory for the combustion chamber!",
183
+ "Please make sure that your exergy analysis consider the chemical exergy.")
184
+
185
+ # Convert inlet and outlet dictionaries to lists for ordered access.
186
+ inlets = list(self.inl.values())
187
+ outlets = list(self.outl.values())
188
+
189
+ # --- Mechanical cost auxiliary equation ---
190
+ if (outlets[0]["e_M"] != 0 and inlets[0]["e_M"] != 0 and inlets[1]["e_M"] != 0):
191
+ A[counter, outlets[0]["CostVar_index"]["M"]] = -1 / outlets[0]["E_M"]
192
+ A[counter, inlets[0]["CostVar_index"]["M"]] = (1 / inlets[0]["E_M"]) * inlets[0]["m"] / (inlets[0]["m"] + inlets[1]["m"])
193
+ A[counter, inlets[1]["CostVar_index"]["M"]] = (1 / inlets[1]["E_M"]) * inlets[1]["m"] / (inlets[0]["m"] + inlets[1]["m"])
194
+ else: # pressure can only decrease in the combustion chamber (case with p_inlet = p0 and p_outlet < p0 NOT considered)
195
+ A[counter, outlets[0]["CostVar_index"]["M"]] = 1
196
+ equations[counter] = f"aux_mixing_mech_{self.outl[0]['name']}"
197
+
198
+ # --- Chemical cost auxiliary equation ---
199
+ if (outlets[0]["e_CH"] != 0 and inlets[0]["e_CH"] != 0 and inlets[1]["e_CH"] != 0):
200
+ A[counter+1, outlets[0]["CostVar_index"]["CH"]] = -1 / outlets[0]["E_CH"]
201
+ A[counter+1, inlets[0]["CostVar_index"]["CH"]] = (1 / inlets[0]["E_CH"]) * inlets[0]["m"] / (inlets[0]["m"] + inlets[1]["m"])
202
+ A[counter+1, inlets[1]["CostVar_index"]["CH"]] = (1 / inlets[1]["E_CH"]) * inlets[1]["m"] / (inlets[0]["m"] + inlets[1]["m"])
203
+ elif inlets[0]["e_CH"] == 0:
204
+ A[counter+1, inlets[0]["CostVar_index"]["CH"]] = 1
205
+ elif inlets[1]["e_CH"] == 0:
206
+ A[counter+1, inlets[1]["CostVar_index"]["CH"]] = 1
207
+ equations[counter+1] = f"aux_mixing_chem_{self.outl[0]['name']}"
208
+
209
+ # Set the right-hand side entries to zero.
210
+ b[counter] = 0
211
+ b[counter+1] = 0
212
+
213
+ return [A, b, counter + 2, equations]
214
+
215
+ def exergoeconomic_balance(self, T0):
216
+ """
217
+ Perform exergoeconomic balance calculations for the combustion chamber.
218
+
219
+ This method calculates various exergoeconomic parameters including:
220
+ - Cost rates of product (C_P) and fuel (C_F)
221
+ - Specific cost of product (c_P) and fuel (c_F)
222
+ - Cost rate of exergy destruction (C_D)
223
+ - Relative cost difference (r)
224
+ - Exergoeconomic factor (f)
225
+
226
+ Parameters
227
+ ----------
228
+ T0 : float
229
+ Ambient temperature
230
+
231
+ Notes
232
+ -----
233
+ The exergoeconomic balance considers thermal (T), chemical (CH),
234
+ and mechanical (M) exergy components for the inlet and outlet streams.
235
+ """
236
+ self.C_P = self.outl[0]["C_T"] - (
237
+ self.inl[0]["C_T"] + self.inl[1]["C_T"]
238
+ )
239
+ self.C_F = (
240
+ self.inl[0]["C_CH"] + self.inl[1]["C_CH"] -
241
+ self.outl[0]["C_CH"] + self.inl[0]["C_M"] +
242
+ self.inl[1]["C_M"] - self.outl[0]["C_M"]
243
+ )
244
+ self.c_F = self.C_F / self.E_F
245
+ self.c_P = self.C_P / self.E_P
246
+ self.C_D = self.c_F * self.E_D
247
+ self.r = (self.c_P - self.c_F) / self.c_F
248
+ self.f = self.Z_costs / (self.Z_costs + self.C_D)
@@ -0,0 +1,126 @@
1
+ import numpy as np
2
+
3
+
4
+ def component_registry(cls):
5
+ """
6
+ A decorator function to register components in the component registry.
7
+ Registers the class using the class's name as the key.
8
+ """
9
+ component_registry.items[cls.__name__] = cls
10
+ return cls
11
+
12
+
13
+ # Initialize the registry to store components
14
+ component_registry.items = {}
15
+
16
+
17
+ @component_registry
18
+ class Component:
19
+ r"""
20
+ Base class for all ExerPy components.
21
+
22
+ This class serves as the parent class for all exergy analysis components. It provides
23
+ the basic structure and methods for exergy analysis calculations including the
24
+ calculation of exergetic efficiency and exergy balance.
25
+
26
+ Parameters
27
+ ----------
28
+ **kwargs : dict
29
+ Arbitrary keyword arguments that will be assigned as attributes to the component.
30
+
31
+ Attributes
32
+ ----------
33
+ E_F : float
34
+ Exergy fuel of the component :math:`\dot{E}_\mathrm{F}` in :math:`\mathrm{W}`.
35
+ E_P : float
36
+ Exergy product of the component :math:`\dot{E}_\mathrm{P}` in :math:`\mathrm{W}`.
37
+ E_D : float
38
+ Exergy destruction of the component :math:`\dot{E}_\mathrm{D}` in :math:`\mathrm{W}`.
39
+ epsilon : float
40
+ Exergetic efficiency of the component :math:`\varepsilon` in :math:`-`.
41
+
42
+ Notes
43
+ -----
44
+ The exergetic efficiency is calculated as the ratio of exergy product to
45
+ exergy fuel:
46
+
47
+ .. math::
48
+
49
+ \varepsilon = \frac{\dot{E}_\mathrm{P}}{\dot{E}_\mathrm{F}}
50
+
51
+ The exergy balance for any component follows the principle:
52
+
53
+ .. math::
54
+
55
+ \dot{E}_\mathrm{F} = \dot{E}_\mathrm{P} + \dot{E}_\mathrm{D}
56
+
57
+
58
+ See Also
59
+ --------
60
+ exerpy.components : Module containing all available components for exergy analysis
61
+ """
62
+
63
+ def __init__(self, **kwargs):
64
+ r"""Initialize the component with given parameters."""
65
+ self.__dict__.update(kwargs)
66
+
67
+ def calc_exergy_balance(self, T0: float, p0: float) -> None:
68
+ r"""
69
+ Calculate the exergy balance of the component.
70
+
71
+ This method should be implemented by child classes to perform specific
72
+ exergy balance calculations.
73
+
74
+ Parameters
75
+ ----------
76
+ T0 : float
77
+ Ambient temperature in :math:`\mathrm{K}`.
78
+ p0 : float
79
+ Ambient pressure in :math:`\mathrm{Pa}`.
80
+ """
81
+ pass
82
+
83
+ def calc_epsilon(self):
84
+ r"""
85
+ Calculate the exergetic efficiency of the component.
86
+
87
+ The exergetic efficiency is defined as the ratio of exergy product to
88
+ exergy fuel. If the exergy fuel is zero, the function returns NaN to
89
+ avoid division by zero.
90
+
91
+ Returns
92
+ -------
93
+ float or nan
94
+ Exergetic efficiency :math:`\varepsilon = \frac{\dot{E}_\mathrm{P}}{\dot{E}_\mathrm{F}}`
95
+ or NaN if :math:`\dot{E}_\mathrm{F} = 0`.
96
+
97
+ Notes
98
+ -----
99
+ .. math::
100
+ \varepsilon = \begin{cases}
101
+ \frac{\dot{E}_\mathrm{P}}{\dot{E}_\mathrm{F}} & \mathrm{if } \dot{E}_\mathrm{F} \neq 0\\
102
+ \mathrm{NaN} & \mathrm{if } \dot{E}_\mathrm{F} = 0
103
+ \end{cases}
104
+ """
105
+ if self.E_F == 0:
106
+ return np.nan
107
+ else:
108
+ return self.E_P / self.E_F
109
+
110
+
111
+ def exergoeconomic_balance(self, T0):
112
+ r"""
113
+ Placeholder method for exergoeconomic balance.
114
+
115
+ This method is intentionally empty in the base class.
116
+ In each child class (e.g. Pump, Turbine, HeatExchanger), you should
117
+ override it with the logic that calculates the component's
118
+ exergoeconomic variables, e.g. ``C_F``, ``C_P``, ``C_D``, ``r``, and ``f``.
119
+
120
+ Parameters
121
+ ----------
122
+ T0 : float
123
+ Ambient temperature in :math:`\mathrm{K}`.
124
+ """
125
+ return
126
+
File without changes