5#ifndef DUNE_LOCALFUNCTIONS_TEST_TEST_LOCALFE_HH
6#define DUNE_LOCALFUNCTIONS_TEST_TEST_LOCALFE_HH
22#include <dune/geometry/referenceelements.hh>
24#include <dune/localfunctions/common/virtualinterface.hh>
25#include <dune/localfunctions/common/virtualwrappers.hh>
26#include <dune/localfunctions/common/localfiniteelement.hh>
31double jacobianTOL = 1e-5;
36class ShapeFunctionAsCallable
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 ShapeFunctionAsCallable(
const FE& fe,
int shapeFunction) :
47 shapeFunction_(shapeFunction)
50 RangeType operator() (DomainType x)
const
52 std::vector<RangeType> yy;
53 fe_.localBasis().evaluateFunction(x, yy);
54 return yy[shapeFunction_];
67bool testLocalInterpolation(
const FE& fe)
70 std::vector<typename ShapeFunctionAsCallable<FE>::CT> coeff;
71 for(
size_t i=0; i<fe.size(); ++i)
78 ShapeFunctionAsCallable<FE> sfAsCallable(fe, i);
82 fe.localInterpolation().interpolate(sfAsCallable, coeff);
85 if (coeff.size() != fe.localBasis().size())
87 std::cout <<
"Bug in LocalInterpolation for finite element type "
89 std::cout <<
" Interpolation produces " << coeff.size() <<
" degrees of freedom" << std::endl;
90 std::cout <<
" Basis has size " << fe.localBasis().size() << std::endl;
91 std::cout << std::endl;
96 for(std::size_t j=0; j<coeff.size(); ++j)
98 if ( abs(coeff[j] - (i==j)) > TOL)
100 std::cout << std::setprecision(16);
101 std::cout <<
"Bug in LocalInterpolation for finite element type "
103 std::cout <<
" Degree of freedom " << j <<
" applied to shape function " << i
104 <<
" yields value " << coeff[j] <<
", not the expected value " << (i==j) << std::endl;
105 std::cout << std::endl;
117bool testCanRepresentConstants(
const FE& fe,
120 typedef typename FE::Traits::LocalBasisType LB;
121 using RangeType =
typename LB::Traits::RangeType;
126 auto constantOne = [](
const typename LB::Traits::DomainType& xi) {
return RangeType(1.0); };
129 std::vector<double> coefficients;
130 fe.localInterpolation().interpolate(constantOne, coefficients);
136 for (
size_t i=0; i<quad.size(); i++) {
139 const auto& testPoint = quad[i].position();
142 std::vector<RangeType> values;
143 fe.localBasis().evaluateFunction(testPoint, values);
146 for (
size_t j=0; j<values.size(); j++)
147 sum += coefficients[j] * values[j];
149 if ((RangeType(1.0)-sum).two_norm() > TOL)
152 <<
" cannot represent constant functions!" << std::endl;
153 std::cout <<
" At position: " << testPoint <<
","
155 std::cout <<
" discrete approximation of the '1' function has value " << sum
157 std::cout << std::endl;
168bool testJacobian(
const FE& fe,
170 const std::function<
bool(
const typename FE::Traits::LocalBasisType::Traits::DomainType&)> derivativePointSkip =
nullptr)
172 typedef typename FE::Traits::LocalBasisType LB;
186 for (
size_t i=0; i<quad.size(); i++) {
193 std::vector<typename LB::Traits::JacobianType> jacobians;
194 fe.localBasis().evaluateJacobian(testPoint, jacobians);
195 if(jacobians.size() != fe.localBasis().size()) {
196 std::cout <<
"Bug in evaluateJacobian() for finite element type "
198 std::cout <<
" Jacobian vector has size " << jacobians.size()
200 std::cout <<
" Basis has size " << fe.localBasis().size()
202 std::cout << std::endl;
207 if (derivativePointSkip && derivativePointSkip(quad[i].position()))
211 for (
int k=0; k<LB::Traits::dimDomain; k++) {
217 upPos[k] += jacobianTOL;
218 downPos[k] -= jacobianTOL;
220 std::vector<typename LB::Traits::RangeType> upValues, downValues;
222 fe.localBasis().evaluateFunction(upPos, upValues);
223 fe.localBasis().evaluateFunction(downPos, downValues);
226 for (
unsigned int j=0; j<fe.localBasis().size(); ++j) {
228 for(
int l=0; l < LB::Traits::dimRange; ++l) {
233 double finiteDiff = (upValues[j][l] - downValues[j][l])
238 TOL/jacobianTOL*((std::abs(finiteDiff)>1) ? std::abs(finiteDiff) : 1.) )
240 std::cout << std::setprecision(16);
241 std::cout <<
"Bug in evaluateJacobian() for finite element type "
243 std::cout <<
" Shape function derivative does not agree with "
244 <<
"FD approximation" << std::endl;
245 std::cout <<
" Shape function " << j <<
" component " << l
246 <<
" at position " << testPoint <<
": derivative in "
247 <<
"direction " << k <<
" is " <<
derivative <<
", but "
248 << finiteDiff <<
" is expected." << std::endl;
249 std::cout << std::endl;
267 static bool test(
const FE& fe,
268 double eps,
double delta,
unsigned int diffOrder, std::size_t order = 2,
269 const std::function<
bool(
const typename FE::Traits::LocalBasisType::Traits::DomainType&)> derivativePointSkip =
nullptr)
274 std::cout <<
"No test for differentiability orders larger than 2!" << std::endl;
277 success = success and
testOrder2(fe, eps, delta, order, derivativePointSkip);
280 success = success and
testOrder1(fe, eps, delta, order, derivativePointSkip);
282 success = success and
testOrder0(fe, eps, delta, order);
292 std::size_t order = 2)
294 typedef typename FE::Traits::LocalBasisType::Traits::RangeType RangeType;
295 constexpr auto dimDomain = FE::Traits::LocalBasisType::Traits::dimDomain;
309 for (
size_t i = 0; i < quad.size(); i++)
315 std::vector<RangeType> partialValues;
316 std::array<unsigned int, dimDomain> multiIndex;
317 std::fill(multiIndex.begin(), multiIndex.end(), 0);
319 fe.localBasis().partial(multiIndex, testPoint, partialValues);
321 if (partialValues.size() != fe.localBasis().size())
323 std::cout <<
"Bug in partial() for finite element type "
325 std::cout <<
" values vector has size "
326 << partialValues.size() << std::endl;
327 std::cout <<
" Basis has size " << fe.localBasis().size()
329 std::cout << std::endl;
334 std::vector<RangeType> referenceValues;
335 fe.localBasis().evaluateFunction(testPoint, referenceValues);
338 for (
unsigned int j = 0; j < fe.localBasis().size(); ++j)
341 for (
int l = 0; l < FE::Traits::LocalBasisType::Traits::dimRange; ++l)
344 if (std::abs(partialValues[j][l] - referenceValues[j][l])
346 * ((std::abs(referenceValues[j][l]) > 1) ? std::abs(referenceValues[j][l]) : 1.))
348 std::cout << std::setprecision(16);
349 std::cout <<
"Bug in partial() for finite element type "
351 std::cout <<
" Shape function value does not agree with "
352 <<
"output of method evaluateFunction." << std::endl;
353 std::cout <<
" Shape function " << j <<
" component " << l
354 <<
" at position " << testPoint <<
": value is " << partialValues[j][l]
355 <<
", but " << referenceValues[j][l] <<
" is expected." << std::endl;
356 std::cout << std::endl;
372 std::size_t order = 2,
373 const std::function<
bool(
const typename FE::Traits::LocalBasisType::Traits::DomainType&)> derivativePointSkip =
nullptr)
375 typedef typename FE::Traits::LocalBasisType LB;
376 typedef typename LB::Traits::RangeFieldType RangeField;
391 for (
size_t i = 0; i < quad.size(); i++)
397 if (derivativePointSkip && derivativePointSkip(testPoint))
401 for (
int k = 0; k < LB::Traits::dimDomain; k++)
404 std::vector<typename LB::Traits::RangeType> firstPartialDerivatives;
405 std::array<unsigned int, LB::Traits::dimDomain> multiIndex;
406 std::fill(multiIndex.begin(), multiIndex.end(), 0);
408 fe.localBasis().partial(multiIndex, testPoint, firstPartialDerivatives);
409 if (firstPartialDerivatives.size() != fe.localBasis().size())
411 std::cout <<
"Bug in partial() for finite element type "
413 std::cout <<
" firstPartialDerivatives vector has size "
414 << firstPartialDerivatives.size() << std::endl;
415 std::cout <<
" Basis has size " << fe.localBasis().size()
417 std::cout << std::endl;
425 upPos[k] += jacobianTOL;
426 downPos[k] -= jacobianTOL;
428 std::vector<typename LB::Traits::RangeType> upValues, downValues;
430 fe.localBasis().evaluateFunction(upPos, upValues);
431 fe.localBasis().evaluateFunction(downPos, downValues);
434 for (
unsigned int j = 0; j < fe.localBasis().size(); ++j)
437 for (
int l = 0; l < LB::Traits::dimRange; ++l)
439 RangeField finiteDiff = (upValues[j][l] - downValues[j][l])
443 RangeField partialDerivative = firstPartialDerivatives[j][l];
444 if (std::abs(partialDerivative - finiteDiff)
446 * ((std::abs(finiteDiff) > 1) ? std::abs(finiteDiff) : 1.))
448 std::cout << std::setprecision(16);
449 std::cout <<
"Bug in partial() for finite element type "
451 std::cout <<
" Shape function derivative does not agree with "
452 <<
"FD approximation" << std::endl;
453 std::cout <<
" Shape function " << j <<
" component " << l
454 <<
" at position " << testPoint <<
": derivative in "
455 <<
"direction " << k <<
" is " << partialDerivative <<
", but "
456 << finiteDiff <<
" is expected." << std::endl;
457 std::cout << std::endl;
474 std::size_t order = 2,
475 const std::function<
bool(
const typename FE::Traits::LocalBasisType::Traits::DomainType&)> derivativePointSkip =
nullptr)
477 typedef typename FE::Traits::LocalBasisType LocalBasis;
478 typedef typename LocalBasis::Traits::DomainFieldType DF;
479 typedef typename LocalBasis::Traits::DomainType Domain;
480 static const int dimDomain = LocalBasis::Traits::dimDomain;
482 static const std::size_t dimR = LocalBasis::Traits::dimRange;
483 typedef typename LocalBasis::Traits::RangeType Range;
484 typedef typename LocalBasis::Traits::RangeFieldType RangeField;
498 for (std::size_t i = 0; i < quad.size(); i++)
501 const Domain& testPoint = quad[i].position();
504 if (derivativePointSkip && derivativePointSkip(testPoint))
508 std::array<std::vector<Dune::FieldMatrix<RangeField, dimDomain, dimDomain> >, dimR> partialHessians;
509 for (
size_t k = 0; k < dimR; k++)
510 partialHessians[k].resize(fe.size());
513 for (
int dir0 = 0; dir0 < dimDomain; dir0++)
515 for (
int dir1 = 0; dir1 < dimDomain; dir1++)
518 std::vector<Range> secondPartialDerivative;
519 std::array<unsigned int,dimDomain> multiIndex;
520 std::fill(multiIndex.begin(), multiIndex.end(), 0);
523 fe.localBasis().partial(multiIndex, testPoint, secondPartialDerivative);
525 if (secondPartialDerivative.size() != fe.localBasis().size())
527 std::cout <<
"Bug in partial() for finite element type "
528 << Dune::className<FE>() <<
":" << std::endl;
529 std::cout <<
" return vector has size " << secondPartialDerivative.size()
531 std::cout <<
" Basis has size " << fe.localBasis().size()
533 std::cout << std::endl;
538 for (
size_t k = 0; k < dimR; k++)
539 for (std::size_t j = 0; j < fe.localBasis().size(); ++j)
540 partialHessians[k][j][dir0][dir1] = secondPartialDerivative[j][k];
546 for (std::size_t dir0 = 0; dir0 < dimDomain; ++dir0)
548 for (
unsigned int dir1 = 0; dir1 < dimDomain; dir1++)
551 std::array<Domain,4> neighbourPos;
552 std::fill(neighbourPos.begin(), neighbourPos.end(), testPoint);
554 neighbourPos[0][dir0] += delta;
555 neighbourPos[0][dir1] += delta;
556 neighbourPos[1][dir0] -= delta;
557 neighbourPos[1][dir1] += delta;
558 neighbourPos[2][dir0] += delta;
559 neighbourPos[2][dir1] -= delta;
560 neighbourPos[3][dir0] -= delta;
561 neighbourPos[3][dir1] -= delta;
563 std::array<std::vector<Range>, 4> neighbourValues;
564 for (
int k = 0; k < 4; k++)
565 fe.localBasis().evaluateFunction(neighbourPos[k],
569 for (std::size_t j = 0; j < fe.localBasis().size(); ++j)
572 for (std::size_t k = 0; k < dimR; ++k)
574 RangeField finiteDiff = (neighbourValues[0][j][k]
575 - neighbourValues[1][j][k] - neighbourValues[2][j][k]
576 + neighbourValues[3][j][k]) / (4 * delta * delta);
579 RangeField partialDerivative = partialHessians[k][j][dir0][dir1];
582 if (std::abs(partialDerivative - finiteDiff)
583 > eps / delta * (
std::max(std::abs(finiteDiff), 1.0)))
585 std::cout << std::setprecision(16);
586 std::cout <<
"Bug in partial() for finite element type "
587 << Dune::className<FE>() <<
":" << std::endl;
588 std::cout <<
" Second shape function derivative does not agree with "
589 <<
"FD approximation" << std::endl;
590 std::cout <<
" Shape function " << j <<
" component " << k
591 <<
" at position " << testPoint <<
": derivative in "
592 <<
"local direction (" << dir0 <<
", " << dir1 <<
") is "
593 << partialDerivative <<
", but " << finiteDiff
594 <<
" is expected." << std::endl;
595 std::cout << std::endl;
613 DisableLocalInterpolation = 1,
614 DisableVirtualInterface = 2,
617 DisableRepresentConstants = 16
631bool testFE(
const FE& fe,
632 char disabledTests = DisableNone,
633 unsigned int diffOrder = 0,
634 const std::function<
bool(
const typename FE::Traits::LocalBasisType::Traits::DomainType&)> derivativePointSkip =
nullptr)
637 unsigned int quadOrder = 2;
641 if (FE::Traits::LocalBasisType::Traits::dimDomain != fe.type().dim())
643 std::cout <<
"Bug in type() for finite element type "
645 std::cout <<
" Coordinate dimension is " << FE::Traits::LocalBasisType::Traits::dimDomain << std::endl;
646 std::cout <<
" but GeometryType is " << fe.type() <<
" with dimension " << fe.type().dim() << std::endl;
650 if (fe.size() != fe.localBasis().size())
652 std::cout <<
"Bug in finite element type "
654 std::cout <<
" Size reported by LocalFiniteElement is " << fe.size() << std::endl;
655 std::cout <<
" but size reported by LocalBasis is " << fe.localBasis().size() << std::endl;
660 std::vector<typename FE::Traits::LocalBasisType::Traits::RangeType> values;
663 if (values.size() != fe.size())
665 std::cout <<
"Bug in finite element type "
667 std::cout <<
" LocalFiniteElement.size() returns " << fe.size() <<
"," << std::endl;
668 std::cout <<
" but LocalBasis::evaluateFunction returns " << values.size() <<
" values!" << std::endl;
672 if (fe.size() != fe.localCoefficients().size())
674 std::cout <<
"Bug in finite element type "
676 std::cout <<
" Size reported by LocalFiniteElement is " << fe.size() << std::endl;
677 std::cout <<
" but size reported by LocalCoefficients is " << fe.localCoefficients().size() << std::endl;
681 const auto& lc = fe.localCoefficients();
682 for(
size_t i=0; i<lc.size(); i++)
684 const auto& lk = lc.localKey(i);
685 if (lk.codim() > fe.type().dim())
687 std::cout <<
"Bug in finite element type "
689 std::cout <<
" Codimension reported by localKey(" << i <<
") is " << lk.codim() << std::endl;
690 std::cout <<
" but geometry is " << fe.type() <<
" with dimension " << fe.type().dim() << std::endl;
695 if (not (disabledTests & DisableLocalInterpolation))
697 success = testLocalInterpolation<FE>(fe) and success;
700 if (not (disabledTests & DisableRepresentConstants))
702 success = testCanRepresentConstants<FE>(fe) and success;
705 if (not (disabledTests & DisableJacobian))
707 success = testJacobian<FE>(fe, quadOrder, derivativePointSkip) and success;
712 success = (diffOrder == 0) and success;
715 if (not (disabledTests & DisableEvaluate))
717 success = TestPartial::test(fe, TOL, jacobianTOL, diffOrder, quadOrder, derivativePointSkip) and success;
720 if (not (disabledTests & DisableVirtualInterface))
722 typedef typename FE::Traits::LocalBasisType::Traits ImplementationLBTraits;
727 const VirtualFEImp virtualFE(fe);
728 if (not (disabledTests & DisableLocalInterpolation))
729 success = testLocalInterpolation<VirtualFEInterface>(virtualFE) and success;
730 if (not (disabledTests & DisableJacobian))
732 success = testJacobian<VirtualFEInterface>(virtualFE, quadOrder, derivativePointSkip) and success;
737 success = (diffOrder == 0) and success;
740 const TypeErasedLFE typeErasedLFE(fe);
741 if (not (disabledTests & DisableLocalInterpolation))
742 success = testLocalInterpolation<TypeErasedLFE>(typeErasedLFE) and success;
743 if (not (disabledTests & DisableJacobian))
744 success = testJacobian<TypeErasedLFE>(typeErasedLFE, quadOrder, derivativePointSkip) and success;
748 TypeErasedLFE typeErasedLFE;
758#define TEST_FE(A) { bool b = testFE(A); std::cout << "testFE(" #A ") " << (b?"succeeded\n":"failed\n"); success &= b; }
759#define TEST_FE2(A,B) { bool b = testFE(A, B); std::cout << "testFE(" #A ", " #B ") " << (b?"succeeded\n":"failed\n"); success &= b; }
760#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; }
761#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:92
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:225
Type erasure class storing a local finite element.
Definition: localfiniteelement.hh:40
Abstract base class for quadrature rules.
Definition: quadraturerules.hh:214
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:326
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:43
constexpr auto max
Function object that returns the greater of the given values.
Definition: hybridutilities.hh:485
std::string className()
Provide the demangled class name of a type T as a string.
Definition: classname.hh:47
Class providing access to the singletons of the reference elements.
Definition: referenceelements.hh:128
Helper class to test the 'partial' method.
Definition: test-localfe.hh:265
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:289
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:369
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:471