3#ifndef DUNE_LOCALFUNCTIONS_TEST_TEST_LOCALFE_HH
4#define DUNE_LOCALFUNCTIONS_TEST_TEST_LOCALFE_HH
20#include <dune/geometry/referenceelements.hh>
22#include <dune/localfunctions/common/virtualinterface.hh>
23#include <dune/localfunctions/common/virtualwrappers.hh>
28double jacobianTOL = 1e-5;
33class ShapeFunctionAsFunction :
39 typedef typename FE::Traits::LocalBasisType::Traits::DomainType DomainType;
40 typedef typename FE::Traits::LocalBasisType::Traits::RangeType RangeType;
43 typedef typename FE::Traits::LocalBasisType::Traits::RangeFieldType CT;
45 ShapeFunctionAsFunction(
const FE& fe,
int shapeFunction) :
47 shapeFunction_(shapeFunction)
50 void evaluate (
const DomainType& x, RangeType& y)
const
52 std::vector<RangeType> yy;
53 fe_.localBasis().evaluateFunction(x, yy);
54 y = yy[shapeFunction_];
67bool testLocalInterpolation(
const FE& fe)
69 std::vector<typename ShapeFunctionAsFunction<FE>::CT> coeff;
70 for(
size_t i=0; i<fe.size(); ++i)
73 ShapeFunctionAsFunction<FE> f(fe, i);
77 fe.localInterpolation().interpolate(f, coeff);
80 if (coeff.size() != fe.localBasis().size())
82 std::cout <<
"Bug in LocalInterpolation for finite element type "
84 std::cout <<
" Interpolation produces " << coeff.size() <<
" degrees of freedom" << std::endl;
85 std::cout <<
" Basis has size " << fe.localBasis().size() << std::endl;
86 std::cout << std::endl;
91 for(std::size_t j=0; j<coeff.size(); ++j)
93 if ( std::abs(coeff[j] - (i==j)) > TOL)
95 std::cout << std::setprecision(16);
96 std::cout <<
"Bug in LocalInterpolation for finite element type "
98 std::cout <<
" Degree of freedom " << j <<
" applied to shape function " << i
99 <<
" yields value " << coeff[j] <<
", not the expected value " << (i==j) << std::endl;
100 std::cout << std::endl;
111bool testJacobian(
const FE& fe,
unsigned order = 2)
113 typedef typename FE::Traits::LocalBasisType LB;
127 for (
size_t i=0; i<quad.size(); i++) {
134 std::vector<typename LB::Traits::JacobianType> jacobians;
135 fe.localBasis().evaluateJacobian(testPoint, jacobians);
136 if(jacobians.size() != fe.localBasis().size()) {
137 std::cout <<
"Bug in evaluateJacobianGlobal() for finite element type "
139 std::cout <<
" Jacobian vector has size " << jacobians.size()
141 std::cout <<
" Basis has size " << fe.localBasis().size()
143 std::cout << std::endl;
148 for (
int k=0; k<LB::Traits::dimDomain; k++) {
154 upPos[k] += jacobianTOL;
155 downPos[k] -= jacobianTOL;
157 std::vector<typename LB::Traits::RangeType> upValues, downValues;
159 fe.localBasis().evaluateFunction(upPos, upValues);
160 fe.localBasis().evaluateFunction(downPos, downValues);
163 for (
unsigned int j=0; j<fe.localBasis().size(); ++j) {
165 for(
int l=0; l < LB::Traits::dimRange; ++l) {
168 double derivative = jacobians[j][l][k];
170 double finiteDiff = (upValues[j][l] - downValues[j][l])
174 if ( std::abs(derivative-finiteDiff) >
175 TOL/jacobianTOL*((std::abs(finiteDiff)>1) ? std::abs(finiteDiff) : 1.) )
177 std::cout << std::setprecision(16);
178 std::cout <<
"Bug in evaluateJacobian() for finite element type "
180 std::cout <<
" Shape function derivative does not agree with "
181 <<
"FD approximation" << std::endl;
182 std::cout <<
" Shape function " << j <<
" component " << l
183 <<
" at position " << testPoint <<
": derivative in "
184 <<
"direction " << k <<
" is " << derivative <<
", but "
185 << finiteDiff <<
" is expected." << std::endl;
186 std::cout << std::endl;
204 static bool test(
const FE& fe,
205 double eps,
double delta,
unsigned int diffOrder, std::size_t order = 2)
210 std::cout <<
"No test for differentiability orders larger than 2!" << std::endl;
213 success = success and
testOrder2(fe, eps, delta, order);
216 success = success and
testOrder1(fe, eps, delta, order);
218 success = success and
testOrder0(fe, eps, delta, order);
228 std::size_t order = 2)
230 typedef typename FE::Traits::LocalBasisType::Traits::RangeType RangeType;
231 constexpr auto dimDomain = FE::Traits::LocalBasisType::Traits::dimDomain;
245 for (
size_t i = 0; i < quad.size(); i++)
251 std::vector<RangeType> partialValues;
252 std::array<unsigned int, dimDomain> multiIndex;
253 std::fill(multiIndex.begin(), multiIndex.end(), 0);
255 fe.localBasis().partial(multiIndex, testPoint, partialValues);
257 if (partialValues.size() != fe.localBasis().size())
259 std::cout <<
"Bug in partial() for finite element type "
261 std::cout <<
" values vector has size "
262 << partialValues.size() << std::endl;
263 std::cout <<
" Basis has size " << fe.localBasis().size()
265 std::cout << std::endl;
270 std::vector<RangeType> referenceValues;
271 fe.localBasis().evaluateFunction(testPoint, referenceValues);
274 for (
unsigned int j = 0; j < fe.localBasis().size(); ++j)
277 for (
int l = 0; l < FE::Traits::LocalBasisType::Traits::dimRange; ++l)
280 if (std::abs(partialValues[j][l] - referenceValues[j][l])
282 * ((std::abs(referenceValues[j][l]) > 1) ? std::abs(referenceValues[j][l]) : 1.))
284 std::cout << std::setprecision(16);
285 std::cout <<
"Bug in partial() for finite element type "
287 std::cout <<
" Shape function value does not agree with "
288 <<
"output of method evaluateFunction." << std::endl;
289 std::cout <<
" Shape function " << j <<
" component " << l
290 <<
" at position " << testPoint <<
": value is " << partialValues[j][l]
291 <<
", but " << referenceValues[j][l] <<
" is expected." << std::endl;
292 std::cout << std::endl;
308 std::size_t order = 2)
310 typedef typename FE::Traits::LocalBasisType LB;
311 typedef typename LB::Traits::RangeFieldType RangeField;
326 for (
size_t i = 0; i < quad.size(); i++)
332 for (
int k = 0; k < LB::Traits::dimDomain; k++)
335 std::vector<typename LB::Traits::RangeType> firstPartialDerivatives;
336 std::array<unsigned int, LB::Traits::dimDomain> multiIndex;
337 std::fill(multiIndex.begin(), multiIndex.end(), 0);
339 fe.localBasis().partial(multiIndex, testPoint, firstPartialDerivatives);
340 if (firstPartialDerivatives.size() != fe.localBasis().size())
342 std::cout <<
"Bug in partial() for finite element type "
344 std::cout <<
" firstPartialDerivatives vector has size "
345 << firstPartialDerivatives.size() << std::endl;
346 std::cout <<
" Basis has size " << fe.localBasis().size()
348 std::cout << std::endl;
356 upPos[k] += jacobianTOL;
357 downPos[k] -= jacobianTOL;
359 std::vector<typename LB::Traits::RangeType> upValues, downValues;
361 fe.localBasis().evaluateFunction(upPos, upValues);
362 fe.localBasis().evaluateFunction(downPos, downValues);
365 for (
unsigned int j = 0; j < fe.localBasis().size(); ++j)
368 for (
int l = 0; l < LB::Traits::dimRange; ++l)
370 RangeField finiteDiff = (upValues[j][l] - downValues[j][l])
374 RangeField partialDerivative = firstPartialDerivatives[j][l];
375 if (std::abs(partialDerivative - finiteDiff)
377 * ((std::abs(finiteDiff) > 1) ? std::abs(finiteDiff) : 1.))
379 std::cout << std::setprecision(16);
380 std::cout <<
"Bug in partial() for finite element type "
382 std::cout <<
" Shape function derivative does not agree with "
383 <<
"FD approximation" << std::endl;
384 std::cout <<
" Shape function " << j <<
" component " << l
385 <<
" at position " << testPoint <<
": derivative in "
386 <<
"direction " << k <<
" is " << partialDerivative <<
", but "
387 << finiteDiff <<
" is expected." << std::endl;
388 std::cout << std::endl;
405 std::size_t order = 2)
407 typedef typename FE::Traits::LocalBasisType LocalBasis;
408 typedef typename LocalBasis::Traits::DomainFieldType DF;
409 typedef typename LocalBasis::Traits::DomainType Domain;
410 static const int dimDomain = LocalBasis::Traits::dimDomain;
412 static const std::size_t dimR = LocalBasis::Traits::dimRange;
413 typedef typename LocalBasis::Traits::RangeType Range;
414 typedef typename LocalBasis::Traits::RangeFieldType RangeField;
428 for (std::size_t i = 0; i < quad.size(); i++)
431 const Domain& testPoint = quad[i].position();
434 std::array<std::vector<Dune::FieldMatrix<RangeField, dimDomain, dimDomain> >, dimR> partialHessians;
435 for (
size_t k = 0; k < dimR; k++)
436 partialHessians[k].resize(fe.size());
439 for (
int dir0 = 0; dir0 < dimDomain; dir0++)
441 for (
int dir1 = 0; dir1 < dimDomain; dir1++)
444 std::vector<Range> secondPartialDerivative;
445 std::array<unsigned int,dimDomain> multiIndex;
446 std::fill(multiIndex.begin(), multiIndex.end(), 0);
449 fe.localBasis().partial(multiIndex, testPoint, secondPartialDerivative);
451 if (secondPartialDerivative.size() != fe.localBasis().size())
453 std::cout <<
"Bug in partial() for finite element type "
454 << Dune::className<FE>() <<
":" << std::endl;
455 std::cout <<
" return vector has size " << secondPartialDerivative.size()
457 std::cout <<
" Basis has size " << fe.localBasis().size()
459 std::cout << std::endl;
464 for (
size_t k = 0; k < dimR; k++)
465 for (std::size_t j = 0; j < fe.localBasis().size(); ++j)
466 partialHessians[k][j][dir0][dir1] = secondPartialDerivative[j][k];
472 for (std::size_t dir0 = 0; dir0 < dimDomain; ++dir0)
474 for (
unsigned int dir1 = 0; dir1 < dimDomain; dir1++)
477 std::array<Domain,4> neighbourPos;
478 std::fill(neighbourPos.begin(), neighbourPos.end(), testPoint);
480 neighbourPos[0][dir0] += delta;
481 neighbourPos[0][dir1] += delta;
482 neighbourPos[1][dir0] -= delta;
483 neighbourPos[1][dir1] += delta;
484 neighbourPos[2][dir0] += delta;
485 neighbourPos[2][dir1] -= delta;
486 neighbourPos[3][dir0] -= delta;
487 neighbourPos[3][dir1] -= delta;
489 std::array<std::vector<Range>, 4> neighbourValues;
490 for (
int k = 0; k < 4; k++)
491 fe.localBasis().evaluateFunction(neighbourPos[k],
495 for (std::size_t j = 0; j < fe.localBasis().size(); ++j)
498 for (std::size_t k = 0; k < dimR; ++k)
500 RangeField finiteDiff = (neighbourValues[0][j][k]
501 - neighbourValues[1][j][k] - neighbourValues[2][j][k]
502 + neighbourValues[3][j][k]) / (4 * delta * delta);
505 RangeField partialDerivative = partialHessians[k][j][dir0][dir1];
508 if (std::abs(partialDerivative - finiteDiff)
509 > eps / delta * (std::max(std::abs(finiteDiff), 1.0)))
511 std::cout << std::setprecision(16);
512 std::cout <<
"Bug in partial() for finite element type "
513 << Dune::className<FE>() <<
":" << std::endl;
514 std::cout <<
" Second shape function derivative does not agree with "
515 <<
"FD approximation" << std::endl;
516 std::cout <<
" Shape function " << j <<
" component " << k
517 <<
" at position " << testPoint <<
": derivative in "
518 <<
"local direction (" << dir0 <<
", " << dir1 <<
") is "
519 << partialDerivative <<
", but " << finiteDiff
520 <<
" is expected." << std::endl;
521 std::cout << std::endl;
539 DisableLocalInterpolation = 1,
540 DisableVirtualInterface = 2,
547bool testFE(
const FE& fe,
char disabledTests = DisableNone,
unsigned int diffOrder = 0)
550 unsigned int quadOrder = 2;
554 if (FE::Traits::LocalBasisType::Traits::dimDomain != fe.type().dim())
556 std::cout <<
"Bug in type() for finite element type "
558 std::cout <<
" Coordinate dimension is " << FE::Traits::LocalBasisType::Traits::dimDomain << std::endl;
559 std::cout <<
" but GeometryType is " << fe.type() <<
" with dimension " << fe.type().dim() << std::endl;
563 if (fe.size() != fe.localBasis().size())
565 std::cout <<
"Bug in finite element type "
567 std::cout <<
" Size reported by LocalFiniteElement is " << fe.size() << std::endl;
568 std::cout <<
" but size reported by LocalBasis is " << fe.localBasis().size() << std::endl;
573 std::vector<typename FE::Traits::LocalBasisType::Traits::RangeType> values;
576 if (values.size() != fe.size())
578 std::cout <<
"Bug in finite element type "
580 std::cout <<
" LocalFiniteElement.size() returns " << fe.size() <<
"," << std::endl;
581 std::cout <<
" but LocalBasis::evaluateFunction returns " << values.size() <<
" values!" << std::endl;
585 if (fe.size() != fe.localCoefficients().size())
587 std::cout <<
"Bug in finite element type "
589 std::cout <<
" Size reported by LocalFiniteElement is " << fe.size() << std::endl;
590 std::cout <<
" but size reported by LocalCoefficients is " << fe.localCoefficients().size() << std::endl;
594 const auto& lc = fe.localCoefficients();
595 for(
size_t i=0; i<lc.size(); i++)
597 const auto& lk = lc.localKey(i);
598 if (lk.codim() > fe.type().dim())
600 std::cout <<
"Bug in finite element type "
602 std::cout <<
" Codimension reported by localKey(" << i <<
") is " << lk.codim() << std::endl;
603 std::cout <<
" but geometry is " << fe.type() <<
" with dimension " << fe.type().dim() << std::endl;
608 if (not (disabledTests & DisableLocalInterpolation))
610 success = testLocalInterpolation<FE>(fe) and success;
612 if (not (disabledTests & DisableJacobian))
614 success = testJacobian<FE>(fe, quadOrder) and success;
619 success = (diffOrder == 0) and success;
622 if (not (disabledTests & DisableEvaluate))
624 success = TestPartial::test(fe, TOL, jacobianTOL, diffOrder, quadOrder) and success;
627 if (not (disabledTests & DisableVirtualInterface))
629 typedef typename FE::Traits::LocalBasisType::Traits ImplementationLBTraits;
633 const VirtualFEImp virtualFE(fe);
634 if (not (disabledTests & DisableLocalInterpolation))
635 success = testLocalInterpolation<VirtualFEInterface>(virtualFE) and success;
636 if (not (disabledTests & DisableJacobian))
638 success = testJacobian<VirtualFEInterface>(virtualFE) and success;
643 success = (diffOrder == 0) and success;
650#define TEST_FE(A) { bool b = testFE(A); std::cout << "testFE(" #A ") " << (b?"succeeded\n":"failed\n"); success &= b; }
651#define TEST_FE2(A,B) { bool b = testFE(A, B); std::cout << "testFE(" #A ", " #B ") " << (b?"succeeded\n":"failed\n"); success &= b; }
652#define TEST_FE3(A,B,C) { bool b = testFE(A, B, C); std::cout << "testFE(" #A ", " #B ", " #C ") " << (b?"succeeded\n":"failed\n"); success &= b; }
vector space out of a tensor product of fields.
Definition: fvector.hh:93
void evaluate(const typename Traits::DomainType &x, typename Traits::RangeType &y) const
Function evaluation.
Return a proper base class for functions to use with LocalInterpolation.
Definition: virtualinterface.hh:35
class for wrapping a finite element using the virtual interface
Definition: virtualwrappers.hh:240
virtual base class for local finite elements with functions
Definition: virtualinterface.hh:266
Abstract base class for quadrature rules.
Definition: quadraturerules.hh:97
static const QuadratureRule & rule(const GeometryType &t, int p, QuadratureType::Enum qt=QuadratureType::GaussLegendre)
select the appropriate QuadratureRule for GeometryType t and order p
Definition: quadraturerules.hh:225
A free function to provide the demangled class name of a given object or type as a string.
std::string className()
Provide the demangled class name of a type T as a string.
Definition: classname.hh:26
Class providing access to the singletons of the reference elements.
Definition: referenceelements.hh:168
Helper class to test the 'partial' method.
Definition: test-localfe.hh:202
static bool testOrder0(const FE &fe, double eps, double delta, std::size_t order=2)
Test the 'partial' method for zero-order partial derivatives, i.e., values.
Definition: test-localfe.hh:225
static bool testOrder2(const FE &fe, double eps, double delta, std::size_t order=2)
Test second-order partial derivatives.
Definition: test-localfe.hh:402
static bool testOrder1(const FE &fe, double eps, double delta, std::size_t order=2)
Test the 'partial' method for first-order partial derivatives.
Definition: test-localfe.hh:305