Extra parameters in pyDolfin Expression

Asked by dbeacham on 2010-01-18

Is there a less hacked way to add extra parameter values to be used in an Expression in python than:

class MyExp(Expression):
    def __new__(cls, *args, **kwargs):
        obj = Expression.__new__(cls, **kwargs)
        return obj

    def __init__(self, *args):
        ....
        ....

where *args are my extra parameters (ie mesh, mesh functions etc.) and __new__ might have to be better worked if I had included my own kwargs. The above seems to work ok, but let me know of any major problems with it.

I could always use a MyExp.init(...) function after I've created an instance to set up class variables, but just curious as to whether I missed something obvious for a one line initiation.

David.

Question information

Language:
English Edit question
Status:
Answered
For:
DOLFIN Edit question
Assignee:
No assignee Edit question
Last query:
2010-01-18
Last reply:
2010-01-18
Johan Hake (johan-hake) said : #1

On Monday 18 January 2010 08:29:03 dbeacham wrote:
> New question #97842 on DOLFIN:
> https://answers.launchpad.net/dolfin/+question/97842
>
> Is there a less hacked way to add extra parameter values to be used in an
> Expression in python than:
>
> class MyExp(Expression):
> def __new__(cls, *args, **kwargs):
> obj = Expression.__new__(cls, **kwargs)
> return obj
>
> def __init__(self, *args):
> ....
> ....

It has been possible to pass user defined optional arguments to the __init__
method. But it looks like a regression has kicked in.

I have fixed the regression in dolfin dev, and added a doc string example.

You should now be able to do:

   class MyExp(Expression):
       def __init__(self, **kwargs):
           self._mesh = kwargs['mesh']
           self._domain = kwargs['domain']
       def eval(self, values, x):
          info(self._mesh, 1)
          info(self._domain, 1)

   mesh = UnitCube(1,1,1)
   domain = MeshFunction("uint", mesh, 0)
   e = MyExp(mesh=mesh, domain=domain)
   e(0,0,0)

Do not use *args and do _not_ call the base class __init__. Yes, it is counter
intuitive but it is a result of having the Expression class do both compiled
Expressions and python derived Expressions.

I prefer having two classes, CompiledExpression and Expression, so we could
say goodbye to this kind of troubles ;)

Johan

> where *args are my extra parameters (ie mesh, mesh functions etc.) and
> __new__ might have to be better worked if I had included my own kwargs.
> The above seems to work ok, but let me know of any major problems with it.
>
> I could always use a MyExp.init(...) function after I've created an
> instance to set up class variables, but just curious as to whether I
> missed something obvious for a one line initiation.
>
> David.
>

Anders Logg (logg) said : #2

On Mon, Jan 18, 2010 at 10:23:54AM -0800, Johan Hake wrote:
> On Monday 18 January 2010 08:29:03 dbeacham wrote:
> > New question #97842 on DOLFIN:
> > https://answers.launchpad.net/dolfin/+question/97842
> >
> > Is there a less hacked way to add extra parameter values to be used in an
> > Expression in python than:
> >
> > class MyExp(Expression):
> > def __new__(cls, *args, **kwargs):
> > obj = Expression.__new__(cls, **kwargs)
> > return obj
> >
> > def __init__(self, *args):
> > ....
> > ....
>
> It has been possible to pass user defined optional arguments to the __init__
> method. But it looks like a regression has kicked in.
>
> I have fixed the regression in dolfin dev, and added a doc string example.
>
> You should now be able to do:
>
> class MyExp(Expression):
> def __init__(self, **kwargs):
> self._mesh = kwargs['mesh']
> self._domain = kwargs['domain']
> def eval(self, values, x):
> info(self._mesh, 1)
> info(self._domain, 1)
>
> mesh = UnitCube(1,1,1)
> domain = MeshFunction("uint", mesh, 0)
> e = MyExp(mesh=mesh, domain=domain)
> e(0,0,0)
>
> Do not use *args and do _not_ call the base class __init__. Yes, it is counter
> intuitive but it is a result of having the Expression class do both compiled
> Expressions and python derived Expressions.
>
> I prefer having two classes, CompiledExpression and Expression, so we could
> say goodbye to this kind of troubles ;)

I'd prefer keeping "Expression" for the simplest option which is
visible in most demos:

  f = Expression("sin(x[0])")

and find a suitable name for Expression with eval.

Ideally, it should also be the same in C++.

Candidates are

  UserExpression
  ComplexExpression

But I'm not sure I like any of them.

--
Anders

> Johan
>
>
> > where *args are my extra parameters (ie mesh, mesh functions etc.) and
> > __new__ might have to be better worked if I had included my own kwargs.
> > The above seems to work ok, but let me know of any major problems with it.
> >
> > I could always use a MyExp.init(...) function after I've created an
> > instance to set up class variables, but just curious as to whether I
> > missed something obvious for a one line initiation.
> >
> > David.
> >
>
> _______________________________________________
> Mailing list: https://launchpad.net/~dolfin
> Post to : <email address hidden>
> Unsubscribe : https://launchpad.net/~dolfin
> More help : https://help.launchpad.net/ListHelp

Johan Hake (johan-hake) said : #3

On Monday 18 January 2010 10:33:46 Anders Logg wrote:
> On Mon, Jan 18, 2010 at 10:23:54AM -0800, Johan Hake wrote:
> > On Monday 18 January 2010 08:29:03 dbeacham wrote:
> > > New question #97842 on DOLFIN:
> > > https://answers.launchpad.net/dolfin/+question/97842
> > >
> > > Is there a less hacked way to add extra parameter values to be used in
> > > an Expression in python than:
> > >
> > > class MyExp(Expression):
> > > def __new__(cls, *args, **kwargs):
> > > obj = Expression.__new__(cls, **kwargs)
> > > return obj
> > >
> > > def __init__(self, *args):
> > > ....
> > > ....
> >
> > It has been possible to pass user defined optional arguments to the
> > __init__ method. But it looks like a regression has kicked in.
> >
> > I have fixed the regression in dolfin dev, and added a doc string
> > example.
> >
> > You should now be able to do:
> >
> > class MyExp(Expression):
> > def __init__(self, **kwargs):
> > self._mesh = kwargs['mesh']
> > self._domain = kwargs['domain']
> > def eval(self, values, x):
> > info(self._mesh, 1)
> > info(self._domain, 1)
> >
> > mesh = UnitCube(1,1,1)
> > domain = MeshFunction("uint", mesh, 0)
> > e = MyExp(mesh=mesh, domain=domain)
> > e(0,0,0)
> >
> > Do not use *args and do _not_ call the base class __init__. Yes, it is
> > counter intuitive but it is a result of having the Expression class do
> > both compiled Expressions and python derived Expressions.
> >
> > I prefer having two classes, CompiledExpression and Expression, so we
> > could say goodbye to this kind of troubles ;)
>
> I'd prefer keeping "Expression" for the simplest option which is
> visible in most demos:
>
> f = Expression("sin(x[0])")
>
> and find a suitable name for Expression with eval.
>
> Ideally, it should also be the same in C++.

So we could change Expression to let say UserExpression in C++ too. But I
think this is double communication. Expression is a user defined expression
and has to be sub-classed anyway.

JIT compiling an expression in PyDOLFIN does quite a lot of magic behind the
scenes and justifies a more explicit name like CompiledExpression or
JITExpression. Clarity before beauty!

> Candidates are
>
> UserExpression
> ComplexExpression

I still prefer CompileExpression and Expression, but wrt your suggestion I
would go for the first one. Passing a mesh to an __init__ is not complex.

Johan

Can you help with this problem?

Provide an answer of your own, or ask dbeacham for more information if necessary.

To post a message you must log in.