Skip to content

Commit 3be132b

Browse files
update code
1 parent 62e9855 commit 3be132b

File tree

3 files changed

+64
-36
lines changed

3 files changed

+64
-36
lines changed

ppsci/utils/sym_to_func.py

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,23 @@
1+
# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
2+
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
115
"""
216
Sympy to python function conversion module
317
"""
418

19+
from __future__ import annotations
20+
521
import functools
622
from typing import TYPE_CHECKING
723
from typing import Dict
@@ -17,7 +33,6 @@
1733

1834
from ppsci.autodiff import hessian
1935
from ppsci.autodiff import jacobian
20-
from ppsci.utils import logger
2136

2237
if TYPE_CHECKING:
2338
from ppsci import arch
@@ -235,7 +250,7 @@ def __init__(self, expr: Union[sp.Number, sp.NumberSymbol]):
235250
self.expr = float(self.expr)
236251
else:
237252
raise TypeError(
238-
f"expr({expr}) should be float/int/bool, but got {type(self.expr)}"
253+
f"expr({expr}) should be Float/Integer/Boolean/Rational, but got {type(self.expr)}"
239254
)
240255
self.expr = paddle.to_tensor(self.expr)
241256

@@ -253,10 +268,9 @@ class ComposedNode(nn.Layer):
253268
Compose list of several callable objects together.
254269
"""
255270

256-
def __init__(self, target: str, funcs: List[Node]):
271+
def __init__(self, funcs: List[Node]):
257272
super().__init__()
258273
self.funcs = funcs
259-
self.target = target
260274

261275
def forward(self, data_dict: Dict):
262276
# call all funcs in order
@@ -299,19 +313,57 @@ def _post_traverse(cur_node: sp.Basic, nodes: List[sp.Basic]) -> List[sp.Basic]:
299313

300314

301315
def sympy_to_function(
302-
target: str,
303316
expr: sp.Expr,
304317
models: Optional[Union[arch.Arch, Tuple[arch.Arch, ...]]] = None,
305318
) -> ComposedNode:
306319
"""Convert sympy expression to callable function.
307320
308321
Args:
309-
target (str): Alias of `expr`, such as "z" for expression: "z = a + b * c".
310322
expr (sp.Expr): Sympy expression to be converted.
311323
models (Optional[Union[arch.Arch, Tuple[arch.Arch, ...]]]): Model(s) for computing forward result in `LayerNode`.
312324
313325
Returns:
314326
ComposedNode: Callable object for computing expr with necessary input(s) data in dict given.
327+
328+
Examples:
329+
>>> import paddle
330+
>>> import sympy as sp
331+
>>> from ppsci import arch
332+
>>> from ppsci.utils import sym_to_func
333+
334+
>>> a, b, c, x, y = sp.symbols("a b c x y")
335+
>>> u = sp.Function("u")(x, y)
336+
>>> v = sp.Function("v")(x, y)
337+
>>> z = -a + b * (c ** 2) + u * v + 2.3
338+
339+
>>> model = arch.MLP(("x", "y"), ("u", "v"), 4, 16)
340+
341+
>>> batch_size = 13
342+
>>> a_tensor = paddle.randn([batch_size, 1])
343+
>>> b_tensor = paddle.randn([batch_size, 1])
344+
>>> c_tensor = paddle.randn([batch_size, 1])
345+
>>> x_tensor = paddle.randn([batch_size, 1])
346+
>>> y_tensor = paddle.randn([batch_size, 1])
347+
348+
>>> model_output_dict = model({"x": x_tensor, "y": y_tensor})
349+
>>> u_tensor, v_tensor = model_output_dict["u"], model_output_dict["v"]
350+
351+
>>> z_tensor_manually = (
352+
... -a_tensor + b_tensor * (c_tensor ** 2)
353+
... + u_tensor * v_tensor + 2.3
354+
... )
355+
>>> z_tensor_sympy = sym_to_func.sympy_to_function(z, model)(
356+
... {
357+
... "a": a_tensor,
358+
... "b": b_tensor,
359+
... "c": c_tensor,
360+
... "x": x_tensor,
361+
... "y": y_tensor,
362+
... }
363+
... )
364+
365+
>>> paddle.allclose(z_tensor_manually, z_tensor_sympy).item()
366+
True
315367
"""
316368

317369
# simplify expression to reduce nodes in tree
@@ -330,9 +382,10 @@ def sympy_to_function(
330382
sympy_nodes = list(dict.fromkeys(sympy_nodes))
331383

332384
# convert sympy node to callable node
385+
if not isinstance(models, (tuple, list)):
386+
models = (models,)
333387
callable_nodes = []
334388
for i, node in enumerate(sympy_nodes):
335-
logger.debug(f"tree node [{i + 1}/{len(sympy_nodes)}]: {node}")
336389
if isinstance(node.func, sp.core.function.UndefinedFunction):
337390
match = False
338391
for model in models:
@@ -359,4 +412,4 @@ def sympy_to_function(
359412
)
360413

361414
# Compose callable nodes into one callable object
362-
return ComposedNode(target, callable_nodes)
415+
return ComposedNode(callable_nodes)

test/utils/test_linear_elasticity_sympy.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import ppsci
2222
from ppsci import equation
2323
from ppsci.autodiff import clear
24-
from ppsci.utils import expression
24+
from ppsci.utils import sym_to_func
2525

2626
__all__ = []
2727

@@ -227,8 +227,8 @@ def test_linearelasticity(E, nu, lambda_, mu, rho, dim, time):
227227
E, nu, lambda_, mu, rho, dim, time
228228
).equations
229229
for target, expr in sympy_expr_dict.items():
230-
sympy_expr_dict[target] = expression.sympy_to_function(
231-
target, expr, [disp_net, stress_net]
230+
sympy_expr_dict[target] = sym_to_func.sympy_to_function(
231+
expr, [disp_net, stress_net]
232232
)
233233

234234
# compute equation with python function

test/utils/test_navier_stokes_sympy.py

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -127,29 +127,6 @@ def __init__(self, nu, rho=1, dim=3, time=True):
127127

128128

129129
class ZeroEquation_sympy:
130-
"""
131-
Zero Equation Turbulence model
132-
133-
Parameters
134-
==========
135-
nu : float
136-
The kinematic viscosity of the fluid.
137-
max_distance : float
138-
The maximum wall distance in the flow field.
139-
rho : float, Sympy sp.Symbol/Expr, str
140-
The density. If `rho` is a str then it is
141-
converted to Sympy sp.Function of form 'rho(x,y,z,t)'.
142-
If 'rho' is a Sympy sp.Symbol or Expression then this
143-
is substituted into the equation. Default is 1.
144-
dim : int
145-
Dimension of the Zero Equation Turbulence model (2 or 3).
146-
Default is 3.
147-
time : bool
148-
If time-dependent equations or not. Default is True.
149-
150-
Example
151-
"""
152-
153130
def __init__(
154131
self, nu, max_distance, rho=1, dim=3, time=True
155132
): # TODO add density into model
@@ -454,7 +431,6 @@ def momentum_y_f(out):
454431
sympy_expr_dict = NavierStokes_sympy(nu_sympy, rho, dim, time).equations
455432
for target, expr in sympy_expr_dict.items():
456433
sympy_expr_dict[target] = sym_to_func.sympy_to_function(
457-
target,
458434
expr,
459435
[
460436
model,
@@ -528,7 +504,6 @@ def test_nu_constant(self, nu, rho, dim, time):
528504
sympy_expr_dict = NavierStokes_sympy(nu_sympy, rho, dim, time).equations
529505
for target, expr in sympy_expr_dict.items():
530506
sympy_expr_dict[target] = sym_to_func.sympy_to_function(
531-
target,
532507
expr,
533508
[
534509
model,

0 commit comments

Comments
 (0)