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) {
 
  231          double derivative = jacobians[j][l][k];
 
  233          double finiteDiff = (upValues[j][l] - downValues[j][l])
 
  237          if ( std::abs(derivative-finiteDiff) >
 
  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:97
 
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.
 
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