← Back to team overview

dolfin team mailing list archive

Re: PyDOLFIN interface

 

2008/11/4 Johan Hake <hake@xxxxxxxxx>:
> On Tuesday 04 November 2008 13:59:22 Martin Sandve Alnæs wrote:
>> 2008/11/4 Johan Hake <hake@xxxxxxxxx>:
>> > On Tuesday 04 November 2008 13:07:07 Martin Sandve Alnæs wrote:
>> >> 2008/11/4 Johan Hake <hake@xxxxxxxxx>:
>> >> > Hello!
>> >> >
>> >> > I have started the work on the PyDOLFIN. We can now define the forms
>> >> > in the poisson demo, using the syntax previously discussed, see python
>> >> > poisson demo.
>> >> >
>> >> > A FunctionSpace now inherits both dolfin::FunctionSpace and
>> >> > ffc.FiniteElement, and it can be used to instantiate user defined
>> >> > Functions which can be used to define forms.
>> >> >
>> >> > We need to discuss how to implement a discrete function. This is a bit
>> >> > complicated using the metaclass magic that is implemented now. Now we
>> >> > cannot do:
>> >> >
>> >> >  u = Function(V)
>> >> >  x = u.vector()
>> >> >
>> >> > as Function is just a dummy class for creation of userdefined
>> >> > functions.
>>
>> I don't quite understand the problem here.
>> Are you saying that type(u) is not a subclass of cpp_Function or what?
>
> With the metaclass implementation, Function cannot inherit cpp_Function or
> ffc.Function. A derived class of Function will inherit Function, cpp_Function
> and ffc.Function though. Function is as it is now, only an more or less empty
> class that can be inherited.
>
> The syntax above can be valid with some __new__ magic in Function, probably
> much in line with what you had in mind.
>
>> >> We don't have to use metaclasses, it would be enough to implement
>> >> Function.__new__(cls, *args). This function can return objects of
>> >> a different type, e.g. a compiled function that doesn't inherit from
>> >> dolfin.Function but directly from dolfin::Function.
>> >
>> > and from ufl.Function too?
>>
>> Yes.
>>
>> >> (I didn't understand this stuff fully until last week...)
>> >
>> > Yes I have thought about that solution, but then the created class wont
>> > be a Function. It can be handy to have a class that all python Function
>> > can be checked if isinstance of. With the __new__ function we create
>> > different classes.
>>
>> This is not a problem. On the contrary, you either wish to
>> check if a function is a cpp_Function or a ufl.Function.
>> I would consider "isinstance(f, dolfin.Function)" a bug in
>> most circumstances. That's one of the things I don't
>> like about this design...
>
> Yes, but if you check if u is a Function you allready know it is a
> cpp_Function _and_ an ufl.Function. Just one to keep in mind ;)

That's the bug right there. You (almost) never want to check for a
dolfin.Function, because you're usually _either_ working with
ufl.Function functionality _or_ working with cpp_Function functionality.
Checking for dolfin.Function is then _wrong_, since a real ufl.Function
or cpp_Function won't pass the test.


>> > The advantage, as I see it with your suggestion would be that we can use
>> > the present feature of compiling many functions at a time, but we loose
>> > the consistent syntax:
>> >
>> >  class MyFunction(Function):
>> >      def eval(v,x):
>> >           do something
>> >
>> >  class MyCompiledFunction(Function):
>> >      cpp_code = do something
>> >
>> >  f = MyFunction(V)
>> >  g = MyCompiledFunction(V)
>> >
>> > and it could be complicated to pass the right FunctionSpaces to the
>> > compile_function function.
>>
>> I forgot about this syntax. It's nice, but personally I'll be fine
>> without it :-)
>>
>> >> > Is it possible to define a DiscreteFunction class in c++ (or just in
>> >> > swig?) that inherits dolfin::Function, and in its constructor calls
>> >> > vector()?
>> >> >
>> >> > Then we can use this class in python to create discrete functions. We
>> >> > then avoid the director class that is created by swig for all
>> >> > functions that inherits the cpp_Function. The obvious syntax would
>> >> > then be
>> >> >
>> >> >  u = DiscreteFunction(V)
>> >> >
>> >> > in python. I think with some python magic we still can have the syntax
>> >> >
>> >> >  u = Function(V)
>> >> >
>> >> > which would imply that a discrete function is created, but I haven't
>> >> > implemented it.
>> >>
>> >> That would basically be duplicating the design that has been replaced...
>> >> I think dropping the metaclass is a much easier solution.
>> >
>> > No, this is just for the python interface. This could come handy with the
>> > __new__ implementation you want too. By this we circumvent the director
>> > class that swig creates for dolfin::functions. We dont want to call eval
>> > on such a class to often do we? :)
>> >
>> >> > We also have a problem with MixedElements. Now the FunctionSpace
>> >> > inherits ffc.FiniteElement and a MixedElement is not a FiniteElement.
>> >> > I suppose we could overload the __add__ operator for the FunctionSpace
>> >> > together with a new class MixedFunctionSpace, to fix this?
>> >> >
>> >> > Johan
>> >>
>> >> We also have (in UFL at least) the classes VectorElement and
>> >> TensorElement, so this gets complicated. I think we should just make
>> >> FunctionSpace own an element instead.
>> >>
>> >> element = FiniteElement(...)
>> >> V = FunctionSpace(mesh, element)
>> >> f = Function(V) # calls FiniteElement.__init__(self, element)
>> >
>> > Thats looks nice. We could also use the syntax Anders suggested,
>> >
>> >  V = FunctionSpace(mesh, "Lagrange", 1)
>> >
>> > and then instantiate the FiniteElement in the __init__ function.
>>
>> No, we can't, that's exactly the issue you brought up with MixedElement.
>> ("Lagrange", 1) doesn't carry all information about an element.
>> In UFL we have classes FiniteElement, MixedElement, VectorElement,
>> and TensorElement. In addition to (family,domain,degree), a
>> VectorElement can have a dim, and a TensorElement
>> can have a shape and symmetries...
>
> Of course :P
>
> But would it be possible to create a MixedFunctionSpace by adding two other
> function spaces, with some overloading of __add__? And would it be possible
> to extend the initialization of FunctionSpace, with kwargs and some __new__
> magic, to instantiate FunctionSpace of different elements?

If you do that, you suddenly get a hierarchy of FunctionSpace classes.
My challenge to Anders would then be:

V1 = TensorFunctionSpace(mesh, "CG", 2) # , shape=(2,2),
symmetry=True) # optional args
V2 = VectorFunctionSpace(mesh, "CG", 1) #, dim=2) # optional args
V3 = FunctionSpace(mesh, "DG", 0)
V = MixedFunctionSpace(V1, V2, V3)

Here each of these will be a new cpp_FunctionSpace,
calling jit and constructing dofmaps and whatnot.
It seems possible, but...

> Maybee more relevant do we want it?

Anders does.


>> > This wont work for the basis functions though, but we could just add a
>> > class that inherits the ffc.BasisFunction and which can be instantiated
>> > with both a FunctionSpace and a FiniteElement.
>>
>> We'd need to consider both BasisFunction, and BasisFunctions, which is a
>> function and a bit more complicated. Also TestFunction(s) and
>> TrialFunction(s), but those are just syntactic sugar.
>
> Ok.
>
>> I'd very much prefer letting BasisFunction be and just passing it an
>> element.
>
> I see you point.


In particular, what happens with
    t, v, s = BasisFunctions(V)
with V a mixed function space like above?
That's getting quite difficult to follow.


But my largest concern is that inheriting from ufl classes and
overriding their behaviour may have unanticipated effects inside UFL.
For example, operators like +-*/ can't be implemented on a
dolfin.Function or cpp_Function.

--
Martin


Follow ups

References