← Back to team overview

dolfin team mailing list archive

Re: Image to Function data structure conversion

 

[snip]

> >> 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

This has to be done in the dolfin.i file, and not in your interface file 
that %import dolfin.i, otherwise the macros won't kick in for the right 
types. 

Not sure what you mean with in an implicit way.

Also, if you %import the development version of dolfin.i you should be able to 
declare your derived class as:

%include <boost_shared_ptr.i> 
SWIG_SHARED_PTR_DERIVED(DolfinImageFunctionImageType,dolfin::Function,itk::DolfinImageFunction<ImageType>)

or something.

> > 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.
>
> I'm using swig 1.3.38, I noticed that the patch you submitted to swig
> was used in 1.3.37; but the above does not work for me. I tried using
> the swig interface code, before/after the class declaration and still
> shared_ptr does not get wrapped in the desired way. Even following
> this http://article.gmane.org/gmane.comp.programming.swig/12803 didn't
> help.

In the development version of PyDOLFIN we run the shared_ptr macros before we 
include the class declarations.

> I noticed that, at least for the latest binary release, shared
> pointers are not wrapped properly in python. Try this:
>
> mesh = UnitSquare(100, 100)
> V = FunctionSpace(mesh, "CG", 1)
> f = Function(V)
> f.function_space_ptr()
>
> Out[17]: <Swig Object of type 'std::tr1::shared_ptr<
> dolfin::FunctionSpace const > *' at 0x9728b80>
>
> I guess the above returned object is useless? That's what I get for
> returned Function in my code.

Yes, shared_ptr in python is not woring properly in the latest release 
version.

> >> 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/
> >> >Itk 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
>
> No, it's done in wrapitk using cableswig (which itself uses gccxml),
> python and cmake. The end user simply specifies the desired wrapping
> types. In this thread, let's assume that automatic template
> instantiation is properly done.

Fine ;)

> >> >> 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.
>
> The template instantiator defines a class like:
>
> itkImageToDolfinFunctionID2
>
> which stands for an image of dimention 2 and type double. Given that
> the shared pointer object is created in Convert() method, shouldn't
> the memory leak problem be solved by something like:
>
> %newobject itkImageToDolfinFunctionID2::Convert;
>
> It doesn't work for me. At least this should work:
>
> %newobject ::Convert;
>
> which should cover every function called 'Convert' in any classes, but
> it dosn't work either. I also tried this before/after class
> declaration. Where is the similar code in dolfin?

Not sure of what is not working for you. Do you return a raw pointer or a 
shared_ptr? The %newobject directive should not do anything with the type 
recognition of swig, it just set the 'thisown' attribute of the returned 
object to True, so python will destroy the object when it goes out of scope.

> >> > 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.
>
> In the ImageFunction:Function case, the ctor takes an argument of
> image type, while the parent class arguments objects (Mesh,
> FiniteElement and DofMap) are required to be initialised based on the
> image object. With private member variables, if not impossible, it is
> difficult to do so. My work-around was sub-classing from FunctionSpace
> and assigning it to the Function object later.

I see. It is therefore you need the ImageToDolfinFunction class with the 
Convert functions?

> > 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.
>
> init() is not called in any of the copy ctors of Function, this could
> be a source of the bug.

Again, you do not want to do this as you then won't be able to use your 
overloaded eval function, as the Function will then be treated to be 
discrete, i.e., using the coefficients in _vector together with the basis 
function in the FunctionSpace to interpolate any eval(). 

Johan


Follow ups

References