// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include #include #include #include #include bool success = true; template ::is_specialized, int> = 0> ctype eps () { return std::numeric_limits::epsilon(); } template ::is_specialized, int> = 0> ctype eps () { return std::numeric_limits::epsilon(); } /* This is a simple accuracy test on the reference element. It integrates x^p and y^p with the quadrature rule of order p, which should give an exact result. */ /* Exact (analytical) solution on different reference elements. */ template ctype analyticalSolution (Dune::GeometryType t, int p, int direction ) { using Dune::GeometryType; ctype exact=0; if (t.isCube()) { exact = ctype( 1 )/(p+1); return exact; } if (t.isSimplex()) { /* 1/(prod(k=1..dim,(p+k)) */ exact = ctype( 1 ); for( int k = 1; k <= dim; ++k ) exact *= p+k; exact = ctype( 1 ) / exact; return exact; } if (t.isPrism()) { const int pdim = (dim > 0 ? dim-1 : 0); if( direction < dim-1 ) { Dune::GeometryType nt = Dune::GeometryTypes::simplex( dim-1 ); if( dim > 0 ) exact = analyticalSolution< ctype, pdim >( nt, p, direction ); else exact = ctype( 1 ); } else exact = ctype( 1 ) / ctype( Dune::Factorial< pdim >::factorial * (p+1)); return exact; } if (t.isPyramid()) { switch( direction ) { case 0 : case 1 : exact = ctype( 1 )/((p+3)*(p+1)); break; case 2 : exact = ctype( 2 )/((p+1)*(p+2)*(p+3)); break; }; return exact; } DUNE_THROW(Dune::NotImplemented, __func__ << " for " << t); return exact; } template void checkQuadrature(const QuadratureRule &quad) { using std::pow; using std::abs; using namespace Dune; typedef typename QuadratureRule::CoordType ctype; const unsigned int dim = QuadratureRule::d; const unsigned int p = quad.order(); const Dune::GeometryType& t = quad.type(); FieldVector integral(0); for (typename QuadratureRule::iterator qp=quad.begin(); qp!=quad.end(); ++qp) { // pos of integration point const FieldVector< ctype, dim > &x = qp->position(); const ctype weight = qp->weight(); for (unsigned int d=0; d(t,p,d); ctype relativeError = abs(integral[d] - exact) / (abs(integral[d]) + abs(exact)); if (relativeError > maxRelativeError) maxRelativeError = relativeError; } ctype epsilon = pow(2.0,p)*p*eps(); if (p==0) epsilon = 2.0*eps(); if (maxRelativeError > epsilon) { std::cerr << "Error: Quadrature for " << t << " and order=" << p << " failed" << std::endl; for (unsigned int d=0; d(t,p,d); ctype relativeError = abs(integral[d] - exact) / (abs(integral[d]) + abs(exact)); std::cerr << " relative error " << relativeError << " in direction " << d << " (exact = " << exact << " numerical = " << integral[d] << ")" << std::endl; } success = false; } } template void checkWeights(const QuadratureRule &quad) { using std::abs; typedef typename QuadratureRule::CoordType ctype; const unsigned int dim = QuadratureRule::d; const unsigned int p = quad.order(); const Dune::GeometryType& t = quad.type(); typedef typename QuadratureRule::iterator QuadIterator; ctype volume = 0; QuadIterator qp = quad.begin(); QuadIterator qend = quad.end(); for (; qp!=qend; ++qp) { volume += qp->weight(); } if (abs(volume - Dune::ReferenceElements::general(t).volume()) > quad.size()*eps()) { std::cerr << "Error: Quadrature for " << t << " and order=" << p << " does not sum to volume of RefElem" << std::endl; std::cerr << "\tSums to " << volume << "( RefElem.volume() = " << Dune::ReferenceElements::general(t).volume() << ")" << "(difference " << volume - Dune::ReferenceElements::general(t).volume() << ")" << std::endl; success = false; } } template void check(Dune::GeometryType type, unsigned int maxOrder, Dune::QuadratureType::Enum qt = Dune::QuadratureType::GaussLegendre) { typedef Dune::QuadratureRule Quad; std::string qt_str = ""; switch (qt) { case Dune::QuadratureType::GaussLegendre: qt_str = "GaussLegendre"; break; case Dune::QuadratureType::GaussJacobi_1_0: qt_str = "GaussJacobi_1_0"; break; case Dune::QuadratureType::GaussJacobi_2_0: qt_str = "GaussJacobi_2_0"; break; case Dune::QuadratureType::GaussJacobi_n_0: qt_str = "GaussJacobi_n_0"; break; case Dune::QuadratureType::GaussLobatto: qt_str = "GaussLobatto"; break; case Dune::QuadratureType::GaussRadauLeft: qt_str = "GaussRadauLeft"; break; case Dune::QuadratureType::GaussRadauRight: qt_str = "GaussRadauRight"; break; default: qt_str = "unknown"; } std::cout << "check(Quadrature of type " << qt_str << ")" << std::endl; for (unsigned int p=0; p<=maxOrder; ++p) { const Quad & quad = Dune::QuadratureRules::rule(type, p, qt); if (quad.type() != type || unsigned(quad.order()) < p) { std::cerr << "Error: Type mismatch! Requested Quadrature for " << type << " and order=" << p << "." << std::endl << "\tGot Quadrature for " << quad.type() << " and order=" << quad.order() << std::endl; success = false; return; } checkWeights(quad); checkQuadrature(quad); } if (dim>0 && (dim>3 || type.isCube() || type.isSimplex())) { type = type.isCube() ? Dune::GeometryTypes::cube(dim-1) : Dune::GeometryTypes::simplex(dim-1); check(type , maxOrder, qt); } } template void checkCompositeRule(Dune::GeometryType type, unsigned int maxOrder, unsigned int maxRefinement, Dune::QuadratureType::Enum qt = Dune::QuadratureType::GaussLegendre) { typedef Dune::QuadratureRule BaseQuad; typedef Dune::CompositeQuadratureRule Quad; for (unsigned int p=0; p<=maxOrder; ++p) { const BaseQuad& baseQuad = Dune::QuadratureRules::rule(type, p, qt); Quad quad = Quad(baseQuad, Dune::refinementLevels(maxRefinement)); checkWeights(quad); checkQuadrature(quad); } if (dim>0 && (dim>3 || type.isCube() || type.isSimplex())) { type = type.isCube() ? Dune::GeometryTypes::cube(dim-1) : Dune::GeometryTypes::simplex(dim-1); check(type, maxOrder, qt); } } int main (int argc, char** argv) { unsigned int maxOrder = 45; if (argc > 1) { maxOrder = std::atoi(argv[1]); std::cout << "maxOrder = " << maxOrder << std::endl; } try { check(Dune::GeometryTypes::cube(4), maxOrder); check(Dune::GeometryTypes::cube(4), std::min(maxOrder, unsigned(31)), Dune::QuadratureType::GaussLobatto); check(Dune::GeometryTypes::cube(4), std::min(maxOrder, unsigned(30)), Dune::QuadratureType::GaussRadauLeft); check(Dune::GeometryTypes::cube(4), std::min(maxOrder, unsigned(30)), Dune::QuadratureType::GaussRadauRight); check(Dune::GeometryTypes::simplex(4), maxOrder); #if HAVE_LAPACK check(Dune::GeometryTypes::simplex(4), maxOrder, Dune::QuadratureType::GaussJacobi_n_0); #else std::cout << "Skip GaussJacobi_n_0 tests as LAPACK has not been found" << std::endl; #endif check(Dune::GeometryTypes::prism, maxOrder); check(Dune::GeometryTypes::pyramid, maxOrder); unsigned int maxRefinement = 4; checkCompositeRule(Dune::GeometryTypes::triangle, maxOrder, maxRefinement); #if HAVE_QUADMATH check(Dune::GeometryTypes::cube(4), maxOrder); check(Dune::GeometryTypes::cube(4), std::min(maxOrder, unsigned(31)), Dune::QuadratureType::GaussLobatto); check(Dune::GeometryTypes::cube(4), std::min(maxOrder, unsigned(30)), Dune::QuadratureType::GaussRadauLeft); check(Dune::GeometryTypes::cube(4), std::min(maxOrder, unsigned(30)), Dune::QuadratureType::GaussRadauRight); #else std::cout << "Skip Float128 tests as Quadmath is not supported" << std::endl; #endif } catch( const Dune::Exception &e ) { std::cerr << e << std::endl; throw; } catch (...) { std::cerr << "Generic exception!" << std::endl; throw; } return success ? 0 : 1; }