upgrade from 2017.1 to 2019.1: cppcode in Expressions

Issue #1095 new
Nico Schlömer created an issue

I’m in the process of upgrading a 2017.1-compatible dolfin code to 2019.1. Here I have a fairly complex Expression that relies on cppcode:

def supg(mesh, convection, diffusion, element_degree):
    cppcode = """#include <dolfin/mesh/Vertex.h>

class SupgStab : public Expression {
public:
double epsilon;
int p;
std::shared_ptr<GenericFunction> convection;
std::shared_ptr<Mesh> mesh;

SupgStab(): Expression()
{}

void eval(
  Array<double>& tau,
  const Array<double>& x,
  const ufc::cell& c
  ) const
{
  Array<double> v(x.size());
  convection->eval(v, x, c);
  double conv_norm = 0.0;
  for (uint i = 0; i < v.size(); ++i)
    conv_norm += v[i]*v[i];
  conv_norm = sqrt(conv_norm);

  Cell cell(*mesh, c.index);

  //// The alternative for the lazy:
  //const double h = cell.diameter();

  // Compute the directed diameter of the cell, cf. :cite:`sold2`.
  //
  //    diam(cell, s) = 2*||s|| / sum_{nodes n_i} |s.\\grad\\psi|
  //
  // where \\psi is the P_1 basis function of n_i.
  //
  const double area = cell.volume();
  const unsigned int* vertices = cell.entities(0);
  assert(vertices);
  double sum = 0.0;
  for (int i=0; i<3; i++) {
    for (int j=i+1; j<3; j++) {
      // Get edge coords.
      const dolfin::Vertex v0(*mesh, vertices[i]);
      const dolfin::Vertex v1(*mesh, vertices[j]);
      const Point p0 = v0.point();
      const Point p1 = v1.point();
      const double e0 = p0[0] - p1[0];
      const double e1 = p0[1] - p1[1];

      // Note that
      //
      //     \\grad\\psi = ortho_edge / edgelength / height
      //               = ortho_edge / (2*area)
      //
      // so
      //
      //   (v.\\grad\\psi) = (v.ortho_edge) / (2*area).
      //
      // Move the constant factors out of the summation.
      //
      // It would be really nice if we could just do
      //    edge.dot((-v[1], v[0]))
      // but unfortunately, edges just dot with other edges.
      sum += fabs(e1*v[0] - e0*v[1]);
    }
  }
  const double h = 4 * conv_norm * area / sum;

  // Just a little sanity check here.
  assert(h <= cell.diameter());

  const double Pe = 0.5*conv_norm * h/(p*epsilon);
  assert(Pe > 0.0);

  // We'd like to compute `xi = (1.0/tanh(Pe) - 1.0/Pe) / Pe`. This expression
  // can hardly be evaluated for small Pe, see
  // <https://stackoverflow.com/a/43279491/353337>. Hence, use its Taylor
  // expansion around 0.
  const double xi = Pe > 1.0e-5 ?
      (1.0/tanh(Pe) - 1.0/Pe) / Pe :
      1.0/3.0 - Pe*Pe / 45.0 + 2.0/945.0 * Pe*Pe*Pe*Pe;
  // const double xi =  (Pe > 1.0 ? 1.0 - 1.0/Pe : 0.0) / Pe;

  tau[0] = h*h / 4 / epsilon / p * xi;

  if (tau[0] > 1.0e3)
  {
    std::cout << "tau   = " << tau[0] << std::endl;
    std::cout << "||b|| = " << conv_norm << std::endl;
    std::cout << "Pe    = " << Pe << std::endl;
    std::cout << "h     = " << h << std::endl;
    std::cout << "xi    = " << xi << std::endl;
    throw 1;
  }

  return;
}
};
"""
    # TODO set degree
    tau = Expression(cppcode, degree=5)
    tau.convection = convection
    tau.mesh = mesh
    tau.epsilon = diffusion
    tau.p = element_degree
    return tau

With 2019.1, this fails to compile. In the generated output, I find

       void eval(Eigen::Ref<Eigen::VectorXd> values, Eigen::Ref<const Eigen::VectorXd> x) const override
         {
            values[0] = #include <dolfin/mesh/Vertex.h>
          // [...]

so I’m guessing the entire cppcode is supposed to be one expression that’s a valid rhs.

Well, I don’t have that. Any hint on how to modify the code?

Comments (14)

  1. Nico Schlömer reporter

    Thanks Michal for the link, this helped me a great deal. This now gets me to the cryptic

    E           ImportError: generic_type: type "SupgStab" referenced unknown base type "dolfin::Expression"
    

    Any idea what this might be about?

  2. Nico Schlömer reporter

    MWE:

    from dolfin import compile_cpp_code
    
    cppcode = """
    #include <dolfin/function/Expression.h>
    #include <pybind11/pybind11.h>
    namespace py = pybind11;
    
    class SupgStab : public dolfin::Expression {
    public:
    SupgStab(): dolfin::Expression()
    {}
    };
    
    PYBIND11_MODULE(SIGNATURE, m)
    {
        py::class_<SupgStab, std::shared_ptr<SupgStab>, dolfin::Expression>
        (m, "SupgStab")
        .def(py::init<>());
    }
    """
    
    compiled_module = compile_cpp_code(cppcode)
    

  3. Nico Schlömer reporter

    Okay, even the linked demo fails with this error on my machine

    ImportError: generic_type: type "Conductivity" referenced unknown base type "dolfin::Expression"
    

    Apparently, something is wrong with my installation. Hm.

  4. Michal Habera

    Sorry for delayed response. It seems the pybind cpp code cannot find dolfin. You can pass include_dirs and libraries as kwargs to compile_cpp_code. Try to manually include dolfin cpp library.

  5. Nico Schlömer reporter

    Huh? That’s funny. Everything is in the default directories, installed from Debian. And indeed,

    compiled_module = compile_cpp_code(cppcode, include_dirs=["/usr/include/"]) 
    

    doesn’t help. I would have expected a different error on missing includes/linker errors, too.

  6. Ellery Ames

    I am having a similar issue, which arose here. I boot up a Docker container running fenics 2109.1 and try to create a compiled expression with

    from dolfin import *
    
    cpp_code = """
    #include <pybind11/pybind11.h>
    #include <dolfin.h>
    namespace py = pybind11;
    
    #include <dolfin/function/Expression.h>
    
    class Profile : public dolfin::Expression
    {
    public:
    
      Profile() : dolfin::Expression(){}
    
    };
    
    PYBIND11_MODULE(SIGNATURE, m)
    {
      py::class_<Profile, std::shared_ptr<Profile>, dolfin::Expression>
        (m, "Profile")
        .def(py::init<>());
    }
    """
    # Compile expression
    expr = CompiledExpression(compile_cpp_code(cpp_code, include_dirs=["/usr/local/include/"]).Profile(), degree=1)
    

    This fails with the error:

    Traceback (most recent call last):

    File "expr_test.py", line 27, in <module>

    expr = CompiledExpression(compile_cpp_code(cpp_code, include_dirs=["/usr/local/include/"]).Profile(), degree=1)

    File "/usr/local/lib/python3.6/dist-packages/dolfin/jit/pybind11jit.py", line 96, in compile_cpp_code

    generate=jit_generate)

    File "/usr/local/lib/python3.6/dist-packages/dolfin/jit/jit.py", line 47, in mpi_jit

    return local_jit(*args, **kwargs)

    File "/usr/local/lib/python3.6/dist-packages/dolfin/jit/jit.py", line 103, in dijitso_jit

    return dijitso.jit(*args, **kwargs)

    File "/usr/local/lib/python3.6/dist-packages/dijitso/jit.py", line 212, in jit

    lib = load_library(signature, cache_params)

    File "/usr/local/lib/python3.6/dist-packages/dijitso/cache.py", line 363, in load_library

    lib = __import__(signature)

    ImportError: generic_type: type "Profile" referenced unknown base type "dolfin::Expression"

    Any progress in understanding this issue?

  7. Jørgen Dokken

    There has been talk about having a new/final release of dolfin (as all development has moved to dolfinx). With this release I think it would be natural to update the debian packages. Usually @Drew Parsons is kind enough to build these packages for us. @Marie Elisabeth Rognes @Cécile Daversin-Catty , are we closing in on a release? UFL has already been tagged with: 2021.1.0

  8. Stefan Lindström

    I have it too on 2019.2, and waiting for a new Ubuntu PPA. Is there any progress @Marie Elisabeth Rognes ?

  9. Log in to comment