dolfin team mailing list archive
-
dolfin team
-
Mailing list archive
-
Message #09819
Re: PyDOLFIN Function
On Tue, Sep 23, 2008 at 05:07:49PM +0200, Evan Lezar wrote:
>
>
> On Tue, Sep 23, 2008 at 5:03 PM, Shawn Walker <walker@xxxxxxxxxxxxxxx> wrote:
>
>
>
> On Tue, 23 Sep 2008, Anders Logg wrote:
>
> > On Tue, Sep 23, 2008 at 12:35:48PM +0200, Marie Rognes wrote:
> >> Anders Logg wrote:
> >>> On Wed, Sep 17, 2008 at 01:23:17PM +0200, Evan Lezar wrote:
> >>>
> >>>> 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).
> >>>>
> >>>>
> >>>>
> >>>> 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
> >>>>
> >>>
> >>> That is the correct way, but the vector will be ignored since the
> >>> Function from now on will create and own its vector of degrees of
> >>> freedom.
> >>>
> >>> So you can do something like
> >>>
> >>> f = Function(element, mesh, Vector())
> >>> x = f.vector()
> >>>
> >>> The vector you send in will be ignored and then you need to pick it
> >>> out afterwards.
> >>>
> >>> Once the new design is in place it will be
> >>>
> >>> f = Function(V) # V is a FunctionSpace
> >>> x = f.vector()
> >>>
> >>>
> >>
> >>
> >> Follow-up question: So, what is the right way to initialize a Function
> >> with a vector of computed values?
> >
> > You can't. You have to create the function first, then set the values
> > in the vector:
> >
> > f = Function(element, mesh, Vector())
> > x = f.vector()
> >
> > solve(A, x, b)
>
> I'm sorry, should this be:
>
> f.vector() = x?
>
> Maybe I just misread the question.
>
>
> I think that we are using this function to do different things. I am using the
> function to visualise a field based on a pre-computed vector of coefficients,
> whereas Anders is storing the solution of a set of linear equations directly in
> the function vector.
I hope things may clear up in a while, but we have many things going
right now: redesign of the function classes, the parallel XML parser
(and then the rest of the parallelization), introduction of the new
FunctionSpace class, higher-order meshes, renaming of member functions
etc. So it may be a few weeks until it clears up...
--
Anders
Attachment:
signature.asc
Description: Digital signature
References