← Back to team overview

dolfin team mailing list archive

Re: Image to Function data structure conversion

 

2009/2/14 A Navaei <axnavaei@xxxxxxxxxxxxxx>:
> 2009/2/14 Garth N. Wells <gnw20@xxxxxxxxx>:
>>
>>
>> A Navaei wrote:
>>>
>>> 2009/2/14 Johan Hake <hake@xxxxxxxxx>:
>>>>
>>>> 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.
>>>
>>> By 'user-defined' Function, do you mean those sub-classes which simply
>>> override eval() in order to implement user-defined values? In this
>>> case, perhaps there should be a difference between a 'user-defined'
>>> Function class and a class which requires extending Function more
>>> extensively. The latter should have access to the private member
>>> variables.
>>>
>>
>> I can't see why this is needed. Function only has two pieces of private
>> member data, both of which can be accessed through member functions.
>
> The accessors are read-only:
>
> const FunctionSpace& function_space() const;
> boost::shared_ptr<const FunctionSpace> function_space_ptr() const;
>
> For instance, in the ImageFunction case, FunctionSpace instance needs
> to be initialised using the image size and image data.

Well, I guess that's why you have so many friend classes in dolfin -
that's one solution.


-Ali

>
>
> -Ali
>
>>
>> Garth
>>
>>>
>>> -Ali
>>>
>>>> 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
>>>>
>>>>
>>
>> --
>> Dr Garth N Wells
>> Department of Engineering
>> University of Cambridge
>> Trumpington Street
>> Cambridge CB2 1PZ
>> United Kingdom
>>
>> tel.   +44 1223 3 32743
>> fax.   +44 1223 3 32662
>> e-mail gnw20@xxxxxxxxx
>>
>>
>


Follow ups

References