DUNE PDELab (git)

enabledifferentiabilitycheck.hh
1#ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_TEST_ENABLEDIFFERENTIABILITYCHECK_HH
2#define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_TEST_ENABLEDIFFERENTIABILITYCHECK_HH
3
4// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file AUTHORS.md
5// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception OR LGPL-3.0-or-later
6#include <optional>
7
8#include <dune/common/test/testsuite.hh>
9#include <dune/common/transpose.hh>
10
12
13#include <dune/typetree/traversal.hh>
14
15template <class Element, class GridView>
16std::string elementStr(const Element &element, const GridView &gridView);
17
18// Flag to enable a local continuity check for checking partial
19// differentiability across an intersection within checkBasisDifferentiability().
20//
21// For each inside basis function this will compute the jump against
22// zero or the corresponding inside basis function. The latter is then
23// checked for being (up to a tolerance) zero on a set of quadrature points.
24struct EnableDifferentiabilityCheck
25{
26 std::size_t order_ = 5;
27 double tol_ = 1e-10;
28 std::string checkLocation = "across";
29
30 template <class JumpEvaluator, class QuadRuleFactoryMethod>
31 auto localJumpDifferentiabilityCheck(const JumpEvaluator &jumpEvaluator,
32 const QuadRuleFactoryMethod &quadRuleFactoryMethod,
33 std::size_t order, double tol) const
34 {
35 return [=](const auto &intersection, const auto &treePath, const auto &insideNode,
36 const auto &outsideNode, const auto &insideToOutside)
37 {
38 // using Intersection = std::decay_t<decltype(intersection)>;
39 using Node = std::decay_t<decltype(insideNode)>;
40
41 std::vector<int> isDifferentiable(insideNode.size(), true);
42 const auto &quadRule = quadRuleFactoryMethod(intersection, order);
43
44 // using Range = typename Node::FiniteElement::Traits::LocalBasisType::Traits::RangeType;
45 using JacobiRange =
46 typename Node::FiniteElement::Traits::LocalBasisType::Traits::JacobianType;
47 std::vector<std::vector<JacobiRange>> insideValues;
48 std::vector<std::vector<JacobiRange>> outsideValues;
49
50 // Evaluate inside and outside basis functions.
51 insideValues.resize(quadRule.size());
52 outsideValues.resize(quadRule.size());
53
54 std::size_t insideNodeSize = insideNode.finiteElement().localBasis().size();
55 std::size_t outsideNodeSize = outsideNode.finiteElement().localBasis().size();
56
57 for (std::size_t k = 0; k < quadRule.size(); ++k)
58 {
59 std::vector<JacobiRange> insideLocalJacobians, outsideLocalJacobians;
60
61 insideLocalJacobians.resize(insideNodeSize);
62 outsideLocalJacobians.resize(outsideNodeSize);
63 insideValues[k].resize(insideNodeSize);
64 outsideValues[k].resize(outsideNodeSize);
65
66 auto insidePoint = intersection.geometryInInside().global(quadRule[k].position());
67 auto outsidePoint = intersection.geometryInOutside().global(quadRule[k].position());
68 insideNode.finiteElement().localBasis().evaluateJacobian(insidePoint,
69 insideLocalJacobians);
70 outsideNode.finiteElement().localBasis().evaluateJacobian(outsidePoint,
71 outsideLocalJacobians);
72 auto insideJacobiInverseTransposed
73 = intersection.inside().geometry().jacobianInverseTransposed(insidePoint);
74 auto outsideJacobiInverseTransposed
75 = intersection.outside().geometry().jacobianInverseTransposed(outsidePoint);
76 for (std::size_t i = 0; i < insideNodeSize; ++i)
77 {
78 // TODO make this viable for localJac of type FieldVector (at least)
79 insideValues[k][i] = insideLocalJacobians[i] * transpose(insideJacobiInverseTransposed);
80 if (i < outsideNodeSize)
81 outsideValues[k][i]
82 = outsideLocalJacobians[i] * transpose(outsideJacobiInverseTransposed);
83 }
84 }
85
86 // Check jump against outside basis function or zero.
87 for (std::size_t i = 0; i < insideNode.size(); ++i)
88 {
89 for (std::size_t k = 0; k < quadRule.size(); ++k)
90 {
91 auto jump = insideValues[k][i];
92 if (insideToOutside[i].has_value())
93 jump -= outsideValues[k][insideToOutside[i].value()];
94 isDifferentiable[i] = isDifferentiable[i]
95 and (jumpEvaluator(jump, intersection, quadRule[k].position()) < tol);
96 }
97 }
98 for (std::size_t k = 0; k < quadRule.size(); ++k)
99 {
100 insideValues[k].clear();
101 outsideValues[k].clear();
102 }
103 return isDifferentiable;
104 };
105 }
106
107 auto localDifferentiabilityCheck() const
108 {
109 auto jumpNorm = [](auto &&jump, auto &&intersection, auto &&x) -> double
110 { return jump.infinity_norm(); };
111
112 auto quadRuleProvider = [](auto &&intersection, auto &&order)
113 {
114 return Dune::QuadratureRules<double, std::decay_t<decltype(intersection)>::mydimension>::rule(intersection.type(),
115 order);
116 };
117
118 return localJumpDifferentiabilityCheck(jumpNorm, quadRuleProvider, order_, tol_);
119 }
120};
121
122struct EnableVertexDifferentiabilityCheck: public EnableDifferentiabilityCheck
123{
124 std::size_t order_ = 5;
125 double tol_ = 1e-10;
126 std::string checkLocation = "at vertices of";
127
128 auto localDifferentiabilityCheck() const
129 {
130 auto jumpNorm = [](auto &&jump, auto &&intersection, auto &&x) -> double
131 { return jump.infinity_norm(); };
132
133 auto quadRuleProvider = [](auto &&intersection, auto &&order)
134 {
135 using Pt = Dune::QuadraturePoint<double, std::decay_t<decltype(intersection)>::mydimension>;
136 std::vector<Pt> quadRule;
137 for (int i = 0; i < intersection.geometry().corners(); ++i)
138 quadRule.push_back(
139 Pt{intersection.geometry().local(intersection.geometry().corner(i)), 1.});
140 return quadRule;
141 };
142
143 return localJumpDifferentiabilityCheck(jumpNorm, quadRuleProvider, order_, tol_);
144 }
145};
146
147struct EnableNormalDifferentiabilityAtMidpointsCheck: public EnableDifferentiabilityCheck
148{
149 std::size_t order_ = 5;
150 double tol_ = 1e-10;
151 std::string checkLocation = "at edge midpoint of";
152
153 auto localDifferentiabilityCheck() const
154 {
155 auto jumpNorm = [](auto &&jump, auto &&intersection, auto &&x) -> double
156 {
158 jump.mv(intersection.unitOuterNormal(x), res);
159 return res.infinity_norm();
160 };
161
162 auto quadRuleProvider = [](auto &&intersection, auto &&order)
163 {
164 using Pt = Dune::QuadraturePoint<double, std::decay_t<decltype(intersection)>::mydimension>;
165 std::vector<Pt> quadRule;
166
167 quadRule.push_back(Pt{intersection.geometry().local(intersection.geometry().center()), 1.});
168 return quadRule;
169 };
170
171 return localJumpDifferentiabilityCheck(jumpNorm, quadRuleProvider, order_, tol_);
172 }
173};
174
175/*
176 * Check if basis functions are differentiable across faces.
177 * Differeniability is checked by evaluation at a set of quadrature points
178 * from a quadrature rule of given order, or at a given set of points, like vertices/ center, etc.
179 * If two basis functions (on neighboring elements) share the same
180 * global index, their derivatives at the quadrature points (located on
181 * their intersection) should coincide up to the given tolerance.
182 *
183 * If a basis function only appears on one side of the intersection,
184 * it should be zero on the intersection.
185 */
186template <class Basis, class Flag>
187Dune::TestSuite checkBasisDifferentiability(const Basis &basis, const Flag &flag)
188{
189 Dune::TestSuite test("Global differentiability check of basis functions");
190
191 auto const &localCheck = flag.localDifferentiabilityCheck();
192
193 auto localView = basis.localView();
194 auto neighborLocalView = basis.localView();
195
196 for (const auto &e : elements(basis.gridView()))
197 {
198 localView.bind(e);
199 for (const auto &intersection : intersections(basis.gridView(), e))
200 {
201 if (intersection.neighbor())
202 {
203 neighborLocalView.bind(intersection.outside());
204
206 localView.tree(),
207 [&](const auto &insideNode, auto &&treePath)
208 {
209 const auto &outsideNode = Dune::TypeTree::child(neighborLocalView.tree(), treePath);
210
211 std::vector<std::optional<int>> insideToOutside;
212 insideToOutside.resize(insideNode.size());
213
214 // Map all inside DOFs to outside DOFs if possible
215 for (std::size_t i = 0; i < insideNode.size(); ++i)
216 {
217 for (std::size_t j = 0; j < outsideNode.size(); ++j)
218 {
219 if (localView.index(insideNode.localIndex(i))
220 == neighborLocalView.index(outsideNode.localIndex(j)))
221 {
222 // Basis function should only appear once in the neighbor element.
223 test.check(not insideToOutside[i].has_value())
224 << "Basis function " << localView.index(insideNode.localIndex(i))
225 << " appears twice in element "
226 << elementStr(neighborLocalView.element(), basis.gridView());
227 insideToOutside[i] = j;
228 }
229 }
230 }
231
232 // Apply continuity check on given intersection with given inside/outside DOF node
233 // pair.
234 auto isDifferentiable
235 = localCheck(intersection, treePath, insideNode, outsideNode, insideToOutside);
236
237 for (std::size_t i = 0; i < insideNode.size(); ++i)
238 {
239 test.check(isDifferentiable[i])
240 << "Basis function " << localView.index(insideNode.localIndex(i))
241 << " is not differentiable " << flag.checkLocation
242 << " intersection of elements "
243 << elementStr(localView.element(), basis.gridView()) << " and "
244 << elementStr(neighborLocalView.element(), basis.gridView());
245 }
246 });
247 }
248 }
249 }
250 return test;
251}
252#endif
FieldTraits< vt >::real_type infinity_norm() const
infinity norm (maximum of absolute values of entries)
Definition: densevector.hh:661
vector space out of a tensor product of fields.
Definition: fvector.hh:91
Single evaluation point in a quadrature rule.
Definition: quadraturerules.hh:66
A container for all quadrature rules of dimension dim
Definition: quadraturerules.hh:260
A Simple helper class to organize your test suite.
Definition: testsuite.hh:31
IteratorRange<... > intersections(const GV &gv, const Entity &e)
Iterates over all Intersections of an Entity with respect to the given GridView.
IteratorRange<... > elements(const GV &gv)
Iterates over all elements / cells (entities with codimension 0) of a GridView.
constexpr auto treePath(const T &... t)
Constructs a new HybridTreePath from the given indices.
Definition: treepath.hh:326
void forEachLeafNode(Tree &&tree, LeafFunc &&leafFunc)
Traverse tree and visit each leaf node.
Definition: traversal.hh:269
auto transpose(const Matrix &matrix)
Return the transposed of the given matrix.
Definition: transpose.hh:183
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Nov 24, 23:30, 2024)