XDMFFile.write second argument type

Issue #1002 new
Marco Morandini created an issue

This test

from dolfin import *
mesh = UnitCubeMesh(1,1,1)
element_eps_p_eq_project = FiniteElement("CG", mesh.ufl_cell(), degree=1)
V_eps_p_eq_project = FunctionSpace(mesh, element_eps_p_eq_project)
eps_p_eq_project = Function(V_eps_p_eq_project, name="eps_p_eq")
filex = XDMFFile('pippo.xdmf')
filex.write(eps_p_eq_project, 0)
#filex.write(eps_p_eq_project, 0.) # this works
#filex.write(eps_p_eq_project, t=0) # this works
#filex.write(u=eps_p_eq_project, t=0) # this works

fails for me with

Traceback (most recent call last):
  File "pippo3.py", line 7, in <module>
    filex.write(eps_p_eq_project, 0)
ValueError: vector::reserve

Comments (4)

  1. Michal Habera

    Thanks for reporting this. I have spent several hours trying to debug... The issue is related to pybind11 bindings.

    Binding of XDMFFile::write in https://bitbucket.org/fenics-project/dolfin/src/925edd1586195242d27aa1b438464f2ed83372be/python/src/io.cpp?at=master&fileviewer=file-view-default#io.cpp-374 is for time variable as double. The first call run according to pybind11 overload resolution order (section 7.8 in https://media.readthedocs.org/pdf/pybind11/latest/pybind11.pdf ) tries the binding without int -> double conversion, so the function binding is not matched.

    For some unknown reason, the dolfin.function.Function matches std::vector<dolfin::Point> in "write" method binding for points (https://bitbucket.org/fenics-project/dolfin/src/925edd1586195242d27aa1b438464f2ed83372be/python/src/io.cpp?at=master&fileviewer=file-view-default#io.cpp-387) that follows in the first run. This then fails with vector::reserve strange error.

    I have a workaround where "write" method matches general py::object and then does the logic to distinguish Point from Function, but the problem is still strange dolfin.function.Function matching std::vector<dolfin::Point>. Any ideas why this happens, @chris_richardson @garth-wells ?

  2. Michal Habera

    After several days of fighting I have finally found the snag.

    Any Python object that has __getitem__ magic method is matched as std::vector<> for pybind11 bindings python -> cpp conversion. Since dolfin.function.function.Function (terrible naming, btw...) has __getitem__ (this is from UFL's exproperators.py) the problem is born.

    @chris_richardson I will prepare PR also for the other related issue.

    Consider the following simple code

    import dolfin as d
    
    base_code = '''
    #include <pybind11/pybind11.h>
    #include <pybind11/stl.h>
    namespace py = pybind11;
    
    #include <vector>
    #include <stdio.h>
    #include <dolfin/function/Function.h>
    #include <dolfin/geometry/Point.h>
    
    void write(std::vector<dolfin::Point>& points)
    {
      std::cout << "Write called for dolfin::Point" << std::endl;
    }
    
    void write(dolfin::Function& fction)
    {
      std::cout << "Write called for dolfin::Function" << std::endl;
    }
    
    
    PYBIND11_MODULE(SIGNATURE, m)
    {
      m.def("write", (void (*)(std::vector<dolfin::Point>&)) &write);
      m.def("write", (void (*)(dolfin::Function&)) &write);
      m.def("write", [](py::object obj){
        std::cout << "Py obj" << std::endl;
      });
    }
    '''
    
    compiled = d.compile_cpp_code(base_code)
    
    mesh = d.UnitSquareMesh(2, 2)
    V = d.FunctionSpace(mesh, "CG", 1)
    
    u = d.Function(V)
    
    points = [d.Point(1), d.Point(1)]
    
    class BadObject:
        def __getitem__(self, pos):
            return pos
    
    bo = BadObject()
    
    # Fails when converting to std::vector
    # but should be caught by the last binding
    #compiled.write(u)
    
    # Fails when converting to std::vector
    # but should be caught by the last binding
    #compiled.write(bo)
    
    # OK
    compiled.write(points)
    
    # OK
    compiled.write(u.cpp_object())
    
  3. Log in to comment