barotropy 0.0.2__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 (47) hide show
  1. barotropy/__init__.py +69 -0
  2. barotropy/barotropic_model.py +322 -0
  3. barotropy/fluent_automation/__init__.py +5 -0
  4. barotropy/fluent_automation/fluent_automation.py +970 -0
  5. barotropy/fluent_automation/fluent_plot_nozzle_data.py +183 -0
  6. barotropy/fluent_automation/stream_residuals.py +93 -0
  7. barotropy/fluent_automation/stream_transcript.py +24 -0
  8. barotropy/fluid_properties/__init__.py +5 -0
  9. barotropy/fluid_properties/core.py +1470 -0
  10. barotropy/fluid_properties/low_level_interface.py +918 -0
  11. barotropy/isentropic_nozzle.py +102 -0
  12. barotropy/math.py +446 -0
  13. barotropy/matlab/FluidCoolProp_2Phase.m +365 -0
  14. barotropy/matlab/compute_properties_isentrope.m +36 -0
  15. barotropy/matlab/compute_properties_metastable_Td.m +53 -0
  16. barotropy/matlab/compute_properties_metastable_ps.m +64 -0
  17. barotropy/matlab/compute_pseudocritical_line.m +27 -0
  18. barotropy/matlab/compute_pseudocritical_point.m +36 -0
  19. barotropy/matlab/compute_saturation_line.m +49 -0
  20. barotropy/matlab/compute_saturation_point_entropy.m +48 -0
  21. barotropy/matlab/compute_spinodal_line.m +65 -0
  22. barotropy/matlab/compute_spinodal_point.m +125 -0
  23. barotropy/matlab/compute_spinodal_point_entropy.m +192 -0
  24. barotropy/matlab/create_barotropic_model.m +281 -0
  25. barotropy/matlab/create_barotropic_model_segment.m +48 -0
  26. barotropy/matlab/evaluate_isentrope_polynomials.m +58 -0
  27. barotropy/matlab/export_fluent_expressions.m +122 -0
  28. barotropy/matlab/plot_barotropic_model.m +106 -0
  29. barotropy/matlab/plot_barotropic_polynomials.m +86 -0
  30. barotropy/matlab/plot_barotropic_process_ps.m +90 -0
  31. barotropy/matlab/plot_phase_diagram.m +83 -0
  32. barotropy/matlab/set_plot_options.m +70 -0
  33. barotropy/plot_options.py +260 -0
  34. barotropy/pysolver_view/__init__.py +25 -0
  35. barotropy/pysolver_view/nonlinear_system.py +614 -0
  36. barotropy/pysolver_view/nonlinear_system_problems.py +59 -0
  37. barotropy/pysolver_view/numerical_differentiation.py +236 -0
  38. barotropy/pysolver_view/optimization.py +988 -0
  39. barotropy/pysolver_view/optimization_problems.py +273 -0
  40. barotropy/pysolver_view/optimization_wrappers.py +509 -0
  41. barotropy/pysolver_view/pysolver_utilities.py +288 -0
  42. barotropy/sCO2_utilities.py +259 -0
  43. barotropy/utilities.py +780 -0
  44. barotropy-0.0.2.dist-info/LICENSE.md +9 -0
  45. barotropy-0.0.2.dist-info/METADATA +218 -0
  46. barotropy-0.0.2.dist-info/RECORD +47 -0
  47. barotropy-0.0.2.dist-info/WHEEL +4 -0
barotropy/__init__.py ADDED
@@ -0,0 +1,69 @@
1
+ # Highlight exception messages
2
+ # https://stackoverflow.com/questions/25109105/how-to-colorize-the-output-of-python-errors-in-the-gnome-terminal/52797444#52797444
3
+ try:
4
+ import IPython.core.ultratb
5
+ except ImportError:
6
+ # No IPython. Use default exception printing.
7
+ pass
8
+ else:
9
+ import sys
10
+ sys.excepthook = IPython.core.ultratb.ColorTB()
11
+
12
+ # Import subpackages
13
+ from .fluent_automation import *
14
+ from .fluid_properties import *
15
+ from .barotropic_model import *
16
+
17
+ # Import submodules
18
+ from .math import *
19
+ from .plot_options import *
20
+ from .sCO2_utilities import *
21
+ from .utilities import *
22
+
23
+ # Package info
24
+ __version__ = "0.0.2"
25
+ PACKAGE_NAME = "barotropy"
26
+ URL_GITHUB = "https://github.com/turbo-sim/barotropy"
27
+ URL_DOCS = "https://turbo-sim.github.io/barotropy/"
28
+ URL_DTU = "https://thermalpower.dtu.dk/"
29
+ BREAKLINE = 80 * "-"
30
+
31
+ def print_banner():
32
+ """Prints a banner."""
33
+ banner = """
34
+ ____ __
35
+ / __ )____ __________ / /__________ ____ __ __
36
+ / __ / __ `/ ___/ __ \/ __/ ___/ __ \/ __ \/ / / /
37
+ / /_/ / /_/ / / / /_/ / /_/ / / /_/ / /_/ / /_/ /
38
+ /_____/\__,_/_/ \____/\__/_/ \____/ .___/\__, /
39
+ /_/ /____/
40
+ """
41
+ # banner = """
42
+ # ____ ___ ____ ____ __________ ____ ______ __
43
+ # / __ )/ | / __ \/ __ \/_ __/ __ \/ __ \/ __ \ \/ /
44
+ # / __ / /| | / /_/ / / / / / / / /_/ / / / / /_/ /\ /
45
+ # / /_/ / ___ |/ _, _/ /_/ / / / / _, _/ /_/ / ____/ / /
46
+ # /_____/_/ |_/_/ |_|\____/ /_/ /_/ |_|\____/_/ /_/
47
+
48
+ # """
49
+ print(BREAKLINE)
50
+ print(banner)
51
+ print(BREAKLINE)
52
+ # https://manytools.org/hacker-tools/ascii-banner/
53
+ # Style: Sland
54
+
55
+
56
+ def print_package_info():
57
+ """Prints package information with predefined values."""
58
+
59
+ info = f""" Version: {__version__}
60
+ Repository: {URL_GITHUB}
61
+ Documentation: {URL_DOCS}"""
62
+ print_banner()
63
+ print(info)
64
+ print(BREAKLINE)
65
+
66
+
67
+
68
+
69
+
@@ -0,0 +1,322 @@
1
+ import numpy as np
2
+
3
+ from scipy.integrate import solve_ivp
4
+
5
+ from . import fluid_properties as props
6
+
7
+ PROCESS_TYPES = ["polytropic", "adiabatic"]
8
+ MULTIPHASE_MODELS = ["blended", "blending", "equilibrium", "metastable"]
9
+
10
+ def barotropic_model_one_fluid(
11
+ fluid_name=None,
12
+ T_in=None,
13
+ p_in=None,
14
+ p_out=None,
15
+ efficiency=None,
16
+ number_of_points=None,
17
+ multiphase_model="blended",
18
+ calculation_type="polytropic",
19
+ tolerance=1e-6,
20
+ ):
21
+
22
+ # Compute process as an adiabatic or polytropic expansion
23
+ if calculation_type == "adiabatic":
24
+ states = calculate_adiabatic_process(
25
+ fluid_name=fluid_name,
26
+ T_in=T_in,
27
+ p_in=p_in,
28
+ p_out=p_out,
29
+ efficiency=efficiency,
30
+ # multiphase_model=multiphase_model,
31
+ number_of_points=number_of_points,
32
+ )
33
+
34
+ elif calculation_type == "polytropic":
35
+ states, _ = polytropic_process_one_fluid(
36
+ fluid_name=fluid_name,
37
+ T_in=T_in,
38
+ p_in=p_in,
39
+ p_out=p_out,
40
+ efficiency=efficiency,
41
+ multiphase_model=multiphase_model,
42
+ number_of_points=number_of_points,
43
+ tolerance=tolerance,
44
+ )
45
+
46
+ else:
47
+ options = ", ".join(f"'{k}'" for k in PROCESS_TYPES)
48
+ raise ValueError(
49
+ f"Invalid process type '{calculation_type}'. Available options: {options}"
50
+ )
51
+
52
+ return states
53
+
54
+
55
+ def polytropic_process_one_fluid(
56
+ fluid_name,
57
+ T_in,
58
+ p_in,
59
+ p_out,
60
+ efficiency,
61
+ multiphase_model="blended",
62
+ q_onset=0.00,
63
+ q_transition=0.01,
64
+ tolerance=1e-6,
65
+ number_of_points=None,
66
+ ):
67
+ """ """
68
+
69
+ # Differential equation defining the polytropic process
70
+ def odefun(t, y):
71
+ # Keep variables in memory to use previous state as initial guess
72
+ nonlocal rho_guess, T_guess
73
+
74
+ # Rename input variables
75
+ p = t
76
+ (h,) = y
77
+
78
+ # Compute equilibrium state
79
+ state_eq = fluid.set_state(props.HmassP_INPUTS, h, p, generalize_quality=True)
80
+
81
+ # Compute metastable state
82
+ state_meta = fluid.set_state_metastable("p", p, "hmass", h, rho_guess, T_guess)
83
+ rho_guess = state_meta.rho # Update guess for the next iteration
84
+ T_guess = state_meta.T # Update guess for the next iteration
85
+
86
+ # Determine the actual thermodynamic state
87
+ if multiphase_model == "equilibrium":
88
+ state = state_eq
89
+ elif multiphase_model == "metastable":
90
+ state = state_meta
91
+ elif multiphase_model == "blended" or multiphase_model == "blending":
92
+ x = 1 - (state_eq["Q"] - q_onset) / q_transition
93
+ # sigma = sigmoid_smoothstep(x)
94
+ sigma = sigmoid_smootherstep(x)
95
+ state = {}
96
+ for key in state_eq.keys():
97
+ state[key] = state_eq[key]*(1-sigma) + state_meta[key]*sigma
98
+ else:
99
+ options = ", ".join(f"'{k}'" for k in MULTIPHASE_MODELS)
100
+ raise ValueError(
101
+ f"Invalid multiphase model {multiphase_model}'. Available options: {options}"
102
+ )
103
+
104
+ # Compute right-hand-side of the ODE
105
+ dhdp = efficiency / state["rho"]
106
+
107
+ return dhdp, state
108
+
109
+ # Compute inlet state
110
+ fluid = props.Fluid(name=fluid_name, backend="HEOS", exceptions=True)
111
+ state_in = fluid.set_state(props.PT_INPUTS, p_in, T_in)
112
+ rho_guess = state_in.rho
113
+ T_guess = state_in.T
114
+
115
+ # Solve polytropic expansion differential equation
116
+ solution = solve_ivp(
117
+ lambda p, h: odefun(p, h)[0],
118
+ [state_in.p, p_out],
119
+ [state_in.h],
120
+ t_eval=np.linspace(state_in.p, p_out, number_of_points)
121
+ if number_of_points
122
+ else None,
123
+ method="LSODA", # "RK45", "Radau", "LSODA"
124
+ rtol=tolerance,
125
+ atol=tolerance,
126
+ )
127
+ if not solution.success:
128
+ raise Exception(solution.message)
129
+
130
+ # Postprocess solution
131
+ states = postprocess_ode(solution.t, solution.y, odefun)
132
+
133
+ return states, solution
134
+
135
+
136
+ def calculate_adiabatic_process(
137
+ fluid_name,
138
+ T_in,
139
+ p_in,
140
+ p_out,
141
+ efficiency,
142
+ number_of_points=None,
143
+ ):
144
+ # Compute inlet state
145
+ fluid = props.Fluid(name=fluid_name, backend="HEOS", exceptions=True)
146
+ state_in = fluid.set_state(props.PT_INPUTS, p_in, T_in)
147
+
148
+ # Compute outlet state
149
+ state_out_s = fluid.set_state(props.PSmass_INPUTS, p_out, state_in.s)
150
+ h_out = state_in.h - efficiency * (state_in.h - state_out_s.h)
151
+ state_out = fluid.set_state(props.HmassP_INPUTS, h_out, p_out)
152
+
153
+ # Prepare list of states
154
+ if number_of_points is not None:
155
+ p_array = np.logspace(np.log10(state_in.p), np.log10(state_out.p), number_of_points)
156
+ s_array = np.linspace(state_in.s, state_out.s, number_of_points)
157
+ states = []
158
+ for p, s in zip(p_array, s_array):
159
+ states.append(fluid.set_state(props.PSmass_INPUTS, p, s))
160
+ else:
161
+ states = [state_in, state_out]
162
+
163
+ return props.states_to_dict(states)
164
+
165
+
166
+ def postprocess_ode(t, y, ode_handle):
167
+ """
168
+ Post-processes the output of an ordinary differential equation (ODE) solver.
169
+
170
+ This function takes the time points and corresponding ODE solution matrix,
171
+ and for each time point, it calls a user-defined ODE handling function to
172
+ process the state of the ODE system. It collects the results into a
173
+ dictionary where each key corresponds to a state variable and the values
174
+ are numpy arrays of that state variable at each integration step
175
+
176
+ Parameters
177
+ ----------
178
+ t : array_like
179
+ Integration points at which the ODE was solved, as a 1D numpy array.
180
+ y : array_like
181
+ The solution of the ODE system, as a 2D numpy array with shape (n,m) where
182
+ n is the number of points and m is the number of state variables.
183
+ ode_handle : callable
184
+ A function that takes in a integration point and state vector and returns a tuple,
185
+ where the first element is ignored (can be None) and the second element
186
+ is a dictionary representing the processed state of the system.
187
+
188
+ Returns
189
+ -------
190
+ ode_out : dict
191
+ A dictionary where each key corresponds to a state variable and each value
192
+ is a numpy array containing the values of that state variable at each integration step.
193
+ """
194
+ # Initialize ode_out as a dictionary
195
+ ode_out = {}
196
+ for t_i, y_i in zip(t, y.T):
197
+ _, out = ode_handle(t_i, y_i)
198
+
199
+ for key, value in out.items():
200
+ # Initialize with an empty list
201
+ if key not in ode_out:
202
+ ode_out[key] = []
203
+ # Append the value to list of current key
204
+ ode_out[key].append(value)
205
+
206
+ # Convert lists to numpy arrays
207
+ for key in ode_out:
208
+ ode_out[key] = np.array(ode_out[key])
209
+
210
+ return ode_out
211
+
212
+
213
+ # def sigmoid_hyperbolic(x, x0=0.5, alpha=1):
214
+ # r"""
215
+ # Compute the sigmoid hyperbolic function.
216
+
217
+ # This function calculates a sigmoid function based on the hyperbolic tangent.
218
+ # The formula is given by:
219
+
220
+ # .. math::
221
+ # \sigma(x) = \frac{1 + \tanh\left(\frac{x - x_0}{\alpha}\right)}{2}
222
+
223
+ # Parameters
224
+ # ----------
225
+ # x : array_like
226
+ # Input data.
227
+ # x0 : float, optional
228
+ # Center of the sigmoid function. Default is 0.5.
229
+ # alpha : float, optional
230
+ # Scale parameter. Default is 0.1.
231
+
232
+ # Returns
233
+ # -------
234
+ # array_like
235
+ # Output of the sigmoid hyperbolic function.
236
+
237
+ # """
238
+ # x = np.array(x) # Ensure x is a NumPy array for vectorized operations
239
+ # sigma = (1 + np.tanh((x - x0) / alpha)) / 2
240
+ # return sigma
241
+
242
+
243
+ # def sigmoid_rational(x, n, m):
244
+ # r"""
245
+ # Compute the sigmoid rational function.
246
+
247
+ # This function calculates a sigmoid function using an algebraic approach based on a rational function.
248
+ # The formula is given by:
249
+
250
+ # .. math::
251
+ # \sigma(x) = \frac{x^n}{x^n + (1-x)^m}
252
+
253
+ # Parameters
254
+ # ----------
255
+ # x : array_like
256
+ # Input data.
257
+ # n : int
258
+ # Power of the numerator.
259
+ # m : int
260
+ # Power of the denominator.
261
+
262
+ # Returns
263
+ # -------
264
+ # array_like
265
+ # Output of the sigmoid algebraic function.
266
+
267
+ # """
268
+ # x = np.array(x) # Ensure x is a NumPy array for vectorized operations
269
+ # x = np.where(x < 0, 0, x) # Set x to 0 where x < 0
270
+ # x = np.where(x > 1, 1, x) # Set x to 1 where x > 1
271
+ # sigma = x**n / (x**n + (1 - x) ** m)
272
+ # return sigma
273
+
274
+
275
+ # def sigmoid_smoothstep(x):
276
+ # """
277
+ # Compute the smooth step function.
278
+
279
+ # This function calculates a smooth step function with zero first-order
280
+ # derivatives at the endpoints. More information available at:
281
+ # https://resources.wolframcloud.com/FunctionRepository/resources/SmoothStep/
282
+
283
+ # Parameters
284
+ # ----------
285
+ # x : array_like
286
+ # Input data.
287
+
288
+ # Returns
289
+ # -------
290
+ # array_like
291
+ # Output of the sigmoid smoothstep function.
292
+
293
+ # """
294
+ # x = np.array(x) # Ensure x is a NumPy array for vectorized operations
295
+ # x = np.where(x < 0, 0, x) # Set x to 0 where x < 0
296
+ # x = np.where(x > 1, 1, x) # Set x to 1 where x > 1
297
+ # return x**2 * (3 - 2 * x)
298
+
299
+
300
+ # def sigmoid_smootherstep(x):
301
+ # """
302
+ # Compute the smoother step function.
303
+
304
+ # This function calculates a smoother step function with zero second-order
305
+ # derivatives at the endpoints. It is a modification of the smoothstep
306
+ # function to provide smoother transitions.
307
+
308
+ # Parameters
309
+ # ----------
310
+ # x : array_like
311
+ # Input data.
312
+
313
+ # Returns
314
+ # -------
315
+ # array_like
316
+ # Output of the sigmoid smootherstep function.
317
+
318
+ # """
319
+ # x = np.array(x) # Ensure x is a NumPy array for vectorized operations
320
+ # x = np.where(x < 0, 0, x) # Set x to 0 where x < 0
321
+ # x = np.where(x > 1, 1, x) # Set x to 1 where x > 1
322
+ # return 6 * x**5 - 15 * x**4 + 10 * x**3
@@ -0,0 +1,5 @@
1
+
2
+ from .fluent_automation import *
3
+ from .fluent_plot_nozzle_data import *
4
+ from .stream_residuals import *
5
+ from .stream_transcript import *