← Back to team overview

dolfin team mailing list archive

Re: Reading functions from file

 

On Tuesday 09 December 2008 13:44:37 Anders Logg wrote:
> On Tue, Dec 09, 2008 at 01:37:59PM +0100, Martin Sandve Alnæs wrote:
> > 2008/12/9 Anders Logg <logg@xxxxxxxxx>:
> > > On Tue, Dec 09, 2008 at 09:47:03AM +0100, Martin Sandve Alnæs wrote:
> > >> 2008/12/9 Anders Logg <logg@xxxxxxxxx>:
> > >> > On Tue, Dec 09, 2008 at 08:44:49AM +0100, Johan Hake wrote:
> > >> >> On Monday 08 December 2008 22:31:58 Martin Sandve Alnæs wrote:
> > >> >> > 2008/12/8 Johan Hake <hake@xxxxxxxxx>:
> > >> >> > > On Monday 08 December 2008 14:53:09 Anders Logg wrote:
> > >> >> > >> On Mon, Dec 08, 2008 at 02:31:23PM +0100, Johan Hake wrote:
> > >> >> > >> > On Monday 08 December 2008 13:55:26 Anders Logg wrote:
> > >> >> > >> > > On Mon, Dec 08, 2008 at 08:01:32AM +0100, Johan Hake wrote:
> > >> >> > >> > > > On Sunday 07 December 2008 23:33:53 Anders Logg wrote:
> > >> >> > >> > > > > Something that needs to be added to the new Function
> > >> >> > >> > > > > interface is reading functions from file. This has
> > >> >> > >> > > > > worked before:
> > >> >> > >> > > > >
> > >> >> > >> > > > >   f = Function("function.xml")
> > >> >> > >> > > > >
> > >> >> > >> > > > > Can this be added to the metaclass machinery?
> > >> >> > >> > > >
> > >> >> > >> > > > No, but to the __new__ function ;) so I guess yes!
> > >> >> > >> > > >
> > >> >> > >> > > > The metalclass produces Function classes. The __new__
> > >> >> > >> > > > function instantiate new Functions from what ever
> > >> >> > >> > > > argument. This is such a case.
> > >> >> > >> > >
> > >> >> > >> > > It looks like some work is needed to get this in place.
> > >> >> > >> > >
> > >> >> > >> > > The "constructor" currently looks as follows:
> > >> >> > >> > >
> > >> >> > >> > >     def __new__(cls, V, **kwargs):
> > >> >> > >> > >
> > >> >> > >> > > so to do
> > >> >> > >> > >
> > >> >> > >> > >     f = Function("function.xml")
> > >> >> > >> > >
> > >> >> > >> > > we need to check if V is a string. Could you add some
> > >> >> > >> > > hooks for this?
> > >> >> > >> >
> > >> >> > >> > I will have a look at it. I do not like V beeing both a
> > >> >> > >> > FunctionSpace and potentially a filename. I consider having
> > >> >> > >> > a bunch of kwargs, all defaulting to None. E.g.
> > >> >> > >> >
> > >> >> > >> >   def __new__(cls,
> > >> >> > >> > V=None,cpparg=None,defaults=None,filename=None):
> > >> >> > >> >
> > >> >> > >> > Then if you create a Function from file you do:
> > >> >> > >> >
> > >> >> > >> >   f = Function(filename="some_function.xml")
> > >> >> > >> >
> > >> >> > >> > the cpparg can the repreresent what is sent to
> > >> >> > >> > compile_function.
> > >> >> > >>
> > >> >> > >> Then it would be different from the C++ constructor (which
> > >> >> > >> doesn't handle named default arguments) and the Mesh
> > >> >> > >> constructor in both C++ and Python:
> > >> >> > >>
> > >> >> > >>   mesh = Mesh("mesh.xml")
> > >> >> > >
> > >> >> > > The Mesh class has a much clearer C++ interface. It is either
> > >> >> > > instantiated with a filename-string or from another mesh. The
> > >> >> > > Function class is a versatile class already in the C++
> > >> >> > > interface, which defines different constructors, but evenmore
> > >> >> > > so in the python interface.
> > >> >> > >
> > >> >> > > Then I do not think that adding a kwarg for filename is that
> > >> >> > > bad. The design goal of having as similare interface as
> > >> >> > > possible is good, but then there are different programming
> > >> >> > > cultures too, to take into acount. I am not religious about it,
> > >> >> > > but as far as we can I think we should define kwargs to reflect
> > >> >> > > different instantiation protocol.
> > >> >> > >
> > >> >> > > kwargs gives information about how to instantiate a Function. A
> > >> >> > > common way to figure out how to use a class in python, is to
> > >> >> > > look at the args and kwargs in class.__init__.
> > >> >> >
> > >> >> > Here, let me fix that for you:
> > >> >> >
> > >> >> >   A common way to figure out how to use a
> > >> >> >   poorly designed and/or documented
> > >> >> >   class in python, is to look at the args and kwargs in
> > >> >> > class.__init__.
> > >> >> >
> > >> >> > Forcing the user to look at the source code rarely reflects good
> > >> >> > code.
> > >> >>
> > >> >> I suppose you do not mean that forcing a user to look at the
> > >> >> argument list is reflecting bad code design, but rather the other
> > >> >> way around. If we have bad code design we may force the user to
> > >> >> look at the argument list together with other documentation?
> > >> >>
> > >> >> > But I agree that keyword arguments isn't such a bad thing in
> > >> >> > python.
> > >> >>
> > >> >> Good!
> > >> >>
> > >> >> > >> Yes, first create the cpp.Function, then extract
> > >> >> > >> v.function_space.element().signature() and use that to create
> > >> >> > >> the form compiler element. Will that work?
> > >> >> > >
> > >> >> > > Yes it will be doable. I didn't know that the FiniteElements in
> > >> >> > > the elementlibrary all defined its signature. To accomplish
> > >> >> > > this we need to add some construction options for the
> > >> >> > > dolfin.FunctionSpace though, as it is too restrictive now.
> > >> >> >
> > >> >> > Whatever requirements you decide to put on the element signature,
> > >> >> > it would be nice if they were documented formally (i.e. not as
> > >> >> > ffc code), and placed in the UFC manual.
> > >> >> >
> > >> >> > > Martin has also asked for a way to instantiate a
> > >> >> > > dolfin.FunctionSpace either with an ufc form or from an
> > >> >> > > ufc_finite_element together with an ufc_dofmap. We should not
> > >> >> > > forget the pure ufc interface. I think it is good that Martin
> > >> >> > > keep up that pressure! To reverse engeneer a
> > >> >> > > dolfin.FunctionSpace from these entities will probably not be
> > >> >> > > doable.
> > >> >> > >
> > >> >> > > But for that usercase it should be sufficient to construct a
> > >> >> > > cpp.FunctionSpace which can be sent to assemble, e.g:
> > >> >> > >
> > >> >> > >  V = cpp.FunctionSpace(mesh,ufc_element,ufc_dofmap)
> > >> >> > >  f = Function(V,...) # We need to add support for sending in
> > >> >> > > just # a cpp.FunctionSpace to a Function, and then return # a
> > >> >> > > cpp.Function
> > >> >> > >
> > >> >> > >  A =
> > >> >> > > assemble(compiled_ufc_form,function_spaces=V,coefficients=[f])
> > >> >> > >
> > >> >> > > We already have checks for cpp.FunctionSpace and cpp.Function
> > >> >> > > for the coefficients.
> > >> >> > >
> > >> >> > > I do not know how the coefficient kwarg should work though.
> > >> >> > >
> > >> >> > >  assemble(...,coefficient ={f_ufl:f_cpp})
> > >> >> > >
> > >> >> > > as the form that is sent in to the assemble function is
> > >> >> > > compiled and does not carry any information about the ufl/ffc
> > >> >> > > coefficient function. Do you have anything to add here Martin?
> > >> >> >
> > >> >> > Looks good. Either a dict or a list should be accepted.
> > >> >> > UFC does not require a UFL source!
> > >> >>
> > >> >> Exactly.
> > >> >>
> > >> >> > Maybe we can add a helper function:
> > >> >> >
> > >> >> > def function_spaces(form, mesh):
> > >> >> >     spaces = []
> > >> >> >     ... loop over form arguments and create FunctionSpace objects
> > >> >> > with reuse if possible
> > >> >> >     return spaces
> > >> >>
> > >> >> My hands on experience with pure ffc code is nil, so please be more
> > >> >> explicit.
> > >> >>
> > >> >> > Maybe not exactly what's needed. But preferably we will have
> > >> >> > tools that enable easy use of UFC code directly, but which are
> > >> >> > also used behind the scenes regularly by common code such that
> > >> >> > they are actually in use and being maintained.
> > >> >> > Otherwise somebody(tm) will just keep making design decisions
> > >> >> > that breaks UFC compatibility, which sort of weakens the point of
> > >> >> > a unified interface...
> > >> >>
> > >> >> I think I see your point. Instead of hiding the ufc stuff, in
> > >> >> ffc.jit, which is the case today, we should use it more explicitly
> > >> >> in the code, together with hooks to the outside world, for people
> > >> >> that want to use PyDOLFIN with pure ufc.
> > >> >>
> > >> >> But isn't this desing desision already broken in C++ DOLFIN?
> > >> >>
> > >> >> Johan
> > >> >
> > >> > Not necessarily. Before we had an interface to the assembler
> > >> > functions that allowed sending in ufc objects. This has been
> > >> > removed.
> > >> >
> > >> > Instead we now provide a simple way to wrap ufc objects into a Form
> > >> > and then sending it to assemble():
> > >> >
> > >> >  Form dolfin_form(ufc_form, ...);
> > >> >  assemble(A, dolfin_form);
> > >> >
> > >> > (By the way, it looks like we should change the order of arguments
> > >> > in the Form constructor above so the ufc::form is first.)
> > >> >
> > >> > This gives the same flexibility as before at the expense of an extra
> > >> > line of code but simplifies the assembler interface.
> > >>
> > >> Ok! And Form is usable from Python then?
> > >> I'll take a look at the source code before I say more.
> > >
> > > In Python there is another Form class (subclass of cpp.Form) that
> > > takes care of this. It takes "anything" as input and produces
> > > something that can be used with the C++ assemble functions (so it does
> > > JIT compilation when necessary but not if it gets a UFC form).
> > >
> > > Take a look at form.py.
> >
> > Looks good.
> >
> > What I'm not confident about now is the python FunctionSpace hierarchy.
> > In which cases will a dolfin-constructed MixedFunctionSpace behave
> > differently from a cpp.FunctionSpace constructed from a mixed ufc
> > element?
>
> In only two ways as far as I can tell:
>
> 1. One can do V + Q etc with the Python classes in functionspace.py.
>
> 2. The attribute "spaces" set on line 126 in functionspace.py is used
> in Function_sub and Function_split in function.py.

I think an important point here is that a lot of the things that is added in 
the python interface, like Function(s), FunctionSpace, MixedFunctionSpace, 
aso, is done to facilitate a seamless(hopefully) mix of the form compiler 
language and PyDOLFIN.

If one want to use PyDOLFIN with already precompiled ufc_foo, one do that with 
the knowledge of not being able to e.g:

   W = V + P

where V and P are cpp.FunctionSpaces created using ufc_foo. Then we should 
only check for cpp.FunctionSpace in our code where this is needed and give 
appropriate error messages if not that is handed. This will be the same for 
cpp.Functions.

Johan


Follow ups

References