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.