zoomy-core 0.1.11__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.
- zoomy_core/__init__.py +7 -0
- zoomy_core/decorators/decorators.py +25 -0
- zoomy_core/fvm/flux.py +52 -0
- zoomy_core/fvm/nonconservative_flux.py +97 -0
- zoomy_core/fvm/ode.py +55 -0
- zoomy_core/fvm/solver_numpy.py +297 -0
- zoomy_core/fvm/timestepping.py +13 -0
- zoomy_core/mesh/mesh.py +1236 -0
- zoomy_core/mesh/mesh_extrude.py +168 -0
- zoomy_core/mesh/mesh_util.py +487 -0
- zoomy_core/misc/custom_types.py +6 -0
- zoomy_core/misc/interpolation.py +140 -0
- zoomy_core/misc/io.py +439 -0
- zoomy_core/misc/logger_config.py +18 -0
- zoomy_core/misc/misc.py +213 -0
- zoomy_core/model/analysis.py +147 -0
- zoomy_core/model/basefunction.py +113 -0
- zoomy_core/model/basemodel.py +512 -0
- zoomy_core/model/boundary_conditions.py +193 -0
- zoomy_core/model/initial_conditions.py +171 -0
- zoomy_core/model/model.py +63 -0
- zoomy_core/model/models/GN.py +70 -0
- zoomy_core/model/models/advection.py +53 -0
- zoomy_core/model/models/basisfunctions.py +181 -0
- zoomy_core/model/models/basismatrices.py +377 -0
- zoomy_core/model/models/core.py +564 -0
- zoomy_core/model/models/coupled_constrained.py +60 -0
- zoomy_core/model/models/poisson.py +41 -0
- zoomy_core/model/models/shallow_moments.py +757 -0
- zoomy_core/model/models/shallow_moments_sediment.py +378 -0
- zoomy_core/model/models/shallow_moments_topo.py +423 -0
- zoomy_core/model/models/shallow_moments_variants.py +1509 -0
- zoomy_core/model/models/shallow_water.py +266 -0
- zoomy_core/model/models/shallow_water_topo.py +111 -0
- zoomy_core/model/models/shear_shallow_flow.py +594 -0
- zoomy_core/model/models/sme_turbulent.py +613 -0
- zoomy_core/model/models/vam.py +455 -0
- zoomy_core/postprocessing/postprocessing.py +72 -0
- zoomy_core/preprocessing/openfoam_moments.py +452 -0
- zoomy_core/transformation/helpers.py +25 -0
- zoomy_core/transformation/to_amrex.py +238 -0
- zoomy_core/transformation/to_c.py +181 -0
- zoomy_core/transformation/to_jax.py +14 -0
- zoomy_core/transformation/to_numpy.py +115 -0
- zoomy_core/transformation/to_openfoam.py +254 -0
- zoomy_core/transformation/to_ufl.py +67 -0
- zoomy_core-0.1.11.dist-info/METADATA +225 -0
- zoomy_core-0.1.11.dist-info/RECORD +51 -0
- zoomy_core-0.1.11.dist-info/WHEEL +5 -0
- zoomy_core-0.1.11.dist-info/licenses/LICENSE +674 -0
- zoomy_core-0.1.11.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
try:
|
|
2
|
+
import jax.numpy as jnp
|
|
3
|
+
_HAVE_JAX = True
|
|
4
|
+
except ImportError:
|
|
5
|
+
_HAVE_JAX = False
|
|
6
|
+
import numpy as jnp
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
|
|
10
|
+
import sympy
|
|
11
|
+
|
|
12
|
+
from sympy import (
|
|
13
|
+
Matrix,
|
|
14
|
+
lambdify,
|
|
15
|
+
powsimp,
|
|
16
|
+
init_printing,
|
|
17
|
+
zeros
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from typing import Union, Callable
|
|
21
|
+
from types import SimpleNamespace
|
|
22
|
+
from attrs import define, field
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
from library.model.boundary_conditions import BoundaryConditions
|
|
27
|
+
from library.model.initial_conditions import InitialConditions, Constant
|
|
28
|
+
from library.python.misc.misc import Zstruct
|
|
29
|
+
|
|
30
|
+
init_printing()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def vectorize_constant_sympy_expressions(expr, Q, Qaux):
|
|
34
|
+
symbol_list = Q.get_list() + Qaux.get_list()
|
|
35
|
+
q0 = Q[0]
|
|
36
|
+
|
|
37
|
+
rows, cols = expr.shape
|
|
38
|
+
|
|
39
|
+
new_data = []
|
|
40
|
+
|
|
41
|
+
for i in range(rows):
|
|
42
|
+
row = []
|
|
43
|
+
for j in range(cols):
|
|
44
|
+
entry = expr[i, j]
|
|
45
|
+
if not any(symbol in entry.free_symbols for symbol in symbol_list):
|
|
46
|
+
if entry == 0:
|
|
47
|
+
row.append(10 ** (-20) * q0)
|
|
48
|
+
else:
|
|
49
|
+
row.append(entry + 10 ** (-20) * q0)
|
|
50
|
+
else:
|
|
51
|
+
row.append(entry)
|
|
52
|
+
new_data.append(row)
|
|
53
|
+
|
|
54
|
+
return Matrix(new_data)
|
|
55
|
+
|
|
56
|
+
def default_simplify(expr):
|
|
57
|
+
return powsimp(expr, combine="all", force=False, deep=True)
|
|
58
|
+
|
|
59
|
+
def get_default_function_arguments():
|
|
60
|
+
return Zstruct(
|
|
61
|
+
time=sympy.symbols("t", real=True),
|
|
62
|
+
position=register_sympy_attribute(3, "X"),
|
|
63
|
+
distance=sympy.symbols("dX", real=True),
|
|
64
|
+
p=register_sympy_attribute(0, "p_"),
|
|
65
|
+
n=register_sympy_attribute(3, "n"),
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
@define(frozen=True, slots=True, kw_only=True)
|
|
69
|
+
class Core:
|
|
70
|
+
"""
|
|
71
|
+
Generic (virtual) model implementation.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
boundary_conditions: BoundaryConditions
|
|
75
|
+
|
|
76
|
+
name: str = "Model"
|
|
77
|
+
dimension: int = 1
|
|
78
|
+
|
|
79
|
+
initial_conditions: InitialConditions = field(factory=Constant)
|
|
80
|
+
aux_initial_conditions: InitialConditions = field(factory=Constant)
|
|
81
|
+
|
|
82
|
+
parameters: Zstruct = field(factory=lambda: Zstruct())
|
|
83
|
+
|
|
84
|
+
function_arguments: Zstruct = field(factory=lambda: get_default_function_arguments())
|
|
85
|
+
variables: Zstruct = field(init=False, default=1)
|
|
86
|
+
positive_variables: Union[dict, list, None] = field(default=None)
|
|
87
|
+
aux_variables: Zstruct = field(default=0)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
_simplify: Callable = field(factory=lambda: default_simplify)
|
|
92
|
+
|
|
93
|
+
# Derived fields initialized in __attrs_post_init__
|
|
94
|
+
_default_parameters: dict = field(init=False, factory=dict)
|
|
95
|
+
n_variables: int = field(init=False)
|
|
96
|
+
n_aux_variables: int = field(init=False)
|
|
97
|
+
n_parameters: int = field(init=False)
|
|
98
|
+
parameter_symbols: Zstruct = field(init=False)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def __attrs_post_init__(self):
|
|
103
|
+
|
|
104
|
+
# Use object.__setattr__ because class is frozen
|
|
105
|
+
object.__setattr__(self, "variables", register_sympy_attribute(self.variables, "q", self.positive_variables))
|
|
106
|
+
object.__setattr__(self, "aux_variables", register_sympy_attribute(self.aux_variables, "qaux"))
|
|
107
|
+
# object.__setattr__(self, "position", register_sympy_attribute(self.dimension, "X"))
|
|
108
|
+
|
|
109
|
+
object.__setattr__(self, "parameters_symbols", register_sympy_attribute(self.parameters, "p"))
|
|
110
|
+
object.__setattr__(self, "parameters", register_parameter_values(self.parameters))
|
|
111
|
+
object.__setattr__(
|
|
112
|
+
self, "normal",
|
|
113
|
+
register_sympy_attribute(["n" + str(i) for i in range(self.dimension)], "n")
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
object.__setattr__(self, "n_variables", self.variables.length())
|
|
117
|
+
object.__setattr__(self, "n_aux_variables", self.aux_variables.length())
|
|
118
|
+
object.__setattr__(self, "n_parameters", self.parameters.length())
|
|
119
|
+
|
|
120
|
+
def initialize_boundary_conditions(self, mesh):
|
|
121
|
+
self.boundary_conditions.initialize(
|
|
122
|
+
mesh,
|
|
123
|
+
self.time,
|
|
124
|
+
self.position,
|
|
125
|
+
self.distance,
|
|
126
|
+
self.variables,
|
|
127
|
+
self.aux_variables,
|
|
128
|
+
self.parameters,
|
|
129
|
+
self.normal,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
def print_boundary_conditions(self):
|
|
133
|
+
inputs = self.get_boundary_conditions_matrix_inputs()
|
|
134
|
+
return self.boundary_conditions.get_boundary_function_matrix(*inputs)
|
|
135
|
+
|
|
136
|
+
def squeeze(self, printer='jax'):
|
|
137
|
+
if printer == 'jax':
|
|
138
|
+
return jnp.squeeze
|
|
139
|
+
elif printer == 'numpy':
|
|
140
|
+
return np.squeeze
|
|
141
|
+
else:
|
|
142
|
+
assert False
|
|
143
|
+
|
|
144
|
+
def array(self, printer='jax'):
|
|
145
|
+
if printer == 'jax':
|
|
146
|
+
return jnp.array
|
|
147
|
+
elif printer == 'numpy':
|
|
148
|
+
return np.array
|
|
149
|
+
else:
|
|
150
|
+
assert False
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def get_boundary_conditions_matrix_inputs(self):
|
|
154
|
+
"""
|
|
155
|
+
Returns the inputs for the boundary conditions matrix.
|
|
156
|
+
"""
|
|
157
|
+
return (
|
|
158
|
+
self.time,
|
|
159
|
+
self.position,
|
|
160
|
+
self.distance,
|
|
161
|
+
self.variables,
|
|
162
|
+
self.aux_variables,
|
|
163
|
+
self.parameters,
|
|
164
|
+
self.normal,
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
def get_boundary_conditions_matrix_inputs_as_list(self):
|
|
168
|
+
"""
|
|
169
|
+
Returns the inputs for the boundary conditions matrix where the Zstructs are converted to lists.
|
|
170
|
+
"""
|
|
171
|
+
return [
|
|
172
|
+
self.time,
|
|
173
|
+
self.position.get_list(),
|
|
174
|
+
self.distance,
|
|
175
|
+
self.variables.get_list(),
|
|
176
|
+
self.aux_variables.get_list(),
|
|
177
|
+
self.parameters.get_list(),
|
|
178
|
+
self.normal.get_list(),
|
|
179
|
+
]
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _get_boundary_conditions(self, printer="jax"):
|
|
183
|
+
"""Returns a runtime boundary_conditions for jax arrays from the symbolic model."""
|
|
184
|
+
n_boundary_functions = len(self.boundary_conditions.boundary_functions)
|
|
185
|
+
bcs = []
|
|
186
|
+
for i in range(n_boundary_functions):
|
|
187
|
+
func_bc = lambdify(
|
|
188
|
+
[
|
|
189
|
+
self.time,
|
|
190
|
+
self.position.get_list(),
|
|
191
|
+
self.distance,
|
|
192
|
+
self.variables.get_list(),
|
|
193
|
+
self.aux_variables.get_list(),
|
|
194
|
+
self.parameters.get_list(),
|
|
195
|
+
self.normal.get_list(),
|
|
196
|
+
],
|
|
197
|
+
vectorize_constant_sympy_expressions(self.boundary_conditions.boundary_functions[i], self.variables, self.aux_variables),
|
|
198
|
+
printer,
|
|
199
|
+
)
|
|
200
|
+
# the func=func part is necessary, because of https://stackoverflow.com/questions/46535577/initialising-a-list-of-lambda-functions-in-python/46535637#46535637
|
|
201
|
+
f = (
|
|
202
|
+
lambda time,
|
|
203
|
+
position,
|
|
204
|
+
distance,
|
|
205
|
+
q,
|
|
206
|
+
qaux,
|
|
207
|
+
p,
|
|
208
|
+
n,
|
|
209
|
+
func=func_bc: self.squeeze(printer=printer)(
|
|
210
|
+
self.array(printer=printer)(func(time, position, distance, q, qaux, p, n)), axis=1
|
|
211
|
+
)
|
|
212
|
+
)
|
|
213
|
+
bcs.append(f)
|
|
214
|
+
return bcs
|
|
215
|
+
|
|
216
|
+
def _get_pde(self, printer="jax"):
|
|
217
|
+
"""Returns a runtime model for numpy arrays from the symbolic model."""
|
|
218
|
+
l_flux = [
|
|
219
|
+
lambdify(
|
|
220
|
+
(
|
|
221
|
+
self.variables.get_list(),
|
|
222
|
+
self.aux_variables.get_list(),
|
|
223
|
+
self.parameters.get_list(),
|
|
224
|
+
),
|
|
225
|
+
vectorize_constant_sympy_expressions(
|
|
226
|
+
self.flux()[d], self.variables, self.aux_variables
|
|
227
|
+
),
|
|
228
|
+
printer,
|
|
229
|
+
)
|
|
230
|
+
for d in range(self.dimension)
|
|
231
|
+
]
|
|
232
|
+
# the f=l_flux[d] part is necessary, because of https://stackoverflow.com/questions/46535577/initialising-a-list-of-lambda-functions-in-python/46535637#46535637
|
|
233
|
+
flux = [
|
|
234
|
+
lambda Q, Qaux, param, f=l_flux[d]: self.squeeze(printer=printer)(
|
|
235
|
+
self.array(printer=printer)(f(Q, Qaux, param)), axis=1
|
|
236
|
+
)
|
|
237
|
+
for d in range(self.dimension)
|
|
238
|
+
]
|
|
239
|
+
l_flux_jacobian = lambdify(
|
|
240
|
+
[
|
|
241
|
+
self.variables.get_list(),
|
|
242
|
+
self.aux_variables.get_list(),
|
|
243
|
+
self.parameters.get_list(),
|
|
244
|
+
],
|
|
245
|
+
self.flux_jacobian(),
|
|
246
|
+
printer,
|
|
247
|
+
)
|
|
248
|
+
flux_jacobian = l_flux_jacobian
|
|
249
|
+
|
|
250
|
+
l_nonconservative_matrix = [
|
|
251
|
+
lambdify(
|
|
252
|
+
[
|
|
253
|
+
self.variables.get_list(),
|
|
254
|
+
self.aux_variables.get_list(),
|
|
255
|
+
self.parameters.get_list(),
|
|
256
|
+
],
|
|
257
|
+
vectorize_constant_sympy_expressions(
|
|
258
|
+
self.nonconservative_matrix()[d],
|
|
259
|
+
self.variables,
|
|
260
|
+
self.aux_variables,
|
|
261
|
+
),
|
|
262
|
+
printer,
|
|
263
|
+
)
|
|
264
|
+
for d in range(self.dimension)
|
|
265
|
+
]
|
|
266
|
+
nonconservative_matrix = [
|
|
267
|
+
lambda Q, Qaux, param, f=l_nonconservative_matrix[d]: f(Q, Qaux, param)
|
|
268
|
+
for d in range(self.dimension)
|
|
269
|
+
]
|
|
270
|
+
|
|
271
|
+
l_quasilinear_matrix = [
|
|
272
|
+
lambdify(
|
|
273
|
+
[
|
|
274
|
+
self.variables.get_list(),
|
|
275
|
+
self.aux_variables.get_list(),
|
|
276
|
+
self.parameters.get_list(),
|
|
277
|
+
],
|
|
278
|
+
vectorize_constant_sympy_expressions(
|
|
279
|
+
self.quasilinear_matrix()[d], self.variables, self.aux_variables
|
|
280
|
+
),
|
|
281
|
+
printer,
|
|
282
|
+
)
|
|
283
|
+
for d in range(self.dimension)
|
|
284
|
+
]
|
|
285
|
+
quasilinear_matrix = l_quasilinear_matrix
|
|
286
|
+
|
|
287
|
+
l_eigenvalues = lambdify(
|
|
288
|
+
[
|
|
289
|
+
self.variables.get_list(),
|
|
290
|
+
self.aux_variables.get_list(),
|
|
291
|
+
self.parameters.get_list(),
|
|
292
|
+
self.normal.get_list(),
|
|
293
|
+
],
|
|
294
|
+
vectorize_constant_sympy_expressions(
|
|
295
|
+
self.eigenvalues(), self.variables, self.aux_variables
|
|
296
|
+
),
|
|
297
|
+
printer,
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
def eigenvalues(Q, Qaux, param, normal):
|
|
301
|
+
return jnp.squeeze(
|
|
302
|
+
jnp.array(l_eigenvalues(Q, Qaux, param, normal)), axis=1
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
l_left_eigenvectors = lambdify(
|
|
306
|
+
[
|
|
307
|
+
self.variables.get_list(),
|
|
308
|
+
self.aux_variables.get_list(),
|
|
309
|
+
self.parameters.get_list(),
|
|
310
|
+
self.normal.get_list(),
|
|
311
|
+
],
|
|
312
|
+
vectorize_constant_sympy_expressions(
|
|
313
|
+
self.left_eigenvectors(), self.variables, self.aux_variables
|
|
314
|
+
),
|
|
315
|
+
printer,
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
def left_eigenvectors(Q, Qaux, param, normal):
|
|
319
|
+
return self.squeeze(printer=printer)(
|
|
320
|
+
self.array(printer=printer)(l_left_eigenvectors(Q, Qaux, param, normal)), axis=1
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
l_right_eigenvectors = lambdify(
|
|
325
|
+
[
|
|
326
|
+
self.variables.get_list(),
|
|
327
|
+
self.aux_variables.get_list(),
|
|
328
|
+
self.parameters.get_list(),
|
|
329
|
+
self.normal.get_list(),
|
|
330
|
+
],
|
|
331
|
+
vectorize_constant_sympy_expressions(
|
|
332
|
+
self.right_eigenvectors(), self.variables, self.aux_variables
|
|
333
|
+
),
|
|
334
|
+
printer,
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
def right_eigenvectors(Q, Qaux, param, normal):
|
|
338
|
+
return self.squeeze(printer=printer)(
|
|
339
|
+
self.array(printer=printer)(l_right_eigenvectors(Q, Qaux, param, normal)), axis=1
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
l_source = lambdify(
|
|
345
|
+
[
|
|
346
|
+
self.variables.get_list(),
|
|
347
|
+
self.aux_variables.get_list(),
|
|
348
|
+
self.parameters.get_list(),
|
|
349
|
+
],
|
|
350
|
+
vectorize_constant_sympy_expressions(
|
|
351
|
+
self.source(), self.variables, self.aux_variables
|
|
352
|
+
),
|
|
353
|
+
printer,
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
def source(Q, Qaux, param):
|
|
357
|
+
return self.squeeze(printer=printer)(self.array(printer=printer)(l_source(Q, Qaux, param)), axis=1)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
l_source_jacobian = lambdify(
|
|
361
|
+
[
|
|
362
|
+
self.variables.get_list(),
|
|
363
|
+
self.aux_variables.get_list(),
|
|
364
|
+
self.parameters.get_list(),
|
|
365
|
+
],
|
|
366
|
+
vectorize_constant_sympy_expressions(
|
|
367
|
+
self.source_jacobian(), self.variables, self.aux_variables
|
|
368
|
+
),
|
|
369
|
+
printer,
|
|
370
|
+
)
|
|
371
|
+
source_jacobian = l_source_jacobian
|
|
372
|
+
|
|
373
|
+
l_source_implicit = lambdify(
|
|
374
|
+
[
|
|
375
|
+
self.variables.get_list(),
|
|
376
|
+
self.aux_variables.get_list(),
|
|
377
|
+
self.parameters.get_list(),
|
|
378
|
+
],
|
|
379
|
+
vectorize_constant_sympy_expressions(
|
|
380
|
+
self.source_implicit(), self.variables, self.aux_variables
|
|
381
|
+
),
|
|
382
|
+
printer,
|
|
383
|
+
)
|
|
384
|
+
def source_implicit(Q, Qaux, param):
|
|
385
|
+
return self.squeeze(printer=printer)(self.array(printer=printer)(l_source_implicit(Q, Qaux, param)), axis=1)
|
|
386
|
+
|
|
387
|
+
l_residual = lambdify(
|
|
388
|
+
[
|
|
389
|
+
self.variables.get_list(),
|
|
390
|
+
self.aux_variables.get_list(),
|
|
391
|
+
self.parameters.get_list(),
|
|
392
|
+
],
|
|
393
|
+
vectorize_constant_sympy_expressions(
|
|
394
|
+
self.residual(), self.variables, self.aux_variables
|
|
395
|
+
),
|
|
396
|
+
printer,
|
|
397
|
+
)
|
|
398
|
+
def residual(Q, Qaux, param):
|
|
399
|
+
return self.squeeze(printer=printer)(self.array(printer=printer)(l_residual(Q, Qaux, param)), axis=1)
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
l_interpolate_3d = lambdify(
|
|
403
|
+
[
|
|
404
|
+
self.position.get_list(),
|
|
405
|
+
self.variables.get_list(),
|
|
406
|
+
self.aux_variables.get_list(),
|
|
407
|
+
self.parameters.get_list(),
|
|
408
|
+
],
|
|
409
|
+
vectorize_constant_sympy_expressions(
|
|
410
|
+
self.interpolate_3d(), self.variables, self.aux_variables
|
|
411
|
+
),
|
|
412
|
+
printer,
|
|
413
|
+
)
|
|
414
|
+
def interpolate_3d(X, Q, Qaux, param):
|
|
415
|
+
return self.squeeze(printer=printer)(self.array(printer=printer)(l_interpolate_3d(X, Q, Qaux, param)), axis=1)
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
left_eigenvectors = None
|
|
420
|
+
right_eigenvectors = None
|
|
421
|
+
d = {
|
|
422
|
+
"flux": flux,
|
|
423
|
+
"flux_jacobian": flux_jacobian,
|
|
424
|
+
"nonconservative_matrix": nonconservative_matrix,
|
|
425
|
+
"quasilinear_matrix": quasilinear_matrix,
|
|
426
|
+
"eigenvalues": eigenvalues,
|
|
427
|
+
"left_eigenvectors": left_eigenvectors,
|
|
428
|
+
"right_eigenvectors": right_eigenvectors,
|
|
429
|
+
"source": source,
|
|
430
|
+
"source_jacobian": source_jacobian,
|
|
431
|
+
"source_implicit": source_implicit,
|
|
432
|
+
"residual": residual,
|
|
433
|
+
"interpolate_3d": interpolate_3d,
|
|
434
|
+
}
|
|
435
|
+
return SimpleNamespace(**d)
|
|
436
|
+
|
|
437
|
+
def flux(self):
|
|
438
|
+
return [Matrix(self.variables[:]) for d in range(self.dimension)]
|
|
439
|
+
|
|
440
|
+
def nonconservative_matrix(self):
|
|
441
|
+
return [zeros(self.n_variables, self.n_variables) for d in range(self.dimension)]
|
|
442
|
+
|
|
443
|
+
def source(self):
|
|
444
|
+
return zeros(self.n_variables, 1)
|
|
445
|
+
|
|
446
|
+
def flux_jacobian(self):
|
|
447
|
+
""" generated automatically unless explicitly provided """
|
|
448
|
+
return [ self._simplify(
|
|
449
|
+
Matrix(self.flux()[d]).jacobian(self.variables),
|
|
450
|
+
) for d in range(self.dimension) ]
|
|
451
|
+
|
|
452
|
+
def quasilinear_matrix(self):
|
|
453
|
+
""" generated automatically unless explicitly provided """
|
|
454
|
+
return [ self._simplify(
|
|
455
|
+
Matrix(self.flux_jacobian()[d] + self.nonconservative_matrix()[d],
|
|
456
|
+
)
|
|
457
|
+
) for d in range(self.dimension) ]
|
|
458
|
+
|
|
459
|
+
def source_jacobian(self):
|
|
460
|
+
""" generated automatically unless explicitly provided """
|
|
461
|
+
return self._simplify(
|
|
462
|
+
Matrix(self.source()).jacobian(self.variables),
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
def source_implicit(self):
|
|
466
|
+
return zeros(self.n_variables, 1)
|
|
467
|
+
|
|
468
|
+
def residual(self):
|
|
469
|
+
return zeros(self.n_variables, 1)
|
|
470
|
+
|
|
471
|
+
def interpolate_3d(self):
|
|
472
|
+
return zeros(6, 1)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
def eigenvalues(self):
|
|
476
|
+
A = self.normal[0] * self.quasilinear_matrix()[0]
|
|
477
|
+
for d in range(1, self.dimension):
|
|
478
|
+
A += self.normal[d] * self.quasilinear_matrix()[d]
|
|
479
|
+
return self._simplify(eigenvalue_dict_to_matrix(A.eigenvals()))
|
|
480
|
+
|
|
481
|
+
def left_eigenvectors(self):
|
|
482
|
+
return zeros(self.n_variables, self.n_variables)
|
|
483
|
+
|
|
484
|
+
def right_eigenvectors(self):
|
|
485
|
+
return zeros(self.n_variables, self.n_variables)
|
|
486
|
+
|
|
487
|
+
def substitute_precomputed_denominator(self, expr, sym, sym_inv):
|
|
488
|
+
if isinstance(expr, sympy.MatrixBase):
|
|
489
|
+
return expr.applyfunc(lambda e: self.substitute_precomputed_denominator(e, sym, sym_inv))
|
|
490
|
+
|
|
491
|
+
num, den = sympy.fraction(expr)
|
|
492
|
+
if den.has(sym):
|
|
493
|
+
# split into (part involving sym, part not involving sym)
|
|
494
|
+
den_sym, den_rest = den.as_independent(sym, as_Add=False)
|
|
495
|
+
# careful: as_independent returns (independent, dependent)
|
|
496
|
+
# so we need to swap naming
|
|
497
|
+
den_rest, den_sym = den_sym, den_rest
|
|
498
|
+
|
|
499
|
+
# replace sym by sym_inv in the sym-dependent part
|
|
500
|
+
den_sym_repl = den_sym.xreplace({sym: sym_inv})
|
|
501
|
+
|
|
502
|
+
return self.substitute_precomputed_denominator(num, sym, sym_inv) * den_sym_repl / den_rest
|
|
503
|
+
elif expr.args:
|
|
504
|
+
return expr.func(*[self.substitute_precomputed_denominator(arg, sym, sym_inv) for arg in expr.args])
|
|
505
|
+
else:
|
|
506
|
+
return expr
|
|
507
|
+
|
|
508
|
+
def transform_positive_variable_intput_to_list(argument, positive, n_variables):
|
|
509
|
+
out = [False for _ in range(n_variables)]
|
|
510
|
+
if positive is None:
|
|
511
|
+
return out
|
|
512
|
+
if type(positive) == type({}):
|
|
513
|
+
assert type(argument) == type(positive)
|
|
514
|
+
for i, a in enumerate(argument.keys()):
|
|
515
|
+
if a in positive.keys():
|
|
516
|
+
out[i] = positive[a]
|
|
517
|
+
if type(positive) == list:
|
|
518
|
+
for i in positive:
|
|
519
|
+
out[i] = True
|
|
520
|
+
return out
|
|
521
|
+
|
|
522
|
+
def register_sympy_attribute(argument, string_identifier="q_", positives=None):
|
|
523
|
+
if type(argument) == int:
|
|
524
|
+
positive = transform_positive_variable_intput_to_list(argument, positives, argument)
|
|
525
|
+
attributes = {
|
|
526
|
+
string_identifier + str(i): sympy.symbols(
|
|
527
|
+
string_identifier + str(i), real=True, positive=positive[i]
|
|
528
|
+
)
|
|
529
|
+
for i in range(argument)
|
|
530
|
+
}
|
|
531
|
+
elif type(argument) == type({}):
|
|
532
|
+
positive = transform_positive_variable_intput_to_list(argument, positives, len(argument))
|
|
533
|
+
attributes = {
|
|
534
|
+
name: sympy.symbols(str(name), real=True, positive=pos) for name, pos in zip(argument.keys(), positive)
|
|
535
|
+
}
|
|
536
|
+
elif type(argument) == list:
|
|
537
|
+
positive = transform_positive_variable_intput_to_list(argument, positives, len(argument))
|
|
538
|
+
attributes = {name: sympy.symbols(str(name), real=True, positive=pos) for name, pos in zip(argument, positive)}
|
|
539
|
+
elif type(argument) == Zstruct:
|
|
540
|
+
d = argument.as_dict()
|
|
541
|
+
register_sympy_attribute(d, string_identifier, positives)
|
|
542
|
+
else:
|
|
543
|
+
assert False
|
|
544
|
+
return Zstruct(**attributes)
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
def register_parameter_symbols(parameters):
|
|
548
|
+
if type(parameters) == type({}):
|
|
549
|
+
for k, v in parameters.items():
|
|
550
|
+
parameters[k] = sympy.symbols(str(k), real=True)
|
|
551
|
+
elif type(parameters) == Zstruct:
|
|
552
|
+
d = parameters.as_dict()
|
|
553
|
+
register_parameter_symbols(d)
|
|
554
|
+
else:
|
|
555
|
+
assert False
|
|
556
|
+
return register_sympy_attribute(parameters, "p_")
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
def eigenvalue_dict_to_matrix(eigenvalues, simplify=default_simplify):
|
|
560
|
+
evs = []
|
|
561
|
+
for ev, mult in eigenvalues.items():
|
|
562
|
+
for i in range(mult):
|
|
563
|
+
evs.append(simplify(ev))
|
|
564
|
+
return Matrix(evs)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import numpy.polynomial.legendre as L
|
|
3
|
+
import numpy.polynomial.chebyshev as C
|
|
4
|
+
from scipy.optimize import least_squares as lsq
|
|
5
|
+
import sympy
|
|
6
|
+
from sympy import Matrix
|
|
7
|
+
from sympy.abc import x
|
|
8
|
+
|
|
9
|
+
from sympy import integrate, diff
|
|
10
|
+
from sympy import legendre
|
|
11
|
+
from sympy import lambdify
|
|
12
|
+
|
|
13
|
+
from zoomy_core.model.basemodel import (
|
|
14
|
+
register_sympy_attribute,
|
|
15
|
+
eigenvalue_dict_to_matrix,
|
|
16
|
+
)
|
|
17
|
+
from zoomy_core.model.basemodel import Model
|
|
18
|
+
import zoomy_core.model.initial_conditions as IC
|
|
19
|
+
|
|
20
|
+
class CoupledConstrained(Model):
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
boundary_conditions,
|
|
24
|
+
initial_conditions,
|
|
25
|
+
dimension=2,
|
|
26
|
+
fields=2,
|
|
27
|
+
aux_variables=4,
|
|
28
|
+
parameters={},
|
|
29
|
+
_default_parameters={},
|
|
30
|
+
settings={},
|
|
31
|
+
settings_default={},
|
|
32
|
+
):
|
|
33
|
+
self.variables = register_sympy_attribute(fields, "q")
|
|
34
|
+
self.n_variables = self.variables.length()
|
|
35
|
+
super().__init__(
|
|
36
|
+
dimension=dimension,
|
|
37
|
+
fields=fields,
|
|
38
|
+
aux_variables=aux_variables,
|
|
39
|
+
parameters=parameters,
|
|
40
|
+
_default_parameters=_default_parameters,
|
|
41
|
+
boundary_conditions=boundary_conditions,
|
|
42
|
+
initial_conditions=initial_conditions,
|
|
43
|
+
settings={**settings_default, **settings},
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def source_implicit(self):
|
|
48
|
+
out = Matrix([0 for i in range(2)])
|
|
49
|
+
u = self.variables[0]
|
|
50
|
+
p = self.variables[1]
|
|
51
|
+
param = self.parameters
|
|
52
|
+
dudt = self.aux_variables.dudx
|
|
53
|
+
dudx = self.aux_variables.dudx
|
|
54
|
+
dpdx = self.aux_variables.dpdx
|
|
55
|
+
f = self.aux_variables.f
|
|
56
|
+
out[0] = dudt + dpdx + 1
|
|
57
|
+
out[1] = dudx + f
|
|
58
|
+
# out[0] = dudx -1.
|
|
59
|
+
# out[1] = dpdx
|
|
60
|
+
return out
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import numpy.polynomial.legendre as L
|
|
3
|
+
import numpy.polynomial.chebyshev as C
|
|
4
|
+
from scipy.optimize import least_squares as lsq
|
|
5
|
+
import sympy
|
|
6
|
+
from sympy import Matrix, sqrt
|
|
7
|
+
from sympy.abc import x
|
|
8
|
+
from attr import define, field
|
|
9
|
+
|
|
10
|
+
from sympy import integrate, diff
|
|
11
|
+
from sympy import legendre
|
|
12
|
+
from sympy import lambdify
|
|
13
|
+
|
|
14
|
+
from zoomy_core.misc.misc import Zstruct
|
|
15
|
+
from zoomy_core.model.basemodel import (
|
|
16
|
+
register_sympy_attribute,
|
|
17
|
+
eigenvalue_dict_to_matrix,
|
|
18
|
+
)
|
|
19
|
+
from zoomy_core.model.basemodel import Model
|
|
20
|
+
import zoomy_core.model.initial_conditions as IC
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@define(kw_only=True, slots=True, frozen=True)
|
|
24
|
+
class Poisson(Model):
|
|
25
|
+
dimension: int = 1
|
|
26
|
+
variables: Zstruct = field(init=False, default=1)
|
|
27
|
+
aux_variables: Zstruct = field(factory = lambda: ['ddTdxx', 'ddTdyy', 'ddTdzz'])
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def residual(self):
|
|
31
|
+
R = Matrix([0 for i in range(self.n_variables)])
|
|
32
|
+
T = self.variables[0]
|
|
33
|
+
ddTdxx = self.aux_variables.ddTdxx
|
|
34
|
+
param = self.parameters
|
|
35
|
+
|
|
36
|
+
R[0] = - ddTdxx + 2
|
|
37
|
+
return R
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|