Johan Hake wrote:
> On Monday 24 August 2009 23:57:26 Garth N. Wells wrote:
>> 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.
> 
> I have now added a first iteration on the python interface of subfunctions, 
> see commit message. I think it is quite nice. More explicit than the c++ 
> interface ;)
> 

To the untrained eye ;).

Could you add examples of its use to some of the existing Python demos? 
Good examples would be shallow copies for plotting and a deep copy to 
compute norms of the vector.

Garth

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