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 ;) 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
