Convert sympy to ufl?

Is there a way to convert sympy expressions to ufl expressions? For instance how to convert

import sympy
x = sympy.Symbol("x")
sympy_input = sympy.cos(x) + x ** 2

into

import fenics
mesh = fenics.UnitIntervalMesh(10)
x = fenics.SpatialCoordinate(mesh)[0]
ufl_output = fenics.cos(x) + x**2

automatically?

Using strings and eval:

import sympy

x = sympy.Symbol("x")
cos = sympy.cos
sympy_input = cos(x) + x ** 2


import fenics
mesh = fenics.UnitIntervalMesh(10)
cos = fenics.cos
x = fenics.SpatialCoordinate(mesh)[0]
ufl_output = eval(str(sympy_input))
print(fenics.assemble(ufl_output*fenics.dx))

However, is there a specfic reason for using sympy?
UFL-forms can be differentiated etc, so in most use cases there is no need for using sympy.

EDIT: You can also use: https://github.com/MiroK/ulfy

1 Like

Thanks a lot!

However, is there a specfic reason for using sympy?

Good question. I am not sure. So I am using sympy to create manufactured solutions. So for instance I would like to take the derivative of cos(x) + x**2 symbolically and obtain -sin(x) + 2*x. I can do that in sympy. Can ufl also do this for me?

Yes, you can:
Consider this minimal example:

import fenics
mesh = fenics.UnitIntervalMesh(10)
cos = fenics.cos
x = fenics.SpatialCoordinate(mesh)[0]
expr =  cos(x) + x ** 2

print(fenics.assemble(fenics.grad(expr)[0]*fenics.dx))

which returns 0.540302 which is the analytical solution:

1 Like

Awesome. Is there a way to pretty print ufl so that something like sin(x) + 2*x appears on my screen?

No, as calling grad on a ufl expression does not compute the gradient until it is required (for instance in an assembly loop), you will not be able to see the symbolic representation of the derivative as you would like to.

1 Like

Ok thanks a lot! I think I will try to go pure ufl and only use sympy if I really need the pretty printed formulas.

How to use ufl expressions in connection with mixed elements. With sympy I would do something like

bc = DirichlectBC(V.sub(1), 
     Expression(sympy.printing.ccode(ex), degree=2),
    "on_boundary")

If I try an ufl expression with

bc = DirichlectBC(V.sub(1), ex, "on_boundary")

I get

*** Error:   Unable to create function.
*** Reason:  Cannot be created from subspace. Consider collapsing the function space.
*** Where:   This error was encountered inside Function.cpp.

Consider for instance:

from fenics import *
mesh = UnitIntervalMesh(10)
x = SpatialCoordinate(mesh)[0]
expr =  as_vector((cos(x) + x ** 2, x**3))

P2 =  VectorElement("CG", interval, 2, dim=2)
P1 = FiniteElement("CG", interval,  1)
V = FunctionSpace(mesh, MixedElement(P2,P1))
u_bc = project(expr, V.sub(0).collapse())
bc = DirichletBC(V.sub(0), u_bc, "on_boundary")
expr1 = sin(x)
u_bc1 = project(expr1, V.sub(1).collapse())
bc1 = DirichletBC(V.sub(1), u_bc1, "on_boundary")
1 Like

Thanks a lot for walking me through all this! It works for me now! Also ufl is a really nice formalism + python API.