zoomy-core 0.1.1__py3-none-any.whl → 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

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