21#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
51 std::vector<std::array<int, 3>>
result;
53 int nDof = Base::PolynomialNDOF<2, 3>();
55 nDof = Base::PolynomialNDOF<3, 3>();
61 case 0: nDofNeeded = 1;
break;
62 case 1: nDofNeeded = dim == 2 ? 3 : 4;
break;
63 case 2: nDofNeeded = dim == 2 ? 6 : 10;
break;
64 case 3: nDofNeeded = dim == 2 ? 10 : 20;
break;
67 nDof = std::min(nDof, nDofNeeded);
69 for (
int i = 0; i < nDof; i++)
72 result.push_back(Base::diffOperatorOrderList2D[i]);
74 result.push_back(Base::diffOperatorOrderList[i]);
86 if (a > 0)
result *= std::pow(p(0), a);
87 if (
b > 0)
result *= std::pow(p(1),
b);
88 if (c > 0)
result *= std::pow(p(2), c);
111 if (a % 2 == 1)
return 0.0;
112 return 2.0 / (a + 1.0);
117 t_real Ix = (a % 2 == 1) ? 0.0 : 2.0 / (a + 1.0);
118 t_real Iy = (
b % 2 == 1) ? 0.0 : 2.0 / (
b + 1.0);
123 t_real Ix = (a % 2 == 1) ? 0.0 : 2.0 / (a + 1.0);
124 t_real Iy = (
b % 2 == 1) ? 0.0 : 2.0 / (
b + 1.0);
125 t_real Iz = (c % 2 == 1) ? 0.0 : 2.0 / (c + 1.0);
150 auto factorial = [](
int n) ->
t_real {
152 for (
int i = 2; i <=
n; i++)
result *= i;
155 return factorial(a) * factorial(
b) / factorial(a +
b + 2);
161 auto factorial = [](
int n) ->
t_real {
163 for (
int i = 2; i <=
n; i++)
result *= i;
166 return factorial(a) * factorial(
b) * factorial(c) / factorial(a +
b + c + 3);
171 auto factorial = [](
int n) ->
t_real {
173 for (
int i = 2; i <=
n; i++)
result *= i;
176 t_real I_tri = factorial(a) * factorial(
b) / factorial(a +
b + 2);
177 t_real I_line = (c % 2 == 1) ? 0.0 : 2.0 / (c + 1.0);
178 return I_tri * I_line;
194 if (a == 0 &&
b == 0)
196 return 4.0 * (1.0/(c+1) - 2.0/(c+2) + 1.0/(c+3));
200 if ((a % 2 == 1 &&
b == 0 && c == 0) || (
b % 2 == 1 && a == 0 && c == 0))
205 if (a == 2 &&
b == 0 && c == 0)
207 if (a == 0 &&
b == 2 && c == 0)
211 if (a == 0 &&
b == 0 && c == 0)
228 if (scheme == 0)
return std::nan(
"");
231 for (
t_index iG = 0; iG < scheme; iG++)
257 CHECK(INT_SCHEME_Line_1 > 0);
258 CHECK(INT_SCHEME_Line_2 > 0);
259 CHECK(INT_SCHEME_Line_3 > 0);
260 CHECK(INT_SCHEME_Line_4 > 0);
262 CHECK(INT_SCHEME_Quad_1 > 0);
263 CHECK(INT_SCHEME_Quad_4 > 0);
264 CHECK(INT_SCHEME_Quad_9 > 0);
265 CHECK(INT_SCHEME_Quad_16 > 0);
267 CHECK(INT_SCHEME_Tri_1 > 0);
268 CHECK(INT_SCHEME_Tri_3 > 0);
269 CHECK(INT_SCHEME_Tri_6 > 0);
270 CHECK(INT_SCHEME_Tri_7 > 0);
271 CHECK(INT_SCHEME_Tri_12 > 0);
273 CHECK(INT_SCHEME_Tet_1 > 0);
274 CHECK(INT_SCHEME_Tet_4 > 0);
275 CHECK(INT_SCHEME_Tet_8 > 0);
276 CHECK(INT_SCHEME_Tet_14 > 0);
277 CHECK(INT_SCHEME_Tet_24 > 0);
279 CHECK(INT_SCHEME_Hex_1 > 0);
280 CHECK(INT_SCHEME_Hex_8 > 0);
281 CHECK(INT_SCHEME_Hex_27 > 0);
282 CHECK(INT_SCHEME_Hex_64 > 0);
284 CHECK(INT_SCHEME_Prism_1 > 0);
285 CHECK(INT_SCHEME_Prism_6 > 0);
286 CHECK(INT_SCHEME_Prism_18 > 0);
287 CHECK(INT_SCHEME_Prism_21 > 0);
288 CHECK(INT_SCHEME_Prism_48 > 0);
290 CHECK(INT_SCHEME_Pyramid_1 > 0);
291 CHECK(INT_SCHEME_Pyramid_8 > 0);
292 CHECK(INT_SCHEME_Pyramid_27 > 0);
293 CHECK(INT_SCHEME_Pyramid_64 > 0);
296TEST_CASE(
"Quadrature: weight sums equal reference element volumes")
298 constexpr t_real tol = 1e-12;
304 if (scheme == 0)
continue;
307 for (
t_index iG = 0; iG < scheme; iG++)
314 CHECK(sum == doctest::Approx(2.0).epsilon(tol));
321 if (scheme == 0)
continue;
324 for (
t_index iG = 0; iG < scheme; iG++)
331 CHECK(sum == doctest::Approx(4.0).epsilon(tol));
338 if (scheme == 0)
continue;
341 for (
t_index iG = 0; iG < scheme; iG++)
348 CHECK(sum == doctest::Approx(8.0).epsilon(tol));
355 if (scheme == 0)
continue;
358 for (
t_index iG = 0; iG < scheme; iG++)
365 CHECK(sum == doctest::Approx(0.5).epsilon(tol));
372 if (scheme == 0)
continue;
375 for (
t_index iG = 0; iG < scheme; iG++)
382 CHECK(sum == doctest::Approx(1.0/6.0).epsilon(tol));
389 if (scheme == 0)
continue;
392 for (
t_index iG = 0; iG < scheme; iG++)
399 CHECK(sum == doctest::Approx(1.0).epsilon(tol));
406 if (scheme == 0)
continue;
409 for (
t_index iG = 0; iG < scheme; iG++)
416 CHECK(sum == doctest::Approx(4.0/3.0).epsilon(tol));
420TEST_CASE(
"Quadrature: Line integrates polynomials up to expected order")
422 constexpr t_real tol = 1e-12;
433 for (
const auto& tc :
tests)
436 CAPTURE(tc.maxExactDegree);
438 for (
int deg = 0; deg <= std::min(tc.maxExactDegree, 6); deg++)
444 CHECK(numeric == doctest::Approx(exact).epsilon(tol));
449TEST_CASE(
"Quadrature: Quad integrates polynomials up to expected order")
451 constexpr t_real tol = 1e-12;
461 for (
const auto& tc :
tests)
464 int maxDeg = std::min(tc.maxDegreePerDir, 3);
466 for (
int a = 0; a <= maxDeg; a++)
468 for (
int b = 0;
b <= maxDeg;
b++)
470 if (a +
b > tc.maxDegreePerDir * 2)
continue;
477 CHECK(numeric == doctest::Approx(exact).epsilon(tol));
483TEST_CASE(
"Quadrature: Hex integrates polynomials up to expected order")
485 constexpr t_real tol = 1e-12;
491 for (
const auto& tc :
tests)
494 int maxDeg = std::min(tc.maxDegreePerDir, 2);
496 for (
int a = 0; a <= maxDeg; a++)
498 for (
int b = 0;
b <= maxDeg;
b++)
500 for (
int c = 0; c <= maxDeg; c++)
508 CHECK(numeric == doctest::Approx(exact).epsilon(tol));
515TEST_CASE(
"Quadrature: Triangle integrates polynomials up to expected order")
517 constexpr t_real tol = 1e-10;
533 CHECK(w == doctest::Approx(0.5).epsilon(tol));
537 for (
int i = 0; i < 3; i++) {
541 CHECK(sum_w == doctest::Approx(0.5).epsilon(tol));
547 for (
const auto& tc :
tests)
550 CAPTURE(tc.maxTotalDegree);
552 for (
int a = 0; a <= tc.maxTotalDegree; a++)
554 for (
int b = 0;
b <= tc.maxTotalDegree - a;
b++)
561 if (std::isnan(exact) || std::isnan(numeric))
564 CHECK(numeric == doctest::Approx(exact).epsilon(tol));
570TEST_CASE(
"Quadrature: Tetrahedron integrates polynomials up to expected order")
572 constexpr t_real tol = 1e-10;
584 for (
const auto& tc :
tests)
587 CAPTURE(tc.maxTotalDegree);
589 for (
int a = 0; a <= tc.maxTotalDegree; a++)
591 for (
int b = 0;
b <= tc.maxTotalDegree - a;
b++)
593 for (
int c = 0; c <= tc.maxTotalDegree - a -
b; c++)
601 if (std::isnan(exact) || std::isnan(numeric))
604 CHECK(numeric == doctest::Approx(exact).epsilon(tol));
611TEST_CASE(
"Quadrature: Prism integrates polynomials up to expected order")
613 constexpr t_real tol = 1e-10;
617 struct TestCase {
int order;
int maxTriDegree;
int maxLineDegree; };
620 for (
const auto& tc :
tests)
624 for (
int a = 0; a <= tc.maxTriDegree; a++)
626 for (
int b = 0;
b <= tc.maxTriDegree - a;
b++)
628 for (
int c = 0; c <= tc.maxLineDegree && c <= 3; c += 2)
636 if (std::isnan(exact) || std::isnan(numeric))
639 CHECK(numeric == doctest::Approx(exact).epsilon(tol));
646TEST_CASE(
"Quadrature: Pyramid integrates constant and low-degree polynomials")
648 constexpr t_real tol = 1e-10;
656 for (
const auto& tc :
tests)
659 CAPTURE(tc.maxExactDegree);
665 CHECK(numeric == doctest::Approx(exact).epsilon(tol));
669 if (tc.maxExactDegree >= 1)
672 CHECK(numeric_x == doctest::Approx(0.0).epsilon(tol));
675 CHECK(numeric_y == doctest::Approx(0.0).epsilon(tol));
679 if (tc.maxExactDegree >= 1)
682 if (!std::isnan(exact))
685 CHECK(numeric == doctest::Approx(exact).epsilon(tol));
690 if (tc.maxExactDegree >= 2)
693 if (!std::isnan(exact_x2))
696 CHECK(numeric == doctest::Approx(exact_x2).epsilon(tol));
700 if (!std::isnan(exact_y2))
703 CHECK(numeric == doctest::Approx(exact_y2).epsilon(tol));
708 if (tc.maxExactDegree >= 2)
711 if (!std::isnan(exact))
714 CHECK(numeric == doctest::Approx(exact).epsilon(tol));
720TEST_CASE(
"Quadrature: Quadrature class Integration method works")
722 constexpr t_real tol = 1e-12;
734 CHECK(sum == doctest::Approx(4.0).epsilon(tol));
743 CHECK(sum == doctest::Approx(4.0/3.0).epsilon(tol));
750 acc = p(0) * p(0) * p(1) * p(1);
752 CHECK(sum == doctest::Approx(4.0/9.0).epsilon(tol));
756TEST_CASE(
"Quadrature: GetQuadraturePointInfo returns correct data")
773 t_real coordSum = pParam(0) + pParam(1);
774 CHECK(coordSum <= 1.0 + 1e-12);
775 CHECK(pParam(0) >= -1e-12);
776 CHECK(pParam(1) >= -1e-12);
780 CHECK(totalWeight == doctest::Approx(0.5).epsilon(1e-12));
783TEST_CASE(
"Quadrature: IntegrationSimple overloads work correctly")
785 constexpr t_real tol = 1e-12;
796 CHECK(sum == doctest::Approx(2.0).epsilon(tol));
805 CHECK(sum == doctest::Approx(2.0).epsilon(tol));
815TEST_CASE(
"Quadrature: Taylor basis integration on 2D elements (degree <= 3)")
817 constexpr t_real tol = 1e-10;
830 {
TriSpace, 2, 3, {{1, 1}, {2, 2}, {4, 4}, {5, 5}, {6, 6}}},
832 {
QuadSpace, 2, 3, {{1, 1}, {3, 3}, {5, 5}, {6, 5}}},
842 for (
const auto& [intOrder, maxExactDegree] : cfg.testOrdersWithDegree)
845 CAPTURE(maxExactDegree);
848 if (scheme == 0)
continue;
850 for (
size_t iMono = 0; iMono <
monomials.size(); iMono++)
853 int a = exp[0],
b = exp[1], c = exp[2];
854 int totalDegree = a +
b + c;
857 if (totalDegree > maxExactDegree)
863 CAPTURE(totalDegree);
867 if (std::isnan(exact))
continue;
871 if (std::isnan(numeric))
continue;
873 CHECK(numeric == doctest::Approx(exact).epsilon(tol));
879TEST_CASE(
"Quadrature: Taylor basis integration on 3D elements (degree <= 3)")
881 constexpr t_real tol = 1e-10;
893 {
TetSpace, 3, 3, {{1, 1}, {2, 2}, {3, 3}, {5, 5}, {6, 6}}},
895 {
HexSpace, 3, 3, {{1, 1}, {3, 3}, {5, 5}, {6, 5}}},
897 {
PrismSpace, 3, 3, {{1, 1}, {2, 2}, {4, 4}, {5, 5}, {6, 5}}},
900 for (
const auto& cfg :
configs)
907 for (
const auto& [intOrder, maxExactDegree] : cfg.testOrdersWithDegree)
910 CAPTURE(maxExactDegree);
913 if (scheme == 0)
continue;
915 for (
size_t iMono = 0; iMono <
monomials.size(); iMono++)
918 int a = exp[0],
b = exp[1], c = exp[2];
919 int totalDegree = a +
b + c;
922 if (totalDegree > maxExactDegree)
928 CAPTURE(totalDegree);
932 if (std::isnan(exact))
continue;
936 if (std::isnan(numeric))
continue;
938 CHECK(numeric == doctest::Approx(exact).epsilon(tol));
944TEST_CASE(
"Quadrature: Taylor basis integration on 1D elements (degree <= 3)")
946 constexpr t_real tol = 1e-12;
950 for (
int deg = 0; deg <= 3; deg++)
960 CAPTURE(tc.maxExactDegree);
968 if (totalDegree > tc.maxExactDegree)
976 CHECK(numeric == doctest::Approx(exact).epsilon(tol));
981TEST_CASE(
"Quadrature: Pyramid Taylor basis (degree <= 2)")
983 constexpr t_real tol = 1e-10;
992 for (
const auto& tc :
tests)
995 CAPTURE(tc.maxExactDegree);
998 if (scheme == 0)
continue;
1002 int a = exp[0],
b = exp[1], c = exp[2];
1003 int totalDegree = a +
b + c;
1006 if (totalDegree > tc.maxExactDegree)
1014 if (std::isnan(exact))
continue;
1017 if (std::isnan(numeric))
continue;
1019 CHECK(numeric == doctest::Approx(exact).epsilon(tol));
1033 Eigen::Matrix<t_real, 1, 10> polyVals;
1038 for (
size_t i = 0; i <
monomials.size() && i < 10; i++)
1042 CHECK(polyVals(0, i) == doctest::Approx(
expected).epsilon(1e-12));
1048 Eigen::Matrix<t_real, 1, 20> polyVals;
1052 for (
size_t i = 0; i <
monomials.size() && i < 20; i++)
1056 CHECK(polyVals(0, i) == doctest::Approx(
expected).epsilon(1e-12));
void FPolynomialFill3D(TDIBJ &T, real x, real y, real z, real lx, real ly, real lz, int rows, int cols)
void FPolynomialFill2D(TDIBJ &T, real x, real y, real z, real lx, real ly, real lz, int rows, int cols)
constexpr t_index GetQuadratureScheme(ParamSpace ps, int int_order)
void GetQuadraturePoint(ParamSpace ps, t_index scheme, int iG, TPoint &pParam, t_real &w)
Eigen::Matrix< t_real, 4, Eigen::Dynamic > tD01Nj
DNDS_DEVICE_CALLABLE constexpr ParamSpace GetParamSpace() const
DNDS_DEVICE_CALLABLE std::enable_if_t< std::is_invocable_v< TFunc, TAcc &, int > > IntegrationSimple(TAcc &buf, TFunc &&f)
Simple integration without shape function access.
DNDS_DEVICE_CALLABLE t_index GetNumPoints() const
DNDS_DEVICE_CALLABLE auto GetQuadraturePointInfo(int iG) const
DNDS_DEVICE_CALLABLE real GetWeight(int iG) const
DNDS_DEVICE_CALLABLE void Integration(TAcc &buf, TFunc &&f)
General integration method with shape function access.
std::vector< std::pair< int, int > > testOrdersWithDegree
t_real QuadratureMonomialIntegral(ParamSpace ps, int int_order, int a, int b=0, int c=0)
Numerically integrate a monomial using quadrature.
t_real ExactMonomialIntegral(ParamSpace ps, int a, int b=0, int c=0)
Compute exact integral of monomial over parametric reference element.
t_real EvalMonomial(const tPoint &p, int a, int b=0, int c=0)
Evaluate a monomial x^a * y^b * z^c at point p.
std::vector< std::array< int, 3 > > GetTaylorBasisMonomials(int dim, int maxOrder)
Get the list of Taylor basis monomial exponents up to given order.
ParamSpace GetParamSpaceFromElement(ElemType t)
Get parametric space from element type for testing.
std::vector< std::array< int, 3 > > monomials
TEST_CASE("3D: VFV P2 HQM error < P1 on sinCos3D")
Eigen::Vector3d n(1.0, 0.0, 0.0)