← Back to team overview

dolfin team mailing list archive

Re: PyDOLFIN Function

 

On Tue, Sep 16, 2008 at 2:18 PM, Anders Logg <logg@xxxxxxxxx> wrote:

> On Tue, Sep 16, 2008 at 01:10:35PM +0100, Garth N. Wells wrote:
> >
> >
> > Anders Logg wrote:
> > > On Mon, Sep 15, 2008 at 08:09:43PM +0100, Garth N. Wells wrote:
> > >>
> > >> Anders Logg wrote:
> > >>> On Mon, Sep 15, 2008 at 06:31:56PM +0200, Anders Logg wrote:
> > >>>> On Mon, Sep 15, 2008 at 04:42:32PM +0100, Garth N. Wells wrote:
> > >>>>> Anders Logg wrote:
> > >>>>>> On Mon, Sep 15, 2008 at 04:32:38PM +0100, Garth N. Wells wrote:
> > >>>>>>> Anders Logg wrote:
> > >>>>>>>> On Mon, Sep 15, 2008 at 03:47:59PM +0100, Garth N. Wells wrote:
> > >>>>>>>>> Anders Logg wrote:
> > >>>>>>>>>> On Mon, Sep 15, 2008 at 03:12:58PM +0100, Garth N. Wells
> wrote:
> > >>>>>>>>>>> Anders Logg wrote:
> > >>>>>>>>>>>> On Mon, Sep 15, 2008 at 03:06:55PM +0200, Johan Hake wrote:
> > >>>>>>>>>>>>> On Monday 15 September 2008 14:29:08 Garth N. Wells wrote:
> > >>>>>>>>>>>>>> Could a Python expert take a look at
> site-packges/dolfin/function.py?
> > >>>>>>>>>>>>>> The code directly following the comment
> > >>>>>>>>>>>>>>
> > >>>>>>>>>>>>>>   # Special case, Function(element, mesh, x), need to
> create simple form
> > >>>>>>>>>>>>>> to get arguments
> > >>>>>>>>>>>>>>
> > >>>>>>>>>>>>>> need to be updated but I don't understand it well.
> > >>>>>>>>>>>>> The first special case is for initializing a Function with
> a given Vector, by
> > >>>>>>>>>>>>> constructing a dofmap from the handed element.
> > >>>>>>>>>>>>>
> > >>>>>>>>>>>>> As constructing a Function from a vector is removed from
> the cpp interface,
> > >>>>>>>>>>>>> and we have not, (or have we?) figured out how to wrap a
> shared_ptr in swig,
> > >>>>>>>>>>>>> we should probably just remove the first case for now.
> > >>>>>>>>>>>>>
> > >>>>>>>>>>>>> Johan
> > >>>>>>>>>>>> The question is how we want to create discrete Functions in
> Python.
> > >>>>>>>>>>>> Previously, this was done by
> > >>>>>>>>>>>>
> > >>>>>>>>>>>>   u = Function(element, mesh, Vector())
> > >>>>>>>>>>>>
> > >>>>>>>>>>>> but now the third argument is not needed anymore. If we
> remove it,
> > >>>>>>>>>>>> we get
> > >>>>>>>>>>>>
> > >>>>>>>>>>>>   u = Function(element, mesh)
> > >>>>>>>>>>>>
> > >>>>>>>>>>>> but that doesn't work since that is the way to initialize a
> > >>>>>>>>>>>> user-defined function (something overloading eval()).
> > >>>>>>>>>>>>
> > >>>>>>>>>>>> We could put in a flag and make "discrete" the default. Then
> all
> > >>>>>>>>>>>> user-defined functions need to set the flag to "user".
> > >>>>>>>>>>>>
> > >>>>>>>>>>>> Suggestions? This is a good time to worry about how we want
> to design
> > >>>>>>>>>>>> the Function interface.
> > >>>>>>>>>>>>
> > >>>>>>>>>>> Sounds ok to me. This is basically what Vector() was doing,
> and a flag
> > >>>>>>>>>>> would be more descriptive.
> > >>>>>>>>>>>
> > >>>>>>>>>>> Garth
> > >>>>>>>>>> Maybe we could first try to think seriously about reducing the
> number
> > >>>>>>>>>> of different constructors in Function. There are 14 now! See
> below.
> > >>>>>>>>>>
> > >>>>>>>>>> I guess we need the following two basic constructors (empty
> and copy):
> > >>>>>>>>>>
> > >>>>>>>>>>   /// Create empty function (read data from file)
> > >>>>>>>>>>   Function();
> > >>>>>>>>>>
> > >>>>>>>>>>   /// Copy constructor
> > >>>>>>>>>>   Function(const Function& f);
> > >>>>>>>>>>
> > >>>>>>>>>> Then we have one for reading from file, which seems ok:
> > >>>>>>>>>>
> > >>>>>>>>>>   /// Create function from data file
> > >>>>>>>>>>   explicit Function(const std::string filename);
> > >>>>>>>>>>
> > >>>>>>>>>> And then the following set of constructors for constants:
> > >>>>>>>>>>
> > >>>>>>>>>>   /// Create constant scalar function from given value
> > >>>>>>>>>>   Function(Mesh& mesh, real value);
> > >>>>>>>>>>
> > >>>>>>>>> This one is useful.
> > >>>>>>>>>
> > >>>>>>>>>>   /// Create constant vector function from given size and
> value
> > >>>>>>>>>>   Function(Mesh& mesh, uint size, real value);
> > >>>>>>>>>>
> > >>>>>>>>> We could get rid of this one and use the below constructor.
> > >>>>>>>>>
> > >>>>>>>>>>   /// Create constant vector function from given size and
> values
> > >>>>>>>>>>   Function(Mesh& mesh, const Array<real>& values);
> > >>>>>>>>>>
> > >>>>>>>>> This one is useful.
> > >>>>>>>>>
> > >>>>>>>>>>   /// Create constant tensor function from given shape and
> values
> > >>>>>>>>>>   Function(Mesh& mesh, const Array<uint>& shape, const
> Array<real>& values);
> > >>>>>>>>>>
> > >>>>>>>>> This is the most generic of the constant functions, so I guess
> we need it.
> > >>>>>>>>>
> > >>>>>>>>>> And then there's this constructor which is needed for
> w.split(u, p):
> > >>>>>>>>>>
> > >>>>>>>>>>   /// Create discrete function from sub function
> > >>>>>>>>>>   explicit Function(SubFunction sub_function);
> > >>>>>>>>>>
> > >>>>>>>>>> But then there's the following mess of constructors:
> > >>>>>>>>>>
> > >>>>>>>>> Some of these constructors are necessary to support the
> PyDOLFIN
> > >>>>>>>>> interface. Can we get around this somehow to avoid duplication?
> > >>>>>>>>>
> > >>>>>>>>>>   /// Create function from given ufc::function
> > >>>>>>>>>>   Function(Mesh& mesh, const ufc::function& function, uint
> size);
> > >>>>>>>>>>
> > >>>>>>>>>>   /// Create discrete function for argument function i of form
> > >>>>>>>>>>   Function(Mesh& mesh, Form& form, uint i = 1);
> > >>>>>>>>>>
> > >>>>>>>>>>   /// Create discrete function for argument function i of form
> > >>>>>>>>>>   Function(Mesh& mesh, DofMap& dof_map, const ufc::form& form,
> uint i = 1);
> > >>>>>>>>>>
> > >>>>>>>>>>   /// Create discrete function for argument function i of form
> (data may be shared)
> > >>>>>>>>>>   Function(std::tr1::shared_ptr<Mesh> mesh,
> > >>>>>>>>>>            std::tr1::shared_ptr<GenericVector> x,
> > >>>>>>>>>>            std::tr1::shared_ptr<DofMap> dof_map, const
> ufc::form& form, uint i = 1);
> > >>>>>>>>>>
> > >>>>>>>>>>   /// Create discrete function based on signatures
> > >>>>>>>>>>   Function(std::tr1::shared_ptr<Mesh> mesh,
> > >>>>>>>>>>            const std::string finite_element_signature,
> > >>>>>>>>>>            const std::string dof_map_signature);
> > >>>>>>>>>>
> > >>>>>>>>>>   /// Create user-defined function (evaluation operator must
> be overloaded)
> > >>>>>>>>>>   explicit Function(Mesh& mesh);
> > >>>>>>>>>>
> > >>>>>>>>> We need this one.
> > >>>>>>>>>
> > >>>>>>>>> Garth
> > >>>>>>>> If we just consider discrete functions for a while, the question
> is
> > >>>>>>>> how these may be most conveniently (and naturally) defined in
> C++ and
> > >>>>>>>> Python.
> > >>>>>>>>
> > >>>>>>>> In C++, one only has a dolfin::Form, for example
> PoissonBilinearForm,
> > >>>>>>>> and then it's simple to create a discrete Function by
> > >>>>>>>>
> > >>>>>>>>   Function u(mesh, form);
> > >>>>>>>>
> > >>>>>>>> This will extract the element and dof map for the second
> argument of
> > >>>>>>>> the form (the trial function) which is normally what is needed.
> > >>>>>>>>
> > >>>>>>>> In Python, one does not have a dolfin::Form, but instead one has
> a
> > >>>>>>>> FiniteElement, and then the simplest thing to do is
> > >>>>>>>>
> > >>>>>>>>   u = Function(element, mesh)
> > >>>>>>>>
> > >>>>>>>> The element is the first argument for practical reasons (see
> > >>>>>>>> function.py) but maybe it shouldn't. I'd like to change this so
> that
> > >>>>>>>> the mesh is always first. All Functions require a Mesh and then
> it's
> > >>>>>>>> natural to put this first.
> > >>>>>>>>
> > >>>>>>>> So then we would have
> > >>>>>>>>
> > >>>>>>>>   C++:    Function u(mesh, form);
> > >>>>>>>>   Python: u = Function(mesh, element)
> > >>>>>>>>
> > >>>>>>>> On the other hand, we've been discussing adding a FunctionSpace
> class,
> > >>>>>>>> and then it might be natural to just have
> > >>>>>>>>
> > >>>>>>>>   C++:    Function u(V);
> > >>>>>>>>   Python: u = Function(V)
> > >>>>>>>>
> > >>>>>>>> This would create a discrete Function. Constant Functions and
> > >>>>>>>> user-defined Functions may be created without reference to a
> > >>>>>>>> FunctionSpace. This would solve the problem of overloading
> > >>>>>>>> constructors. It would be very clear that whenever a
> FunctionSpace is
> > >>>>>>>> involved, it is a discrete Function.
> > >>>>>>>>
> > >>>>>>> Agree. It's not appropriate to initialise a discrete function
> with a
> > >>>>>>> form. It seems that using a FunctionSpace will simplify the
> interface
> > >>>>>>> and provide uniformity across the C++ and Python interfaces, so
> let's
> > >>>>>>> get FunctionSpace (or something similar with another name) in
> place and
> > >>>>>>>   then remove some the Function constructors.
> > >>>>>> I think FunctionSpace is a good name.
> > >>>>>>
> > >>>>>>> Function spaces are not only associated with DiscreteFunctions.
> We
> > >>>>>>> usually interpolate user defined function in the finite element
> space,
> > >>>>>>> so perhaps there is some scope to unify discrete and user defined
> > >>>>>>> functions?
> > >>>>>>>
> > >>>>>>> Garth
> > >>>>>> Perhaps, but it would require storing an extra vector of values
> for
> > >>>>>> user-defined functions unnecessarily.
> > >>>>>>
> > >>>>> I'm not suggesting that we store a vector of values - just pointing
> out
> > >>>>> a function space is also associated with user-defined functions.
> > >>>>>
> > >>>>> Garth
> > >>>> Yes, I forgot for a minute that user-defined functions also need to
> be
> > >>>> associated with a particular function space when used in a form.
> > >>>>
> > >>>> Then it seems we still have the problem of differentiating between
> > >>>> user-defined functions and discrete functions when overloading
> > >>>> constructors.
> > >>> I have a suggestion that would solve this as well as another problem
> > >>> we've discussed a few times before regarding Functions
> > >>> (time-stepping). It's rather drastic but it might work.
> > >>>
> > >>> * Remove GenericFunction, DiscreteFunction, UserFunction etc and just
> > >>>   have one single class named Function.
> > >>>
> > >> Sounds good to me. I often found the current design a bit complicated.
> A
> > >> simpler design will make parallisation easier.
> > >>
> > >>> * Always require a FunctionSpace in the inialization of Function:
> > >>>
> > >>>   u = Function(V)
> > >>>
> > >>> * Let a Function consist of two things, a function space V and
> > >>>   degrees of freedom U:
> > >>>
> > >>>   u_h = \sum_i U_i \phi_i
> > >>>
> > >>>   where {\phi_i} are the basis functions for V.
> > >>>
> > >> As long as it's general enough to permit 'quadrature functions'.
> > >>
> > >>> * Keep a shared_ptr to V, and a pointer to a Vector U.
> > >>>
> > >> It might be useful to make the vector a shared pointer (need to check
> > >> what a smart pointer returns if it doesn't point to anything) because
> it
> > >> would be useful with sub-functions.
> > >>
> > >>> * The Vector pointer is initialized to 0 by default and as long as it
> > >>>   remains 0, the Function behaves like a user-defined Function, that
> > >>>   is, the eval() function is used.
> > >>>
> > >>> * Whenever someone calls the vector() member function, the Vector U
> is
> > >>>   initialized to a Vector of correct size (determined by the DofMap
> in
> > >>>   the FunctionSpace V). From this point on, the Function behaves like
> > >>>   a discrete Function, that is, the values in U are used, not eval().
> > >>>
> > >> Sounds good.
> > >>
> > >>> * This would make the behavior dynamic. For example, one may set u0
> to
> > >>>   an initial value in time-stepping and then do u0 = u1 and u0 would
> > >>>   change behavior from user-defined to discrete.
> > >>>
> > >>> * Constant functions are handled by a new class named simply
> Constant,
> > >>>   which is a subclass of Function that overloads eval() and returns
> > >>>   the constant value.
> > >>>
> > >> Perhaps ConstantFunction would be a better name?
> > >
> > > Maybe, but it would also be natural to couple this to Constant in UFL
> > > in the same way as we couple Function to Function.
> > >
> > > Another reason to use Constant is that ConstantFunction implies that
> > > there may be other subclasses of Function than Constant and it would
> > > be good to avoid building a hierarchy (again). The class Constant just
> > > happens to be implemented as a subclass of Function, but it should be
> > > thought of as something different.
> > >
> > >> No matter what happens, it seems that FunctionSpace is the next step.
> > >> Related to this, is it the intention that a FiniteElement owns a
> > >> ufc::finite_elememt and provides wrapper, like DofMap?
> > >
> > > Yes, that was my plan. It only needs to overload the subset of
> > > functionality of ufc::finite_element that we need now.
> > >
> >
> > OK. I can put FiniteElement together pretty quickly if you haven't
> > started already.
> >
> > Garth
>
> I haven't (not more than the empty template that's currently there).
>
> --
> Anders
>

Hi

What is the correct way to initialize a  discrete function in python.  I see
that the way I was using in the electromagnetic demo no longer works.  f =
Function(element, mesh, vector)

Evan


> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.6 (GNU/Linux)
>
> iD8DBQFIz6QBTuwUCDsYZdERArEwAJ9uP2buK+ylGsM+l9YF7dDoVfiX/QCfa6G0
> 0wJ7S3o2ym5xChd8LL09vh8=
> =1ceY
> -----END PGP SIGNATURE-----
>
> _______________________________________________
> DOLFIN-dev mailing list
> DOLFIN-dev@xxxxxxxxxx
> http://www.fenics.org/mailman/listinfo/dolfin-dev
>
>

Follow ups

References