← Back to team overview

dolfin team mailing list archive

Re: Status of new Expression interface

 

On Friday 27 November 2009 01:20:14 Anders Logg wrote:
> On Thu, Nov 26, 2009 at 10:49:16PM -0800, Johan Hake wrote:
> > On Thursday 26 November 2009 16:09:53 Garth N. Wells wrote:
> > > Anders Logg wrote:
> > > > On Thu, Nov 26, 2009 at 09:42:22PM +0000, Harish Narayanan wrote:
> > > >> Anders Logg wrote:
> > > >>> Looks like the new Expression interface might be working now but
> > > >>> more tests are needed. Please help out getting all the demos over
> > > >>> to the new interface.
> > > >>>
> > > >>> The changes to the interface are as follows:
> > > >>>
> > > >>> 1. V=V argument in Expression should be removed
> > > >>>
> > > >>> 2. mesh argument in Constant should be removed
> > > >>>
> > > >>> 3. Subclasses of Expression overloading eval must overload dim if
> > > >>> not scalar
> >
> > Ok, this might seem to be a bit far fetched but I think it is quite nice.
> >
> > What with:
> >
> >   class MyExpression(Expression):
> >       def eval(self, x):
> >           ....
> >           return x_values, y_values
> >
> > The value dimension would then just be the length of the return argument.
> > The _actual_ eval function would then, using the fabulous metaclass, be:
> >
> >    def eval(self, values, x):
> >        values[0], values[1] = user_eval(self, x)
> >
> > where user_eval is the eval method defined above by the user.
> >
> > This will solve the value dimension problem for python expressions, and
> > make the eval method the user specify more pythonic.
> 
> Being able to do return sin(x[0]), cos(x[1]) would be very nice.
> 
> But I guess we would still have to implement the dim() function when
> subclassing Expression?

The point was actually to not do that. My initial thought was to call the user 
provided function using a dummy self, (or an initialized one) and a dummy x 
arg. Then the number of return argument would decide the value dimension.

This approach would work for simple Expressions, with no need for a special 
initialization. 

   class MyExpression(Expression):
       def eval(self, x):
           return sin(x[0]), cos(x[1])

A more complex Expression a la:

   class MyExpression(Expression):
       def __init__(self, foo, bar):
           self._bar = bar
           self._foo = foo
       def eval(self, x):
           return self._bar.baz*x[0], 2*self._foo

would be impossible to evaluate as it need both bar and foo, when the class i 
constructed.

So the bottom line is , yes wee need to provide the dim method.

> > How do we evaluate the value dimension for multi line C++ expression? Do
> > we require the user to initialize the base Expression class using either
> > the uint dim constructor or the vector<uint> value_shape constructor?
> >
> > If so I do not see that the code in __init__ take care of this case,
> > yet...
> 
> I have assumed that the cpparg input is either a single string (and
> then it's scalar), a tuple of strings (and then it's a vector) or a
> nested tuple (and then it's a tensor).

Correct. This is how we have used these argument before.

> Are there other cases I have missed?

Yes, the __new__ method is called when a derived class is instantiated too. So 
when one try f = Source(V), the logic tells us that it is a scalar function 
that is instantiated. This can be prevented with some tests of course.

> > We also need a cleanup of different erroneous user cases. The one that
> > Garth sketches below, should issue an error. Now it assume the the V is a
> > "cpparg", and somehow gets through.
> 
> Yes.
> 
> > I have also provided the protected attribute _ufl_element. Now there
> > seems to be an element, and a degree attribute. The latter is OK, but I
> > think the former should use the _ufl_element attribute, as other code use
> > the method ufl_element() to access this.
> 
> ok.
> 
> > > How should subclaases be initialised?
> > >
> > >   f = Source(V)
> > >
> > > works, but
> >
> > Should issue an error.
> >
> > >   f = Source
> > >
> > > doesn't.
> >
> > Here you just tell f to be the subclass Source. With the present design
> > you should just use:
> >
> >   f = Source()
> >
> > I have pushed a fix for a bug that prevented this :)
> 
> I thought f = Source() worked already. It did when I tested yesterday.

It didn't when I tried.

> Or did you mean you remove the f = Source(V) thing?

No, not yet.

I Can look at it this evening if not someone(TM) has done it already.

> There were quite a few references to function spaces and V in
> expression.py when I left it yesterday. Did you clean those out as
> well?

No, I just tried to get into the changes that has been done.

Johan



Follow ups

References