← Back to team overview

dolfin team mailing list archive

Re: PyDOLFIN interface

 

2008/11/4 Martin Sandve Alnæs <martinal@xxxxxxxxx>:
> 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.

Speaking of which, does FunctionSpace and Function need to implement __repr__?
If so, why? It won't work anyway since it just uses the string "mesh".
In UFL I've used repr for quite a few things, and this would break a lot.

--
Martin


Follow ups

References