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