On Thu, Mar 12, 2009 at 5:26 PM, Anders Logg <[email protected]> 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 <[email protected]> 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 <[email protected]> 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 <[email protected]> >> >> >> >> 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 _______________________________________________ DOLFIN-dev mailing list [email protected] http://www.fenics.org/mailman/listinfo/dolfin-dev
