← Back to team overview

dolfin team mailing list archive

Re: Image to Function data structure conversion

 

On Saturday 14 February 2009 17:28:18 Garth N. Wells wrote:
> Johan Hake wrote:
> > On Saturday 14 February 2009 13:48:05 A Navaei wrote:
> >> It seems that the error can be re-produced even without sub-classing
> >> and using existing dolfin classes in pure c++. Based on the itk-dolfin
> >> interface code, the below minimal code should generate the error (note
> >> that I use the binary distribution which uses std::tr1, replacing it
> >> with boost shared pointer should not have any effect).
> >
> > Not in c++ but swig only support std::tr1::shared_ptr from version
> > 1.3.37. But if you intend to use shared_ptr only internally there whould
> > not be any problems.
> >
> >> After wrapping in python:
> >>
> >> (1) Calling FunctionTest.CreateFunction(), which returns by value,
> >> results this error:
> >>
> >> RuntimeError: *** Error: Unable to assign to function, missing
> >> coefficients (user-defined function).
> >
> > You cannot assign another user-defined function to another Function. It
> > must be a discrete function, which has an initialized _vector. This is
> > probably a feature that other developers should answer for.
> >
> > However this means that you cannot copy a userdefined function, with the
> > side effect of not beeing able to return a user-defined Function by
> > value.
> >
> >> Since dolfin::Function does come with the required copy ctors, the
> >> problem cannot be stemmed from this.
> >
> > This use the assignment operator which requires the Function to be a
> > discrete and not a user-defined Function.
> >
> > I consider this to be a bug in the library. Any other comments from the
> > C++ DOLFIN developers (I am mostly dealing with the python interface)?
>
> In a nutshell, are you suggesting that the Function copy constructor
> should work for user-defined Functions?

Yes. Why shouldn't it? 

I can see why the assigment operator should not work.

Johan


> Garth
>
> >> (2) Calling FunctionTest.CreateFunctionPtr(), which returns the shared
> >> pointer, does not generate any errors.
> >
> > This should be expected, as the copy constructors is not called. When you
> > get all this to work, eventually ;), I would suggest using shared_ptr
> > types for the return argument, as shared_ptrs are much nicer to deal with
> > in both c++ and python. But then you probably need the development
> > version of DOLFIN. We do consider a release soon, which you can switch to
> > when this is out.
> >
> > The support for shared_ptr in PyDOLFIN is lately added, but has more or
> > less stabilized now, I think.
> >
> >> However, there are problems
> >> with handling the shared pointer in python. I used this in my swig
> >> interface file (or in an implicit way you can include dolfin.i
> >> defining the right flags):
> >>
> >> #define SWIG_SHARED_PTR_NAMESPACE std // comment out if it's boost
> >> #define SWIG_SHARED_PTR_SUBNAMESPACE tr1 // comment out if it's boost
> >> %include "boost_shared_ptr.i"
> >> # if defined(SWIG_SHARED_PTR_QNAMESPACE)
> >> SWIG_SHARED_PTR(Function, dolfin::Function)
> >> #endif
> >
> > Which version of swig do you have, refering to the comment above. You
> > need swig version >= 1.3.35 to be able to use shared_ptr in the first
> > place and >= 1.3.37 to be able to use std::str1::shared_ptr.
> >
> >> Having this, in python, FunctionTest.CreateFunctionPtr() returns a
> >> proxy to the shared pointer object which is not useful. Are there any
> >> steps missed in the wrapping process?
> >
> > Strictly speaking it does _not_ return a proxy but rather a raw pointer
> > to the object. The proxy is the python wrapper class that swig creates
> > for us when it have the correct type knowledge, which in this case, swig
> > does not have.
> >
> >> c++ test code:
> >> -----------------------------
> >> class FunctionTest
> >> {
> >> public:
> >> 	typedef std::tr1::shared_ptr<const dolfin::Mesh> MeshConstPointerType;
> >> 	typedef std::tr1::shared_ptr<const dolfin::FiniteElement>
> >> ElementConstPointerType;
> >> 	typedef std::tr1::shared_ptr<const dolfin::DofMap>
> >> DofMapConstPointerType; typedef std::tr1::shared_ptr<const
> >> dolfin::FunctionSpace>
> >> FSConstPointerType; typedef std::tr1::shared_ptr<dolfin::Function>
> >> FPointerType;
> >>
> >> 	static dolfin::Function CreateFunction()
> >> 	{
> >> 		dolfin::Mesh mesh = dolfin::UnitSquare(100, 100);
> >> 		std::string elemSig("FiniteElement('Lagrange', 'triangle', 1)");
> >> 		std::string dofSig("FFC dof map for FiniteElement('Lagrange',
> >> 'triangle', 1)");
> >>
> >> 		FSConstPointerType fs(new dolfin::FunctionSpace(
> >> 		typename IFSType::MeshConstPointerType(&mesh,
> >> dolfin::NoDeleter<const dolfin::Mesh>()),
> >> 		typename IFSType::ElementConstPointerType(new
> >> dolfin::FiniteElement(elemSig)), typename
> >> IFSType::DofMapConstPointerType(new dolfin::DofMap(dofSig, mesh))) );
> >>
> >> 		dolfin::Function func(fs);
> >> 		return func;
> >> 	};
> >>
> >> 	static FPointerType CreateFunctionPtr()
> >> 	{
> >> 		dolfin::Mesh mesh = dolfin::UnitSquare(100, 100);
> >> 		std::string elemSig("FiniteElement('Lagrange', 'triangle', 1)");
> >> 		std::string dofSig("FFC dof map for FiniteElement('Lagrange',
> >> 'triangle', 1)");
> >>
> >> 		FSConstPointerType fs(new dolfin::FunctionSpace(
> >> 		typename IFSType::MeshConstPointerType(&mesh,
> >> dolfin::NoDeleter<const dolfin::Mesh>()),
> >> 		typename IFSType::ElementConstPointerType(new
> >> dolfin::FiniteElement(elemSig)), typename
> >> IFSType::DofMapConstPointerType(new dolfin::DofMap(dofSig, mesh))) );
> >>
> >> 		FPointerType funcp = FPointerType(new dolfin::Function(fs));
> >> 		return funcp;
> >> 	};
> >> };
> >> ----------------------------
> >>
> >>> Yes, I can call wrapped DolfinImageFunction in python with no problem,
> >>> but when using it in pure c++ (itk::ImageToDolfinFunction) an then
> >>> calling ImageToDolfinFunction after wrapped in python generated the
> >>> error:
> >>>
> >>> RuntimeError: *** Error: Unable to assign to function, missing
> >>> coefficients (user-defined function).
> >
> > I think we sorted out this problem above: do not return by value.
> >
> >>> why v._vector is not null in the first case? I also tried the shared
> >>> pointer ctors and ended up with the same result. Moreover, I tried
> >>> sub-classing FunctionSpace (see
> >>> http://code.google.com/p/wrapitk/source/browse/trunk/ExternalProjects/I
> >>>tk Dolfin/src/itkDolfinImageFunctionSpace.h), with and without shared
> >>> pointer ctors, again the same error.
> >>>
> >>>> First I assume that you properly instantiate the templates somewhere
> >>>> else in your build script, as itkDolfin.swg does not define any such
> >>>> templates.
> >>>
> >>> That's correct, wrapitk instantiates the templates automatically.
> >
> > Ok. Is this done in some of the SMake macros? I am really not familiar to
> > CMake
> >
> >>>> Second you should probably return a pointer to the created function in
> >>>> DolfinImageFunction(), and set
> >>>>
> >>>>  %newobject
> >>>> itk::ImageToDolfinFunction<YourImageTypes>.DolfinImageFunction;
> >>>>
> >>>> or define a copy constructor to your DolfinImageFunction, as you are
> >>>> returning by value now.
> >>>
> >>> I've tried a simple copy ctor like this:
> >>>
> >>>        DolfinImageFunction(const DolfinImageFunction &v)
> >>>        {
> >>>                 *this = v;
> >>>        }
> >>>
> >>> which does get called, but didn't help.
> >
> > Again, bug in copy constructor. You should be able to return a raw
> > pointer to the function, but make sure you use the %newobject directive
> > mentioned above, to till swig that it should take ownership to the
> > returned object.
> >
> >>> Just to mention that one problem with c++ dolfin classes is that their
> >>> member variables are mostly private, causing restrictions on the
> >>> sub-classes.
> >
> > This should others answer.
> >
> >>> Is there a specific reason for having private variables
> >>> instead of protected? For instance, DolfinImageFunction ctors are not
> >>> able to initialise _function_space or _vector.
> >
> > This should not be any problems in the ordinary constructor as you can
> > just pass the function_space to the super constructor, and a properly
> > working copy constructor should also fix this for any derived copy
> > constructors.
> >
> > The _vector is created by calling init(). But you do not want to do this
> > as the Function will then change status from a user-defined to a discrete
> > function, making it impossible to reach the eval function.
> >
> > Again hope this helps.
> >
> > Johan
> > _______________________________________________
> > DOLFIN-dev mailing list
> > DOLFIN-dev@xxxxxxxxxx
> > http://www.fenics.org/mailman/listinfo/dolfin-dev




Follow ups

References