Johan Hake wrote:
> On Monday 24 August 2009 13:41:24 Garth N. Wells wrote:
>> Johan Hake wrote:
>>> On Monday 24 August 2009 13:04:45 Garth N. Wells wrote:
>>>> Johan Hake wrote:
>>>>> On Monday 24 August 2009 10:30:52 Garth N. Wells wrote:
>>>>>> Johan Hake wrote:
>>>>>>> On Monday 24 August 2009 10:11:49 Garth N. Wells wrote:
>>>>>>>>>>>>>> dolfin/swig/dolfin_headers.i description: Work on new sub
>>>>>>>>>>>>>> Function logic.
>>>>>>>>>>>>> I am not sure we can completely wrap the new logic to PyDOLFIN.
>>>>>>>>>>>>>
>>>>>>>>>>>>> To be able to have the double inheritance of cpp.Function and
>>>>>>>>>>>>> ufl.Function in PyDOLFIN, new Functions have to be constructed
>>>>>>>>>>>>> in the Python interface (function.py).
>>>>>>>>>>>>>
>>>>>>>>>>>>> The operator[] is mapped to a hidden function _sub. The created
>>>>>>>>>>>>> Function that is returned from this is passed to the copy
>>>>>>>>>>>>> constructor in the Python version of sub (creating a new
>>>>>>>>>>>>> Function object). This is basically just how we did it before
>>>>>>>>>>>>> the new design, because previously operator[] returned a
>>>>>>>>>>>>> SubFunctionData, which was passed to a Function constructor.
>>>>>>>>>>>>> The transition to the new logic works in PyDOLFIN because the
>>>>>>>>>>>>> Function copy constructor is used instead of the removed
>>>>>>>>>>>>> SubFunctionData constructor.
>>>>>>>>>>>>>
>>>>>>>>>>>>> This means that the handy operator[], which returns a Function
>>>>>>>>>>>>> with a shared vector, cannot fully be used from PyDOLFIN. Would
>>>>>>>>>>>>> it be possible to add a shallow copy function in some way.
>>>>>>>>>>>>> Would this work with the present SubFunction design?
>>>>>>>>>>>> Would something like
>>>>>>>>>>>>
>>>>>>>>>>>>      Function::sub_function(Function& sub_function, uint i)
>>>>>>>>>>> Yes I think so. If we could make this a constructor (shallow copy
>>>>>>>>>>> constructor) I would be most happy!
>>>>>>>>>> So a constructor
>>>>>>>>>>
>>>>>>>>>>      Function::Function(uint i)
>>>>>>>>>>
>>>>>>>>>> would be better?
>>>>>>>>> Yes, but then we could not fetch the shared Vector?
>>>>>>>>>
>>>>>>>>>> I'm reluctant to add a constructor since it breaks the
>>>>>>>>>> paradigm that a Function constructor gives a deep copy.
>>>>>>>>> Ok.
>>>>>>>>>
>>>>>>>>>> Could you create
>>>>>>>>>> an empty Function internally on the PyDOLFIN side and then pass it
>>>>>>>>>> to
>>>>>>>>>>
>>>>>>>>>>      Function::sub_function(Function& sub_function, uint i)
>>>>>>>>>>
>>>>>>>>>> to attach the shared data to create the sub-Function
>>>>>>>>>> 'sub_function'?
>>>>>>>>> Yes, this should be fine. I guess such a function will then just
>>>>>>>>> destroy any present vector and exchange it with the one shared with
>>>>>>>>> the FullFunction?
>>>>>>>> Yes. We can throw an error if there is any data already attached to
>>>>>>>> the Function.
>>>>>>> When we create a new Function in PyDOLFIN using the DiscreteFunction,
>>>>>>> we do create a vector, so this will prevent us using this class. We
>>>>>>> use the DiscreteFunction to circumvent some director (SWIG stuff to
>>>>>>> be able to inherit a cpp.Function in Python) overhead wrt to call the
>>>>>>> eval function during assemble. I guess we will not assemble the
>>>>>>> function returned from operator[] so then we can create the Function
>>>>>>> using cpp.Function instead.
>>>>>> What if we add a constructor to DiscreteFunction to take care of
>>>>>> sub-functions? Would that work?
>>>>> Yes, this should work. Then we could add a constructor taking a
>>>>> Function and a number as you suggested above.
>>>> This is trickier than I anticipated. The problem with
>>>>
>>>>      Function::Function(const Function& v, uint i)
>>>>
>>>> is that v cannot be const since v keeps track of its sub-functions and
>>>> create and stores them on-demand. I could just create a sub-function and
>>>> not cache it, but then it would be re-created every time. The problem
>>>> with this is that creating a sub-dof map is not trivial if the dof map
>>>> has been renumbered.
>>>>
>>>> I'm also a bit uncomfortable with shallow copies because bad things can
>>>> happen when something goes out of scope.
>>> If we make _vector protected, we should be able to handle everything in
>>> something like:
>>>
>>>    DiscreteFunction::DiscreteFunction(Function& v, uint i)
>>>
>>>
>>> Here we just let the new DiscreteFunction share both _vector and
>>> _function_space. Maybe this was what you did not like?
>>>
>>>> Could this be taken care of on the Python side by introducing something
>>>> like a SubFunction? Function::operator[] returns a reference, and
>>>> PyDOLFIN could take are of things through the assignment operators of
>>>> the Python Function and SubFunction classes?
>>> This is exactly what happens now (if I understand your suggestion
>>> correctly :) ) and this is probably why the new SubFunction design just
>>> works in PyDOLFIN now. The thing is that we make a deep copy. The sharing
>>> of data we get from operator[] is lost. This might not be a big problem.
>> It would help me understand what to do on the C++ side if I knew what
>> the Python would/should look like. In C++ we can do
>>
>>     // We know that u0 will share the data because of the reference
>>     Function& u0_ref = u[0];
>>
>>     // We know that u0 will be a copy because there is no reference
>>     Function u0_copy = u[0];
>>
>> What's the plan to distinguish the two cases in Python?
> 
> This discussion ;)
> 
> The above would map to Python as:
> 
>   u0_ref = u._sub(0)
>   u0_copy = cpp.Function(u._sub(0))
> 
> as the copy constructor cannot be implicitly called. The first one will be a 
> shared version of the subfunction and the second one will be a deepcopy.
> 
> However the returned function is a pure cpp.Function that do not inherits 
> ufl.Function. To accomplish this we need to dynamically construct such class, 
> and initialize it. The initialization of the cpp.Function has been done using 
> the DiscreteFunction constructor that takes a SubFunctionData and now a 
> Function.
> 
> I am not sure how/if we can do something similar for the reference version. 
> The suggestion above, using a separate constructor could work. It will then 
> be 
> a different instance of the actual Function, than the one stored in the 
> original mixed function, but it will have the same shared vector and function 
> space.
> 

I've added a constructor to DiscreteFunction, so go ahead and see what 
you can do on the Python side. I'm not entirely comfortable with the C++ 
interface, but we may be able to refine it once how things will look on 
the Python side become clearer.

Garth

> Johan
> 
> 
>> Garth
>>
>>> Johan
>>>
>>>> I don't really understand
>>>> how things work on the Python side for Functions, so I'm clutching at
>>>> straws.
>>>>
>>>>
>>>>
>>>> Garth
>>>>
>>>>>>>> It would be neat if we could somehow make member functions 'private'
>>>>>>>> to PyDOLFIN.
>>>>>>> We can, just rename them in dolfin_function_pre.i
>>>>>>>
>>>>>>>   %rename (_foo) dolfin::Function::foo;
>>>>>>>
>>>>>>> We do this for some of the functions (_sub: operator[] and _in for
>>>>>>> in) already.
>>>>>> I meant C++ member functions which are intended for use through
>>>>>> PyDOLFIN only.
>>>>> I see :)
>>>>>
>>>>> We could hide some python specific classes, like the DiscreteFunction
>>>>> class, by not including it in dolfin_function.h, and then manually add
>>>>> it to dolfin_headers.i.
>>>>>
>>>>> With this we hide it from
>>>>>
>>>>>   #include <dolfin.h>
>>>>>
>>>>> We then have to manually add them as #includes in dolfin.i and to
>>>>> dolfin_headers.i. We can automate this by adding a
>>>>> dolfin_pydolfin_headers.i, which lists the #includes. This file is then
>>>>> parsed by generate.py.
>>>>>
>>>>> If this sounds reasonable I can look into it.
>>>>>
>>>>> Johan
>>>>>
>>>>>> Garth


_______________________________________________
DOLFIN-dev mailing list
[email protected]
http://www.fenics.org/mailman/listinfo/dolfin-dev

Reply via email to