diff --git a/src/analysis/PolynomialP.hpp b/src/analysis/PolynomialP.hpp index e2830df47c1aef4919c8dc160c887b038b99c7fb..7572931bfee1c3476e610a6cb262a5e59e4d754c 100644 --- a/src/analysis/PolynomialP.hpp +++ b/src/analysis/PolynomialP.hpp @@ -2,6 +2,13 @@ #define POLYNOMIALP_HPP #include <algebra/TinyVector.hpp> +#include <analysis/CubeGaussQuadrature.hpp> +#include <analysis/GaussQuadratureDescriptor.hpp> +#include <analysis/QuadratureManager.hpp> +#include <analysis/SquareGaussQuadrature.hpp> +#include <analysis/TriangleGaussQuadrature.hpp> +#include <geometry/SquareTransformation.hpp> +#include <geometry/TriangleTransformation.hpp> #include <utils/Exceptions.hpp> template <size_t N, size_t Dimension> @@ -576,4 +583,45 @@ class PolynomialP ~PolynomialP() = default; }; +template <size_t N, size_t Dimension, size_t P> +PUGS_INLINE double +integrate(const PolynomialP<N, Dimension> Q, const std::array<TinyVector<Dimension>, P>& positions) +{ + double integral = 0.; + static_assert(P > 1, "For the integration, number of positions should be greater or equal to 2"); + static_assert(N >= 0, "invalid degree"); + if constexpr (Dimension == 1) { + static_assert(P == 2, "In 1D number of positions should be 2"); + throw NotImplementedError("Not yet Available in 1D"); + } else if constexpr (Dimension == 2) { + static_assert(P <= 4, "In 2D number of positions should be lesser or equal to 4"); + if constexpr (P == 2) { + } else if constexpr (P == 3) { + const QuadratureFormula<2>& lN = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(N)); + auto point_list = lN.pointList(); + auto weight_list = lN.weightList(); + TriangleTransformation<2> t{positions[0], positions[1], positions[2]}; + auto value = weight_list[0] * Q(t(point_list[0])); + for (size_t i = 1; i < weight_list.size(); ++i) { + value += weight_list[i] * Q(t(point_list[i])); + } + integral = value; + } else { + const QuadratureFormula<2>& lN = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(N)); + auto point_list = lN.pointList(); + auto weight_list = lN.weightList(); + SquareTransformation<2> s{positions[0], positions[1], positions[2], positions[3]}; + auto value = weight_list[0] * Q(s(point_list[0])); + for (size_t i = 1; i < weight_list.size(); ++i) { + value += weight_list[i] * Q(s(point_list[i])); + } + integral = value; + } + } else { + static_assert(Dimension == 3, "Dimension should be <=3"); + throw NotImplementedError("Not yet Available in 3D"); + } + return integral; +} + #endif // POLYNOMIALP_HPP diff --git a/tests/test_PolynomialP.cpp b/tests/test_PolynomialP.cpp index b568179e3597bd4e80ff79442629f011500f9074..1533f9be9410de1ea4a31f784960d92b0c5093db 100644 --- a/tests/test_PolynomialP.cpp +++ b/tests/test_PolynomialP.cpp @@ -1,12 +1,13 @@ -#include <catch2/catch_test_macros.hpp> - #include <Kokkos_Core.hpp> - -#include <utils/PugsAssert.hpp> -#include <utils/Types.hpp> - #include <algebra/TinyMatrix.hpp> +#include <analysis/GaussQuadratureDescriptor.hpp> #include <analysis/PolynomialP.hpp> +#include <analysis/QuadratureManager.hpp> +#include <analysis/SquareGaussQuadrature.hpp> +#include <catch2/catch_approx.hpp> +#include <catch2/catch_test_macros.hpp> +#include <utils/PugsAssert.hpp> +#include <utils/Types.hpp> // Instantiate to ensure full coverage is performed template class PolynomialP<0, 2>; @@ -91,13 +92,25 @@ TEST_CASE("PolynomialP", "[analysis]") { TinyVector<6> coef(1, -2, 10, 7, 2, 9); TinyVector<10> coef2(2, -4, -1, -3, 3, -5, -6, 0, 1, 7); + TinyVector<10> coef3(2, -4, -1, -3, 3, -5, -6, 0, 1, 7); + TinyVector<20> coef4(2, -4, -1, -3, 3, -5, -6, -2, 1, 7, 3, -2, 1, 2.5, 6, -9, 0.5, 4, -5, -8); PolynomialP<2, 2> P(coef); PolynomialP<3, 2> Q(coef2); + PolynomialP<2, 3> R(coef3); + PolynomialP<3, 3> S(coef4); TinyVector<2, size_t> relative_coef(1, 1); TinyVector<2, size_t> relative_coef2(1, 2); + TinyVector<3, size_t> relative_coef3(1, 0, 1); + TinyVector<3, size_t> relative_coef3b(0, 0, 2); + TinyVector<3, size_t> relative_coef4(1, 1, 1); + TinyVector<3, size_t> relative_coef5(0, 2, 1); REQUIRE(P[relative_coef] == 2); REQUIRE(Q[relative_coef2] == 1); REQUIRE(Q[relative_coef] == 3); + REQUIRE(R[relative_coef3] == -6); + REQUIRE(R[relative_coef3b] == 7); + REQUIRE(S[relative_coef4] == 6); + REQUIRE(S[relative_coef5] == 4); } SECTION("evaluation") @@ -124,12 +137,55 @@ TEST_CASE("PolynomialP", "[analysis]") TinyVector<6> coef(1, -2, 10, 7, 2, 9); TinyVector<6> coef2(-2, 14, 2, 0, 0, 0); TinyVector<6> coef3(10, 2, 18, 0, 0, 0); + TinyVector<10> coef4(2, -4, -1, -3, 3, -5, -6, 1, 1, 7); + TinyVector<10> coef5(-1, -5, 2, 1, 0, 0, 0, 0, 0, 0); PolynomialP<2, 2> P(coef); PolynomialP<2, 2> Q(coef2); PolynomialP<2, 2> R(coef3); + PolynomialP<2, 3> S(coef4); + PolynomialP<2, 3> T(coef5); REQUIRE(Q == P.derivative(0)); REQUIRE(R == P.derivative(1)); + REQUIRE(T == S.derivative(1)); + } + + SECTION("integrate") + { + TinyVector<6> coef(1, -2, 10, 7, 2, 9); + std::array<TinyVector<2>, 4> positions; + std::array<TinyVector<2>, 3> positions2; + positions[0] = TinyVector<2>{0, 0}; + positions[1] = TinyVector<2>{0, 0.5}; + positions[2] = TinyVector<2>{0.3, 0.7}; + positions[3] = TinyVector<2>{0.4, 0.1}; + positions2[0] = TinyVector<2>{0, 0}; + positions2[1] = TinyVector<2>{0, 0.5}; + positions2[2] = TinyVector<2>{0.3, 0.7}; + PolynomialP<2, 2> P(coef); + auto p1 = [](const TinyVector<2>& X) { + const double x = X[0]; + const double y = X[1]; + return 1 - 2. * x + 10 * y + 7 * x * x + 2 * x * y + 9 * y * y; + }; + const QuadratureFormula<2>& l3 = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(3)); + auto point_list = l3.pointList(); + auto weight_list = l3.weightList(); + SquareTransformation<2> s{positions[0], positions[1], positions[2], positions[3]}; + auto value = weight_list[0] * p1(s(point_list[0])); + for (size_t i = 1; i < weight_list.size(); ++i) { + value += weight_list[i] * p1(s(point_list[i])); + } + const QuadratureFormula<2>& t3 = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(3)); + auto point_list2 = t3.pointList(); + auto weight_list2 = t3.weightList(); + TriangleTransformation<2> t{positions2[0], positions2[1], positions2[2]}; + auto value2 = weight_list2[0] * p1(t(point_list2[0])); + for (size_t i = 1; i < weight_list2.size(); ++i) { + value2 += weight_list2[i] * p1(t(point_list2[i])); + } + REQUIRE(value == integrate(P, positions)); + REQUIRE(value2 == Catch::Approx(integrate(P, positions2))); } // // SECTION("product")