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 <[EMAIL PROTECTED]> 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?
--
Marie E. Rognes
Ph.D Fellow,
Centre of Mathematics for Applications,
University of Oslo
http://folk.uio.no/meg
_______________________________________________
DOLFIN-dev mailing list
[email protected]
http://www.fenics.org/mailman/listinfo/dolfin-dev