On Tuesday 25 August 2009 11:56:15 Garth N. Wells wrote: > 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 ;).
True, but the distinction in c++ is not very self documented. > 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. Done Johan > 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
