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
