dolfin team mailing list archive
-
dolfin team
-
Mailing list archive
-
Message #12663
Re: [HG DOLFIN] Automatically interpolate user-defined functions on assignment
On Thu, Mar 12, 2009 at 5:26 PM, Anders Logg <logg@xxxxxxxxx> wrote:
> On Thu, Mar 12, 2009 at 04:59:43PM +0100, Martin Sandve Alnæs wrote:
>> On Thu, Mar 12, 2009 at 4:33 PM, Anders Logg <logg@xxxxxxxxx> wrote:
>> > On Thu, Mar 12, 2009 at 01:42:55PM +0100, Martin Sandve Alnæs wrote:
>> >> On Thu, Mar 12, 2009 at 1:16 PM, Johan Hake <hake@xxxxxxxxx> wrote:
>> >> > On Thursday 12 March 2009 12:58:33 Garth N. Wells wrote:
>> >> >> Anders Logg wrote:
>> >> >> > On Thu, Mar 12, 2009 at 10:46:14AM +0100, Martin Sandve Alnæs wrote:
>> >> >> >> On Thu, Mar 12, 2009 at 10:32 AM, Anders Logg <logg@xxxxxxxxx> wrote:
>> >> >> >>> On Thu, Mar 12, 2009 at 10:25:36AM +0100, Martin Sandve Alnæs wrote:
>> >> >> >>>> I have serious problems with the idea of letting user-defined
>> >> >> >>>> functions change nature to discrete functions as a side effect
>> >> >> >>>> of other operations, effectively hiding the user-defined
>> >> >> >>>> implementation of eval.
>> >> >> >>>>
>> >> >> >>>> (I know this concept wasn't introduced in this discussion, but it's
>> >> >> >>>> related).
>> >> >> >>>
>> >> >> >>> You mean by calling u.vector()? Yes, I agree it's problematic.
>> >> >> >>>
>> >> >> >>> But I don't know how to handle it otherwise. Consider the following
>> >> >> >>> example:
>> >> >> >>>
>> >> >> >>> u = Function(V)
>> >> >> >>> solve(A, u.vector(), b)
>> >> >> >>>
>> >> >> >>> First u is a user-defined function since it doesn't have a
>> >> >> >>> vector. Then it becomes discrete when we ask for the vector.
>> >> >> >>>
>> >> >> >>> The problem I think is that there is no way for us to check whether a
>> >> >> >>> user has overloaded eval() without trying to call it.
>> >> >> >>
>> >> >> >> If we didn't require that user-defined functions had a function space
>> >> >> >> for various operations, this wouldn't be as large a problem.
>> >> >> >> Then you could do
>> >> >> >>
>> >> >> >> class MyFunction(Function)
>> >> >> >> {
>> >> >> >> MyFunction(V): Function(V) {}
>> >> >> >> MyFunction(): Function() {}
>> >> >> >> void eval(...) { ... }
>> >> >> >> }
>> >> >> >>
>> >> >> >> MyFunction f;
>> >> >> >> f.vector(); // error, no function space!
>> >> >> >>
>> >> >> >> MyFunction f(V);
>> >> >> >> f.vector(); // ok, should interpolate and make f discrete
>> >> >> >>
>> >> >> >> This is already possible, but function spaces get attached
>> >> >> >> unneccesarily:
>> >> >> >>
>> >> >> >>
>> >> >> >> 1) It's not necessary to attach function spaces to functions for
>> >> >> >> assembly, since a user-defined function is evaluated through
>> >> >> >> ufc::finite_element::evaluate_dofs for each cell anyway.
>> >> >> >> This would remove the need for the side-effect in
>> >> >> >>
>> >> >> >> MyFunction f;
>> >> >> >> MyForm a;
>> >> >> >> a.f = f; // attaches function space to f
>> >> >
>> >> > Isn't the function space used to deduct the value rank during assemble now? If
>> >> > we go for this approach we probably need to readd the rank function and make
>> >> > it virtual?
>> >>
>> >> I don't see how the current approach with rank deducted from
>> >> some function space is any safer than deducting it from the
>> >> finite element of the form. Which is to say: this is unsafe, the
>> >> user should define the rank when defining eval.
>> >
>> > We just removed the rank() and dim() arguments from the Function
>> > interface as they are not needed.
>>
>> Are not needed because a Function always has a FunctionSpace
>> or for some other reason? If we don't require a FunctionSpace
>> I think they should be re-added. I expect to be able to use a Function
>> for other things than assembly, e.g., if I get some arbitrary Function
>> to some code:
>>
>> void foo(Function & f)
>> {
>> ... compute something with f
>> }
>>
>> I can't know the dimensions of arguments to f.
>> This means I can't write generic code to do something with Functions.
>
> One of the simplifying assumptions we made a while back when
> redesigning the Function classes was that a Function always has a
> FunctionSpace. This still seems to be a good assumption and perhaps we
> should enforce it even stronger than we do now.
>
> It would also make it easy to check for errors during assembly. The
> form knows the correct FunctionSpace and the assembler may compare
> that FunctionSpace against the FunctionSpace of the Function.
I'm happy with "a Function always has a FunctionSpace" concept if it is
strictly enforced at construction time. The current situation is not so,
and since I'm allowed to create a user function without a function space
I expect to be able to use it where it makes sense.
C++ is often much easier to work with if objects are completely initialized at
construction time, then there are a lot of mistakes you're just not
allowed to make.
>> > I don't think having rank(), dim(), geometric_dimension() as mandatory
>> > in the Function interface would help. I've seen more examples of
>> > programs breaking from rank() and dim() being implemented incorrectly
>> > than I've seen programs breaking from eval() being implemented
>> > incorrectly. And no error-checking can save a user from typing
>> >
>> > values[100] = x[30]
>> >
>> > inside eval(), unless we move away from arrays to some bounds-checking
>> > type for the arguments to eval.
>>
>> Ok, it probably isn't a big problem to not have a check for this in assembly.
>> The main error this kind of check used to catch was mismatch between
>> function argument order in forms, which isn't a problem anymore.
>>
>>
>> >> > The geometric dimension is proably deducable from other places during
>> >> > assemble.
>> >>
>> >> Of course, but that doesn't guarantee that the Function and the Form
>> >> uses the same dimensions. Error checking is _the_ reason for
>> >> making the user provide this information explicitly.
>> >>
>> >> The point of having explicit rank in a Function is not that the expected
>> >> rank isn't available during assembly, but because the actual rank of the
>> >> Function should be _checked against_ the rank expected for the form argument.
>> >>
>> >> In general, I find it very frustrating that DOLFIN has so little
>> >> error checking.
>> >
>> > No one objects to error-checking. Error-checking is good and we should
>> > do more of it. Feel free to add as much as you like. Make sure to
>> > include clear and sensible error messages.
>>
>> I'm sorry, I don't have any time to donate for this, my time is
>> better spent with UFL anyway.
>>
>> I'm trying to adapt a habit of always documenting my assumptions
>> of input arguments to a function with checks and assertions.
>> It's way harder to add checks to other peoples code or code I
>> wrote myself long ago.
>>
>> I believe the only way to do better at this point is if everybody
>> starts writing checks whenever new code is added or old
>> code is modified. It also makes reading code easier!
>
> Yes, that works fine if you know what you want to do from the start,
> but I find that the design is often evolving and I wouldn't know which
> unit tests to write until the code is finished.
Tests are hard, I know... But here I was thinking about simple
things like matching dimensions and vector sizes etc.
Martin
Follow ups
References