← 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: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?


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


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

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

I'd very much prefer letting BasisFunction be and just passing it an element.

--
Martin


Follow ups

References