Draft: Add geometry mapped by an element-function
Summary
A geometry that is defined as the mapping of a reference geometry
Details
A geometry can be seen as a class interface representing a reference domain R
plus a mapping f
, such that f(R)
is of the same topology as R
and f
a bijective (diffeomorphic) mapping between R
and f(R)
. The MappedGeometry
provides this interface for a given ReferenceElement
R
and mapping f
.
Additionally, the MappedGeometry
allows to be defined on a different reference domain than associated to the mapping f
. This could be, for example, the domain of a subEntity or element-intersection. In this case, we build a composition of two mappings f
and g
, where g
represents a local-geometry transform between the two reference domains. Let I
be the reference domain of the subEntity and g
the associated geometry mapping (that is bijective between I
and g(I)
), then the MappedGeometry
represents the composition f o g
associated to the reference domain I
.
We require for the local function f
to fulfill some interface to be allowed in this wrapper class. Let lf
be an object of local function, x
be a local coordinate in the reference element of the geometry, then (formulated in c++-20 concepts)
template <class LF, class Range, class Domain, class LocalContext,
class DLF = std::decay_t<decltype(derivative(std::declval<const LF&>())> >
concept LocalFunction = require (const LF& lf, const Domain& x)
{
{ lf(x) } -> std::convertible_to<Range>;
{ lf.localContext() } -> std::convertible_to<LocalContext>;
{ derivative(lf) } -> std::regular_invocable<Domain>;
require (const DLF& dlf, const Domain& x)
{
{ dlf(x) } -> std::convertible_to<typename DerivativeTraits<Range(Domain)>::Range>;
};
};
In this concept we make explicit notion of a "LocalContext" the local-function is associated to. This context refers to an entity or intersection the local-function was bound. This means that the local-function can be evaluated in the local-coordinates of that LocalContext
. We thus require, that the local-context provides also a geometry.
Example 1
This example uses dune-functions, just to make the example short. One can easily define a local function following the test-mappedgeometry.cc
// construct a base grid e.g. with piecewise flat elements
YaspGrid<2> grid({1.0,1.0}, {10,10});
using Domain = FieldVector<double,2>;
using Range = FieldVector<double,3>;
auto sig = Functions::SignatureTag<Range(Domain)>{};
auto f = Functions::makeDifferentiableFunctionFromCallables(sig,
[](const Domain& x) -> FieldVector<double,3> {
return {x[0], x[1], std::sin(x[0] * x[1])};
},
[](const Domain& x) -> FieldMatrix<double,3,2> {
return {
{1.0, 0.0},
{0.0, 1.0},
{x[1] * std::cos(x[0] * x[1]), x[0] * std::cos(x[0] * x[1])}
};
});
// create a differentiable analytic grid function
auto fGridFunction = Functions::makeAnalyticGridViewFunction(f, grid.leafGridView());
// build the corresponding local function
auto fLocalFunction = localFunction(fGridFunction);
for (const auto& e : elements(grid.leafGridView()))
{
// bind the local function to the grid element
fLocalFunction.bind(e);
// construct the mapped geometry
MappedGeometry geometry{referenceElement(e), fLocalFunction};
// unbind the local function from the element
fLocalFunction.unbind();
}
Example 2
In this example also intersection geometries are transformed. Since the local function must be bound to a grid element, we need an additional geometry transformation from the intersection geometry to the element geometry. The local-geometry transform is passed as additional argument. It can also be used to define a geometry on sub-entities of the grid element, by using a reference sub-element geometry mapping.
Let grid
, f
, fGridFunction
, fLocalFunction
be defined as in Example 1.
for (const auto& e : elements(grid.leafGridView()))
{
// bind the local function to the grid element
fLocalFunction.bind(e);
for (const auto& is : intersections(element, grid.leafGridView())
{
// construct the mapped geometry for the intersection
MappedGeometry isGeometry{referenceElement(is), fLocalFunction, is.geometryInInside()};
}
auto refElem = referenceElement(e);
for (int i = 0; i < refElem.size(1); ++i)
{
auto edgeRefElem = referenceElement<double,grid.dimension-1>(refElem.type(i,1));
// construct a mapped geometry for the i'th subentity of codim 1
// NOTE: this required a well-oriented (twist-free) grid
MappedGeometry edgeGeometry{edgeRefElem, fLocalFunction, refElem.geometry<1>(i)};
}
// unbind the local function from the element
fLocalFunction.unbind();
}