← Back to team overview

dolfin team mailing list archive

Re: Image to Function data structure conversion

 

2009/2/14 Johan Hake <hake@xxxxxxxxx>:
> [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>)

Why using the derived macro? This is the function of interested for wrapping:

 class itkImageToDolfinFunctionID2 {
   public:
     static std::tr1::shared_ptr< dolfin::Function >
Convert(itkImageD2 * imageData);
 };

(agian, ignore the namings due to template instantiation). So, Convert returns

std::tr1::shared_ptr< dolfin::Function >

type, and _not _

std::tr1::shared_ptr< itk::DolfinImageFunction<ImageType> >

which means we should simply apply the macro to dolfin::Function:

SWIG_SHARED_PTR(Function, dolfin::Function)

Is that right? Any, it doesn't wrap!

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

In that case, the problem may not be from my code. Does it work in the
development version? If so, what could solve the problem?

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

That's correct.

>
>> > 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().

Yes, that's why I'm working on wrapping shared_ptr.


-Ali

>
> Johan
>


Follow ups

References