zoomy-core 0.1.14__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 (57) hide show
  1. decorators/decorators.py +25 -0
  2. fvm/__init__.py +0 -0
  3. fvm/flux.py +52 -0
  4. fvm/nonconservative_flux.py +97 -0
  5. fvm/ode.py +55 -0
  6. fvm/solver_numpy.py +297 -0
  7. fvm/timestepping.py +13 -0
  8. mesh/__init__.py +0 -0
  9. mesh/mesh.py +1239 -0
  10. mesh/mesh_extrude.py +168 -0
  11. mesh/mesh_util.py +487 -0
  12. misc/__init__.py +0 -0
  13. misc/custom_types.py +6 -0
  14. misc/interpolation.py +140 -0
  15. misc/io.py +448 -0
  16. misc/logger_config.py +18 -0
  17. misc/misc.py +218 -0
  18. model/__init__.py +0 -0
  19. model/analysis.py +147 -0
  20. model/basefunction.py +113 -0
  21. model/basemodel.py +513 -0
  22. model/boundary_conditions.py +193 -0
  23. model/initial_conditions.py +171 -0
  24. model/model.py +65 -0
  25. model/models/GN.py +70 -0
  26. model/models/advection.py +53 -0
  27. model/models/basisfunctions.py +181 -0
  28. model/models/basismatrices.py +381 -0
  29. model/models/coupled_constrained.py +60 -0
  30. model/models/poisson.py +41 -0
  31. model/models/shallow_moments.py +757 -0
  32. model/models/shallow_moments_sediment.py +378 -0
  33. model/models/shallow_moments_topo.py +423 -0
  34. model/models/shallow_moments_variants.py +1509 -0
  35. model/models/shallow_water.py +266 -0
  36. model/models/shallow_water_topo.py +111 -0
  37. model/models/shear_shallow_flow.py +594 -0
  38. model/models/sme_turbulent.py +613 -0
  39. model/models/vam.py +455 -0
  40. postprocessing/__init__.py +0 -0
  41. postprocessing/plotting.py +244 -0
  42. postprocessing/postprocessing.py +75 -0
  43. preprocessing/__init__.py +0 -0
  44. preprocessing/openfoam_moments.py +453 -0
  45. transformation/__init__.py +0 -0
  46. transformation/helpers.py +25 -0
  47. transformation/to_amrex.py +241 -0
  48. transformation/to_c.py +185 -0
  49. transformation/to_jax.py +14 -0
  50. transformation/to_numpy.py +118 -0
  51. transformation/to_openfoam.py +258 -0
  52. transformation/to_ufl.py +67 -0
  53. zoomy_core-0.1.14.dist-info/METADATA +52 -0
  54. zoomy_core-0.1.14.dist-info/RECORD +57 -0
  55. zoomy_core-0.1.14.dist-info/WHEEL +5 -0
  56. zoomy_core-0.1.14.dist-info/licenses/LICENSE +674 -0
  57. zoomy_core-0.1.14.dist-info/top_level.txt +8 -0
@@ -0,0 +1,381 @@
1
+ import os
2
+ import numpy as np
3
+ import sympy
4
+ from sympy import integrate, diff, Matrix
5
+ from sympy.abc import z
6
+ from time import time as get_time
7
+
8
+
9
+ from scipy.optimize import least_squares as lsq
10
+
11
+ from zoomy_core.model.models.basisfunctions import Legendre_shifted
12
+ from zoomy_core.misc import misc as misc
13
+
14
+
15
+ class Basismatrices:
16
+ def __init__(self, basis=Legendre_shifted(), use_cache=True, cache_path=".cache"):
17
+ self.basisfunctions = basis
18
+ self.use_cache = use_cache
19
+ self.cache_dir = cache_path
20
+ self.cache_subdir = f"basismatrices/{basis.name}/{basis.level}"
21
+
22
+ def load_cached_matrices(self):
23
+ main_dir = misc.get_main_directory()
24
+
25
+ path = os.path.join(os.path.join(main_dir, self.cache_dir), self.cache_subdir)
26
+ failed = False
27
+ try:
28
+ self.phib = np.load(os.path.join(path, "phib.npy"))
29
+ self.M = np.load(os.path.join(path, "M.npy"))
30
+ self.A = np.load(os.path.join(path, "A.npy"))
31
+ self.B = np.load(os.path.join(path, "B.npy"))
32
+ self.D = np.load(os.path.join(path, "D.npy"))
33
+ self.Dxi = np.load(os.path.join(path, "Dxi.npy"))
34
+ self.Dxi2 = np.load(os.path.join(path, "Dxi2.npy"))
35
+ self.DD = np.load(os.path.join(path, "DD.npy"))
36
+ self.D1 = np.load(os.path.join(path, "D1.npy"))
37
+ self.DT = np.load(os.path.join(path, "DT.npy"))
38
+ except:
39
+ failed = True
40
+ return failed
41
+
42
+ def save_cached_matrices(self):
43
+ main_dir = misc.get_main_directory()
44
+
45
+ path = os.path.join(os.path.join(main_dir, self.cache_dir), self.cache_subdir)
46
+ os.makedirs(path, exist_ok=True)
47
+ np.save(os.path.join(path, "phib"), self.phib)
48
+ np.save(os.path.join(path, "M"), self.M)
49
+ np.save(os.path.join(path, "A"), self.A)
50
+ np.save(os.path.join(path, "B"), self.B)
51
+ np.save(os.path.join(path, "D"), self.D)
52
+ np.save(os.path.join(path, "Dxi"), self.Dxi)
53
+ np.save(os.path.join(path, "Dxi2"), self.Dxi2)
54
+ np.save(os.path.join(path, "DD"), self.DD)
55
+ np.save(os.path.join(path, "D1"), self.D1)
56
+ np.save(os.path.join(path, "DT"), self.DT)
57
+
58
+
59
+
60
+ def _compute_matrices(self, level):
61
+ start = get_time()
62
+ # object is key here, as we need to have a symbolic representation of the fractions.
63
+ self.phib = np.empty((level + 1), dtype=object)
64
+ self.M = np.empty((level + 1, level + 1), dtype=object)
65
+ self.A = np.empty((level + 1, level + 1, level + 1), dtype=object)
66
+ self.B = np.empty((level + 1, level + 1, level + 1), dtype=object)
67
+ self.D = np.empty((level + 1, level + 1), dtype=object)
68
+ self.Dxi = np.empty((level + 1, level + 1), dtype=object)
69
+ self.Dxi2 = np.empty((level + 1, level + 1), dtype=object)
70
+
71
+ self.DD = np.empty((level + 1, level + 1), dtype=object)
72
+ self.D1 = np.empty((level + 1, level + 1), dtype=object)
73
+ self.DT = np.empty((level + 1, level + 1, level + 1), dtype=object)
74
+
75
+ for k in range(level + 1):
76
+ self.phib[k] = self._phib(k)
77
+ for i in range(level + 1):
78
+ self.M[k, i] = self._M(k, i)
79
+ self.D[k, i] = self._D(k, i)
80
+ self.Dxi[k, i] = self._Dxi(k, i)
81
+ self.Dxi2[k, i] = self._Dxi2(k, i)
82
+
83
+ self.DD[k, i] = self._DD(k, i)
84
+ self.D1[k, i] = self._D1(k, i)
85
+ for j in range(level + 1):
86
+ self.A[k, i, j] = self._A(k, i, j)
87
+ self.B[k, i, j] = self._B(k, i, j)
88
+ self.DT[k, i, j] = self._DT(k, i, j)
89
+
90
+
91
+ def compute_matrices(self, level):
92
+ failed = True
93
+ if self.use_cache:
94
+ failed = self.load_cached_matrices()
95
+ if failed or (not self.use_cache):
96
+ self._compute_matrices(level)
97
+ self.save_cached_matrices()
98
+
99
+ def enforce_boundary_conditions_lsq(self, rhs=np.zeros(2), dim=1):
100
+ level = len(self.basisfunctions.basis) - 1
101
+ constraint_bottom = [self.basisfunctions.eval(i, 0.0) for i in range(level + 1)]
102
+ constraint_top = [
103
+ diff(self.basisfunctions.eval(i, z), z).subs(z, 1.0)
104
+ for i in range(level + 1)
105
+ ]
106
+ A = Matrix([constraint_bottom, constraint_top])
107
+
108
+ I = np.linspace(0, level, 1 + level, dtype=int)
109
+ I_enforce = I[1:]
110
+ rhs = np.zeros(2)
111
+ # rhs = np.zeros(level)
112
+ I_free = np.delete(I, I_enforce)
113
+ A_enforce = A[:, list(I_enforce)]
114
+ A_free = np.array(A[:, list(I_free)], dtype=float)
115
+ AtA = A_enforce.T @ A_enforce
116
+ reg = 10 ** (-6)
117
+ A_enforce_inv = np.array((AtA + reg * np.eye(AtA.shape[0])).inv(), dtype=float)
118
+
119
+ def f_1d(Q):
120
+ for i, q in enumerate(Q.T):
121
+ # alpha_enforce = q[I_enforce+1]
122
+ alpha_free = q[I_free + 1]
123
+ b = rhs - np.dot(A_free, alpha_free)
124
+ # b = rhs
125
+ result = np.dot(A_enforce_inv, A_enforce.T @ b)
126
+ alpha = 1.0
127
+ Q[I_enforce + 1, i] = (1 - alpha) * Q[I_enforce + 1, i] + (
128
+ alpha
129
+ ) * result
130
+ return Q
131
+
132
+ def f_2d(Q):
133
+ i1 = [[0] + [i + 1 for i in range(1 + level)]]
134
+ i2 = [[0] + [i + 1 + 1 + level for i in range(1 + level)]]
135
+ Q1 = Q[i1]
136
+ Q2 = Q[i2]
137
+ Q1 = f_1d(Q1)
138
+ Q2 = f_1d(Q2)
139
+ Q[i1] = Q1
140
+ Q[i2] = Q2
141
+ return Q
142
+
143
+ if dim == 1:
144
+ return f_1d
145
+ elif dim == 2:
146
+ return f_2d
147
+ else:
148
+ assert False
149
+
150
+ def enforce_boundary_conditions_lsq2(self, rhs=np.zeros(2), dim=1):
151
+ level = len(self.basisfunctions.basis) - 1
152
+ constraint_bottom = [self.basisfunctions.eval(i, 0.0) for i in range(level + 1)]
153
+ constraint_top = [
154
+ diff(self.basisfunctions.eval(i, z), z).subs(z, 1.0)
155
+ for i in range(level + 1)
156
+ ]
157
+ A = Matrix([constraint_bottom, constraint_top])
158
+
159
+ I = np.linspace(0, level, 1 + level, dtype=int)
160
+ I_enforce = I[1:]
161
+ rhs = np.zeros(2)
162
+ # rhs = np.zeros(level)
163
+ I_free = np.delete(I, I_enforce)
164
+ A_enforce = A[:, list(I_enforce)]
165
+ A_free = np.array(A[:, list(I_free)], dtype=float)
166
+
167
+ def obj(alpha0, lam):
168
+ def f(alpha):
169
+ return np.sum((alpha - alpha0) ** 2) + lam * np.sum(
170
+ np.array(np.dot(A, alpha) ** 2, dtype=float)
171
+ )
172
+
173
+ return f
174
+
175
+ def f_1d(Q):
176
+ for i, q in enumerate(Q.T):
177
+ h = q[0]
178
+ alpha = q[1:] / h
179
+ f = obj(alpha, 0.1)
180
+ result = lsq(f, alpha)
181
+ Q[1:, i] = h * result.z
182
+ return Q
183
+
184
+ def f_2d(Q):
185
+ i1 = [[0] + [i + 1 for i in range(1 + level)]]
186
+ i2 = [[0] + [i + 1 + 1 + level for i in range(1 + level)]]
187
+ Q1 = Q[i1]
188
+ Q2 = Q[i2]
189
+ Q1 = f_1d(Q1)
190
+ Q2 = f_1d(Q2)
191
+ Q[i1] = Q1
192
+ Q[i2] = Q2
193
+ return Q
194
+
195
+ if dim == 1:
196
+ return f_1d
197
+ elif dim == 2:
198
+ return f_2d
199
+ else:
200
+ assert False
201
+
202
+ def enforce_boundary_conditions(
203
+ self, enforced_basis=[-2, -1], rhs=np.zeros(2), dim=1
204
+ ):
205
+ level = len(self.basisfunctions.basis) - 1
206
+ constraint_bottom = [self.basisfunctions.eval(i, 0.0) for i in range(level + 1)]
207
+ constraint_top = [
208
+ diff(self.basisfunctions.eval(i, z), z).subs(z, 1.0)
209
+ for i in range(level + 1)
210
+ ]
211
+ A = Matrix([constraint_bottom, constraint_top][: len(enforced_basis)])
212
+
213
+ # test to only constrain bottom
214
+ # A = Matrix([constraint_bottom])
215
+ # enforced_basis = [-1]
216
+ # rhs=np.zeros(1)
217
+
218
+ I = np.linspace(0, level, 1 + level, dtype=int)
219
+ I_enforce = I[enforced_basis]
220
+ I_free = np.delete(I, I_enforce)
221
+ A_enforce = A[:, list(I_enforce)]
222
+ A_free = np.array(A[:, list(I_free)], dtype=float)
223
+ A_enforce_inv = np.array(A_enforce.inv(), dtype=float)
224
+
225
+ def f_1d(Q):
226
+ for i, q in enumerate(Q.T):
227
+ alpha_enforce = q[I_enforce + 1]
228
+ alpha_free = q[I_free + 1]
229
+ b = rhs - np.dot(A_free, alpha_free)
230
+ result = np.dot(A_enforce_inv, b)
231
+ alpha = 1.0
232
+ Q[I_enforce + 1, i] = (1 - alpha) * Q[I_enforce + 1, i] + (
233
+ alpha
234
+ ) * result
235
+ return Q
236
+
237
+ def f_2d(Q):
238
+ i1 = [[0] + [i + 1 for i in range(1 + level)]]
239
+ i2 = [[0] + [i + 1 + 1 + level for i in range(1 + level)]]
240
+ Q1 = Q[i1]
241
+ Q2 = Q[i2]
242
+ Q1 = f_1d(Q1)
243
+ Q2 = f_1d(Q2)
244
+ Q[i1] = Q1
245
+ Q[i2] = Q2
246
+ return Q
247
+
248
+ if dim == 1:
249
+ return f_1d
250
+ elif dim == 2:
251
+ return f_2d
252
+ else:
253
+ assert False
254
+
255
+ """
256
+ Compute phi_k(@xi=0)
257
+ """
258
+
259
+ def _phib(self, k):
260
+ return self.basisfunctions.eval(k, self.basisfunctions.bounds()[0])
261
+
262
+ """
263
+ Compute <phi_k, phi_i>
264
+ """
265
+
266
+ def _M(self, k, i):
267
+ return integrate(
268
+ self.basisfunctions.weight(z) * self.basisfunctions.eval(k, z) * self.basisfunctions.eval(i, z), (z, self.basisfunctions.bounds()[0], self.basisfunctions.bounds()[1])
269
+ )
270
+
271
+ """
272
+ Compute <phi_k, phi_i, phi_j>
273
+ """
274
+
275
+ def _A(self, k, i, j):
276
+ return integrate(
277
+ self.basisfunctions.weight(z) * self.basisfunctions.eval(k, z)
278
+ * self.basisfunctions.eval(i, z)
279
+ * self.basisfunctions.eval(j, z),
280
+ (z, self.basisfunctions.bounds()[0], self.basisfunctions.bounds()[1]),
281
+ )
282
+
283
+ """
284
+ Compute <(phi')_k, phi_j, int(phi)_j>
285
+ """
286
+
287
+ def _B(self, k, i, j):
288
+ return integrate(
289
+ self.basisfunctions.weight(z) * diff(self.basisfunctions.eval(k, z), z)
290
+ * integrate(self.basisfunctions.eval(j, z), z)
291
+ * self.basisfunctions.eval(i, z),
292
+ (z, self.basisfunctions.bounds()[0], self.basisfunctions.bounds()[1]),
293
+ )
294
+
295
+ """
296
+ Compute <(phi')_k, (phi')_j>
297
+ """
298
+
299
+ def _D(self, k, i):
300
+ return integrate(
301
+ self.basisfunctions.weight(z) * diff(self.basisfunctions.eval(k, z), z)
302
+ * diff(self.basisfunctions.eval(i, z), z),
303
+ (z, self.basisfunctions.bounds()[0], self.basisfunctions.bounds()[1]),
304
+ )
305
+
306
+ """
307
+ Compute <(phi')_k, (phi')_j * xi>
308
+ """
309
+ def _Dxi(self, k, i):
310
+ return integrate(
311
+ self.basisfunctions.weight(z) * diff(self.basisfunctions.eval(k, z), z)
312
+ * diff(self.basisfunctions.eval(i, z), z) * z,
313
+ (z, self.basisfunctions.bounds()[0], self.basisfunctions.bounds()[1]),
314
+ )
315
+ """
316
+ Compute <(phi')_k, (phi')_j * xi**2>
317
+ """
318
+ def _Dxi2(self, k, i):
319
+ return integrate(
320
+ self.basisfunctions.weight(z) * diff(self.basisfunctions.eval(k, z), z)
321
+ * diff(self.basisfunctions.eval(i, z), z) * z * z,
322
+ (z, self.basisfunctions.bounds()[0], self.basisfunctions.bounds()[1]),
323
+ )
324
+
325
+ """
326
+ Compute <(phi)_k, (phi')_j>
327
+ """
328
+
329
+ def _D1(self, k, i):
330
+ return integrate(
331
+ self.basisfunctions.weight(z) * self.basisfunctions.eval(k, z) * diff(self.basisfunctions.eval(i, z), z),
332
+ (z, self.basisfunctions.bounds()[0], self.basisfunctions.bounds()[1]),
333
+ )
334
+
335
+ """
336
+ Compute <(phi)_k, (phi'')_j>
337
+ """
338
+
339
+ def _DD(self, k, i):
340
+ return integrate(
341
+ self.basisfunctions.weight(z) * self.basisfunctions.eval(k, z)
342
+ * diff(diff(self.basisfunctions.eval(i, z), z), z),
343
+ (z, self.basisfunctions.bounds()[0], self.basisfunctions.bounds()[1]),
344
+ )
345
+
346
+ """
347
+
348
+ Compute <(phi')_k, (phi')_j>
349
+ """
350
+
351
+ def _DT(self, k, i, j):
352
+ return integrate(
353
+ self.basisfunctions.weight(z) * diff(self.basisfunctions.eval(k, z), z)
354
+ * diff(self.basisfunctions.eval(i, z), z)
355
+ * self.basisfunctions.eval(j, z),
356
+ (z, self.basisfunctions.bounds()[0], self.basisfunctions.bounds()[1]),
357
+ )
358
+
359
+
360
+ class BasisNoHOM(Basismatrices):
361
+ def _A(self, k, i, j):
362
+ count = 0
363
+ # count += float(k > 0)
364
+ count += float(i > 0)
365
+ count += float(j > 0)
366
+ # if count > 1:
367
+ if (i == 0 and j == k) or (j == 0 and i == k) or (k == 0 and i == j):
368
+ return super()._A(k, i, j)
369
+ return 0
370
+
371
+ def _B(self, k, i, j):
372
+ count = 0
373
+ # count += float(k > 0)
374
+ count += float(i > 0)
375
+ count += float(j > 0)
376
+ # if count > 1:
377
+ # if not (i==0 or j==0):
378
+ if (i == 0 and j == k) or (j == 0 and i == k) or (k == 0 and i == j):
379
+ return super()._B(k, i, j)
380
+ return 0
381
+ # return super()._B(k, i, j)
@@ -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
+