diff --git a/src/analysis/EconomicalGaussQuadrature.cpp b/src/analysis/EconomicalGaussQuadrature.cpp index 27ada266d21ce6cdb2628b00faad7c17e7cae3f6..c3033f89b1bc50b752eaf800f622b9bf6dc0c91b 100644 --- a/src/analysis/EconomicalGaussQuadrature.cpp +++ b/src/analysis/EconomicalGaussQuadrature.cpp @@ -16,15 +16,87 @@ template <> void EconomicalGaussQuadrature<2>::_buildPointAndWeightLists() { + using R2 = TinyVector<2>; + using QuadratureGroup = std::array<double, 3>; + + auto fill_quadrature_points = [](auto quadrature_group_list, auto& point_list, auto& weight_list) { + Assert(point_list.size() == weight_list.size()); + + size_t k = 0; + for (size_t i = 0; i < quadrature_group_list.size(); ++i) { + auto [w, xi, eta] = quadrature_group_list[i]; + if (xi != eta) { + Assert(xi != 0, "quadrature group was not defined correctly"); + if (eta == 0) { + point_list[k + 0] = {xi, eta}; + point_list[k + 1] = {-xi, eta}; + point_list[k + 2] = {eta, xi}; + point_list[k + 3] = {eta, -xi}; + + weight_list[k + 0] = w; + weight_list[k + 1] = w; + weight_list[k + 2] = w; + weight_list[k + 3] = w; + + k += 4; + } else { + point_list[k + 0] = {xi, eta}; + point_list[k + 1] = {-xi, eta}; + point_list[k + 2] = {xi, -eta}; + point_list[k + 3] = {-xi, -eta}; + point_list[k + 4] = {eta, xi}; + point_list[k + 5] = {-eta, xi}; + point_list[k + 6] = {eta, -xi}; + point_list[k + 7] = {-eta, -xi}; + + weight_list[k + 0] = w; + weight_list[k + 1] = w; + weight_list[k + 2] = w; + weight_list[k + 3] = w; + weight_list[k + 4] = w; + weight_list[k + 5] = w; + weight_list[k + 6] = w; + weight_list[k + 7] = w; + + k += 8; + } + } else { + if (xi == 0) { + point_list[k] = {xi, eta}; + + weight_list[k] = w; + + k += 1; + } else { + point_list[k + 0] = {xi, eta}; + point_list[k + 1] = {-xi, eta}; + point_list[k + 2] = {xi, -eta}; + point_list[k + 3] = {-xi, -eta}; + + weight_list[k + 0] = w; + weight_list[k + 1] = w; + weight_list[k + 2] = w; + weight_list[k + 3] = w; + + k += 4; + } + } + } + + Assert(k == point_list.size(), "invalid number of quadrature points"); + }; + switch (m_degree) { case 0: case 1: { constexpr size_t nb_points = 1; - SmallArray<TinyVector<2>> point_list(nb_points); + SmallArray<R2> point_list(nb_points); SmallArray<double> weight_list(nb_points); - point_list[0] = {0, 0}; - weight_list[0] = 4; + std::array<QuadratureGroup, 1> quadrature_group_list = // + {QuadratureGroup{4.000000000000000, 0.000000000000000, 0.000000000000000}}; + + fill_quadrature_points(quadrature_group_list, point_list, weight_list); m_point_list = point_list; m_weight_list = weight_list; @@ -33,18 +105,13 @@ EconomicalGaussQuadrature<2>::_buildPointAndWeightLists() case 2: case 3: { constexpr size_t nb_points = 4; - SmallArray<TinyVector<2>> point_list(nb_points); + SmallArray<R2> point_list(nb_points); SmallArray<double> weight_list(nb_points); - point_list[0] = {+0.577350269189626, +0.577350269189626}; - point_list[1] = {+0.577350269189626, -0.577350269189626}; - point_list[2] = {-0.577350269189626, +0.577350269189626}; - point_list[3] = {-0.577350269189626, -0.577350269189626}; + std::array<QuadratureGroup, 1> quadrature_group_list = // + {QuadratureGroup{1.000000000000000, 0.577350269189626, 0.577350269189626}}; - weight_list[0] = 1; - weight_list[1] = 1; - weight_list[2] = 1; - weight_list[3] = 1; + fill_quadrature_points(quadrature_group_list, point_list, weight_list); m_point_list = point_list; m_weight_list = weight_list; @@ -53,26 +120,14 @@ EconomicalGaussQuadrature<2>::_buildPointAndWeightLists() case 4: case 5: { constexpr size_t nb_points = 8; - SmallArray<TinyVector<2>> point_list(nb_points); + SmallArray<R2> point_list(nb_points); SmallArray<double> weight_list(nb_points); - point_list[0] = {+0.683130051063973, +0.000000000000000}; - point_list[1] = {-0.683130051063973, +0.000000000000000}; - point_list[2] = {+0.000000000000000, +0.683130051063973}; - point_list[3] = {+0.000000000000000, -0.683130051063973}; - point_list[4] = {+0.881917103688197, +0.881917103688197}; - point_list[5] = {+0.881917103688197, -0.881917103688197}; - point_list[6] = {-0.881917103688197, +0.881917103688197}; - point_list[7] = {-0.881917103688197, -0.881917103688197}; - - weight_list[0] = 0.816326530612245; - weight_list[1] = 0.816326530612245; - weight_list[2] = 0.816326530612245; - weight_list[3] = 0.816326530612245; - weight_list[4] = 0.183673469387755; - weight_list[5] = 0.183673469387755; - weight_list[6] = 0.183673469387755; - weight_list[7] = 0.183673469387755; + std::array quadrature_group_list = // + {QuadratureGroup{0.816326530612245, 0.683130051063973, 0.000000000000000}, + QuadratureGroup{0.183673469387755, 0.881917103688197, 0.881917103688197}}; + + fill_quadrature_points(quadrature_group_list, point_list, weight_list); m_point_list = point_list; m_weight_list = weight_list; @@ -81,41 +136,182 @@ EconomicalGaussQuadrature<2>::_buildPointAndWeightLists() case 6: case 7: { constexpr size_t nb_points = 12; - SmallArray<TinyVector<2>> point_list(nb_points); + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array quadrature_group_list = // + {QuadratureGroup{0.241975308641975, 0.925820099772551, 0.000000000000000}, + QuadratureGroup{0.237431774690630, 0.805979782918599, 0.805979782918599}, + QuadratureGroup{0.520592916667394, 0.380554433208316, 0.380554433208316}}; + + fill_quadrature_points(quadrature_group_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 8: + case 9: { + constexpr size_t nb_points = 20; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array quadrature_group_list = // + {QuadratureGroup{0.018475842507491, 1.121225763866564, 0.000000000000000}, + QuadratureGroup{0.390052939160735, 0.451773049920657, 0.000000000000000}, + QuadratureGroup{0.083095178026482, 0.891849420851512, 0.891849420851512}, + QuadratureGroup{0.254188020152646, 0.824396370149276, 0.411623426336542}}; + + fill_quadrature_points(quadrature_group_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 10: + case 11: { + constexpr size_t nb_points = 25; + SmallArray<R2> point_list(nb_points); SmallArray<double> weight_list(nb_points); - point_list[0] = {+0.925820099772551, +0.000000000000000}; - point_list[1] = {-0.925820099772551, +0.000000000000000}; - point_list[2] = {+0.000000000000000, +0.925820099772551}; - point_list[3] = {+0.000000000000000, -0.925820099772551}; - point_list[4] = {+0.805979782918599, +0.805979782918599}; - point_list[5] = {+0.805979782918599, -0.805979782918599}; - point_list[6] = {-0.805979782918599, +0.805979782918599}; - point_list[7] = {-0.805979782918599, -0.805979782918599}; - point_list[8] = {+0.380554433208316, +0.380554433208316}; - point_list[9] = {+0.380554433208316, -0.380554433208316}; - point_list[10] = {-0.380554433208316, +0.380554433208316}; - point_list[11] = {-0.380554433208316, -0.380554433208316}; - - weight_list[0] = 0.241975308641975; - weight_list[1] = 0.241975308641975; - weight_list[2] = 0.241975308641975; - weight_list[3] = 0.241975308641975; - weight_list[4] = 0.237431774690630; - weight_list[5] = 0.237431774690630; - weight_list[6] = 0.237431774690630; - weight_list[7] = 0.237431774690630; - weight_list[8] = 0.520592916667394; - weight_list[9] = 0.520592916667394; - weight_list[10] = 0.520592916667394; - weight_list[11] = 0.520592916667394; + std::array quadrature_group_list = // + {QuadratureGroup{0.365379525585903, 0.000000000000000, 0.000000000000000}, + QuadratureGroup{0.027756165564204, 1.044402915409813, 0.000000000000000}, + QuadratureGroup{0.244272057751754, 0.769799068396649, 0.000000000000000}, + QuadratureGroup{0.034265103851229, 0.935787012440540, 0.935787012440540}, + QuadratureGroup{0.308993036133713, 0.413491953449114, 0.413491953449114}, + QuadratureGroup{0.146684377651312, 0.883025508525690, 0.575653595840465}}; + + fill_quadrature_points(quadrature_group_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 12: + case 13: { + constexpr size_t nb_points = 36; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array quadrature_group_list = // + {QuadratureGroup{0.005656169693764, 1.086056158573971, 0.000000000000000}, + QuadratureGroup{0.192443867470396, 0.658208197042585, 0.000000000000000}, + QuadratureGroup{0.005166832979773, 1.001300602991729, 1.001300602991729}, + QuadratureGroup{0.200302559622138, 0.584636168775946, 0.584636168775946}, + QuadratureGroup{0.228125175912536, 0.246795612720261, 0.246795612720261}, + QuadratureGroup{0.117496926974491, 0.900258815287201, 0.304720678579870}, + QuadratureGroup{0.066655770186205, 0.929866705560780, 0.745052720131169}}; + + fill_quadrature_points(quadrature_group_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 14: + case 15: { + constexpr size_t nb_points = 45; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array quadrature_group_list = // + {QuadratureGroup{-0.001768979827207, 0.000000000000000, 0.000000000000000}, + QuadratureGroup{+0.012816726617512, 1.027314357719367, 0.000000000000000}, + QuadratureGroup{+0.119897873101347, 0.856766776147643, 0.000000000000000}, + QuadratureGroup{+0.210885452208801, 0.327332998189723, 0.000000000000000}, + QuadratureGroup{+0.006392720128215, 0.967223740028505, 0.967223740028505}, + QuadratureGroup{+0.104415680788580, 0.732168901749711, 0.732168901749711}, + QuadratureGroup{+0.168053047203816, 0.621974427996805, 0.321696694921009}, + QuadratureGroup{+0.076169694452294, 0.928618480068352, 0.455124178121179}, + QuadratureGroup{+0.028794154400064, 0.960457474887516, 0.809863684081217}}; + + fill_quadrature_points(quadrature_group_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 16: + case 17: { + constexpr size_t nb_points = 60; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array quadrature_group_list = // + {QuadratureGroup{0.020614915919991, 0.989353074512600, 0.000000000000000}, + QuadratureGroup{0.128025716179910, 0.376285207157973, 0.000000000000000}, + QuadratureGroup{0.005511739534032, 0.978848279262233, 0.978848279262233}, + QuadratureGroup{0.039207712457142, 0.885794729164116, 0.885794729164116}, + QuadratureGroup{0.076396945079863, 0.171756123838348, 0.171756123838348}, + QuadratureGroup{0.141513729949972, 0.590499273806002, 0.319505036634574}, + QuadratureGroup{0.083903279363798, 0.799079131916863, 0.597972451929457}, + QuadratureGroup{0.060394163649685, 0.803743962958745, 0.058344481776551}, + QuadratureGroup{0.057387752969213, 0.936506276127495, 0.347386316166203}, + QuadratureGroup{0.021922559481864, 0.981321179805452, 0.706000287798646}}; + + fill_quadrature_points(quadrature_group_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 18: + case 19: { + constexpr size_t nb_points = 72; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array quadrature_group_list = // + {QuadratureGroup{0.038205406871462, 0.943962831808239, 0.000000000000000}, + QuadratureGroup{0.135368502976521, 0.536918434376013, 0.000000000000000}, + QuadratureGroup{0.005773708558664, 0.973981076394170, 0.973981076394170}, + QuadratureGroup{0.067460759759473, 0.742995535327609, 0.742995535327609}, + QuadratureGroup{0.140899115227892, 0.285010052188916, 0.285010052188916}, + QuadratureGroup{0.047466627685662, 0.068354569272491, 0.068354569272491}, + QuadratureGroup{0.078619467342982, 0.802952004398543, 0.203345534163332}, + QuadratureGroup{0.094979169511394, 0.634244672807882, 0.426572172992877}, + QuadratureGroup{0.022331162356015, 0.978350706908227, 0.295830776620995}, + QuadratureGroup{0.055594877793785, 0.901672714410389, 0.541983037327871}, + QuadratureGroup{0.006049054506376, 1.007018449383116, 0.669414798783936}, + QuadratureGroup{0.024839207949609, 0.945161453573471, 0.829501421477824}}; + + fill_quadrature_points(quadrature_group_list, point_list, weight_list); + + m_point_list = point_list; + m_weight_list = weight_list; + break; + } + case 20: + case 21: { + constexpr size_t nb_points = 88; + SmallArray<R2> point_list(nb_points); + SmallArray<double> weight_list(nb_points); + + std::array quadrature_group_list = // + {QuadratureGroup{0.019503841092684, 0.980883148832881, 0.000000000000000}, + QuadratureGroup{0.089012127744268, 0.678152700336576, 0.000000000000000}, + QuadratureGroup{0.114568584702749, 0.240599282275864, 0.000000000000000}, + QuadratureGroup{0.007463627359106, 0.965176994929162, 0.965176994929162}, + QuadratureGroup{0.050585943594705, 0.749698539312765, 0.749698539312765}, + QuadratureGroup{0.074613865184212, 0.568983925500818, 0.568983925500818}, + QuadratureGroup{0.023501091310143, 0.971086142843168, 0.355832132274584}, + QuadratureGroup{0.011588562644144, 0.983453947854968, 0.645588139196562}, + QuadratureGroup{0.023073245798171, 0.933927707027213, 0.821920249234369}, + QuadratureGroup{0.001570221774472, 1.014086498915039, 0.862185099566557}, + QuadratureGroup{0.049102258016277, 0.877914842155496, 0.168914072450263}, + QuadratureGroup{0.042512352239126, 0.882246882640128, 0.568113580166780}, + QuadratureGroup{0.067270936863160, 0.741324453314596, 0.371360260002223}, + QuadratureGroup{0.103507336515645, 0.469570217710647, 0.237333359193547}}; + + fill_quadrature_points(quadrature_group_list, point_list, weight_list); m_point_list = point_list; m_weight_list = weight_list; break; } default: { - throw NormalError("Gauss quadrature formulae handle degrees up to 7 on quadrangles"); + throw NormalError("Gauss quadrature formulae handle degrees up to 21 on squares"); } } } @@ -270,7 +466,7 @@ EconomicalGaussQuadrature<3>::_buildPointAndWeightLists() break; } default: { - throw NormalError("Gauss quadrature formulae handle degrees up to 7 on hexahedra"); + throw NormalError("Gauss quadrature formulae handle degrees up to 7 on cubes"); } } } diff --git a/src/analysis/EconomicalGaussQuadrature.hpp b/src/analysis/EconomicalGaussQuadrature.hpp index 0862d0a66486d23c99ae9a0525302673bb2e99b4..601c76f2206b6a5191d81f0c6b888019677d0f1c 100644 --- a/src/analysis/EconomicalGaussQuadrature.hpp +++ b/src/analysis/EconomicalGaussQuadrature.hpp @@ -7,7 +7,13 @@ * Defines Economical Gauss quadrature on the reference element * \f$]-1,1[^d\f$, where \f$d\f$ denotes the \a Dimension. * - * \note formulae are extracted from High-order Finite Element Method [2004 - Chapman & Hall] + * \note formulae are given by D. A. DUNAVANT + * + * In 2d: ‘Economical symmetrical quadrature rules for complete + * polynomials over a square domain‘ (1985). + * + * In 3d: 'Efficient symmetrical cubature rules for complete + * polynomials of high degree over the unit cube' (1986). */ template <size_t Dimension> class EconomicalGaussQuadrature final : public QuadratureForumla<Dimension> diff --git a/tests/test_EconomicalGaussQuadrature.cpp b/tests/test_EconomicalGaussQuadrature.cpp index 1da84db8d901c65e4ac092bcb5595b504fdb284d..18b7143cc42b685274a7ddeb4f1045ac824fdbec 100644 --- a/tests/test_EconomicalGaussQuadrature.cpp +++ b/tests/test_EconomicalGaussQuadrature.cpp @@ -604,6 +604,76 @@ TEST_CASE("EconomicalGaussQuadrature", "[analysis]") const double y = X[1]; return p7(X) * (2 * x - 3 * y - 3); }; + auto p9 = [&p8](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p8(X) * (x + 2 * y - 1.7); + }; + auto p10 = [&p9](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p9(X) * (-1.3 * x - 1.7 * y + 1.3); + }; + auto p11 = [&p10](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p10(X) * (0.8 * x - 3.1 * y + 0.6); + }; + auto p12 = [&p11](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p11(X) * (1.8 * x + 1.3 * y - 0.3); + }; + auto p13 = [&p12](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p12(X) * (-0.9 * x + 1.1 * y - 0.6); + }; + auto p14 = [&p13](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p13(X) * (0.6 * x + 0.3 * y + 1.1); + }; + auto p15 = [&p14](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p14(X) * (0.5 * x - 0.4 * y - 1.1); + }; + auto p16 = [&p15](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p15(X) * (-0.3 * x - 0.3 * y - 0.2); + }; + auto p17 = [&p16](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p16(X) * (-0.1 * x - 0.4 * y - 0.3); + }; + auto p18 = [&p17](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p17(X) * (0.2 * x + 0.3 * y + 0.3); + }; + auto p19 = [&p18](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p18(X) * (2.1 * x + 3.3 * y - 0.3); + }; + auto p20 = [&p19](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p19(X) * (1.2 * x - 2.1 * y + 0.6); + }; + auto p21 = [&p20](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p20(X) * (-1.3 * x - 1.2 * y + 0.7); + }; + auto p22 = [&p21](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return p21(X) * (1.1 * x - 2.2 * y - 0.3); + }; SECTION("degree 0 and 1") { @@ -678,10 +748,221 @@ TEST_CASE("EconomicalGaussQuadrature", "[analysis]") REQUIRE(get_order(p8, l7, 957697. / 175) == Catch::Approx(8)); } + SECTION("degree 8 and 9") + { + EconomicalGaussQuadrature<2> l8(8); + EconomicalGaussQuadrature<2> l9(9); + + REQUIRE(same_formulas(l8, l9)); + + REQUIRE(l9.numberOfPoints() == 20); + + REQUIRE(integrate(p0, l9) == Catch::Approx(8)); + REQUIRE(integrate(p1, l9) == Catch::Approx(4)); + REQUIRE(integrate(p2, l9) == Catch::Approx(20. / 3)); + REQUIRE(integrate(p3, l9) == Catch::Approx(-13)); + REQUIRE(integrate(p4, l9) == Catch::Approx(-1184. / 15)); + REQUIRE(integrate(p5, l9) == Catch::Approx(1971. / 25)); + REQUIRE(integrate(p6, l9) == Catch::Approx(60441. / 175)); + REQUIRE(integrate(p7, l9) == Catch::Approx(-1307119. / 525)); + REQUIRE(integrate(p8, l9) == Catch::Approx(957697. / 175)); + REQUIRE(integrate(p9, l9) == Catch::Approx(-196981. / 5250)); + REQUIRE(integrate(p10, l9) != Catch::Approx(78447601. / 577500)); + + REQUIRE(get_order(p10, l9, 78447601. / 577500) == Catch::Approx(10)); + } + + SECTION("degree 10 and 11") + { + EconomicalGaussQuadrature<2> l10(10); + EconomicalGaussQuadrature<2> l11(11); + + REQUIRE(same_formulas(l10, l11)); + + REQUIRE(l11.numberOfPoints() == 25); + + REQUIRE(integrate(p0, l11) == Catch::Approx(8)); + REQUIRE(integrate(p1, l11) == Catch::Approx(4)); + REQUIRE(integrate(p2, l11) == Catch::Approx(20. / 3)); + REQUIRE(integrate(p3, l11) == Catch::Approx(-13)); + REQUIRE(integrate(p4, l11) == Catch::Approx(-1184. / 15)); + REQUIRE(integrate(p5, l11) == Catch::Approx(1971. / 25)); + REQUIRE(integrate(p6, l11) == Catch::Approx(60441. / 175)); + REQUIRE(integrate(p7, l11) == Catch::Approx(-1307119. / 525)); + REQUIRE(integrate(p8, l11) == Catch::Approx(957697. / 175)); + REQUIRE(integrate(p9, l11) == Catch::Approx(-196981. / 5250)); + REQUIRE(integrate(p10, l11) == Catch::Approx(78447601. / 577500)); + REQUIRE(integrate(p11, l11) == Catch::Approx(673235482069. / 86625000)); + REQUIRE(integrate(p12, l11) != Catch::Approx(-4092600398251. / 303187500)); + + REQUIRE(get_order(p12, l11, -4092600398251. / 303187500) == Catch::Approx(12)); + } + + SECTION("degree 12 and 13") + { + EconomicalGaussQuadrature<2> l12(12); + EconomicalGaussQuadrature<2> l13(13); + + REQUIRE(same_formulas(l12, l13)); + + REQUIRE(l13.numberOfPoints() == 36); + + REQUIRE(integrate(p0, l13) == Catch::Approx(8)); + REQUIRE(integrate(p1, l13) == Catch::Approx(4)); + REQUIRE(integrate(p2, l13) == Catch::Approx(20. / 3)); + REQUIRE(integrate(p3, l13) == Catch::Approx(-13)); + REQUIRE(integrate(p4, l13) == Catch::Approx(-1184. / 15)); + REQUIRE(integrate(p5, l13) == Catch::Approx(1971. / 25)); + REQUIRE(integrate(p6, l13) == Catch::Approx(60441. / 175)); + REQUIRE(integrate(p7, l13) == Catch::Approx(-1307119. / 525)); + REQUIRE(integrate(p8, l13) == Catch::Approx(957697. / 175)); + REQUIRE(integrate(p9, l13) == Catch::Approx(-196981. / 5250)); + REQUIRE(integrate(p10, l13) == Catch::Approx(78447601. / 577500)); + REQUIRE(integrate(p11, l13) == Catch::Approx(673235482069. / 86625000)); + REQUIRE(integrate(p12, l13) == Catch::Approx(-4092600398251. / 303187500)); + REQUIRE(integrate(p13, l13) == Catch::Approx(77231697272647. / 5053125000)); + REQUIRE(integrate(p14, l13) != Catch::Approx(46574962939049. / 9384375000)); + + REQUIRE(get_order(p14, l13, 46574962939049. / 9384375000) == Catch::Approx(14)); + } + + SECTION("degree 14 and 15") + { + EconomicalGaussQuadrature<2> l14(14); + EconomicalGaussQuadrature<2> l15(15); + + REQUIRE(same_formulas(l14, l15)); + + REQUIRE(l15.numberOfPoints() == 45); + + REQUIRE(integrate(p0, l15) == Catch::Approx(8)); + REQUIRE(integrate(p1, l15) == Catch::Approx(4)); + REQUIRE(integrate(p2, l15) == Catch::Approx(20. / 3)); + REQUIRE(integrate(p3, l15) == Catch::Approx(-13)); + REQUIRE(integrate(p4, l15) == Catch::Approx(-1184. / 15)); + REQUIRE(integrate(p5, l15) == Catch::Approx(1971. / 25)); + REQUIRE(integrate(p6, l15) == Catch::Approx(60441. / 175)); + REQUIRE(integrate(p7, l15) == Catch::Approx(-1307119. / 525)); + REQUIRE(integrate(p8, l15) == Catch::Approx(957697. / 175)); + REQUIRE(integrate(p9, l15) == Catch::Approx(-196981. / 5250)); + REQUIRE(integrate(p10, l15) == Catch::Approx(78447601. / 577500)); + REQUIRE(integrate(p11, l15) == Catch::Approx(673235482069. / 86625000)); + REQUIRE(integrate(p12, l15) == Catch::Approx(-4092600398251. / 303187500)); + REQUIRE(integrate(p13, l15) == Catch::Approx(77231697272647. / 5053125000)); + REQUIRE(integrate(p14, l15) == Catch::Approx(46574962939049. / 9384375000)); + REQUIRE(integrate(p15, l15) == Catch::Approx(-4818864487842259. / 1094843750000)); + REQUIRE(integrate(p16, l15) != Catch::Approx(-89885697514686141. / 23265429687500)); + + REQUIRE(get_order(p16, l15, -89885697514686141. / 23265429687500) == Catch::Approx(16)); + } + + SECTION("degree 16 and 17") + { + EconomicalGaussQuadrature<2> l16(16); + EconomicalGaussQuadrature<2> l17(17); + + REQUIRE(same_formulas(l16, l17)); + + REQUIRE(l17.numberOfPoints() == 60); + + REQUIRE(integrate(p0, l17) == Catch::Approx(8)); + REQUIRE(integrate(p1, l17) == Catch::Approx(4)); + REQUIRE(integrate(p2, l17) == Catch::Approx(20. / 3)); + REQUIRE(integrate(p3, l17) == Catch::Approx(-13)); + REQUIRE(integrate(p4, l17) == Catch::Approx(-1184. / 15)); + REQUIRE(integrate(p5, l17) == Catch::Approx(1971. / 25)); + REQUIRE(integrate(p6, l17) == Catch::Approx(60441. / 175)); + REQUIRE(integrate(p7, l17) == Catch::Approx(-1307119. / 525)); + REQUIRE(integrate(p8, l17) == Catch::Approx(957697. / 175)); + REQUIRE(integrate(p9, l17) == Catch::Approx(-196981. / 5250)); + REQUIRE(integrate(p10, l17) == Catch::Approx(78447601. / 577500)); + REQUIRE(integrate(p11, l17) == Catch::Approx(673235482069. / 86625000)); + REQUIRE(integrate(p12, l17) == Catch::Approx(-4092600398251. / 303187500)); + REQUIRE(integrate(p13, l17) == Catch::Approx(77231697272647. / 5053125000)); + REQUIRE(integrate(p14, l17) == Catch::Approx(46574962939049. / 9384375000)); + REQUIRE(integrate(p15, l17) == Catch::Approx(-4818864487842259. / 1094843750000)); + REQUIRE(integrate(p16, l17) == Catch::Approx(-89885697514686141. / 23265429687500)); + REQUIRE(integrate(p17, l17) == Catch::Approx(16706355156097391. / 12085937500000)); + REQUIRE(integrate(p18, l17) != Catch::Approx(495866230514635109957. / 397838847656250000.).epsilon(1E-8)); + + REQUIRE(get_order(p18, l17, 495866230514635109957. / 397838847656250000.) == Catch::Approx(18).margin(0.001)); + } + + SECTION("degree 18 and 19") + { + EconomicalGaussQuadrature<2> l18(18); + EconomicalGaussQuadrature<2> l19(19); + + REQUIRE(same_formulas(l18, l19)); + + REQUIRE(l19.numberOfPoints() == 72); + + REQUIRE(integrate(p0, l19) == Catch::Approx(8)); + REQUIRE(integrate(p1, l19) == Catch::Approx(4)); + REQUIRE(integrate(p2, l19) == Catch::Approx(20. / 3)); + REQUIRE(integrate(p3, l19) == Catch::Approx(-13)); + REQUIRE(integrate(p4, l19) == Catch::Approx(-1184. / 15)); + REQUIRE(integrate(p5, l19) == Catch::Approx(1971. / 25)); + REQUIRE(integrate(p6, l19) == Catch::Approx(60441. / 175)); + REQUIRE(integrate(p7, l19) == Catch::Approx(-1307119. / 525)); + REQUIRE(integrate(p8, l19) == Catch::Approx(957697. / 175)); + REQUIRE(integrate(p9, l19) == Catch::Approx(-196981. / 5250)); + REQUIRE(integrate(p10, l19) == Catch::Approx(78447601. / 577500)); + REQUIRE(integrate(p11, l19) == Catch::Approx(673235482069. / 86625000)); + REQUIRE(integrate(p12, l19) == Catch::Approx(-4092600398251. / 303187500)); + REQUIRE(integrate(p13, l19) == Catch::Approx(77231697272647. / 5053125000)); + REQUIRE(integrate(p14, l19) == Catch::Approx(46574962939049. / 9384375000)); + REQUIRE(integrate(p15, l19) == Catch::Approx(-4818864487842259. / 1094843750000)); + REQUIRE(integrate(p16, l19) == Catch::Approx(-89885697514686141. / 23265429687500)); + REQUIRE(integrate(p17, l19) == Catch::Approx(16706355156097391. / 12085937500000)); + REQUIRE(integrate(p18, l19) == Catch::Approx(495866230514635109957. / 397838847656250000.)); + REQUIRE(integrate(p19, l19) == Catch::Approx(703712939580204375319. / 132612949218750000.)); + REQUIRE(integrate(p20, l19) != Catch::Approx(-891851528496270127477. / 884086328125000000.)); + + REQUIRE(get_order(p20, l19, -891851528496270127477. / 884086328125000000.) == Catch::Approx(20).margin(0.001)); + } + + SECTION("degree 20 and 21") + { + EconomicalGaussQuadrature<2> l20(20); + EconomicalGaussQuadrature<2> l21(21); + + REQUIRE(same_formulas(l20, l21)); + + REQUIRE(l21.numberOfPoints() == 88); + + REQUIRE(integrate(p0, l21) == Catch::Approx(8)); + REQUIRE(integrate(p1, l21) == Catch::Approx(4)); + REQUIRE(integrate(p2, l21) == Catch::Approx(20. / 3)); + REQUIRE(integrate(p3, l21) == Catch::Approx(-13)); + REQUIRE(integrate(p4, l21) == Catch::Approx(-1184. / 15)); + REQUIRE(integrate(p5, l21) == Catch::Approx(1971. / 25)); + REQUIRE(integrate(p6, l21) == Catch::Approx(60441. / 175)); + REQUIRE(integrate(p7, l21) == Catch::Approx(-1307119. / 525)); + REQUIRE(integrate(p8, l21) == Catch::Approx(957697. / 175)); + REQUIRE(integrate(p9, l21) == Catch::Approx(-196981. / 5250)); + REQUIRE(integrate(p10, l21) == Catch::Approx(78447601. / 577500)); + REQUIRE(integrate(p11, l21) == Catch::Approx(673235482069. / 86625000)); + REQUIRE(integrate(p12, l21) == Catch::Approx(-4092600398251. / 303187500)); + REQUIRE(integrate(p13, l21) == Catch::Approx(77231697272647. / 5053125000)); + REQUIRE(integrate(p14, l21) == Catch::Approx(46574962939049. / 9384375000)); + REQUIRE(integrate(p15, l21) == Catch::Approx(-4818864487842259. / 1094843750000)); + REQUIRE(integrate(p16, l21) == Catch::Approx(-89885697514686141. / 23265429687500)); + REQUIRE(integrate(p17, l21) == Catch::Approx(16706355156097391. / 12085937500000)); + REQUIRE(integrate(p18, l21) == Catch::Approx(495866230514635109957. / 397838847656250000.)); + REQUIRE(integrate(p19, l21) == Catch::Approx(703712939580204375319. / 132612949218750000.)); + REQUIRE(integrate(p20, l21) == Catch::Approx(-891851528496270127477. / 884086328125000000.)); + REQUIRE(integrate(p21, l21) == Catch::Approx(31710268999580650802107. / 66306474609375000000.)); + REQUIRE(integrate(p22, l21) != Catch::Approx(-1827205780869627586647799. / 726213769531250000000.).epsilon(1E-8)); + + REQUIRE(get_order(p22, l21, -1827205780869627586647799. / 726213769531250000000.) == + Catch::Approx(22).margin(0.01)); + } + SECTION("not implemented formulae") { - REQUIRE_THROWS_WITH(EconomicalGaussQuadrature<2>(8), - "error: Gauss quadrature formulae handle degrees up to 7 on quadrangles"); + REQUIRE_THROWS_WITH(EconomicalGaussQuadrature<2>(22), + "error: Gauss quadrature formulae handle degrees up to 21 on squares"); } } @@ -856,7 +1137,7 @@ TEST_CASE("EconomicalGaussQuadrature", "[analysis]") SECTION("not implemented formulae") { REQUIRE_THROWS_WITH(EconomicalGaussQuadrature<3>(8), - "error: Gauss quadrature formulae handle degrees up to 7 on hexahedra"); + "error: Gauss quadrature formulae handle degrees up to 7 on cubes"); } }