← Back to team overview

dolfin team mailing list archive

Re: Reading functions from file

 

2008/12/9 Johan Hake <hake@xxxxxxxxx>:
> 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.

That's ok.

>> 2. The attribute "spaces" set on line 126 in functionspace.py is used
>> in Function_sub and Function_split in function.py.

Is there another way to create a sub function from
a cpp.Function on a mixed ufc element in Python?

> 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.

Yes. Making these checks correctly is important.
I guess there aren't that many of them.

--
Martin


Follow ups

References