layercake-model 1.0.2a0__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.
- layercake/__init__.py +16 -0
- layercake/arithmetic/equation.py +410 -0
- layercake/arithmetic/symbolic/__init__.py +0 -0
- layercake/arithmetic/symbolic/expressions.py +73 -0
- layercake/arithmetic/symbolic/operators.py +338 -0
- layercake/arithmetic/terms/__init__.py +9 -0
- layercake/arithmetic/terms/base.py +884 -0
- layercake/arithmetic/terms/constant.py +119 -0
- layercake/arithmetic/terms/gradient.py +185 -0
- layercake/arithmetic/terms/jacobian.py +183 -0
- layercake/arithmetic/terms/linear.py +98 -0
- layercake/arithmetic/terms/operations.py +262 -0
- layercake/arithmetic/terms/operators.py +226 -0
- layercake/arithmetic/utils.py +20 -0
- layercake/bakery/__init__.py +0 -0
- layercake/bakery/cake.py +705 -0
- layercake/bakery/layers.py +569 -0
- layercake/basis/__init__.py +4 -0
- layercake/basis/base.py +244 -0
- layercake/basis/planar_fourier.py +418 -0
- layercake/basis/spherical_harmonics.py +166 -0
- layercake/formatters/__init__.py +0 -0
- layercake/formatters/base.py +183 -0
- layercake/formatters/fortran.py +85 -0
- layercake/formatters/julia.py +93 -0
- layercake/formatters/python.py +89 -0
- layercake/inner_products/__init__.py +0 -0
- layercake/inner_products/definition.py +218 -0
- layercake/utils/__init__.py +8 -0
- layercake/utils/commutativity.py +45 -0
- layercake/utils/integration.py +200 -0
- layercake/utils/matrix.py +104 -0
- layercake/utils/parallel.py +215 -0
- layercake/utils/symbolic_tensor.py +172 -0
- layercake/utils/tensor.py +83 -0
- layercake/variables/__init__.py +0 -0
- layercake/variables/coordinate.py +65 -0
- layercake/variables/field.py +535 -0
- layercake/variables/parameter.py +664 -0
- layercake/variables/systems.py +143 -0
- layercake/variables/utils.py +142 -0
- layercake/variables/variable.py +314 -0
- layercake_model-1.0.2a0.dist-info/METADATA +142 -0
- layercake_model-1.0.2a0.dist-info/RECORD +47 -0
- layercake_model-1.0.2a0.dist-info/WHEEL +5 -0
- layercake_model-1.0.2a0.dist-info/licenses/LICENSE.txt +11 -0
- layercake_model-1.0.2a0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
Operators definition module
|
|
5
|
+
===========================
|
|
6
|
+
|
|
7
|
+
This module defines various symbolic operators (mainly differential ones)
|
|
8
|
+
acting on the fields of the partial differential equations in |Sympy| expression.
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
from sympy.core.decorators import call_highest_priority
|
|
14
|
+
from sympy import Expr, Matrix, Mul, Add, diff
|
|
15
|
+
from sympy.core.numbers import Zero
|
|
16
|
+
from sympy import Derivative
|
|
17
|
+
|
|
18
|
+
from layercake.utils.commutativity import enable_commutativity, disable_commutativity
|
|
19
|
+
from layercake.variables.systems import CoordinateSystem
|
|
20
|
+
|
|
21
|
+
# courtesy of https://stackoverflow.com/questions/15463412/differential-operator-usable-in-matrix-form-in-python-module-sympy
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class D(Expr):
|
|
25
|
+
"""Symbolic differential operator acting on |Sympy| expression.
|
|
26
|
+
Inspired by `this post <https://stackoverflow.com/questions/15463412/differential-operator-usable-in-matrix-form-in-python-module-sympy>`_.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
*variables: ~sympy.core.symbol.Symbol
|
|
31
|
+
Variables with respect to which the operator differentiates.
|
|
32
|
+
The number of variables indicate the order of the derivative.
|
|
33
|
+
|
|
34
|
+
Attributes
|
|
35
|
+
----------
|
|
36
|
+
variables: list(~sympy.core.symbol.Symbol)
|
|
37
|
+
Variables with respect to which the operator differentiates.
|
|
38
|
+
The number of variables indicate the order of the derivative.
|
|
39
|
+
evaluate: bool
|
|
40
|
+
Whether the expression resulting from the action of the operator is
|
|
41
|
+
evaluated.
|
|
42
|
+
Default to `False`.
|
|
43
|
+
latex: str
|
|
44
|
+
LaTeX representation of the operator.
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
_op_priority = 11.
|
|
49
|
+
is_commutative = False
|
|
50
|
+
|
|
51
|
+
def __new__(cls, *variables, **kwargs):
|
|
52
|
+
derivatives = Expr.__new__(cls, *variables, **kwargs)
|
|
53
|
+
derivatives.evaluate = False
|
|
54
|
+
nc_variables = [disable_commutativity(var) for var in variables]
|
|
55
|
+
derivatives.variables = nc_variables
|
|
56
|
+
latexes = list()
|
|
57
|
+
for var in variables:
|
|
58
|
+
if hasattr(var, 'latex'):
|
|
59
|
+
if var.latex is not None:
|
|
60
|
+
latexes.append(var.latex)
|
|
61
|
+
continue
|
|
62
|
+
if hasattr(var, 'symbol'):
|
|
63
|
+
if var.symbol is not None:
|
|
64
|
+
latexes.append(str(var.symbol))
|
|
65
|
+
continue
|
|
66
|
+
latexes.append(str(var))
|
|
67
|
+
|
|
68
|
+
if len(variables) > 1:
|
|
69
|
+
derivatives.latex = r'\frac{\partial^' + str(len(variables)) + r'}{'
|
|
70
|
+
else:
|
|
71
|
+
derivatives.latex = r'\frac{\partial}{'
|
|
72
|
+
|
|
73
|
+
for var in latexes[:-1]:
|
|
74
|
+
derivatives.latex += r'\partial ' + var + ' '
|
|
75
|
+
derivatives.latex += r'\partial ' + latexes[-1] + r'}'
|
|
76
|
+
|
|
77
|
+
return derivatives
|
|
78
|
+
|
|
79
|
+
def __repr__(self):
|
|
80
|
+
return 'D%s' % str(tuple(self.variables))
|
|
81
|
+
|
|
82
|
+
def __str__(self):
|
|
83
|
+
return self.__repr__()
|
|
84
|
+
|
|
85
|
+
@call_highest_priority('__mul__')
|
|
86
|
+
def __rmul__(self, other):
|
|
87
|
+
return Mul(other, self)
|
|
88
|
+
|
|
89
|
+
@call_highest_priority('__rmul__')
|
|
90
|
+
def __mul__(self, other):
|
|
91
|
+
if isinstance(other, D):
|
|
92
|
+
variables = self.variables + other.variables
|
|
93
|
+
return D(*variables)
|
|
94
|
+
if isinstance(other, Matrix):
|
|
95
|
+
other_copy = other.copy()
|
|
96
|
+
for i, elem in enumerate(other):
|
|
97
|
+
other_copy[i] = self * elem
|
|
98
|
+
return other_copy
|
|
99
|
+
|
|
100
|
+
if self.evaluate:
|
|
101
|
+
return diff(other, *self.variables)
|
|
102
|
+
else:
|
|
103
|
+
return Mul(self, other)
|
|
104
|
+
|
|
105
|
+
def __pow__(self, power, modulo=None):
|
|
106
|
+
|
|
107
|
+
if modulo is not None:
|
|
108
|
+
raise NotImplemented('D class: Modular exponentiation not implemented for derivatives')
|
|
109
|
+
|
|
110
|
+
variables = self.variables
|
|
111
|
+
for i in range(power - 1):
|
|
112
|
+
variables += self.variables
|
|
113
|
+
return D(*variables)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _diff(expr, *variables):
|
|
117
|
+
if isinstance(expr, D):
|
|
118
|
+
expr.variables += variables
|
|
119
|
+
return D(*expr.variables)
|
|
120
|
+
if isinstance(expr, Matrix):
|
|
121
|
+
expr_copy = expr.copy()
|
|
122
|
+
for i, elem in enumerate(expr):
|
|
123
|
+
expr_copy[i] = diff(elem, *variables)
|
|
124
|
+
return expr_copy
|
|
125
|
+
return diff(expr, *variables)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _evaluate_mul(expr):
|
|
129
|
+
end = 0
|
|
130
|
+
if expr.args:
|
|
131
|
+
if isinstance(expr.args[-1], D):
|
|
132
|
+
if len(expr.args[:-1]) == 1:
|
|
133
|
+
cte = expr.args[0]
|
|
134
|
+
return Zero()
|
|
135
|
+
end = -1
|
|
136
|
+
for i in range(len(expr.args)-1+end, -1, -1):
|
|
137
|
+
arg = expr.args[i]
|
|
138
|
+
if isinstance(arg, Add):
|
|
139
|
+
arg = _evaluate_add(arg)
|
|
140
|
+
if isinstance(arg, Mul):
|
|
141
|
+
arg = _evaluate_mul(arg)
|
|
142
|
+
if isinstance(arg, D):
|
|
143
|
+
left = Mul(*expr.args[:i])
|
|
144
|
+
right = Mul(*expr.args[i+1:])
|
|
145
|
+
right = _diff(right, *arg.variables)
|
|
146
|
+
ans = left * right
|
|
147
|
+
return _evaluate_mul(ans)
|
|
148
|
+
return expr
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _evaluate_add(expr):
|
|
152
|
+
newargs = []
|
|
153
|
+
for arg in expr.args:
|
|
154
|
+
if isinstance(arg, Mul):
|
|
155
|
+
arg = _evaluate_mul(arg)
|
|
156
|
+
if isinstance(arg, Add):
|
|
157
|
+
arg = _evaluate_add(arg)
|
|
158
|
+
if isinstance(arg, D):
|
|
159
|
+
arg = Zero()
|
|
160
|
+
newargs.append(arg)
|
|
161
|
+
return Add(*newargs)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _test_if_derivative_in_expr(expr, subs):
|
|
165
|
+
|
|
166
|
+
status = False
|
|
167
|
+
for arg in expr.args:
|
|
168
|
+
|
|
169
|
+
if isinstance(arg, Derivative) or isinstance(arg, D):
|
|
170
|
+
if arg not in subs:
|
|
171
|
+
subs.append(arg)
|
|
172
|
+
status = True
|
|
173
|
+
if hasattr(arg, 'args'):
|
|
174
|
+
res = _test_if_derivative_in_expr(arg, subs)
|
|
175
|
+
if res:
|
|
176
|
+
status = True
|
|
177
|
+
|
|
178
|
+
return status
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def evaluate_expr(expr):
|
|
182
|
+
"""Evaluate a given |Sympy| expression.
|
|
183
|
+
|
|
184
|
+
Parameters
|
|
185
|
+
----------
|
|
186
|
+
expr: ~sympy.core.expr.Expr
|
|
187
|
+
The expression to evaluate.
|
|
188
|
+
|
|
189
|
+
Returns
|
|
190
|
+
-------
|
|
191
|
+
~sympy.core.expr.Expr
|
|
192
|
+
The evaluated expression.
|
|
193
|
+
|
|
194
|
+
"""
|
|
195
|
+
if isinstance(expr, Matrix):
|
|
196
|
+
for i, elem in enumerate(expr):
|
|
197
|
+
elem = elem.expand()
|
|
198
|
+
expr[i] = evaluate_expr(elem)
|
|
199
|
+
return enable_commutativity(expr)
|
|
200
|
+
expr = expr.expand()
|
|
201
|
+
if isinstance(expr, Mul):
|
|
202
|
+
expr = _evaluate_mul(expr)
|
|
203
|
+
elif isinstance(expr, Add):
|
|
204
|
+
expr = _evaluate_add(expr)
|
|
205
|
+
elif isinstance(expr, D):
|
|
206
|
+
expr = Zero()
|
|
207
|
+
|
|
208
|
+
constant = True
|
|
209
|
+
while constant:
|
|
210
|
+
repl = list()
|
|
211
|
+
constant = _test_if_derivative_in_expr(expr, repl)
|
|
212
|
+
if constant:
|
|
213
|
+
new_expr = expr.replace(repl[0], Zero())
|
|
214
|
+
for rep in repl[1:]:
|
|
215
|
+
new_expr = new_expr.replace(rep, Zero())
|
|
216
|
+
else:
|
|
217
|
+
new_expr = expr
|
|
218
|
+
|
|
219
|
+
expr = new_expr
|
|
220
|
+
|
|
221
|
+
return expr
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _latex_repr(r):
|
|
225
|
+
def wrapper(f):
|
|
226
|
+
f.latex = r
|
|
227
|
+
return f
|
|
228
|
+
return wrapper
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
@_latex_repr(r'\nabla')
|
|
232
|
+
def Nabla(coordinate_system):
|
|
233
|
+
"""Function returning the Nabla (Del - :math:`\\nabla`) operator associated with a given
|
|
234
|
+
coordinate system.
|
|
235
|
+
|
|
236
|
+
Notes
|
|
237
|
+
-----
|
|
238
|
+
The returned expression has an additional `latex` attribute.
|
|
239
|
+
|
|
240
|
+
Parameters
|
|
241
|
+
----------
|
|
242
|
+
coordinate_system: ~systems.CoordinateSystem
|
|
243
|
+
Coordinate system for which the :math:`\\nabla` operator must be returned.
|
|
244
|
+
|
|
245
|
+
Returns
|
|
246
|
+
-------
|
|
247
|
+
~sympy.core.expr.Expr
|
|
248
|
+
The :math:`\\nabla` operator associated with the coordinate system.
|
|
249
|
+
|
|
250
|
+
"""
|
|
251
|
+
if not isinstance(coordinate_system, CoordinateSystem):
|
|
252
|
+
raise ValueError('Nabla only take coordinates systems as input.')
|
|
253
|
+
|
|
254
|
+
derivative_list = list()
|
|
255
|
+
for coord in coordinate_system.coordinates:
|
|
256
|
+
derivative_list.append(Mul(coord.infinitesimal_length**(-1), D(coord.symbol), evaluate=False))
|
|
257
|
+
|
|
258
|
+
mat = Matrix([derivative_list])
|
|
259
|
+
mat.latex = r'\nabla'
|
|
260
|
+
return mat
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
@_latex_repr(r'\nabla \cdot')
|
|
264
|
+
def Divergence(coordinate_system):
|
|
265
|
+
"""Function returning the divergence (:math:`\\nabla \\cdot`) operator associated with a given
|
|
266
|
+
coordinate system.
|
|
267
|
+
|
|
268
|
+
Notes
|
|
269
|
+
-----
|
|
270
|
+
The returned expression has an additional `latex` attribute.
|
|
271
|
+
|
|
272
|
+
Parameters
|
|
273
|
+
----------
|
|
274
|
+
coordinate_system: ~systems.CoordinateSystem
|
|
275
|
+
Coordinate system for which the divergence operator must be returned.
|
|
276
|
+
|
|
277
|
+
Returns
|
|
278
|
+
-------
|
|
279
|
+
~sympy.core.expr.Expr
|
|
280
|
+
The divergence operator associated with the coordinate system.
|
|
281
|
+
|
|
282
|
+
"""
|
|
283
|
+
|
|
284
|
+
if not isinstance(coordinate_system, CoordinateSystem):
|
|
285
|
+
raise ValueError('Divergence only take coordinates systems as input.')
|
|
286
|
+
|
|
287
|
+
derivative_list = list()
|
|
288
|
+
volume = coordinate_system.infinitesimal_volume
|
|
289
|
+
for coord in coordinate_system.coordinates:
|
|
290
|
+
derivative_list.append(Mul(volume**(-1), Mul(D(coord.symbol), volume / coord.infinitesimal_length,
|
|
291
|
+
evaluate=False), evaluate=False))
|
|
292
|
+
|
|
293
|
+
mat = Matrix([derivative_list])
|
|
294
|
+
mat.latex = r'\nabla \cdot'
|
|
295
|
+
return mat
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
class _Add_Laplacian(Add):
|
|
299
|
+
|
|
300
|
+
def __new__(cls, *args, **kwargs):
|
|
301
|
+
a = Add.__new__(cls, *args, **kwargs)
|
|
302
|
+
a._latex = r'\nabla^2'
|
|
303
|
+
|
|
304
|
+
return a
|
|
305
|
+
|
|
306
|
+
@property
|
|
307
|
+
def latex(self):
|
|
308
|
+
return self._latex
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
@_latex_repr(r'\nabla^2')
|
|
312
|
+
def Laplacian(coordinate_system):
|
|
313
|
+
"""Function returning the Laplacian (:math:`\\nabla^2`) operator associated with a given
|
|
314
|
+
coordinate system.
|
|
315
|
+
|
|
316
|
+
Notes
|
|
317
|
+
-----
|
|
318
|
+
The returned expression has an additional `latex` attribute.
|
|
319
|
+
|
|
320
|
+
Parameters
|
|
321
|
+
----------
|
|
322
|
+
coordinate_system: ~systems.CoordinateSystem
|
|
323
|
+
Coordinate system for which the Laplacian operator must be returned.
|
|
324
|
+
|
|
325
|
+
Returns
|
|
326
|
+
-------
|
|
327
|
+
~sympy.core.expr.Expr
|
|
328
|
+
The Laplacian operator associated with the coordinate system.
|
|
329
|
+
|
|
330
|
+
"""
|
|
331
|
+
if not isinstance(coordinate_system, CoordinateSystem):
|
|
332
|
+
raise ValueError('Laplacian only take coordinates systems as input.')
|
|
333
|
+
nabla = Nabla(coordinate_system)
|
|
334
|
+
divergence = Divergence(coordinate_system)
|
|
335
|
+
laplacian = Mul(divergence[0] * nabla[0], evaluate=False)
|
|
336
|
+
for i in range(1, len(nabla)):
|
|
337
|
+
laplacian = _Add_Laplacian(laplacian, Mul(divergence[i] * nabla[i], evaluate=False))
|
|
338
|
+
return laplacian
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
|
|
2
|
+
from .jacobian import vorticity_advection, Jacobian
|
|
3
|
+
from .operators import OperatorTerm
|
|
4
|
+
from .operations import AdditionOfTerms, ProductOfTerms
|
|
5
|
+
from .linear import LinearTerm
|
|
6
|
+
from .constant import ConstantTerm
|
|
7
|
+
|
|
8
|
+
__all__ = ['vorticity_advection', 'Jacobian', 'ProductOfTerms',
|
|
9
|
+
'OperatorTerm', 'AdditionOfTerms', 'LinearTerm', 'ConstantTerm']
|