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

Potentially problematic release.


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

Files changed (57) 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/gmsh_loader.py +301 -0
  8. zoomy_core/mesh/mesh.py +1192 -0
  9. zoomy_core/mesh/mesh_extrude.py +168 -0
  10. zoomy_core/mesh/mesh_util.py +487 -0
  11. zoomy_core/misc/custom_types.py +6 -0
  12. zoomy_core/misc/gui.py +61 -0
  13. zoomy_core/misc/interpolation.py +140 -0
  14. zoomy_core/misc/io.py +401 -0
  15. zoomy_core/misc/logger_config.py +18 -0
  16. zoomy_core/misc/misc.py +216 -0
  17. zoomy_core/misc/static_class.py +94 -0
  18. zoomy_core/model/analysis.py +147 -0
  19. zoomy_core/model/basefunction.py +113 -0
  20. zoomy_core/model/basemodel.py +512 -0
  21. zoomy_core/model/boundary_conditions.py +193 -0
  22. zoomy_core/model/initial_conditions.py +171 -0
  23. zoomy_core/model/model.py +63 -0
  24. zoomy_core/model/models/GN.py +70 -0
  25. zoomy_core/model/models/advection.py +53 -0
  26. zoomy_core/model/models/basisfunctions.py +181 -0
  27. zoomy_core/model/models/basismatrices.py +377 -0
  28. zoomy_core/model/models/core.py +564 -0
  29. zoomy_core/model/models/coupled_constrained.py +60 -0
  30. zoomy_core/model/models/old_smm copy.py +867 -0
  31. zoomy_core/model/models/poisson.py +41 -0
  32. zoomy_core/model/models/shallow_moments.py +757 -0
  33. zoomy_core/model/models/shallow_moments_sediment.py +378 -0
  34. zoomy_core/model/models/shallow_moments_topo.py +423 -0
  35. zoomy_core/model/models/shallow_moments_variants.py +1509 -0
  36. zoomy_core/model/models/shallow_water.py +266 -0
  37. zoomy_core/model/models/shallow_water_topo.py +111 -0
  38. zoomy_core/model/models/shear_shallow_flow.py +594 -0
  39. zoomy_core/model/models/sme_turbulent.py +613 -0
  40. zoomy_core/model/models/swe_old.py +1018 -0
  41. zoomy_core/model/models/vam.py +455 -0
  42. zoomy_core/postprocessing/postprocessing.py +72 -0
  43. zoomy_core/preprocessing/openfoam_moments.py +452 -0
  44. zoomy_core/transformation/helpers.py +25 -0
  45. zoomy_core/transformation/to_amrex.py +238 -0
  46. zoomy_core/transformation/to_c.py +181 -0
  47. zoomy_core/transformation/to_jax.py +14 -0
  48. zoomy_core/transformation/to_numpy.py +115 -0
  49. zoomy_core/transformation/to_openfoam.py +254 -0
  50. zoomy_core/transformation/to_ufl.py +67 -0
  51. {zoomy_core-0.1.1.dist-info → zoomy_core-0.1.2.dist-info}/METADATA +1 -1
  52. zoomy_core-0.1.2.dist-info/RECORD +55 -0
  53. zoomy_core-0.1.2.dist-info/top_level.txt +1 -0
  54. zoomy_core-0.1.1.dist-info/RECORD +0 -5
  55. zoomy_core-0.1.1.dist-info/top_level.txt +0 -1
  56. {zoomy_core-0.1.1.dist-info → zoomy_core-0.1.2.dist-info}/WHEEL +0 -0
  57. {zoomy_core-0.1.1.dist-info → zoomy_core-0.1.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,423 @@
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, Piecewise
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 attrs import define, field
14
+ import attr
15
+ from typing import Union, Dict, List
16
+
17
+
18
+ from library.zoomy_core.model.basemodel import (
19
+ register_sympy_attribute,
20
+ eigenvalue_dict_to_matrix,
21
+ )
22
+ from library.zoomy_core.model.basemodel import Model
23
+ from library.zoomy_core.model.models.basismatrices import Basismatrices
24
+ from library.zoomy_core.model.models.basisfunctions import Legendre_shifted, Basisfunction
25
+
26
+
27
+
28
+
29
+ @define(frozen=True, slots=True, kw_only=True)
30
+ class ShallowMomentsTopo(Model):
31
+ dimension: int = 2
32
+ level: int
33
+ variables: Union[list, int] = field(init=False)
34
+ positive_variables: Union[List[int], Dict[str, int], None] = attr.ib(default=attr.Factory(lambda: [1]))
35
+ aux_variables: Union[list, int] = field(default=0)
36
+ basisfunctions: Union[Basisfunction, type[Basisfunction]] = field(default=Legendre_shifted)
37
+ basismatrices: Basismatrices = field(init=False)
38
+
39
+ _default_parameters: dict = field(
40
+ init=False,
41
+ factory=lambda: {"g": 9.81, "ex": 0.0, "ey": 0.0, "ez": 1.0, "eps_low_water": 1e-6, "rho": 1000},
42
+ )
43
+
44
+ def __attrs_post_init__(self):
45
+ object.__setattr__(self, "variables", ((self.level+1)*self.dimension)+2)
46
+ object.__setattr__(self, "aux_variables", 2*((self.level+1)*self.dimension+2))
47
+ super().__attrs_post_init__()
48
+ aux_variables = self.aux_variables
49
+ aux_var_list = aux_variables.keys()
50
+ object.__setattr__(self, "aux_variables", register_sympy_attribute(aux_var_list, "qaux_"))
51
+
52
+ # Recompute basis matrices
53
+ object.__setattr__(self, "basisfunctions", self.basisfunctions(level=self.level))
54
+ basismatrices = Basismatrices(self.basisfunctions)
55
+ basismatrices.compute_matrices(self.level)
56
+ object.__setattr__(self, "basismatrices", basismatrices)
57
+
58
+ def get_primitives(self):
59
+ offset = self.level + 1
60
+ b = self.variables[0]
61
+ h = self.variables[1]
62
+ hinv = 1/h
63
+ ha = self.variables[2 : 2 + self.level + 1]
64
+ alpha = [ha[i] * hinv for i in range(offset)]
65
+ if self.dimension == 1:
66
+ hb = [0 for i in range(self.level+1)]
67
+ else:
68
+ hb = self.variables[2 + offset : 2 + offset + self.level + 1]
69
+ beta = [hb[i] * hinv for i in range(offset)]
70
+ return [b, h, alpha, beta, hinv]
71
+
72
+
73
+ def project_2d_to_3d(self):
74
+ out = Matrix([0 for i in range(6)])
75
+ level = self.level
76
+ offset = level+1
77
+ offset_aux = self.n_variables
78
+ x = self.position[0]
79
+ y = self.position[1]
80
+ z = self.position[2]
81
+
82
+ b, h, alpha, beta, hinv = self.get_primitives()
83
+ dbdx = self.aux_variables[0]
84
+ dhdx = self.aux_variables[1]
85
+ dbdy = self.aux_variables[offset_aux]
86
+ dhdy = self.aux_variables[1+offset_aux]
87
+ dalphadx = [self.aux_variables[2+i] for i in range(offset)]
88
+ if self.dimension == 2:
89
+ dbetady = [self.aux_variables[2+i+offset_aux] for i in range(offset)]
90
+
91
+ psi = [self.basisfunctions.eval_psi(k, z) for k in range(level+1)]
92
+ phi = [self.basisfunctions.eval(k, z) for k in range(level+1)]
93
+
94
+ rho_w = 1000.
95
+ g = 9.81
96
+ u_3d = self.basismatrices.basisfunctions.reconstruct_velocity_profile_at(alpha, z)
97
+ v_3d = 0
98
+ def dot(a, b):
99
+ s = 0
100
+ for i in range(len(a)):
101
+ s += a[i] * b[i]
102
+ return s
103
+ w_3d = - dhdx * dot(alpha,psi) - h * dot(dalphadx,psi) + dot(alpha, phi) * (z * dhdx + dbdx)
104
+ if self.dimension == 2:
105
+ v_3d = self.basismatrices.basisfunctions.reconstruct_velocity_profile_at(beta, z)
106
+ w_3d += - dhdy * dot(beta,psi) - h * dot(dbetady,psi) + dot(beta, phi) * (z * dhdy + dbdy)
107
+
108
+ out[0] = b
109
+ out[1] = h
110
+ out[2] = u_3d
111
+ out[3] = v_3d
112
+ out[4] = w_3d
113
+ out[5] = rho_w * g * h * (1-z)
114
+ return out
115
+
116
+ def flux(self):
117
+ flux_x = Matrix([0 for i in range(self.n_variables)])
118
+ flux_y = Matrix([0 for i in range(self.n_variables)])
119
+ b, h, alpha, beta, hinv = self.get_primitives()
120
+ p = self.parameters
121
+ flux_x[1] = h * alpha[0]
122
+ flux_x[2] = p.g * p.ez * h * h / 2
123
+ for k in range(self.level + 1):
124
+ for i in range(self.level + 1):
125
+ for j in range(self.level + 1):
126
+ flux_x[k + 2] += (
127
+ h * alpha[i] * alpha[j]
128
+ * self.basismatrices.A[k, i, j]
129
+ / self.basismatrices.M[k, k]
130
+ )
131
+ if self.dimension == 2:
132
+ offset = self.level + 1
133
+ p = self.parameters
134
+ for k in range(self.level + 1):
135
+ for i in range(self.level + 1):
136
+ for j in range(self.level + 1):
137
+ flux_x[1 + k + 1 + offset] += (
138
+ h * beta[i] * alpha[j]
139
+ * self.basismatrices.A[k, i, j]
140
+ / self.basismatrices.M[k, k]
141
+ )
142
+
143
+ flux_y[1] = h * beta[0]
144
+ flux_y[2 + offset] = p.g * p.ez * h * h / 2
145
+ for k in range(self.level + 1):
146
+ for i in range(self.level + 1):
147
+ for j in range(self.level + 1):
148
+ flux_y[1 + k + 1] += (
149
+ h * beta[i] * alpha[j]
150
+ * self.basismatrices.A[k, i, j]
151
+ / self.basismatrices.M[k, k]
152
+ )
153
+ for k in range(self.level + 1):
154
+ for i in range(self.level + 1):
155
+ for j in range(self.level + 1):
156
+ flux_y[1 + k + 1 + offset] += (
157
+ h * beta[i] * beta[j]
158
+ * self.basismatrices.A[k, i, j]
159
+ / self.basismatrices.M[k, k]
160
+ )
161
+ return [flux_x, flux_y][:self.dimension]
162
+
163
+ def nonconservative_matrix(self):
164
+ nc_x = Matrix([[0 for i in range(self.n_variables)] for j in range(self.n_variables)])
165
+ nc_y = Matrix([[0 for i in range(self.n_variables)] for j in range(self.n_variables)])
166
+ b, h, alpha, beta, hinv = self.get_primitives()
167
+ p = self.parameters
168
+ um = alpha[0]
169
+ for k in range(1, self.level + 1):
170
+ nc_x[1+k + 1, 1+k + 1] += um
171
+ for k in range(self.level + 1):
172
+ for i in range(1, self.level + 1):
173
+ for j in range(1, self.level + 1):
174
+ nc_x[1+k + 1, 1+i + 1] -= (
175
+ alpha[j]
176
+ * self.basismatrices.B[k, i, j]
177
+ / self.basismatrices.M[k, k]
178
+ )
179
+ if self.dimension == 2:
180
+ offset = self.level + 1
181
+ b, h, alpha, beta, hinv = self.get_primitives()
182
+ p = self.parameters
183
+ um = alpha[0]
184
+ vm = beta[0]
185
+ for k in range(1, self.level + 1):
186
+ nc_y[1+k + 1, 1+k + 1 + offset] += um
187
+ for k in range(self.level + 1):
188
+ for i in range(1, self.level + 1):
189
+ for j in range(1, self.level + 1):
190
+ nc_x[1+k + 1, 1+i + 1] -= (
191
+ alpha[j]
192
+ * self.basismatrices.B[k, i, j]
193
+ / self.basismatrices.M[k, k]
194
+ )
195
+ nc_y[1+k + 1, 1+i + 1 + offset] -= (
196
+ alpha[j]
197
+ * self.basismatrices.B[k, i, j]
198
+ / self.basismatrices.M[k, k]
199
+ )
200
+
201
+ for k in range(1, self.level + 1):
202
+ nc_x[1+k + 1 + offset, 1+k + 1] += vm
203
+ nc_y[1+k + 1 + offset, 1+k + 1 + offset] += vm
204
+ for k in range(self.level + 1):
205
+ for i in range(1, self.level + 1):
206
+ for j in range(1, self.level + 1):
207
+ nc_x[1+k + 1 + offset, 1+i + 1] -= (
208
+ beta[j]
209
+ * self.basismatrices.B[k, i, j]
210
+ / self.basismatrices.M[k, k]
211
+ )
212
+ nc_y[1+k + 1 + offset, 1+i + 1 + offset] -= (
213
+ beta[j]
214
+ * self.basismatrices.B[k, i, j]
215
+ / self.basismatrices.M[k, k]
216
+ )
217
+ return [-nc_x, -nc_y][:self.dimension]
218
+
219
+ def eigenvalues(self):
220
+ # we delete heigher order moments (level >= 2) for analytical eigenvalues
221
+ offset = self.level + 1
222
+ A = self.normal[0] * self.quasilinear_matrix()[0]
223
+ for d in range(1, self.dimension):
224
+ A += self.normal[d] * self.quasilinear_matrix()[d]
225
+ b, h, alpha, beta, hinv = self.get_primitives()
226
+ alpha_erase = alpha[1:] if self.level >= 2 else []
227
+ beta_erase = beta[1:] if self.level >= 2 else []
228
+ for alpha_i in alpha_erase:
229
+ A = A.subs(alpha_i, 0)
230
+ for beta_i in beta_erase:
231
+ A = A.subs(beta_i, 0)
232
+ return eigenvalue_dict_to_matrix(A.eigenvals())
233
+
234
+ def source(self):
235
+ out = Matrix([0 for i in range(self.n_variables)])
236
+ return out
237
+
238
+ def newtonian(self):
239
+ assert "nu" in vars(self.parameters)
240
+ out = Matrix([0 for i in range(self.n_variables)])
241
+ offset = self.level + 1
242
+ b, h, alpha, beta, hinv = self.get_primitives()
243
+ p = self.parameters
244
+ for k in range(1 + self.level):
245
+ for i in range(1 + self.level):
246
+ out[1+1 + k] += (
247
+ -p.nu
248
+ * alpha[i]
249
+ * hinv
250
+ * self.basismatrices.D[i, k]
251
+ / self.basismatrices.M[k, k]
252
+ )
253
+ if self.dimension == 2:
254
+ out[1+1 + k + offset] += (
255
+ -p.nu
256
+ * beta[i]
257
+ * hinv
258
+ * self.basismatrices.D[i, k]
259
+ / self.basismatrices.M[k, k]
260
+ )
261
+ return out
262
+
263
+ def slip_mod(self):
264
+ assert "lamda" in vars(self.parameters)
265
+ assert "rho" in vars(self.parameters)
266
+ assert "c_slipmod" in vars(self.parameters)
267
+
268
+ out = Matrix([0 for i in range(self.n_variables)])
269
+ offset = self.level+1
270
+ b, h, alpha, beta, hinv = self.get_primitives()
271
+ p = self.parameters
272
+ ub = 0
273
+ vb = 0
274
+ for i in range(1 + self.level):
275
+ ub += alpha[i]
276
+ vb += beta[i]
277
+ for k in range(1, 1 + self.level):
278
+ out[2 + k] += (
279
+ -1.0 * p.c_slipmod / p.lamda / p.rho * ub / self.basismatrices.M[k, k]
280
+ )
281
+ if self.dimension == 2:
282
+ out[2+offset+k] += (
283
+ -1.0 * p.c_slipmod / p.lamda / p.rho * vb / self.basismatrices.M[k, k]
284
+ )
285
+ return out
286
+
287
+
288
+ def slip(self):
289
+ assert "lamda" in vars(self.parameters)
290
+ assert "rho" in vars(self.parameters)
291
+ out = Matrix([0 for i in range(self.n_variables)])
292
+ offset = self.level + 1
293
+ b, h, alpha, beta, hinv = self.get_primitives()
294
+ p = self.parameters
295
+ for k in range(1 + self.level):
296
+ for i in range(1 + self.level):
297
+ out[1+1 + k] += (
298
+ -1.0 / p.lamda / p.rho * alpha[i] / self.basismatrices.M[k, k]
299
+ )
300
+ if self.dimension == 2:
301
+ out[1+1 + k + offset] += (
302
+ -1.0 / p.lamda / p.rho * beta[i] / self.basismatrices.M[k, k]
303
+ )
304
+ return out
305
+
306
+ def chezy(self):
307
+ assert "C" in vars(self.parameters)
308
+ out = Matrix([0 for i in range(self.n_variables)])
309
+ offset = self.level + 1
310
+ b, h, alpha, beta, hinv = self.get_primitives()
311
+ p = self.parameters
312
+ tmp = 0
313
+ for i in range(1 + self.level):
314
+ for j in range(1 + self.level):
315
+ tmp += alpha[i] * alpha[j] + beta[i] * beta[j]
316
+ sqrt = sympy.sqrt(tmp)
317
+ for k in range(1 + self.level):
318
+ for l in range(1 + self.level):
319
+ out[1 + k] += (
320
+ -1.0 / (p.C**2 * self.basismatrices.M[k, k]) * alpha[l] * sqrt
321
+ )
322
+ if self.dimension == 2:
323
+ out[1 + k + offset] += (
324
+ -1.0 / (p.C**2 * self.basismatrices.M[k, k]) * beta[l] * sqrt
325
+ )
326
+ return out
327
+
328
+ def gravity(self):
329
+ out = Matrix([0 for i in range(self.n_variables)])
330
+ out[2] = -self.parameters.g * self.parameters.ex * self.variables[0]
331
+ if self.dimension == 2:
332
+ offset = self.level + 1
333
+ out[2 + offset] = -self.parameters.g * self.parameters.ey * self.variables[0]
334
+ return out
335
+
336
+ def newtonian_turbulent_algebraic(self):
337
+ assert "nu" in vars(self.parameters)
338
+ assert "l_bl" in vars(self.parameters)
339
+ assert "l_turb" in vars(self.parameters)
340
+ assert "kappa" in vars(self.parameters)
341
+ out = Matrix([0 for i in range(self.n_variables)])
342
+ offset = self.level + 1
343
+
344
+ b, h, a, b, hinv = self.get_primitives()
345
+
346
+ p = self.parameters
347
+ dU_dx = a[0] / (p.l_turb * h)
348
+ abs_dU_dx = sympy.Piecewise((dU_dx, dU_dx >=0), (-dU_dx, True))
349
+ for k in range(1 + self.level):
350
+ out[1 + k] += (
351
+ -(p.nu + p.kappa * sympy.sqrt(p.nu * abs_dU_dx) * p.l_bl * ( 1-p.l_bl)) * dU_dx * self.basismatrices.phib[k] * hinv
352
+ )
353
+ for i in range(1 + self.level):
354
+ out[1 + k] += (
355
+ -p.nu * hinv
356
+ * a[i]
357
+ * self.basismatrices.D[i, k]
358
+ )
359
+ out[1 + k] += (
360
+ -p.kappa * sympy.sqrt(p.nu * abs_dU_dx) * hinv
361
+ * a[i]
362
+ * (self.basismatrices.Dxi[i, k] - self.basismatrices.Dxi2[i, k])
363
+ )
364
+ if self.dimension == 2:
365
+ dV_dy = b[0] / (p.l_turb * h)
366
+ abs_dV_dy = sympy.Piecewise((dV_dy, dV_dy >=0), (-dV_dy, True))
367
+ for k in range(1 + self.level):
368
+ out[1 + k + offset] += (
369
+ -(p.nu + p.kappa * sympy.sqrt(p.nu * abs_dV_dy) * p.l_bl * ( 1-p.l_bl)) * dV_dy * self.basismatrices.phib[k] *hinv
370
+ )
371
+ for i in range(1 + self.level):
372
+ out[1 + k + offset] += (
373
+ -p.nu
374
+ / h
375
+ * b[i]
376
+ * self.basismatrices.D[i, k]
377
+ )
378
+ out[1 + k + offset] += (
379
+ -p.kappa * sympy.sqrt(p.nu * abs_dV_dy) * hinv
380
+ * b[i]
381
+ * (self.basismatrices.Dxi[i, k] - self.basismatrices.Dxi2[i, k])
382
+ )
383
+
384
+ return out
385
+
386
+ @define(frozen=True, slots=True, kw_only=True)
387
+ class ShallowMomentsTopoNumerical(ShallowMomentsTopo):
388
+ ref_model: Model = field(init=False)
389
+
390
+ def __attrs_post_init__(self):
391
+ super().__attrs_post_init__()
392
+ object.__setattr__(self, "ref_model", ShallowMomentsTopo(level=self.level, dimension=self.dimension, boundary_conditions=self.boundary_conditions))
393
+
394
+ def flux(self):
395
+ return [self.substitute_precomputed_denominator(f, self.variables[1], self.aux_variables.hinv) for f in self.ref_model.flux()]
396
+
397
+ def nonconservative_matrix(self):
398
+ return [self.substitute_precomputed_denominator(f, self.variables[1], self.aux_variables.hinv) for f in self.ref_model.nonconservative_matrix()]
399
+
400
+ def quasilinear_matrix(self):
401
+ return [self.substitute_precomputed_denominator(f, self.variables[1], self.aux_variables.hinv) for f in self.ref_model.quasilinear_matrix()]
402
+
403
+ def source(self):
404
+ return self.substitute_precomputed_denominator(self.ref_model.source(), self.variables[1], self.aux_variables.hinv)
405
+
406
+ def source_implicit(self):
407
+ return self.substitute_precomputed_denominator(self.ref_model.source_implicit(), self.variables[1], self.aux_variables.hinv)
408
+
409
+ def residual(self):
410
+ return self.substitute_precomputed_denominator(self.ref_model.residual(), self.variables[1], self.aux_variables.hinv)
411
+
412
+ def left_eigenvectors(self):
413
+ return self.substitute_precomputed_denominator(self.ref_model.left_eigenvectors(), self.variables[1], self.aux_variables.hinv)
414
+
415
+ def right_eigenvectors(self):
416
+ return self.substitute_precomputed_denominator(self.ref_model.right_eigenvectors(), self.variables[1], self.aux_variables.hinv)
417
+
418
+ def eigenvalues(self):
419
+ h = self.variables[1]
420
+ evs = self.substitute_precomputed_denominator(self.ref_model.eigenvalues(), self.variables[1], self.aux_variables.hinv)
421
+ for i in range(self.n_variables):
422
+ evs[i] = Piecewise((evs[i], h > 1e-8), (0, True))
423
+ return evs