zoomy-core 0.1.1__py3-none-any.whl → 0.1.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.

Potentially problematic release.


This version of zoomy-core might be problematic. Click here for more details.

Files changed (53) hide show
  1. zoomy_core/decorators/decorators.py +25 -0
  2. zoomy_core/fvm/flux.py +97 -0
  3. zoomy_core/fvm/nonconservative_flux.py +97 -0
  4. zoomy_core/fvm/ode.py +55 -0
  5. zoomy_core/fvm/solver_numpy.py +305 -0
  6. zoomy_core/fvm/timestepping.py +13 -0
  7. zoomy_core/mesh/mesh.py +1234 -0
  8. zoomy_core/mesh/mesh_extrude.py +168 -0
  9. zoomy_core/mesh/mesh_util.py +487 -0
  10. zoomy_core/misc/custom_types.py +6 -0
  11. zoomy_core/misc/interpolation.py +140 -0
  12. zoomy_core/misc/io.py +438 -0
  13. zoomy_core/misc/logger_config.py +18 -0
  14. zoomy_core/misc/misc.py +216 -0
  15. zoomy_core/misc/static_class.py +94 -0
  16. zoomy_core/model/analysis.py +147 -0
  17. zoomy_core/model/basefunction.py +113 -0
  18. zoomy_core/model/basemodel.py +512 -0
  19. zoomy_core/model/boundary_conditions.py +193 -0
  20. zoomy_core/model/initial_conditions.py +171 -0
  21. zoomy_core/model/model.py +63 -0
  22. zoomy_core/model/models/GN.py +70 -0
  23. zoomy_core/model/models/advection.py +53 -0
  24. zoomy_core/model/models/basisfunctions.py +181 -0
  25. zoomy_core/model/models/basismatrices.py +377 -0
  26. zoomy_core/model/models/core.py +564 -0
  27. zoomy_core/model/models/coupled_constrained.py +60 -0
  28. zoomy_core/model/models/poisson.py +41 -0
  29. zoomy_core/model/models/shallow_moments.py +757 -0
  30. zoomy_core/model/models/shallow_moments_sediment.py +378 -0
  31. zoomy_core/model/models/shallow_moments_topo.py +423 -0
  32. zoomy_core/model/models/shallow_moments_variants.py +1509 -0
  33. zoomy_core/model/models/shallow_water.py +266 -0
  34. zoomy_core/model/models/shallow_water_topo.py +111 -0
  35. zoomy_core/model/models/shear_shallow_flow.py +594 -0
  36. zoomy_core/model/models/sme_turbulent.py +613 -0
  37. zoomy_core/model/models/vam.py +455 -0
  38. zoomy_core/postprocessing/postprocessing.py +72 -0
  39. zoomy_core/preprocessing/openfoam_moments.py +452 -0
  40. zoomy_core/transformation/helpers.py +25 -0
  41. zoomy_core/transformation/to_amrex.py +238 -0
  42. zoomy_core/transformation/to_c.py +181 -0
  43. zoomy_core/transformation/to_jax.py +14 -0
  44. zoomy_core/transformation/to_numpy.py +115 -0
  45. zoomy_core/transformation/to_openfoam.py +254 -0
  46. zoomy_core/transformation/to_ufl.py +67 -0
  47. {zoomy_core-0.1.1.dist-info → zoomy_core-0.1.3.dist-info}/METADATA +2 -1
  48. zoomy_core-0.1.3.dist-info/RECORD +51 -0
  49. zoomy_core-0.1.3.dist-info/top_level.txt +1 -0
  50. zoomy_core-0.1.1.dist-info/RECORD +0 -5
  51. zoomy_core-0.1.1.dist-info/top_level.txt +0 -1
  52. {zoomy_core-0.1.1.dist-info → zoomy_core-0.1.3.dist-info}/WHEEL +0 -0
  53. {zoomy_core-0.1.1.dist-info → zoomy_core-0.1.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,238 @@
1
+ import os
2
+ from sympy import MatrixSymbol, fraction, cancel, Matrix, symbols, radsimp, powsimp
3
+ import sympy as sp
4
+ from copy import deepcopy
5
+
6
+ from library.zoomy_core.misc.misc import Zstruct
7
+ from library.zoomy_core.model.sympy2c import create_module
8
+ from library.zoomy_core.transformation.helpers import regularize_denominator, substitute_sympy_attributes_with_symbol_matrix
9
+
10
+ import sympy as sp
11
+ from sympy.printing.cxx import CXX11CodePrinter
12
+ import re
13
+ import textwrap
14
+
15
+
16
+ class AmrexPrinter(CXX11CodePrinter):
17
+ """
18
+ After the normal C++ printer has done its job, replace every
19
+ 'std::foo(' with 'amrex::Math::foo(' – except if foo is listed
20
+ in 'custom_map'. No other overrides are necessary.
21
+ """
22
+ def __init__(self, model, *args, **kwargs):
23
+ super().__init__(*args, **kwargs)
24
+ self.map_Q = {k: f"Q({i})" for i, k in enumerate(model.variables.values())}
25
+ self.map_Qaux = {k: f"Qaux({i})" for i, k in enumerate(model.aux_variables.values())}
26
+ self.map_param = {k: str(float(model.parameter_values[i])) for i, k in enumerate(model.parameters.values())}
27
+ self.map_normal = {k: f"normal({i})" for i, k in enumerate(model.normal.values())}
28
+ self.map_position = {k: f"X({i})" for i, k in enumerate(model.position.values())}
29
+
30
+
31
+ self._custom_map = set({})
32
+ # names that should *keep* their std:: prefix
33
+
34
+ # pre-compile regex std::something(
35
+ self._std_regex = re.compile(r'std::([A-Za-z_]\w*)')
36
+
37
+ def _print_Symbol(self, s):
38
+ for map in [self.map_Q, self.map_Qaux, self.map_param, self.map_normal, self.map_position]:
39
+ if s in map:
40
+ return map[s]
41
+ return super()._print_Symbol(s)
42
+
43
+ def _print_Pow(self, expr):
44
+ """
45
+ Print a SymPy Power.
46
+
47
+ * integer exponent -> amrex::Math::powi<EXP>(base)
48
+ * otherwise -> amrex::Math::pow (run-time exponent)
49
+ """
50
+ base, exp = expr.as_base_exp()
51
+
52
+ # integer exponent ------------------------------------------------
53
+ if exp.is_Integer:
54
+ n = int(exp)
55
+
56
+ # 0, 1 and negative exponents inlined
57
+ if n == 0:
58
+ return "1.0"
59
+ if n == 1:
60
+ return self._print(base)
61
+ if n < 0:
62
+ # negative integer: 1 / powi<-n>(base)
63
+ return (f"(1.0 / amrex::Math::powi<{abs(n)}>("
64
+ f"{self._print(base)}))")
65
+
66
+ # positive integer
67
+ return f"amrex::Math::powi<{n}>({self._print(base)})"
68
+
69
+ # non-integer exponent -------------------------------------------
70
+ return (f"std::pow("
71
+ f"{self._print(base)}, {self._print(exp)})")
72
+
73
+ # the only method we override
74
+ def doprint(self, expr, **settings):
75
+ code = super().doprint(expr, **settings)
76
+
77
+ # callback that the regex will call for every match
78
+ def _repl(match):
79
+ fname = match.group(1)
80
+ if fname in self._custom_map:
81
+ return self._custom_map[fname]
82
+ else:
83
+ return f'std::{fname}'
84
+
85
+ # apply the replacement to the whole code string
86
+ return self._std_regex.sub(_repl, code)
87
+
88
+ def convert_expression_body(self, expr, target='res'):
89
+
90
+ tmp_sym = sp.numbered_symbols('t')
91
+ temps, simplified = sp.cse(expr, symbols=tmp_sym)
92
+ lines = []
93
+ for lhs, rhs in temps:
94
+ lines.append(f"amrex::Real {self.doprint(lhs)} = {self.doprint(rhs)};")
95
+
96
+ for i in range(expr.rows):
97
+ for j in range(expr.cols):
98
+ lines.append(f"{target}({i},{j}) = {self.doprint(simplified[0][i, j])};")
99
+
100
+ body = '\n '.join(lines)
101
+ return body
102
+
103
+ def createSmallMatrix(self, rows, cols):
104
+ return f"amrex::SmallMatrix<amrex::Real,{rows},{cols}>"
105
+
106
+ def create_file_header(self, n_dof_q, n_dof_qaux, dim):
107
+ header = textwrap.dedent(f"""
108
+ #pragma once
109
+ #include <AMReX_Array4.H>
110
+ #include <AMReX_Vector.H>
111
+
112
+ class Model {{
113
+ public:
114
+ static constexpr int n_dof_q = {n_dof_q};
115
+ static constexpr int n_dof_qaux = {n_dof_qaux};
116
+ static constexpr int dimension = {dim};
117
+ """)
118
+ return header
119
+
120
+ def create_file_footer(self):
121
+ return """
122
+ };
123
+ """
124
+
125
+ def create_function(self, name, expr, n_dof_q, n_dof_qaux, target='res'):
126
+ if type(expr) is list:
127
+ dim = len(expr)
128
+ return [self.create_function(f"{name}_{dir}", expr[i], n_dof_q, n_dof_qaux) for i, dir in enumerate(['x', 'y', 'z'][:dim])]
129
+ res_shape = expr.shape
130
+ body = self.convert_expression_body((expr), target=target)
131
+ text = f"""
132
+ AMREX_GPU_HOST_DEVICE
133
+ AMREX_FORCE_INLINE
134
+ static {self.createSmallMatrix(*res_shape)}
135
+ {name} ( {self.createSmallMatrix(n_dof_q, 1)} const& Q,
136
+ {self.createSmallMatrix(n_dof_qaux, 1)} const& Qaux) noexcept
137
+ {{
138
+ auto {target} = {self.createSmallMatrix(*res_shape)}{{}};
139
+ {body}
140
+ return {target};
141
+ }}
142
+ """
143
+ return text
144
+
145
+ def create_function_normal(self, name, expr, n_dof_q, n_dof_qaux, dim, target='res'):
146
+ if type(expr) is list:
147
+ dim = len(expr)
148
+ return [self.create_function_normal(f"{name}_{dir}", expr[i], n_dof_q, n_dof_qaux, dim) for i, dir in enumerate(['x', 'y', 'z'][:dim])]
149
+ res_shape = expr.shape
150
+ body = self.convert_expression_body(expr, target=target)
151
+ text = f"""
152
+ AMREX_GPU_HOST_DEVICE
153
+ AMREX_FORCE_INLINE
154
+ static {self.createSmallMatrix(*res_shape)}
155
+ {name} ( {self.createSmallMatrix(n_dof_q, 1)} const& Q,
156
+ {self.createSmallMatrix(n_dof_qaux, 1)} const& Qaux,
157
+ {self.createSmallMatrix(dim, 1)} const& normal) noexcept
158
+ {{
159
+ auto {target} = {self.createSmallMatrix(*res_shape)}{{}};
160
+ {body}
161
+ return {target};
162
+
163
+ }}
164
+ """
165
+ return text
166
+
167
+ def create_function_interpolate(self, name, expr, n_dof_q, n_dof_qaux, target='res'):
168
+ res_shape = expr.shape
169
+ body = self.convert_expression_body(expr, target=target)
170
+ text = f"""
171
+ AMREX_GPU_HOST_DEVICE
172
+ AMREX_FORCE_INLINE
173
+ static {self.createSmallMatrix(*res_shape)}
174
+ {name} ( {self.createSmallMatrix(n_dof_q, 1)} const& Q,
175
+ {self.createSmallMatrix(n_dof_qaux, 1)} const& Qaux,
176
+ {self.createSmallMatrix(3, 1)} const& X) noexcept
177
+ {{
178
+ auto {target} = {self.createSmallMatrix(*res_shape)}{{}};
179
+ {body}
180
+ return {target};
181
+ }}
182
+
183
+ """
184
+ return text
185
+
186
+
187
+ def create_function_boundary(self, name, expr, n_dof_q, n_dof_qaux, dim, target='res'):
188
+ res_shape = expr.shape
189
+ body = self.convert_expression_body(expr, target=target)
190
+ text = f"""
191
+ AMREX_GPU_HOST_DEVICE
192
+ AMREX_FORCE_INLINE
193
+ static {self.createSmallMatrix(*res_shape)}
194
+ {name} ( {self.createSmallMatrix(n_dof_q, 1)} const& Q,
195
+ {self.createSmallMatrix(n_dof_qaux, 1)} const& Qaux,
196
+ {self.createSmallMatrix(dim, 1)} const& normal,
197
+ {self.createSmallMatrix(3, 1)} const& position,
198
+ amrex::Real const& time,
199
+ amrex::Real const& dX) noexcept
200
+ {{
201
+ auto {target} = {self.createSmallMatrix(*res_shape)}{{}};
202
+ {body}
203
+ return {target};
204
+
205
+ }}
206
+ """
207
+ return text
208
+
209
+ def create_model(self, model):
210
+ n_dof = model.n_variables
211
+ n_dof_qaux = model.n_aux_variables
212
+ dim = model.dimension
213
+ module_functions = []
214
+ module_functions += self.create_function('flux', model.flux(), n_dof, n_dof_qaux)
215
+ module_functions += self.create_function('flux_jacobian', model.flux_jacobian(), n_dof, n_dof_qaux)
216
+ module_functions += self.create_function('nonconservative_matrix', model.nonconservative_matrix(), n_dof, n_dof_qaux)
217
+ module_functions += self.create_function('quasilinear_matrix', model.quasilinear_matrix(), n_dof, n_dof_qaux)
218
+ module_functions.append(self.create_function_normal('eigenvalues', model.eigenvalues(), n_dof, n_dof_qaux, dim))
219
+ module_functions.append(self.create_function('left_eigenvectors', model.left_eigenvectors(), n_dof, n_dof_qaux))
220
+ module_functions.append(self.create_function('right_eigenvectors', model.right_eigenvectors(), n_dof, n_dof_qaux))
221
+ module_functions.append(self.create_function('source', model.source(), n_dof, n_dof_qaux))
222
+ module_functions.append(self.create_function('residual', model.residual(), n_dof, n_dof_qaux))
223
+ module_functions.append(self.create_function('source_implicit', model.source_implicit(), n_dof, n_dof_qaux))
224
+ module_functions.append(self.create_function_interpolate('project_2d_to_3d', model.project_2d_to_3d(), n_dof, n_dof_qaux))
225
+ module_functions.append(self.create_function_boundary('boundary_conditions', model.boundary_conditions.get_boundary_condition_function(model.time, model.position, model.distance, model.variables, model.aux_variables, model.parameters, model.normal), n_dof, n_dof_qaux, dim))
226
+ full = self.create_file_header(n_dof, n_dof_qaux, dim) + '\n\n' + '\n\n'.join(module_functions) + self.create_file_footer()
227
+ return full
228
+
229
+
230
+ def write_code(model, settings):
231
+ printer = AmrexPrinter(model)
232
+ expr = printer.create_model(model)
233
+ main_dir = os.getenv("ZOOMY_DIR")
234
+ path = os.path.join(main_dir, settings.output.directory, ".amrex_interface")
235
+ os.makedirs(path, exist_ok=True)
236
+ path = os.path.join(path, "Model.h")
237
+ with open(path, 'w+') as f:
238
+ f.write(expr)
@@ -0,0 +1,181 @@
1
+ import os
2
+ import re
3
+ import textwrap
4
+ import sympy as sp
5
+ from sympy.printing.cxx import CXX11CodePrinter
6
+
7
+ class CPrinter(CXX11CodePrinter):
8
+ """
9
+ Convert SymPy expressions to C code.
10
+ """
11
+
12
+ def __init__(self, model, *args, **kwargs):
13
+ super().__init__(*args, **kwargs)
14
+
15
+ self.n_dof_q = model.n_variables
16
+ self.n_dof_qaux = model.n_aux_variables
17
+
18
+ # Map variable names to Q[i], Qaux[i]
19
+ self.map_Q = {k: f"Q[{i}]" for i, k in enumerate(model.variables.values())}
20
+ self.map_Qaux = {k: f"Qaux[{i}]" for i, k in enumerate(model.aux_variables.values())}
21
+ self.map_param = {k: str(float(model.parameter_values[i])) for i, k in enumerate(model.parameters.values())}
22
+
23
+ self.map_normal = {k: f"n[{i}]" for i, k in enumerate(model.normal.values())}
24
+ self.map_position = {k: f"X[{i}]" for i, k in enumerate(model.position.values())}
25
+
26
+ self._std_regex = re.compile(r'std::([A-Za-z_]\w*)')
27
+
28
+ # --- Symbol printing --------------------------------------------------
29
+ def _print_Symbol(self, s):
30
+ for m in [self.map_Q, self.map_Qaux, self.map_param, self.map_normal, self.map_position]:
31
+ if s in m:
32
+ return m[s]
33
+ return super()._print_Symbol(s)
34
+
35
+ # --- Pow printing -----------------------------------------------------
36
+ def _print_Pow(self, expr):
37
+ base, exp = expr.as_base_exp()
38
+ if exp.is_Integer:
39
+ n = int(exp)
40
+ if n == 0:
41
+ return "1.0"
42
+ if n == 1:
43
+ return self._print(base)
44
+ if n < 0:
45
+ return f"(1.0 / std::pow({self._print(base)}, {abs(n)}))"
46
+ return f"std::pow({self._print(base)}, {n})"
47
+ return f"std::pow({self._print(base)}, {self._print(exp)})"
48
+
49
+ # --- Expression conversion --------------------------------------------
50
+ def convert_expression_body(self, expr, target='res'):
51
+ tmp_sym = sp.numbered_symbols('t')
52
+ temps, simplified = sp.cse(expr, symbols=tmp_sym)
53
+ lines = []
54
+ cols = expr.shape[1]
55
+ for lhs, rhs in temps:
56
+ lines.append(f"double {self.doprint(lhs)} = {self.doprint(rhs)};")
57
+ for i in range(expr.rows):
58
+ for j in range(expr.cols):
59
+ lines.append(f"{target}[{i * cols +j}] = {self.doprint(simplified[0][i, j])};")
60
+ return "\n ".join(lines)
61
+
62
+ # --- Header / Footer --------------------------------------------------
63
+ def create_file_header(self, n_dof_q, n_dof_qaux, dim, list_sorted_function_names):
64
+ return textwrap.dedent(f"""\
65
+ #pragma once
66
+
67
+ static const int MODEL_n_dof_q = {n_dof_q};
68
+ static const int MODEL_n_dof_qaux = {n_dof_qaux};
69
+ static const int MODEL_dimension = {dim};
70
+ static const int MODEL_n_boundary_tags = {len(list_sorted_function_names)};
71
+ static const char* MODEL_map_boundary_tag_to_function_index[] = {{ {", ".join(f'"{item}"' for item in list_sorted_function_names)} }};
72
+ """)
73
+
74
+ def create_file_footer(self):
75
+ return "\n"
76
+
77
+ # --- Function generators ---------------------------------------------
78
+ def create_function(self, name, expr, n_dof_q, n_dof_qaux, target='res'):
79
+ if isinstance(expr, list):
80
+ dim = len(expr)
81
+ return [self.create_function(f"{name}_{d}", expr[i], n_dof_q, n_dof_qaux)
82
+ for i, d in enumerate(['x', 'y', 'z'][:dim])]
83
+
84
+ rows, cols = expr.shape
85
+ body = self.convert_expression_body(expr, target)
86
+ return f"""
87
+ inline void {name}(
88
+ const double* Q,
89
+ const double* Qaux,
90
+ double* res
91
+ )
92
+ {{
93
+ {body}
94
+ }}
95
+ """
96
+
97
+ def create_function_normal(self, name, expr, n_dof_q, n_dof_qaux, dim, target='res'):
98
+ if isinstance(expr, list):
99
+ return [self.create_function_normal(f"{name}_{d}", expr[i], n_dof_q, n_dof_qaux, dim)
100
+ for i, d in enumerate(['x', 'y', 'z'][:dim])]
101
+
102
+ rows, cols = expr.shape
103
+ body = self.convert_expression_body(expr, target)
104
+ return f"""
105
+ inline void {name}(
106
+ const double* Q,
107
+ const double* Qaux,
108
+ const double* n,
109
+ double* res)
110
+ {{
111
+ {body}
112
+ }}
113
+ """
114
+
115
+ def create_function_interpolate(self, name, expr, n_dof_q, n_dof_qaux, target='res'):
116
+ rows, cols = expr.shape
117
+ body = self.convert_expression_body(expr, target)
118
+ return f"""
119
+ inline double* {name}(
120
+ const double* Q,
121
+ const double* Qaux,
122
+ const double* X,
123
+ double* res)
124
+ {{
125
+ {body}
126
+ }}
127
+ """
128
+
129
+ def create_function_boundary(self, name, expr, n_dof_q, n_dof_qaux, dim, target='res'):
130
+ rows, cols = expr.shape
131
+ body = self.convert_expression_body(expr, target)
132
+ return f"""
133
+ inline double* {name}(
134
+ const double* Q,
135
+ const double* Qaux,
136
+ const double* n,
137
+ const double* X,
138
+ const double time,
139
+ const double dX,
140
+ double* res)
141
+ {{
142
+ {body}
143
+ }}
144
+ """
145
+
146
+ # --- Full model generation ------------------------------------------
147
+ def create_model(self, model):
148
+ n_dof = model.n_variables
149
+ n_dof_qaux = model.n_aux_variables
150
+ dim = model.dimension
151
+ funcs = []
152
+ funcs += self.create_function('flux', model.flux(), n_dof, n_dof_qaux)
153
+ funcs += self.create_function('flux_jacobian', model.flux_jacobian(), n_dof, n_dof_qaux)
154
+ funcs += self.create_function('nonconservative_matrix', model.nonconservative_matrix(), n_dof, n_dof_qaux)
155
+ funcs += self.create_function('quasilinear_matrix', model.quasilinear_matrix(), n_dof, n_dof_qaux)
156
+ funcs.append(self.create_function_normal('eigenvalues', model.eigenvalues(), n_dof, n_dof_qaux, dim))
157
+ funcs.append(self.create_function('left_eigenvectors', model.left_eigenvectors(), n_dof, n_dof_qaux))
158
+ funcs.append(self.create_function('right_eigenvectors', model.right_eigenvectors(), n_dof, n_dof_qaux))
159
+ funcs.append(self.create_function('source', model.source(), n_dof, n_dof_qaux))
160
+ funcs.append(self.create_function('residual', model.residual(), n_dof, n_dof_qaux))
161
+ funcs.append(self.create_function('source_implicit', model.source_implicit(), n_dof, n_dof_qaux))
162
+ funcs.append(self.create_function_interpolate('interpolate', model.project_2d_to_3d(), n_dof, n_dof_qaux))
163
+ funcs.append(self.create_function_boundary(
164
+ 'boundary_conditions',
165
+ model.boundary_conditions.get_boundary_condition_function(
166
+ model.time, model.position, model.distance,
167
+ model.variables, model.aux_variables, model.parameters, model.normal),
168
+ n_dof, n_dof_qaux, dim))
169
+
170
+ return self.create_file_header(n_dof, n_dof_qaux, dim, model.boundary_conditions.list_sorted_function_names) + "\n".join(funcs) + self.create_file_footer()
171
+
172
+
173
+ def write_code(model, settings):
174
+ printer = CPrinter(model)
175
+ code = printer.create_model(model)
176
+ main_dir = os.getenv("ZOOMY_DIR")
177
+ path = os.path.join(main_dir, settings.output.directory, ".c_interface")
178
+ os.makedirs(path, exist_ok=True)
179
+ file_path = os.path.join(path, "Model.H")
180
+ with open(file_path, "w+") as f:
181
+ f.write(code)
@@ -0,0 +1,14 @@
1
+ from attrs import define
2
+ try:
3
+ import jax.numpy as jnp
4
+ except ImportError:
5
+ import numpy as jnp
6
+
7
+ from library.zoomy_core.transformation.to_numpy import NumpyRuntimeModel
8
+
9
+
10
+
11
+ @define(kw_only=False, slots=True, frozen=True)
12
+ class JaxRuntimeModel(NumpyRuntimeModel):
13
+ module = {'ones_like': jnp.ones_like, 'zeros_like': jnp.zeros_like, 'array': jnp.array, 'squeeze': jnp.squeeze}
14
+ printer="jax"
@@ -0,0 +1,115 @@
1
+ from typing import Callable
2
+ import numpy as np
3
+ from attrs import define, field
4
+
5
+ from library.zoomy_core.misc.custom_types import FArray
6
+
7
+
8
+ @define(kw_only=False, slots=True, frozen=True)
9
+ class NumpyRuntimeModel:
10
+ """Runtime model generated from a symbolic Model."""
11
+
12
+ # --- User-provided ---
13
+ model: object = field()
14
+
15
+ # --- Automatically derived ---
16
+ name: str = field(init=False)
17
+ dimension: int = field(init=False)
18
+ n_variables: int = field(init=False)
19
+ n_aux_variables: int = field(init=False)
20
+ n_parameters: int = field(init=False)
21
+ parameters: FArray = field(init=False)
22
+ flux: Callable = field(init=False)
23
+ dflux: Callable = field(init=False)
24
+ source: Callable = field(init=False)
25
+ source_jacobian_wrt_variables: Callable = field(init=False)
26
+ source_jacobian_wrt_aux_variables: Callable = field(init=False)
27
+ nonconservative_matrix: Callable = field(init=False)
28
+ quasilinear_matrix: Callable = field(init=False)
29
+ eigenvalues: Callable = field(init=False)
30
+ residual: Callable = field(init=False)
31
+ project_2d_to_3d: Callable = field(init=False)
32
+ project_3d_to_2d: Callable = field(init=False)
33
+ boundary_conditions: Callable = field(default=None, init=False)
34
+
35
+ left_eigenvectors: Callable = field(default=None, init=False)
36
+ right_eigenvectors: Callable = field(default=None, init=False)
37
+
38
+ # --- Constants ---
39
+ module = {
40
+ "ones_like": np.ones_like,
41
+ "zeros_like": np.zeros_like,
42
+ "array": np.array,
43
+ "squeeze": np.squeeze,
44
+ }
45
+ printer = "numpy"
46
+
47
+
48
+ # ------------------------------------------------------------------
49
+
50
+ def __attrs_post_init__(self):
51
+ model = self.model
52
+
53
+
54
+ flux=model._flux.lambdify(modules=[self.module, self.printer])
55
+ dflux=model._dflux.lambdify(modules=[self.module, self.printer])
56
+ nonconservative_matrix=model._nonconservative_matrix.lambdify(
57
+ modules=[self.module, self.printer]
58
+ )
59
+ quasilinear_matrix=model._quasilinear_matrix.lambdify(
60
+ modules=[self.module, self.printer]
61
+ )
62
+ eigenvalues=model._eigenvalues.lambdify(
63
+ modules=[self.module, self.printer]
64
+ )
65
+ left_eigenvectors=model._left_eigenvectors.lambdify(
66
+ modules=[self.module, self.printer]
67
+ )
68
+ right_eigenvectors=model._right_eigenvectors.lambdify(
69
+ modules=[self.module, self.printer]
70
+ )
71
+ source=model._source.lambdify(modules=[self.module, self.printer])
72
+ source_jacobian_wrt_variables=model._source_jacobian_wrt_variables.lambdify(
73
+ modules=[self.module, self.printer]
74
+ )
75
+ source_jacobian_wrt_aux_variables=model._source_jacobian_wrt_aux_variables.lambdify(
76
+ modules=[self.module, self.printer]
77
+ )
78
+ residual=model._residual.lambdify(modules=[self.module, self.printer])
79
+ project_2d_to_3d=model._project_2d_to_3d.lambdify(
80
+ modules=[self.module, self.printer]
81
+ )
82
+ project_3d_to_2d=model._project_3d_to_2d.lambdify(
83
+ modules=[self.module, self.printer]
84
+ )
85
+ bcs = model._boundary_conditions.lambdify(modules=[self.module, self.printer])
86
+
87
+
88
+ # --- Assign frozen fields -------------------------------------
89
+ object.__setattr__(self, "name", model.name)
90
+ object.__setattr__(self, "dimension", model.dimension)
91
+ object.__setattr__(self, "n_variables", model.n_variables)
92
+ object.__setattr__(self, "n_aux_variables", model.n_aux_variables)
93
+ object.__setattr__(self, "n_parameters", model.n_parameters)
94
+ object.__setattr__(self, "parameters", model.parameter_values)
95
+
96
+ object.__setattr__(self, "flux", flux)
97
+ object.__setattr__(self, "dflux", dflux)
98
+ object.__setattr__(self, "source", source)
99
+ object.__setattr__(
100
+ self, "source_jacobian_wrt_variables", source_jacobian_wrt_variables
101
+ )
102
+ object.__setattr__(
103
+ self,
104
+ "source_jacobian_wrt_aux_variables",
105
+ source_jacobian_wrt_aux_variables,
106
+ )
107
+ object.__setattr__(self, "nonconservative_matrix", nonconservative_matrix)
108
+ object.__setattr__(self, "quasilinear_matrix", quasilinear_matrix)
109
+ object.__setattr__(self, "eigenvalues", eigenvalues)
110
+ object.__setattr__(self, "left_eigenvectors", left_eigenvectors)
111
+ object.__setattr__(self, "right_eigenvectors", right_eigenvectors)
112
+ object.__setattr__(self, "residual", residual)
113
+ object.__setattr__(self, "project_2d_to_3d", project_2d_to_3d)
114
+ object.__setattr__(self, "project_3d_to_2d", project_3d_to_2d)
115
+ object.__setattr__(self, "boundary_conditions", bcs)