From cd8646f2016b78a9145b9d15a28937adb76cf035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Del=20Pino?= <stephane.delpino44@gmail.com> Date: Fri, 8 Oct 2021 12:10:29 +0200 Subject: [PATCH] Start writing of simplicial Gauss-Lengendre quadrature formulae Only sets 1d formulae which is trivially set as the tensorial ones --- src/analysis/CMakeLists.txt | 1 + .../SimplicialGaussLegendreQuadrature.cpp | 27 + .../SimplicialGaussLegendreQuadrature.hpp | 33 ++ tests/CMakeLists.txt | 1 + ...test_SimplicialGaussLegendreQuadrature.cpp | 524 ++++++++++++++++++ 5 files changed, 586 insertions(+) create mode 100644 src/analysis/SimplicialGaussLegendreQuadrature.cpp create mode 100644 src/analysis/SimplicialGaussLegendreQuadrature.hpp create mode 100644 tests/test_SimplicialGaussLegendreQuadrature.cpp diff --git a/src/analysis/CMakeLists.txt b/src/analysis/CMakeLists.txt index a99e6a339..833370313 100644 --- a/src/analysis/CMakeLists.txt +++ b/src/analysis/CMakeLists.txt @@ -2,5 +2,6 @@ add_library( PugsAnalysis + SimplicialGaussLegendreQuadrature.cpp TensorialGaussLegendreQuadrature.cpp TensorialGaussLobattoQuadrature.cpp) diff --git a/src/analysis/SimplicialGaussLegendreQuadrature.cpp b/src/analysis/SimplicialGaussLegendreQuadrature.cpp new file mode 100644 index 000000000..d09e9a020 --- /dev/null +++ b/src/analysis/SimplicialGaussLegendreQuadrature.cpp @@ -0,0 +1,27 @@ +#include <analysis/SimplicialGaussLegendreQuadrature.hpp> +#include <analysis/TensorialGaussLegendreQuadrature.hpp> +#include <utils/Exceptions.hpp> + +template <> +void +SimplicialGaussLegendreQuadrature<1>::_buildPointAndWeightLists() +{ + TensorialGaussLegendreQuadrature<1> gauss(m_order); + + m_point_list = gauss.pointList(); + m_weight_list = gauss.weightList(); +} + +template <> +void +SimplicialGaussLegendreQuadrature<2>::_buildPointAndWeightLists() +{ + throw NotImplementedError("gauss legendre quadrature on 2d simplex"); +} + +template <> +void +SimplicialGaussLegendreQuadrature<3>::_buildPointAndWeightLists() +{ + throw NotImplementedError("gauss legendre quadrature on 3d simplex"); +} diff --git a/src/analysis/SimplicialGaussLegendreQuadrature.hpp b/src/analysis/SimplicialGaussLegendreQuadrature.hpp new file mode 100644 index 000000000..824eb0995 --- /dev/null +++ b/src/analysis/SimplicialGaussLegendreQuadrature.hpp @@ -0,0 +1,33 @@ +#ifndef SIMPLICIAL_GAUSS_LEGENDRE_QUADRATURE_HPP +#define SIMPLICIAL_GAUSS_LEGENDRE_QUADRATURE_HPP + +#include <analysis/QuadratureFormula.hpp> + +/** + * Defines Gauss Legendre quadrature on the reference simplex element + * - in 1d, the segment \f$]-1,1[\f$ + * - in 2d, the triangle defined by \f$(-1,-1)\f$, \f$(1,-1)\f$ and \f$(-1,1)\f$ + * - in 3d, the tetrahedron joining \f$(-1,-1-1)\f$, \f$(1,-1,-1)\f$, \f$(-1,1,-1)\f$ and \f$(-1,1-,1)\f$ + * + * \note formulae are extracted from High-order Finite Element Method [2004 - Chapman & Hall] + */ +template <size_t Dimension> +class SimplicialGaussLegendreQuadrature final : public QuadratureForumla<Dimension> +{ + private: + void _buildPointAndWeightLists(); + + public: + SimplicialGaussLegendreQuadrature(SimplicialGaussLegendreQuadrature&&) = default; + SimplicialGaussLegendreQuadrature(const SimplicialGaussLegendreQuadrature&) = default; + + explicit SimplicialGaussLegendreQuadrature(const size_t order) : QuadratureForumla<Dimension>(order) + { + this->_buildPointAndWeightLists(); + } + + SimplicialGaussLegendreQuadrature() = delete; + ~SimplicialGaussLegendreQuadrature() = default; +}; + +#endif // SIMPLICIAL_GAUSS_LEGENDRE_QUADRATURE_HPP diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7ecbb1f77..69b85561e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -99,6 +99,7 @@ add_executable (unit_tests test_PugsUtils.cpp test_Q1Transformation.cpp test_RevisionInfo.cpp + test_SimplicialGaussLegendreQuadrature.cpp test_SmallArray.cpp test_SmallVector.cpp test_SymbolTable.cpp diff --git a/tests/test_SimplicialGaussLegendreQuadrature.cpp b/tests/test_SimplicialGaussLegendreQuadrature.cpp new file mode 100644 index 000000000..80fd1c7e0 --- /dev/null +++ b/tests/test_SimplicialGaussLegendreQuadrature.cpp @@ -0,0 +1,524 @@ +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> +#include <catch2/matchers/catch_matchers_all.hpp> + +#include <analysis/SimplicialGaussLegendreQuadrature.hpp> +#include <utils/Exceptions.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("SimplicialGaussLegendreQuadrature", "[analysis]") +{ + auto same_formulas = [](auto quadrature_formula0, auto quadrature_formula1) { + auto point_list0 = quadrature_formula0.pointList(); + auto weight_list0 = quadrature_formula0.weightList(); + + auto point_list1 = quadrature_formula1.pointList(); + auto weight_list1 = quadrature_formula1.weightList(); + + bool is_same = true; + + for (size_t i = 0; i < point_list0.size(); ++i) { + if (point_list0[i] != point_list1[i]) { + return false; + } + } + for (size_t i = 0; i < weight_list0.size(); ++i) { + if (weight_list0[i] != weight_list1[i]) { + return false; + } + } + + return is_same; + }; + + SECTION("1D") + { + auto is_symmetric_formula = [](auto quadrature_formula) { + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + bool is_symmetric = true; + + const size_t middle_index = point_list.size() / 2; + for (size_t i = 0; i <= middle_index; ++i) { + if (point_list[i] != -point_list[point_list.size() - 1 - i]) { + return false; + } + } + for (size_t i = 0; i <= middle_index; ++i) { + if (weight_list[i] != weight_list[point_list.size() - 1 - i]) { + return false; + } + } + + return is_symmetric; + }; + + auto integrate = [](auto f, auto quadrature_formula, const double a, const double b) { + auto point_list = quadrature_formula.pointList(); + auto weight_list = quadrature_formula.weightList(); + + double alpha = 0.5 * (b - a); + double beta = 0.5 * (a + b); + + auto x = [&alpha, &beta](auto x_hat) { return alpha * x_hat + beta; }; + + auto value = weight_list[0] * f(x(point_list[0])); + for (size_t i = 1; i < weight_list.size(); ++i) { + value += weight_list[i] * f(x(point_list[i])); + } + + return alpha * value; + }; + + auto get_order = [&integrate](auto f, auto quadrature_formula, const double a, const double b, + const double exact_value) { + double int_ab = integrate(f, quadrature_formula, a, b); + double int_first_half = integrate(f, quadrature_formula, a, 0.5 * (a + b)); + double int_second_half = integrate(f, quadrature_formula, 0.5 * (a + b), b); + + return -std::log((int_first_half + int_second_half - exact_value) / (int_ab - exact_value)) / std::log(2); + }; + + auto p0 = [](const TinyVector<1>&) { return 1; }; + auto p1 = [&p0](const TinyVector<1>& X) { + const double x = X[0]; + return 2 * x + p0(X); + }; + auto p2 = [&p1](const TinyVector<1>& X) { + const double x = X[0]; + return 3 * x * x + p1(X); + }; + auto p3 = [&p2](const TinyVector<1>& X) { + const double x = X[0]; + return 4 * std::pow(x, 3) + p2(X); + }; + auto p4 = [&p3](const TinyVector<1>& X) { + const double x = X[0]; + return 5 * std::pow(x, 4) + p3(X); + }; + auto p5 = [&p4](const TinyVector<1>& X) { + const double x = X[0]; + return 6 * std::pow(x, 5) + p4(X); + }; + auto p6 = [&p5](const TinyVector<1>& X) { + const double x = X[0]; + return 7 * std::pow(x, 6) + p5(X); + }; + auto p7 = [&p6](const TinyVector<1>& X) { + const double x = X[0]; + return 8 * std::pow(x, 7) + p6(X); + }; + auto p8 = [&p7](const TinyVector<1>& X) { + const double x = X[0]; + return 9 * std::pow(x, 8) + p7(X); + }; + auto p9 = [&p8](const TinyVector<1>& X) { + const double x = X[0]; + return 10 * std::pow(x, 9) + p8(X); + }; + auto p10 = [&p9](const TinyVector<1>& X) { + const double x = X[0]; + return 11 * std::pow(x, 10) + p9(X); + }; + auto p11 = [&p10](const TinyVector<1>& X) { + const double x = X[0]; + return 12 * std::pow(x, 11) + p10(X); + }; + auto p12 = [&p11](const TinyVector<1>& X) { + const double x = X[0]; + return 13 * std::pow(x, 12) + p11(X); + }; + auto p13 = [&p12](const TinyVector<1>& X) { + const double x = X[0]; + return 14 * std::pow(x, 13) + p12(X); + }; + auto p14 = [&p13](const TinyVector<1>& X) { + const double x = X[0]; + return 15 * std::pow(x, 14) + p13(X); + }; + auto p15 = [&p14](const TinyVector<1>& X) { + const double x = X[0]; + return 16 * std::pow(x, 15) + p14(X); + }; + auto p16 = [&p15](const TinyVector<1>& X) { + const double x = X[0]; + return 17 * std::pow(x, 16) + p15(X); + }; + auto p17 = [&p16](const TinyVector<1>& X) { + const double x = X[0]; + return 18 * std::pow(x, 17) + p16(X); + }; + auto p18 = [&p17](const TinyVector<1>& X) { + const double x = X[0]; + return 19 * std::pow(x, 18) + p17(X); + }; + auto p19 = [&p18](const TinyVector<1>& X) { + const double x = X[0]; + return 20 * std::pow(x, 19) + p18(X); + }; + auto p20 = [&p19](const TinyVector<1>& X) { + const double x = X[0]; + return 21 * std::pow(x, 20) + p19(X); + }; + auto p21 = [&p20](const TinyVector<1>& X) { + const double x = X[0]; + return 22 * std::pow(x, 21) + p20(X); + }; + auto p22 = [&p21](const TinyVector<1>& X) { + const double x = X[0]; + return 23 * std::pow(x, 22) + p21(X); + }; + auto p23 = [&p22](const TinyVector<1>& X) { + const double x = X[0]; + return 24 * std::pow(x, 23) + p22(X); + }; + auto p24 = [&p23](const TinyVector<1>& X) { + const double x = X[0]; + return 25 * std::pow(x, 24) + p23(X); + }; + + SECTION("order 0 and 1") + { + SimplicialGaussLegendreQuadrature<1> l0(0); + SimplicialGaussLegendreQuadrature<1> l1(1); + + REQUIRE(same_formulas(l0, l1)); + REQUIRE(is_symmetric_formula(l1)); + + REQUIRE(l1.numberOfPoints() == 1); + + REQUIRE(integrate(p0, l1, 0.5, 1) == Catch::Approx(0.5)); + REQUIRE(integrate(p1, l1, 0, 1) == Catch::Approx(2)); + REQUIRE(integrate(p2, l1, 0, 1) != Catch::Approx(3)); + + REQUIRE(get_order(p2, l1, -1, 1, 4) == Catch::Approx(2)); + } + + SECTION("order 2 and 3") + { + SimplicialGaussLegendreQuadrature<1> l2(2); + SimplicialGaussLegendreQuadrature<1> l3(3); + + REQUIRE(same_formulas(l2, l3)); + REQUIRE(is_symmetric_formula(l3)); + + REQUIRE(l3.numberOfPoints() == 2); + + REQUIRE(integrate(p0, l3, 0.5, 1) == Catch::Approx(0.5)); + REQUIRE(integrate(p1, l3, 0, 1) == Catch::Approx(2)); + REQUIRE(integrate(p2, l3, 0, 1) == Catch::Approx(3)); + REQUIRE(integrate(p3, l3, 0, 1) == Catch::Approx(4)); + REQUIRE(integrate(p4, l3, 0, 1) != Catch::Approx(5)); + + REQUIRE(get_order(p4, l3, -1, 1, 6) == Catch::Approx(4)); + } + + SECTION("order 4 and 5") + { + SimplicialGaussLegendreQuadrature<1> l4(4); + SimplicialGaussLegendreQuadrature<1> l5(5); + + REQUIRE(same_formulas(l4, l5)); + REQUIRE(is_symmetric_formula(l5)); + + REQUIRE(l5.numberOfPoints() == 3); + + REQUIRE(integrate(p0, l5, 0.5, 1) == Catch::Approx(0.5)); + REQUIRE(integrate(p1, l5, 0, 1) == Catch::Approx(2)); + REQUIRE(integrate(p2, l5, 0, 1) == Catch::Approx(3)); + REQUIRE(integrate(p3, l5, 0, 1) == Catch::Approx(4)); + REQUIRE(integrate(p4, l5, 0, 1) == Catch::Approx(5)); + REQUIRE(integrate(p5, l5, 0, 1) == Catch::Approx(6)); + REQUIRE(integrate(p6, l5, 0, 1) != Catch::Approx(7)); + + REQUIRE(get_order(p6, l5, -1, 1, 8) == Catch::Approx(6)); + } + + SECTION("order 6 and 7") + { + SimplicialGaussLegendreQuadrature<1> l6(6); + SimplicialGaussLegendreQuadrature<1> l7(7); + + REQUIRE(same_formulas(l6, l7)); + REQUIRE(is_symmetric_formula(l7)); + + REQUIRE(l7.numberOfPoints() == 4); + + REQUIRE(integrate(p0, l7, 0.5, 1) == Catch::Approx(0.5)); + REQUIRE(integrate(p1, l7, 0, 1) == Catch::Approx(2)); + REQUIRE(integrate(p2, l7, 0, 1) == Catch::Approx(3)); + REQUIRE(integrate(p3, l7, 0, 1) == Catch::Approx(4)); + REQUIRE(integrate(p4, l7, 0, 1) == Catch::Approx(5)); + REQUIRE(integrate(p5, l7, 0, 1) == Catch::Approx(6)); + REQUIRE(integrate(p6, l7, 0, 1) == Catch::Approx(7)); + REQUIRE(integrate(p7, l7, 0, 1) == Catch::Approx(8)); + REQUIRE(integrate(p8, l7, 0, 1) != Catch::Approx(9)); + + REQUIRE(get_order(p8, l7, -1, 1, 10) == Catch::Approx(8)); + } + + SECTION("order 8 and 9") + { + SimplicialGaussLegendreQuadrature<1> l8(8); + SimplicialGaussLegendreQuadrature<1> l9(9); + + REQUIRE(same_formulas(l8, l9)); + REQUIRE(is_symmetric_formula(l9)); + + REQUIRE(l9.numberOfPoints() == 5); + + REQUIRE(integrate(p0, l9, 0.5, 1) == Catch::Approx(0.5)); + REQUIRE(integrate(p1, l9, 0, 1) == Catch::Approx(2)); + REQUIRE(integrate(p2, l9, 0, 1) == Catch::Approx(3)); + REQUIRE(integrate(p3, l9, 0, 1) == Catch::Approx(4)); + REQUIRE(integrate(p4, l9, 0, 1) == Catch::Approx(5)); + REQUIRE(integrate(p5, l9, 0, 1) == Catch::Approx(6)); + REQUIRE(integrate(p6, l9, 0, 1) == Catch::Approx(7)); + REQUIRE(integrate(p7, l9, 0, 1) == Catch::Approx(8)); + REQUIRE(integrate(p8, l9, 0, 1) == Catch::Approx(9)); + REQUIRE(integrate(p9, l9, 0, 1) == Catch::Approx(10)); + REQUIRE(integrate(p10, l9, 0, 1) != Catch::Approx(11).epsilon(1E-13)); + + REQUIRE(get_order(p10, l9, -1, 1, 12) == Catch::Approx(10)); + } + + SECTION("order 10 and 11") + { + SimplicialGaussLegendreQuadrature<1> l10(10); + SimplicialGaussLegendreQuadrature<1> l11(11); + + REQUIRE(same_formulas(l10, l11)); + REQUIRE(is_symmetric_formula(l11)); + + REQUIRE(l11.numberOfPoints() == 6); + + REQUIRE(integrate(p0, l11, 0.5, 1) == Catch::Approx(0.5)); + REQUIRE(integrate(p1, l11, 0, 1) == Catch::Approx(2)); + REQUIRE(integrate(p2, l11, 0, 1) == Catch::Approx(3)); + REQUIRE(integrate(p3, l11, 0, 1) == Catch::Approx(4)); + REQUIRE(integrate(p4, l11, 0, 1) == Catch::Approx(5)); + REQUIRE(integrate(p5, l11, 0, 1) == Catch::Approx(6)); + REQUIRE(integrate(p6, l11, 0, 1) == Catch::Approx(7)); + REQUIRE(integrate(p7, l11, 0, 1) == Catch::Approx(8)); + REQUIRE(integrate(p8, l11, 0, 1) == Catch::Approx(9)); + REQUIRE(integrate(p9, l11, 0, 1) == Catch::Approx(10)); + REQUIRE(integrate(p10, l11, 0, 1) == Catch::Approx(11)); + REQUIRE(integrate(p11, l11, 0, 1) == Catch::Approx(12)); + REQUIRE(integrate(p12, l11, 0, 1) != Catch::Approx(13).epsilon(1E-13)); + + REQUIRE(get_order(p12, l11, -1, 1, 14) == Catch::Approx(12)); + } + + SECTION("order 12 and 13") + { + SimplicialGaussLegendreQuadrature<1> l12(12); + SimplicialGaussLegendreQuadrature<1> l13(13); + + REQUIRE(same_formulas(l12, l13)); + REQUIRE(is_symmetric_formula(l13)); + + REQUIRE(l13.numberOfPoints() == 7); + + REQUIRE(integrate(p0, l13, 0.5, 1) == Catch::Approx(0.5)); + REQUIRE(integrate(p1, l13, 0, 1) == Catch::Approx(2)); + REQUIRE(integrate(p2, l13, 0, 1) == Catch::Approx(3)); + REQUIRE(integrate(p3, l13, 0, 1) == Catch::Approx(4)); + REQUIRE(integrate(p4, l13, 0, 1) == Catch::Approx(5)); + REQUIRE(integrate(p5, l13, 0, 1) == Catch::Approx(6)); + REQUIRE(integrate(p6, l13, 0, 1) == Catch::Approx(7)); + REQUIRE(integrate(p7, l13, 0, 1) == Catch::Approx(8)); + REQUIRE(integrate(p8, l13, 0, 1) == Catch::Approx(9)); + REQUIRE(integrate(p9, l13, 0, 1) == Catch::Approx(10)); + REQUIRE(integrate(p10, l13, 0, 1) == Catch::Approx(11)); + REQUIRE(integrate(p11, l13, 0, 1) == Catch::Approx(12)); + REQUIRE(integrate(p12, l13, 0, 1) == Catch::Approx(13)); + REQUIRE(integrate(p13, l13, 0, 1) == Catch::Approx(14)); + REQUIRE(integrate(p14, l13, 0, 1) != Catch::Approx(15).epsilon(1E-13)); + + REQUIRE(get_order(p14, l13, -1, 1, 16) == Catch::Approx(14)); + } + + SECTION("order 14 and 15") + { + SimplicialGaussLegendreQuadrature<1> l14(14); + SimplicialGaussLegendreQuadrature<1> l15(15); + + REQUIRE(same_formulas(l14, l15)); + REQUIRE(is_symmetric_formula(l15)); + + REQUIRE(l15.numberOfPoints() == 8); + + REQUIRE(integrate(p0, l15, 0.5, 1) == Catch::Approx(0.5)); + REQUIRE(integrate(p1, l15, 0, 1) == Catch::Approx(2)); + REQUIRE(integrate(p2, l15, 0, 1) == Catch::Approx(3)); + REQUIRE(integrate(p3, l15, 0, 1) == Catch::Approx(4)); + REQUIRE(integrate(p4, l15, 0, 1) == Catch::Approx(5)); + REQUIRE(integrate(p5, l15, 0, 1) == Catch::Approx(6)); + REQUIRE(integrate(p6, l15, 0, 1) == Catch::Approx(7)); + REQUIRE(integrate(p7, l15, 0, 1) == Catch::Approx(8)); + REQUIRE(integrate(p8, l15, 0, 1) == Catch::Approx(9)); + REQUIRE(integrate(p9, l15, 0, 1) == Catch::Approx(10)); + REQUIRE(integrate(p10, l15, 0, 1) == Catch::Approx(11)); + REQUIRE(integrate(p11, l15, 0, 1) == Catch::Approx(12)); + REQUIRE(integrate(p12, l15, 0, 1) == Catch::Approx(13)); + REQUIRE(integrate(p13, l15, 0, 1) == Catch::Approx(14)); + REQUIRE(integrate(p14, l15, 0, 1) == Catch::Approx(15)); + REQUIRE(integrate(p15, l15, 0, 1) == Catch::Approx(16)); + REQUIRE(integrate(p16, l15, 0, 1) != Catch::Approx(17).epsilon(1E-13)); + + REQUIRE(get_order(p16, l15, -1, 1, 18) == Catch::Approx(16)); + } + + SECTION("order 16 and 17") + { + SimplicialGaussLegendreQuadrature<1> l16(16); + SimplicialGaussLegendreQuadrature<1> l17(17); + + REQUIRE(same_formulas(l16, l17)); + REQUIRE(is_symmetric_formula(l17)); + + REQUIRE(l17.numberOfPoints() == 9); + + REQUIRE(integrate(p0, l17, 0.5, 1) == Catch::Approx(0.5)); + REQUIRE(integrate(p1, l17, 0, 1) == Catch::Approx(2)); + REQUIRE(integrate(p2, l17, 0, 1) == Catch::Approx(3)); + REQUIRE(integrate(p3, l17, 0, 1) == Catch::Approx(4)); + REQUIRE(integrate(p4, l17, 0, 1) == Catch::Approx(5)); + REQUIRE(integrate(p5, l17, 0, 1) == Catch::Approx(6)); + REQUIRE(integrate(p6, l17, 0, 1) == Catch::Approx(7)); + REQUIRE(integrate(p7, l17, 0, 1) == Catch::Approx(8)); + REQUIRE(integrate(p8, l17, 0, 1) == Catch::Approx(9)); + REQUIRE(integrate(p9, l17, 0, 1) == Catch::Approx(10)); + REQUIRE(integrate(p10, l17, 0, 1) == Catch::Approx(11)); + REQUIRE(integrate(p11, l17, 0, 1) == Catch::Approx(12)); + REQUIRE(integrate(p12, l17, 0, 1) == Catch::Approx(13)); + REQUIRE(integrate(p13, l17, 0, 1) == Catch::Approx(14)); + REQUIRE(integrate(p14, l17, 0, 1) == Catch::Approx(15)); + REQUIRE(integrate(p15, l17, 0, 1) == Catch::Approx(16)); + REQUIRE(integrate(p16, l17, 0, 1) == Catch::Approx(17)); + REQUIRE(integrate(p17, l17, 0, 1) == Catch::Approx(18)); + REQUIRE(integrate(p18, l17, 0, 1) != Catch::Approx(19).epsilon(1E-13)); + + REQUIRE(get_order(p18, l17, -1, 1, 20) == Catch::Approx(18)); + } + + SECTION("order 18 and 19") + { + SimplicialGaussLegendreQuadrature<1> l18(18); + SimplicialGaussLegendreQuadrature<1> l19(19); + + REQUIRE(same_formulas(l18, l19)); + REQUIRE(is_symmetric_formula(l19)); + + REQUIRE(l19.numberOfPoints() == 10); + + REQUIRE(integrate(p0, l19, 0.5, 1) == Catch::Approx(0.5)); + REQUIRE(integrate(p1, l19, 0, 1) == Catch::Approx(2)); + REQUIRE(integrate(p2, l19, 0, 1) == Catch::Approx(3)); + REQUIRE(integrate(p3, l19, 0, 1) == Catch::Approx(4)); + REQUIRE(integrate(p4, l19, 0, 1) == Catch::Approx(5)); + REQUIRE(integrate(p5, l19, 0, 1) == Catch::Approx(6)); + REQUIRE(integrate(p6, l19, 0, 1) == Catch::Approx(7)); + REQUIRE(integrate(p7, l19, 0, 1) == Catch::Approx(8)); + REQUIRE(integrate(p8, l19, 0, 1) == Catch::Approx(9)); + REQUIRE(integrate(p9, l19, 0, 1) == Catch::Approx(10)); + REQUIRE(integrate(p10, l19, 0, 1) == Catch::Approx(11)); + REQUIRE(integrate(p11, l19, 0, 1) == Catch::Approx(12)); + REQUIRE(integrate(p12, l19, 0, 1) == Catch::Approx(13)); + REQUIRE(integrate(p13, l19, 0, 1) == Catch::Approx(14)); + REQUIRE(integrate(p14, l19, 0, 1) == Catch::Approx(15)); + REQUIRE(integrate(p15, l19, 0, 1) == Catch::Approx(16)); + REQUIRE(integrate(p16, l19, 0, 1) == Catch::Approx(17)); + REQUIRE(integrate(p17, l19, 0, 1) == Catch::Approx(18)); + REQUIRE(integrate(p18, l19, 0, 1) == Catch::Approx(19)); + REQUIRE(integrate(p19, l19, 0, 1) == Catch::Approx(20)); + REQUIRE(integrate(p20, l19, 0, 1) != Catch::Approx(21).epsilon(1E-13)); + + REQUIRE(get_order(p20, l19, -1, 1, 22) == Catch::Approx(20)); + } + + SECTION("order 20 and 21") + { + SimplicialGaussLegendreQuadrature<1> l20(20); + SimplicialGaussLegendreQuadrature<1> l21(21); + + REQUIRE(same_formulas(l20, l21)); + REQUIRE(is_symmetric_formula(l21)); + + REQUIRE(l21.numberOfPoints() == 11); + + REQUIRE(integrate(p0, l21, 0.5, 1) == Catch::Approx(0.5)); + REQUIRE(integrate(p1, l21, 0, 1) == Catch::Approx(2)); + REQUIRE(integrate(p2, l21, 0, 1) == Catch::Approx(3)); + REQUIRE(integrate(p3, l21, 0, 1) == Catch::Approx(4)); + REQUIRE(integrate(p4, l21, 0, 1) == Catch::Approx(5)); + REQUIRE(integrate(p5, l21, 0, 1) == Catch::Approx(6)); + REQUIRE(integrate(p6, l21, 0, 1) == Catch::Approx(7)); + REQUIRE(integrate(p7, l21, 0, 1) == Catch::Approx(8)); + REQUIRE(integrate(p8, l21, 0, 1) == Catch::Approx(9)); + REQUIRE(integrate(p9, l21, 0, 1) == Catch::Approx(10)); + REQUIRE(integrate(p10, l21, 0, 1) == Catch::Approx(11)); + REQUIRE(integrate(p11, l21, 0, 1) == Catch::Approx(12)); + REQUIRE(integrate(p12, l21, 0, 1) == Catch::Approx(13)); + REQUIRE(integrate(p13, l21, 0, 1) == Catch::Approx(14)); + REQUIRE(integrate(p14, l21, 0, 1) == Catch::Approx(15)); + REQUIRE(integrate(p15, l21, 0, 1) == Catch::Approx(16)); + REQUIRE(integrate(p16, l21, 0, 1) == Catch::Approx(17)); + REQUIRE(integrate(p17, l21, 0, 1) == Catch::Approx(18)); + REQUIRE(integrate(p18, l21, 0, 1) == Catch::Approx(19)); + REQUIRE(integrate(p19, l21, 0, 1) == Catch::Approx(20)); + REQUIRE(integrate(p20, l21, 0, 1) == Catch::Approx(21)); + REQUIRE(integrate(p21, l21, 0, 1) == Catch::Approx(22)); + REQUIRE(integrate(p22, l21, 0, 1) != Catch::Approx(23).epsilon(1E-14)); + + REQUIRE(get_order(p22, l21, -1, 1, 24) == Catch::Approx(22).margin(0.02)); + } + + SECTION("order 22 and 23") + { + SimplicialGaussLegendreQuadrature<1> l22(22); + SimplicialGaussLegendreQuadrature<1> l23(23); + + REQUIRE(same_formulas(l22, l23)); + REQUIRE(is_symmetric_formula(l23)); + + REQUIRE(l23.numberOfPoints() == 12); + + REQUIRE(integrate(p0, l23, 0.5, 1) == Catch::Approx(0.5)); + REQUIRE(integrate(p1, l23, 0, 1) == Catch::Approx(2)); + REQUIRE(integrate(p2, l23, 0, 1) == Catch::Approx(3)); + REQUIRE(integrate(p3, l23, 0, 1) == Catch::Approx(4)); + REQUIRE(integrate(p4, l23, 0, 1) == Catch::Approx(5)); + REQUIRE(integrate(p5, l23, 0, 1) == Catch::Approx(6)); + REQUIRE(integrate(p6, l23, 0, 1) == Catch::Approx(7)); + REQUIRE(integrate(p7, l23, 0, 1) == Catch::Approx(8)); + REQUIRE(integrate(p8, l23, 0, 1) == Catch::Approx(9)); + REQUIRE(integrate(p9, l23, 0, 1) == Catch::Approx(10)); + REQUIRE(integrate(p10, l23, 0, 1) == Catch::Approx(11)); + REQUIRE(integrate(p11, l23, 0, 1) == Catch::Approx(12)); + REQUIRE(integrate(p12, l23, 0, 1) == Catch::Approx(13)); + REQUIRE(integrate(p13, l23, 0, 1) == Catch::Approx(14)); + REQUIRE(integrate(p14, l23, 0, 1) == Catch::Approx(15)); + REQUIRE(integrate(p15, l23, 0, 1) == Catch::Approx(16)); + REQUIRE(integrate(p16, l23, 0, 1) == Catch::Approx(17)); + REQUIRE(integrate(p17, l23, 0, 1) == Catch::Approx(18)); + REQUIRE(integrate(p18, l23, 0, 1) == Catch::Approx(19)); + REQUIRE(integrate(p19, l23, 0, 1) == Catch::Approx(20)); + REQUIRE(integrate(p20, l23, 0, 1) == Catch::Approx(21)); + REQUIRE(integrate(p21, l23, 0, 1) == Catch::Approx(22)); + REQUIRE(integrate(p22, l23, 0, 1) == Catch::Approx(23)); + REQUIRE(integrate(p23, l23, 0, 1) == Catch::Approx(24)); + REQUIRE(integrate(p24, l23, 0, 1) != Catch::Approx(25).epsilon(1E-15)); + + REQUIRE(get_order(p24, l23, -1, 1, 26) == Catch::Approx(24).margin(0.05)); + } + + SECTION("not implemented formulae") + { + REQUIRE_THROWS_WITH(SimplicialGaussLegendreQuadrature<1>(24), + "error: Gauss-Legendre quadrature formulae handle orders up to 23"); + } + } +} -- GitLab