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
36 typedef typename FE::Traits::LocalBasisType::Traits::DomainType DomainType;
37 typedef typename FE::Traits::LocalBasisType::Traits::RangeType RangeType;
40 typedef typename FE::Traits::LocalBasisType::Traits::DomainType DomainType;
41 typedef typename FE::Traits::LocalBasisType::Traits::RangeType RangeType;
44 typedef typename FE::Traits::LocalBasisType::Traits::RangeFieldType CT;
46 ShapeFunctionAsFunction(
const FE& fe,
int shapeFunction) :
48 shapeFunction_(shapeFunction)
51 void evaluate (
const DomainType& x, RangeType& y)
const
53 std::vector<RangeType> yy;
54 fe_.localBasis().evaluateFunction(x, yy);
55 y = yy[shapeFunction_];
66class ShapeFunctionAsCallable
69 typedef typename FE::Traits::LocalBasisType::Traits::DomainType DomainType;
70 typedef typename FE::Traits::LocalBasisType::Traits::RangeType RangeType;
73 ShapeFunctionAsCallable(
const FE& fe,
int shapeFunction) :
75 shapeFunction_(shapeFunction)
78 RangeType operator() (DomainType x)
const
80 std::vector<RangeType> yy;
81 fe_.localBasis().evaluateFunction(x, yy);
82 return yy[shapeFunction_];
95bool testLocalInterpolation(
const FE& fe)
97 std::vector<typename ShapeFunctionAsFunction<FE>::CT> coeff;
98 for(
size_t i=0; i<fe.size(); ++i)
107 ShapeFunctionAsFunction<FE> f(fe, i);
111 fe.localInterpolation().interpolate(f, coeff);
114 if (coeff.size() != fe.localBasis().size())
116 std::cout <<
"Bug in LocalInterpolation for finite element type "
118 std::cout <<
" Interpolation produces " << coeff.size() <<
" degrees of freedom" << std::endl;
119 std::cout <<
" Basis has size " << fe.localBasis().size() << std::endl;
120 std::cout << std::endl;
125 for(std::size_t j=0; j<coeff.size(); ++j)
127 if ( std::abs(coeff[j] - (i==j)) > TOL)
129 std::cout << std::setprecision(16);
130 std::cout <<
"Bug in LocalInterpolation for finite element type "
132 std::cout <<
" Degree of freedom " << j <<
" applied to shape function " << i
133 <<
" yields value " << coeff[j] <<
", not the expected value " << (i==j) << std::endl;
134 std::cout << std::endl;
146 ShapeFunctionAsCallable<FE> sfAsCallable(fe, i);
150 fe.localInterpolation().interpolate(sfAsCallable, coeff);
153 if (coeff.size() != fe.localBasis().size())
155 std::cout <<
"Bug in LocalInterpolation for finite element type "
157 std::cout <<
" Interpolation produces " << coeff.size() <<
" degrees of freedom" << std::endl;
158 std::cout <<
" Basis has size " << fe.localBasis().size() << std::endl;
159 std::cout << std::endl;
164 for(std::size_t j=0; j<coeff.size(); ++j)
166 if ( std::abs(coeff[j] - (i==j)) > TOL)
168 std::cout << std::setprecision(16);
169 std::cout <<
"Bug in LocalInterpolation for finite element type "
171 std::cout <<
" Degree of freedom " << j <<
" applied to shape function " << i
172 <<
" yields value " << coeff[j] <<
", not the expected value " << (i==j) << std::endl;
173 std::cout << std::endl;
185bool testCanRepresentConstants(
const FE& fe,
188 typedef typename FE::Traits::LocalBasisType LB;
189 using RangeType =
typename LB::Traits::RangeType;
194 auto constantOne = [](
const typename LB::Traits::DomainType& xi) {
return RangeType(1.0); };
197 std::vector<double> coefficients;
198 fe.localInterpolation().interpolate(constantOne, coefficients);
204 for (
size_t i=0; i<quad.size(); i++) {
207 const auto& testPoint = quad[i].position();
210 std::vector<RangeType> values;
211 fe.localBasis().evaluateFunction(testPoint, values);
214 for (
size_t j=0; j<values.size(); j++)
215 sum += coefficients[j] * values[j];
217 if ((RangeType(1.0)-sum).two_norm() > TOL)
220 <<
" cannot represent constant functions!" << std::endl;
221 std::cout <<
" At position: " << testPoint <<
","
223 std::cout <<
" discrete approximation of the '1' function has value " << sum
225 std::cout << std::endl;
236bool testJacobian(
const FE& fe,
238 const std::function<
bool(
const typename FE::Traits::LocalBasisType::Traits::DomainType&)> derivativePointSkip =
nullptr)
240 typedef typename FE::Traits::LocalBasisType LB;
254 for (
size_t i=0; i<quad.size(); i++) {
261 std::vector<typename LB::Traits::JacobianType> jacobians;
262 fe.localBasis().evaluateJacobian(testPoint, jacobians);
263 if(jacobians.size() != fe.localBasis().size()) {
264 std::cout <<
"Bug in evaluateJacobian() for finite element type "
266 std::cout <<
" Jacobian vector has size " << jacobians.size()
268 std::cout <<
" Basis has size " << fe.localBasis().size()
270 std::cout << std::endl;
275 if (derivativePointSkip && derivativePointSkip(quad[i].position()))
279 for (
int k=0; k<LB::Traits::dimDomain; k++) {
285 upPos[k] += jacobianTOL;
286 downPos[k] -= jacobianTOL;
288 std::vector<typename LB::Traits::RangeType> upValues, downValues;
290 fe.localBasis().evaluateFunction(upPos, upValues);
291 fe.localBasis().evaluateFunction(downPos, downValues);
294 for (
unsigned int j=0; j<fe.localBasis().size(); ++j) {
296 for(
int l=0; l < LB::Traits::dimRange; ++l) {
301 double finiteDiff = (upValues[j][l] - downValues[j][l])
306 TOL/jacobianTOL*((std::abs(finiteDiff)>1) ? std::abs(finiteDiff) : 1.) )
308 std::cout << std::setprecision(16);
309 std::cout <<
"Bug in evaluateJacobian() for finite element type "
311 std::cout <<
" Shape function derivative does not agree with "
312 <<
"FD approximation" << std::endl;
313 std::cout <<
" Shape function " << j <<
" component " << l
314 <<
" at position " << testPoint <<
": derivative in "
315 <<
"direction " << k <<
" is " <<
derivative <<
", but "
316 << finiteDiff <<
" is expected." << std::endl;
317 std::cout << std::endl;
335 static bool test(
const FE& fe,
336 double eps,
double delta,
unsigned int diffOrder, std::size_t order = 2,
337 const std::function<
bool(
const typename FE::Traits::LocalBasisType::Traits::DomainType&)> derivativePointSkip =
nullptr)
342 std::cout <<
"No test for differentiability orders larger than 2!" << std::endl;
345 success = success and
testOrder2(fe, eps, delta, order, derivativePointSkip);
348 success = success and
testOrder1(fe, eps, delta, order, derivativePointSkip);
350 success = success and
testOrder0(fe, eps, delta, order);
360 std::size_t order = 2)
362 typedef typename FE::Traits::LocalBasisType::Traits::RangeType RangeType;
363 constexpr auto dimDomain = FE::Traits::LocalBasisType::Traits::dimDomain;
377 for (
size_t i = 0; i < quad.size(); i++)
383 std::vector<RangeType> partialValues;
384 std::array<unsigned int, dimDomain> multiIndex;
385 std::fill(multiIndex.begin(), multiIndex.end(), 0);
387 fe.localBasis().partial(multiIndex, testPoint, partialValues);
389 if (partialValues.size() != fe.localBasis().size())
391 std::cout <<
"Bug in partial() for finite element type "
393 std::cout <<
" values vector has size "
394 << partialValues.size() << std::endl;
395 std::cout <<
" Basis has size " << fe.localBasis().size()
397 std::cout << std::endl;
402 std::vector<RangeType> referenceValues;
403 fe.localBasis().evaluateFunction(testPoint, referenceValues);
406 for (
unsigned int j = 0; j < fe.localBasis().size(); ++j)
409 for (
int l = 0; l < FE::Traits::LocalBasisType::Traits::dimRange; ++l)
412 if (std::abs(partialValues[j][l] - referenceValues[j][l])
414 * ((std::abs(referenceValues[j][l]) > 1) ? std::abs(referenceValues[j][l]) : 1.))
416 std::cout << std::setprecision(16);
417 std::cout <<
"Bug in partial() for finite element type "
419 std::cout <<
" Shape function value does not agree with "
420 <<
"output of method evaluateFunction." << std::endl;
421 std::cout <<
" Shape function " << j <<
" component " << l
422 <<
" at position " << testPoint <<
": value is " << partialValues[j][l]
423 <<
", but " << referenceValues[j][l] <<
" is expected." << std::endl;
424 std::cout << std::endl;
440 std::size_t order = 2,
441 const std::function<
bool(
const typename FE::Traits::LocalBasisType::Traits::DomainType&)> derivativePointSkip =
nullptr)
443 typedef typename FE::Traits::LocalBasisType LB;
444 typedef typename LB::Traits::RangeFieldType RangeField;
459 for (
size_t i = 0; i < quad.size(); i++)
465 if (derivativePointSkip && derivativePointSkip(testPoint))
469 for (
int k = 0; k < LB::Traits::dimDomain; k++)
472 std::vector<typename LB::Traits::RangeType> firstPartialDerivatives;
473 std::array<unsigned int, LB::Traits::dimDomain> multiIndex;
474 std::fill(multiIndex.begin(), multiIndex.end(), 0);
476 fe.localBasis().partial(multiIndex, testPoint, firstPartialDerivatives);
477 if (firstPartialDerivatives.size() != fe.localBasis().size())
479 std::cout <<
"Bug in partial() for finite element type "
481 std::cout <<
" firstPartialDerivatives vector has size "
482 << firstPartialDerivatives.size() << std::endl;
483 std::cout <<
" Basis has size " << fe.localBasis().size()
485 std::cout << std::endl;
493 upPos[k] += jacobianTOL;
494 downPos[k] -= jacobianTOL;
496 std::vector<typename LB::Traits::RangeType> upValues, downValues;
498 fe.localBasis().evaluateFunction(upPos, upValues);
499 fe.localBasis().evaluateFunction(downPos, downValues);
502 for (
unsigned int j = 0; j < fe.localBasis().size(); ++j)
505 for (
int l = 0; l < LB::Traits::dimRange; ++l)
507 RangeField finiteDiff = (upValues[j][l] - downValues[j][l])
511 RangeField partialDerivative = firstPartialDerivatives[j][l];
512 if (std::abs(partialDerivative - finiteDiff)
514 * ((std::abs(finiteDiff) > 1) ? std::abs(finiteDiff) : 1.))
516 std::cout << std::setprecision(16);
517 std::cout <<
"Bug in partial() for finite element type "
519 std::cout <<
" Shape function derivative does not agree with "
520 <<
"FD approximation" << std::endl;
521 std::cout <<
" Shape function " << j <<
" component " << l
522 <<
" at position " << testPoint <<
": derivative in "
523 <<
"direction " << k <<
" is " << partialDerivative <<
", but "
524 << finiteDiff <<
" is expected." << std::endl;
525 std::cout << std::endl;
542 std::size_t order = 2,
543 const std::function<
bool(
const typename FE::Traits::LocalBasisType::Traits::DomainType&)> derivativePointSkip =
nullptr)
545 typedef typename FE::Traits::LocalBasisType LocalBasis;
546 typedef typename LocalBasis::Traits::DomainFieldType DF;
547 typedef typename LocalBasis::Traits::DomainType Domain;
548 static const int dimDomain = LocalBasis::Traits::dimDomain;
550 static const std::size_t dimR = LocalBasis::Traits::dimRange;
551 typedef typename LocalBasis::Traits::RangeType Range;
552 typedef typename LocalBasis::Traits::RangeFieldType RangeField;
566 for (std::size_t i = 0; i < quad.size(); i++)
569 const Domain& testPoint = quad[i].position();
572 if (derivativePointSkip && derivativePointSkip(testPoint))
576 std::array<std::vector<Dune::FieldMatrix<RangeField, dimDomain, dimDomain> >, dimR> partialHessians;
577 for (
size_t k = 0; k < dimR; k++)
578 partialHessians[k].resize(fe.size());
581 for (
int dir0 = 0; dir0 < dimDomain; dir0++)
583 for (
int dir1 = 0; dir1 < dimDomain; dir1++)
586 std::vector<Range> secondPartialDerivative;
587 std::array<unsigned int,dimDomain> multiIndex;
588 std::fill(multiIndex.begin(), multiIndex.end(), 0);
591 fe.localBasis().partial(multiIndex, testPoint, secondPartialDerivative);
593 if (secondPartialDerivative.size() != fe.localBasis().size())
595 std::cout <<
"Bug in partial() for finite element type "
596 << Dune::className<FE>() <<
":" << std::endl;
597 std::cout <<
" return vector has size " << secondPartialDerivative.size()
599 std::cout <<
" Basis has size " << fe.localBasis().size()
601 std::cout << std::endl;
606 for (
size_t k = 0; k < dimR; k++)
607 for (std::size_t j = 0; j < fe.localBasis().size(); ++j)
608 partialHessians[k][j][dir0][dir1] = secondPartialDerivative[j][k];
614 for (std::size_t dir0 = 0; dir0 < dimDomain; ++dir0)
616 for (
unsigned int dir1 = 0; dir1 < dimDomain; dir1++)
619 std::array<Domain,4> neighbourPos;
620 std::fill(neighbourPos.begin(), neighbourPos.end(), testPoint);
622 neighbourPos[0][dir0] += delta;
623 neighbourPos[0][dir1] += delta;
624 neighbourPos[1][dir0] -= delta;
625 neighbourPos[1][dir1] += delta;
626 neighbourPos[2][dir0] += delta;
627 neighbourPos[2][dir1] -= delta;
628 neighbourPos[3][dir0] -= delta;
629 neighbourPos[3][dir1] -= delta;
631 std::array<std::vector<Range>, 4> neighbourValues;
632 for (
int k = 0; k < 4; k++)
633 fe.localBasis().evaluateFunction(neighbourPos[k],
637 for (std::size_t j = 0; j < fe.localBasis().size(); ++j)
640 for (std::size_t k = 0; k < dimR; ++k)
642 RangeField finiteDiff = (neighbourValues[0][j][k]
643 - neighbourValues[1][j][k] - neighbourValues[2][j][k]
644 + neighbourValues[3][j][k]) / (4 * delta * delta);
647 RangeField partialDerivative = partialHessians[k][j][dir0][dir1];
650 if (std::abs(partialDerivative - finiteDiff)
651 > eps / delta * (
std::max(std::abs(finiteDiff), 1.0)))
653 std::cout << std::setprecision(16);
654 std::cout <<
"Bug in partial() for finite element type "
655 << Dune::className<FE>() <<
":" << std::endl;
656 std::cout <<
" Second shape function derivative does not agree with "
657 <<
"FD approximation" << std::endl;
658 std::cout <<
" Shape function " << j <<
" component " << k
659 <<
" at position " << testPoint <<
": derivative in "
660 <<
"local direction (" << dir0 <<
", " << dir1 <<
") is "
661 << partialDerivative <<
", but " << finiteDiff
662 <<
" is expected." << std::endl;
663 std::cout << std::endl;
681 DisableLocalInterpolation = 1,
682 DisableVirtualInterface = 2,
685 DisableRepresentConstants = 16
699bool testFE(
const FE& fe,
700 char disabledTests = DisableNone,
701 unsigned int diffOrder = 0,
702 const std::function<
bool(
const typename FE::Traits::LocalBasisType::Traits::DomainType&)> derivativePointSkip =
nullptr)
705 unsigned int quadOrder = 2;
709 if (FE::Traits::LocalBasisType::Traits::dimDomain != fe.type().dim())
711 std::cout <<
"Bug in type() for finite element type "
713 std::cout <<
" Coordinate dimension is " << FE::Traits::LocalBasisType::Traits::dimDomain << std::endl;
714 std::cout <<
" but GeometryType is " << fe.type() <<
" with dimension " << fe.type().dim() << std::endl;
718 if (fe.size() != fe.localBasis().size())
720 std::cout <<
"Bug in finite element type "
722 std::cout <<
" Size reported by LocalFiniteElement is " << fe.size() << std::endl;
723 std::cout <<
" but size reported by LocalBasis is " << fe.localBasis().size() << std::endl;
728 std::vector<typename FE::Traits::LocalBasisType::Traits::RangeType> values;
731 if (values.size() != fe.size())
733 std::cout <<
"Bug in finite element type "
735 std::cout <<
" LocalFiniteElement.size() returns " << fe.size() <<
"," << std::endl;
736 std::cout <<
" but LocalBasis::evaluateFunction returns " << values.size() <<
" values!" << std::endl;
740 if (fe.size() != fe.localCoefficients().size())
742 std::cout <<
"Bug in finite element type "
744 std::cout <<
" Size reported by LocalFiniteElement is " << fe.size() << std::endl;
745 std::cout <<
" but size reported by LocalCoefficients is " << fe.localCoefficients().size() << std::endl;
749 const auto& lc = fe.localCoefficients();
750 for(
size_t i=0; i<lc.size(); i++)
752 const auto& lk = lc.localKey(i);
753 if (lk.codim() > fe.type().dim())
755 std::cout <<
"Bug in finite element type "
757 std::cout <<
" Codimension reported by localKey(" << i <<
") is " << lk.codim() << std::endl;
758 std::cout <<
" but geometry is " << fe.type() <<
" with dimension " << fe.type().dim() << std::endl;
763 if (not (disabledTests & DisableLocalInterpolation))
765 success = testLocalInterpolation<FE>(fe) and success;
768 if (not (disabledTests & DisableRepresentConstants))
770 success = testCanRepresentConstants<FE>(fe) and success;
773 if (not (disabledTests & DisableJacobian))
775 success = testJacobian<FE>(fe, quadOrder, derivativePointSkip) and success;
780 success = (diffOrder == 0) and success;
783 if (not (disabledTests & DisableEvaluate))
785 success = TestPartial::test(fe, TOL, jacobianTOL, diffOrder, quadOrder, derivativePointSkip) and success;
788 if (not (disabledTests & DisableVirtualInterface))
790 typedef typename FE::Traits::LocalBasisType::Traits ImplementationLBTraits;
794 const VirtualFEImp virtualFE(fe);
795 if (not (disabledTests & DisableLocalInterpolation))
796 success = testLocalInterpolation<VirtualFEInterface>(virtualFE) and success;
797 if (not (disabledTests & DisableJacobian))
799 success = testJacobian<VirtualFEInterface>(virtualFE, quadOrder, derivativePointSkip) and success;
804 success = (diffOrder == 0) and success;
811#define TEST_FE(A) { bool b = testFE(A); std::cout << "testFE(" #A ") " << (b?"succeeded\n":"failed\n"); success &= b; }
812#define TEST_FE2(A,B) { bool b = testFE(A, B); std::cout << "testFE(" #A ", " #B ") " << (b?"succeeded\n":"failed\n"); success &= b; }
813#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; }
814#define TEST_FE4(A,B,C,D) { bool b = testFE(A, B, C, D); std::cout << "testFE(" #A ", " #B ", " #C ", " #D ") " << (b?"succeeded\n":"failed\n"); success &= b; }
vector space out of a tensor product of fields.
Definition: fvector.hh:95
class for wrapping a finite element using the virtual interface
Definition: virtualwrappers.hh:238
virtual base class for local finite elements with functions
Definition: virtualinterface.hh:284
Abstract base class for quadrature rules.
Definition: quadraturerules.hh:152
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:280
A free function to provide the demangled class name of a given object or type as a string.
TrigonometricFunction< K, -cosFactor, sinFactor > derivative(const TrigonometricFunction< K, sinFactor, cosFactor > &f)
Obtain derivative of TrigonometricFunction function.
Definition: trigonometricfunction.hh:39
auto max(ADLTag< 0 >, const V &v1, const V &v2)
implements binary Simd::max()
Definition: defaults.hh:79
std::string className()
Provide the demangled class name of a type T as a string.
Definition: classname.hh:45
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:333
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:357
static bool testOrder1(const FE &fe, double eps, double delta, std::size_t order=2, const std::function< bool(const typename FE::Traits::LocalBasisType::Traits::DomainType &)> derivativePointSkip=nullptr)
Test the 'partial' method for first-order partial derivatives.
Definition: test-localfe.hh:437
static bool testOrder2(const FE &fe, double eps, double delta, std::size_t order=2, const std::function< bool(const typename FE::Traits::LocalBasisType::Traits::DomainType &)> derivativePointSkip=nullptr)
Test second-order partial derivatives.
Definition: test-localfe.hh:539