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
layercake/__init__.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
from .variables.parameter import Parameter
|
|
3
|
+
from .variables.field import Field, ParameterField, FunctionField
|
|
4
|
+
from .basis.base import SymbolicBasis
|
|
5
|
+
from .arithmetic.symbolic.expressions import Expression
|
|
6
|
+
from .arithmetic.terms import *
|
|
7
|
+
from .arithmetic.equation import Equation
|
|
8
|
+
from .arithmetic.symbolic.operators import Laplacian, D
|
|
9
|
+
from .bakery.layers import Layer
|
|
10
|
+
from .bakery.cake import Cake
|
|
11
|
+
|
|
12
|
+
__all__ = ['Parameter', 'ParameterField', 'FunctionField', 'Field', 'Expression', 'SymbolicBasis', 'vorticity_advection', 'Jacobian',
|
|
13
|
+
'OperatorTerm', 'ProductOfTerms', 'AdditionOfTerms', 'LinearTerm', 'ConstantTerm', 'Equation', 'Laplacian', 'D',
|
|
14
|
+
'Layer', 'Cake']
|
|
15
|
+
|
|
16
|
+
__version__ = '1.0.2a0'
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
Equation definition module
|
|
5
|
+
==========================
|
|
6
|
+
|
|
7
|
+
Main class to define partial differential equation.
|
|
8
|
+
This class is the workhorse of LayerCake to define and specify
|
|
9
|
+
partial differential equation.
|
|
10
|
+
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from sympy import Symbol, S, Eq
|
|
14
|
+
import matplotlib.pyplot as plt
|
|
15
|
+
from layercake.arithmetic.terms.base import ArithmeticTerms
|
|
16
|
+
from layercake.utils import isin
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# TODO: deal with the cases where lists of terms are empty - maybe nothing is needed but to check
|
|
20
|
+
|
|
21
|
+
class Equation(object):
|
|
22
|
+
"""Main class to define and specify partial differential equations.
|
|
23
|
+
|
|
24
|
+
Notes
|
|
25
|
+
-----
|
|
26
|
+
The left-hand side is always expressed as a partial time derivative of
|
|
27
|
+
something: :math:`\\partial_t` .
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
field: ~field.Field
|
|
32
|
+
The spatial field over which the partial differential equation.
|
|
33
|
+
lhs_terms: ~arithmetic.terms.base.ArithmeticTerms or list(~arithmetic.terms.base.ArithmeticTerms), optional
|
|
34
|
+
Terms on the left-hand side of the equation. At least one must involve the field defined above.
|
|
35
|
+
name: str, optional
|
|
36
|
+
Name for the equation.
|
|
37
|
+
|
|
38
|
+
Attributes
|
|
39
|
+
----------
|
|
40
|
+
field: ~field.Field
|
|
41
|
+
The spatial field over which the partial differential equation.
|
|
42
|
+
rhs_terms: list(~arithmetic.terms.base.ArithmeticTerms)
|
|
43
|
+
List of additive terms in the right-hand side of the equation.
|
|
44
|
+
lhs_terms: ListOfArithmeticTerms(~arithmetic.terms.base.ArithmeticTerms)
|
|
45
|
+
Term on the left-hand side of the equation.
|
|
46
|
+
name: str
|
|
47
|
+
Optional name for the equation.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
_t = Symbol('t')
|
|
51
|
+
|
|
52
|
+
def __init__(self, field, lhs_terms=None, name=''):
|
|
53
|
+
|
|
54
|
+
self.field = field
|
|
55
|
+
self.field._equation = self
|
|
56
|
+
self.rhs_terms = ListOfAdditiveArithmeticTerms()
|
|
57
|
+
if lhs_terms is None:
|
|
58
|
+
self.lhs_terms = ListOfAdditiveArithmeticTerms()
|
|
59
|
+
elif isinstance(lhs_terms, list):
|
|
60
|
+
self.lhs_terms = ListOfAdditiveArithmeticTerms(lhs_terms)
|
|
61
|
+
else:
|
|
62
|
+
self.lhs_terms = ListOfAdditiveArithmeticTerms([lhs_terms])
|
|
63
|
+
self.name = name
|
|
64
|
+
self._layer = None
|
|
65
|
+
self._cake = None
|
|
66
|
+
|
|
67
|
+
def add_rhs_term(self, term):
|
|
68
|
+
"""Add a term to the right-hand side of the equation.
|
|
69
|
+
|
|
70
|
+
Parameters
|
|
71
|
+
----------
|
|
72
|
+
term: ~arithmetic.terms.base.ArithmeticTerms
|
|
73
|
+
Term to be added to the right-hand side of the equation.
|
|
74
|
+
"""
|
|
75
|
+
if not issubclass(term.__class__, ArithmeticTerms):
|
|
76
|
+
raise ValueError('Provided term must be a valid ArithmeticTerm object.')
|
|
77
|
+
self.terms.append(term)
|
|
78
|
+
|
|
79
|
+
def add_rhs_terms(self, terms):
|
|
80
|
+
"""Add multiple terms to the right-hand side of the equation.
|
|
81
|
+
|
|
82
|
+
Parameters
|
|
83
|
+
----------
|
|
84
|
+
terms: list(~arithmetic.terms.base.ArithmeticTerms)
|
|
85
|
+
Terms to be added to the right-hand side of the equation.
|
|
86
|
+
"""
|
|
87
|
+
for t in terms:
|
|
88
|
+
self.add_rhs_term(t)
|
|
89
|
+
|
|
90
|
+
def add_lhs_term(self, term):
|
|
91
|
+
"""Add a term to the left-hand side of the equation.
|
|
92
|
+
|
|
93
|
+
Parameters
|
|
94
|
+
----------
|
|
95
|
+
term: ~arithmetic.terms.base.ArithmeticTerms
|
|
96
|
+
Term to be added to the left-hand side of the equation.
|
|
97
|
+
"""
|
|
98
|
+
if not issubclass(term.__class__, ArithmeticTerms):
|
|
99
|
+
raise ValueError('Provided term must be a valid ArithmeticTerm object.')
|
|
100
|
+
self.lhs_terms.append(term)
|
|
101
|
+
|
|
102
|
+
def add_lhs_terms(self, terms):
|
|
103
|
+
"""Add multiple terms to the left-hand side of the equation.
|
|
104
|
+
|
|
105
|
+
Parameters
|
|
106
|
+
----------
|
|
107
|
+
terms: list(~arithmetic.terms.base.ArithmeticTerms)
|
|
108
|
+
Terms to be added to the left-hand side of the equation.
|
|
109
|
+
"""
|
|
110
|
+
for t in terms:
|
|
111
|
+
self.add_lhs_term(t)
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def terms(self):
|
|
115
|
+
"""Alias for the list of RHS arithmetic terms."""
|
|
116
|
+
return self.rhs_terms
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def other_fields(self):
|
|
120
|
+
"""list(~field.Field): List of additional fields present in the equation."""
|
|
121
|
+
other_fields = list()
|
|
122
|
+
for equation_term in self.terms:
|
|
123
|
+
for term in equation_term.terms:
|
|
124
|
+
if term.field is not self.field and term.field.dynamical and term.field not in other_fields:
|
|
125
|
+
other_fields.append(term.field)
|
|
126
|
+
other_fields = other_fields + self.other_fields_in_lhs
|
|
127
|
+
return other_fields
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def other_fields_in_lhs(self):
|
|
131
|
+
"""list(~field.Field): List of additional fields present in the LHS of the equation."""
|
|
132
|
+
other_fields = list()
|
|
133
|
+
for equation_term in self.lhs_terms:
|
|
134
|
+
for term in equation_term.terms:
|
|
135
|
+
if term.field is not self.field and term.field.dynamical and term.field not in other_fields:
|
|
136
|
+
other_fields.append(term.field)
|
|
137
|
+
return other_fields
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def parameter_fields(self):
|
|
141
|
+
"""list(~field.ParameterField): List of non-dynamical parameter fields present in the equation."""
|
|
142
|
+
parameter_fields = list()
|
|
143
|
+
for equation_term in self.terms:
|
|
144
|
+
for term in equation_term.terms:
|
|
145
|
+
if term.field is not self.field and not term.field.dynamical and term.field not in parameter_fields:
|
|
146
|
+
parameter_fields.append(term.field)
|
|
147
|
+
for equation_term in self.lhs_terms:
|
|
148
|
+
for term in equation_term.terms:
|
|
149
|
+
if term.field is not self.field and not term.field.dynamical and term.field not in parameter_fields:
|
|
150
|
+
parameter_fields.append(term.field)
|
|
151
|
+
return parameter_fields
|
|
152
|
+
|
|
153
|
+
@property
|
|
154
|
+
def parameters(self):
|
|
155
|
+
"""list(~parameter.Parameter): List of parameters present in the equation."""
|
|
156
|
+
parameters_list = list()
|
|
157
|
+
for term in self.terms + self.lhs_terms:
|
|
158
|
+
params_list = term.parameters
|
|
159
|
+
for param in params_list:
|
|
160
|
+
if not isin(param, parameters_list):
|
|
161
|
+
parameters_list.append(param)
|
|
162
|
+
|
|
163
|
+
for param_field in self.parameter_fields:
|
|
164
|
+
for param in param_field.parameters:
|
|
165
|
+
if param is not None and not isin(param, parameters_list):
|
|
166
|
+
parameters_list.append(param)
|
|
167
|
+
|
|
168
|
+
return parameters_list
|
|
169
|
+
|
|
170
|
+
@property
|
|
171
|
+
def parameters_symbols(self):
|
|
172
|
+
"""list(~sympy.core.symbol.Symbol): List of parameter's symbols present in the equation."""
|
|
173
|
+
return [p.symbol for p in self.parameters]
|
|
174
|
+
|
|
175
|
+
@property
|
|
176
|
+
def symbolic_expression(self):
|
|
177
|
+
"""~sympy.core.expr.Expr: Symbolic expression of the equation."""
|
|
178
|
+
return Eq(self.symbolic_lhs.diff(self._t, evaluate=False), self.rhs_terms.symbolic_expression)
|
|
179
|
+
|
|
180
|
+
@property
|
|
181
|
+
def numerical_expression(self):
|
|
182
|
+
"""~sympy.core.expr.Expr: Expression of the equation with parameters replaced by their
|
|
183
|
+
configured values."""
|
|
184
|
+
return Eq(self.numerical_lhs.diff(self._t, evaluate=False), self.rhs_terms.symbolic_expression)
|
|
185
|
+
|
|
186
|
+
@property
|
|
187
|
+
def symbolic_rhs(self):
|
|
188
|
+
"""~sympy.core.expr.Expr: Symbolic expression of the right-hand side of the equation."""
|
|
189
|
+
return self.rhs_terms.symbolic_expression
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def numerical_rhs(self):
|
|
193
|
+
"""~sympy.core.expr.Expr: Expression of the right-hand side of the equation with
|
|
194
|
+
parameters replaced by their configured values."""
|
|
195
|
+
return self.rhs_terms.numerical_expression
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def symbolic_lhs(self):
|
|
199
|
+
"""~sympy.core.expr.Expr: Symbolic expression of the left-hand side of the equation."""
|
|
200
|
+
return self.lhs_terms.symbolic_expression
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def numerical_lhs(self):
|
|
204
|
+
"""~sympy.core.expr.Expr: Expression of the left-hand side of the equation with
|
|
205
|
+
parameters replaced by their configured values."""
|
|
206
|
+
return self.lhs_terms.numerical_expression
|
|
207
|
+
|
|
208
|
+
@property
|
|
209
|
+
def lhs_inner_products(self):
|
|
210
|
+
"""list(~sympy.matrices.immutable.ImmutableSparseMatrix or ~sympy.tensor.array.ImmutableSparseNDimArray) or list(sparse.COO(float)): Inner products of each term of
|
|
211
|
+
the left-hand side of the equation, if available."""
|
|
212
|
+
return [term.inner_products for term in self.lhs_terms]
|
|
213
|
+
|
|
214
|
+
@property
|
|
215
|
+
def lhs_inner_products_addition(self):
|
|
216
|
+
"""~sympy.matrices.immutable.ImmutableSparseMatrix or ~sympy.tensor.array.ImmutableSparseNDimArray or sparse.COO(float): Added left-hand
|
|
217
|
+
side inner products of the equation, if available. Might raise an error if not all terms are compatible."""
|
|
218
|
+
result = self.lhs_terms[0].inner_products.copy()
|
|
219
|
+
for term in self.lhs_terms[1:]:
|
|
220
|
+
result = result + term.inner_products
|
|
221
|
+
return result
|
|
222
|
+
|
|
223
|
+
@property
|
|
224
|
+
def maximum_rank(self):
|
|
225
|
+
"""int: Maximum rank of the right-hand side terms tensors."""
|
|
226
|
+
return max(self.terms.maximum_rank, self.lhs_terms.maximum_rank)
|
|
227
|
+
|
|
228
|
+
def compute_inner_products(self, basis, numerical=False, timeout=None, num_threads=None, permute=False):
|
|
229
|
+
"""Compute the inner products tensor of the left-hand and right-hand side terms.
|
|
230
|
+
|
|
231
|
+
Parameters
|
|
232
|
+
----------
|
|
233
|
+
basis: SymbolicBasis
|
|
234
|
+
Basis with which to compute the inner products.
|
|
235
|
+
numerical: bool, optional
|
|
236
|
+
Whether the resulting computed inner products must be numerical or symbolic.
|
|
237
|
+
Default to `False`, i.e. symbolic output.
|
|
238
|
+
num_threads: int or None, optional
|
|
239
|
+
Number of threads to use to compute the inner products. If `None` use all the cpus available.
|
|
240
|
+
Default to `None`.
|
|
241
|
+
timeout: int or float or bool or None, optional
|
|
242
|
+
Control the switch from symbolic to numerical integration. By default, `parallel_integration` workers will try to integrate
|
|
243
|
+
|Sympy| expressions symbolically, but a fallback to numerical integration can be enforced.
|
|
244
|
+
The options are:
|
|
245
|
+
|
|
246
|
+
* `None`: This is the "full-symbolic" mode. No timeout will be applied, and the switch to numerical integration will never happen.
|
|
247
|
+
Can result in very long and improbable computation time.
|
|
248
|
+
* `True`: This is the "full-numerical" mode. Symbolic computations do not occur, and the workers try directly to integrate
|
|
249
|
+
numerically.
|
|
250
|
+
* `False`: Same as `None`.
|
|
251
|
+
* An integer: defines a timeout after which, if a symbolic integration have not completed, the worker switch to the
|
|
252
|
+
numerical integration.
|
|
253
|
+
permute: bool, optional
|
|
254
|
+
If `True`, applies all the possible permutations to the tensor indices
|
|
255
|
+
from 1 to the rank of the tensor.
|
|
256
|
+
Default to `False`, i.e. no permutation is applied.
|
|
257
|
+
"""
|
|
258
|
+
self.lhs_terms.compute_inner_products(basis, numerical, timeout, num_threads, permute)
|
|
259
|
+
self.rhs_terms.compute_inner_products(basis, numerical, timeout, num_threads, permute)
|
|
260
|
+
|
|
261
|
+
def to_latex(self, enclose_lhs=True, drop_first_lhs_char=True, drop_first_rhs_char=False):
|
|
262
|
+
"""Generate a LaTeX string representing the equation mathematically.
|
|
263
|
+
|
|
264
|
+
Parameters
|
|
265
|
+
----------
|
|
266
|
+
enclose_lhs: bool, optional
|
|
267
|
+
Whether to enclose the left-hand side term inside parenthesis.
|
|
268
|
+
Default to `True`.
|
|
269
|
+
drop_first_lhs_char: bool, optional
|
|
270
|
+
Whether to drop the first two character of the left-hand side latex string.
|
|
271
|
+
Useful to drop the sign in front of it.
|
|
272
|
+
Default to `True`.
|
|
273
|
+
drop_first_rhs_char: bool, optional
|
|
274
|
+
Whether to drop the first two character of the right-hand side latex string.
|
|
275
|
+
Useful to drop the sign in front of it.
|
|
276
|
+
Default to `False`.
|
|
277
|
+
|
|
278
|
+
Returns
|
|
279
|
+
-------
|
|
280
|
+
str
|
|
281
|
+
The LaTeX string representing the equation.
|
|
282
|
+
"""
|
|
283
|
+
lhs = self.lhs_terms[0].latex
|
|
284
|
+
for term in self.lhs_terms[1:]:
|
|
285
|
+
lhs += term.latex
|
|
286
|
+
if drop_first_lhs_char:
|
|
287
|
+
lhs = lhs[2:]
|
|
288
|
+
if enclose_lhs:
|
|
289
|
+
latex_string = r'\frac{\partial}{\partial t} ' + r'\left(' + lhs + r'\right)'
|
|
290
|
+
else:
|
|
291
|
+
latex_string = r'\frac{\partial}{\partial t} ' + lhs
|
|
292
|
+
|
|
293
|
+
first_term = self.terms[0].latex
|
|
294
|
+
if drop_first_rhs_char:
|
|
295
|
+
first_term = first_term[2:]
|
|
296
|
+
latex_string += ' = ' + first_term
|
|
297
|
+
|
|
298
|
+
for term in self.terms[1:]:
|
|
299
|
+
latex_string += term.latex
|
|
300
|
+
|
|
301
|
+
return latex_string
|
|
302
|
+
|
|
303
|
+
def show_latex(self, enclose_lhs=True, drop_first_lhs_char=True, drop_first_rhs_char=False):
|
|
304
|
+
"""Show the LaTeX string representing the equation mathematically rendered in a window.
|
|
305
|
+
|
|
306
|
+
Parameters
|
|
307
|
+
----------
|
|
308
|
+
enclose_lhs: bool, optional
|
|
309
|
+
Whether to enclose the left-hand side term inside parenthesis.
|
|
310
|
+
Default to `True`.
|
|
311
|
+
drop_first_lhs_char: bool, optional
|
|
312
|
+
Whether to drop the first two character of the left-hand side latex string.
|
|
313
|
+
Useful to drop the sign in front of it.
|
|
314
|
+
Default to `True`.
|
|
315
|
+
drop_first_rhs_char: bool, optional
|
|
316
|
+
Whether to drop the first two character of the right-hand side latex string.
|
|
317
|
+
Useful to drop the sign in front of it.
|
|
318
|
+
Default to `False`.
|
|
319
|
+
"""
|
|
320
|
+
|
|
321
|
+
latex_string = self.to_latex(enclose_lhs=enclose_lhs,
|
|
322
|
+
drop_first_lhs_char=drop_first_lhs_char,
|
|
323
|
+
drop_first_rhs_char=drop_first_rhs_char
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
plt.figure(figsize=(8, 2))
|
|
327
|
+
plt.axis('off')
|
|
328
|
+
plt.text(-0.1, 0.5, '$%s$' % latex_string)
|
|
329
|
+
plt.show()
|
|
330
|
+
|
|
331
|
+
def __repr__(self):
|
|
332
|
+
eq = self.symbolic_expression
|
|
333
|
+
return f'{eq.lhs} = {eq.rhs}'
|
|
334
|
+
|
|
335
|
+
def __str__(self):
|
|
336
|
+
return self.__repr__()
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
class ListOfAdditiveArithmeticTerms(list):
|
|
340
|
+
"""Class holding list of additive arithmetic terms in equations."""
|
|
341
|
+
|
|
342
|
+
def compute_inner_products(self, basis, numerical=False, timeout=None, num_threads=None, permute=False):
|
|
343
|
+
"""Compute the inner products tensor of the all the terms of the list.
|
|
344
|
+
|
|
345
|
+
Parameters
|
|
346
|
+
----------
|
|
347
|
+
basis: SymbolicBasis
|
|
348
|
+
Basis with which to compute the inner products.
|
|
349
|
+
numerical: bool, optional
|
|
350
|
+
Whether the resulting computed inner products must be numerical or symbolic.
|
|
351
|
+
Default to `False`, i.e. symbolic output.
|
|
352
|
+
num_threads: int or None, optional
|
|
353
|
+
Number of threads to use to compute the inner products. If `None` use all the cpus available.
|
|
354
|
+
Default to `None`.
|
|
355
|
+
timeout: int or float or bool or None, optional
|
|
356
|
+
Control the switch from symbolic to numerical integration. By default, `parallel_integration` workers will try to integrate
|
|
357
|
+
|Sympy| expressions symbolically, but a fallback to numerical integration can be enforced.
|
|
358
|
+
The options are:
|
|
359
|
+
|
|
360
|
+
* `None`: This is the "full-symbolic" mode. No timeout will be applied, and the switch to numerical integration will never happen.
|
|
361
|
+
Can result in very long and improbable computation time.
|
|
362
|
+
* `True`: This is the "full-numerical" mode. Symbolic computations do not occur, and the workers try directly to integrate
|
|
363
|
+
numerically.
|
|
364
|
+
* `False`: Same as `None`.
|
|
365
|
+
* An integer: defines a timeout after which, if a symbolic integration have not completed, the worker switch to the
|
|
366
|
+
numerical integration.
|
|
367
|
+
permute: bool, optional
|
|
368
|
+
If `True`, applies all the possible permutations to the tensor indices
|
|
369
|
+
from 1 to the rank of the tensor.
|
|
370
|
+
Default to `False`, i.e. no permutation is applied.
|
|
371
|
+
"""
|
|
372
|
+
|
|
373
|
+
for term in self:
|
|
374
|
+
term.compute_inner_products(basis, numerical, timeout, num_threads, permute)
|
|
375
|
+
|
|
376
|
+
@property
|
|
377
|
+
def maximum_rank(self):
|
|
378
|
+
"""int: Maximum rank of the right-hand side terms tensors."""
|
|
379
|
+
max_rank = 0
|
|
380
|
+
for term in self:
|
|
381
|
+
max_rank = max(max_rank, term.rank)
|
|
382
|
+
return max_rank
|
|
383
|
+
|
|
384
|
+
@property
|
|
385
|
+
def same_rank(self):
|
|
386
|
+
"""bool: Check if all terms have the same rank."""
|
|
387
|
+
rank = self[0].rank
|
|
388
|
+
for term in self[1:]:
|
|
389
|
+
if term.rank != rank:
|
|
390
|
+
return False
|
|
391
|
+
return True
|
|
392
|
+
|
|
393
|
+
@property
|
|
394
|
+
def symbolic_expression(self):
|
|
395
|
+
"""~sympy.core.expr.Expr: Symbolic expression of the collection of additive arithmetic terms."""
|
|
396
|
+
|
|
397
|
+
rterm = S.Zero
|
|
398
|
+
for term in self:
|
|
399
|
+
rterm += term.symbolic_expression
|
|
400
|
+
return rterm
|
|
401
|
+
|
|
402
|
+
@property
|
|
403
|
+
def numerical_expression(self):
|
|
404
|
+
"""~sympy.core.expr.Expr: Expression of the collection of additive arithmetic terms with
|
|
405
|
+
parameters replaced by their configured values."""
|
|
406
|
+
|
|
407
|
+
rterm = S.Zero
|
|
408
|
+
for term in self:
|
|
409
|
+
rterm += term.numerical_expression
|
|
410
|
+
return rterm
|
|
File without changes
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
|
|
2
|
+
"""
|
|
3
|
+
Expressions definition module
|
|
4
|
+
=============================
|
|
5
|
+
|
|
6
|
+
This module defines mathematical expression to be inserted in the models equations.
|
|
7
|
+
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Expression(object):
|
|
12
|
+
""" Class defining a general mathematical expression in the equations.
|
|
13
|
+
Can be used for example as prefactor for arithmetic terms.
|
|
14
|
+
|
|
15
|
+
Parameters
|
|
16
|
+
----------
|
|
17
|
+
symbolic_expression: ~sympy.core.expr.Expr
|
|
18
|
+
A |Sympy| expression to represent the field mathematical expression in symbolic expressions.
|
|
19
|
+
expression_parameters: None or list(~parameter.Parameter), optional
|
|
20
|
+
List of parameters appearing in the symbolic expression.
|
|
21
|
+
If `None`, assumes that no parameters are appearing there.
|
|
22
|
+
units: str, optional
|
|
23
|
+
The units of the variable.
|
|
24
|
+
Should be specified by joining atoms like `'[unit^power]'`, e.g '`[m^2][s^-2][Pa^-2]'`.
|
|
25
|
+
Empty by default.
|
|
26
|
+
latex: str, optional
|
|
27
|
+
Latex string representing the variable.
|
|
28
|
+
Empty by default.
|
|
29
|
+
|
|
30
|
+
Attributes
|
|
31
|
+
----------
|
|
32
|
+
symbolic_expression: ~sympy.core.expr.Expr
|
|
33
|
+
A |Sympy| expression to represent the field mathematical expression in symbolic expressions.
|
|
34
|
+
units: str
|
|
35
|
+
The units of the variable.
|
|
36
|
+
Should be specified by joining atoms like `'[unit^power]'`, e.g '`[m^2][s^-2][Pa^-2]'`.
|
|
37
|
+
latex: str, optional
|
|
38
|
+
Latex string representing the variable.
|
|
39
|
+
expression_parameters: None or list(~parameter.Parameter), optional
|
|
40
|
+
List of parameters appearing in the symbolic expression.
|
|
41
|
+
If `None`, assumes that no parameters are appearing there.
|
|
42
|
+
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
def __init__(self, symbolic_expression, expression_parameters=None, units="", latex=None):
|
|
46
|
+
|
|
47
|
+
self.symbolic_expression = symbolic_expression
|
|
48
|
+
self.expression_parameters = expression_parameters
|
|
49
|
+
self.units = units
|
|
50
|
+
self.latex = latex
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def symbol(self):
|
|
54
|
+
"""~sympy.core.expr.Expr: Synonym for the symbolic expression, to be accepted as prefactor."""
|
|
55
|
+
return self.symbolic_expression
|
|
56
|
+
@property
|
|
57
|
+
def numerical_expression(self):
|
|
58
|
+
"""~sympy.core.expr.Expr: The numeric expression, i.e. with parameters replaced by their numerical value."""
|
|
59
|
+
substitutions = list()
|
|
60
|
+
if self.expression_parameters is None:
|
|
61
|
+
expr_parameters = list()
|
|
62
|
+
else:
|
|
63
|
+
expr_parameters = self.expression_parameters
|
|
64
|
+
for param in expr_parameters:
|
|
65
|
+
substitutions.append((param.symbol, float(param)))
|
|
66
|
+
return self.symbolic_expression.subs(substitutions)
|
|
67
|
+
|
|
68
|
+
def __str__(self):
|
|
69
|
+
return self.symbolic_expression
|
|
70
|
+
|
|
71
|
+
def __repr__(self):
|
|
72
|
+
return self.__str__()
|
|
73
|
+
|