Hans Petter Langtangen wrote: > I think users will find it strange that a Constant and Expression must > be associated with a mesh. Why not allow > > g = Constant(6.0) > f = Expression('sin(x[0])') > > For quadrature one only needs to evaluate a Constant or Expression so > I don't see any need for a mesh or space if there are other components > in the form that have a space or mesh to be used for integration.
We need to re-assess the design around Constant/Expression/Function. We've lost our way a little with the re-designs around the function classes. A first step is to clean up some issues on the C++ side (like why we need the geometric dimension) which will trickle down to the Python side. The following step would be to address some of the Python-specific issues. Now that we have Expression, perhaps we should get rid of Constant since g = Constant(6.0) h = Expression('6.0') serve essentially the same purpose (a small difference, at least on the C++ side, is that a Constant can be treated as a double, e.g. it can be incremented). For an Expression, we may be able to default to a QuadratureFunction to avoid providing the mesh/function space at initialisation. The possible issue at present is that UFL may insist on the order of the QuadratureFunction being known, but this could be changed in UFL. > (The mesh determines the no of space dimensions and the length of the > x argument when an Expression is evaluated.) > > For non-quadrature approaches, f must be interpolated onto a space > and an error message could tell the user to explicitly do so. > > In case one does > > M = f*dx # or g*dx > assemble(M) > > the form or assemble lacks a mesh to do the integration and then an > error message can be issued, telling the user to insert a mesh or > space argument in assemble (I think this is more logical than > attaching a mesh or space to f). I would guess that one needs a space > and not only a mesh since it's otherwise hard to figure out the > appropriate order of the quadrature rule? > > In situations where grad(f) is needed, one must follow Doug's suggestion > and explicitly interpolate: > > f_approx = interpolate(f, V) > dot(grad(f_approx), grad(u))*dx > > grad(Expression) should just give an error message saying that the > operation is impossible, which is intuitive: it's a formula and there is no > information about the derivative. (The optimal solution would be to > accept an eval_derivative function or an optional string for the > derivative: Expression('sin(x[0])', derivative=['cos(x[0])', 0, 0])). > This could be added easily. > In most cases, an Expression enters a form together with other quantities > that have associated function spaces. Isn't that sufficient? > If one is happy to evaluate the Expression at quadrature points but let the form compiler determine the number of points, this should be OK. > As a tutorial writer, it is quite a problem to explain why the very > simplest examples have non-intuitive constructions when everything else > in FEniCS is so intuitive. > It's very useful to have the perspective of the tutorial writer! Garth > These suggestions come from a naive user's point of view - I realize > that some of the ideas may be impossible because of inner workings in > UFL/DOLFIN/PyDOLFIN. My main point is to start with what's intuitive > and then issue error messages when a mesh or space needs to be > associated with a Constant or Expression. > > Hans Petter > > > Fri, 13 Nov Anders Logg wrote: >> On Fri, Nov 13, 2009 at 09:46:21AM +0000, Garth N. Wells wrote: >>> >>> Anders Logg wrote: >>>> On Fri, Nov 13, 2009 at 08:18:38AM +0000, Garth N. Wells wrote: >>>>> Anders Logg wrote: >>>>>> On Fri, Nov 13, 2009 at 07:28:07AM +0100, Johan Hake wrote: >>>>>>> On Thursday 12 November 2009 21:15:51 Anders Logg wrote: >>>>>>>> I have received some complaints on the new Expression class. It works >>>>>>>> reasonably well from C++ but is still confusing from Python: >>>>>>>> >>>>>>>> 1. Why does a function space need to be specified in the constructor? >>>>>>>> >>>>>>>> f = Expression("sin(x[0])", V=V) >>>>>>>> >>>>>>>> Does this mean f is a function on V? (No, it doesn't.) >>>>>>>> >>>>>>>> 2. The keyword argument V=foo is confusing: >>>>>>>> >>>>>>>> f = Expression(("sin(x[0])", "cos(x[1])"), V=V) >>>>>>>> g = Expression("1 - x[0]", V=Q) >>>>>>>> >>>>>>>> The reason for the function space argument V is that we need to know >>>>>>>> how to approximate an expression when it appears in a form. For >>>>>>>> example, when we do >>>>>>>> >>>>>>>> L = dot(v, grad(f))*dx >>>>>>>> >>>>>>>> we need to interpolate f (locally) into a finite element space so we >>>>>>>> can compute the gradient. >>>>>>>> >>>>>>>> Sometimes we also need to know the mesh on which the expression is >>>>>>>> defined: >>>>>>>> >>>>>>>> M = f*dx >>>>>>>> >>>>>>>> This integral can't be computed unless we know the mesh which is why >>>>>>>> one needs to do >>>>>>>> >>>>>>>> assemble(M, mesh=mesh) >>>>>>>> >>>>>>>> My suggestion for fixing these issues is the following: >>>>>>>> >>>>>>>> 1. We require a mesh argument when constructing an expression. >>>>>>>> >>>>>>>> f = Expression("sin(x[0])", mesh) >>>>>>>> >>>>>>>> 2. We allow an optional argument for specifying the finite element. >>>>>>>> >>>>>>>> f = Expression("sin(x[0])", mesh, element) >>>>>>>> >>>>> We could also have >>>>> >>>>> f = Expression("sin(x[0])", mesh, k) >>>>> >>>>> where k is the order of the continuous Lagrange basis since that's the >>>>> most commonly used. >>>>> >>>>>>>> 3. When the element is not specified, we choose a simple default >>>>>>>> element which is piecewise linear approximation. We can derive the >>>>>>>> geometric dimension from the mesh and we can derive the value shape >>>>>>>> from the expression (scalar, vector or tensor). >>>>>>>> >>>>> This is bad. If a user increases the polynomial order of the test/trial >>>>> functions and f remains P1, the convergence rate will not be optimal. >>>>> >>>>> A better solution would be to define it on a QuadratureElement by >>>>> default. This, I think, is the behaviour that most people would expect. >>>>> This would take care of higher-order cases. >>>> Yes, I've thought about this. That would perhaps be the best solution. >>>> Does a quadrature element have a fixed degree or can the form compiler >>>> adjust it later to match the degree of for example the basis functions >>>> in the form? >>>> >>> Kristian? >>> >>>> If one should happen to differentiate a coefficient in a form, we just >>>> need to give an informative error message and advise that one needs to >>>> specify a finite element for the approximation of the coefficient. >>>> >>>>>>>> This will remove the need for the V argument and the confusion about >>>>>>>> whether an expression is defined on some function space (which it is >>>>>>>> not). >>>>> But it is when it's used in a form since it's interpolated in the given >>>>> space. >>>> The important point is that we only need to be able to interpolate it >>>> locally to any given cell in the mesh, so we just need a mesh and a >>>> cell. The dofmap is never used so it's different from a full function >>>> space. >>>> >>> I think you mean element rather than cell? >> I actually meant cell. But the restriction operator (extracting the >> information we need to integrate over the cell) requires an element >> (which implements evaluate_dof). >> >> -- >> Anders >> >> >>> Garth >>> >>>>>>>> It also removes the need for an additional mesh=mesh argument >>>>>>>> when assembling functionals and computing norms. >>>>>>>> >>>>>>>> This change will make the Constant and Expression constructors very >>>>>>>> similar in that they require a value and a mesh (and some optional >>>>>>>> stuff). Therefore it would be good to change the order of the >>>>>>>> arguments in Constant so they are the same as in Expression: >>>>>>>> >>>>>>>> f = Constant(0, mesh) >>>>>>>> f = Expression("0", mesh) >>>>>>>> >>>>> Yes. >>>> Good. >>>> >>>>>>>> And we should change Constant rather than Expression since Expression >>>>>>>> might have an optional element argument: >>>>>>>> >>>>>>>> f = Expression("0", mesh, element) >>>>>>>> >>>>>>>> Does this sound good? >>>>>>> Yes, I think so. I suppose you mean >>>>>>> >>>>>>> f = CompiledExpression("0", mesh) >>>>>>> >>>>>>> Just referring to the Blueprint about the simplification of the >>>>>>> Expression >>>>>>> class in PyDOLFIN. >>>>>> I'm not so sure anymore. Calling it Expression looks simpler. >>>>> Agree. >>>> Good. >>>> >>>>> Garth >>>>> >>>>> What >>>>>> were the reasons for splitting it into Expression and >>>>>> CompiledExpression? Is it the problem with the non-standard >>>>>> constructor when implementing subclasses? >>>>>> >>>>>> It's just that the most common use of expressions in simple demos will >>>>>> be stuff like >>>>>> >>>>>> f = Expression("sin(x([0])", mesh) >>>>>> >>>>>> so one could argue that this should be as simple as possible (and just >>>>>> be named Expression). >>>>>> >>>>>>> Should an Expression in PyDOLFIN then always have a mesh? This will >>>>>>> make an >>>>>>> Expression in PyDOLFIN and DOLFIN different, which is fine with me. >>>>>> Yes, to avoid needing to pass the mesh to assemble() and norm() in >>>>>> some cases and to automatically get the geometric dimension. >>>>>> >>>>>>> If others agree, can you add it to the Blueprint, mentioned above, and >>>>>>> I can >>>>>>> do the change some time next week, or after a release (?). >>>>>> Let's hear some more comments first. >>>>>> >>>>> _______________________________________________ >>>>> DOLFIN-dev mailing list >>>>> DOLFIN-dev@fenics.org >>>>> http://www.fenics.org/mailman/listinfo/dolfin-dev >>> _______________________________________________ >>> DOLFIN-dev mailing list >>> DOLFIN-dev@fenics.org >>> http://www.fenics.org/mailman/listinfo/dolfin-dev > > _______________________________________________ DOLFIN-dev mailing list DOLFIN-dev@fenics.org http://www.fenics.org/mailman/listinfo/dolfin-dev