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.

Files changed (51) hide show
  1. zoomy_core/__init__.py +7 -0
  2. zoomy_core/decorators/decorators.py +25 -0
  3. zoomy_core/fvm/flux.py +52 -0
  4. zoomy_core/fvm/nonconservative_flux.py +97 -0
  5. zoomy_core/fvm/ode.py +55 -0
  6. zoomy_core/fvm/solver_numpy.py +297 -0
  7. zoomy_core/fvm/timestepping.py +13 -0
  8. zoomy_core/mesh/mesh.py +1236 -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/interpolation.py +140 -0
  13. zoomy_core/misc/io.py +439 -0
  14. zoomy_core/misc/logger_config.py +18 -0
  15. zoomy_core/misc/misc.py +213 -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.11.dist-info/METADATA +225 -0
  48. zoomy_core-0.1.11.dist-info/RECORD +51 -0
  49. zoomy_core-0.1.11.dist-info/WHEEL +5 -0
  50. zoomy_core-0.1.11.dist-info/licenses/LICENSE +674 -0
  51. zoomy_core-0.1.11.dist-info/top_level.txt +1 -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 zoomy_core.model.basemodel import (
19
+ register_sympy_attribute,
20
+ eigenvalue_dict_to_matrix,
21
+ )
22
+ from zoomy_core.model.basemodel import Model
23
+ import zoomy_core.model.initial_conditions as IC
24
+ from 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)