dolfin team mailing list archive
-
dolfin team
-
Mailing list archive
-
Message #10256
Re: new Function design
On Tuesday 21 October 2008 23:23:27 Martin Sandve Alnæs wrote:
> 2008/10/21 Johan Hake <hake@xxxxxxxxx>:
> > On Tuesday 21 October 2008 22:34:04 Martin Sandve Alnæs wrote:
> >> 2008/10/21 Johan Hake <hake@xxxxxxxxx>:
> >> > On Tuesday 21 October 2008 21:37:13 Martin Sandve Alnæs wrote:
> >> >> 2008/10/21 Anders Logg <logg@xxxxxxxxx>:
> >> >> > On Tue, Oct 21, 2008 at 06:01:53PM +0100, Garth N. Wells wrote:
> >> >> >> Anders Logg wrote:
> >> >> >> > On Tue, Oct 21, 2008 at 04:45:01PM +0100, Garth N. Wells wrote:
> >> >> >> >> I have a few questions and thoughts regarding the new Function
> >> >> >> >> design
> >> >> >> >>
> >> >> >> >> * It's not clear to me what the intention is with user-defined
> >> >> >> >> functions. The functions Function::interpolate(...) never call
> >> >> >> >> eval(..), so they can't pick up user-defined values. Should
> >> >> >> >> Function::interpolate test for the presence of a GenericVector
> >> >> >> >> to decide whether or not the Function is discrete or
> >> >> >> >> user-defined?
> >> >> >> >
> >> >> >> > Yes, sorry. I've missed this. I'll fix it.
> >> >> >> >
> >> >> >> >> * It would be useful to declare user-defined functions without
> >> >> >> >> associating a FunctionSpace. If we want to interpolate the
> >> >> >> >> function, a FunctionSpace must then be provided. Anyone see any
> >> >> >> >> problems with this?
> >> >> >> >
> >> >> >> > The reasoning here is that all Functions must always be
> >> >> >> > associated with a FunctionSpace so that they may be correctly
> >> >> >> > interpreted in forms and correctly plotted. When a Function is
> >> >> >> > created in PyDOLFIN, it must always be associated with a certain
> >> >> >> > FiniteElement (and in a while FunctionSpace). It would simplify
> >> >> >> > the handling of Functions if they are always associated with a
> >> >> >> > FunctionSpace.
> >> >> >>
> >> >> >> I agree that is makes life simple if every function has a space,
> >> >> >> but it is a bit clunky for declaring user-defined functions. The
> >> >> >> forms must be declared first to extract the finite element to
> >> >> >> create the function space. Could look nasty when a lot of
> >> >> >> functions are involved.
> >> >> >>
> >> >> >> We have a function Function::interpolate which takes a function
> >> >> >> space V as an argument and it interpolates the function u in V.
> >> >> >> What if we permit undefined function spaces (which perhaps only
> >> >> >> have a domain)? We would then interpolate the user defined
> >> >> >> function u in the provided space V.
> >> >> >>
> >> >> >> Garth
> >> >> >
> >> >> > Are user-defined functions ever used without being related to a
> >> >> > particular element/function space?
> >> >> >
> >> >> > It don't think it will be very clumsy. The clumsy thing will be to
> >> >> > (in C++) get from something compiled by a form compiler to a
> >> >> > FunctionSpace.
> >> >> >
> >> >> > If we can make that operation smooth, then creating (user-defined)
> >> >> > functions will be very simple and convenient. One just needs to
> >> >> > supply the variable V holding the function space.
> >> >> >
> >> >> > The current way of extracting function space data from the form is
> >> >> > not very nice (in C++). What would be the optimal way to initialize
> >> >> > a FunctionSpace in C++? We could think of extending the code
> >> >> > generation to generate code that makes this convenient.
> >> >> >
> >> >> > --
> >> >> > Anders
> >> >>
> >> >> The current way of extracting function space data from the form is
> >> >> not very nice in Python either, since it doesn't work with compiled
> >> >> functions. (Never mind that the current code is FFC-specific, this
> >> >> will be the same with UFL).
> >> >>
> >> >> Using Python functors can easily make the assembly slower than
> >> >> solving the linear system, so it's not really interesting to do in
> >> >> real applications...
> >> >>
> >> >> To make a function object that is both of a C++ subclass of
> >> >> dolfin::Function and of the Python class ufl.Function, we can't use
> >> >> the fixed multiple inheritance
> >> >> solution in the current PyDOLFIN.
> >> >>
> >> >> We would have to define a new class dynamically in python, inheriting
> >> >> from both ufl.Function and the freshly compiled C++ Function
> >> >> subclass. After all this work cleaning up the Function class
> >> >> hierarchy, is that really something you want?
> >> >>
> >> >> I'm not sure if that is even possible to do while maintaining
> >> >> efficiency, with cross-language inheritance and SWIG directors and
> >> >> all that.
> >> >>
> >> >> If anyone has another solution, I'm very interested in hearing it!
> >> >> Otherwise, I'm all for keeping the ufl.Function objects used in form
> >> >> definition separated from dolfin.Function objects used in assembly.
> >> >
> >> > I agree with Martin that we need to have a solution for PyDOLFIN users
> >> > that does not depend on using python functors, as it will take forever
> >> > for a complex form together with a moderate mesh to just assemble the
> >> > form.
> >> >
> >> > Is it possible to let compile_functions compile a cpp function, with a
> >> > FunctionSpace and all, instead of a mesh as it is today. Then after
> >> > doing
> >>
> >> If you have a dolfin::FunctionSpace object already, there's no reason
> >> compile_functions can't take this instead of dolfin::Mesh.
> >> That's exactly the same and no problem at all.
> >>
> >> > this compile_function extract the element, and instantiate a
> >> > UFL/FFC/PyFunction-function, and "attach" the compiled version to it.
> >> > This
> >>
> >> What I state above is that this "attachment" must be done with
> >> dynamic creation of a new class with multiple inheritance.
> >> And I am unsure whether this will work out properly with SWIG directors
> >> etc. I believe it _may_ work, but I don't dare to keep my hopes up :-)
> >
> > Ok, I get it. For a moment I thought we could get away by defineing our
> > own PyDOLFIN::Function class that could inherit from UFL/FFC, and then
> > have a cpp_Function, but I realise this will not work.
> >
> >> See the attached python file for a prototype of dynamic class creation
> >> with multiple inheritance using pure python classes.
> >> (I think this is called "aspect oriented programming" by some people)
> >>
> >> > can be used to define forms, but more important it can be handed to
> >> > the python assembly that check if the function has a compiled version
> >> > attached to it and send this to the cpp_assembler?
> >>
> >> If the "attachment" is anything other than inheritance, it will have
> >> to be checked with manually written python code _everywhere_
> >> a dolfin::Function is expected... We can't have one kind of functions
> >> for assembly and one for other stuff.
> >
> > Ok, I guess we have three different cases:
> >
> > 1) PyFunctions inherting from both UFL/FFC and cpp_Function as today,
> > taking a functionsspace in its constructor. This will work with both
> > user defined and discrete functions, more or less as we have it
> > today.
> >
> > 2) The special functions, MeshSize, etc, can also be defined in the same
> > way as now, right?
> >
> > 3) Using compile_functions, that creates a multi inheritance object that
> > can be sent to any function expecting a cpp_Function, without
> > manually extending the python interface.
>
> I'm with you up to this point.
>
> > Could the last be done by letting compile_function create a muliti
> > inheritance Function. Instantiate the cpp_one with the function space and
> > by that creating a dummy cpp_function. Then "attach" the compiled
> > function to a protected attribute and define eval, by overloading it in
> > python. This will then just call the attached and compiled cpp_functions
> > eval.
>
> What you describe here sounds like the envelope-letter design
> that was just _removed_ from dolfin.
Yes, but only for compiled functions in Python. No other places.
> What I'm suggesting is that
> compile_functions dynamically creates a Python class that inherits
> from ufl.Function and the freshly compiled C++ class, which is
> a dolfin::Function subclass. Then it can construct an object of this
> new class, passing a FunctionSpace object given by the user to
> the dolfin::Function constructor, and an ufl.FiniteElement to the
> ufl.Function constructor.
This sounds doable. I realize now that this was what you were talking about in
your previous emails, but I did not get it until now ;)
> This of course requires that dolfin.FunctionSpace
> is a Python subclass of dolfin::FunctionSpace with an additional
> ufl.FiniteElement member variable. Using jit, dolfin.FunctionSpace
> can compile the ufc::finite_element and ufc::dof_map classes it needs
> from an ufl.FiniteElement. And then there's the issue of reusing
> dofmaps, where DofMapSet enters the play...
Do we need to jit compile ufc::finite_elements and ufc::dof_maps from the
created ufl.FiniteElement? What about the one that follows from the
FunctionSpace?
> > This will hopefully work in all cases that expect a cpp_Function? In
> > assembly where we need speed we extract the compiled function and send
> > that one to cpp_assembly.
>
> I'm not sure what you mean by extracting.
Well, we could define a function 'compiled_function', in the python interface,
that returnes the compiled c++ function, and then in Py_assemble we could
check each coeffisient function for hasattr('compiled_function'), but
nevermind. Your approach is cleaner and should work.
> > Neat? No... but could work!
>
> And it is pretty much guaranteed to blow the minds
> of any non-experts who tries to understand it.
Well, you almost blewed my mind out with your suggestion ;)
Johan
Follow ups
References