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
