Sympy to Fenics - Unable to compile

Hey, there.

I’m using a previous script programmed in sympy to obtain a 2x1 vector that, to my understanding, should represent a displacements boundary condition programmed in sympy. Here I add this code:

from sympy import symbols, atan2, sqrt, pi, log, sin, cos, Matrix

def calculate_displacements():
    x, y = symbols('x[0] x[1]')

    r_expr = sqrt(x**2 + y**2)

    theta_expr = atan2(y, x)

    gr = 1
    a_expr = cos(theta_expr)
    b_expr = -sin(theta_expr)
    c_expr = sin(theta_expr)
    d_expr = cos(theta_expr)
    u_r_expr = -1/2*cos(theta_expr)-gr*r_expr/(4*pi)*(-1+2*log(r_expr)+cos(2*theta_expr)*(1+2*log(r_expr))+2*(pi-theta_expr)*sin(2*theta_expr))
    u_theta_expr = 1/2*sin(theta_expr)+gr*r_expr/(4*pi)*(2*(theta_expr-pi)*(2-2*cos(2*theta_expr))-(1+2*log(r_expr))*sin(2*theta_expr))

    matriz_2x2 = Matrix([[a_expr, b_expr], [c_expr, d_expr]])
    matriz_2x1 = Matrix([u_r_expr, u_theta_expr])

    displacements = matriz_2x2 * matriz_2x1

    return displacements

Later, I’m calling this script in another code, and trying to import from sympy to a fenics expression that can be applied on boundaries:

disp = calculate_displacements() #vector 2d with python symbolic    
disp_0 = dolfin.Expression(sympy.printing.ccode(disp[0]), degree=1)
disp_1 = dolfin.Expression(sympy.printing.ccode(disp[1]), degree=1)

---------------------------------------------
RuntimeError: Unable to compile C++ code with dijitso

------------------- Start compiler output ------------------------
/tmp/tmpub49mgm6/dolfin_expression_dcc992add57a69e21eb4916509aef08b.cpp: In member function ‘virtual void dolfin::dolfin_expression_dcc992add57a69e21eb4916509aef08b::eval(Eigen::Ref<Eigen::Matrix<double, -1, 1> >, Eigen::Ref<const Eigen::Matrix<double, -1, 1> >) const’:
/tmp/tmpub49mgm6/dolfin_expression_dcc992add57a69e21eb4916509aef08b.cpp:61:158: error: too few arguments to function ‘void dolfin::log(int, std::string, ...)’

I don’t understand the error so, my question is, is this properly programmed? Can you actually import from sympy to fenics as I did with this implementation, or does it have to be with me writing bad expressions (I revised them several times)?

Thanks in advance.

Full error

------------------- Start compiler output ------------------------
/tmp/tmp_13w9miu/dolfin_expression_dcc992add57a69e21eb4916509aef08b.cpp: In member function ‘virtual void dolfin::dolfin_expression_dcc992add57a69e21eb4916509aef08b::eval(Eigen::Ref<Eigen::Matrix<double, -1, 1> >, Eigen::Ref<const Eigen::Matrix<double, -1, 1> >) const’:
/tmp/tmp_13w9miu/dolfin_expression_dcc992add57a69e21eb4916509aef08b.cpp:61:158: error: too few arguments to function ‘void dolfin::log(int, std::string, ...)’
   61 |           values[0] = x[0]*(-0.5*x[0]/sqrt(pow(x[0], 2) + pow(x[1], 2)) - 1.0/4.0*sqrt(pow(x[0], 2) + pow(x[1], 2))*((2*log(sqrt(pow(x[0], 2) + pow(x[1], 2))) + 1)*cos(2*atan2(x[1], x[0])) + (-2*atan2(x[1], x[0]) + 2*M_PI)*sin(2*atan2(x[1], x[0])) + 2*log(sqrt(pow(x[0], 2) + pow(x[1], 2))) - 1)/M_PI)/sqrt(pow(x[0], 2) + pow(x[1], 2)) - x[1]*(0.5*x[1]/sqrt(pow(x[0], 2) + pow(x[1], 2)) + (1.0/4.0)*sqrt(pow(x[0], 2) + pow(x[1], 2))*((2 - 2*cos(2*atan2(x[1], x[0])))*(2*atan2(x[1], x[0]) - 2*M_PI) - (2*log(sqrt(pow(x[0], 2) + pow(x[1], 2))) + 1)*sin(2*atan2(x[1], x[0])))/M_PI)/sqrt(pow(x[0], 2) + pow(x[1], 2));
      |
         ^
In file included from /usr/include/dolfin/common/Array.h:32,
                 from /usr/include/dolfin/function/Expression.h:27,
                 from /tmp/tmp_13w9miu/dolfin_expression_dcc992add57a69e21eb4916509aef08b.cpp:13:
/usr/include/dolfin/log/log.h:103:8: note: declared here
  103 |   void log(int debug_level, std::string msg, ...);
      |        ^~~
/tmp/tmp_13w9miu/dolfin_expression_dcc992add57a69e21eb4916509aef08b.cpp:61:290: error: too few arguments to function ‘void dolfin::log(int, std::string, ...)’
   61 |           values[0] = x[0]*(-0.5*x[0]/sqrt(pow(x[0], 2) + pow(x[1], 2)) - 1.0/4.0*sqrt(pow(x[0], 2) + pow(x[1], 2))*((2*log(sqrt(pow(x[0], 2) + pow(x[1], 2))) + 1)*cos(2*atan2(x[1], x[0])) + (-2*atan2(x[1], x[0]) + 2*M_PI)*sin(2*atan2(x[1], x[0])) + 2*log(sqrt(pow(x[0], 2) + pow(x[1], 2))) - 1)/M_PI)/sqrt(pow(x[0], 2) + pow(x[1], 2)) - x[1]*(0.5*x[1]/sqrt(pow(x[0], 2) + pow(x[1], 2)) + (1.0/4.0)*sqrt(pow(x[0], 2) + pow(x[1], 2))*((2 - 2*cos(2*atan2(x[1], x[0])))*(2*atan2(x[1], x[0]) - 2*M_PI) - (2*log(sqrt(pow(x[0], 2) + pow(x[1], 2))) + 1)*sin(2*atan2(x[1], x[0])))/M_PI)/sqrt(pow(x[0], 2) + pow(x[1], 2));
      |
                                                                                                                                             ^
In file included from /usr/include/dolfin/common/Array.h:32,
                 from /usr/include/dolfin/function/Expression.h:27,
                 from /tmp/tmp_13w9miu/dolfin_expression_dcc992add57a69e21eb4916509aef08b.cpp:13:
/usr/include/dolfin/log/log.h:103:8: note: declared here
  103 |   void log(int debug_level, std::string msg, ...);
      |        ^~~
/tmp/tmp_13w9miu/dolfin_expression_dcc992add57a69e21eb4916509aef08b.cpp:61:541: error: too few arguments to function ‘void dolfin::log(int, std::string, ...)’
   61 |           values[0] = x[0]*(-0.5*x[0]/sqrt(pow(x[0], 2) + pow(x[1], 2)) - 1.0/4.0*sqrt(pow(x[0], 2) + pow(x[1], 2))*((2*log(sqrt(pow(x[0], 2) + pow(x[1], 2))) + 1)*cos(2*atan2(x[1], x[0])) + (-2*atan2(x[1], x[0]) + 2*M_PI)*sin(2*atan2(x[1], x[0])) + 2*log(sqrt(pow(x[0], 2) + pow(x[1], 2))) - 1)/M_PI)/sqrt(pow(x[0], 2) + pow(x[1], 2)) - x[1]*(0.5*x[1]/sqrt(pow(x[0], 2) + pow(x[1], 2)) + (1.0/4.0)*sqrt(pow(x[0], 2) + pow(x[1], 2))*((2 - 2*cos(2*atan2(x[1], x[0])))*(2*atan2(x[1], x[0]) - 2*M_PI) - (2*log(sqrt(pow(x[0], 2) + pow(x[1], 2))) + 1)*sin(2*atan2(x[1], x[0])))/M_PI)/sqrt(pow(x[0], 2) + pow(x[1], 2));
      |


                                                                                ^
In file included from /usr/include/dolfin/common/Array.h:32,
                 from /usr/include/dolfin/function/Expression.h:27,
                 from /tmp/tmp_13w9miu/dolfin_expression_dcc992add57a69e21eb4916509aef08b.cpp:13:
/usr/include/dolfin/log/log.h:103:8: note: declared here
  103 |   void log(int debug_level, std::string msg, ...);
      |        ^~~

-------------------  End compiler output  ------------------------
Compilation failed! Sources, command, and errors have been written to: /mnt/c/fenics_cracks/Dirichlet_Robin_M2/jitfailure-dolfin_expression_dcc992add57a69e21eb4916509aef08b
Traceback (most recent call last):
  File "/usr/lib/petsc/lib/python3/dist-packages/dolfin/jit/jit.py", line 168, in compile_class
    module, signature = dijitso_jit(cpp_data, module_name, params,
  File "/usr/lib/petsc/lib/python3/dist-packages/dolfin/jit/jit.py", line 50, in mpi_jit
    return local_jit(*args, **kwargs)
  File "/usr/lib/petsc/lib/python3/dist-packages/dolfin/jit/jit.py", line 106, in dijitso_jit
    return dijitso.jit(*args, **kwargs)
  File "/home/edu/.local/lib/python3.8/site-packages/dijitso/jit.py", line 216, in jit
    raise DijitsoError("Dijitso JIT compilation failed, see '%s' for details"
dijitso.jit.DijitsoError: Dijitso JIT compilation failed, see '/mnt/c/fenics_cracks/Dirichlet_Robin_M2/jitfailure-dolfin_expression_dcc992add57a69e21eb4916509aef08b' for details

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "Dirichlet_Robin_M2.py", line 69, in <module>
    disp_0 = dolfin.Expression(sympy.printing.ccode(disp[0]), degree=1)
  File "/usr/lib/petsc/lib/python3/dist-packages/dolfin/function/expression.py", line 400, in __init__
    self._cpp_object = jit.compile_expression(cpp_code, params)
  File "/usr/lib/petsc/lib/python3/dist-packages/dolfin/function/jit.py", line 158, in compile_expression
    expression = compile_class(cpp_data, mpi_comm=mpi_comm)
  File "/usr/lib/petsc/lib/python3/dist-packages/dolfin/jit/jit.py", line 173, in compile_class
    raise RuntimeError("Unable to compile C++ code with dijitso")
RuntimeError: Unable to compile C++ code with dijitso

It’s not scoping the log function correctly with std::log. It’s instead calling old DOLFIN’s log function which traces the codes operation. If you read through the sympy documentation there’s probably some information on how to scope out functions in code generation. Otherwise you could try the ugly hack of just replacing log with std::log in the generated code. Something like

code = code.replace("log", "std::log")

Hello Nate,

Thank you for your answer. If I am getting it right, the code where I am generating my symbolic expressions should remain as it is, and the code where I’m implementing my FEM solution should be:

disp = calculate_displacements() #vector 2d with python symbolic    
disp = disp.replace("log", "std::log") #change log to std log
disp_0 = dolfin.Expression(sympy.printing.ccode(disp[0]), degree=1)
disp_1 = dolfin.Expression(sympy.printing.ccode(disp[1]), degree=1

Should it work like this? Is this what you meant? What if, in my original sympy code, I just wrote std::log instead of log?
Thanks again

Something along these lines yes. I’d expect you’d just have to replace the log with std::log in your C/C++ code string. Since you haven’t provided a minimal working example I doubt I can help further.

The way I tried to implement your solution was with the lines above, using replace, instead of manually replacing log with std::log. It didn’t work: TypeError: first argument to replace() must be a type, an expression or a callable. As far as I know, log a string (sympy documentation) and I doubt replace can be used here. Could you help me any further? Are there any other options?

Thanks again.

str.replace is a method of the string class. I don’t know what the type of the object that you’re calling .replace on is. As I said, without a MWE I can’t really provide much help. My advice was to call .replace on the code string that you’re producing from sympy’s code generation.

If you check my original post, you will find there the code that I’m using to generate my sympy expressions, full code displayed. That, I think, could be a MWE. Later on, I implemented

disp = calculate_displacements() #vector 2d with python symbolic    
disp = disp.replace("log", "std::log") #change log to std log
disp_0 = dolfin.Expression(sympy.printing.ccode(disp[0]), degree=1)
disp_1 = dolfin.Expression(sympy.printing.ccode(disp[1]), degree=1

This is where the first argument to replace() must be a type, an expression or a callable arose.

Thanks again.

@egomezp Please be considerate of the users answering your questions, as they do so in their own free time, on top of any work, teaching or other activity which is already going on in their life.

@nate asked you twice to provide a MWE. It’s true you posted an example in the first post, but that example surely has changed due to the intermediate replies. It won’t take you more than a minute to copy and paste it again in a further reply, updating it where needed, and doing so may help clarify the question for people who have already replied to you, or people who haven’t replied yet but may be willing to help.

Okay. This is my MWE:

I’m using this code to generate my sympy expressions:

from sympy import symbols, atan2, sqrt, pi, log, sin, cos, Matrix

def calculate_displacements():
    # Definir símbolos
    x, y = symbols('x[0] x[1]')

    # Definir r en términos de x e y
    r_expr = sqrt(x**2 + y**2)

    # Definir theta en términos de x e y
    theta_expr = atan2(y, x)

    # Definir expresiones analíticas
    gr = 1
    a_expr = cos(theta_expr)
    b_expr = -sin(theta_expr)
    c_expr = sin(theta_expr)
    d_expr = cos(theta_expr)
    u_r_expr = -1/2*cos(theta_expr)-gr*r_expr/(4*pi)*(-1+2*log(r_expr)+cos(2*theta_expr)*(1+2*log(r_expr))+2*(pi-theta_expr)*sin(2*theta_expr))
    u_theta_expr = 1/2*sin(theta_expr)+gr*r_expr/(4*pi)*(2*(theta_expr-pi)*(2-2*cos(2*theta_expr))-(1+2*log(r_expr))*sin(2*theta_expr))

    # Definir las matrices con expresiones
    matriz_2x2 = Matrix([[a_expr, b_expr], [c_expr, d_expr]])
    matriz_2x1 = Matrix([u_r_expr, u_theta_expr])

    # Realizar la multiplicación de matrices con expresiones 
    displacements = matriz_2x2 * matriz_2x1
    return displacements

And later on, following @nate 's guide, I want to import this expressions to my FEniCs program using

disp = calculate_displacements()
disp = disp.replace("log", "std::log") #change log to std log
disp_x0 = dolfin.Expression(sympy.printing.ccode(disp[0]), degree=1)
disp_x1 = dolfin.Expression(sympy.printing.ccode(disp[1]), degree=1)

As @nate mentioned, I can’t use disp.replace because replace needs a type, expression or callable in order to replace, but sympy is working with strings. That’s where I am right now, my actual code.

Thanks!

The following works for me

import dolfin
import sympy
from sympy import symbols, atan2, sqrt, pi, log, sin, cos, Matrix

def calculate_displacements():
    # Definir símbolos
    x, y = symbols('x[0] x[1]')

    # Definir r en términos de x e y
    r_expr = sqrt(x**2 + y**2)

    # Definir theta en términos de x e y
    theta_expr = atan2(y, x)

    # Definir expresiones analíticas
    gr = 1
    a_expr = cos(theta_expr)
    b_expr = -sin(theta_expr)
    c_expr = sin(theta_expr)
    d_expr = cos(theta_expr)
    u_r_expr = -1/2*cos(theta_expr)-gr*r_expr/(4*pi)*(-1+2*log(r_expr)+cos(2*theta_expr)*(1+2*log(r_expr))+2*(pi-theta_expr)*sin(2*theta_expr))
    u_theta_expr = 1/2*sin(theta_expr)+gr*r_expr/(4*pi)*(2*(theta_expr-pi)*(2-2*cos(2*theta_expr))-(1+2*log(r_expr))*sin(2*theta_expr))

    # Definir las matrices con expresiones
    matriz_2x2 = Matrix([[a_expr, b_expr], [c_expr, d_expr]])
    matriz_2x1 = Matrix([u_r_expr, u_theta_expr])

    # Realizar la multiplicación de matrices con expresiones
    displacements = matriz_2x2 * matriz_2x1
    return displacements

disp = calculate_displacements()
disp_ccode = [sympy.printing.ccode(disp[i]).replace("log", "std::log") for i in (0, 1)]
disp_x0 = dolfin.Expression(disp_ccode[0], degree=1)
disp_x1 = dolfin.Expression(disp_ccode[1], degree=1)
1 Like

Now it seems to be fixed. I’m working on another part of the code which is not working, but this seems fixed.

Thanks again to both of you, and sorry.