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,1509 @@
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
+ from typing import Union
15
+
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
+ import library.zoomy_core.model.initial_conditions as IC
24
+ from library.zoomy_core.model.models.basismatrices import Basismatrices, Legendre_shifted, Basisfunction
25
+
26
+
27
+ class HybridSFFSMM(Model):
28
+ def __init__(
29
+ self,
30
+ boundary_conditions,
31
+ initial_conditions,
32
+ aux_initial_conditions=IC.Constant(),
33
+ dimension=1,
34
+ fields=3,
35
+ aux_variables=0,
36
+ parameters={},
37
+ _default_parameters={"g": 1.0, "ex": 0.0, "ez": 1.0},
38
+ basismatrices=Basismatrices(),
39
+ ):
40
+ self.basismatrices = basis
41
+ self.variables = register_sympy_attribute(fields, "q")
42
+ self.n_variables = self.variables.length()
43
+ self.level = self.n_variables - 3
44
+ self.basismatrices.compute_matrices(self.level)
45
+ super().__init__(
46
+ dimension=dimension,
47
+ fields=fields,
48
+ aux_variables=aux_variables,
49
+ parameters=parameters,
50
+ _default_parameters=_default_parameters,
51
+ boundary_conditions=boundary_conditions,
52
+ initial_conditions=initial_conditions,
53
+ aux_initial_conditions=aux_initial_conditions,
54
+ settings={**settings_default, **settings},
55
+ )
56
+
57
+ def get_alphas(self):
58
+ Q = self.variables
59
+ h = Q[0]
60
+ # exlude h and P
61
+ ha = Q[1:-1]
62
+ return ha
63
+
64
+ def flux(self):
65
+ flux_x = Matrix([0 for i in range(self.n_variables)])
66
+ h = self.variables[0]
67
+ ha = self.get_alphas()
68
+ a = [_ha / h for _ha in ha]
69
+ hu = self.variables[1]
70
+ u = hu / h
71
+ P11 = self.variables[-1]
72
+ p = self.parameters
73
+ # mass malance
74
+ flux_x[0] = ha[0]
75
+ # mean momentum (following SSF)
76
+ flux_x[1] = hu * u + h * P11 + p.g * h**2 / 2
77
+ # flux_x[1] = 0
78
+ # for i in range(self.level+1):
79
+ # for j in range(self.level+1):
80
+ # flux_x[1] += ha[i] * ha[j] / h * self.basismatrices.A[0, i, j] / self.basismatrices.M[ 0, 0 ]
81
+ # higher order moments (SMM)
82
+ for k in range(1, self.level + 1):
83
+ for i in range(self.level + 1):
84
+ for j in range(self.level + 1):
85
+ flux_x[k + 1] += (
86
+ h
87
+ * a[i]
88
+ * a[j]
89
+ * self.basismatrices.A[k, i, j]
90
+ / self.basismatrices.M[k, k]
91
+ )
92
+ # P
93
+ flux_x[-1] = 2 * P11 * u
94
+ for k in range(1, self.level + 1):
95
+ for i in range(1, self.level + 1):
96
+ for j in range(1, self.level + 1):
97
+ flux_x[-1] += a[i] * a[j] * a[k] * self.basismatrices.A[k, i, j]
98
+ return [flux_x]
99
+
100
+ def nonconservative_matrix(self):
101
+ nc = Matrix([[0 for i in range(self.n_variables)] for j in range(self.n_variables)])
102
+ h = self.variables[0]
103
+ ha = self.get_alphas()
104
+ hu = self.variables[1]
105
+ u = hu / h
106
+ a = [_ha / h for _ha in ha]
107
+ P11 = self.variables[-1]
108
+ p = self.parameters
109
+ um = ha[0] / h
110
+
111
+ # mean momentum
112
+ # nc[1, 0] = - p.g * p.ez * h
113
+ nc[1, 0] = 0
114
+ # higher order momennts (SMM)
115
+ for k in range(1, self.level + 1):
116
+ nc[k + 1, k + 1] += um
117
+ for k in range(self.level + 1):
118
+ for i in range(1, self.level + 1):
119
+ for j in range(1, self.level + 1):
120
+ nc[k + 1, i + 1] -= (
121
+ ha[j]
122
+ / h
123
+ * self.basismatrices.B[k, i, j]
124
+ / self.basismatrices.M[k, k]
125
+ )
126
+ nc[-1, -1] = u
127
+ return [nc]
128
+
129
+ def eigenvalues(self):
130
+ A = self.normal[0] * self.sympy_quasilinear_matrix[0]
131
+ for d in range(1, self.dimension):
132
+ A += self.normal[d] * self.sympy_quasilinear_matrix[d]
133
+ # alpha_erase = self.variables[2:]
134
+ # for alpha_i in alpha_erase:
135
+ # A = A.subs(alpha_i, 0)
136
+ # return eigenvalue_dict_to_matrix(A.eigenvals())
137
+ evs = Matrix([0 for i in range(self.n_variables)])
138
+ h = self.variables[0]
139
+ hu = self.variables[1]
140
+ u = hu / h
141
+ P11 = self.variables[2]
142
+ p = self.parameters
143
+
144
+ b = sympy.sqrt(P11)
145
+ a = sympy.sqrt(p.g * h + 3 * P11)
146
+
147
+ evs[0] = u
148
+ evs[1] = u + a
149
+ evs[2] = u - a
150
+
151
+ return evs
152
+
153
+ def source(self):
154
+ out = Matrix([0 for i in range(self.n_variables)])
155
+ return out
156
+
157
+ def topography(self):
158
+ assert "dhdx" in vars(self.aux_variables)
159
+ out = Matrix([0 for i in range(self.n_variables)])
160
+ h = self.variables[0]
161
+ p = self.parameters
162
+ dhdx = self.aux_variables.dhdx
163
+ out[1] = h * p.g * (p.ex - p.ez * dhdx)
164
+ return out
165
+
166
+
167
+ class ShallowMomentsAugmentedSSF(Model):
168
+ def __init__(
169
+ self,
170
+ boundary_conditions,
171
+ initial_conditions,
172
+ aux_initial_conditions=IC.Constant(),
173
+ dimension=1,
174
+ fields=3,
175
+ aux_variables=0,
176
+ parameters={},
177
+ _default_parameters={"g": 1.0, "ex": 0.0, "ez": 1.0},
178
+ settings={},
179
+ settings_default={"topography": False, "friction": []},
180
+ basis=Legendre_shifted(),
181
+ ):
182
+ self.basismatrices = basis
183
+ self.variables = register_sympy_attribute(fields, "q")
184
+ self.n_variables = self.variables.length()
185
+ self.level = self.n_variables - 2
186
+ self.basismatrices.compute_matrices(self.level)
187
+ super().__init__(
188
+ dimension=dimension,
189
+ fields=fields,
190
+ aux_variables=aux_variables,
191
+ parameters=parameters,
192
+ _default_parameters=_default_parameters,
193
+ boundary_conditions=boundary_conditions,
194
+ initial_conditions=initial_conditions,
195
+ aux_initial_conditions=aux_initial_conditions,
196
+ settings={**settings_default, **settings},
197
+ )
198
+
199
+ def get_alphas(self):
200
+ Q = self.variables
201
+ h = Q[0]
202
+ # exlude u0 and P
203
+ ha = Q[2:-1]
204
+ P = Q[-1]
205
+ sum_aiMii = 0
206
+ N = self.level
207
+ for i, hai in enumerate(ha):
208
+ sum_aiMii += hai * self.basismatrices.M[i + 1, i + 1] / h
209
+
210
+ aN = sympy.sqrt((P - h * sum_aiMii) / (h * self.basismatrices.M[N, N]))
211
+ # now I want to include u0
212
+ ha = Q[1:]
213
+ ha[-1] = aN * h
214
+ return ha
215
+
216
+ def flux(self):
217
+ flux = Matrix([0 for i in range(self.n_variables)])
218
+ h = self.variables[0]
219
+ ha = self.get_alphas()
220
+ P11 = self.variables[-1]
221
+ p = self.parameters
222
+ flux[0] = ha[0]
223
+ flux[1] = p.g * p.ez * h * h / 2
224
+ for k in range(self.level + 1):
225
+ for i in range(self.level + 1):
226
+ for j in range(self.level + 1):
227
+ # TODO avoid devision by zero
228
+ flux[k + 1] += (
229
+ ha[i]
230
+ * ha[j]
231
+ / h
232
+ * self.basismatrices.A[k, i, j]
233
+ / self.basismatrices.M[k, k]
234
+ )
235
+ flux[-1] = 2 * P11 * ha[0] / h
236
+ return [flux]
237
+
238
+ def nonconservative_matrix(self):
239
+ nc = Matrix([[0 for i in range(self.n_variables)] for j in range(self.n_variables)])
240
+ h = self.variables[0]
241
+ ha = self.get_alphas()
242
+ P11 = self.variables[-1]
243
+ p = self.parameters
244
+ um = ha[0] / h
245
+ # nc[1, 0] = - p.g * p.ez * h
246
+ for k in range(1, self.level + 1):
247
+ nc[k + 1, k + 1] += um
248
+ for k in range(self.level + 1):
249
+ for i in range(1, self.level + 1):
250
+ for j in range(1, self.level + 1):
251
+ nc[k + 1, i + 1] -= (
252
+ ha[j]
253
+ / h
254
+ * self.basismatrices.B[k, i, j]
255
+ / self.basismatrices.M[k, k]
256
+ )
257
+ for k in range(nc.shape[1]):
258
+ nc[-1, k] = 0
259
+ nc[-1, 1] = -P11
260
+ nc[-1, -1] = +P11
261
+ return [nc]
262
+
263
+ def eigenvalues(self):
264
+ A = self.normal[0] * self.sympy_quasilinear_matrix[0]
265
+ for d in range(1, self.dimension):
266
+ A += self.normal[d] * self.sympy_quasilinear_matrix[d]
267
+ # alpha_erase = self.variables[2:]
268
+ # for alpha_i in alpha_erase:
269
+ # A = A.subs(alpha_i, 0)
270
+ return eigenvalue_dict_to_matrix(A.eigenvals())
271
+
272
+ def source(self):
273
+ out = Matrix([0 for i in range(self.n_variables)])
274
+ return out
275
+
276
+ def topography(self):
277
+ assert "dhdx" in vars(self.aux_variables)
278
+ out = Matrix([0 for i in range(self.n_variables)])
279
+ h = self.variables[0]
280
+ p = self.parameters
281
+ dhdx = self.aux_variables.dhdx
282
+ out[1] = h * p.g * (p.ex - p.ez * dhdx)
283
+ return out
284
+
285
+
286
+ class ShallowMoments(Model):
287
+ """
288
+ Shallow Moments 1d
289
+
290
+ :gui:
291
+ - tab: model
292
+ - requires: [ 'mesh.dimension': 1 ]
293
+
294
+ """
295
+
296
+ def __init__(
297
+ self,
298
+ boundary_conditions,
299
+ initial_conditions,
300
+ aux_initial_conditions=IC.Constant(),
301
+ dimension=1,
302
+ fields=2,
303
+ aux_variables=0,
304
+ parameters={},
305
+ _default_parameters={"g": 1.0, "ex": 0.0, "ez": 1.0},
306
+ settings={},
307
+ settings_default={"topography": False, "friction": []},
308
+ basis=Basismatrices(),
309
+ ):
310
+ self.variables = register_sympy_attribute(fields, "q")
311
+ self.n_variables = self.variables.length()
312
+ self.level = self.n_variables - 2
313
+ self.basismatrices = basis
314
+ self.basismatrices.basisfunctions = type(self.basismatrices.basisfunctions)(
315
+ level=self.level
316
+ )
317
+ self.basismatrices.compute_matrices(self.level)
318
+ super().__init__(
319
+ dimension=dimension,
320
+ fields=fields,
321
+ aux_variables=aux_variables,
322
+ parameters=parameters,
323
+ _default_parameters=_default_parameters,
324
+ boundary_conditions=boundary_conditions,
325
+ initial_conditions=initial_conditions,
326
+ aux_initial_conditions=aux_initial_conditions,
327
+ settings={**settings_default, **settings},
328
+ )
329
+
330
+ def flux(self):
331
+ flux = Matrix([0 for i in range(self.n_variables)])
332
+ h = self.variables[0]
333
+ ha = self.variables[1 : 1 + self.level + 1]
334
+ p = self.parameters
335
+ flux[0] = ha[0]
336
+ flux[1] = p.g * p.ez * h * h / 2
337
+ for k in range(self.level + 1):
338
+ for i in range(self.level + 1):
339
+ for j in range(self.level + 1):
340
+ # TODO avoid devision by zero
341
+ flux[k + 1] += (
342
+ ha[i]
343
+ * ha[j]
344
+ / h
345
+ * self.basismatrices.A[k, i, j]
346
+ / self.basismatrices.M[k, k]
347
+ )
348
+ return [flux]
349
+
350
+ def nonconservative_matrix(self):
351
+ nc = Matrix([[0 for i in range(self.n_variables)] for j in range(self.n_variables)])
352
+ h = self.variables[0]
353
+ ha = self.variables[1 : 1 + self.level + 1]
354
+ p = self.parameters
355
+ um = ha[0] / h
356
+ # nc[1, 0] = - p.g * p.ez * h
357
+ for k in range(1, self.level + 1):
358
+ nc[k + 1, k + 1] += um
359
+ for k in range(self.level + 1):
360
+ for i in range(1, self.level + 1):
361
+ for j in range(1, self.level + 1):
362
+ nc[k + 1, i + 1] -= (
363
+ ha[j]
364
+ / h
365
+ * self.basismatrices.B[k, i, j]
366
+ / self.basismatrices.M[k, k]
367
+ )
368
+ return [nc]
369
+
370
+ def eigenvalues(self):
371
+ A = self.normal[0] * self.sympy_quasilinear_matrix[0]
372
+ for d in range(1, self.dimension):
373
+ A += self.normal[d] * self.sympy_quasilinear_matrix[d]
374
+ alpha_erase = self.variables[2:]
375
+ for alpha_i in alpha_erase:
376
+ A = A.subs(alpha_i, 0)
377
+ return eigenvalue_dict_to_matrix(A.eigenvals())
378
+
379
+
380
+ def source(self):
381
+ out = Matrix([0 for i in range(self.n_variables)])
382
+ return out
383
+
384
+ def topography(self):
385
+ assert "dhdx" in vars(self.aux_variables)
386
+ out = Matrix([0 for i in range(self.n_variables)])
387
+ h = self.variables[0]
388
+ p = self.parameters
389
+ dhdx = self.aux_variables.dhdx
390
+ out[1] = h * p.g * (p.ex - p.ez * dhdx)
391
+ return out
392
+
393
+ def inclined_plane(self):
394
+ out = Matrix([0 for i in range(self.n_variables)])
395
+ h = self.variables[0]
396
+ p = self.parameters
397
+ out[1] = h * p.g * (p.ex)
398
+ return out
399
+
400
+ def material_wave(self):
401
+ assert "nu" in vars(self.parameters)
402
+ assert "rho" in vars(self.parameters)
403
+ out = Matrix([0 for i in range(self.n_variables)])
404
+ return out
405
+
406
+ def newtonian(self):
407
+ """
408
+ :gui:
409
+ - requires_parameter: ('nu', 0.0)
410
+ """
411
+ assert "nu" in vars(self.parameters)
412
+ out = Matrix([0 for i in range(self.n_variables)])
413
+ h = self.variables[0]
414
+ ha = self.variables[1 : 1 + self.level + 1]
415
+ p = self.parameters
416
+ for k in range(1 + self.level):
417
+ for i in range(1 + self.level):
418
+ # out[1+k] += -p.nu/h * p.eta_bulk * ha[i] / h * self.basismatrices.D[i, k]/ self.basismatrices.M[k, k]
419
+ out[1 + k] += (
420
+ -p.nu
421
+ / h
422
+ * ha[i]
423
+ / h
424
+ * self.basismatrices.D[i, k]
425
+ / self.basismatrices.M[k, k]
426
+ )
427
+ return out
428
+
429
+ def newtonian_no_ibp(self):
430
+ """
431
+ :gui:
432
+ - requires_parameter: ('nu', 0.0)
433
+ """
434
+ assert "nu" in vars(self.parameters)
435
+ out = Matrix([0 for i in range(self.n_variables)])
436
+ h = self.variables[0]
437
+ ha = self.variables[1 : 1 + self.level + 1]
438
+ p = self.parameters
439
+ for k in range(1 + self.level):
440
+ for i in range(1 + self.level):
441
+ # out[1+k] += -p.nu/h * p.eta_bulk * ha[i] / h * self.basismatrices.D[i, k]/ self.basismatrices.M[k, k]
442
+ out[1 + k] += (
443
+ -p.nu
444
+ / h
445
+ * ha[i]
446
+ / h
447
+ * self.basismatrices.DD[k, i]
448
+ / self.basismatrices.M[k, k]
449
+ )
450
+ return out
451
+
452
+ def newtonian_turbulent(self):
453
+ """
454
+ :gui:
455
+ - requires_parameter: ('nu', 0.0)
456
+ """
457
+ p = self.parameters
458
+ nut1 = [
459
+ 1.06245397e-05,
460
+ -8.64966128e-06,
461
+ -4.24655215e-06,
462
+ 1.51861028e-06,
463
+ 2.25140517e-06,
464
+ 1.81867029e-06,
465
+ -1.02154323e-06,
466
+ -1.78795289e-06,
467
+ -5.07515843e-07,
468
+ ]
469
+ nut2 = np.array(
470
+ [
471
+ 0.21923893,
472
+ -0.04171894,
473
+ -0.05129916,
474
+ -0.04913612,
475
+ -0.03863209,
476
+ -0.02533469,
477
+ -0.0144186,
478
+ -0.00746847,
479
+ -0.0031811,
480
+ -0.00067986,
481
+ 0.0021782,
482
+ ]
483
+ )
484
+ nut2 = nut2 / nut2[0] * 1.06245397 * 10 ** (-5)
485
+ nut3 = [
486
+ 1.45934315e-05,
487
+ -1.91969629e-05,
488
+ 5.80456268e-06,
489
+ -5.13207491e-07,
490
+ 2.29489571e-06,
491
+ -1.24361978e-06,
492
+ -2.78720732e-06,
493
+ -2.01469118e-07,
494
+ 1.24957663e-06,
495
+ ]
496
+ nut4 = [
497
+ 1.45934315e-05,
498
+ -1.45934315e-05 * 3 / 4,
499
+ -1.45934315e-05 * 1 / 4,
500
+ 0,
501
+ 0,
502
+ 0,
503
+ 0,
504
+ 0,
505
+ 0,
506
+ 0,
507
+ 0,
508
+ 0,
509
+ ]
510
+ nut5 = [p.nut, -p.nut * 3 / 4, -p.nut * 1 / 4, 0, 0, 0, 0, 0, 0, 0, 0, 0]
511
+ nut = nut5
512
+ out = Matrix([0 for i in range(self.n_variables)])
513
+ h = self.variables[0]
514
+ ha = self.variables[1 : 1 + self.level + 1]
515
+ p = self.parameters
516
+ for k in range(1 + self.level):
517
+ for i in range(1 + self.level):
518
+ for j in range(1 + self.level):
519
+ out[1 + k] += (
520
+ -p.c_nut
521
+ * nut[j]
522
+ / h
523
+ * ha[i]
524
+ / h
525
+ * self.basismatrices.DT[k, i, j]
526
+ / self.basismatrices.M[k, k]
527
+ )
528
+ return out
529
+
530
+ def newtonian_boundary_layer_classic(self):
531
+ assert "nu" in vars(self.parameters)
532
+ assert "eta" in vars(self.parameters)
533
+ out = Matrix([0 for i in range(self.n_variables)])
534
+ h = self.variables[0]
535
+ ha = self.variables[1 : 1 + self.level + 1]
536
+ p = self.parameters
537
+ phi_0 = [
538
+ self.basismatrices.basisfunctions.eval(i, 0.0)
539
+ for i in range(self.level + 1)
540
+ ]
541
+ dphidx_0 = [
542
+ (diff(self.basismatrices.basisfunctions.eval(i, x), x)).subs(x, 0.0)
543
+ for i in range(self.level + 1)
544
+ ]
545
+ tau_bot = 0
546
+ for i in range(1 + self.level):
547
+ tau_bot += ha[i] / h * dphidx_0[i]
548
+ for k in range(1 + self.level):
549
+ out[k + 1] = (
550
+ -p.c_bl
551
+ * p.eta
552
+ * (p.nu + p.nut_bl)
553
+ / h
554
+ * tau_bot
555
+ * phi_0[k]
556
+ / self.basismatrices.M[k, k]
557
+ )
558
+ return out
559
+
560
+ def newtonian_boundary_layer(self):
561
+ assert "nu" in vars(self.parameters)
562
+ out = Matrix([0 for i in range(self.n_variables)])
563
+ h = self.variables[0]
564
+ h = self.variables[0]
565
+ ha = self.variables[1 : 1 + self.level + 1]
566
+ p = self.parameters
567
+ phi_0 = [self.basismatrices.basis.eval(i, 0.0) for i in range(self.level + 1)]
568
+ dphidx_0 = [
569
+ (diff(self.basismatrices.basis.eval(i, x), x)).subs(x, 0.0)
570
+ for i in range(self.level + 1)
571
+ ]
572
+ dz_boundary_layer = 0.005
573
+ u_bot = 0
574
+ for i in range(1 + self.level):
575
+ u_bot += ha[i] / h / self.basismatrices.M[i, i]
576
+ tau_bot = p.nu * (u_bot - 0.0) / dz_boundary_layer
577
+ for k in range(1 + self.level):
578
+ out[k + 1] = -p.eta * tau_bot / h
579
+ return out
580
+
581
+ def steady_state_channel(self):
582
+ assert "eta_ss" in vars(self.parameters)
583
+ moments_ss = np.array(
584
+ [
585
+ 0.21923893,
586
+ -0.04171894,
587
+ -0.05129916,
588
+ -0.04913612,
589
+ -0.03863209,
590
+ -0.02533469,
591
+ -0.0144186,
592
+ -0.00746847,
593
+ -0.0031811,
594
+ -0.00067986,
595
+ 0.0021782,
596
+ ]
597
+ )[: self.level + 1]
598
+ out = Matrix([0 for i in range(self.n_variables)])
599
+ h = self.variables[0]
600
+ ha = self.variables[1 : 1 + self.level + 1]
601
+ mean = ha[0] / h
602
+ mean_ss = moments_ss[0]
603
+ scaling = mean / mean_ss
604
+ p = self.parameters
605
+ for i in range(1, self.level + 1):
606
+ out[1 + i] = -p.eta_ss * h * (ha[i] / h - scaling * moments_ss[i])
607
+ return out
608
+
609
+ def slip(self):
610
+ """
611
+ :gui:
612
+ - requires_parameter: ('lamda', 0.0)
613
+ - requires_parameter: ('rho', 1.0)
614
+ """
615
+ assert "lamda" in vars(self.parameters)
616
+ assert "rho" in vars(self.parameters)
617
+ out = Matrix([0 for i in range(self.n_variables)])
618
+ h = self.variables[0]
619
+ ha = self.variables[1 : 1 + self.level + 1]
620
+ p = self.parameters
621
+ for k in range(1 + self.level):
622
+ for i in range(1 + self.level):
623
+ out[1 + k] += (
624
+ -1.0 / p.lamda / p.rho * ha[i] / h / self.basismatrices.M[k, k]
625
+ )
626
+ return out
627
+
628
+ def slip_mod(self):
629
+ """
630
+ :gui:
631
+ - requires_parameter: ('lamda', 0.0)
632
+ - requires_parameter: ('rho', 1.0)
633
+ """
634
+ assert "lamda" in vars(self.parameters)
635
+ assert "rho" in vars(self.parameters)
636
+ out = Matrix([0 for i in range(self.n_variables)])
637
+ h = self.variables[0]
638
+ ha = self.variables[1 : 1 + self.level + 1]
639
+ p = self.parameters
640
+ ub = 0
641
+ for i in range(1 + self.level):
642
+ ub += ha[i] / h
643
+ for k in range(1, 1 + self.level):
644
+ out[1 + k] += (
645
+ -1.0 * p.c_slipmod / p.lamda / p.rho * ub / self.basismatrices.M[k, k]
646
+ )
647
+ return out
648
+
649
+ def no_slip(self):
650
+ out = Matrix([0 for i in range(self.n_variables)])
651
+ h = self.variables[0]
652
+ ha = self.variables[1 : 1 + self.level + 1]
653
+ p = self.parameters
654
+ a0 = [ha[i] / h for i in range(self.level + 1)]
655
+ a = [ha[i] / h for i in range(self.level + 1)]
656
+ # for i in range(self.level+1):
657
+ # out[i+1] = ha[i]
658
+ phi_0 = np.zeros(self.level + 1)
659
+ ns_iterations = 2
660
+ for k in range(self.level + 1):
661
+ phi_0[k] = self.basismatrices.basis.eval(k, x).subs(x, 0.0)
662
+
663
+ def f(j, a, a0, basis_0):
664
+ out = 0
665
+ for i in range(self.level + 1):
666
+ # out += -2*p.ns_1*(a[i] - a0[i]) -2*p.ns_2*basis_0[j] * a[i] * basis_0[i]
667
+ out += -2 * p.ns_2 * basis_0[j] * a[i] * basis_0[i]
668
+ return out
669
+
670
+ for i in range(ns_iterations):
671
+ for k in range(1, 1 + self.level):
672
+ out[1 + k] += h * (f(k, a, a0, phi_0))
673
+ a = [a[k] + out[k] / h for k in range(self.level + 1)]
674
+ # return sympy.simplify(out)
675
+ return out
676
+
677
+ def chezy(self):
678
+ """
679
+ :gui:
680
+ - requires_parameter: ('C', 1000.0)
681
+ """
682
+ assert "C" in vars(self.parameters)
683
+ out = Matrix([0 for i in range(self.n_variables)])
684
+ h = self.variables[0]
685
+ ha = self.variables[1 : 1 + self.level + 1]
686
+ p = self.parameters
687
+ tmp = 0
688
+ for i in range(1 + self.level):
689
+ for j in range(1 + self.level):
690
+ tmp += ha[i] * ha[j] / h / h
691
+ sqrt = sympy.sqrt(tmp)
692
+ for k in range(1 + self.level):
693
+ for l in range(1 + self.level):
694
+ out[1 + k] += (
695
+ -1.0 / (p.C**2 * self.basismatrices.M[k, k]) * ha[l] * sqrt / h
696
+ )
697
+ return out
698
+
699
+ def chezy_mean(self):
700
+ """
701
+ :gui:
702
+ - requires_parameter: ('C', 1000.0)
703
+ """
704
+ assert "C" in vars(self.parameters)
705
+ out = Matrix([0 for i in range(self.n_variables)])
706
+ h = self.variables[0]
707
+ ha = self.variables[1 : 1 + self.level + 1]
708
+ p = self.parameters
709
+ tmp = 0
710
+ u = ha[0] / h
711
+ for k in range(1 + self.level):
712
+ out[1 + k] += -1.0 / (p.C**2 * self.basismatrices.M[k, k]) * u**2
713
+ return out
714
+
715
+ def chezy_ssf(self):
716
+ """
717
+ :gui:
718
+ - requires_parameter: ('C', 1000.0)
719
+ """
720
+ assert "Cf" in vars(self.parameters)
721
+ out = Matrix([0 for i in range(self.n_variables)])
722
+ h = self.variables[0]
723
+ ha = self.variables[1 : 1 + self.level + 1]
724
+ p = self.parameters
725
+ tmp = 0
726
+ for i in range(1 + self.level):
727
+ for j in range(1 + self.level):
728
+ tmp += ha[i] * ha[j] / h / h
729
+ sqrt = sympy.sqrt(tmp)
730
+ for k in range(1 + self.level):
731
+ for l in range(1 + self.level):
732
+ out[1 + k] += -(p.Cf * self.basismatrices.M[k, k]) * ha[l] * sqrt / h
733
+ return out
734
+
735
+ def shear_new(self):
736
+ """
737
+ :gui:
738
+ - requires_parameter: ('beta', 1.0)
739
+ """
740
+ assert "beta" in vars(self.parameters)
741
+ out = Matrix([0 for i in range(self.n_variables)])
742
+ h = self.variables[0]
743
+ ha = self.variables[1 : 1 + self.level + 1]
744
+ p = self.parameters
745
+ tmp = 0
746
+ d_phi_0 = np.zeros(self.level + 1)
747
+ phi_0 = np.zeros(self.level + 1)
748
+ for k in range(self.level + 1):
749
+ d_phi_0[k] = diff(self.basismatrices.basis.eval(k, x), x).subs(x, 0.0)
750
+ phi_0[k] = self.basismatrices.basis.eval(k, x).subs(x, 0.0)
751
+ friction_factor = 0.0
752
+ for k in range(self.level + 1):
753
+ friction_factor -= p.beta * d_phi_0[k] * ha[k] / h / h
754
+ k = 0
755
+ # for k in range(1+self.level):
756
+ out[1 + k] += friction_factor * phi_0[k] / (self.basismatrices.M[k, k])
757
+ return out
758
+
759
+ def shear(self):
760
+ """
761
+ :gui:
762
+ - requires_parameter: ('beta', 1.0)
763
+ """
764
+ assert "beta" in vars(self.parameters)
765
+ out = Matrix([0 for i in range(self.n_variables)])
766
+ h = self.variables[0]
767
+ ha = self.variables[1 : 1 + self.level + 1]
768
+ p = self.parameters
769
+ tmp = 0
770
+ d_phi_0 = np.zeros(self.level + 1)
771
+ phi_0 = np.zeros(self.level + 1)
772
+ for k in range(self.level + 1):
773
+ d_phi_0[k] = diff(self.basismatrices.basis.eval(k, x), x).subs(x, 0.0)
774
+ phi_0[k] = self.basismatrices.basis.eval(k, x).subs(x, 0.0)
775
+ friction_factor = 0.0
776
+ for k in range(self.level + 1):
777
+ friction_factor -= p.beta * d_phi_0[k] * ha[k] / h
778
+ for k in range(self.level + 1):
779
+ out[1 + k] += friction_factor * phi_0[k] / (self.basismatrices.M[k, k]) / h
780
+ return out
781
+
782
+ def shear_crazy(self):
783
+ """
784
+ :gui:
785
+ - requires_parameter: ('beta', 1.0)
786
+ """
787
+ assert "beta" in vars(self.parameters)
788
+ out = Matrix([0 for i in range(self.n_variables)])
789
+ h = self.variables[0]
790
+ ha = self.variables[1 : 1 + self.level + 1]
791
+ p = self.parameters
792
+ tmp = 0
793
+ d_phi_0 = np.zeros(self.level + 1)
794
+ phi_0 = np.zeros(self.level + 1)
795
+ for k in range(self.level + 1):
796
+ d_phi_0[k] = diff(self.basismatrices.basis.eval(k, x), x).subs(x, 0.0)
797
+ phi_0[k] = self.basismatrices.basis.eval(k, x).subs(x, 0.0)
798
+ for k in range(self.level + 1):
799
+ out[1 + k] += -p.beta * d_phi_0[k] * phi_0[k] * ha[k] / h
800
+ return out
801
+
802
+ def manning_mean(self):
803
+ """
804
+ :gui:
805
+ - requires_parameter: ('C', 1000.0)
806
+ """
807
+ assert "kst" in vars(self.parameters)
808
+ assert "g" in vars(self.parameters)
809
+ out = Matrix([0 for i in range(self.n_variables)])
810
+ h = self.variables[0]
811
+ ha = self.variables[1 : 1 + self.level + 1]
812
+ p = self.parameters
813
+ u = ha[0] / h
814
+ for k in range(1 + self.level):
815
+ out[1 + k] += (
816
+ -1.0
817
+ / p.kst**2
818
+ * p.g
819
+ / h ** (1 / 3)
820
+ * u**2
821
+ * (self.basismatrices.M[k, k])
822
+ )
823
+ return out
824
+
825
+ def steady_state(self):
826
+ out = Matrix([0 for i in range(self.n_variables)])
827
+ h = self.variables[0]
828
+ ha = self.variables[1 : 1 + self.level + 1]
829
+ p = self.parameters
830
+ tmp = 0
831
+ d_phi_0 = np.zeros(self.level + 1)
832
+ phi_0 = np.zeros(self.level + 1)
833
+ for k in range(self.level + 1):
834
+ d_phi_0[k] = diff(self.basismatrices.basis.eval(k, x), x).subs(x, 0.0)
835
+ phi_0[k] = self.basismatrices.basis.eval(k, x).subs(x, 0.0)
836
+ shear_factor = 0.0
837
+ u_bottom = 0.0
838
+ u_diff = ha[0] / h
839
+ for k in range(self.level + 1):
840
+ u_diff += phi_0[k] * ha[k] / h
841
+ for k in range(self.level + 1):
842
+ shear_factor += d_phi_0[k] * (
843
+ ha[k] / h - eval(f"p.Q_ss{k + 1}") / eval(f"p.Q_ss{0}")
844
+ )
845
+ # for k in range(1, self.level+1):
846
+ # out[1+k] += - shear_factor * np.abs(u_diff) * p.S * phi_0[k] /(self.basismatrices.M[k,k])
847
+ for k in range(1, self.level + 1):
848
+ # out[1+k] += - p.A * np.abs(u_diff)* (ha[k]/h - eval(f'p.Q_ss{k+1}')/eval(f'p.Q_ss{0}'))
849
+ out[1 + k] += (
850
+ -p.A
851
+ * np.abs(ha[0] / h)
852
+ * (ha[k] / h - eval(f"p.Q_ss{k + 1}") / eval(f"p.Q_ss{0}"))
853
+ )
854
+ return out
855
+
856
+
857
+ class ShallowMomentsSSF(ShallowMoments):
858
+ def eigenvalues(self):
859
+ A = self.normal[0] * self.sympy_quasilinear_matrix[0]
860
+ for d in range(1, self.dimension):
861
+ A += self.normal[d] * self.sympy_quasilinear_matrix[d]
862
+ # alpha_erase = self.variables[2:]
863
+ # for alpha_i in alpha_erase:
864
+ # A = A.subs(alpha_i, 0)
865
+ return eigenvalue_dict_to_matrix(sympy.simplify(A).eigenvals())
866
+
867
+
868
+ class ShallowMomentsSSFEnergy(ShallowMoments):
869
+ def flux(self):
870
+ flux = Matrix([0 for i in range(self.n_variables)])
871
+ h = self.variables[0]
872
+ ha = self.variables[1 : 1 + self.level + 1] - self.variables[1] / np.diag(
873
+ self.basismatrices.M
874
+ )
875
+ ha[1:] -= self.variables[1] * np.diag(self.basismatrices.M)[1:]
876
+ p = self.parameters
877
+ flux[0] = ha[0]
878
+ flux[1] = p.g * p.ez * h * h / 2
879
+ for k in range(self.level + 1):
880
+ for i in range(self.level + 1):
881
+ for j in range(self.level + 1):
882
+ # TODO avoid devision by zero
883
+ flux[k + 1] += (
884
+ ha[i]
885
+ * ha[j]
886
+ / h
887
+ * self.basismatrices.A[k, i, j]
888
+ / self.basismatrices.M[k, k]
889
+ )
890
+
891
+ flux_hu = flux[1]
892
+
893
+ for k in range(1, self.level + 1):
894
+ flux[k + 1] += flux_hu / self.basismatrices.M[k, k]
895
+ return [flux]
896
+
897
+ def nonconservative_matrix(self):
898
+ nc = Matrix([[0 for i in range(self.n_variables)] for j in range(self.n_variables)])
899
+ h = self.variables[0]
900
+ ha = self.variables[1 : 1 + self.level + 1] - self.variables[1] / np.diag(
901
+ self.basismatrices.M
902
+ )
903
+ ha[1:] -= self.variables[1] * np.diag(self.basismatrices.M)[1:]
904
+ p = self.parameters
905
+ um = ha[0] / h
906
+ # nc[1, 0] = - p.g * p.ez * h
907
+ for k in range(1, self.level + 1):
908
+ nc[k + 1, k + 1] += um
909
+ for k in range(self.level + 1):
910
+ for i in range(1, self.level + 1):
911
+ for j in range(1, self.level + 1):
912
+ nc[k + 1, i + 1] -= (
913
+ ha[j]
914
+ / h
915
+ * self.basismatrices.B[k, i, j]
916
+ / self.basismatrices.M[k, k]
917
+ )
918
+ return [nc]
919
+
920
+ def chezy(self):
921
+ """
922
+ :gui:
923
+ - requires_parameter: ('C', 1000.0)
924
+ """
925
+ assert "C" in vars(self.parameters)
926
+ out = Matrix([0 for i in range(self.n_variables)])
927
+ h = self.variables[0]
928
+ ha = self.variables[1 : 1 + self.level + 1] - self.variables[1] / np.diag(
929
+ self.basismatrices.M
930
+ )
931
+ ha[1:] -= self.variables[1] * np.diag(self.basismatrices.M)[1:]
932
+ p = self.parameters
933
+ tmp = 0
934
+ for i in range(1 + self.level):
935
+ for j in range(1 + self.level):
936
+ tmp += ha[i] * ha[j] / h / h
937
+ sqrt = sympy.sqrt(tmp)
938
+ for k in range(1 + self.level):
939
+ for l in range(1 + self.level):
940
+ out[1 + k] += -1.0 / (p.C**2) * ha[l] / h * sqrt
941
+
942
+ for k in range(1 + self.level):
943
+ out[1 + k] += out[1] / self.basismatrices.M[k, k]
944
+
945
+ return out
946
+
947
+ def eigenvalues(self):
948
+ A = self.normal[0] * self.sympy_quasilinear_matrix[0]
949
+ for d in range(1, self.dimension):
950
+ A += self.normal[d] * self.sympy_quasilinear_matrix[d]
951
+ return eigenvalue_dict_to_matrix(sympy.simplify(A).eigenvals())
952
+
953
+
954
+ class ShallowMomentsTurbulenceSimple(ShallowMoments):
955
+ def __init__(
956
+ self,
957
+ boundary_conditions,
958
+ initial_conditions,
959
+ dimension=1,
960
+ fields=4,
961
+ aux_variables=0,
962
+ parameters={},
963
+ _default_parameters={"g": 1.0, "ex": 0.0, "ey": 0.0, "ez": 1.0},
964
+ settings={},
965
+ settings_default={"topography": False, "friction": []},
966
+ basis=Legendre_shifted(),
967
+ ):
968
+ super().__init__(
969
+ dimension=dimension,
970
+ fields=fields - 2,
971
+ aux_variables=aux_variables,
972
+ parameters=parameters,
973
+ _default_parameters=_default_parameters,
974
+ boundary_conditions=boundary_conditions,
975
+ initial_conditions=initial_conditions,
976
+ settings={**settings_default, **settings},
977
+ basis=basis,
978
+ )
979
+ self.variables = register_sympy_attribute(fields, "q")
980
+ self.n_variables = self.variables.length()
981
+ assert self.n_variables >= 4
982
+
983
+
984
+ @define(frozen=True, slots=True, kw_only=True)
985
+ class ShallowMoments2d(Model):
986
+ dimension: int = 2
987
+ level: int
988
+ variables: Union[list, int] = field(init=False)
989
+ aux_variables: Union[list, int] = field(default=0)
990
+ basis: Basis
991
+ basis: Basismatrices = field(factory=Basismatrices)
992
+
993
+ _default_parameters: dict = field(
994
+ init=False,
995
+ factory=lambda: {"g": 9.81, "ex": 0.0, "ey": 0.0, "ez": 1.0}
996
+ )
997
+
998
+ def __attrs_post_init__(self):
999
+ object.__setattr__(self, "variables", (self.level+1*2)+1)
1000
+ super().__attrs_post_init__()
1001
+
1002
+ # Recompute basis matrices
1003
+ basis = self.basis
1004
+ basis.basisfunctions = type(basis.basisfunctions)(level=self.level)
1005
+ basis.compute_matrices(self.level)
1006
+ object.__setattr__(self, "basis", basis)
1007
+
1008
+
1009
+
1010
+ def project_2d_to_3d(self):
1011
+ out = Matrix([0 for i in range(5)])
1012
+ level = self.level
1013
+ offset = level+1
1014
+ x = self.position[0]
1015
+ y = self.position[1]
1016
+ z = self.position[2]
1017
+ h = self.variables[0]
1018
+ a = [self.variables[1+i]/h for i in range(offset)]
1019
+ b = [self.variables[1+offset+i]/h for i in range(offset)]
1020
+ dudx = self.aux_variables[0]
1021
+ dvdy = self.aux_variables[1]
1022
+ rho_w = 1000.
1023
+ g = 9.81
1024
+ # rho_3d = rho_w * Piecewise((1., h-z > 0), (0.,True))
1025
+ # u_3d = u*Piecewise((1, h-z > 0), (0, True))
1026
+ # v_3d = v*Piecewise((1, h-z > 0), (0, True))
1027
+ # w_3d = (-h * dudx - h * dvdy )*Piecewise((1, h-z > 0), (0, True))
1028
+ # p_3d = rho_w * g * Piecewise((h-z, h-z > 0), (0, True))
1029
+ u_3d = self.basismatrices.basisfunctions.reconstruct_velocity_profile_at(a, z)
1030
+ v_3d = self.basismatrices.basisfunctions.reconstruct_velocity_profile_at(b, z)
1031
+ out[0] = h
1032
+ out[1] = u_3d
1033
+ out[2] = v_3d
1034
+ out[3] = 0
1035
+ out[4] = rho_w * g * h * (1-z)
1036
+
1037
+ return out
1038
+
1039
+ def flux(self):
1040
+ offset = self.level + 1
1041
+ flux_x = Matrix([0 for i in range(self.n_variables)])
1042
+ flux_y = Matrix([0 for i in range(self.n_variables)])
1043
+ h = self.variables[0]
1044
+ ha = self.variables[1 : 1 + self.level + 1]
1045
+ hb = self.variables[1 + self.level + 1 : 1 + 2 * (self.level + 1)]
1046
+ p = self.parameters
1047
+ flux_x[0] = ha[0]
1048
+ flux_x[1] = p.g * p.ez * h * h / 2
1049
+ for k in range(self.level + 1):
1050
+ for i in range(self.level + 1):
1051
+ for j in range(self.level + 1):
1052
+ # TODO avoid devision by zero
1053
+ flux_x[k + 1] += (
1054
+ ha[i]
1055
+ * ha[j]
1056
+ / h
1057
+ * self.basismatrices.A[k, i, j]
1058
+ / self.basismatrices.M[k, k]
1059
+ )
1060
+ for k in range(self.level + 1):
1061
+ for i in range(self.level + 1):
1062
+ for j in range(self.level + 1):
1063
+ # TODO avoid devision by zero
1064
+ flux_x[k + 1 + offset] += (
1065
+ hb[i]
1066
+ * ha[j]
1067
+ / h
1068
+ * self.basismatrices.A[k, i, j]
1069
+ / self.basismatrices.M[k, k]
1070
+ )
1071
+
1072
+ flux_y[0] = hb[0]
1073
+ flux_y[1 + offset] = p.g * p.ez * h * h / 2
1074
+ for k in range(self.level + 1):
1075
+ for i in range(self.level + 1):
1076
+ for j in range(self.level + 1):
1077
+ # TODO avoid devision by zero
1078
+ flux_y[k + 1] += (
1079
+ hb[i]
1080
+ * ha[j]
1081
+ / h
1082
+ * self.basismatrices.A[k, i, j]
1083
+ / self.basismatrices.M[k, k]
1084
+ )
1085
+ for k in range(self.level + 1):
1086
+ for i in range(self.level + 1):
1087
+ for j in range(self.level + 1):
1088
+ # TODO avoid devision by zero
1089
+ flux_y[k + 1 + offset] += (
1090
+ hb[i]
1091
+ * hb[j]
1092
+ / h
1093
+ * self.basismatrices.A[k, i, j]
1094
+ / self.basismatrices.M[k, k]
1095
+ )
1096
+ return [flux_x, flux_y]
1097
+
1098
+ def nonconservative_matrix(self):
1099
+ offset = self.level + 1
1100
+ nc_x = Matrix([[0 for i in range(self.n_variables)] for j in range(self.n_variables)])
1101
+ nc_y = Matrix([[0 for i in range(self.n_variables)] for j in range(self.n_variables)])
1102
+ h = self.variables[0]
1103
+ ha = self.variables[1 : 1 + self.level + 1]
1104
+ hb = self.variables[1 + offset : 1 + offset + self.level + 1]
1105
+ p = self.parameters
1106
+ um = ha[0] / h
1107
+ vm = hb[0] / h
1108
+ for k in range(1, self.level + 1):
1109
+ nc_x[k + 1, k + 1] += um
1110
+ nc_y[k + 1, k + 1 + offset] += um
1111
+ for k in range(self.level + 1):
1112
+ for i in range(1, self.level + 1):
1113
+ for j in range(1, self.level + 1):
1114
+ nc_x[k + 1, i + 1] -= (
1115
+ ha[j]
1116
+ / h
1117
+ * self.basismatrices.B[k, i, j]
1118
+ / self.basismatrices.M[k, k]
1119
+ )
1120
+ nc_y[k + 1, i + 1 + offset] -= (
1121
+ ha[j]
1122
+ / h
1123
+ * self.basismatrices.B[k, i, j]
1124
+ / self.basismatrices.M[k, k]
1125
+ )
1126
+
1127
+ for k in range(1, self.level + 1):
1128
+ nc_x[k + 1 + offset, k + 1] += vm
1129
+ nc_y[k + 1 + offset, k + 1 + offset] += vm
1130
+ for k in range(self.level + 1):
1131
+ for i in range(1, self.level + 1):
1132
+ for j in range(1, self.level + 1):
1133
+ nc_x[k + 1 + offset, i + 1] -= (
1134
+ hb[j]
1135
+ / h
1136
+ * self.basismatrices.B[k, i, j]
1137
+ / self.basismatrices.M[k, k]
1138
+ )
1139
+ nc_y[k + 1 + offset, i + 1 + offset] -= (
1140
+ hb[j]
1141
+ / h
1142
+ * self.basismatrices.B[k, i, j]
1143
+ / self.basismatrices.M[k, k]
1144
+ )
1145
+ return [nc_x, nc_y]
1146
+
1147
+ def eigenvalues(self):
1148
+ # we delete heigher order moments (level >= 2) for analytical eigenvalues
1149
+ offset = self.level + 1
1150
+ A = self.normal[0] * self.sympy_quasilinear_matrix[0]
1151
+ for d in range(1, self.dimension):
1152
+ A += self.normal[d] * self.sympy_quasilinear_matrix[d]
1153
+ alpha_erase = self.variables[2 : 2 + self.level]
1154
+ beta_erase = self.variables[2 + offset : 2 + offset + self.level]
1155
+ for alpha_i in alpha_erase:
1156
+ A = A.subs(alpha_i, 0)
1157
+ for beta_i in beta_erase:
1158
+ A = A.subs(beta_i, 0)
1159
+ return eigenvalue_dict_to_matrix(A.eigenvals())
1160
+
1161
+ def constraints_implicit(self):
1162
+ assert "dhdx" in vars(self.aux_variables)
1163
+ assert "dhdy" in vars(self.aux_variables)
1164
+ out = Matrix([0 for i in range(1)])
1165
+ h = self.variables[0]
1166
+ hu = self.variables[1]
1167
+ hv = self.variables[2]
1168
+ p = self.parameters
1169
+ dhdt = self.aux_variables.dhdt
1170
+ dhudt = self.aux_variables.dhudt
1171
+ dhvdt = self.aux_variables.dhvdt
1172
+ dhudx = self.aux_variables.dhudx
1173
+ dhudy = self.aux_variables.dhudy
1174
+ dhvdx = self.aux_variables.dhudx
1175
+ dhvdy = self.aux_variables.dhudy
1176
+ out[0] = dhdt + dhudx + dhvdx
1177
+ out[1] = dhudt + dhudx + dhvdx
1178
+ return out
1179
+
1180
+ def source(self):
1181
+ out = Matrix([0 for i in range(self.n_variables)])
1182
+ return out
1183
+
1184
+ def topography(self):
1185
+ assert "dhdx" in vars(self.aux_variables)
1186
+ assert "dhdy" in vars(self.aux_variables)
1187
+ offset = self.level + 1
1188
+ out = Matrix([0 for i in range(self.n_variables)])
1189
+ h = self.variables[0]
1190
+ p = self.parameters
1191
+ dhdx = self.aux_variables.dhdx
1192
+ dhdy = self.aux_variables.dhdy
1193
+ out[1] = h * p.g * (p.ex - p.ez * dhdx)
1194
+ out[1 + offset] = h * p.g * (p.ey - p.ez * dhdy)
1195
+ return out
1196
+
1197
+ def newtonian(self):
1198
+ assert "nu" in vars(self.parameters)
1199
+ out = Matrix([0 for i in range(self.n_variables)])
1200
+ offset = self.level + 1
1201
+ h = self.variables[0]
1202
+ ha = self.variables[1 : 1 + self.level + 1]
1203
+ hb = self.variables[1 + offset : 1 + self.level + 1 + offset]
1204
+ p = self.parameters
1205
+ for k in range(1 + self.level):
1206
+ for i in range(1 + self.level):
1207
+ out[1 + k] += (
1208
+ -p.nu
1209
+ / h
1210
+ * ha[i]
1211
+ / h
1212
+ * self.basismatrices.D[i, k]
1213
+ / self.basismatrices.M[k, k]
1214
+ )
1215
+ out[1 + k + offset] += (
1216
+ -p.nu
1217
+ / h
1218
+ * hb[i]
1219
+ / h
1220
+ * self.basismatrices.D[i, k]
1221
+ / self.basismatrices.M[k, k]
1222
+ )
1223
+ return out
1224
+
1225
+ def slip_mod(self):
1226
+ """
1227
+ :gui:
1228
+ - requires_parameter: ('lamda', 0.0)
1229
+ - requires_parameter: ('rho', 1.0)
1230
+ """
1231
+ assert "lamda" in vars(self.parameters)
1232
+ assert "rho" in vars(self.parameters)
1233
+ out = Matrix([0 for i in range(self.n_variables)])
1234
+ offset = self.level+1
1235
+ h = self.variables[0]
1236
+ ha = self.variables[1 : 1 + self.level + 1]
1237
+ hb = self.variables[1+offset : 1+offset + self.level + 1]
1238
+ p = self.parameters
1239
+ ub = 0
1240
+ vb = 0
1241
+ for i in range(1 + self.level):
1242
+ ub += ha[i] / h
1243
+ vb += hb[i] / h
1244
+ for k in range(1, 1 + self.level):
1245
+ out[1 + k] += (
1246
+ -1.0 * p.c_slipmod / p.lamda / p.rho * ub / self.basismatrices.M[k, k]
1247
+ )
1248
+ out[1+offset+k] += (
1249
+ -1.0 * p.c_slipmod / p.lamda / p.rho * vb / self.basismatrices.M[k, k]
1250
+ )
1251
+ return out
1252
+
1253
+ def newtonian_boundary_layer(self):
1254
+ assert "nu" in vars(self.parameters)
1255
+ out = Matrix([0 for i in range(self.n_variables)])
1256
+ offset = self.level + 1
1257
+ h = self.variables[0]
1258
+ h = self.variables[0]
1259
+ ha = self.variables[1 : 1 + self.level + 1]
1260
+ hb = self.variables[1 + offset : 1 + self.level + 1 + offset]
1261
+ p = self.parameters
1262
+ phi_0 = [self.basismatrices.eval(i, 0.0) for i in range(self.level + 1)]
1263
+ dphidx_0 = [
1264
+ (diff(self.basismatrices.eval(i, x), x)).subs(x, 0.0)
1265
+ for i in range(self.level + 1)
1266
+ ]
1267
+ for k in range(1 + self.level):
1268
+ for i in range(1 + self.level):
1269
+ out[1 + k] += (
1270
+ -p.nu
1271
+ / h
1272
+ * ha[i]
1273
+ / h
1274
+ / self.basismatrices.M[k, k]
1275
+ * phi_0[k]
1276
+ * dphidx_0[i]
1277
+ )
1278
+ out[1 + k + offset] += (
1279
+ -p.nu
1280
+ / h
1281
+ * hb[i]
1282
+ / h
1283
+ / self.basismatrices.M[k, k]
1284
+ * phi_0[k]
1285
+ * dphidx_0[i]
1286
+ )
1287
+ return out
1288
+
1289
+ def sindy(self):
1290
+ assert "nu" in vars(self.parameters)
1291
+ out = Matrix([0 for i in range(self.n_variables)])
1292
+ offset = self.level + 1
1293
+ h = self.variables[0]
1294
+ ha = self.variables[1 : 1 + self.level + 1]
1295
+ hb = self.variables[1 + offset : 1 + self.level + 1 + offset]
1296
+ p = self.parameters
1297
+ out[1] += (
1298
+ p.C1 * sympy.Abs(ha[0] / h)
1299
+ + p.C2 * sympy.Abs(ha[1] / h)
1300
+ + p.C3 * sympy.Abs(ha[0] / h) ** (7 / 3)
1301
+ + p.C4 * sympy.Abs(ha[1] / h) ** (7 / 3)
1302
+ )
1303
+ out[2] += (
1304
+ p.C5 * sympy.Abs(ha[0] / h)
1305
+ + p.C6 * sympy.Abs(ha[1] / h)
1306
+ + p.C7 * sympy.Abs(ha[0] / h) ** (7 / 3)
1307
+ + p.C8 * sympy.Abs(ha[1] / h) ** (7 / 3)
1308
+ )
1309
+ out[3] += (
1310
+ p.C1 * sympy.Abs(ha[0] / h)
1311
+ + p.C2 * sympy.Abs(ha[1] / h)
1312
+ + p.C3 * sympy.Abs(ha[0] / h) ** (7 / 3)
1313
+ + p.C4 * sympy.Abs(ha[1] / h) ** (7 / 3)
1314
+ )
1315
+ out[4] += (
1316
+ p.C5 * sympy.Abs(ha[0] / h)
1317
+ + p.C6 * sympy.Abs(ha[1] / h)
1318
+ + p.C7 * sympy.Abs(ha[0] / h) ** (7 / 3)
1319
+ + p.C8 * sympy.Abs(ha[1] / h) ** (7 / 3)
1320
+ )
1321
+ return out
1322
+
1323
+ def slip(self):
1324
+ assert "lamda" in vars(self.parameters)
1325
+ assert "rho" in vars(self.parameters)
1326
+ out = Matrix([0 for i in range(self.n_variables)])
1327
+ offset = self.level + 1
1328
+ h = self.variables[0]
1329
+ h = self.variables[0]
1330
+ ha = self.variables[1 : 1 + self.level + 1]
1331
+ hb = self.variables[1 + offset : 1 + self.level + 1 + offset]
1332
+ p = self.parameters
1333
+ for k in range(1 + self.level):
1334
+ for i in range(1 + self.level):
1335
+ out[1 + k] += (
1336
+ -1.0 / p.lamda / p.rho * ha[i] / h / self.basismatrices.M[k, k]
1337
+ )
1338
+ out[1 + k + offset] += (
1339
+ -1.0 / p.lamda / p.rho * hb[i] / h / self.basismatrices.M[k, k]
1340
+ )
1341
+ return out
1342
+
1343
+ def chezy(self):
1344
+ assert "C" in vars(self.parameters)
1345
+ out = Matrix([0 for i in range(self.n_variables)])
1346
+ offset = self.level + 1
1347
+ h = self.variables[0]
1348
+ ha = self.variables[1 : 1 + self.level + 1]
1349
+ hb = self.variables[1 + offset : 1 + self.level + 1 + offset]
1350
+ p = self.parameters
1351
+ tmp = 0
1352
+ for i in range(1 + self.level):
1353
+ for j in range(1 + self.level):
1354
+ tmp += ha[i] * ha[j] / h / h + hb[i] * hb[j] / h / h
1355
+ sqrt = sympy.sqrt(tmp)
1356
+ for k in range(1 + self.level):
1357
+ for l in range(1 + self.level):
1358
+ out[1 + k] += (
1359
+ -1.0 / (p.C**2 * self.basismatrices.M[k, k]) * ha[l] * sqrt / h
1360
+ )
1361
+ out[1 + k + offset] += (
1362
+ -1.0 / (p.C**2 * self.basismatrices.M[k, k]) * hb[l] * sqrt / h
1363
+ )
1364
+ return out
1365
+
1366
+
1367
+ def reconstruct_uvw(Q, grad, lvl, phi, psi):
1368
+ """
1369
+ returns functions u(z), v(z), w(z)
1370
+ """
1371
+ offset = lvl + 1
1372
+ h = Q[0]
1373
+ alpha = Q[1 : 1 + offset] / h
1374
+ beta = Q[1 + offset : 1 + 2 * offset] / h
1375
+ dhalpha_dx = grad[1 : 1 + offset, 0]
1376
+ dhbeta_dy = grad[1 + offset : 1 + 2 * offset, 1]
1377
+
1378
+ def u(z):
1379
+ u_z = 0
1380
+ for i in range(lvl + 1):
1381
+ u_z += alpha[i] * phi(z)[i]
1382
+ return u_z
1383
+
1384
+ def v(z):
1385
+ v_z = 0
1386
+ for i in range(lvl + 1):
1387
+ v_z += beta[i] * phi(z)[i]
1388
+ return v_z
1389
+
1390
+ def w(z):
1391
+ basis_0 = psi(0)
1392
+ basis_z = psi(z)
1393
+ u_z = 0
1394
+ v_z = 0
1395
+ grad_h = grad[0, :]
1396
+ # grad_hb = grad[-1, :]
1397
+ grad_hb = np.zeros(grad[0, :].shape)
1398
+ result = 0
1399
+ for i in range(lvl + 1):
1400
+ u_z += alpha[i] * basis_z[i]
1401
+ v_z += beta[i] * basis_z[i]
1402
+ for i in range(lvl + 1):
1403
+ result -= dhalpha_dx[i] * (basis_z[i] - basis_0[i])
1404
+ result -= dhbeta_dy[i] * (basis_z[i] - basis_0[i])
1405
+
1406
+ result += u_z * (z * grad_h[0] + grad_hb[0])
1407
+ result += v_z * (z * grad_h[1] + grad_hb[1])
1408
+ return result
1409
+
1410
+ return u, v, w
1411
+
1412
+
1413
+ def generate_velocity_profiles(
1414
+ Q,
1415
+ centers,
1416
+ model: Model,
1417
+ list_of_positions: list[np.ndarray],
1418
+ ):
1419
+ def find_closest_element(centers, pos):
1420
+ assert centers.shape[1] == np.array(pos).shape[0]
1421
+ return np.argmin(np.linalg.norm(centers - pos, axis=1))
1422
+
1423
+ # find the closest element to the given position
1424
+ vertices = []
1425
+ for pos in list_of_positions:
1426
+ vertex = find_closest_element(centers, pos)
1427
+ vertices.append(vertex)
1428
+
1429
+ Z = np.linspace(0, 1, 100)
1430
+ list_profiles = []
1431
+ list_means = []
1432
+ level = int((model.n_variables - 1) / model.dimension) - 1
1433
+ offset = level + 1
1434
+ list_h = []
1435
+ for vertex in vertices:
1436
+ profiles = []
1437
+ means = []
1438
+ for d in range(model.dimension):
1439
+ q = Q[vertex, :]
1440
+ h = q[0]
1441
+ coefs = q[1 + d * offset : 1 + (d + 1) * offset] / h
1442
+ profile = model.basis.basis.reconstruct_velocity_profile(coefs, Z=Z)
1443
+ mean = coefs[0]
1444
+ profiles.append(profile)
1445
+ means.append(mean)
1446
+ list_profiles.append(profiles)
1447
+ list_means.append(means)
1448
+ list_h.append(h)
1449
+ return list_profiles, list_means, list_of_positions, Z, list_h
1450
+
1451
+
1452
+ if __name__ == "__main__":
1453
+ # basis = Legendre_shifted(1)
1454
+ # basis = Spline()
1455
+ # basis = OrthogonalSplineWithConstant(degree=2, knots=[0, 0.1, 0.3,0.5, 1,1])
1456
+ # basis=OrthogonalSplineWithConstant(degree=1, knots=[0,0, 0.02, 0.04, 0.06, 0.08, 0.1, 1])
1457
+ # basis=OrthogonalSplineWithConstant(degree=1, knots=[0,0, 0.1, 1])
1458
+ # basis.plot()
1459
+
1460
+ # basis = Legendre_shifted(basis=Legendre_shifted(order=8))
1461
+ # f = basis.enforce_boundary_conditions()
1462
+ # q = np.array([[1., 0.1, 0., 0., 0., 0.], [1., 0.1, 0., 0., 3., 0.]])
1463
+ # print(f(q))
1464
+
1465
+ # basis =Legendre_shifted(order=8)
1466
+ # basis.plot()
1467
+ # z = np.linspace(0,1,100)
1468
+ # f = basis.get_lambda(1)
1469
+ # print(f(z), f(1.0))
1470
+ # f = basis.get_lambda(1)
1471
+ # print(f(z))
1472
+
1473
+ # X = np.linspace(0,1,100)
1474
+ # coef = np.array([0.2, -0.01, -0.1, -0.05, -0.04])
1475
+ # U = basis.basis.reconstruct_velocity_profile(coef, Z=X)
1476
+ # coef2 = coef*2
1477
+ # factor = 1.0 / 0.2
1478
+ # coef3 = coef * factor
1479
+ # U2 = basis.basis.reconstruct_velocity_profile(coef2, Z=X)
1480
+ # U3 = basis.basis.reconstruct_velocity_profile(coef3, Z=X)
1481
+ # fig, ax = plt.subplots()
1482
+ # ax.plot(U, X)
1483
+ # ax.plot(U2, X)
1484
+ # ax.plot(U3, X)
1485
+ # plt.show()
1486
+
1487
+ # X = np.linspace(0,1,100)
1488
+ # nut = 10**(-5)
1489
+ # coef = np.array([nut, -nut, 0, 0, 0, 0, 0 ])
1490
+ # U = basis.basis.reconstruct_velocity_profile(coef, Z=X)
1491
+ # fig, ax = plt.subplots()
1492
+ # ax.plot(U, X)
1493
+ # plt.show()
1494
+
1495
+ # nut = np.load('/home/ingo/Git/sms/nut_nut2.npy')
1496
+ # y = np.load('/home/ingo/Git/sms/nut_y2.npy')
1497
+ # coef = basis.basis.reconstruct_alpha(nut, y)
1498
+ # coef_offset = np.sum(coef)
1499
+ # coef[0] -= coef_offset
1500
+ # print(coef)
1501
+ # X = np.linspace(0,1,100)
1502
+ # _nut = basis.basis.reconstruct_velocity_profile(coef, Z=X)
1503
+ # fig, ax = plt.subplots()
1504
+ # ax.plot(_nut, X)
1505
+ # plt.show()
1506
+
1507
+ basis = Legendre_shifted(basis=Legendre_shifted(level=2))
1508
+ basis.compute_matrices(2)
1509
+ print(basis.D)